Split up SettingItem code (#1484)

* Remove unused click handling code

* Split up settings item code
This commit is contained in:
MinusGix 2022-10-12 15:08:42 -05:00 committed by GitHub
parent fdb1e52f4e
commit 2ee625d4b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 476 additions and 421 deletions

View File

@ -53,7 +53,6 @@
history::DocumentHistory,
proxy::LapceProxy,
selection_range::{SelectionRangeDirection, SyntaxSelectionRanges},
settings::SettingsValueKind,
};
use lapce_rpc::plugin::PluginId;
@ -133,7 +132,8 @@ pub enum LocalBufferKind {
pub enum BufferContent {
File(PathBuf),
Local(LocalBufferKind),
SettingsValue(String, SettingsValueKind, String, String),
/// A setting input; with its name.
SettingsValue(String),
Scratch(BufferId, String),
}

View File

@ -24,7 +24,6 @@
keypress::KeyPressFocus,
palette::PaletteStatus,
panel::{PanelData, PanelKind},
settings::SettingsValueKind,
};
use crate::{
@ -44,7 +43,6 @@ pub struct LapceEditorView {
pub find: Option<WidgetPod<LapceTabData, Box<dyn Widget<LapceTabData>>>>,
cursor_blink_timer: TimerToken,
autosave_timer: TimerToken,
last_idle_timer: TimerToken,
display_border: bool,
background_color_name: &'static str,
ime: ImeComponent,
@ -98,7 +96,6 @@ pub fn new(
find,
cursor_blink_timer: TimerToken::INVALID,
autosave_timer: TimerToken::INVALID,
last_idle_timer: TimerToken::INVALID,
display_border: true,
background_color_name: LapceTheme::EDITOR_BACKGROUND,
ime: ImeComponent::default(),
@ -611,38 +608,6 @@ fn event(
}
}
}
Event::Timer(id) if self.last_idle_timer == *id => {
ctx.set_handled();
let editor_data = data.editor_view_content(self.view_id);
if let BufferContent::SettingsValue(_, kind, parent, key) =
&editor_data.editor.content
{
let content = editor_data.doc.buffer().to_string();
let new_value = match kind {
SettingsValueKind::String => {
Some(serde_json::json!(content))
}
SettingsValueKind::Integer => {
content.parse::<i64>().ok().map(|n| serde_json::json!(n))
}
SettingsValueKind::Float => {
content.parse::<f64>().ok().map(|n| serde_json::json!(n))
}
SettingsValueKind::Bool => None,
};
if let Some(new_value) = new_value {
ctx.submit_command(Command::new(
LAPCE_UI_COMMAND,
LapceUICommand::UpdateSettingsFile(
parent.to_string(),
key.to_string(),
new_value,
),
Target::Widget(data.id),
));
}
}
}
Event::Timer(id) if self.autosave_timer == *id => {
ctx.set_handled();
if let Some(editor) = data
@ -914,18 +879,6 @@ fn update(
let old_editor_data = old_data.editor_view_content(self.view_id);
let editor_data = data.editor_view_content(self.view_id);
if let BufferContent::SettingsValue(..) = &editor_data.editor.content {
if !editor_data.doc.buffer().is_pristine()
&& (editor_data.doc.buffer().len()
!= old_editor_data.doc.buffer().len()
|| editor_data.doc.buffer().text().slice_to_cow(..)
!= old_editor_data.doc.buffer().text().slice_to_cow(..))
{
self.last_idle_timer =
ctx.request_timer(Duration::from_millis(500), None);
}
}
let offset = editor_data.editor.cursor.offset();
let old_offset = old_editor_data.editor.cursor.offset();

View File

@ -5,6 +5,7 @@
piet::{
PietText, PietTextLayout, Text, TextAttribute, TextLayout, TextLayoutBuilder,
},
widget::Padding,
BoxConstraints, Command, Cursor, Env, Event, EventCtx, ExtEventSink, FontWeight,
LayoutCtx, LifeCycle, LifeCycleCtx, Modifiers, PaintCtx, Point, Rect,
RenderContext, Size, Target, TimerToken, UpdateCtx, Widget, WidgetExt, WidgetId,
@ -434,19 +435,13 @@ fn into_settings_map(
value = v.clone();
}
}
self.children.push(WidgetPod::new(
LapcePadding::new(
(10.0, 10.0),
LapceSettingsItem::new(
data,
volt.name.clone(),
key.to_string(),
config.description.clone(),
value,
ctx.get_external_handle(),
),
)
.boxed(),
self.children.push(create_settings_item(
data,
volt.name.clone(),
key.to_string(),
config.description.clone(),
value,
ctx.get_external_handle(),
));
}
}
@ -459,20 +454,14 @@ fn into_settings_map(
// TODO(dbuga): we should generate kebab-case field names
let field = field.replace('_', "-");
let value = settings.remove(&field).unwrap();
self.children.push(WidgetPod::new(
LapcePadding::new(
(10.0, 10.0),
LapceSettingsItem::new(
data,
kind.to_string(),
field,
desc.to_string(),
value,
ctx.get_external_handle(),
),
)
.boxed(),
))
self.children.push(create_settings_item(
data,
kind.to_string(),
field,
desc.to_string(),
value,
ctx.get_external_handle(),
));
}
}
}
@ -559,109 +548,122 @@ struct LapceSettingsItemKeypress {
cursor: usize,
}
struct LapceSettingsItem {
/// Create a settings item widget
/// Includes padding.
fn create_settings_item(
data: &mut LapceTabData,
kind: String,
name: String,
key: String,
desc: String,
value: serde_json::Value,
padding: f64,
checkbox_width: f64,
input_max_width: f64,
event_sink: ExtEventSink,
) -> WidgetPod<LapceTabData, Box<dyn Widget<LapceTabData>>> {
let insets = (10.0, 10.0);
match value {
serde_json::Value::Number(n) => {
let value_kind = if n.is_f64() {
SettingsValueKind::Float
} else {
SettingsValueKind::Integer
};
WidgetPod::new(
LapcePadding::new(
insets,
InputSettingsItem::new(
data,
kind,
key,
desc,
event_sink,
n.to_string(),
value_kind,
),
)
.boxed(),
)
}
serde_json::Value::String(s) => WidgetPod::new(
LapcePadding::new(
insets,
InputSettingsItem::new(
data,
kind,
key,
desc,
event_sink,
s,
SettingsValueKind::String,
),
)
.boxed(),
),
serde_json::Value::Bool(checked) => WidgetPod::new(
LapcePadding::new(
insets,
CheckBoxSettingsItem::new(key, kind, desc, checked),
)
.boxed(),
),
serde_json::Value::Array(_)
| serde_json::Value::Object(_)
| serde_json::Value::Null => panic!("Unknown setting value kind"),
}
}
/// Shared information between each setting item
struct SettingsItemInfo {
width: f64,
cursor: usize,
input: String,
value_changed: bool,
last_idle_timer: TimerToken,
padding: f64,
/// Key of the field
key: String,
kind: String,
desc: String,
name_text: Option<PietTextLayout>,
desc_text: Option<PietTextLayout>,
value_text: Option<Option<PietTextLayout>>,
input_widget: Option<WidgetPod<LapceTabData, Box<dyn Widget<LapceTabData>>>>,
}
impl LapceSettingsItem {
/// Timer which keeps track of when it was last edited
/// So that it can update
last_idle_timer: TimerToken,
}
impl SettingsItemInfo {
/// The amount of time to wait for the next key press before storing settings.
const SAVE_DELAY: Duration = Duration::from_millis(500);
pub fn new(
data: &mut LapceTabData,
kind: String,
key: String,
desc: String,
value: serde_json::Value,
event_sink: ExtEventSink,
) -> Self {
let input = match &value {
serde_json::Value::Number(n) => {
if n.is_f64() {
Some((n.to_string(), SettingsValueKind::Float))
} else {
Some((n.to_string(), SettingsValueKind::Integer))
}
}
serde_json::Value::String(s) => {
Some((s.to_string(), SettingsValueKind::String))
}
serde_json::Value::Array(_)
| serde_json::Value::Object(_)
| serde_json::Value::Bool(_)
| serde_json::Value::Null => None,
};
let input = input.map(|(input, value_kind)| {
let name = format!("{kind}.{key}");
let content = BufferContent::SettingsValue(
name.clone(),
value_kind,
kind.clone(),
key.clone(),
);
let mut doc = Document::new(
content.clone(),
data.id,
event_sink,
data.proxy.clone(),
);
doc.reload(Rope::from(&input), true);
data.main_split.value_docs.insert(name, Arc::new(doc));
let editor =
LapceEditorData::new(None, None, None, content, &data.config);
let view_id = editor.view_id;
let input = LapceEditorView::new(editor.view_id, editor.editor_id, None)
.hide_header()
.hide_gutter()
.padding((5.0, 0.0, 50.0, 0.0));
data.main_split.editors.insert(view_id, Arc::new(editor));
(view_id, WidgetPod::new(input.boxed()))
});
let input_widget = input.map(|i| i.1);
Self {
kind,
name: key,
desc,
value,
padding: 10.0,
fn new(key: String, kind: String, desc: String) -> Self {
SettingsItemInfo {
width: 0.0,
checkbox_width: 20.0,
input_max_width: 500.0,
cursor: 0,
input: "".to_string(),
value_changed: false,
last_idle_timer: TimerToken::INVALID,
padding: 10.0,
key,
kind,
desc,
name_text: None,
desc_text: None,
value_text: None,
input_widget,
last_idle_timer: TimerToken::INVALID,
}
}
/// Check if the last-idle-timer has been triggered, and thus it should probably update
fn idle_timer_triggered(&self, token: TimerToken) -> bool {
token == self.last_idle_timer
}
fn clear_text_layout_cache(&mut self) {
self.name_text = None;
self.desc_text = None;
}
/// Get the text layout for the name of the setting item, creating it if it has changed
/// or if it is not already initialize.
pub fn name(
&mut self,
text: &mut PietText,
data: &LapceTabData,
) -> &PietTextLayout {
let splits: Vec<&str> = self.name.rsplitn(2, '.').collect();
// TODO: This could likely use smallvec, or even skip the allocs completely for
// the *common* case of the name text not changing..
let splits: Vec<&str> = self.key.rsplitn(2, '.').collect();
let mut name_text = "".to_string();
if let Some(title) = splits.get(1) {
for (i, part) in title.split('.').enumerate() {
@ -699,17 +701,17 @@ pub fn name(
self.name_text.as_ref().unwrap()
}
/// Get the text layout for the description of the setting item, creating it if it doesn't exist.
/// `extra_width` is used for when there are other rendered elements on the same line as the description,
/// such as the checkbox.
pub fn desc(
&mut self,
text: &mut PietText,
data: &LapceTabData,
extra_width: f64,
) -> &PietTextLayout {
if self.desc_text.is_none() {
let max_width = if self.value.is_boolean() {
self.width - self.checkbox_width
} else {
self.width
};
let max_width = self.width - extra_width;
let text_layout = text
.new_text_layout(self.desc.clone())
.font(
@ -731,45 +733,366 @@ pub fn desc(
self.desc_text.as_ref().unwrap()
}
pub fn value(
&mut self,
text: &mut PietText,
fn update_settings(
&self,
data: &LapceTabData,
) -> Option<&PietTextLayout> {
if self.value_text.is_none() {
let value = match &self.value {
serde_json::Value::Number(n) => Some(n.to_string()),
serde_json::Value::String(s) => Some(s.to_string()),
serde_json::Value::Array(_)
| serde_json::Value::Object(_)
| serde_json::Value::Bool(_)
| serde_json::Value::Null => None,
};
let text_layout = value.map(|value| {
self.input = value.to_string();
text.new_text_layout(value)
.font(
data.config.ui.font_family(),
data.config.ui.font_size() as f64,
)
.text_color(
data.config
.get_color_unchecked(LapceTheme::EDITOR_FOREGROUND)
.clone(),
)
.build()
.unwrap()
});
self.value_text = Some(text_layout);
}
self.value_text.as_ref().unwrap().as_ref()
ctx: &mut EventCtx,
value: serde_json::Value,
) {
ctx.submit_command(Command::new(
LAPCE_UI_COMMAND,
LapceUICommand::UpdateSettingsFile(
self.kind.clone(),
self.key.clone(),
value,
),
Target::Widget(data.id),
));
}
fn clear_text_layout_cache(&mut self) {
self.name_text = None;
self.desc_text = None;
self.value_text = None;
fn update(
&mut self,
_ctx: &mut UpdateCtx,
old_data: &LapceTabData,
data: &LapceTabData,
_env: &Env,
) {
if data.config.id != old_data.config.id {
self.clear_text_layout_cache();
}
}
fn layout(
&mut self,
ctx: &mut LayoutCtx,
bc: &BoxConstraints,
data: &LapceTabData,
_env: &Env,
extra_width: f64,
) -> Size {
let width = bc.max().width;
if width != self.width {
self.width = width;
self.clear_text_layout_cache();
}
let text = ctx.text();
let name = self.name(text, data).size();
let desc = self.desc(text, data, extra_width).size();
let mut height = name.height + desc.height + (self.padding * 3.0);
height = height.round();
Size::new(self.width, height)
}
/// Paint the name of the setting and the description
/// `extra_width` decides how the description should be shifted to the right
/// Returns the y position of the description, so that you can relative to it.
fn paint(
&mut self,
ctx: &mut PaintCtx,
data: &LapceTabData,
_env: &Env,
extra_width: f64,
) -> f64 {
let mut y = 0.0;
let padding = self.padding;
let rect = ctx
.size()
.to_rect()
.inflate(0.0, padding)
.inset((padding, 0.0, -30.0, 0.0));
if ctx.is_hot() {
ctx.fill(
rect,
data.config
.get_color_unchecked(LapceTheme::EDITOR_CURRENT_LINE),
);
}
let text = ctx.text();
let text = self.name(text, data);
y += padding;
ctx.draw_text(text, Point::new(0.0, y));
y += text.size().height;
y += padding;
let desc_y = y;
let text = ctx.text();
let desc = self.desc(text, data, extra_width);
ctx.draw_text(desc, Point::new(extra_width, y));
desc_y
}
}
struct CheckBoxSettingsItem {
checked: bool,
checkbox_width: f64,
info: SettingsItemInfo,
}
impl CheckBoxSettingsItem {
fn new(key: String, kind: String, desc: String, checked: bool) -> Self {
Self {
checked,
checkbox_width: 20.0,
info: SettingsItemInfo::new(key, kind, desc),
}
}
}
impl Widget<LapceTabData> for CheckBoxSettingsItem {
fn event(
&mut self,
ctx: &mut EventCtx,
event: &Event,
data: &mut LapceTabData,
_env: &Env,
) {
match event {
Event::MouseMove(_) => ctx.set_handled(),
Event::MouseDown(mouse_event) => {
let rect = Size::new(self.checkbox_width, self.checkbox_width)
.to_rect()
.with_origin(Point::new(
0.0,
self.info.name(ctx.text(), data).size().height
+ self.info.padding * 2.0
+ 4.0,
));
if rect.contains(mouse_event.pos) {
self.checked = !self.checked;
self.info.last_idle_timer =
ctx.request_timer(SettingsItemInfo::SAVE_DELAY, None);
}
}
Event::Timer(token) if self.info.idle_timer_triggered(*token) => {
ctx.set_handled();
self.info.update_settings(
data,
ctx,
serde_json::Value::Bool(self.checked),
);
}
_ => {}
}
}
fn lifecycle(
&mut self,
ctx: &mut LifeCycleCtx,
event: &LifeCycle,
_data: &LapceTabData,
_env: &Env,
) {
if let LifeCycle::HotChanged(_) = event {
ctx.request_paint();
}
}
fn update(
&mut self,
ctx: &mut UpdateCtx,
old_data: &LapceTabData,
data: &LapceTabData,
env: &Env,
) {
self.info.update(ctx, old_data, data, env);
}
fn layout(
&mut self,
ctx: &mut LayoutCtx,
bc: &BoxConstraints,
data: &LapceTabData,
env: &Env,
) -> Size {
self.info.layout(ctx, bc, data, env, self.checkbox_width)
}
fn paint(&mut self, ctx: &mut PaintCtx, data: &LapceTabData, env: &Env) {
let y = self.info.paint(ctx, data, env, self.checkbox_width);
let width = 13.0;
let height = 13.0;
let origin = Point::new(0.0, y + 4.0);
let rect = Size::new(width, height).to_rect().with_origin(origin);
ctx.stroke(
rect,
data.config
.get_color_unchecked(LapceTheme::EDITOR_FOREGROUND),
1.0,
);
if self.checked {
let mut path = BezPath::new();
path.move_to((origin.x + 3.0, origin.y + 7.0));
path.line_to((origin.x + 6.0, origin.y + 9.5));
path.line_to((origin.x + 10.0, origin.y + 3.0));
ctx.stroke(
path,
data.config
.get_color_unchecked(LapceTheme::EDITOR_FOREGROUND),
2.0,
);
}
}
}
// TODO: Split input into separate kinds for for int/f64/string?
struct InputSettingsItem {
/// ID of the editor so that it can be easily accessed
view_id: WidgetId,
input: WidgetPod<LapceTabData, Padding<LapceTabData, LapceEditorView>>,
/// The value kind of the setting item, so that we know what to parse it as.
value_kind: SettingsValueKind,
info: SettingsItemInfo,
}
impl InputSettingsItem {
fn new(
data: &mut LapceTabData,
kind: String,
key: String,
desc: String,
event_sink: ExtEventSink,
input: String,
value_kind: SettingsValueKind,
) -> Self {
let name = format!("{kind}.{key}");
let content = BufferContent::SettingsValue(name.clone());
let mut doc =
Document::new(content.clone(), data.id, event_sink, data.proxy.clone());
doc.reload(Rope::from(&input), true);
data.main_split.value_docs.insert(name, Arc::new(doc));
let editor = LapceEditorData::new(None, None, None, content, &data.config);
let view_id = editor.view_id;
let input = LapceEditorView::new(editor.view_id, editor.editor_id, None)
.hide_header()
.hide_gutter()
.padding((5.0, 0.0, 50.0, 0.0));
data.main_split.editors.insert(view_id, Arc::new(editor));
Self {
view_id,
input: WidgetPod::new(input),
value_kind,
info: SettingsItemInfo::new(key, kind, desc),
}
}
}
impl Widget<LapceTabData> for InputSettingsItem {
fn event(
&mut self,
ctx: &mut EventCtx,
event: &Event,
data: &mut LapceTabData,
env: &Env,
) {
// Don't alert the input to mouse-wheel events
if !matches!(event, Event::Wheel(_)) {
self.input.event(ctx, event, data, env);
}
match event {
Event::MouseMove(_) => ctx.set_handled(),
// Save settings when it has been some time since the last edit
Event::Timer(token) if self.info.idle_timer_triggered(*token) => {
ctx.set_handled();
let editor_data = data.editor_view_content(self.view_id);
if let BufferContent::SettingsValue(_) = &editor_data.editor.content
{
let content = editor_data.doc.buffer().to_string();
let value = match self.value_kind {
SettingsValueKind::String => {
Some(serde_json::json!(content))
}
SettingsValueKind::Integer => {
content.parse::<i64>().ok().map(|n| serde_json::json!(n))
}
SettingsValueKind::Float => {
content.parse::<f64>().ok().map(|n| serde_json::json!(n))
}
// Should be unreachable
SettingsValueKind::Bool => None,
};
if let Some(value) = value {
self.info.update_settings(data, ctx, value);
}
} else {
log::warn!("Setting Input editor view id referred to editor with non-settings-value BufferContent");
}
}
_ => {}
}
}
fn lifecycle(
&mut self,
ctx: &mut LifeCycleCtx,
event: &LifeCycle,
data: &LapceTabData,
env: &Env,
) {
if let LifeCycle::HotChanged(_) = event {
ctx.request_paint();
}
self.input.lifecycle(ctx, event, data, env);
}
fn update(
&mut self,
ctx: &mut UpdateCtx,
old_data: &LapceTabData,
data: &LapceTabData,
env: &Env,
) {
self.info.update(ctx, old_data, data, env);
let old_editor_data = old_data.editor_view_content(self.view_id);
let editor_data = data.editor_view_content(self.view_id);
// If there's been changes, then report that the last time we were idle is right now
// TODO: minor. These usages of slice_to_cow are fine, since all settings are short values and thus
// it can probably just return a `Cow::Borrowed(_)`, but there's probably a better way to compare
if !editor_data.doc.buffer().is_pristine()
&& (editor_data.doc.buffer().len() != old_editor_data.doc.buffer().len()
|| editor_data.doc.buffer().text().slice_to_cow(..)
!= old_editor_data.doc.buffer().text().slice_to_cow(..))
{
self.info.last_idle_timer =
ctx.request_timer(SettingsItemInfo::SAVE_DELAY, None);
}
self.input.update(ctx, data, env);
}
fn layout(
&mut self,
ctx: &mut LayoutCtx,
bc: &BoxConstraints,
data: &LapceTabData,
env: &Env,
) -> Size {
let size = self.info.layout(ctx, bc, data, env, 0.0);
let input_size = self.input.layout(ctx, bc, data, env);
self.input
.set_origin(ctx, data, env, Point::new(0.0, size.height));
Size::new(size.width, (size.height + input_size.height).ceil())
}
fn paint(&mut self, ctx: &mut PaintCtx, data: &LapceTabData, env: &Env) {
self.info.paint(ctx, data, env, 0.0);
self.input.paint(ctx, data, env);
}
}
@ -824,222 +1147,6 @@ fn run_command(
}
}
impl Widget<LapceTabData> for LapceSettingsItem {
fn event(
&mut self,
ctx: &mut EventCtx,
event: &Event,
data: &mut LapceTabData,
env: &Env,
) {
if let Some(input) = self.input_widget.as_mut() {
match event {
Event::Wheel(_) => {}
_ => {
input.event(ctx, event, data, env);
}
}
}
match event {
Event::MouseDown(mouse_event) => {
// ctx.request_focus();
let input = self.input.clone();
if let Some(_text) = self.value(ctx.text(), data) {
let text = ctx
.text()
.new_text_layout(input)
.font(
data.config.ui.font_family(),
data.config.ui.font_size() as f64,
)
.text_color(
data.config
.get_color_unchecked(LapceTheme::EDITOR_FOREGROUND)
.clone(),
)
.build()
.unwrap();
let mut height = self.name(ctx.text(), data).size().height;
height += self.desc(ctx.text(), data).size().height;
height += self.padding * 2.0 + self.padding;
let rect = Size::new(
ctx.size().width.min(self.input_max_width),
text.size().height,
)
.to_rect()
.with_origin(Point::new(0.0, height))
.inflate(0.0, 8.0);
if rect.contains(mouse_event.pos) {
let pos = mouse_event.pos - (8.0, 0.0);
let hit = text.hit_test_point(pos);
self.cursor = hit.idx;
}
} else if let serde_json::Value::Bool(checked) = self.value {
let rect = Size::new(self.checkbox_width, self.checkbox_width)
.to_rect()
.with_origin(Point::new(
0.0,
self.name(ctx.text(), data).size().height
+ self.padding * 2.0
+ 4.0,
));
if rect.contains(mouse_event.pos) {
self.value = serde_json::json!(!checked);
self.value_changed = true;
self.last_idle_timer =
ctx.request_timer(Self::SAVE_DELAY, None);
}
}
}
Event::MouseMove(_) => {
ctx.set_handled();
}
Event::Timer(token)
if self.value_changed && *token == self.last_idle_timer =>
{
self.value_changed = false;
ctx.submit_command(Command::new(
LAPCE_UI_COMMAND,
LapceUICommand::UpdateSettingsFile(
self.kind.clone(),
self.name.clone(),
self.value.clone(),
),
Target::Widget(data.id),
));
}
_ => {}
}
}
fn lifecycle(
&mut self,
ctx: &mut LifeCycleCtx,
event: &LifeCycle,
data: &LapceTabData,
env: &Env,
) {
if let LifeCycle::HotChanged(_) = event {
ctx.request_paint();
}
if let Some(input) = self.input_widget.as_mut() {
input.lifecycle(ctx, event, data, env);
}
}
fn update(
&mut self,
ctx: &mut UpdateCtx,
old_data: &LapceTabData,
data: &LapceTabData,
env: &Env,
) {
if data.config.id != old_data.config.id {
self.clear_text_layout_cache();
}
if let Some(input) = self.input_widget.as_mut() {
input.update(ctx, data, env);
}
}
fn layout(
&mut self,
ctx: &mut LayoutCtx,
bc: &BoxConstraints,
data: &LapceTabData,
env: &Env,
) -> Size {
let width = bc.max().width;
if width != self.width {
self.width = width;
self.clear_text_layout_cache();
}
let text = ctx.text();
let name = self.name(text, data).size();
let desc = self.desc(text, data).size();
let mut height = name.height + desc.height + (self.padding * 3.0);
height = height.round();
if let Some(input) = self.input_widget.as_mut() {
input.layout(ctx, bc, data, env);
input.set_origin(ctx, data, env, Point::new(0.0, height));
}
let text = ctx.text();
let value = self
.value(text, data)
.map(|v| v.size().height)
.unwrap_or(0.0);
if value > 0.0 {
height += value + self.padding * 2.0;
}
Size::new(self.width, height.ceil())
}
fn paint(&mut self, ctx: &mut PaintCtx, data: &LapceTabData, env: &Env) {
let mut y = 0.0;
let padding = self.padding;
let rect = ctx
.size()
.to_rect()
.inflate(0.0, padding)
.inset((padding, 0.0, -30.0, 0.0));
if ctx.is_hot() {
ctx.fill(
rect,
data.config
.get_color_unchecked(LapceTheme::EDITOR_CURRENT_LINE),
);
}
let text = ctx.text();
let text = self.name(text, data);
y += padding;
ctx.draw_text(text, Point::new(0.0, y));
y += text.size().height;
y += padding;
let x = if let serde_json::Value::Bool(checked) = self.value {
let width = 13.0;
let height = 13.0;
let origin = Point::new(0.0, y + 4.0);
let rect = Size::new(width, height).to_rect().with_origin(origin);
ctx.stroke(
rect,
data.config
.get_color_unchecked(LapceTheme::EDITOR_FOREGROUND),
1.0,
);
if checked {
let mut path = BezPath::new();
path.move_to((origin.x + 3.0, origin.y + 7.0));
path.line_to((origin.x + 6.0, origin.y + 9.5));
path.line_to((origin.x + 10.0, origin.y + 3.0));
ctx.stroke(
path,
data.config
.get_color_unchecked(LapceTheme::EDITOR_FOREGROUND),
2.0,
);
}
self.checkbox_width
} else {
0.0
};
let text = ctx.text();
let text = self.desc(text, data);
ctx.draw_text(text, Point::new(x, y));
if let Some(input) = self.input_widget.as_mut() {
input.paint(ctx, data, env);
}
}
}
#[derive(Clone, Copy)]
pub enum ThemeKind {
Base,
@ -1149,12 +1256,7 @@ fn update_inputs(&mut self, ctx: &mut EventCtx, data: &mut LapceTabData) {
for color in colors {
let name = format!("{}.{color}", self.kind);
let content = BufferContent::SettingsValue(
name.clone(),
SettingsValueKind::String,
self.kind.to_string(),
color.to_string(),
);
let content = BufferContent::SettingsValue(name.clone());
let mut doc = Document::new(
content.clone(),
data.id,

View File

@ -1721,7 +1721,7 @@ fn handle_command_event(
BufferContent::Local(kind) => {
data.main_split.local_docs.get_mut(kind).unwrap()
}
BufferContent::SettingsValue(name, _, _, _) => {
BufferContent::SettingsValue(name) => {
data.main_split.value_docs.get_mut(name).unwrap()
}
BufferContent::Scratch(id, _) => {