diff --git a/advotracker/src/data/constants.rs b/advotracker/src/data/constants.rs index ee16b31..5eb23c1 100644 --- a/advotracker/src/data/constants.rs +++ b/advotracker/src/data/constants.rs @@ -28,6 +28,14 @@ pub static ID_LOCALIZATION_LANGUAGES: &str = "localization_languages"; pub static ID_LOCALIZATION_LABEL_LANGUAGE_NAME: &str = "localization_label_language_name"; pub static ID_LOCALIZATION_LANGUAGE_NAME: &str = "localization_language_name"; +pub static ID_MENU_POPUP: &str = "menu_popup"; +pub static ID_MENU_GRID: &str = "menu_grid"; +pub static ID_MENU_LABEL_ACCOUNT: &str = "menu_label_account"; +pub static ID_MENU_LABEL_QUIT: &str = "menu_label_quit"; +pub static ID_MENU_LABEL_TOGGLE_THEME: &str = "menu_label_toggle_theme"; +pub static ID_MENU_SHORTCUT_QUIT: &str = "menu_shortcut_quit"; +pub static ID_MENU_TOGGLE_THEME: &str = "menu_toggle_theme"; + pub static ID_POLICY_CHECK_FORM: &str = "policy_check_form"; pub static ID_POLICY_CHECK_FORM_ROW_0: &str = "policy_check_form_row_0"; pub static ID_POLICY_CHECK_FORM_ROW_1: &str = "policy_check_form_row_1"; @@ -42,14 +50,7 @@ pub static ID_POLICY_CHECK_LABEL_HINT: &str = "policy_check_label_hint"; pub static ID_POLICY_CHECK_LABEL_MENU: &str = "policy_check_label_menu"; pub static ID_POLICY_CHECK_LABEL_POLICY_NUMBER: &str = "policy_check_label_policy_number"; pub static ID_POLICY_CHECK_LABEL_RESULT: &str = "policy_check_label_result"; -pub static ID_POLICY_CHECK_MENU: &str = "policy_check_menu"; -pub static ID_POLICY_CHECK_MENU_LABEL_ACCOUNT: &str = "policy_check_menu_label_account"; -pub static ID_POLICY_CHECK_MENU_LABEL_QUIT: &str = "policy_check_menu_label_quit"; -pub static ID_POLICY_CHECK_MENU_SHORTCUT_QUIT: &str = "policy_check_menu_shortcut_quit"; -pub static ID_POLICY_CHECK_MENU_LABEL_TOGGLE_THEME: &str = "policy_check_menu_label_toggle_theme"; pub static ID_POLICY_CHECK_POLICY_NUMBER: &str = "policy_check_policy_number"; -pub static ID_POLICY_CHECK_POPUP_MENU: &str = "policy_check_popup_menu"; -pub static ID_POLICY_CHECK_POPUP_MENU_TOGGLE_THEME: &str = "policy_check_popup_menu_toggle_theme"; pub static ID_POLICY_CHECK_POPUP_PROGRESS: &str = "policy_check_popup_progress"; pub static ID_POLICY_CHECK_PROGRESS_BAR: &str = "policy_check_progress_bar"; pub static ID_POLICY_CHECK_PROGRESS_TIME: &str = "policy_check_progress_time"; diff --git a/advotracker/src/widgets/menu/menu_state.rs b/advotracker/src/widgets/menu/menu_state.rs new file mode 100644 index 0000000..98e744a --- /dev/null +++ b/advotracker/src/widgets/menu/menu_state.rs @@ -0,0 +1,286 @@ +/* + * advotracker - Hotline tackingtool for Advocats + * + * Copyright 2020 Ralf Zerres + * SPDX-License-Identifier: (0BSD or MIT) + */ + +use cfg_if::cfg_if; +use orbtk::prelude::*; +use orbtk::shell::event::Key; + +use std::process; + +use crate::{ + data::constants::*, + widgets::policycheck::policycheck_view::PolicycheckView, + widgets::policycheck::policycheck_state::{PolicycheckAction, PolicycheckState}, +}; + +/// Valid `actions` that are handled as state changes in the `Policycheck` widget. +#[derive(Debug, Clone, Copy)] +pub enum MenuAction { + CreateMenuPopup(Entity), + RemoveMenuPopup(Entity), + SetThemeToggle(Entity), +} + +/// Valid `structures` that are handled inside the state of the `Menu` widget. +#[derive(AsAny, Default)] +pub struct MenuState { + action: Option, + menu: Entity, + menu_toggle_theme: Entity, +} + +/// Method definitions, that react on any given state change inside the `Menu` widget. +impl MenuState { + /// Remove the menu popup box + fn remove_menu(&mut self, id: Entity, ctx: &mut Context<'_>) { + ctx.remove_child(self.menu); + println!("Popup {:?} removed !", id); + } + + /// Remove the menu popup box + fn remove_menu_toggle_theme(&mut self, id: Entity, ctx: &mut Context<'_>) { + ctx.remove_child(self.menu_toggle_theme); + println!("Popup {:?} removed !", id); + } + + /// Sets a new action. + pub fn set_action(&mut self, action: MenuAction) { + self.action = action.into(); + } + + /// Set a menu using a stack that holds all valid menu elements + /// The elements are ordered in a stack + fn set_menu(&mut self, ctx: &mut Context<'_>) { + let stack = ctx + .entity_of_child(ID_POLICY_CHECK_BUTTON_MENU) + .expect("PolicycheckState: Can't find entity of resource 'ID_POLICY_CHECK_POPUP_MENU'."); + let current_entity = ctx.entity(); + let build_context = &mut ctx.build_context(); + + // create a new popup menu overlay + self.menu = new_menu(current_entity, build_context); + + // create a menu_popup widget as a child of entity "ID_POLICY_CHECK_BUTTON_MENU" + build_context.append_child(stack, self.menu); + + println!("Popup Menu created: {:?}", self.menu); + } + + /// Set a toggle_theme menu + /// Select the active theme from a `ComboBox` offering a list of valid `themes`` + fn set_menu_toggle_theme(&mut self, ctx: &mut Context<'_>) { + let stack = ctx + .entity_of_child(ID_MENU_LABEL_TOGGLE_THEME) + .expect("MenuState: Can't find entity of resource 'ID_MENU_LABEL_TOGGLE_THEME'."); + let current_entity = ctx.entity(); + let build_context = &mut ctx.build_context(); + + // create a new menu overlay + self.menu_toggle_theme = new_menu_toggle_theme(current_entity, build_context); + + // create a menu_popup widget as a child of entity "ID_POPUP_MENU" + build_context.append_child(stack, self.menu_toggle_theme); + + println!("Popup Menu Toggle Theme created: {:?}", self.menu_toggle_theme); + } +} + +/// Supported methods handled inside the `MenuState` +impl State for MenuState { + /// Initialize the state of widgets inside `MenuState` + fn init(&mut self, _: &mut Registry, ctx: &mut Context<'_>) { + } + + /// Handle messages for the `MenuState` + fn messages( + &mut self, + mut messages: MessageReader, + _registry: &mut Registry, + ctx: &mut Context<'_>, + ) { + for message in messages.read::() { + match message { + MenuAction::ChangeTheme() => { + let theme_index = *PolicycheckView::selected_index_ref(&ctx.widget()); + + cfg_if! { + if #[cfg(windows)] { + match theme_index { + 0 => ctx.switch_theme(theme_default_dark()), + 1 => ctx.switch_theme(theme_default_light()), + 2 => ctx.switch_theme(theme_redox()), + 3 => ctx.switch_theme(theme_fluent_dark()), + 4 => ctx.switch_theme(theme_fluent_light()), + _ => {} + } + } else { + match theme_index { + 0 => ctx.switch_theme(theme_default_dark()), + 1 => ctx.switch_theme(theme_default_light()), + 2 => ctx.switch_theme(theme_redox()), + _ => {} + } + } + } + }, + _ => (), + } + } + } + + /// Update the state of widgets inside the `Menu` view. + fn update(&mut self, _registry: &mut Registry, ctx: &mut Context<'_>) { + if let Some(action) = self.action { + match action { + MenuAction::RemoveMenu(_entity) => { + self.remove_menu(ctx); + } + MenuAction::RemoveMenuToggleTheme(_entity) => { + self.remove_menu_toggle_theme(ctx); + } + MenuAction::SetMenu(_entity) => { + self.set_menu(ctx); + } + MenuAction::SetMenuToggleTheme(_entity) => { + self.set_menu_toggle_theme(ctx); + } + } + } + } +} + +/// Create a new menu popup +pub fn new_menu(menu: Entity, ctx: &mut BuildContext<'_>) -> Entity { + Popup::new() + .id(ID_MENU_POPUP) + .style("container_menu") + .target(menu) + .open(true) + .width(280) + .height(140) + .on_key_down(move | _ctx, key_event | { + match key_event.key { + Key::Q(..) => { + //if is_ctrl_home_down(ctx) + println!("KeyHandler: got Ctrl+Q"); + process::exit(0); + //} + }, + Key::Escape => { + println!("KeyHandler: got Escape"); + //ctx.get::(menu) + // .set_action(PolicycheckAction::RemoveMenu(menu)); + }, + _ => { + println!("KeyHandler: got {:?}", key_event.key); + }, + }; + true + }) + .child( + Grid::new() + .id(ID_MENU_GRID) + .columns( + Columns::create() + .push("80") // Menu Button + .push("1") // Seperator + .push("*") // Keyboard Shortcut + .build(), + ) + .rows( + Rows::create() + .push("auto") + .push("auto") + .push("auto") + .build(), + ) + .child( + Button::new() + .id(ID_MENU_LABEL_ACCOUNT) + .style("button_menu") + .attach(Grid::row(0)) + .attach(Grid::column(0)) + .attach(Grid::column_span(2)) + .icon(material_icons_font::MD_PERSON) + .text("Account") + .build(ctx), + ) + .child( + Button::new() + .id(ID_MENU_LABEL_TOGGLE_THEME) + .style("button_menu") + .attach(Grid::row(1)) + .attach(Grid::column(0)) + .attach(Grid::column_span(2)) + .icon(material_icons_font::MD_EDIT) + .text("Toggle theme") + .on_click(move |states, _| { + states.get_mut::(menu) + .set_action(MenuAction::SetToggleTheme(menu)); + true + }) + .build(ctx), + ) + .child( + Button::new() + .id(ID_MENU_LABEL_QUIT) + .style("button_menu") + .attach(Grid::row(2)) + .attach(Grid::column(0)) + .attach(Grid::column_span(2)) + .icon(material_icons_font::MD_SETTINGS_POWER) + .text("Quit") + .on_mouse_down(move |_states, _| { + process::exit(0); + }) + .build(ctx), + ) + .child( + TextBlock::new() + .id(ID_MENU_SHORTCUT_QUIT) + .style("button_menu") + .attach(Grid::row(2)) + .attach(Grid::column(2)) + .margin((0, 0, 16, 0)) + .h_align("end") + .v_align("center") + .text("CTRL+Q") + .build(ctx), + ) + .build(ctx), + ) + .build(ctx) +} + +/// Create a new popup submenu to toogle the active theme +pub fn new_menu_toggle_theme(menu_toggle_theme: Entity, ctx: &mut BuildContext<'_>) -> Entity { + Popup::new() + .id(ID_MENU_TOGGLE_THEME) + .style("container_menu") + .target(menu_toggle_theme) + .open(true) + .width(280) + .height(140) + .child( + ComboBox::new() + .attach(Grid::column(2)) + .attach(Grid::row(6)) + .count(themes_count) + .items_builder(move |build_ctx, index| { + let theme_name = + PolicycheckView::themes_ref(&build_ctx.get_widget(menu_toggle_theme))[index].clone(); + TextBlock::new().v_align("center").text(theme_name).build(build_ctx) + }) + .on_changed("selected_index", move |ctx, _| { + ctx.send_message(MenuAction::ChangeTheme, menu_toggle_theme); + println!("changed theme."); + }) + .selected_index(menu_toggle_theme) + .build(ctx), + ) + .build(ctx) +} diff --git a/advotracker/src/widgets/menu/menu_view.rs b/advotracker/src/widgets/menu/menu_view.rs new file mode 100644 index 0000000..8a1fc7b --- /dev/null +++ b/advotracker/src/widgets/menu/menu_view.rs @@ -0,0 +1,60 @@ +/* + * advotracker - Hotline tackingtool for Advocats + * + * Copyright 2020 Ralf Zerres + * SPDX-License-Identifier: (0BSD or MIT) + */ + +use cfg_if::cfg_if; +use orbtk::prelude::*; +use orbtk::shell::event::Key; + +use std::process; + +use crate::{ + data::constants::*, + //widgets::policycheck::policycheck_view::PolicycheckView, + widgets::menu::menu_state::{MenuAction, MenuState}, +}; + +type List = Vec; + +// Macro that initializes the widget structures/variables for the menu view +widget!( + MenuView { + selected_index: i32, + themes: List, + themes_count: i32 + } +); + +/// The template implementation of the menu view +/// All GUI elements are styled using the "style" attribute referencing to a ron based css +impl Template for MenuView { + fn template(self, id: Entity, ctx: &mut BuildContext) -> Self { + cfg_if! { + if #[cfg(windows)] { + // define the list of supported themes + let themes = vec![ + "default_dark".to_string(), + "default_light".to_string(), + "redox".to_string(), + "fluent_dark".to_string(), + "fluent_light".to_string() + ]; + } else { + // define the list of supported themes + let themes = vec![ + "default_dark".to_string(), + "default_light".to_string(), + "redox".to_string(), + ]; + } + } + + let themes_count = themes.len(); + + self.themes(themes).child( + ) + } +} diff --git a/advotracker/src/widgets/menu/mod.rs b/advotracker/src/widgets/menu/mod.rs new file mode 100644 index 0000000..5713301 --- /dev/null +++ b/advotracker/src/widgets/menu/mod.rs @@ -0,0 +1,12 @@ +/* + * advotracker - Hotline tackingtool for Advocats + * + * Copyright 2020 Ralf Zerres + * SPDX-License-Identifier: (0BSD or MIT) + */ + +/// The menu view +pub mod menu_view; + +/// The menu state +pub mod menu_state; diff --git a/advotracker/src/widgets/mod.rs b/advotracker/src/widgets/mod.rs index 22404c0..8e52a7c 100644 --- a/advotracker/src/widgets/mod.rs +++ b/advotracker/src/widgets/mod.rs @@ -5,23 +5,26 @@ * SPDX-License-Identifier: (0BSD or MIT) */ -/// The configuration widget. +/// Configuration widget. pub mod configuration; -/// The global helper functions. +/// Global helper functions. pub mod global_state; -/// The localization widget. +/// Localization widget. pub mod localization; /// The starting point (Main View). pub mod main_view; -/// The policycheck wigdet. +/// Menu widget. +pub mod menu; + +/// Policycheck wigdet. pub mod policycheck; -// /// The policydata widget. +// /// Policydata widget. // pub mod policydata; -// /// The policylists widget. +// /// Policylists widget. // pub mod policylist; diff --git a/advotracker/src/widgets/policycheck/policycheck_menu.rs b/advotracker/src/widgets/policycheck/policycheck_menu.rs deleted file mode 100644 index 084a20a..0000000 --- a/advotracker/src/widgets/policycheck/policycheck_menu.rs +++ /dev/null @@ -1,70 +0,0 @@ -/* - * advotracker - Hotline tackingtool for Advocats - * - * Copyright 2020 Ralf Zerres - * SPDX-License-Identifier: (0BSD or MIT) - */ - -use orbtk::prelude::*; - -use crate::data::constants::*; - -widget!( - PolicyCheckMenu { - is_active: Bool - } -); - - -impl Template for PolicyCheckMenu { - fn template(self, _id: Entity, ctx: &mut BuildContext) -> Self { - // let policy_check_menu_container = Container::new() - // .id(ID_POLICY_CHECK_MENU_CONTAINER) - // .class(CLASS_MENU) - // .attach(Grid::row(3)) - // .attach(Grid::column(8)) - // .margin((0.0, 0.0, 4.0, 0.0)) - // .enabled(false) - // .min_size(120.0, 180.0) - // .v_align("center") - // .on_click(move |ctx, _| { - // ctx.get_mut::(id) - // .action(Action::NewEntry(quit)); - // true - // }) - // .build(ctx); - - // let policycheck_menu_container = Container::new() - // .id(ID_POLICY_CHECK_MENU_CONTAINER) - // .background("#dfebf5") - // .width(200.0) - // .height(200.0) - // .child( - - // The menu implemented as an overlay - //ctx.append_child_to_overlay(policy_check_menu_button).unwrap(); - - self.name("PolicyCheckMenu").child( - Stack::new() - .id(ID_POLICY_CHECK_MENU) - .orientation("vertical") - .spacing(8) - .h_align("center") - .child( - Button::new() - .icon(material_icons_font::MD_VERIFIED_USER) - .text("angemeldeter Benutzer") - .margin((0, 8, 0, 0)) - .build(ctx), - ) - .child( - Button::new() - .icon(material_icons_font::MD_EXIT_TO_APP) - .text("Quit") - .margin((0, 8, 0, 0)) - .build(ctx), - ) - .build(ctx), - ) - } -}