/ bin / app / src / app / schema / settings.rs
settings.rs
   1  /* This file is part of DarkFi (https://dark.fi)
   2   *
   3   * Copyright (C) 2020-2024 Dyne.org foundation
   4   *
   5   * This program is free software: you can redistribute it and/or modify
   6   * it under the terms of the GNU Affero General Public License as
   7   * published by the Free Software Foundation, either version 3 of the
   8   * License, or (at your option) any later version.
   9   *
  10   * This program is distributed in the hope that it will be useful,
  11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13   * GNU Affero General Public License for more details.
  14   *
  15   * You should have received a copy of the GNU Affero General Public License
  16   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  17   */
  18  
  19  use crate::{
  20      app::{
  21          node::{create_button, create_editbox, create_layer, create_text, create_vector_art},
  22          App,
  23      },
  24      expr::{self, Compiler},
  25      prop::{PropertyAtomicGuard, PropertyFloat32, PropertyStr, PropertyValue, Role},
  26      scene::{SceneNodePtr, Slot},
  27      shape,
  28      ui::{Button, EditBox, Layer, ShapeVertex, Text, VectorArt, VectorShape},
  29      ExecutorPtr,
  30  };
  31  
  32  use super::{ColorScheme, COLOR_SCHEME};
  33  
  34  use std::{
  35      collections::BTreeMap,
  36      sync::{Arc, Mutex},
  37  };
  38  
  39  #[cfg(any(target_os = "android", feature = "emulate-android"))]
  40  mod android_ui_consts {
  41      pub const SETTING_LABEL_X: f32 = 40.;
  42      pub const SETTING_LABEL_LINESPACE: f32 = 140.;
  43      pub const SETTING_LABEL_BASELINE: f32 = 82.;
  44      pub const SETTING_LABEL_FONTSIZE: f32 = 24.;
  45      pub const SETTING_EDIT_FONTSIZE: f32 = 24.;
  46      pub const SETTING_TITLE_X: f32 = 150.;
  47      pub const SETTING_TITLE_FONTSIZE: f32 = 40.;
  48      pub const SETTING_TITLE_BASELINE: f32 = 82.;
  49      pub const SEARCH_PADDING_X: f32 = 120.;
  50      pub const BORDER_RIGHT_SCALE: f32 = 5.;
  51      pub const CURSOR_ASCENT: f32 = 50.;
  52      pub const CURSOR_DESCENT: f32 = 20.;
  53      pub const SELECT_ASCENT: f32 = 50.;
  54      pub const SELECT_DESCENT: f32 = 20.;
  55  
  56      pub const BACKARROW_SCALE: f32 = 30.;
  57      pub const BACKARROW_X: f32 = 50.;
  58      pub const BACKARROW_Y: f32 = 70.;
  59      pub const BACKARROW_BG_W: f32 = 120.;
  60  }
  61  
  62  #[cfg(target_os = "android")]
  63  mod ui_consts {
  64      pub use super::android_ui_consts::*;
  65  }
  66  
  67  #[cfg(feature = "emulate-android")]
  68  mod ui_consts {
  69      pub use super::android_ui_consts::*;
  70  }
  71  
  72  #[cfg(all(
  73      any(target_os = "linux", target_os = "macos", target_os = "windows"),
  74      not(feature = "emulate-android")
  75  ))]
  76  mod ui_consts {
  77      pub const SETTING_LABEL_X: f32 = 20.;
  78      pub const SETTING_LABEL_LINESPACE: f32 = 60.;
  79      pub const SETTING_LABEL_BASELINE: f32 = 37.;
  80      pub const SETTING_LABEL_FONTSIZE: f32 = 14.;
  81      pub const SETTING_EDIT_FONTSIZE: f32 = 14.;
  82      pub const SETTING_TITLE_X: f32 = 100.;
  83      pub const SETTING_TITLE_FONTSIZE: f32 = 20.;
  84      pub const SETTING_TITLE_BASELINE: f32 = 37.;
  85      pub const SEARCH_PADDING_X: f32 = 80.;
  86      pub const BORDER_RIGHT_SCALE: f32 = 10.;
  87      pub const CURSOR_ASCENT: f32 = 24.;
  88      pub const CURSOR_DESCENT: f32 = 8.;
  89      pub const SELECT_ASCENT: f32 = 30.;
  90      pub const SELECT_DESCENT: f32 = 10.;
  91  
  92      pub const BACKARROW_SCALE: f32 = 15.;
  93      pub const BACKARROW_X: f32 = 38.;
  94      pub const BACKARROW_Y: f32 = 26.;
  95      pub const BACKARROW_BG_W: f32 = 80.;
  96  }
  97  
  98  use ui_consts::*;
  99  
 100  #[derive(Clone)]
 101  struct Setting {
 102      name: String,
 103      node: SceneNodePtr,
 104  }
 105  
 106  impl Setting {
 107      fn value_as_string(&self) -> String {
 108          match &self.node.get_property("value").unwrap().get_value(0).ok().unwrap() {
 109              PropertyValue::Str(s) => s.clone(),
 110              PropertyValue::Uint32(i) => i.to_string(),
 111              PropertyValue::Bool(b) => {
 112                  if *b {
 113                      "TRUE".to_string()
 114                  } else {
 115                      "FALSE".to_string()
 116                  }
 117              }
 118              PropertyValue::Float32(fl) => fl.to_string(),
 119              _ => "unknown".to_string(),
 120          }
 121      }
 122      fn get_value(&self) -> PropertyValue {
 123          self.node.get_property("value").unwrap().get_value(0).ok().unwrap()
 124      }
 125      fn get_default(&self) -> PropertyValue {
 126          self.node.get_property("default").unwrap().get_value(0).ok().unwrap()
 127      }
 128      fn is_default(&self) -> bool {
 129          self.get_value() == self.get_default()
 130      }
 131      fn reset(&self) {
 132          let prop = self.node.get_property("value").unwrap();
 133          prop.set_raw_value(Role::App, 0, self.get_default()).unwrap();
 134      }
 135  }
 136  
 137  pub async fn make(app: &App, window: SceneNodePtr, _ex: ExecutorPtr) {
 138      let mut cc = Compiler::new();
 139      cc.add_const_f32("BORDER_RIGHT_SCALE", BORDER_RIGHT_SCALE);
 140      cc.add_const_f32("SEARCH_PADDING_X", SEARCH_PADDING_X);
 141      cc.add_const_f32("X_RATIO", 1. / 2.);
 142      let window_scale = PropertyFloat32::wrap(
 143          &app.sg_root.lookup_node("/setting/scale").unwrap(),
 144          Role::Internal,
 145          "value",
 146          0,
 147      )
 148      .unwrap();
 149      let atom = &mut PropertyAtomicGuard::new();
 150  
 151      // Main view
 152      let layer_node = create_layer("settings_layer");
 153      let prop = layer_node.get_property("rect").unwrap();
 154      prop.set_f32(atom, Role::App, 0, 0.).unwrap();
 155      prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 156      prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap();
 157      prop.set_expr(atom, Role::App, 3, expr::load_var("h")).unwrap();
 158      layer_node.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
 159      layer_node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 160      let layer_node =
 161          layer_node.setup(|me| Layer::new(me, app.render_api.clone(), app.ex.clone())).await;
 162      window.link(layer_node.clone());
 163  
 164      let mut setting_y = 0.;
 165  
 166      // Create the toolbar bg
 167      let node = create_vector_art("toolbar_bg");
 168      let prop = node.get_property("rect").unwrap();
 169      prop.set_f32(atom, Role::App, 0, 0.).unwrap();
 170      prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 171      prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap();
 172      prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 173      node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
 174  
 175      let (bg_color, sep_color) = match COLOR_SCHEME {
 176          ColorScheme::DarkMode => ([0., 0.11, 0.11, 1.], [0.41, 0.6, 0.65, 1.]),
 177          ColorScheme::PaperLight => ([1., 1., 1., 1.], [0., 0.6, 0.65, 1.]),
 178      };
 179      let mut shape = VectorShape::new();
 180      shape.add_filled_box(
 181          expr::const_f32(0.),
 182          expr::const_f32(0.),
 183          expr::const_f32(BACKARROW_BG_W),
 184          expr::load_var("h"),
 185          bg_color,
 186      );
 187      shape.add_filled_box(
 188          expr::const_f32(BACKARROW_BG_W),
 189          expr::const_f32(0.),
 190          expr::const_f32(BACKARROW_BG_W + 1.),
 191          expr::load_var("h"),
 192          sep_color,
 193      );
 194      shape.add_filled_box(
 195          expr::const_f32(0.),
 196          expr::load_var("h"),
 197          expr::load_var("w"),
 198          cc.compile("h + 1").unwrap(),
 199          sep_color,
 200      );
 201  
 202      let node =
 203          node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
 204      layer_node.link(node);
 205  
 206      // Create the back button
 207      let node = create_vector_art("back_btn_bg");
 208      let prop = node.get_property("rect").unwrap();
 209      prop.set_f32(atom, Role::App, 0, BACKARROW_X).unwrap();
 210      prop.set_f32(atom, Role::App, 1, BACKARROW_Y).unwrap();
 211      prop.set_f32(atom, Role::App, 2, 0.).unwrap();
 212      prop.set_f32(atom, Role::App, 3, 0.).unwrap();
 213      node.set_property_u32(atom, Role::App, "z_index", 3).unwrap();
 214  
 215      let shape = shape::create_back_arrow().scaled(BACKARROW_SCALE);
 216      let node =
 217          node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
 218      layer_node.link(node);
 219  
 220      let node = create_button("back_btn");
 221      node.set_property_bool(atom, Role::App, "is_active", true).unwrap();
 222      let prop = node.get_property("rect").unwrap();
 223      prop.set_f32(atom, Role::App, 0, 0.).unwrap();
 224      prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 225      prop.set_f32(atom, Role::App, 2, BACKARROW_BG_W).unwrap();
 226      prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 227  
 228      let sg_root = app.sg_root.clone();
 229      let goback = move || {
 230          let atom = &mut PropertyAtomicGuard::new();
 231  
 232          // Disable visilibity of all relevant window nodes
 233          // This is needed since for example all chats have a different node name.
 234          let windows = sg_root.lookup_node("/window").unwrap().get_children();
 235          let target_substrings = vec!["_chat_layer", "menu_layer", "settings_layer"];
 236  
 237          for node in windows.iter() {
 238              // Check if the node's name contains any of the target substrings
 239              if target_substrings.iter().any(|&s| node.name.contains(s)) {
 240                  if let Err(e) = node.set_property_bool(atom, Role::App, "is_visible", false) {
 241                      debug!("Failed to set property 'is_visible' on node: {:?}", e);
 242                  }
 243              }
 244          }
 245  
 246          // Go back to the dev channel
 247          let menu_node = sg_root.lookup_node("/window/dev_chat_layer").unwrap();
 248          menu_node.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
 249      };
 250  
 251      let (slot, recvr) = Slot::new("back_clicked");
 252      node.register("click", slot).unwrap();
 253      let goback2 = goback.clone();
 254      let listen_click = app.ex.spawn(async move {
 255          while let Ok(_) = recvr.recv().await {
 256              goback2();
 257          }
 258      });
 259      app.tasks.lock().unwrap().push(listen_click);
 260  
 261      let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
 262      layer_node.link(node.clone());
 263  
 264      // Label: "SETTINGS" title
 265      let node = create_text("settings_label_fontsize");
 266      let prop = node.get_property("rect").unwrap();
 267      prop.set_f32(atom, Role::App, 0, SETTING_TITLE_X).unwrap();
 268      prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 269      prop.set_f32(atom, Role::App, 2, 1000.).unwrap();
 270      prop.set_f32(atom, Role::App, 3, 200.).unwrap();
 271      node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 272      node.set_property_f32(atom, Role::App, "baseline", SETTING_TITLE_BASELINE).unwrap();
 273      node.set_property_f32(atom, Role::App, "font_size", SETTING_TITLE_FONTSIZE).unwrap();
 274      node.set_property_str(atom, Role::App, "text", "SETTINGS").unwrap();
 275      node.set_property_f32_vec(atom, Role::App, "text_color", vec![1., 1., 1., 1.]).unwrap();
 276      node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 277  
 278      let node = node
 279          .setup(|me| {
 280              Text::new(
 281                  me,
 282                  window_scale.clone(),
 283                  app.render_api.clone(),
 284                  app.text_shaper.clone(),
 285                  app.ex.clone(),
 286              )
 287          })
 288          .await;
 289      layer_node.link(node);
 290  
 291      // Search Bar Background
 292      let node = create_vector_art("emoji_picker_bg");
 293      let prop = node.get_property("rect").unwrap();
 294      prop.set_f32(atom, Role::App, 0, 0.).unwrap();
 295      let code = cc.compile("100").unwrap();
 296      prop.set_expr(atom, Role::App, 1, code).unwrap();
 297      prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap();
 298      prop.set_expr(atom, Role::App, 3, expr::load_var("50")).unwrap();
 299      //prop.add_depend(&emoji_dynamic_h_prop, 0, "dynamic_h");
 300      node.set_property_u32(atom, Role::App, "z_index", 4).unwrap();
 301  
 302      let mut shape = VectorShape::new();
 303  
 304      // Top line
 305      shape.add_filled_box(
 306          expr::const_f32(0.),
 307          expr::const_f32(80.),
 308          expr::load_var("w"),
 309          expr::const_f32(1.),
 310          [0.41, 0.6, 0.65, 1.],
 311      );
 312  
 313      let node =
 314          node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
 315      layer_node.link(node);
 316  
 317      // Search Bar Input
 318      let editbox_node = create_editbox("search_input");
 319      editbox_node.set_property_bool(atom, Role::App, "is_active", true).unwrap();
 320      editbox_node.set_property_bool(atom, Role::App, "is_focused", true).unwrap();
 321      let prop = editbox_node.get_property("rect").unwrap();
 322      prop.set_f32(atom, Role::App, 0, SEARCH_PADDING_X).unwrap();
 323      prop.set_expr(atom, Role::App, 1, cc.compile("60 + 20").unwrap()).unwrap();
 324      prop.clone()
 325          .set_expr(atom, Role::App, 2, cc.compile("w - SEARCH_PADDING_X*2").unwrap())
 326          .unwrap();
 327      prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 328      editbox_node.set_property_f32_vec(atom, Role::App, "text_color", vec![1., 1., 1., 1.]).unwrap();
 329      let prop = editbox_node.get_property("cursor_color").unwrap();
 330      prop.set_f32(atom, Role::App, 0, 0.5).unwrap();
 331      prop.set_f32(atom, Role::App, 1, 0.5).unwrap();
 332      prop.set_f32(atom, Role::App, 2, 0.5).unwrap();
 333      prop.set_f32(atom, Role::App, 3, 1.).unwrap();
 334      editbox_node.set_property_f32(atom, Role::App, "cursor_ascent", CURSOR_ASCENT).unwrap();
 335      editbox_node.set_property_f32(atom, Role::App, "cursor_descent", CURSOR_DESCENT).unwrap();
 336      editbox_node.set_property_f32(atom, Role::App, "select_ascent", SELECT_ASCENT).unwrap();
 337      editbox_node.set_property_f32(atom, Role::App, "select_descent", SELECT_DESCENT).unwrap();
 338      editbox_node
 339          .set_property_f32_vec(atom, Role::App, "hi_bg_color", vec![0.5, 0.5, 0.5, 1.])
 340          .unwrap();
 341      let prop = editbox_node.get_property("selected").unwrap();
 342      prop.set_null(atom, Role::App, 0).unwrap();
 343      prop.set_null(atom, Role::App, 1).unwrap();
 344      editbox_node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
 345      editbox_node.set_property_bool(atom, Role::App, "is_active", true).unwrap();
 346      editbox_node.set_property_bool(atom, Role::App, "is_focused", true).unwrap();
 347      editbox_node.set_property_f32(atom, Role::App, "font_size", 16.).unwrap();
 348      editbox_node.set_property_f32(atom, Role::App, "baseline", 16.).unwrap();
 349  
 350      // Search icon
 351      let node = create_vector_art("search_icon");
 352      let prop = node.get_property("rect").unwrap();
 353      prop.set_f32(atom, Role::App, 0, BACKARROW_X).unwrap();
 354      prop.clone()
 355          .set_f32(atom, Role::App, 1, SETTING_LABEL_LINESPACE + SETTING_LABEL_LINESPACE / 2.)
 356          .unwrap();
 357      prop.set_f32(atom, Role::App, 2, 0.).unwrap();
 358      prop.set_f32(atom, Role::App, 3, 0.).unwrap();
 359      node.set_property_u32(atom, Role::App, "z_index", 3).unwrap();
 360  
 361      let shape = shape::create_logo([1., 1., 1., 1.]).scaled(500.);
 362      let node =
 363          node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
 364      layer_node.link(node);
 365  
 366      // Search placeholder
 367      let node = create_text("search_label");
 368      let prop = node.get_property("rect").unwrap();
 369      prop.set_f32(atom, Role::App, 0, SEARCH_PADDING_X).unwrap();
 370      prop.set_expr(atom, Role::App, 1, cc.compile("60 + 20").unwrap()).unwrap();
 371      prop.set_f32(atom, Role::App, 2, 1000.).unwrap();
 372      prop.set_f32(atom, Role::App, 3, 200.).unwrap();
 373      node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 374      node.set_property_f32(atom, Role::App, "baseline", 16.).unwrap();
 375      node.set_property_f32(atom, Role::App, "font_size", 16.).unwrap();
 376      node.set_property_str(atom, Role::App, "text", "SEARCH...").unwrap();
 377      node.set_property_f32_vec(atom, Role::App, "text_color", vec![1., 1., 1., 0.45]).unwrap();
 378      node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 379  
 380      let node = node
 381          .setup(|me| {
 382              Text::new(
 383                  me,
 384                  window_scale.clone(),
 385                  app.render_api.clone(),
 386                  app.text_shaper.clone(),
 387                  app.ex.clone(),
 388              )
 389          })
 390          .await;
 391      layer_node.link(node);
 392  
 393      // Search settings counter
 394      let node = create_text("search_count");
 395      let prop = node.get_property("rect").unwrap();
 396      prop.set_expr(atom, Role::App, 0, cc.compile("w - 50").unwrap()).unwrap();
 397      prop.set_expr(atom, Role::App, 1, cc.compile("60 + 20").unwrap()).unwrap();
 398      prop.set_f32(atom, Role::App, 2, 1000.).unwrap();
 399      prop.set_f32(atom, Role::App, 3, 200.).unwrap();
 400      node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 401      node.set_property_f32(atom, Role::App, "baseline", 16.).unwrap();
 402      node.set_property_f32(atom, Role::App, "font_size", 16.).unwrap();
 403      node.set_property_str(atom, Role::App, "text", "").unwrap();
 404      node.set_property_f32_vec(atom, Role::App, "text_color", vec![0., 0.94, 1., 1.]).unwrap();
 405      node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 406  
 407      let node = node
 408          .setup(|me| {
 409              Text::new(
 410                  me,
 411                  window_scale.clone(),
 412                  app.render_api.clone(),
 413                  app.text_shaper.clone(),
 414                  app.ex.clone(),
 415              )
 416          })
 417          .await;
 418      layer_node.link(node);
 419  
 420      let sg_root3 = app.sg_root.clone();
 421      let search = move || {
 422          let atom = &mut PropertyAtomicGuard::new();
 423  
 424          let path = "/window/settings_layer/search_input";
 425          let node = sg_root3.lookup_node(path.to_string()).unwrap();
 426          let search_string = node.get_property_str("text").unwrap();
 427  
 428          let path = "/window/settings_layer/search_label";
 429          let search_label_node = sg_root3.lookup_node(path.to_string()).unwrap();
 430  
 431          if search_string.len() > 0 {
 432              let _ = search_label_node.set_property_f32(atom, Role::App, "font_size", 0.);
 433          } else {
 434              let _ = search_label_node.set_property_f32(atom, Role::App, "font_size", 16.);
 435          }
 436  
 437          let path = "/window/settings_layer/settings";
 438          let node = sg_root3.lookup_node(path.to_string()).unwrap();
 439          let setting_nodes = node.get_children();
 440          let mut found_nodes = Vec::new();
 441  
 442          // Iterate through the nodes
 443          for node in setting_nodes.iter() {
 444              // Hide all nodes initially, no matter what
 445              let _ = node.set_property_bool(atom, Role::App, "is_visible", false);
 446  
 447              // Check if the node matches the search string
 448              if node.name.contains(&search_string.to_string()) {
 449                  found_nodes.push(node); // Store matching nodes
 450                  if let Err(e) = node.set_property_bool(atom, Role::App, "is_visible", true) {
 451                      debug!("Failed to set property 'is_visible' on node: {:?}", e);
 452                  }
 453              }
 454          }
 455  
 456          // Set the `rect` property for each found node
 457          for (i, node) in found_nodes.iter().enumerate() {
 458              let prop = node.get_property("rect").unwrap();
 459              let y = i as f32 * 60. + 60. + 60.;
 460              prop.set_f32(atom, Role::App, 1, y).unwrap();
 461          }
 462  
 463          // Update the counter
 464          let counter_text = found_nodes.len().to_string();
 465          let path = "/window/settings_layer/search_count";
 466          let node = sg_root3.lookup_node(path.to_string()).unwrap();
 467          let _ = node.set_property_str(atom, Role::App, "text", &counter_text).unwrap();
 468      };
 469  
 470      // Handle searching
 471      let search_text = editbox_node.get_property("text").unwrap();
 472      let search_text_sub = search_text.subscribe_modify();
 473      let search2 = search.clone();
 474      let listen_search_text = app.ex.spawn(async move {
 475          while let Ok(_) = search_text_sub.receive().await {
 476              search2();
 477          }
 478      });
 479      app.tasks.lock().unwrap().push(listen_search_text);
 480  
 481      let node = editbox_node
 482          .setup(|me| {
 483              EditBox::new(
 484                  me,
 485                  window_scale.clone(),
 486                  app.render_api.clone(),
 487                  app.text_shaper.clone(),
 488                  app.ex.clone(),
 489              )
 490          })
 491          .await;
 492      layer_node.link(node);
 493  
 494      // Search background
 495      let node = create_vector_art("search_bg");
 496      let prop = node.get_property("rect").unwrap();
 497      prop.set_f32(atom, Role::App, 0, 0.).unwrap();
 498      prop.set_f32(atom, Role::App, 1, 60.).unwrap();
 499      prop.set_expr(atom, Role::App, 2, cc.compile("w  * 100").unwrap()).unwrap();
 500      prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 501      node.set_property_u32(atom, Role::App, "z_index", 0).unwrap();
 502  
 503      let mut shape = VectorShape::new();
 504  
 505      let x1 = expr::const_f32(0.);
 506      let y1 = expr::const_f32(0.);
 507      let x2 = expr::load_var("w");
 508      let y2 = expr::const_f32(SETTING_LABEL_LINESPACE);
 509      let (color1, color2) = match COLOR_SCHEME {
 510          ColorScheme::DarkMode => ([0., 0.11, 0.11, 0.4], [0., 0.11, 0.11, 0.5]),
 511          ColorScheme::PaperLight => ([1., 1., 1., 1.], [1., 1., 1., 1.]),
 512      };
 513      let mut verts = vec![
 514          ShapeVertex::new(x1.clone(), y1.clone(), color1),
 515          ShapeVertex::new(x2.clone(), y1.clone(), color1),
 516          ShapeVertex::new(x1.clone(), y2.clone(), color2),
 517          ShapeVertex::new(x2, y2, color2),
 518      ];
 519      let mut indices = vec![0, 2, 1, 1, 2, 3];
 520      shape.verts.append(&mut verts);
 521      shape.indices.append(&mut indices);
 522  
 523      shape.add_filled_box(
 524          expr::const_f32(0.),
 525          expr::const_f32(SETTING_LABEL_LINESPACE - 1.),
 526          expr::load_var("w"),
 527          expr::const_f32(SETTING_LABEL_LINESPACE),
 528          [0.15, 0.2, 0.19, 1.],
 529          //[0., 0.11, 0.11, 0.4],
 530      );
 531  
 532      let node =
 533          node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
 534      layer_node.link(node);
 535  
 536      let node = create_vector_art("search_bg2");
 537      let prop = node.get_property("rect").unwrap();
 538      prop.set_f32(atom, Role::App, 0, 0.).unwrap();
 539      prop.set_f32(atom, Role::App, 1, 60.).unwrap();
 540      prop.set_expr(atom, Role::App, 2, cc.compile("w  * 100").unwrap()).unwrap();
 541      prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE / 3.5).unwrap();
 542      node.set_property_u32(atom, Role::App, "z_index", 0).unwrap();
 543  
 544      let mut shape = VectorShape::new();
 545  
 546      let x1 = expr::const_f32(0.);
 547      let y1 = expr::const_f32(0.);
 548      let x2 = expr::load_var("w");
 549      let y2 = expr::const_f32(SETTING_LABEL_LINESPACE);
 550  
 551      let (color1, color2) = match COLOR_SCHEME {
 552          ColorScheme::DarkMode => ([0., 0.94, 1., 0.4], [0., 0.3, 0.25, 0.0]),
 553          ColorScheme::PaperLight => ([0., 0.94, 1., 0.4], [0., 0.3, 0.25, 0.0]),
 554      };
 555  
 556      let mut verts = vec![
 557          ShapeVertex::new(x1.clone(), y1.clone(), color1),
 558          ShapeVertex::new(x2.clone(), y1.clone(), color1),
 559          ShapeVertex::new(x1.clone(), y2.clone(), color2),
 560          ShapeVertex::new(x2, y2, color2),
 561      ];
 562      let mut indices = vec![0, 2, 1, 1, 2, 3];
 563      shape.verts.append(&mut verts);
 564      shape.indices.append(&mut indices);
 565  
 566      shape.add_filled_box(
 567          expr::const_f32(0.),
 568          expr::const_f32(SETTING_LABEL_LINESPACE - 1.),
 569          expr::load_var("w"),
 570          expr::const_f32(SETTING_LABEL_LINESPACE),
 571          [0.15, 0.2, 0.19, 1.],
 572      );
 573  
 574      let node =
 575          node.setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone())).await;
 576      layer_node.link(node);
 577  
 578      // Create a BTreeMap to store settings
 579      let mut settings_map: BTreeMap<String, Arc<Setting>> = BTreeMap::new();
 580  
 581      // Get the app settings
 582      let app_setting_root = app.sg_root.lookup_node("/setting").unwrap();
 583      for setting in app_setting_root.get_children().iter() {
 584          let name = ["app", &setting.name.clone()].join(".");
 585          settings_map.insert(name.clone(), Arc::new(Setting { name, node: setting.clone() }));
 586      }
 587  
 588      // Get the settings from all plugins
 589      let sg_root_children = app.sg_root.clone().get_children();
 590      let plugin_node = sg_root_children.iter().find(|node| node.name == "plugin");
 591      if let Some(pnode) = plugin_node {
 592          for plugin in pnode.get_children().iter() {
 593              let plugin_children = plugin.get_children();
 594              let setting_root = plugin_children.iter().find(|node| node.name == "setting");
 595              if let Some(sroot) = setting_root {
 596                  for setting in sroot.get_children().iter() {
 597                      let name = [plugin.name.clone(), setting.name.clone()].join(".");
 598                      settings_map
 599                          .insert(name.clone(), Arc::new(Setting { name, node: setting.clone() }));
 600                  }
 601              }
 602          }
 603      }
 604  
 605      // Setting currently being edited
 606      let active_setting: Arc<Mutex<Option<Arc<Setting>>>> = Arc::new(Mutex::new(None));
 607  
 608      // Setting Layer
 609      // Contain a setting
 610      let settings_layer_node = create_layer("settings");
 611      let prop = settings_layer_node.get_property("rect").unwrap();
 612      prop.set_f32(atom, Role::App, 0, 0.).unwrap();
 613      prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 614      prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap();
 615      prop.set_f32(atom, Role::App, 3, 0.).unwrap();
 616      settings_layer_node.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
 617      settings_layer_node.set_property_u32(atom, Role::App, "z_index", 0).unwrap();
 618      let settings_layer_node = settings_layer_node
 619          .setup(|me| Layer::new(me, app.render_api.clone(), app.ex.clone()))
 620          .await;
 621      layer_node.link(settings_layer_node.clone());
 622  
 623      // Iterate over the map and process each setting
 624      for setting in settings_map.values() {
 625          let setting_clone = setting.clone();
 626          let setting_name = setting_clone.name.clone();
 627          let is_bool = matches!(setting_clone.get_value(), PropertyValue::Bool(_));
 628  
 629          setting_y += SETTING_LABEL_LINESPACE;
 630  
 631          // Setting Layer
 632          // Contain a setting
 633          let setting_layer_node = create_layer(&setting_name.to_string());
 634          let prop = setting_layer_node.get_property("rect").unwrap();
 635          prop.set_f32(atom, Role::App, 0, 0.).unwrap();
 636          prop.set_f32(atom, Role::App, 1, setting_y + 60.).unwrap();
 637          prop.set_expr(atom, Role::App, 2, expr::load_var("w")).unwrap();
 638          prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 639          setting_layer_node.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
 640          setting_layer_node.set_property_u32(atom, Role::App, "z_index", 0).unwrap();
 641          let setting_layer_node = setting_layer_node
 642              .setup(|me| Layer::new(me, app.render_api.clone(), app.ex.clone()))
 643              .await;
 644          settings_layer_node.link(setting_layer_node.clone());
 645  
 646          // Background Label
 647          let node = create_vector_art("key_bg");
 648          let prop = node.get_property("rect").unwrap();
 649          prop.set_f32(atom, Role::App, 0, 0.).unwrap();
 650          prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 651          prop.clone()
 652              .set_expr(atom, Role::App, 2, cc.compile("w  * X_RATIO - BORDER_RIGHT_SCALE").unwrap())
 653              .unwrap();
 654          prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 655          node.set_property_u32(atom, Role::App, "z_index", 0).unwrap();
 656  
 657          let mut shape = VectorShape::new();
 658  
 659          let x1 = expr::const_f32(0.);
 660          let y1 = expr::const_f32(0.);
 661          let x2 = expr::load_var("w");
 662          let y2 = expr::const_f32(SETTING_LABEL_LINESPACE);
 663          let (color1, color2) = match COLOR_SCHEME {
 664              //ColorScheme::DarkMode => ([0., 0.11, 0.11, 1.], [0., 0.11, 0.11, 1.]),
 665              ColorScheme::DarkMode => ([0., 0.11, 0.11, 0.4], [0., 0.11, 0.11, 0.5]),
 666              ColorScheme::PaperLight => ([1., 1., 1., 1.], [1., 1., 1., 1.]),
 667          };
 668          let mut verts = vec![
 669              ShapeVertex::new(x1.clone(), y1.clone(), color1),
 670              ShapeVertex::new(x2.clone(), y1.clone(), color1),
 671              ShapeVertex::new(x1.clone(), y2.clone(), color2),
 672              ShapeVertex::new(x2, y2, color2),
 673          ];
 674          let mut indices = vec![0, 2, 1, 1, 2, 3];
 675          shape.verts.append(&mut verts);
 676          shape.indices.append(&mut indices);
 677  
 678          shape.add_filled_box(
 679              expr::const_f32(0.),
 680              expr::const_f32(SETTING_LABEL_LINESPACE - 1.),
 681              expr::load_var("w"),
 682              expr::const_f32(SETTING_LABEL_LINESPACE),
 683              [0.15, 0.2, 0.19, 1.],
 684          );
 685  
 686          let node = node
 687              .setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone()))
 688              .await;
 689          setting_layer_node.link(node);
 690  
 691          if is_bool {
 692              // Background Value: Bool FALSE
 693              let node = create_vector_art("value_bg_bool_false");
 694              let prop = node.get_property("rect").unwrap();
 695              prop.clone()
 696                  .set_expr(
 697                      atom,
 698                      Role::App,
 699                      0,
 700                      cc.compile("w * X_RATIO - BORDER_RIGHT_SCALE").unwrap(),
 701                  )
 702                  .unwrap();
 703              prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 704              prop.clone()
 705                  .set_expr(
 706                      atom,
 707                      Role::App,
 708                      2,
 709                      cc.compile("w * (1-X_RATIO) + BORDER_RIGHT_SCALE").unwrap(),
 710                  )
 711                  .unwrap();
 712              prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 713              node.set_property_u32(atom, Role::App, "z_index", 0).unwrap();
 714              node.set_property_bool(
 715                  atom,
 716                  Role::App,
 717                  "is_visible",
 718                  matches!(setting_clone.get_value(), PropertyValue::Bool(false)),
 719              )
 720              .unwrap();
 721  
 722              let mut shape = VectorShape::new();
 723  
 724              let x1 = expr::const_f32(0.);
 725              let y1 = expr::const_f32(0.);
 726              let x2 = expr::load_var("w");
 727              let y2 = expr::const_f32(SETTING_LABEL_LINESPACE);
 728  
 729              let (color1, color2) = match COLOR_SCHEME {
 730                  //ColorScheme::DarkMode => ([0., 0.11, 0.11, 1.], [0., 0.11, 0.11, 1.]),
 731                  ColorScheme::DarkMode => ([0.0, 0.04, 0.04, 0.0], [0.7, 0.0, 0.0, 0.15]),
 732                  ColorScheme::PaperLight => ([0.0, 0.04, 0.04, 0.0], [0.7, 0.0, 0.0, 0.15]),
 733              };
 734  
 735              let mut verts = vec![
 736                  ShapeVertex::new(x1.clone(), y1.clone(), color1),
 737                  ShapeVertex::new(x2.clone(), y1.clone(), color1),
 738                  ShapeVertex::new(x1.clone(), y2.clone(), color2),
 739                  ShapeVertex::new(x2, y2, color2),
 740              ];
 741              let mut indices = vec![0, 2, 1, 1, 2, 3];
 742              shape.verts.append(&mut verts);
 743              shape.indices.append(&mut indices);
 744  
 745              shape.add_filled_box(
 746                  expr::const_f32(0.),
 747                  expr::const_f32(SETTING_LABEL_LINESPACE - 1.),
 748                  expr::load_var("w"),
 749                  expr::const_f32(SETTING_LABEL_LINESPACE),
 750                  [0.15, 0.2, 0.19, 1.],
 751              );
 752  
 753              let node = node
 754                  .setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone()))
 755                  .await;
 756              setting_layer_node.link(node);
 757  
 758              // Background Value: Bool TRUE
 759              let node = create_vector_art("value_bg_bool_true");
 760              let prop = node.get_property("rect").unwrap();
 761              prop.clone()
 762                  .set_expr(
 763                      atom,
 764                      Role::App,
 765                      0,
 766                      cc.compile("w * X_RATIO - BORDER_RIGHT_SCALE").unwrap(),
 767                  )
 768                  .unwrap();
 769              prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 770              prop.clone()
 771                  .set_expr(
 772                      atom,
 773                      Role::App,
 774                      2,
 775                      cc.compile("w * (1-X_RATIO) + BORDER_RIGHT_SCALE").unwrap(),
 776                  )
 777                  .unwrap();
 778              prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 779              node.set_property_u32(atom, Role::App, "z_index", 0).unwrap();
 780              node.set_property_bool(
 781                  atom,
 782                  Role::App,
 783                  "is_visible",
 784                  matches!(setting_clone.get_value(), PropertyValue::Bool(true)),
 785              )
 786              .unwrap();
 787  
 788              let mut shape = VectorShape::new();
 789  
 790              let x1 = expr::const_f32(0.);
 791              let y1 = expr::const_f32(0.);
 792              let x2 = expr::load_var("w");
 793              let y2 = expr::const_f32(SETTING_LABEL_LINESPACE);
 794  
 795              let (color1, color2) = match COLOR_SCHEME {
 796                  //ColorScheme::DarkMode => ([0., 0.11, 0.11, 1.], [0., 0.11, 0.11, 1.]),
 797                  ColorScheme::DarkMode => ([0., 0.3, 0.25, 0.0], [0., 0.3, 0.25, 0.5]),
 798                  ColorScheme::PaperLight => ([0., 0.3, 0.25, 0.0], [0., 0.3, 0.25, 0.5]),
 799              };
 800  
 801              let mut verts = vec![
 802                  ShapeVertex::new(x1.clone(), y1.clone(), color1),
 803                  ShapeVertex::new(x2.clone(), y1.clone(), color1),
 804                  ShapeVertex::new(x1.clone(), y2.clone(), color2),
 805                  ShapeVertex::new(x2, y2, color2),
 806              ];
 807              let mut indices = vec![0, 2, 1, 1, 2, 3];
 808              shape.verts.append(&mut verts);
 809              shape.indices.append(&mut indices);
 810  
 811              shape.add_filled_box(
 812                  expr::const_f32(0.),
 813                  expr::const_f32(SETTING_LABEL_LINESPACE - 1.),
 814                  expr::load_var("w"),
 815                  expr::const_f32(SETTING_LABEL_LINESPACE),
 816                  [0.15, 0.2, 0.19, 1.],
 817              );
 818  
 819              let node = node
 820                  .setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone()))
 821                  .await;
 822              setting_layer_node.link(node);
 823          } else {
 824              // Background Value
 825              let node = create_vector_art("value_bg");
 826              let prop = node.get_property("rect").unwrap();
 827              prop.clone()
 828                  .set_expr(
 829                      atom,
 830                      Role::App,
 831                      0,
 832                      cc.compile("w * X_RATIO - BORDER_RIGHT_SCALE").unwrap(),
 833                  )
 834                  .unwrap();
 835              prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 836              prop.clone()
 837                  .set_expr(
 838                      atom,
 839                      Role::App,
 840                      2,
 841                      cc.compile("w * (1-X_RATIO) + BORDER_RIGHT_SCALE").unwrap(),
 842                  )
 843                  .unwrap();
 844              prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 845              node.set_property_u32(atom, Role::App, "z_index", 0).unwrap();
 846              node.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
 847  
 848              let mut shape = VectorShape::new();
 849  
 850              let x1 = expr::const_f32(0.);
 851              let y1 = expr::const_f32(0.);
 852              let x2 = expr::load_var("w");
 853              let y2 = expr::const_f32(SETTING_LABEL_LINESPACE);
 854  
 855              let (color1, color2) = match COLOR_SCHEME {
 856                  //ColorScheme::DarkMode => ([0., 0.11, 0.11, 1.], [0., 0.11, 0.11, 1.]),
 857                  ColorScheme::DarkMode => ([0., 0.02, 0.02, 0.5], [0., 0.04, 0.04, 0.7]),
 858                  ColorScheme::PaperLight => ([1., 1., 1., 1.], [1., 1., 1., 1.]),
 859              };
 860  
 861              let mut verts = vec![
 862                  ShapeVertex::new(x1.clone(), y1.clone(), color1),
 863                  ShapeVertex::new(x2.clone(), y1.clone(), color1),
 864                  ShapeVertex::new(x1.clone(), y2.clone(), color2),
 865                  ShapeVertex::new(x2, y2, color2),
 866              ];
 867              let mut indices = vec![0, 2, 1, 1, 2, 3];
 868              shape.verts.append(&mut verts);
 869              shape.indices.append(&mut indices);
 870  
 871              shape.add_filled_box(
 872                  expr::const_f32(0.),
 873                  expr::const_f32(SETTING_LABEL_LINESPACE - 1.),
 874                  expr::load_var("w"),
 875                  expr::const_f32(SETTING_LABEL_LINESPACE),
 876                  [0.15, 0.2, 0.19, 1.],
 877              );
 878  
 879              let node = node
 880                  .setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone()))
 881                  .await;
 882              setting_layer_node.link(node);
 883          }
 884  
 885          // Label Key
 886          let label_value_node = create_text("key_label");
 887          let prop = label_value_node.get_property("rect").unwrap();
 888          prop.set_f32(atom, Role::App, 0, SETTING_LABEL_X).unwrap();
 889          prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 890          prop.set_expr(atom, Role::App, 2, cc.compile("w * X_RATIO").unwrap()).unwrap();
 891          prop.set_f32(atom, Role::App, 3, 100.).unwrap();
 892          label_value_node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 893          label_value_node
 894              .set_property_f32(atom, Role::App, "baseline", SETTING_LABEL_BASELINE)
 895              .unwrap();
 896          label_value_node
 897              .set_property_f32(atom, Role::App, "font_size", SETTING_LABEL_FONTSIZE)
 898              .unwrap();
 899          label_value_node.set_property_str(atom, Role::App, "text", setting_name.clone()).unwrap();
 900          if setting.is_default() {
 901              label_value_node
 902                  .set_property_f32_vec(atom, Role::App, "text_color", vec![0.65, 0.87, 0.83, 1.])
 903                  .unwrap();
 904          } else {
 905              label_value_node
 906                  .set_property_f32_vec(atom, Role::App, "text_color", vec![1., 1., 1., 1.])
 907                  .unwrap();
 908          }
 909          label_value_node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 910  
 911          let label_value_node = label_value_node
 912              .setup(|me| {
 913                  Text::new(
 914                      me,
 915                      window_scale.clone(),
 916                      app.render_api.clone(),
 917                      app.text_shaper.clone(),
 918                      app.ex.clone(),
 919                  )
 920              })
 921              .await;
 922          setting_layer_node.link(label_value_node);
 923  
 924          // Text edit
 925          let editbox_node = create_editbox("value_editbox");
 926          editbox_node.set_property_bool(atom, Role::App, "is_active", true).unwrap();
 927          editbox_node.set_property_bool(atom, Role::App, "is_focused", true).unwrap();
 928          let prop = editbox_node.get_property("rect").unwrap();
 929          prop.clone()
 930              .set_expr(atom, Role::App, 0, cc.compile("w * X_RATIO + BORDER_RIGHT_SCALE").unwrap())
 931              .unwrap();
 932          prop.set_f32(atom, Role::App, 1, 0.).unwrap();
 933          prop.clone()
 934              .set_expr(atom, Role::App, 2, cc.compile("w * X_RATIO - BORDER_RIGHT_SCALE").unwrap())
 935              .unwrap();
 936          prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
 937          editbox_node.set_property_f32(atom, Role::App, "baseline", SETTING_LABEL_BASELINE).unwrap();
 938          editbox_node.set_property_f32(atom, Role::App, "font_size", SETTING_EDIT_FONTSIZE).unwrap();
 939          editbox_node.set_property_f32(atom, Role::App, "cursor_ascent", CURSOR_ASCENT).unwrap();
 940          editbox_node.set_property_f32(atom, Role::App, "cursor_descent", CURSOR_DESCENT).unwrap();
 941          editbox_node.set_property_f32(atom, Role::App, "select_ascent", SELECT_ASCENT).unwrap();
 942          editbox_node.set_property_f32(atom, Role::App, "select_descent", SELECT_DESCENT).unwrap();
 943          editbox_node
 944              .set_property_f32_vec(atom, Role::App, "text_color", vec![0.7, 0.7, 0.7, 1.])
 945              .unwrap();
 946          editbox_node
 947              .set_property_f32_vec(atom, Role::App, "cursor_color", vec![0.5, 0.5, 0.5, 1.])
 948              .unwrap();
 949          editbox_node
 950              .set_property_f32_vec(atom, Role::App, "hi_bg_color", vec![0.5, 0.5, 0.5, 1.])
 951              .unwrap();
 952          let prop = editbox_node.get_property("selected").unwrap();
 953          prop.set_null(atom, Role::App, 0).unwrap();
 954          prop.set_null(atom, Role::App, 1).unwrap();
 955          editbox_node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
 956          editbox_node.set_property_bool(atom, Role::App, "is_active", false).unwrap();
 957          editbox_node.set_property_bool(atom, Role::App, "is_focused", false).unwrap();
 958          editbox_node.set_property_f32(atom, Role::App, "font_size", 0.).unwrap();
 959  
 960          let editz_text = PropertyStr::wrap(&editbox_node, Role::App, "text", 0).unwrap();
 961  
 962          // Handle enter pressed in the editbox
 963          {
 964              let (slot, recvr) = Slot::new("setting_enter_pressed");
 965              editbox_node.register("enter_pressed", slot).unwrap();
 966              let setting2 = setting.clone();
 967              let sg_root2 = setting_layer_node.clone();
 968              let active_setting2 = active_setting.clone();
 969              let editz_text2 = editz_text.clone();
 970              let listen_enter = app.ex.spawn(async move {
 971                  while let Ok(_) = recvr.recv().await {
 972                      update_setting(
 973                          setting2.clone(),
 974                          sg_root2.clone(),
 975                          active_setting2.clone(),
 976                          editz_text2.clone(),
 977                      )
 978                      .await;
 979                      refresh_setting(setting2.clone(), sg_root2.clone());
 980                  }
 981              });
 982              app.tasks.lock().unwrap().push(listen_enter);
 983          }
 984  
 985          let node = editbox_node
 986              .setup(|me| {
 987                  EditBox::new(
 988                      me,
 989                      window_scale.clone(),
 990                      app.render_api.clone(),
 991                      app.text_shaper.clone(),
 992                      app.ex.clone(),
 993                  )
 994              })
 995              .await;
 996          setting_layer_node.link(node);
 997  
 998          // Is this setting the one that is currently active
 999          let cloned_active_setting = active_setting.clone();
1000          let is_active_setting = match active_setting.lock().unwrap().as_ref() {
1001              Some(active) => Arc::ptr_eq(active, &setting),
1002              None => false,
1003          };
1004  
1005          if !is_active_setting {
1006              if is_bool {
1007                  // Bool circle: FALSE
1008                  let node = create_vector_art("bool_icon_bg_false");
1009                  let prop = node.get_property("rect").unwrap();
1010                  prop.clone()
1011                      .set_expr(
1012                          atom,
1013                          Role::App,
1014                          0,
1015                          cc.compile("w * X_RATIO + BORDER_RIGHT_SCALE + 6").unwrap(),
1016                      )
1017                      .unwrap();
1018                  prop.set_f32(atom, Role::App, 1, SETTING_LABEL_LINESPACE / 2.).unwrap();
1019                  prop.set_f32(atom, Role::App, 2, 0.).unwrap();
1020                  prop.set_f32(atom, Role::App, 3, 0.).unwrap();
1021                  node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
1022                  node.set_property_bool(
1023                      atom,
1024                      Role::App,
1025                      "is_visible",
1026                      matches!(setting_clone.get_value(), PropertyValue::Bool(false)),
1027                  )
1028                  .unwrap();
1029  
1030                  let shape = shape::create_circle([0.9, 0.4, 0.4, 0.7]).scaled(5.);
1031                  let node = node
1032                      .setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone()))
1033                      .await;
1034                  setting_layer_node.link(node);
1035  
1036                  // Bool circle: TRUE
1037                  let node = create_vector_art("bool_icon_bg_true");
1038                  let prop = node.get_property("rect").unwrap();
1039                  prop.clone()
1040                      .set_expr(
1041                          atom,
1042                          Role::App,
1043                          0,
1044                          cc.compile("w * X_RATIO + BORDER_RIGHT_SCALE + 6").unwrap(),
1045                      )
1046                      .unwrap();
1047                  prop.set_f32(atom, Role::App, 1, SETTING_LABEL_LINESPACE / 2.).unwrap();
1048                  prop.set_f32(atom, Role::App, 2, 0.).unwrap();
1049                  prop.set_f32(atom, Role::App, 3, 0.).unwrap();
1050                  node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
1051                  node.set_property_bool(
1052                      atom,
1053                      Role::App,
1054                      "is_visible",
1055                      matches!(setting_clone.get_value(), PropertyValue::Bool(true)),
1056                  )
1057                  .unwrap();
1058  
1059                  let shape = shape::create_circle([0., 0.94, 1., 1.]).scaled(5.);
1060                  let node = node
1061                      .setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone()))
1062                      .await;
1063                  setting_layer_node.link(node);
1064  
1065                  // Label showing the setting's current value
1066                  let value_node = create_text("value_label");
1067                  let prop = value_node.get_property("rect").unwrap();
1068                  prop.clone()
1069                      .set_expr(
1070                          atom,
1071                          Role::App,
1072                          0,
1073                          cc.compile("w * X_RATIO + BORDER_RIGHT_SCALE + 20 + 6").unwrap(),
1074                      )
1075                      .unwrap();
1076                  prop.set_f32(atom, Role::App, 1, 0.).unwrap();
1077                  prop.clone()
1078                      .set_expr(atom, Role::App, 2, cc.compile("w * X_RATIO").unwrap())
1079                      .unwrap();
1080                  prop.set_f32(atom, Role::App, 3, 100.).unwrap();
1081                  value_node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
1082                  value_node
1083                      .set_property_f32(atom, Role::App, "baseline", SETTING_LABEL_BASELINE)
1084                      .unwrap();
1085                  value_node
1086                      .set_property_f32(atom, Role::App, "font_size", SETTING_LABEL_FONTSIZE)
1087                      .unwrap();
1088                  value_node
1089                      .set_property_str(atom, Role::App, "text", setting_clone.value_as_string())
1090                      .unwrap();
1091                  if matches!(setting_clone.get_value(), PropertyValue::Bool(false)) {
1092                      value_node
1093                          .set_property_f32_vec(
1094                              atom,
1095                              Role::App,
1096                              "text_color",
1097                              vec![0.9, 0.4, 0.4, 1.],
1098                          )
1099                          .unwrap();
1100                  } else {
1101                      value_node
1102                          .set_property_f32_vec(
1103                              atom,
1104                              Role::App,
1105                              "text_color",
1106                              vec![0.0, 0.94, 1., 1.],
1107                          )
1108                          .unwrap();
1109                  }
1110                  value_node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
1111  
1112                  let node = value_node
1113                      .setup(|me| {
1114                          Text::new(
1115                              me,
1116                              window_scale.clone(),
1117                              app.render_api.clone(),
1118                              app.text_shaper.clone(),
1119                              app.ex.clone(),
1120                          )
1121                      })
1122                      .await;
1123                  setting_layer_node.link(node);
1124              } else {
1125                  // Label showing the setting's current value
1126                  let value_node = create_text("value_label");
1127                  let prop = value_node.get_property("rect").unwrap();
1128                  prop.clone()
1129                      .set_expr(
1130                          atom,
1131                          Role::App,
1132                          0,
1133                          cc.compile("w * X_RATIO + BORDER_RIGHT_SCALE").unwrap(),
1134                      )
1135                      .unwrap();
1136                  prop.set_f32(atom, Role::App, 1, 0.).unwrap();
1137                  prop.clone()
1138                      .set_expr(atom, Role::App, 2, cc.compile("w * X_RATIO").unwrap())
1139                      .unwrap();
1140                  prop.set_f32(atom, Role::App, 3, 100.).unwrap();
1141                  value_node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
1142                  value_node
1143                      .set_property_f32(atom, Role::App, "baseline", SETTING_LABEL_BASELINE)
1144                      .unwrap();
1145                  value_node
1146                      .set_property_f32(atom, Role::App, "font_size", SETTING_LABEL_FONTSIZE)
1147                      .unwrap();
1148                  value_node
1149                      .set_property_str(atom, Role::App, "text", setting_clone.value_as_string())
1150                      .unwrap();
1151                  value_node
1152                      .set_property_f32_vec(atom, Role::App, "text_color", vec![1., 1., 1., 1.])
1153                      .unwrap();
1154                  value_node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
1155  
1156                  let node = value_node
1157                      .setup(|me| {
1158                          Text::new(
1159                              me,
1160                              window_scale.clone(),
1161                              app.render_api.clone(),
1162                              app.text_shaper.clone(),
1163                              app.ex.clone(),
1164                          )
1165                      })
1166                      .await;
1167                  setting_layer_node.link(node);
1168              }
1169  
1170              // A wide button useful to select the current setting
1171              let node = create_button("selector_btn");
1172              node.set_property_bool(atom, Role::App, "is_active", true).unwrap();
1173              let prop = node.get_property("rect").unwrap();
1174              prop.set_expr(atom, Role::App, 0, cc.compile("w * X_RATIO").unwrap()).unwrap();
1175              prop.set_f32(atom, Role::App, 1, 0.).unwrap();
1176              prop.clone()
1177                  .set_expr(atom, Role::App, 2, cc.compile("w * (1-X_RATIO)").unwrap())
1178                  .unwrap();
1179              prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
1180  
1181              let sg_root2 = app.sg_root.clone();
1182              let setting_clone2 = setting_clone.clone();
1183              let setting_root2 = setting_layer_node.clone();
1184              let select = move || {
1185                  let atom = &mut PropertyAtomicGuard::new();
1186                  let sg_root = sg_root2.clone();
1187                  let mut lock = cloned_active_setting.lock().unwrap();
1188  
1189                  let path = "/window/settings_layer/search_input";
1190                  let node = sg_root.lookup_node(path).unwrap();
1191                  //node.set_property_bool(atom, Role::App, "is_active", false).unwrap();
1192                  node.set_property_bool(atom, Role::App, "is_focused", false).unwrap();
1193  
1194                  let was_active = if let Some(s) = lock.as_ref() {
1195                      let path = format!("/window/settings_layer/settings/{}", &s.name);
1196                      let old_node = sg_root.lookup_node(&path).unwrap();
1197  
1198                      let _was_active = s.name == setting_clone2.clone().name;
1199  
1200                      // Show the selected setting value label
1201                      // of the selected setting, if there's one
1202                      let node = old_node.lookup_node("/value_label").unwrap();
1203                      let text = PropertyStr::wrap(&node, Role::App, "text", 0).unwrap();
1204                      text.set(atom, &s.value_as_string());
1205  
1206                      // Hide the selected setting editbox
1207                      // of the selected setting, if there's one
1208                      if !_was_active {
1209                          let node = old_node.lookup_node("/value_editbox").unwrap();
1210                          node.set_property_bool(atom, Role::App, "is_active", false).unwrap();
1211                          node.set_property_bool(atom, Role::App, "is_focused", false).unwrap();
1212                          node.set_property_f32(atom, Role::App, "font_size", 0.).unwrap();
1213                          node.set_property_str(atom, Role::App, "text", "").unwrap();
1214                      }
1215  
1216                      // Hide conftrm button
1217                      // (Bool settings don't have a confirm button so we have to check for it to
1218                      // not panic)
1219                      let is_bool =
1220                          matches!(lock.clone().unwrap().get_value(), PropertyValue::Bool(_));
1221                      if !is_bool {
1222                          old_node
1223                              .lookup_node("/confirm_btn_bg")
1224                              .unwrap()
1225                              .set_property_bool(atom, Role::App, "is_visible", false)
1226                              .unwrap();
1227                      }
1228  
1229                      _was_active
1230                  } else {
1231                      false
1232                  };
1233  
1234                  // Update what setting active_setting points to
1235                  *lock = Some(setting_clone2.clone());
1236                  debug!("active setting set to: {}", lock.clone().unwrap().name);
1237  
1238                  if is_bool {
1239                      // Hide the setting value label (set its text empty)
1240                      let editbox = setting_root2.lookup_node("/value_label").unwrap();
1241                      let label_text = PropertyStr::wrap(&editbox, Role::App, "text", 0).unwrap();
1242  
1243                      let value = setting_clone2.get_value();
1244  
1245                      setting_root2
1246                          .lookup_node("/value_bg_bool_true")
1247                          .unwrap()
1248                          .set_property_bool(atom, Role::App, "is_visible", false)
1249                          .unwrap();
1250                      setting_root2
1251                          .lookup_node("/value_bg_bool_false")
1252                          .unwrap()
1253                          .set_property_bool(atom, Role::App, "is_visible", false)
1254                          .unwrap();
1255                      setting_root2
1256                          .lookup_node("/bool_icon_bg_true")
1257                          .unwrap()
1258                          .set_property_bool(atom, Role::App, "is_visible", false)
1259                          .unwrap();
1260                      setting_root2
1261                          .lookup_node("/bool_icon_bg_false")
1262                          .unwrap()
1263                          .set_property_bool(atom, Role::App, "is_visible", false)
1264                          .unwrap();
1265  
1266                      if matches!(value, PropertyValue::Bool(false)) {
1267                          setting_clone2
1268                              .node
1269                              .set_property_bool(atom, Role::User, "value", true)
1270                              .unwrap();
1271                          label_text.set(atom, "TRUE");
1272  
1273                          setting_root2
1274                              .lookup_node("/value_bg_bool_true")
1275                              .unwrap()
1276                              .set_property_bool(atom, Role::App, "is_visible", true)
1277                              .unwrap();
1278                          setting_root2
1279                              .lookup_node("/bool_icon_bg_true")
1280                              .unwrap()
1281                              .set_property_bool(atom, Role::App, "is_visible", true)
1282                              .unwrap();
1283  
1284                          let node = setting_root2.lookup_node("/value_label").unwrap();
1285                          node.set_property_f32_vec(
1286                              atom,
1287                              Role::App,
1288                              "text_color",
1289                              vec![0., 0.94, 1., 1.],
1290                          )
1291                          .unwrap();
1292                      } else {
1293                          setting_clone2
1294                              .node
1295                              .set_property_bool(atom, Role::User, "value", false)
1296                              .unwrap();
1297                          label_text.set(atom, "FALSE");
1298  
1299                          setting_root2
1300                              .lookup_node("/value_bg_bool_false")
1301                              .unwrap()
1302                              .set_property_bool(atom, Role::App, "is_visible", true)
1303                              .unwrap();
1304                          setting_root2
1305                              .lookup_node("/bool_icon_bg_false")
1306                              .unwrap()
1307                              .set_property_bool(atom, Role::App, "is_visible", true)
1308                              .unwrap();
1309  
1310                          let node = setting_root2.lookup_node("/value_label").unwrap();
1311                          node.set_property_f32_vec(
1312                              atom,
1313                              Role::App,
1314                              "text_color",
1315                              vec![0.9, 0.4, 0.4, 1.],
1316                          )
1317                          .unwrap();
1318                      }
1319                  } else {
1320                      // Hide the setting value label (set its text empty)
1321                      // TODO?: Visilibity property on labels
1322                      let editbox = setting_root2.lookup_node("/value_label").unwrap();
1323                      let label_text = PropertyStr::wrap(&editbox, Role::App, "text", 0).unwrap();
1324                      label_text.set(atom, "");
1325  
1326                      // Show the editbox
1327                      let node = setting_root2.lookup_node("/value_editbox").unwrap();
1328                      node.set_property_bool(atom, Role::App, "is_active", true).unwrap();
1329                      node.set_property_bool(atom, Role::App, "is_focused", true).unwrap();
1330                      node.set_property_f32(atom, Role::App, "font_size", 16.).unwrap();
1331                      if !was_active {
1332                          node.set_property_str(
1333                              atom,
1334                              Role::App,
1335                              "text",
1336                              setting_clone2.value_as_string(),
1337                          )
1338                          .unwrap();
1339                      }
1340  
1341                      // Show confirm button
1342                      setting_root2
1343                          .lookup_node("/confirm_btn_bg")
1344                          .unwrap()
1345                          .set_property_bool(atom, Role::App, "is_visible", true)
1346                          .unwrap();
1347                  }
1348  
1349                  refresh_setting(setting_clone2.clone(), setting_root2.clone());
1350              };
1351  
1352              {
1353                  let (slot, recvr) = Slot::new("select_clicked");
1354                  node.register("click", slot).unwrap();
1355                  let select2 = select.clone();
1356                  let listen_click = app.ex.spawn(async move {
1357                      while let Ok(_) = recvr.recv().await {
1358                          select2();
1359                      }
1360                  });
1361                  app.tasks.lock().unwrap().push(listen_click);
1362  
1363                  let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
1364                  setting_layer_node.link(node.clone());
1365              }
1366          }
1367  
1368          if is_bool {
1369              // Switch icon
1370              let node = create_vector_art("switch_btn_bg");
1371              let prop = node.get_property("rect").unwrap();
1372              prop.set_expr(atom, Role::App, 0, cc.compile("w - 50").unwrap()).unwrap();
1373              prop.set_f32(atom, Role::App, 1, SETTING_LABEL_LINESPACE / 2.).unwrap();
1374              prop.set_f32(atom, Role::App, 2, 0.).unwrap();
1375              prop.set_f32(atom, Role::App, 3, 0.).unwrap();
1376              node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
1377  
1378              let shape = shape::create_switch([0., 0.94, 1., 1.]).scaled(10.);
1379              let node = node
1380                  .setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone()))
1381                  .await;
1382              setting_layer_node.link(node);
1383          } else {
1384              // Confirm button
1385              let node = create_vector_art("confirm_btn_bg");
1386              let prop = node.get_property("rect").unwrap();
1387              prop.set_expr(atom, Role::App, 0, cc.compile("w - 50").unwrap()).unwrap();
1388              prop.set_f32(atom, Role::App, 1, SETTING_LABEL_LINESPACE / 2.).unwrap();
1389              prop.set_f32(atom, Role::App, 2, 0.).unwrap();
1390              prop.set_f32(atom, Role::App, 3, 0.).unwrap();
1391              node.set_property_u32(atom, Role::App, "z_index", 3).unwrap();
1392              node.set_property_bool(atom, Role::App, "is_visible", false).unwrap();
1393  
1394              let shape = shape::create_confirm([0., 0.94, 1., 1.]).scaled(10.);
1395              let node = node
1396                  .setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone()))
1397                  .await;
1398              setting_layer_node.link(node.clone());
1399  
1400              let node = create_button("confirm_btn");
1401              node.set_property_bool(atom, Role::App, "is_active", true).unwrap();
1402              let prop = node.get_property("rect").unwrap();
1403              prop.set_expr(atom, Role::App, 0, cc.compile("w - 100").unwrap()).unwrap();
1404              prop.set_f32(atom, Role::App, 1, 0.).unwrap();
1405              prop.set_f32(atom, Role::App, 2, 100.).unwrap();
1406              prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
1407              node.set_property_u32(atom, Role::App, "z_index", 3).unwrap();
1408  
1409              let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
1410              setting_layer_node.link(node.clone());
1411  
1412              // Handle confirm button click
1413              {
1414                  let (slot, recvr) = Slot::new("confirm_clicked");
1415                  node.register("click", slot).unwrap();
1416                  let setting2 = setting.clone();
1417                  let sg_root2 = setting_layer_node.clone();
1418                  let active_setting2 = active_setting.clone();
1419                  let editz_text2 = editz_text.clone();
1420                  let listen_click = app.ex.spawn(async move {
1421                      while let Ok(_) = recvr.recv().await {
1422                          info!("confirm clicked");
1423                          update_setting(
1424                              setting2.clone(),
1425                              sg_root2.clone(),
1426                              active_setting2.clone(),
1427                              editz_text2.clone(),
1428                          )
1429                          .await;
1430                          refresh_setting(setting2.clone(), sg_root2.clone());
1431                      }
1432                  });
1433                  app.tasks.lock().unwrap().push(listen_click);
1434              }
1435          }
1436  
1437          // Reset icon
1438          let node = create_vector_art("reset_btn_bg");
1439          let prop = node.get_property("rect").unwrap();
1440          prop.set_expr(atom, Role::App, 0, cc.compile("w - 100").unwrap()).unwrap();
1441          prop.set_f32(atom, Role::App, 1, SETTING_LABEL_LINESPACE / 2.).unwrap();
1442          prop.set_f32(atom, Role::App, 2, 0.).unwrap();
1443          prop.set_f32(atom, Role::App, 3, 0.).unwrap();
1444          node.set_property_bool(atom, Role::App, "is_visible", !setting.is_default()).unwrap();
1445          node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
1446  
1447          let shape = shape::create_reset([0., 0.94, 1., 1.]).scaled(15.);
1448          let node = node
1449              .setup(|me| VectorArt::new(me, shape, app.render_api.clone(), app.ex.clone()))
1450              .await;
1451          setting_layer_node.link(node);
1452  
1453          let node = create_button("reset_btn");
1454          node.set_property_bool(atom, Role::App, "is_active", !setting.is_default()).unwrap();
1455          let prop = node.get_property("rect").unwrap();
1456          prop.set_expr(atom, Role::App, 0, cc.compile("w - 115").unwrap()).unwrap();
1457          prop.set_f32(atom, Role::App, 1, 0.).unwrap();
1458          prop.set_f32(atom, Role::App, 2, 50.).unwrap();
1459          prop.set_f32(atom, Role::App, 3, SETTING_LABEL_LINESPACE).unwrap();
1460          node.set_property_u32(atom, Role::App, "z_index", 3).unwrap();
1461  
1462          let node = node.setup(|me| Button::new(me, app.ex.clone())).await;
1463          setting_layer_node.link(node.clone());
1464  
1465          // Handle reset button click
1466          {
1467              let (slot, recvr) = Slot::new("reset_clicked");
1468              node.register("click", slot).unwrap();
1469              let setting2 = setting.clone();
1470              let sg_root2 = setting_layer_node.clone();
1471              let active_setting2 = active_setting.clone();
1472              let editz_text2 = editz_text.clone();
1473              let listen_click = app.ex.spawn(async move {
1474                  while let Ok(_) = recvr.recv().await {
1475                      info!("reset clicked");
1476                      setting2.reset();
1477  
1478                      let atom = &mut PropertyAtomicGuard::new();
1479  
1480                      // Show the selected setting value label (set its text empty)
1481                      // of the selected setting, if there's one
1482                      let node = sg_root2.lookup_node("/value_label").unwrap();
1483                      let text = PropertyStr::wrap(&node, Role::App, "text", 0).unwrap();
1484                      text.set(atom, setting2.value_as_string());
1485  
1486                      let node = sg_root2.lookup_node("/value_editbox").unwrap();
1487                      node.set_property_str(atom, Role::App, "text", setting2.value_as_string())
1488                          .unwrap();
1489  
1490                      update_setting(
1491                          setting2.clone(),
1492                          sg_root2.clone(),
1493                          active_setting2.clone(),
1494                          editz_text2.clone(),
1495                      )
1496                      .await;
1497                      refresh_setting(setting2.clone(), sg_root2.clone());
1498                  }
1499              });
1500              app.tasks.lock().unwrap().push(listen_click);
1501          }
1502      }
1503  
1504      let settings_node = app.sg_root.lookup_node("/window/settings_layer").unwrap();
1505      settings_node.set_property_bool(atom, Role::App, "is_visible", false).unwrap();
1506  
1507      // Searchbar results count
1508      let node = app.sg_root.lookup_node("/window/settings_layer/settings").unwrap();
1509      let counter_text = node.get_children().len().to_string();
1510      let node = app.sg_root.lookup_node("/window/settings_layer/search_count").unwrap();
1511      node.set_property_str(atom, Role::App, "text", &counter_text).unwrap();
1512  }
1513  
1514  fn refresh_setting(setting: Arc<Setting>, sn: SceneNodePtr) {
1515      let atom = &mut PropertyAtomicGuard::new();
1516      let is_bool = matches!(setting.get_value(), PropertyValue::Bool(_));
1517  
1518      let node = sn.lookup_node("/key_label").unwrap();
1519      if setting.clone().is_default() {
1520          node.set_property_f32_vec(atom, Role::App, "text_color", vec![0.65, 0.87, 0.83, 1.])
1521              .unwrap();
1522      } else {
1523          node.set_property_f32_vec(atom, Role::App, "text_color", vec![1., 1., 1., 1.]).unwrap();
1524      }
1525  
1526      let node = sn.lookup_node("/reset_btn_bg").unwrap();
1527      node.set_property_bool(atom, Role::App, "is_visible", !setting.clone().is_default()).unwrap();
1528      let node = sn.lookup_node("/reset_btn").unwrap();
1529      node.set_property_bool(atom, Role::App, "is_active", !is_bool && !setting.clone().is_default())
1530          .unwrap();
1531  }
1532  
1533  async fn update_setting(
1534      setting: Arc<Setting>,
1535      sn: SceneNodePtr,
1536      active_setting: Arc<Mutex<Option<Arc<Setting>>>>,
1537      editz_text: PropertyStr,
1538  ) {
1539      let atom = &mut PropertyAtomicGuard::new();
1540  
1541      if let Some(node) = sn.lookup_node("/value_editbox") {
1542          node.set_property_f32(atom, Role::App, "font_size", 0.).unwrap();
1543          node.set_property_bool(atom, Role::App, "is_active", false).unwrap();
1544          node.set_property_bool(atom, Role::App, "is_focused", false).unwrap();
1545      }
1546  
1547      match &setting.get_value() {
1548          PropertyValue::Uint32(_) => {
1549              let value_str = editz_text.get();
1550              let parsed = value_str.parse::<u32>();
1551              if let Ok(value) = parsed {
1552                  if let Some(node) = sn.lookup_node("/value_label") {
1553                      node.set_property_str(atom, Role::App, "text", value_str).unwrap();
1554                  }
1555                  if let Some(node) = sn.lookup_node("/confirm_btn_bg") {
1556                      node.set_property_bool(atom, Role::App, "is_visible", false).unwrap();
1557                  }
1558                  setting.node.set_property_u32(atom, Role::User, "value", value).unwrap();
1559                  let mut active_setting_value = active_setting.lock().unwrap();
1560                  *active_setting_value = None;
1561              }
1562          }
1563          PropertyValue::Float32(_) => {
1564              let value_str = editz_text.get();
1565              let parsed = value_str.parse::<f32>();
1566              if let Ok(value) = parsed {
1567                  if let Some(node) = sn.lookup_node("/value_label") {
1568                      node.set_property_str(atom, Role::App, "text", value_str).unwrap();
1569                  }
1570                  if let Some(node) = sn.lookup_node("/confirm_btn_bg") {
1571                      node.set_property_bool(atom, Role::App, "is_visible", false).unwrap();
1572                  }
1573                  setting.node.set_property_f32(atom, Role::User, "value", value).unwrap();
1574                  let mut active_setting_value = active_setting.lock().unwrap();
1575                  *active_setting_value = None;
1576              }
1577          }
1578          PropertyValue::Str(_) => {
1579              let value_str = editz_text.get();
1580              if let Some(node) = sn.lookup_node("/value_label") {
1581                  node.set_property_str(atom, Role::App, "text", &value_str).unwrap();
1582              }
1583              if let Some(node) = sn.lookup_node("/confirm_btn_bg") {
1584                  node.set_property_bool(atom, Role::App, "is_visible", false).unwrap();
1585              }
1586              setting.node.set_property_str(atom, Role::User, "value", value_str).unwrap();
1587              let mut active_setting_value = active_setting.lock().unwrap();
1588              *active_setting_value = None;
1589          }
1590          _ => {}
1591      };
1592  }