Click outside menu to close app
- Add toucharea outside menu
This commit is contained in:
parent
5f0ca85589
commit
d0916291b4
@ -1,7 +1,7 @@
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use slint::{Color, SharedString};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use slint::{Color, SharedString};
|
|
||||||
|
|
||||||
pub fn parse_hex_color(s: &str) -> Result<Color, String> {
|
pub fn parse_hex_color(s: &str) -> Result<Color, String> {
|
||||||
let clean = s.trim().trim_start_matches('#');
|
let clean = s.trim().trim_start_matches('#');
|
||||||
@ -10,9 +10,7 @@ pub fn parse_hex_color(s: &str) -> Result<Color, String> {
|
|||||||
return Err("color must be RRGGBBAA".into());
|
return Err("color must be RRGGBBAA".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let raw =
|
let raw = u32::from_str_radix(clean, 16).map_err(|_| "invalid hex color")?;
|
||||||
u32::from_str_radix(clean, 16)
|
|
||||||
.map_err(|_| "invalid hex color")?;
|
|
||||||
|
|
||||||
Ok(Color::from_argb_encoded(raw))
|
Ok(Color::from_argb_encoded(raw))
|
||||||
}
|
}
|
||||||
@ -120,17 +118,12 @@ pub struct ButtonStyleResolved {
|
|||||||
pub option_text_color: Color,
|
pub option_text_color: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_config(
|
pub fn load_config(screen_w: i32, screen_h: i32) -> Result<ResolvedConfig, String> {
|
||||||
screen_w: i32,
|
|
||||||
screen_h: i32,
|
|
||||||
) -> Result<ResolvedConfig, String> {
|
|
||||||
let path = config_path();
|
let path = config_path();
|
||||||
|
|
||||||
let raw = if path.exists() {
|
let raw = if path.exists() {
|
||||||
let text = fs::read_to_string(&path)
|
let text = fs::read_to_string(&path).map_err(|e| e.to_string())?;
|
||||||
.map_err(|e| e.to_string())?;
|
toml::from_str::<Config>(&text).map_err(|e| e.to_string())?
|
||||||
toml::from_str::<Config>(&text)
|
|
||||||
.map_err(|e| e.to_string())?
|
|
||||||
} else {
|
} else {
|
||||||
Config {
|
Config {
|
||||||
screen: None,
|
screen: None,
|
||||||
@ -145,9 +138,7 @@ pub fn load_config(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn config_path() -> PathBuf {
|
fn config_path() -> PathBuf {
|
||||||
let mut p =
|
let mut p = dirs::config_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||||
dirs::config_dir()
|
|
||||||
.unwrap_or_else(|| PathBuf::from("."));
|
|
||||||
|
|
||||||
p.push("candywidgets");
|
p.push("candywidgets");
|
||||||
p.push("power-menu");
|
p.push("power-menu");
|
||||||
@ -155,26 +146,19 @@ fn config_path() -> PathBuf {
|
|||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve(
|
fn resolve(raw: Config, fallback_w: i32, fallback_h: i32) -> Result<ResolvedConfig, String> {
|
||||||
raw: Config,
|
|
||||||
fallback_w: i32,
|
|
||||||
fallback_h: i32,
|
|
||||||
) -> Result<ResolvedConfig, String> {
|
|
||||||
let screen = raw.screen.as_ref();
|
let screen = raw.screen.as_ref();
|
||||||
let menu = raw.menu_popup.as_ref();
|
let menu = raw.menu_popup.as_ref();
|
||||||
let buttons = raw.buttons.as_ref();
|
let buttons = raw.buttons.as_ref();
|
||||||
|
|
||||||
let screen_width =
|
let screen_width = screen.and_then(|s| s.width).unwrap_or(fallback_w);
|
||||||
screen.and_then(|s| s.width).unwrap_or(fallback_w);
|
let screen_height = screen.and_then(|s| s.height).unwrap_or(fallback_h);
|
||||||
let screen_height =
|
|
||||||
screen.and_then(|s| s.height).unwrap_or(fallback_h);
|
|
||||||
|
|
||||||
let screen_bg =
|
let screen_bg = screen
|
||||||
screen
|
.and_then(|s| s.bg_color.as_deref())
|
||||||
.and_then(|s| s.bg_color.as_deref())
|
.map(parse_hex_color)
|
||||||
.map(parse_hex_color)
|
.transpose()?
|
||||||
.transpose()?
|
.unwrap_or(Color::from_argb_encoded(0x20A3A3A3));
|
||||||
.unwrap_or(Color::from_argb_encoded(0x20A3A3A3));
|
|
||||||
|
|
||||||
let btn_width = buttons.and_then(|b| b.width).unwrap_or(120);
|
let btn_width = buttons.and_then(|b| b.width).unwrap_or(120);
|
||||||
let btn_height = buttons.and_then(|b| b.height).unwrap_or(120);
|
let btn_height = buttons.and_then(|b| b.height).unwrap_or(120);
|
||||||
@ -188,13 +172,19 @@ fn resolve(
|
|||||||
btn_border_radius: buttons.and_then(|b| b.border_radius).unwrap_or(20),
|
btn_border_radius: buttons.and_then(|b| b.border_radius).unwrap_or(20),
|
||||||
|
|
||||||
btn_bg_normal: parse_hex_color(
|
btn_bg_normal: parse_hex_color(
|
||||||
buttons.and_then(|b| b.bg_color_normal.as_deref()).unwrap_or("91919175")
|
buttons
|
||||||
|
.and_then(|b| b.bg_color_normal.as_deref())
|
||||||
|
.unwrap_or("91919175"),
|
||||||
)?,
|
)?,
|
||||||
btn_bg_hover: parse_hex_color(
|
btn_bg_hover: parse_hex_color(
|
||||||
buttons.and_then(|b| b.bg_color_hover.as_deref()).unwrap_or("92929284")
|
buttons
|
||||||
|
.and_then(|b| b.bg_color_hover.as_deref())
|
||||||
|
.unwrap_or("92929284"),
|
||||||
)?,
|
)?,
|
||||||
btn_bg_clicked: parse_hex_color(
|
btn_bg_clicked: parse_hex_color(
|
||||||
buttons.and_then(|b| b.bg_color_clicked.as_deref()).unwrap_or("9B9B9BAB")
|
buttons
|
||||||
|
.and_then(|b| b.bg_color_clicked.as_deref())
|
||||||
|
.unwrap_or("9B9B9BAB"),
|
||||||
)?,
|
)?,
|
||||||
|
|
||||||
option_icon_height: icon_height,
|
option_icon_height: icon_height,
|
||||||
@ -211,13 +201,13 @@ fn resolve(
|
|||||||
let padding = menu.and_then(|m| m.padding_x).unwrap_or(20);
|
let padding = menu.and_then(|m| m.padding_x).unwrap_or(20);
|
||||||
let spacing = menu.and_then(|m| m.button_spacing).unwrap_or(padding);
|
let spacing = menu.and_then(|m| m.button_spacing).unwrap_or(padding);
|
||||||
|
|
||||||
let menu_width =
|
let menu_width = menu
|
||||||
menu.and_then(|m| m.width)
|
.and_then(|m| m.width)
|
||||||
.unwrap_or(btn_width * 4 + spacing * 3 + padding * 2);
|
.unwrap_or(btn_width * 4 + spacing * 3 + padding * 2);
|
||||||
|
|
||||||
let menu_height =
|
let menu_height = menu
|
||||||
menu.and_then(|m| m.height)
|
.and_then(|m| m.height)
|
||||||
.unwrap_or(btn_height + padding * 2);
|
.unwrap_or(btn_height + padding * 2);
|
||||||
|
|
||||||
Ok(ResolvedConfig {
|
Ok(ResolvedConfig {
|
||||||
screen_width,
|
screen_width,
|
||||||
@ -233,8 +223,12 @@ fn resolve(
|
|||||||
|
|
||||||
menu_width,
|
menu_width,
|
||||||
menu_height,
|
menu_height,
|
||||||
menu_pos_x: menu.and_then(|m| m.pos_x).unwrap_or((screen_width - menu_width) / 2),
|
menu_pos_x: menu
|
||||||
menu_pos_y: menu.and_then(|m| m.pos_y).unwrap_or((screen_height - menu_height) / 2),
|
.and_then(|m| m.pos_x)
|
||||||
|
.unwrap_or((screen_width - menu_width) / 2),
|
||||||
|
menu_pos_y: menu
|
||||||
|
.and_then(|m| m.pos_y)
|
||||||
|
.unwrap_or((screen_height - menu_height) / 2),
|
||||||
menu_bg: menu
|
menu_bg: menu
|
||||||
.and_then(|m| m.bg_color.as_deref())
|
.and_then(|m| m.bg_color.as_deref())
|
||||||
.map(parse_hex_color)
|
.map(parse_hex_color)
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
use slint::{Color, LogicalPosition, LogicalSize, SharedString};
|
|
||||||
use crate::config::ResolvedConfig;
|
use crate::config::ResolvedConfig;
|
||||||
|
use slint::{Color, LogicalPosition, LogicalSize, SharedString};
|
||||||
|
|
||||||
slint::include_modules!();
|
slint::include_modules!();
|
||||||
|
|
||||||
fn to_slint_button_style(
|
fn to_slint_button_style(s: crate::config::ButtonStyleResolved) -> ButtonStyle {
|
||||||
s: crate::config::ButtonStyleResolved,
|
|
||||||
) -> ButtonStyle {
|
|
||||||
ButtonStyle {
|
ButtonStyle {
|
||||||
btn_width: s.btn_width,
|
btn_width: s.btn_width,
|
||||||
btn_height: s.btn_height,
|
btn_height: s.btn_height,
|
||||||
@ -27,9 +25,7 @@ fn to_slint_button_style(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_power_menu(
|
pub fn run_power_menu(cfg: ResolvedConfig) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
cfg: ResolvedConfig
|
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
|
||||||
let ui = PowerMenu::new()?;
|
let ui = PowerMenu::new()?;
|
||||||
|
|
||||||
let button_style = to_slint_button_style(cfg.button_style);
|
let button_style = to_slint_button_style(cfg.button_style);
|
||||||
@ -63,10 +59,16 @@ pub fn run_power_menu(
|
|||||||
|
|
||||||
ui.set_button_style(button_style);
|
ui.set_button_style(button_style);
|
||||||
|
|
||||||
ui.window()
|
ui.window().set_size(LogicalSize::new(
|
||||||
.set_size(LogicalSize::new(cfg.screen_width as f32, cfg.screen_height as f32));
|
cfg.screen_width as f32,
|
||||||
|
cfg.screen_height as f32,
|
||||||
|
));
|
||||||
ui.window().set_position(LogicalPosition::new(0.0, 0.0));
|
ui.window().set_position(LogicalPosition::new(0.0, 0.0));
|
||||||
|
|
||||||
|
ui.on_request_close(|| {
|
||||||
|
slint::quit_event_loop();
|
||||||
|
});
|
||||||
|
|
||||||
ui.run();
|
ui.run();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -71,6 +71,8 @@ component PowerMenuButton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export component PowerMenu inherits Window {
|
export component PowerMenu inherits Window {
|
||||||
|
callback request_close();
|
||||||
|
|
||||||
in property <int> screen_width;
|
in property <int> screen_width;
|
||||||
in property <int> screen_height;
|
in property <int> screen_height;
|
||||||
in property <color> screen_bg;
|
in property <color> screen_bg;
|
||||||
@ -113,6 +115,18 @@ export component PowerMenu inherits Window {
|
|||||||
y:0;
|
y:0;
|
||||||
background: screen_bg;
|
background: screen_bg;
|
||||||
|
|
||||||
|
// Close upon clicking outside the menu
|
||||||
|
TouchArea {
|
||||||
|
x: 0;
|
||||||
|
y: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
clicked => {
|
||||||
|
request_close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Menu pop-up
|
// Menu pop-up
|
||||||
Rectangle {
|
Rectangle {
|
||||||
background: menu_bg;
|
background: menu_bg;
|
||||||
@ -122,6 +136,10 @@ export component PowerMenu inherits Window {
|
|||||||
x: menu_pos_x *1px;
|
x: menu_pos_x *1px;
|
||||||
y: menu_pos_y *1px;
|
y: menu_pos_y *1px;
|
||||||
|
|
||||||
|
TouchArea {
|
||||||
|
// Empty. Prevent close-on-click inside the menu.
|
||||||
|
}
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
HorizontalLayout {
|
HorizontalLayout {
|
||||||
padding: menu_padding_x *1px;
|
padding: menu_padding_x *1px;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user