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 slint::{Color, SharedString};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use slint::{Color, SharedString};
|
||||
|
||||
pub fn parse_hex_color(s: &str) -> Result<Color, String> {
|
||||
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());
|
||||
}
|
||||
|
||||
let raw =
|
||||
u32::from_str_radix(clean, 16)
|
||||
.map_err(|_| "invalid hex color")?;
|
||||
let raw = u32::from_str_radix(clean, 16).map_err(|_| "invalid hex color")?;
|
||||
|
||||
Ok(Color::from_argb_encoded(raw))
|
||||
}
|
||||
@ -120,17 +118,12 @@ pub struct ButtonStyleResolved {
|
||||
pub option_text_color: Color,
|
||||
}
|
||||
|
||||
pub fn load_config(
|
||||
screen_w: i32,
|
||||
screen_h: i32,
|
||||
) -> Result<ResolvedConfig, String> {
|
||||
pub fn load_config(screen_w: i32, screen_h: i32) -> Result<ResolvedConfig, String> {
|
||||
let path = config_path();
|
||||
|
||||
let raw = if path.exists() {
|
||||
let text = fs::read_to_string(&path)
|
||||
.map_err(|e| e.to_string())?;
|
||||
toml::from_str::<Config>(&text)
|
||||
.map_err(|e| e.to_string())?
|
||||
let text = fs::read_to_string(&path).map_err(|e| e.to_string())?;
|
||||
toml::from_str::<Config>(&text).map_err(|e| e.to_string())?
|
||||
} else {
|
||||
Config {
|
||||
screen: None,
|
||||
@ -145,9 +138,7 @@ pub fn load_config(
|
||||
}
|
||||
|
||||
fn config_path() -> PathBuf {
|
||||
let mut p =
|
||||
dirs::config_dir()
|
||||
.unwrap_or_else(|| PathBuf::from("."));
|
||||
let mut p = dirs::config_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||
|
||||
p.push("candywidgets");
|
||||
p.push("power-menu");
|
||||
@ -155,26 +146,19 @@ fn config_path() -> PathBuf {
|
||||
p
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
raw: Config,
|
||||
fallback_w: i32,
|
||||
fallback_h: i32,
|
||||
) -> Result<ResolvedConfig, String> {
|
||||
fn resolve(raw: Config, fallback_w: i32, fallback_h: i32) -> Result<ResolvedConfig, String> {
|
||||
let screen = raw.screen.as_ref();
|
||||
let menu = raw.menu_popup.as_ref();
|
||||
let buttons = raw.buttons.as_ref();
|
||||
|
||||
let screen_width =
|
||||
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_width = 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_bg =
|
||||
screen
|
||||
.and_then(|s| s.bg_color.as_deref())
|
||||
.map(parse_hex_color)
|
||||
.transpose()?
|
||||
.unwrap_or(Color::from_argb_encoded(0x20A3A3A3));
|
||||
let screen_bg = screen
|
||||
.and_then(|s| s.bg_color.as_deref())
|
||||
.map(parse_hex_color)
|
||||
.transpose()?
|
||||
.unwrap_or(Color::from_argb_encoded(0x20A3A3A3));
|
||||
|
||||
let btn_width = buttons.and_then(|b| b.width).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_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(
|
||||
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(
|
||||
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,
|
||||
@ -211,13 +201,13 @@ fn resolve(
|
||||
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 menu_width =
|
||||
menu.and_then(|m| m.width)
|
||||
.unwrap_or(btn_width * 4 + spacing * 3 + padding * 2);
|
||||
let menu_width = menu
|
||||
.and_then(|m| m.width)
|
||||
.unwrap_or(btn_width * 4 + spacing * 3 + padding * 2);
|
||||
|
||||
let menu_height =
|
||||
menu.and_then(|m| m.height)
|
||||
.unwrap_or(btn_height + padding * 2);
|
||||
let menu_height = menu
|
||||
.and_then(|m| m.height)
|
||||
.unwrap_or(btn_height + padding * 2);
|
||||
|
||||
Ok(ResolvedConfig {
|
||||
screen_width,
|
||||
@ -233,8 +223,12 @@ fn resolve(
|
||||
|
||||
menu_width,
|
||||
menu_height,
|
||||
menu_pos_x: menu.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_pos_x: menu
|
||||
.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
|
||||
.and_then(|m| m.bg_color.as_deref())
|
||||
.map(parse_hex_color)
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
use slint::{Color, LogicalPosition, LogicalSize, SharedString};
|
||||
use crate::config::ResolvedConfig;
|
||||
use slint::{Color, LogicalPosition, LogicalSize, SharedString};
|
||||
|
||||
slint::include_modules!();
|
||||
|
||||
fn to_slint_button_style(
|
||||
s: crate::config::ButtonStyleResolved,
|
||||
) -> ButtonStyle {
|
||||
fn to_slint_button_style(s: crate::config::ButtonStyleResolved) -> ButtonStyle {
|
||||
ButtonStyle {
|
||||
btn_width: s.btn_width,
|
||||
btn_height: s.btn_height,
|
||||
@ -27,9 +25,7 @@ fn to_slint_button_style(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_power_menu(
|
||||
cfg: ResolvedConfig
|
||||
) -> Result<(), Box<dyn std::error::Error>> {
|
||||
pub fn run_power_menu(cfg: ResolvedConfig) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let ui = PowerMenu::new()?;
|
||||
|
||||
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.window()
|
||||
.set_size(LogicalSize::new(cfg.screen_width as f32, cfg.screen_height as f32));
|
||||
ui.window().set_size(LogicalSize::new(
|
||||
cfg.screen_width as f32,
|
||||
cfg.screen_height as f32,
|
||||
));
|
||||
ui.window().set_position(LogicalPosition::new(0.0, 0.0));
|
||||
|
||||
ui.on_request_close(|| {
|
||||
slint::quit_event_loop();
|
||||
});
|
||||
|
||||
ui.run();
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -71,6 +71,8 @@ component PowerMenuButton {
|
||||
}
|
||||
|
||||
export component PowerMenu inherits Window {
|
||||
callback request_close();
|
||||
|
||||
in property <int> screen_width;
|
||||
in property <int> screen_height;
|
||||
in property <color> screen_bg;
|
||||
@ -113,6 +115,18 @@ export component PowerMenu inherits Window {
|
||||
y:0;
|
||||
background: screen_bg;
|
||||
|
||||
// Close upon clicking outside the menu
|
||||
TouchArea {
|
||||
x: 0;
|
||||
y: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
clicked => {
|
||||
request_close();
|
||||
}
|
||||
}
|
||||
|
||||
// Menu pop-up
|
||||
Rectangle {
|
||||
background: menu_bg;
|
||||
@ -122,6 +136,10 @@ export component PowerMenu inherits Window {
|
||||
x: menu_pos_x *1px;
|
||||
y: menu_pos_y *1px;
|
||||
|
||||
TouchArea {
|
||||
// Empty. Prevent close-on-click inside the menu.
|
||||
}
|
||||
|
||||
// Buttons
|
||||
HorizontalLayout {
|
||||
padding: menu_padding_x *1px;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user