GPU-accelerated UI toolkit (Vulkan)
git clone https://git.lucas.co/cce-ui.git
Moved style.data.textbox.line_wrap to style.data.textbox.multiline.line_wrap and restricted to multiline textboxes
src/config.rs | 79 +++++++++++++++++++++++++++-----------------
src/layout.rs | 2 +-
src/widget/input/text_box.rs | 50 ++++++++++++----------------
3 files changed, 70 insertions(+), 61 deletions(-)
diff --git a/src/config.rs b/src/config.rs
index f24cdbd..f1f88a8 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -95,44 +95,61 @@ fn kdl_to_json(doc: &kdl::KdlDocument) -> serde_json::Value {
} else {
serde_json::Value::Null
}
- } else if let Some(children) = node.children() {
- kdl_to_json(children)
- } else if has_props {
- serde_json::Value::Object(node_map)
- } else if let Some(entry) = node.entries().first() {
- match entry.value() {
- kdl::KdlValue::Bool(b) => serde_json::Value::Bool(*b),
- kdl::KdlValue::Base2(i) |
- kdl::KdlValue::Base8(i) |
- kdl::KdlValue::Base10(i) |
- kdl::KdlValue::Base16(i) => serde_json::Value::Number(serde_json::Number::from(*i)),
- kdl::KdlValue::Base10Float(f) => {
- let mut val_f = *f;
- if let Some(ty) = entry.ty() {
- let ty_str = ty.value();
- if ty_str.starts_with("f64:") {
- let range_str = ty_str.trim_start_matches("f64:");
- if let Some(dash_idx) = range_str.find('-') {
- let min_str = &range_str[..dash_idx].trim();
- let max_str = &range_str[dash_idx + 1..].trim();
- if let (Ok(min_f), Ok(max_f)) = (min_str.parse::<f64>(), max_str.parse::<f64>()) {
- val_f = val_f.clamp(min_f, max_f);
+ } else {
+ let mut node_val = serde_json::Value::Null;
+ if has_props {
+ node_val = serde_json::Value::Object(node_map);
+ } else if let Some(entry) = node.entries().first() {
+ node_val = match entry.value() {
+ kdl::KdlValue::Bool(b) => serde_json::Value::Bool(*b),
+ kdl::KdlValue::Base2(i) |
+ kdl::KdlValue::Base8(i) |
+ kdl::KdlValue::Base10(i) |
+ kdl::KdlValue::Base16(i) => serde_json::Value::Number(serde_json::Number::from(*i)),
+ kdl::KdlValue::Base10Float(f) => {
+ let mut val_f = *f;
+ if let Some(ty) = entry.ty() {
+ let ty_str = ty.value();
+ if ty_str.starts_with("f64:") {
+ let range_str = ty_str.trim_start_matches("f64:");
+ if let Some(dash_idx) = range_str.find('-') {
+ let min_str = &range_str[..dash_idx].trim();
+ let max_str = &range_str[dash_idx + 1..].trim();
+ if let (Ok(min_f), Ok(max_f)) = (min_str.parse::<f64>(), max_str.parse::<f64>()) {
+ val_f = val_f.clamp(min_f, max_f);
+ }
}
}
}
+ if let Some(num) = serde_json::Number::from_f64(val_f) {
+ serde_json::Value::Number(num)
+ } else {
+ serde_json::Value::Null
+ }
}
- if let Some(num) = serde_json::Number::from_f64(val_f) {
- serde_json::Value::Number(num)
+ kdl::KdlValue::String(s) |
+ kdl::KdlValue::RawString(s) => serde_json::Value::String(s.clone()),
+ kdl::KdlValue::Null => serde_json::Value::Null,
+ };
+ }
+
+ if let Some(children) = node.children() {
+ let children_val = kdl_to_json(children);
+ if let serde_json::Value::Object(children_map) = children_val {
+ if let serde_json::Value::Object(mut nm) = node_val {
+ for (k, v) in children_map {
+ nm.insert(k, v);
+ }
+ serde_json::Value::Object(nm)
} else {
- serde_json::Value::Null
+ serde_json::Value::Object(children_map)
}
+ } else {
+ node_val
}
- kdl::KdlValue::String(s) |
- kdl::KdlValue::RawString(s) => serde_json::Value::String(s.clone()),
- kdl::KdlValue::Null => serde_json::Value::Null,
+ } else {
+ node_val
}
- } else {
- serde_json::Value::Null
};
if let Some(existing) = map.remove(&name) {
@@ -235,7 +252,7 @@ pub fn parse_config_path(key: &str, default_section: &str) -> (String, String, O
const PROP_NODES: &[&str] = &[
"gestures", "key_bindings", "pointer_bind", "gesture_bind",
"button", "button_strip", "dropdown", "toggle", "spinbox", "slider", "font_selector",
- "status", "overlay", "backplate", "desktop", "list", "section", "textbox", "editor", "tree"
+ "status", "overlay", "backplate", "desktop", "list", "section", "textbox", "multiline", "editor", "tree"
];
fn get_or_create_node_mut<'a>(doc: &'a mut kdl::KdlDocument, path: &[&str]) -> Option<&'a mut kdl::KdlNode> {
diff --git a/src/layout.rs b/src/layout.rs
index 1ca82a2..2a92e65 100644
--- a/src/layout.rs
+++ b/src/layout.rs
@@ -106,7 +106,7 @@ fn flatten_json_to_flat_props(val: &serde_json::Value, prefix: &str, flat_props:
"style.control.spinbox.button_padding" => "spinbox_button_padding",
"style.control.spinbox.corner_radius" => "spinbox_corner_radius",
"style.textbox.height" | "style.data.textbox.height" => "textbox_height",
- "style.textbox.line_wrap" | "style.data.textbox.line_wrap" => "textbox_line_wrap",
+ "style.textbox.multiline.line_wrap" | "style.data.textbox.multiline.line_wrap" => "textbox_line_wrap",
"style.control.toggle.font" => "toggle_font",
"style.control.toggle.height" => "toggle_height",
"style.control.toggle.border_width" => "toggle_border_width",
diff --git a/src/widget/input/text_box.rs b/src/widget/input/text_box.rs
index deba499..ce479e2 100644
--- a/src/widget/input/text_box.rs
+++ b/src/widget/input/text_box.rs
@@ -153,7 +153,7 @@ impl TextBox {
let mut current_line = Vec::new();
let mut index_map = vec![(0, 0); chars.len() + 1];
- if !crate::layout::textbox_line_wrap() {
+ if !self.line_wrap_enabled() {
let mut i = 0;
while i < chars.len() {
let ch = chars[i];
@@ -291,6 +291,10 @@ impl TextBox {
changed
}
+ pub fn line_wrap_enabled(&self) -> bool {
+ self.multiline && crate::layout::textbox_line_wrap()
+ }
+
pub fn with_max_width(mut self, max_w: Option<f32>) -> Self {
self.max_width = max_w;
self
@@ -397,12 +401,8 @@ impl TextBox {
pub fn clamp_scroll(&mut self) {
let char_width = self.char_width();
let line_height = self.line_height();
- let max_chars = if self.multiline {
- if crate::layout::textbox_line_wrap() {
- (((self.base.w - 16.0) / char_width).floor() as usize).max(1)
- } else {
- 999999
- }
+ let max_chars = if self.line_wrap_enabled() {
+ (((self.base.w - 16.0) / char_width).floor() as usize).max(1)
} else {
999999
};
@@ -421,7 +421,7 @@ impl TextBox {
self.scroll_y = 0.0;
}
- if !crate::layout::textbox_line_wrap() {
+ if !self.line_wrap_enabled() {
let max_line_len = lines.iter().map(|l| l.chars().count()).max().unwrap_or(0);
let content_w = max_line_len as f32 * char_width;
let max_scroll_x = (content_w - (self.base.w - 16.0)).max(0.0);
@@ -434,12 +434,8 @@ impl TextBox {
pub fn scroll_to_cursor(&mut self) {
let char_width = self.char_width();
let line_height = self.line_height();
- let max_chars = if self.multiline {
- if crate::layout::textbox_line_wrap() {
- (((self.base.w - 16.0) / char_width).floor() as usize).max(1)
- } else {
- 999999
- }
+ let max_chars = if self.line_wrap_enabled() {
+ (((self.base.w - 16.0) / char_width).floor() as usize).max(1)
} else {
999999
};
@@ -471,7 +467,7 @@ impl TextBox {
}
}
- if !crate::layout::textbox_line_wrap() {
+ if !self.line_wrap_enabled() {
let cursor_x = col_idx as f32 * char_width;
if cursor_x < self.scroll_x + 10.0 {
self.scroll_x = (cursor_x - 20.0).max(0.0);
@@ -672,7 +668,7 @@ impl Element for TextBox {
let char_width = self.char_width();
let drag_idx = if self.multiline {
let line_height = self.line_height();
- let max_chars = if crate::layout::textbox_line_wrap() {
+ let max_chars = if self.line_wrap_enabled() {
(((self.base.w - 16.0) / char_width).floor() as usize).max(1)
} else {
999999
@@ -718,7 +714,7 @@ impl Element for TextBox {
let top = self.base.label_offset();
let drag_idx = if self.multiline {
let line_height = self.line_height();
- let max_chars = if crate::layout::textbox_line_wrap() {
+ let max_chars = if self.line_wrap_enabled() {
(((self.base.w - 16.0) / char_width).floor() as usize).max(1)
} else {
999999
@@ -770,7 +766,7 @@ impl Element for TextBox {
let top = self.base.label_offset();
let idx = if self.multiline {
let line_height = self.line_height();
- let max_chars = if crate::layout::textbox_line_wrap() {
+ let max_chars = if self.line_wrap_enabled() {
(((self.base.w - 16.0) / char_width).floor() as usize).max(1)
} else {
999999
@@ -1030,7 +1026,7 @@ impl Element for TextBox {
let end = self.select_anchor.unwrap_or(self.cursor_idx).max(self.cursor_idx);
if self.multiline {
- let max_chars = if crate::layout::textbox_line_wrap() {
+ let max_chars = if self.line_wrap_enabled() {
(((self.base.w - 16.0) / char_width).floor() as usize).max(1)
} else {
999999
@@ -1181,7 +1177,7 @@ impl Element for TextBox {
let end = self.select_anchor.unwrap_or(self.cursor_idx).max(self.cursor_idx);
if self.multiline {
- let max_chars = if crate::layout::textbox_line_wrap() {
+ let max_chars = if self.line_wrap_enabled() {
(((self.base.w - 16.0) / char_width).floor() as usize).max(1)
} else {
999999
@@ -1323,7 +1319,7 @@ impl Element for TextBox {
if self.multiline {
let char_width = self.char_width();
let line_height = self.line_height();
- let max_chars = if crate::layout::textbox_line_wrap() {
+ let max_chars = if self.line_wrap_enabled() {
(((self.base.w - 16.0) / char_width).floor() as usize).max(1)
} else {
999999
@@ -1340,7 +1336,7 @@ impl Element for TextBox {
current_line.clear();
} else {
current_line.push(ch);
- if crate::layout::textbox_line_wrap() && current_line.len() > max_chars {
+ if self.line_wrap_enabled() && current_line.len() > max_chars {
p_lines.push(current_line.iter().collect::<String>());
current_line.clear();
}
@@ -1388,12 +1384,8 @@ impl Element for TextBox {
let char_width = self.char_width();
let line_height = self.line_height();
- let max_chars = if self.multiline {
- if crate::layout::textbox_line_wrap() {
- (((self.base.w - 16.0) / char_width).floor() as usize).max(1)
- } else {
- 999999
- }
+ let max_chars = if self.line_wrap_enabled() {
+ (((self.base.w - 16.0) / char_width).floor() as usize).max(1)
} else {
999999
};
@@ -1421,7 +1413,7 @@ impl Element for TextBox {
}
}
- if !crate::layout::textbox_line_wrap() {
+ if !self.line_wrap_enabled() {
let max_line_len = lines.iter().map(|l| l.chars().count()).max().unwrap_or(0);
let content_w = max_line_len as f32 * char_width;
let max_scroll_x = (content_w - (self.base.w - 16.0)).max(0.0);