settings implementation
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -6928,6 +6928,7 @@ dependencies = [
|
|||||||
"rodio",
|
"rodio",
|
||||||
"rust-ini",
|
"rust-ini",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"smol",
|
"smol",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"wayvr-ipc",
|
"wayvr-ipc",
|
||||||
|
|||||||
@@ -2,50 +2,34 @@
|
|||||||
<include src="t_tab_title.xml" />
|
<include src="t_tab_title.xml" />
|
||||||
<include src="../t_group_box.xml" />
|
<include src="../t_group_box.xml" />
|
||||||
|
|
||||||
|
<template name="SettingsGroupBox">
|
||||||
|
<rectangle macro="group_box" id="${id}">
|
||||||
|
<GroupBoxTitle translation="${translation}" src_builtin="${icon}" />
|
||||||
|
</rectangle>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="CheckBoxSetting">
|
||||||
|
<CheckBox id="${id}" text="${text}" translation="${translation}" checked="${checked}" tooltip="${tooltip}" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="SliderSetting">
|
||||||
|
<label text="${text}" translation="${translation}" />
|
||||||
|
<Slider id="${id}" width="250" height="24" min_value="${min}" max_value="${max}" step="${step}" value="${value}" tooltip="${tooltip}" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="SelectSetting">
|
||||||
|
<label text="${text}" translation="${translation}" tooltip="${tooltip}" />
|
||||||
|
<RadioGroup id="${id}" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="SelectOption">
|
||||||
|
<RadioBox text="${text}" translation="${translation}" value="${value}" tooltip="${tooltip}" />
|
||||||
|
</template>
|
||||||
|
|
||||||
<elements>
|
<elements>
|
||||||
<TabTitle translation="SETTINGS" icon="dashboard/settings.svg" />
|
<TabTitle translation="SETTINGS" icon="dashboard/settings.svg" />
|
||||||
|
|
||||||
<div flex_wrap="wrap" justify_content="stretch" gap="4">
|
<div flex_wrap="wrap" justify_content="stretch" gap="4" id="settings_root" />
|
||||||
<!-- Home screen -->
|
|
||||||
<rectangle macro="group_box">
|
|
||||||
<GroupBoxTitle translation="HOME_SCREEN" src_builtin="dashboard/wayvr_dashboard.svg" />
|
|
||||||
<CheckBox id="cb_hide_username" translation="APP_SETTINGS.HIDE_USERNAME" />
|
|
||||||
</rectangle>
|
|
||||||
|
|
||||||
<!-- General settings -->
|
|
||||||
<rectangle macro="group_box">
|
|
||||||
<GroupBoxTitle translation="GENERAL_SETTINGS" src_builtin="dashboard/settings.svg" />
|
|
||||||
<CheckBox id="cb_am_pm_clock" text="AM/PM clock" />
|
|
||||||
<CheckBox id="cb_opaque_background" translation="APP_SETTINGS.OPAQUE_BACKGROUND" />
|
|
||||||
</rectangle>
|
|
||||||
|
|
||||||
<!-- Application launcher -->
|
|
||||||
<rectangle macro="group_box">
|
|
||||||
<GroupBoxTitle translation="APPLICATION_LAUNCHER" src_builtin="dashboard/apps.svg" />
|
|
||||||
<CheckBox id="cb_xwayland_by_default" translation="APP_SETTINGS.RUN_IN_XWAYLAND_MODE_BY_DEFAULT" />
|
|
||||||
</rectangle>
|
|
||||||
|
|
||||||
<!-- headset settings -->
|
|
||||||
<rectangle macro="group_box">
|
|
||||||
<GroupBoxTitle translation="APP_SETTINGS.HEADSET_SETTINGS" src_builtin="dashboard/vr.svg" />
|
|
||||||
<label translation="APP_SETTINGS.BRIGHTNESS" />
|
|
||||||
<Slider width="100" height="24" min_value="0.0" max_value="100.0" />
|
|
||||||
</rectangle>
|
|
||||||
|
|
||||||
<!-- wlx-overlay-s settings -->
|
|
||||||
<rectangle macro="group_box">
|
|
||||||
<GroupBoxTitle translation="APP_SETTINGS.WLX_OVERLAY_S_SETTINGS" src_builtin="dashboard/vr.svg" />
|
|
||||||
<CheckBox translation="APP_SETTINGS.WLX.NOTIFICATIONS_ENABLED" />
|
|
||||||
<CheckBox translation="APP_SETTINGS.WLX.NOTIFICATIONS_SOUND_ENABLED" />
|
|
||||||
<CheckBox translation="APP_SETTINGS.WLX.KEYBOARD_SOUND_ENABLED" />
|
|
||||||
<CheckBox translation="APP_SETTINGS.WLX.BLOCK_GAME_INPUT" />
|
|
||||||
<label translation="APP_SETTINGS.WLX.SPACE_DRAG_MULTIPLIER" />
|
|
||||||
<Slider width="100" height="24" min_value="0.0" max_value="3.0" />
|
|
||||||
<CheckBox translation="APP_SETTINGS.WLX.SPACE_DRAG_ROTATION_ENABLED" />
|
|
||||||
<CheckBox translation="APP_SETTINGS.WLX.SHOW_SKYBOX" />
|
|
||||||
<CheckBox translation="APP_SETTINGS.WLX.ENABLE_PASSTHROUGH" />
|
|
||||||
</rectangle>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Button color="#AA3333" height="32" sprite_src_builtin="dashboard/refresh.svg" translation="APP_SETTINGS.RESTART_SOFTWARE" />
|
<Button color="#AA3333" height="32" sprite_src_builtin="dashboard/refresh.svg" translation="APP_SETTINGS.RESTART_SOFTWARE" />
|
||||||
|
|||||||
@@ -3,23 +3,68 @@
|
|||||||
"RECENTER_PLAYSPACE": "Re-center playspace"
|
"RECENTER_PLAYSPACE": "Re-center playspace"
|
||||||
},
|
},
|
||||||
"APP_SETTINGS": {
|
"APP_SETTINGS": {
|
||||||
|
"LOOK_AND_FEEL": "Look & Feel",
|
||||||
|
|
||||||
|
"OPAQUE_BACKGROUND": "Opaque background",
|
||||||
|
"HIDE_USERNAME": "Hide username",
|
||||||
|
"HIDE_GRAB_HELP": "Hide grab help",
|
||||||
|
"ANIMATION_SPEED": "UI Animation speed",
|
||||||
|
"ROUND_MULTIPLIER": "UI Edge roundness",
|
||||||
|
"SINGLE_SET_MODE": "Single set mode",
|
||||||
|
"USE_SKYBOX": "Enable skybox",
|
||||||
|
"USE_PASSTHROUGH": "Enable passthrough",
|
||||||
|
"CLOCK_12H": "12-hour clock",
|
||||||
|
|
||||||
|
"FEATURES": "Features",
|
||||||
|
|
||||||
|
"NOTIFICATIONS_ENABLED": "Enable notifications",
|
||||||
|
"NOTIFICATIONS_SOUND_ENABLED": "Notification sounds",
|
||||||
|
"KEYBOARD_SOUND_ENABLED": "Keyboard sounds",
|
||||||
|
"SPACE_DRAG_MULTIPLIER": "Space drag multiplier",
|
||||||
|
"SPACE_DRAG_UNLOCKED": "Allow space drag on all axes",
|
||||||
|
"SPACE_ROTATE_UNLOCKED": "Allow space rotate on all axes",
|
||||||
|
"BLOCK_GAME_INPUT": "Block game input",
|
||||||
|
"BLOCK_GAME_INPUT_IGNORE_WATCH": "Ignore watch when blocking input",
|
||||||
|
|
||||||
|
"CONTROLS": "Controls",
|
||||||
|
|
||||||
|
"FOCUS_FOLLOWS_MOUSE_MODE": "Mouse move on trigger touch",
|
||||||
|
"LEFT_HANDED_MOUSE": "Left-handed mouse",
|
||||||
|
"ALLOW_SLIDING": "Stick interaction during grab",
|
||||||
|
"INVERT_SCROLL_DIRECTION_X": "Invert horizontal scroll direction",
|
||||||
|
"INVERT_SCROLL_DIRECTION_Y": "Invert vertical scroll direction",
|
||||||
|
"SCROLL_SPEED": "Scroll speed",
|
||||||
|
"LONG_PRESS_DURATION": "Long press duration",
|
||||||
|
"POINTER_LERP_FACTOR": "Pointer smoothing",
|
||||||
|
"XR_CLICK_SENSITIVITY": "XR click sensitivity",
|
||||||
|
"XR_CLICK_SENSITIVITY_RELEASE": "XR release sensitivity",
|
||||||
|
"CLICK_FREEZE_TIME_MS": "Click freeze time (ms)",
|
||||||
|
|
||||||
|
"MISC": "Miscellaneous",
|
||||||
|
|
||||||
|
"XWAYLAND_BY_DEFAULT": "Run apps in Compatibility mode by default",
|
||||||
|
"UPRIGHT_SCREEN_FIX": "Upright screen fix",
|
||||||
|
"DOUBLE_CURSOR_FIX": "Double cursor fix",
|
||||||
|
"SCREEN_RENDER_DOWN": "Render screen at lower resolution",
|
||||||
|
|
||||||
|
"UPRIGHT_SCREEN_FIX_HELP": "Fixes upright screens on some desktops",
|
||||||
|
"DOUBLE_CURSOR_FIX_HELP": "Enable this if you see 2 cursors",
|
||||||
|
"SINGLE_SET_MODE_HELP": "Optimize the watch for working with a single set",
|
||||||
|
"XR_CLICK_SENSITIVITY_HELP": "Analog trigger sensitivity",
|
||||||
|
"XR_CLICK_SENSITIVITY_RELEASE_HELP": "Must be lower than click",
|
||||||
|
"CLICK_FREEZE_TIME_MS_HELP": "Helps with double-click precision",
|
||||||
|
"LEFT_HANDED_MOUSE_HELP": "Use this if mouse buttons are swapped",
|
||||||
|
"BLOCK_GAME_INPUT_HELP": "Blocks all input when an overlay is hovered",
|
||||||
|
"BLOCK_GAME_INPUT_IGNORE_WATCH_HELP": "Do not block input when watch is hovered",
|
||||||
|
"USE_SKYBOX_HELP": "Show a skybox if there's no scene app or passthrough",
|
||||||
|
"USE_PASSTHROUGH_HELP": "Allow passthrough if the XR runtime supports it",
|
||||||
|
"SCREEN_RENDER_DOWN_HELP": "Helps with aliasing on high-res screens",
|
||||||
|
|
||||||
|
"__UNUSED": "---- Below this are unused values ----",
|
||||||
|
|
||||||
"BRIGHTNESS": "Brightness",
|
"BRIGHTNESS": "Brightness",
|
||||||
"HEADSET_SETTINGS": "Headset settings",
|
"HEADSET_SETTINGS": "Headset settings",
|
||||||
"HIDE_USERNAME": "Hide username",
|
"RESTART_SOFTWARE": "Restart software"
|
||||||
"OPAQUE_BACKGROUND": "Opaque background",
|
|
||||||
"RESTART_SOFTWARE": "Restart software",
|
|
||||||
"RUN_IN_XWAYLAND_MODE_BY_DEFAULT": "Run in XWayland mode by default",
|
|
||||||
"WLX": {
|
|
||||||
"BLOCK_GAME_INPUT": "Block game input",
|
|
||||||
"ENABLE_PASSTHROUGH": "Enable passthrough",
|
|
||||||
"KEYBOARD_SOUND_ENABLED": "Keyboard sound enabled",
|
|
||||||
"NOTIFICATIONS_ENABLED": "Notifications enabled",
|
|
||||||
"NOTIFICATIONS_SOUND_ENABLED": "Notifications sound enabled",
|
|
||||||
"SHOW_SKYBOX": "Show skybox",
|
|
||||||
"SPACE_DRAG_MULTIPLIER": "Space-drag multiplier",
|
|
||||||
"SPACE_DRAG_ROTATION_ENABLED": "Enable rotation in space-drag"
|
|
||||||
},
|
|
||||||
"WLX_OVERLAY_S_SETTINGS": "WlxOverlay-S settings"
|
|
||||||
},
|
},
|
||||||
"APPLICATION_LAUNCHER": "Application launcher",
|
"APPLICATION_LAUNCHER": "Application launcher",
|
||||||
"APPLICATION_STARTED": "Application started",
|
"APPLICATION_STARTED": "Application started",
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ use wgui::{
|
|||||||
use wlx_common::{audio, dash_interface::BoxDashInterface, timestep::Timestep};
|
use wlx_common::{audio, dash_interface::BoxDashInterface, timestep::Timestep};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assets, settings,
|
assets,
|
||||||
tab::{
|
tab::{
|
||||||
Tab, TabType, apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, processes::TabProcesses,
|
apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, processes::TabProcesses, settings::TabSettings,
|
||||||
settings::TabSettings,
|
Tab, TabType,
|
||||||
},
|
},
|
||||||
util::{
|
util::{
|
||||||
popup_manager::{MountPopupParams, PopupManager, PopupManagerParams},
|
popup_manager::{MountPopupParams, PopupManager, PopupManagerParams},
|
||||||
@@ -41,7 +41,6 @@ pub struct Frontend<T> {
|
|||||||
pub layout: Layout,
|
pub layout: Layout,
|
||||||
globals: WguiGlobals,
|
globals: WguiGlobals,
|
||||||
|
|
||||||
pub settings: Box<dyn settings::SettingsIO>,
|
|
||||||
pub interface: BoxDashInterface<T>,
|
pub interface: BoxDashInterface<T>,
|
||||||
|
|
||||||
// async runtime executor
|
// async runtime executor
|
||||||
@@ -79,7 +78,6 @@ pub struct FrontendUpdateResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct InitParams<T> {
|
pub struct InitParams<T> {
|
||||||
pub settings: Box<dyn settings::SettingsIO>,
|
|
||||||
pub interface: BoxDashInterface<T>,
|
pub interface: BoxDashInterface<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +102,7 @@ pub enum FrontendTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: 'static> Frontend<T> {
|
impl<T: 'static> Frontend<T> {
|
||||||
pub fn new(params: InitParams<T>) -> anyhow::Result<Frontend<T>> {
|
pub fn new(params: InitParams<T>, data: &mut T) -> anyhow::Result<Frontend<T>> {
|
||||||
let mut assets = Box::new(assets::Asset {});
|
let mut assets = Box::new(assets::Asset {});
|
||||||
|
|
||||||
let font_binary_bold = assets.load_from_path_gzip("Quicksand-Bold.ttf.gz")?;
|
let font_binary_bold = assets.load_from_path_gzip("Quicksand-Bold.ttf.gz")?;
|
||||||
@@ -159,7 +157,6 @@ impl<T: 'static> Frontend<T> {
|
|||||||
id_rect_content,
|
id_rect_content,
|
||||||
},
|
},
|
||||||
timestep,
|
timestep,
|
||||||
settings: params.settings,
|
|
||||||
interface: params.interface,
|
interface: params.interface,
|
||||||
popup_manager,
|
popup_manager,
|
||||||
toast_manager,
|
toast_manager,
|
||||||
@@ -170,8 +167,8 @@ impl<T: 'static> Frontend<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// init some things first
|
// init some things first
|
||||||
frontend.update_background()?;
|
frontend.update_background(data)?;
|
||||||
frontend.update_time()?;
|
frontend.update_time(data)?;
|
||||||
|
|
||||||
Frontend::register_widgets(&mut frontend)?;
|
Frontend::register_widgets(&mut frontend)?;
|
||||||
|
|
||||||
@@ -232,7 +229,7 @@ impl<T: 'static> Frontend<T> {
|
|||||||
fn tick(&mut self, params: FrontendUpdateParams<T>) -> anyhow::Result<FrontendUpdateResult> {
|
fn tick(&mut self, params: FrontendUpdateParams<T>) -> anyhow::Result<FrontendUpdateResult> {
|
||||||
// fixme: timer events instead of this thing
|
// fixme: timer events instead of this thing
|
||||||
if self.ticks.is_multiple_of(1000) {
|
if self.ticks.is_multiple_of(1000) {
|
||||||
self.update_time()?;
|
self.update_time(params.data)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -253,7 +250,7 @@ impl<T: 'static> Frontend<T> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_time(&mut self) -> anyhow::Result<()> {
|
fn update_time(&mut self, data: &mut T) -> anyhow::Result<()> {
|
||||||
let mut c = self.layout.start_common();
|
let mut c = self.layout.start_common();
|
||||||
let mut common = c.common();
|
let mut common = c.common();
|
||||||
|
|
||||||
@@ -266,12 +263,12 @@ impl<T: 'static> Frontend<T> {
|
|||||||
let hours = now.hour();
|
let hours = now.hour();
|
||||||
let minutes = now.minute();
|
let minutes = now.minute();
|
||||||
|
|
||||||
let text: String = if !self.settings.get().general.am_pm_clock {
|
let text: String = if self.interface.general_config(data).clock_12h {
|
||||||
format!("{hours:02}:{minutes:02}")
|
|
||||||
} else {
|
|
||||||
let hours_ampm = (hours + 11) % 12 + 1;
|
let hours_ampm = (hours + 11) % 12 + 1;
|
||||||
let suffix = if hours >= 12 { "PM" } else { "AM" };
|
let suffix = if hours >= 12 { "PM" } else { "AM" };
|
||||||
format!("{hours_ampm:02}:{minutes:02} {suffix}")
|
format!("{hours_ampm:02}:{minutes:02} {suffix}")
|
||||||
|
} else {
|
||||||
|
format!("{hours:02}:{minutes:02}")
|
||||||
};
|
};
|
||||||
|
|
||||||
label.set_text(&mut common, Translation::from_raw_text(&text));
|
label.set_text(&mut common, Translation::from_raw_text(&text));
|
||||||
@@ -281,13 +278,15 @@ impl<T: 'static> Frontend<T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mount_popup(&mut self, params: MountPopupParams) -> anyhow::Result<()> {
|
fn mount_popup(&mut self, params: MountPopupParams, data: &mut T) -> anyhow::Result<()> {
|
||||||
|
let config = self.interface.general_config(data);
|
||||||
|
|
||||||
self.popup_manager.mount_popup(
|
self.popup_manager.mount_popup(
|
||||||
self.globals.clone(),
|
self.globals.clone(),
|
||||||
self.settings.as_ref(),
|
|
||||||
&mut self.layout,
|
&mut self.layout,
|
||||||
self.tasks.clone(),
|
self.tasks.clone(),
|
||||||
params,
|
params,
|
||||||
|
config,
|
||||||
)?;
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -299,7 +298,7 @@ impl<T: 'static> Frontend<T> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_background(&self) -> anyhow::Result<()> {
|
fn update_background(&mut self, data: &mut T) -> anyhow::Result<()> {
|
||||||
let Some(mut rect) = self
|
let Some(mut rect) = self
|
||||||
.layout
|
.layout
|
||||||
.state
|
.state
|
||||||
@@ -309,10 +308,10 @@ impl<T: 'static> Frontend<T> {
|
|||||||
anyhow::bail!("");
|
anyhow::bail!("");
|
||||||
};
|
};
|
||||||
|
|
||||||
let (alpha1, alpha2) = if !self.settings.get().general.opaque_background {
|
let (alpha1, alpha2) = if self.interface.general_config(data).opaque_background {
|
||||||
(0.8666, 0.9333)
|
|
||||||
} else {
|
|
||||||
(1.0, 1.0)
|
(1.0, 1.0)
|
||||||
|
} else {
|
||||||
|
(0.8666, 0.9333)
|
||||||
};
|
};
|
||||||
|
|
||||||
rect.params.color.a = alpha1;
|
rect.params.color.a = alpha1;
|
||||||
@@ -324,9 +323,9 @@ impl<T: 'static> Frontend<T> {
|
|||||||
fn process_task(&mut self, params: &mut FrontendUpdateParams<T>, task: FrontendTask) -> anyhow::Result<()> {
|
fn process_task(&mut self, params: &mut FrontendUpdateParams<T>, task: FrontendTask) -> anyhow::Result<()> {
|
||||||
match task {
|
match task {
|
||||||
FrontendTask::SetTab(tab_type) => self.set_tab(params.data, tab_type)?,
|
FrontendTask::SetTab(tab_type) => self.set_tab(params.data, tab_type)?,
|
||||||
FrontendTask::RefreshClock => self.update_time()?,
|
FrontendTask::RefreshClock => self.update_time(params.data)?,
|
||||||
FrontendTask::RefreshBackground => self.update_background()?,
|
FrontendTask::RefreshBackground => self.update_background(params.data)?,
|
||||||
FrontendTask::MountPopup(params) => self.mount_popup(params)?,
|
FrontendTask::MountPopup(popup_params) => self.mount_popup(popup_params, params.data)?,
|
||||||
FrontendTask::RefreshPopupManager => self.refresh_popup_manager()?,
|
FrontendTask::RefreshPopupManager => self.refresh_popup_manager()?,
|
||||||
FrontendTask::ShowAudioSettings => self.action_show_audio_settings()?,
|
FrontendTask::ShowAudioSettings => self.action_show_audio_settings()?,
|
||||||
FrontendTask::UpdateAudioSettingsView => self.action_update_audio_settings()?,
|
FrontendTask::UpdateAudioSettingsView => self.action_update_audio_settings()?,
|
||||||
@@ -343,12 +342,12 @@ impl<T: 'static> Frontend<T> {
|
|||||||
self.layout.remove_children(widget_content.id);
|
self.layout.remove_children(widget_content.id);
|
||||||
|
|
||||||
let tab: Box<dyn Tab<T>> = match tab_type {
|
let tab: Box<dyn Tab<T>> = match tab_type {
|
||||||
TabType::Home => Box::new(TabHome::new(self, widget_content.id)?),
|
TabType::Home => Box::new(TabHome::new(self, widget_content.id, data)?),
|
||||||
TabType::Apps => Box::new(TabApps::new(self, widget_content.id, data)?),
|
TabType::Apps => Box::new(TabApps::new(self, widget_content.id, data)?),
|
||||||
TabType::Games => Box::new(TabGames::new(self, widget_content.id)?),
|
TabType::Games => Box::new(TabGames::new(self, widget_content.id)?),
|
||||||
TabType::Monado => Box::new(TabMonado::new(self, widget_content.id)?),
|
TabType::Monado => Box::new(TabMonado::new(self, widget_content.id)?),
|
||||||
TabType::Processes => Box::new(TabProcesses::new(self, widget_content.id)?),
|
TabType::Processes => Box::new(TabProcesses::new(self, widget_content.id)?),
|
||||||
TabType::Settings => Box::new(TabSettings::new(self, widget_content.id)?),
|
TabType::Settings => Box::new(TabSettings::new(self, widget_content.id, data)?),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.current_tab = Some(tab);
|
self.current_tab = Some(tab);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
mod assets;
|
mod assets;
|
||||||
pub mod frontend;
|
pub mod frontend;
|
||||||
pub mod settings;
|
|
||||||
mod tab;
|
mod tab;
|
||||||
mod util;
|
mod util;
|
||||||
mod various;
|
mod various;
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
|
||||||
pub struct HomeScreen {
|
|
||||||
pub hide_username: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
|
||||||
pub struct General {
|
|
||||||
pub am_pm_clock: bool,
|
|
||||||
pub opaque_background: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
|
||||||
pub struct Tweaks {
|
|
||||||
pub xwayland_by_default: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize)]
|
|
||||||
pub struct Settings {
|
|
||||||
pub home_screen: HomeScreen,
|
|
||||||
pub general: General,
|
|
||||||
pub tweaks: Tweaks,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Settings {
|
|
||||||
pub fn save(&self) -> String {
|
|
||||||
serde_json::to_string_pretty(&self).unwrap() /* want panic */
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn load(input: &str) -> anyhow::Result<Settings> {
|
|
||||||
Ok(serde_json::from_str::<Settings>(input)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait SettingsIO {
|
|
||||||
fn get_mut(&mut self) -> &mut Settings;
|
|
||||||
fn get(&self) -> &Settings;
|
|
||||||
fn save_to_disk(&mut self);
|
|
||||||
fn read_from_disk(&mut self);
|
|
||||||
fn mark_as_dirty(&mut self);
|
|
||||||
}
|
|
||||||
@@ -104,7 +104,7 @@ fn on_app_click(
|
|||||||
layout: data.layout,
|
layout: data.layout,
|
||||||
parent_id: data.id_content,
|
parent_id: data.id_content,
|
||||||
frontend_tasks: &frontend_tasks,
|
frontend_tasks: &frontend_tasks,
|
||||||
settings: data.settings,
|
config: data.config,
|
||||||
on_launched,
|
on_launched,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ use wgui::{
|
|||||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||||
widget::label::WidgetLabel,
|
widget::label::WidgetLabel,
|
||||||
};
|
};
|
||||||
|
use wlx_common::config::GeneralConfig;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
frontend::{Frontend, FrontendTask},
|
frontend::{Frontend, FrontendTask},
|
||||||
settings,
|
|
||||||
tab::{Tab, TabType},
|
tab::{Tab, TabType},
|
||||||
various,
|
various,
|
||||||
};
|
};
|
||||||
@@ -29,7 +29,7 @@ impl<T> Tab<T> for TabHome<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_label_hello(common: &mut CallbackDataCommon, label_hello: Widget, settings: &settings::Settings) {
|
fn configure_label_hello(common: &mut CallbackDataCommon, label_hello: Widget, config: &GeneralConfig) {
|
||||||
let mut username = various::get_username();
|
let mut username = various::get_username();
|
||||||
// first character as uppercase
|
// first character as uppercase
|
||||||
if let Some(first) = username.chars().next() {
|
if let Some(first) = username.chars().next() {
|
||||||
@@ -37,7 +37,7 @@ fn configure_label_hello(common: &mut CallbackDataCommon, label_hello: Widget, s
|
|||||||
username.replace_range(0..1, &first);
|
username.replace_range(0..1, &first);
|
||||||
}
|
}
|
||||||
|
|
||||||
let translated = if !settings.home_screen.hide_username {
|
let translated = if !config.hide_username {
|
||||||
common.i18n().translate_and_replace("HELLO_USER", ("{USER}", &username))
|
common.i18n().translate_and_replace("HELLO_USER", ("{USER}", &username))
|
||||||
} else {
|
} else {
|
||||||
common.i18n().translate("HELLO").to_string()
|
common.i18n().translate("HELLO").to_string()
|
||||||
@@ -48,7 +48,7 @@ fn configure_label_hello(common: &mut CallbackDataCommon, label_hello: Widget, s
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T> TabHome<T> {
|
impl<T> TabHome<T> {
|
||||||
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID) -> anyhow::Result<Self> {
|
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID, data: &mut T) -> anyhow::Result<Self> {
|
||||||
let state = wgui::parser::parse_from_assets(
|
let state = wgui::parser::parse_from_assets(
|
||||||
&ParseDocumentParams {
|
&ParseDocumentParams {
|
||||||
globals: frontend.layout.state.globals.clone(),
|
globals: frontend.layout.state.globals.clone(),
|
||||||
@@ -61,7 +61,7 @@ impl<T> TabHome<T> {
|
|||||||
|
|
||||||
let mut c = frontend.layout.start_common();
|
let mut c = frontend.layout.start_common();
|
||||||
let widget_label = state.fetch_widget(&c.layout.state, "label_hello")?.widget;
|
let widget_label = state.fetch_widget(&c.layout.state, "label_hello")?.widget;
|
||||||
configure_label_hello(&mut c.common(), widget_label, frontend.settings.get_mut());
|
configure_label_hello(&mut c.common(), widget_label, frontend.interface.general_config(data));
|
||||||
|
|
||||||
let btn_apps = state.fetch_component_as::<ComponentButton>("btn_apps")?;
|
let btn_apps = state.fetch_component_as::<ComponentButton>("btn_apps")?;
|
||||||
let btn_games = state.fetch_component_as::<ComponentButton>("btn_games")?;
|
let btn_games = state.fetch_component_as::<ComponentButton>("btn_games")?;
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
use std::{marker::PhantomData, rc::Rc};
|
use std::{collections::HashMap, marker::PhantomData, rc::Rc};
|
||||||
|
|
||||||
|
use strum::AsRefStr;
|
||||||
use wgui::{
|
use wgui::{
|
||||||
assets::AssetPath,
|
assets::AssetPath,
|
||||||
components::checkbox::ComponentCheckbox,
|
components::{checkbox::ComponentCheckbox, slider::ComponentSlider},
|
||||||
layout::WidgetID,
|
layout::{Layout, WidgetID},
|
||||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||||
task::Tasks,
|
task::Tasks,
|
||||||
};
|
};
|
||||||
|
use wlx_common::config::GeneralConfig;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
frontend::{Frontend, FrontendTask},
|
frontend::{Frontend, FrontendTask},
|
||||||
settings,
|
|
||||||
tab::{Tab, TabType},
|
tab::{Tab, TabType},
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Task {
|
enum Task {
|
||||||
ToggleSetting(SettingType, bool),
|
UpdateBool(SettingType, bool),
|
||||||
|
UpdateFloat(SettingType, f32),
|
||||||
|
UpdateInt(SettingType, i32),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TabSettings<T> {
|
pub struct TabSettings<T> {
|
||||||
@@ -31,10 +34,22 @@ impl<T> Tab<T> for TabSettings<T> {
|
|||||||
TabType::Settings
|
TabType::Settings
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, frontend: &mut Frontend<T>, _data: &mut T) -> anyhow::Result<()> {
|
fn update(&mut self, frontend: &mut Frontend<T>, data: &mut T) -> anyhow::Result<()> {
|
||||||
|
let config = frontend.interface.general_config(data);
|
||||||
for task in self.tasks.drain() {
|
for task in self.tasks.drain() {
|
||||||
match task {
|
match task {
|
||||||
Task::ToggleSetting(setting, n) => self.toggle_setting(frontend, setting, n),
|
Task::UpdateBool(setting, n) => {
|
||||||
|
setting.get_frontend_task().map(|task| frontend.tasks.push(task));
|
||||||
|
*setting.mut_bool(config) = n;
|
||||||
|
}
|
||||||
|
Task::UpdateFloat(setting, n) => {
|
||||||
|
setting.get_frontend_task().map(|task| frontend.tasks.push(task));
|
||||||
|
*setting.mut_f32(config) = n;
|
||||||
|
}
|
||||||
|
Task::UpdateInt(setting, n) => {
|
||||||
|
setting.get_frontend_task().map(|task| frontend.tasks.push(task));
|
||||||
|
*setting.mut_i32(config) = n;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -42,109 +57,375 @@ impl<T> Tab<T> for TabSettings<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::enum_variant_names)]
|
#[allow(clippy::enum_variant_names)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Copy, AsRefStr)]
|
||||||
enum SettingType {
|
enum SettingType {
|
||||||
DashHideUsername,
|
AnimationSpeed,
|
||||||
DashAmPmClock,
|
RoundMultiplier,
|
||||||
DashOpaqueBackground,
|
InvertScrollDirectionX,
|
||||||
DashXwaylandByDefault,
|
InvertScrollDirectionY,
|
||||||
|
ScrollSpeed,
|
||||||
|
LongPressDuration,
|
||||||
|
NotificationsEnabled,
|
||||||
|
NotificationsSoundEnabled,
|
||||||
|
KeyboardSoundEnabled,
|
||||||
|
UprightScreenFix,
|
||||||
|
DoubleCursorFix,
|
||||||
|
SingleSetMode,
|
||||||
|
HideGrabHelp,
|
||||||
|
XrClickSensitivity,
|
||||||
|
XrClickSensitivityRelease,
|
||||||
|
AllowSliding,
|
||||||
|
ClickFreezeTimeMs,
|
||||||
|
FocusFollowsMouseMode,
|
||||||
|
LeftHandedMouse,
|
||||||
|
BlockGameInput,
|
||||||
|
BlockGameInputIgnoreWatch,
|
||||||
|
SpaceDragMultiplier,
|
||||||
|
UseSkybox,
|
||||||
|
UsePassthrough,
|
||||||
|
ScreenRenderDown,
|
||||||
|
PointerLerpFactor,
|
||||||
|
SpaceDragUnlocked,
|
||||||
|
SpaceRotateUnlocked,
|
||||||
|
Clock12h,
|
||||||
|
HideUsername,
|
||||||
|
OpaqueBackground,
|
||||||
|
XwaylandByDefault,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SettingType {
|
impl SettingType {
|
||||||
fn get_bool<'a>(&self, settings: &'a mut settings::Settings) -> &'a mut bool {
|
pub fn mut_bool<'a>(self, config: &'a mut GeneralConfig) -> &'a mut bool {
|
||||||
match self {
|
match self {
|
||||||
SettingType::DashHideUsername => &mut settings.home_screen.hide_username,
|
Self::InvertScrollDirectionX => &mut config.invert_scroll_direction_x,
|
||||||
SettingType::DashAmPmClock => &mut settings.general.am_pm_clock,
|
Self::InvertScrollDirectionY => &mut config.invert_scroll_direction_y,
|
||||||
SettingType::DashOpaqueBackground => &mut settings.general.opaque_background,
|
Self::NotificationsEnabled => &mut config.notifications_enabled,
|
||||||
SettingType::DashXwaylandByDefault => &mut settings.tweaks.xwayland_by_default,
|
Self::NotificationsSoundEnabled => &mut config.notifications_sound_enabled,
|
||||||
|
Self::KeyboardSoundEnabled => &mut config.keyboard_sound_enabled,
|
||||||
|
Self::UprightScreenFix => &mut config.upright_screen_fix,
|
||||||
|
Self::DoubleCursorFix => &mut config.double_cursor_fix,
|
||||||
|
Self::SingleSetMode => &mut config.single_set_mode,
|
||||||
|
Self::HideGrabHelp => &mut config.hide_grab_help,
|
||||||
|
Self::AllowSliding => &mut config.allow_sliding,
|
||||||
|
Self::FocusFollowsMouseMode => &mut config.focus_follows_mouse_mode,
|
||||||
|
Self::LeftHandedMouse => &mut config.left_handed_mouse,
|
||||||
|
Self::BlockGameInput => &mut config.block_game_input,
|
||||||
|
Self::BlockGameInputIgnoreWatch => &mut config.block_game_input_ignore_watch,
|
||||||
|
Self::UseSkybox => &mut config.use_skybox,
|
||||||
|
Self::UsePassthrough => &mut config.use_passthrough,
|
||||||
|
Self::ScreenRenderDown => &mut config.screen_render_down,
|
||||||
|
Self::SpaceDragUnlocked => &mut config.space_drag_unlocked,
|
||||||
|
Self::SpaceRotateUnlocked => &mut config.space_rotate_unlocked,
|
||||||
|
Self::Clock12h => &mut config.clock_12h,
|
||||||
|
Self::HideUsername => &mut config.hide_username,
|
||||||
|
Self::OpaqueBackground => &mut config.opaque_background,
|
||||||
|
Self::XwaylandByDefault => &mut config.xwayland_by_default,
|
||||||
|
_ => panic!("Requested bool for non-bool SettingType"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_f32<'a>(self, config: &'a mut GeneralConfig) -> &'a mut f32 {
|
||||||
|
match self {
|
||||||
|
Self::AnimationSpeed => &mut config.animation_speed,
|
||||||
|
Self::RoundMultiplier => &mut config.round_multiplier,
|
||||||
|
Self::ScrollSpeed => &mut config.scroll_speed,
|
||||||
|
Self::LongPressDuration => &mut config.long_press_duration,
|
||||||
|
Self::XrClickSensitivity => &mut config.xr_click_sensitivity,
|
||||||
|
Self::XrClickSensitivityRelease => &mut config.xr_click_sensitivity_release,
|
||||||
|
Self::SpaceDragMultiplier => &mut config.space_drag_multiplier,
|
||||||
|
Self::PointerLerpFactor => &mut config.pointer_lerp_factor,
|
||||||
|
_ => panic!("Requested f32 for non-f32 SettingType"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mut_i32<'a>(self, config: &'a mut GeneralConfig) -> &'a mut i32 {
|
||||||
|
match self {
|
||||||
|
Self::ClickFreezeTimeMs => &mut config.click_freeze_time_ms,
|
||||||
|
_ => panic!("Requested i32 for non-i32 SettingType"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ok is translation, Err is raw text
|
||||||
|
fn get_translation(self) -> Result<&'static str, &'static str> {
|
||||||
|
match self {
|
||||||
|
Self::AnimationSpeed => Ok("APP_SETTINGS.ANIMATION_SPEED"),
|
||||||
|
Self::RoundMultiplier => Ok("APP_SETTINGS.ROUND_MULTIPLIER"),
|
||||||
|
Self::InvertScrollDirectionX => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_X"),
|
||||||
|
Self::InvertScrollDirectionY => Ok("APP_SETTINGS.INVERT_SCROLL_DIRECTION_Y"),
|
||||||
|
Self::ScrollSpeed => Ok("APP_SETTINGS.SCROLL_SPEED"),
|
||||||
|
Self::LongPressDuration => Ok("APP_SETTINGS.LONG_PRESS_DURATION"),
|
||||||
|
Self::NotificationsEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_ENABLED"),
|
||||||
|
Self::NotificationsSoundEnabled => Ok("APP_SETTINGS.NOTIFICATIONS_SOUND_ENABLED"),
|
||||||
|
Self::KeyboardSoundEnabled => Ok("APP_SETTINGS.KEYBOARD_SOUND_ENABLED"),
|
||||||
|
Self::UprightScreenFix => Ok("APP_SETTINGS.UPRIGHT_SCREEN_FIX"),
|
||||||
|
Self::DoubleCursorFix => Ok("APP_SETTINGS.DOUBLE_CURSOR_FIX"),
|
||||||
|
Self::SingleSetMode => Ok("APP_SETTINGS.SINGLE_SET_MODE"),
|
||||||
|
Self::HideGrabHelp => Ok("APP_SETTINGS.HIDE_GRAB_HELP"),
|
||||||
|
Self::XrClickSensitivity => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY"),
|
||||||
|
Self::XrClickSensitivityRelease => Ok("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE"),
|
||||||
|
Self::AllowSliding => Ok("APP_SETTINGS.ALLOW_SLIDING"),
|
||||||
|
Self::ClickFreezeTimeMs => Ok("APP_SETTINGS.CLICK_FREEZE_TIME_MS"),
|
||||||
|
Self::FocusFollowsMouseMode => Ok("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE"),
|
||||||
|
Self::LeftHandedMouse => Ok("APP_SETTINGS.LEFT_HANDED_MOUSE"),
|
||||||
|
Self::BlockGameInput => Ok("APP_SETTINGS.BLOCK_GAME_INPUT"),
|
||||||
|
Self::BlockGameInputIgnoreWatch => Ok("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH"),
|
||||||
|
Self::SpaceDragMultiplier => Ok("APP_SETTINGS.SPACE_DRAG_MULTIPLIER"),
|
||||||
|
Self::UseSkybox => Ok("APP_SETTINGS.USE_SKYBOX"),
|
||||||
|
Self::UsePassthrough => Ok("APP_SETTINGS.USE_PASSTHROUGH"),
|
||||||
|
Self::ScreenRenderDown => Ok("APP_SETTINGS.SCREEN_RENDER_DOWN"),
|
||||||
|
Self::PointerLerpFactor => Ok("APP_SETTINGS.POINTER_LERP_FACTOR"),
|
||||||
|
Self::SpaceDragUnlocked => Ok("APP_SETTINGS.SPACE_DRAG_UNLOCKED"),
|
||||||
|
Self::SpaceRotateUnlocked => Ok("APP_SETTINGS.SPACE_ROTATE_UNLOCKED"),
|
||||||
|
Self::Clock12h => Ok("APP_SETTINGS.CLOCK_12H"),
|
||||||
|
Self::HideUsername => Ok("APP_SETTINGS.HIDE_USERNAME"),
|
||||||
|
Self::OpaqueBackground => Ok("APP_SETTINGS.OPAQUE_BACKGROUND"),
|
||||||
|
Self::XwaylandByDefault => Ok("APP_SETTINGS.XWAYLAND_BY_DEFAULT"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_tooltip(self) -> Option<&'static str> {
|
||||||
|
match self {
|
||||||
|
Self::UprightScreenFix => Some("APP_SETTINGS.UPRIGHT_SCREEN_FIX_HELP"),
|
||||||
|
Self::DoubleCursorFix => Some("APP_SETTINGS.DOUBLE_CURSOR_FIX_HELP"),
|
||||||
|
Self::SingleSetMode => Some("APP_SETTINGS.SINGLE_SET_MODE_HELP"),
|
||||||
|
Self::XrClickSensitivity => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_HELP"),
|
||||||
|
Self::XrClickSensitivityRelease => Some("APP_SETTINGS.XR_CLICK_SENSITIVITY_RELEASE_HELP"),
|
||||||
|
Self::FocusFollowsMouseMode => Some("APP_SETTINGS.FOCUS_FOLLOWS_MOUSE_MODE_HELP"),
|
||||||
|
Self::LeftHandedMouse => Some("APP_SETTINGS.LEFT_HANDED_MOUSE_HELP"),
|
||||||
|
Self::BlockGameInput => Some("APP_SETTINGS.BLOCK_GAME_INPUT_HELP"),
|
||||||
|
Self::BlockGameInputIgnoreWatch => Some("APP_SETTINGS.BLOCK_GAME_INPUT_IGNORE_WATCH_HELP"),
|
||||||
|
Self::UseSkybox => Some("APP_SETTINGS.USE_SKYBOX_HELP"),
|
||||||
|
Self::UsePassthrough => Some("APP_SETTINGS.USE_PASSTHROUGH_HELP"),
|
||||||
|
Self::ScreenRenderDown => Some("APP_SETTINGS.SCREEN_RENDER_DOWN_HELP"),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: incorporate this
|
||||||
|
fn requires_restart(self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::AnimationSpeed
|
||||||
|
| Self::RoundMultiplier
|
||||||
|
| Self::UprightScreenFix
|
||||||
|
| Self::DoubleCursorFix
|
||||||
|
| Self::SingleSetMode
|
||||||
|
| Self::UseSkybox
|
||||||
|
| Self::UsePassthrough
|
||||||
|
| Self::ScreenRenderDown => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_frontend_task(self) -> Option<FrontendTask> {
|
||||||
|
match self {
|
||||||
|
Self::Clock12h => Some(FrontendTask::RefreshClock),
|
||||||
|
Self::OpaqueBackground => Some(FrontendTask::RefreshBackground),
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init_setting_checkbox<T>(
|
macro_rules! category {
|
||||||
frontend: &mut Frontend<T>,
|
($pe:expr, $root:expr, $translation:expr, $icon:expr) => {{
|
||||||
tasks: &Tasks<Task>,
|
let id = $pe.idx.to_string();
|
||||||
checkbox: Rc<ComponentCheckbox>,
|
$pe.idx += 1;
|
||||||
setting: SettingType,
|
|
||||||
additional_frontend_task: Option<FrontendTask>,
|
|
||||||
) -> anyhow::Result<()> {
|
|
||||||
let mut c = frontend.layout.start_common();
|
|
||||||
checkbox.set_checked(&mut c.common(), *setting.get_bool(frontend.settings.get_mut()));
|
|
||||||
|
|
||||||
let tasks = tasks.clone();
|
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||||
let frontend_tasks = frontend.tasks.clone();
|
params.insert(Rc::from("translation"), Rc::from($translation));
|
||||||
|
params.insert(Rc::from("icon"), Rc::from($icon));
|
||||||
|
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||||
|
|
||||||
checkbox.on_toggle(Box::new(move |_common, e| {
|
$pe
|
||||||
tasks.push(Task::ToggleSetting(setting.clone(), e.checked));
|
.parser_state
|
||||||
|
.instantiate_template($pe.doc_params, "SettingsGroupBox", $pe.layout, $root, params)?;
|
||||||
|
|
||||||
if let Some(task) = &additional_frontend_task {
|
$pe.parser_state.get_widget_id(&id)
|
||||||
frontend_tasks.push(task.clone());
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! checkbox {
|
||||||
|
($mp:expr, $root:expr, $setting:expr) => {
|
||||||
|
let id = $mp.idx.to_string();
|
||||||
|
$mp.idx += 1;
|
||||||
|
|
||||||
|
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||||
|
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||||
|
|
||||||
|
match $setting.get_translation() {
|
||||||
|
Ok(translation) => params.insert(Rc::from("translation"), translation.into()),
|
||||||
|
Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(tooltip) = $setting.get_tooltip() {
|
||||||
|
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}));
|
|
||||||
|
|
||||||
c.finish()?;
|
let checked = if *$setting.mut_bool($mp.config) { "1" } else { "0" };
|
||||||
|
params.insert(Rc::from("checked"), Rc::from(checked));
|
||||||
|
|
||||||
|
$mp
|
||||||
|
.parser_state
|
||||||
|
.instantiate_template($mp.doc_params, "CheckBoxSetting", $mp.layout, $root, params)?;
|
||||||
|
|
||||||
|
let checkbox = $mp.parser_state.fetch_component_as::<ComponentCheckbox>(&id)?;
|
||||||
|
checkbox.on_toggle(Box::new({
|
||||||
|
let tasks = $mp.tasks.clone();
|
||||||
|
move |_common, e| {
|
||||||
|
tasks.push(Task::UpdateBool($setting, e.checked));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! slider_f32 {
|
||||||
|
($mp:expr, $root:expr, $setting:expr, $min:expr, $max:expr, $step:expr) => {
|
||||||
|
let id = $mp.idx.to_string();
|
||||||
|
$mp.idx += 1;
|
||||||
|
|
||||||
|
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||||
|
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||||
|
|
||||||
|
match $setting.get_translation() {
|
||||||
|
Ok(translation) => params.insert(Rc::from("translation"), translation.into()),
|
||||||
|
Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(tooltip) = $setting.get_tooltip() {
|
||||||
|
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = $setting.mut_f32($mp.config).to_string();
|
||||||
|
params.insert(Rc::from("value"), Rc::from(value));
|
||||||
|
params.insert(Rc::from("min"), Rc::from($min.to_string()));
|
||||||
|
params.insert(Rc::from("max"), Rc::from($max.to_string()));
|
||||||
|
params.insert(Rc::from("step"), Rc::from($step.to_string()));
|
||||||
|
|
||||||
|
$mp
|
||||||
|
.parser_state
|
||||||
|
.instantiate_template($mp.doc_params, "SliderSetting", $mp.layout, $root, params)?;
|
||||||
|
|
||||||
|
let slider = $mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
||||||
|
slider.on_value_changed(Box::new({
|
||||||
|
let tasks = $mp.tasks.clone();
|
||||||
|
move |_common, e| {
|
||||||
|
tasks.push(Task::UpdateFloat($setting, e.value));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! slider_i32 {
|
||||||
|
($mp:expr, $root:expr, $setting:expr, $min:expr, $max:expr, $step:expr) => {
|
||||||
|
let id = $mp.idx.to_string();
|
||||||
|
$mp.idx += 1;
|
||||||
|
|
||||||
|
let mut params: HashMap<Rc<str>, Rc<str>> = HashMap::new();
|
||||||
|
params.insert(Rc::from("id"), Rc::from(id.as_ref()));
|
||||||
|
|
||||||
|
match $setting.get_translation() {
|
||||||
|
Ok(translation) => params.insert(Rc::from("translation"), translation.into()),
|
||||||
|
Err(raw_text) => params.insert(Rc::from("text"), raw_text.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(tooltip) = $setting.get_tooltip() {
|
||||||
|
params.insert(Rc::from("tooltip"), Rc::from(tooltip));
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = $setting.mut_i32($mp.config).to_string();
|
||||||
|
params.insert(Rc::from("value"), Rc::from(value));
|
||||||
|
params.insert(Rc::from("min"), Rc::from($min.to_string()));
|
||||||
|
params.insert(Rc::from("max"), Rc::from($max.to_string()));
|
||||||
|
params.insert(Rc::from("step"), Rc::from($step.to_string()));
|
||||||
|
|
||||||
|
$mp
|
||||||
|
.parser_state
|
||||||
|
.instantiate_template($mp.doc_params, "SliderSetting", $mp.layout, $root, params)?;
|
||||||
|
|
||||||
|
let slider = $mp.parser_state.fetch_component_as::<ComponentSlider>(&id)?;
|
||||||
|
slider.on_value_changed(Box::new({
|
||||||
|
let tasks = $mp.tasks.clone();
|
||||||
|
move |_common, e| {
|
||||||
|
tasks.push(Task::UpdateInt($setting, e.value as i32));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MacroParams<'a> {
|
||||||
|
layout: &'a mut Layout,
|
||||||
|
parser_state: &'a mut ParserState,
|
||||||
|
doc_params: &'a ParseDocumentParams<'a>,
|
||||||
|
config: &'a mut GeneralConfig,
|
||||||
|
tasks: Tasks<Task>,
|
||||||
|
idx: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> TabSettings<T> {
|
impl<T> TabSettings<T> {
|
||||||
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID) -> anyhow::Result<Self> {
|
pub fn new(frontend: &mut Frontend<T>, parent_id: WidgetID, data: &mut T) -> anyhow::Result<Self> {
|
||||||
let state = wgui::parser::parse_from_assets(
|
let doc_params = ParseDocumentParams {
|
||||||
&ParseDocumentParams {
|
|
||||||
globals: frontend.layout.state.globals.clone(),
|
globals: frontend.layout.state.globals.clone(),
|
||||||
path: AssetPath::BuiltIn("gui/tab/settings.xml"),
|
path: AssetPath::BuiltIn("gui/tab/settings.xml"),
|
||||||
extra: Default::default(),
|
extra: Default::default(),
|
||||||
},
|
};
|
||||||
&mut frontend.layout,
|
let mut parser_state = wgui::parser::parse_from_assets(&doc_params, &mut frontend.layout, parent_id)?;
|
||||||
parent_id,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let tasks = Tasks::new();
|
let root = parser_state.get_widget_id("settings_root")?;
|
||||||
|
|
||||||
init_setting_checkbox(
|
let mut mp = MacroParams {
|
||||||
frontend,
|
layout: &mut frontend.layout,
|
||||||
&tasks,
|
parser_state: &mut parser_state,
|
||||||
state.data.fetch_component_as::<ComponentCheckbox>("cb_hide_username")?,
|
doc_params: &doc_params,
|
||||||
SettingType::DashHideUsername,
|
config: frontend.interface.general_config(data),
|
||||||
None,
|
tasks: Tasks::default(),
|
||||||
)?;
|
idx: 9001,
|
||||||
|
};
|
||||||
|
|
||||||
init_setting_checkbox(
|
let c = category!(mp, root, "APP_SETTINGS.LOOK_AND_FEEL", "dashboard/settings.svg")?;
|
||||||
frontend,
|
checkbox!(mp, c, SettingType::OpaqueBackground);
|
||||||
&tasks,
|
checkbox!(mp, c, SettingType::HideUsername);
|
||||||
state.data.fetch_component_as::<ComponentCheckbox>("cb_am_pm_clock")?,
|
checkbox!(mp, c, SettingType::HideGrabHelp);
|
||||||
SettingType::DashAmPmClock,
|
slider_f32!(mp, c, SettingType::AnimationSpeed, 0.5, 5.0, 0.1); // min, max, step
|
||||||
None,
|
slider_f32!(mp, c, SettingType::RoundMultiplier, 0.5, 5.0, 0.1);
|
||||||
)?;
|
checkbox!(mp, c, SettingType::SingleSetMode);
|
||||||
|
checkbox!(mp, c, SettingType::UseSkybox);
|
||||||
|
checkbox!(mp, c, SettingType::UsePassthrough);
|
||||||
|
checkbox!(mp, c, SettingType::Clock12h);
|
||||||
|
|
||||||
init_setting_checkbox(
|
let c = category!(mp, root, "APP_SETTINGS.FEATURES", "dashboard/settings.svg")?;
|
||||||
frontend,
|
checkbox!(mp, c, SettingType::NotificationsEnabled);
|
||||||
&tasks,
|
checkbox!(mp, c, SettingType::NotificationsSoundEnabled);
|
||||||
state
|
checkbox!(mp, c, SettingType::KeyboardSoundEnabled);
|
||||||
.data
|
checkbox!(mp, c, SettingType::SpaceDragUnlocked);
|
||||||
.fetch_component_as::<ComponentCheckbox>("cb_opaque_background")?,
|
checkbox!(mp, c, SettingType::SpaceRotateUnlocked);
|
||||||
SettingType::DashOpaqueBackground,
|
slider_f32!(mp, c, SettingType::SpaceDragMultiplier, -10.0, 10.0, 0.5);
|
||||||
Some(FrontendTask::RefreshBackground),
|
checkbox!(mp, c, SettingType::BlockGameInput);
|
||||||
)?;
|
checkbox!(mp, c, SettingType::BlockGameInputIgnoreWatch);
|
||||||
|
|
||||||
init_setting_checkbox(
|
let c = category!(mp, root, "APP_SETTINGS.CONTROLS", "dashboard/settings.svg")?;
|
||||||
frontend,
|
checkbox!(mp, c, SettingType::FocusFollowsMouseMode);
|
||||||
&tasks,
|
checkbox!(mp, c, SettingType::LeftHandedMouse);
|
||||||
state
|
checkbox!(mp, c, SettingType::AllowSliding);
|
||||||
.data
|
checkbox!(mp, c, SettingType::InvertScrollDirectionX);
|
||||||
.fetch_component_as::<ComponentCheckbox>("cb_xwayland_by_default")?,
|
checkbox!(mp, c, SettingType::InvertScrollDirectionY);
|
||||||
SettingType::DashXwaylandByDefault,
|
slider_f32!(mp, c, SettingType::ScrollSpeed, 0.1, 5.0, 0.1);
|
||||||
None,
|
slider_f32!(mp, c, SettingType::LongPressDuration, 0.1, 2.0, 0.1);
|
||||||
)?;
|
slider_f32!(mp, c, SettingType::PointerLerpFactor, 0.1, 1.0, 0.1);
|
||||||
|
slider_f32!(mp, c, SettingType::XrClickSensitivity, 0.1, 1.0, 0.1);
|
||||||
|
slider_f32!(mp, c, SettingType::XrClickSensitivityRelease, 0.1, 1.0, 0.1);
|
||||||
|
slider_i32!(mp, c, SettingType::ClickFreezeTimeMs, 0, 500, 50);
|
||||||
|
|
||||||
|
let c = category!(mp, root, "APP_SETTINGS.MISC", "dashboard/settings.svg")?;
|
||||||
|
checkbox!(mp, c, SettingType::XwaylandByDefault);
|
||||||
|
checkbox!(mp, c, SettingType::UprightScreenFix);
|
||||||
|
checkbox!(mp, c, SettingType::DoubleCursorFix);
|
||||||
|
checkbox!(mp, c, SettingType::ScreenRenderDown);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
state,
|
tasks: mp.tasks,
|
||||||
tasks,
|
state: parser_state,
|
||||||
marker: PhantomData,
|
marker: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toggle_setting(&mut self, frontend: &mut Frontend<T>, setting: SettingType, state: bool) {
|
|
||||||
*setting.get_bool(frontend.settings.get_mut()) = state;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,9 @@ use wgui::{
|
|||||||
taffy::Display,
|
taffy::Display,
|
||||||
widget::label::WidgetLabel,
|
widget::label::WidgetLabel,
|
||||||
};
|
};
|
||||||
|
use wlx_common::config::GeneralConfig;
|
||||||
|
|
||||||
use crate::{
|
use crate::frontend::{FrontendTask, FrontendTasks};
|
||||||
frontend::{FrontendTask, FrontendTasks},
|
|
||||||
settings::SettingsIO,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct PopupManagerParams {
|
pub struct PopupManagerParams {
|
||||||
pub parent_id: WidgetID,
|
pub parent_id: WidgetID,
|
||||||
@@ -58,7 +56,7 @@ pub struct PopupManager {
|
|||||||
|
|
||||||
pub struct PopupContentFuncData<'a> {
|
pub struct PopupContentFuncData<'a> {
|
||||||
pub layout: &'a mut Layout,
|
pub layout: &'a mut Layout,
|
||||||
pub settings: &'a dyn SettingsIO,
|
pub config: &'a GeneralConfig,
|
||||||
pub handle: PopupHandle,
|
pub handle: PopupHandle,
|
||||||
pub id_content: WidgetID,
|
pub id_content: WidgetID,
|
||||||
}
|
}
|
||||||
@@ -123,10 +121,10 @@ impl PopupManager {
|
|||||||
pub fn mount_popup(
|
pub fn mount_popup(
|
||||||
&mut self,
|
&mut self,
|
||||||
globals: WguiGlobals,
|
globals: WguiGlobals,
|
||||||
settings: &dyn SettingsIO,
|
|
||||||
layout: &mut Layout,
|
layout: &mut Layout,
|
||||||
frontend_tasks: FrontendTasks,
|
frontend_tasks: FrontendTasks,
|
||||||
params: MountPopupParams,
|
params: MountPopupParams,
|
||||||
|
config: &GeneralConfig,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let doc_params = &ParseDocumentParams {
|
let doc_params = &ParseDocumentParams {
|
||||||
globals: globals.clone(),
|
globals: globals.clone(),
|
||||||
@@ -180,7 +178,7 @@ impl PopupManager {
|
|||||||
layout,
|
layout,
|
||||||
handle: popup_handle.clone(),
|
handle: popup_handle.clone(),
|
||||||
id_content,
|
id_content,
|
||||||
settings,
|
config,
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -12,12 +12,9 @@ use wgui::{
|
|||||||
task::Tasks,
|
task::Tasks,
|
||||||
widget::label::WidgetLabel,
|
widget::label::WidgetLabel,
|
||||||
};
|
};
|
||||||
use wlx_common::{dash_interface::BoxDashInterface, desktop_finder::DesktopEntry};
|
use wlx_common::{config::GeneralConfig, dash_interface::BoxDashInterface, desktop_finder::DesktopEntry};
|
||||||
|
|
||||||
use crate::{
|
use crate::frontend::{FrontendTask, FrontendTasks, SoundType};
|
||||||
frontend::{FrontendTask, FrontendTasks, SoundType},
|
|
||||||
settings::SettingsIO,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Eq, PartialEq, EnumString, VariantNames, AsRefStr)]
|
#[derive(Clone, Copy, Eq, PartialEq, EnumString, VariantNames, AsRefStr)]
|
||||||
enum ResMode {
|
enum ResMode {
|
||||||
@@ -89,7 +86,7 @@ pub struct Params<'a> {
|
|||||||
pub entry: DesktopEntry,
|
pub entry: DesktopEntry,
|
||||||
pub layout: &'a mut Layout,
|
pub layout: &'a mut Layout,
|
||||||
pub parent_id: WidgetID,
|
pub parent_id: WidgetID,
|
||||||
pub settings: &'a dyn SettingsIO,
|
pub config: &'a GeneralConfig,
|
||||||
pub frontend_tasks: &'a FrontendTasks,
|
pub frontend_tasks: &'a FrontendTasks,
|
||||||
pub on_launched: Box<dyn Fn()>,
|
pub on_launched: Box<dyn Fn()>,
|
||||||
}
|
}
|
||||||
@@ -144,7 +141,7 @@ impl View {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let compositor_mode = if params.settings.get().tweaks.xwayland_by_default {
|
let compositor_mode = if params.config.xwayland_by_default {
|
||||||
CompositorMode::Cage
|
CompositorMode::Cage
|
||||||
} else {
|
} else {
|
||||||
CompositorMode::Native
|
CompositorMode::Native
|
||||||
|
|||||||
@@ -1,57 +1,8 @@
|
|||||||
use crate::testbed::{Testbed, TestbedUpdateParams};
|
use crate::testbed::{Testbed, TestbedUpdateParams};
|
||||||
use dash_frontend::{
|
use dash_frontend::frontend::{self, FrontendUpdateParams};
|
||||||
frontend::{self, FrontendUpdateParams},
|
|
||||||
settings::{self, SettingsIO},
|
|
||||||
};
|
|
||||||
use wgui::layout::Layout;
|
use wgui::layout::Layout;
|
||||||
use wlx_common::dash_interface_emulated::DashInterfaceEmulated;
|
use wlx_common::dash_interface_emulated::DashInterfaceEmulated;
|
||||||
|
|
||||||
struct SimpleSettingsIO {
|
|
||||||
settings: settings::Settings,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SimpleSettingsIO {
|
|
||||||
fn new() -> Self {
|
|
||||||
let mut res = Self {
|
|
||||||
settings: settings::Settings::default(),
|
|
||||||
};
|
|
||||||
res.read_from_disk();
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// just a simple impl of a config io for dashboard frontend
|
|
||||||
// use ~/.config later
|
|
||||||
impl settings::SettingsIO for SimpleSettingsIO {
|
|
||||||
fn get_mut(&mut self) -> &mut settings::Settings {
|
|
||||||
&mut self.settings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get(&self) -> &dash_frontend::settings::Settings {
|
|
||||||
&self.settings
|
|
||||||
}
|
|
||||||
|
|
||||||
fn save_to_disk(&mut self) {
|
|
||||||
log::info!("saving settings");
|
|
||||||
let data = self.settings.save();
|
|
||||||
std::fs::write("/tmp/testbed_settings.json", data).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_from_disk(&mut self) {
|
|
||||||
log::info!("loading settings");
|
|
||||||
if let Ok(res) = std::fs::read("/tmp/testbed_settings.json") {
|
|
||||||
let data = String::from_utf8(res).unwrap();
|
|
||||||
self.settings = settings::Settings::load(&data).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_as_dirty(&mut self) {
|
|
||||||
// just save it, at least for now
|
|
||||||
// save_to_disk should be called later in time or at exit, not instantly
|
|
||||||
self.save_to_disk();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct TestbedDashboard {
|
pub struct TestbedDashboard {
|
||||||
frontend: frontend::Frontend<()>,
|
frontend: frontend::Frontend<()>,
|
||||||
}
|
}
|
||||||
@@ -61,10 +12,12 @@ impl TestbedDashboard {
|
|||||||
let settings = SimpleSettingsIO::new();
|
let settings = SimpleSettingsIO::new();
|
||||||
let interface = DashInterfaceEmulated::new();
|
let interface = DashInterfaceEmulated::new();
|
||||||
|
|
||||||
let frontend = frontend::Frontend::new(frontend::InitParams {
|
let frontend = frontend::Frontend::new(
|
||||||
settings: Box::new(settings),
|
frontend::InitParams {
|
||||||
interface: Box::new(interface),
|
interface: Box::new(interface),
|
||||||
})?;
|
},
|
||||||
|
(),
|
||||||
|
)?;
|
||||||
Ok(Self { frontend })
|
Ok(Self { frontend })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
assets::AssetPath,
|
assets::AssetPath,
|
||||||
components::{Component, button, tooltip},
|
components::{button, tooltip, Component},
|
||||||
drawing::Color,
|
drawing::Color,
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
AttribPair, ParserContext, ParserFile, parse_check_f32, parse_check_i32, parse_children, parse_f32,
|
parse_check_f32, parse_check_i32, parse_children, parse_f32, print_invalid_attrib, process_component,
|
||||||
print_invalid_attrib, process_component,
|
|
||||||
style::{parse_color_opt, parse_round, parse_style, parse_text_style},
|
style::{parse_color_opt, parse_round, parse_style, parse_text_style},
|
||||||
|
AttribPair, ParserContext, ParserFile,
|
||||||
},
|
},
|
||||||
widget::util::WLength,
|
widget::util::WLength,
|
||||||
};
|
};
|
||||||
@@ -41,11 +41,15 @@ pub fn parse_component_button<'a>(
|
|||||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
match key {
|
match key {
|
||||||
"text" => {
|
"text" => {
|
||||||
|
if !value.is_empty() {
|
||||||
translation = Some(Translation::from_raw_text(value));
|
translation = Some(Translation::from_raw_text(value));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
"translation" => {
|
"translation" => {
|
||||||
|
if !value.is_empty() {
|
||||||
translation = Some(Translation::from_translation_key(value));
|
translation = Some(Translation::from_translation_key(value));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
"round" => {
|
"round" => {
|
||||||
parse_round(value, &mut round, ctx.doc_params.globals.get().defaults.rounding_mult);
|
parse_round(value, &mut round, ctx.doc_params.globals.get().defaults.rounding_mult);
|
||||||
}
|
}
|
||||||
@@ -77,8 +81,8 @@ pub fn parse_component_button<'a>(
|
|||||||
sprite_src = Some(asset_path);
|
sprite_src = Some(asset_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"tooltip" => tooltip = Some(Translation::from_translation_key(value)),
|
"tooltip" if !value.is_empty() => tooltip = Some(Translation::from_translation_key(value)),
|
||||||
"tooltip_str" => tooltip = Some(Translation::from_raw_text(value)),
|
"tooltip_str" if !value.is_empty() => tooltip = Some(Translation::from_raw_text(value)),
|
||||||
"tooltip_side" => {
|
"tooltip_side" => {
|
||||||
tooltip_side = match value {
|
tooltip_side = match value {
|
||||||
"left" => Some(tooltip::TooltipSide::Left),
|
"left" => Some(tooltip::TooltipSide::Left),
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
components::{Component, checkbox, radio_group::ComponentRadioGroup},
|
components::{checkbox, radio_group::ComponentRadioGroup, Component},
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
AttribPair, Fetchable, ParserContext, parse_check_f32, parse_check_i32, process_component, style::parse_style,
|
parse_check_f32, parse_check_i32, process_component, style::parse_style, AttribPair, Fetchable, ParserContext,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -29,11 +29,15 @@ pub fn parse_component_checkbox(
|
|||||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
match key {
|
match key {
|
||||||
"text" => {
|
"text" => {
|
||||||
|
if !value.is_empty() {
|
||||||
translation = Translation::from_raw_text(value);
|
translation = Translation::from_raw_text(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
"translation" => {
|
"translation" => {
|
||||||
|
if !value.is_empty() {
|
||||||
translation = Translation::from_translation_key(value);
|
translation = Translation::from_translation_key(value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
"value" => {
|
"value" => {
|
||||||
component_value = Some(value.into());
|
component_value = Some(value.into());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ idmap = { workspace = true, features = ["serde"] }
|
|||||||
idmap-derive.workspace = true
|
idmap-derive.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
serde = { workspace = true, features = ["rc"] }
|
serde = { workspace = true, features = ["rc"] }
|
||||||
|
serde_json.workspace = true
|
||||||
xdg.workspace = true
|
xdg.workspace = true
|
||||||
chrono = "0.4.42"
|
chrono = "0.4.42"
|
||||||
smol = "2.0.2"
|
smol = "2.0.2"
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ pub const fn def_pw_tokens() -> PwTokenMap {
|
|||||||
AStrMap::new()
|
AStrMap::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn def_mouse_move_interval_ms() -> u32 {
|
const fn def_mouse_move_interval_ms() -> i32 {
|
||||||
10 // 100fps
|
10 // 100fps
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn def_click_freeze_time_ms() -> u32 {
|
const fn def_click_freeze_time_ms() -> i32 {
|
||||||
300
|
300
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ pub struct GeneralConfig {
|
|||||||
pub attribs: AStrMap<Vec<BackendAttribValue>>,
|
pub attribs: AStrMap<Vec<BackendAttribValue>>,
|
||||||
|
|
||||||
#[serde(default = "def_click_freeze_time_ms")]
|
#[serde(default = "def_click_freeze_time_ms")]
|
||||||
pub click_freeze_time_ms: u32,
|
pub click_freeze_time_ms: i32,
|
||||||
|
|
||||||
#[serde(default = "def_false")]
|
#[serde(default = "def_false")]
|
||||||
pub invert_scroll_direction_x: bool,
|
pub invert_scroll_direction_x: bool,
|
||||||
@@ -125,7 +125,7 @@ pub struct GeneralConfig {
|
|||||||
pub long_press_duration: f32,
|
pub long_press_duration: f32,
|
||||||
|
|
||||||
#[serde(default = "def_mouse_move_interval_ms")]
|
#[serde(default = "def_mouse_move_interval_ms")]
|
||||||
pub mouse_move_interval_ms: u32,
|
pub mouse_move_interval_ms: i32,
|
||||||
|
|
||||||
#[serde(default = "def_true")]
|
#[serde(default = "def_true")]
|
||||||
pub notifications_enabled: bool,
|
pub notifications_enabled: bool,
|
||||||
@@ -240,4 +240,13 @@ pub struct GeneralConfig {
|
|||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub last_set: u32,
|
pub last_set: u32,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub hide_username: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub opaque_background: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub xwayland_by_default: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use wayvr_ipc::{
|
|||||||
packet_server::{WvrProcess, WvrProcessHandle, WvrWindow, WvrWindowHandle},
|
packet_server::{WvrProcess, WvrProcessHandle, WvrWindow, WvrWindowHandle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::desktop_finder::DesktopFinder;
|
use crate::{config::GeneralConfig, desktop_finder::DesktopFinder};
|
||||||
|
|
||||||
pub trait DashInterface<T> {
|
pub trait DashInterface<T> {
|
||||||
fn window_list(&mut self, data: &mut T) -> anyhow::Result<Vec<WvrWindow>>;
|
fn window_list(&mut self, data: &mut T) -> anyhow::Result<Vec<WvrWindow>>;
|
||||||
@@ -15,6 +15,7 @@ pub trait DashInterface<T> {
|
|||||||
fn process_terminate(&mut self, data: &mut T, handle: WvrProcessHandle) -> anyhow::Result<()>;
|
fn process_terminate(&mut self, data: &mut T, handle: WvrProcessHandle) -> anyhow::Result<()>;
|
||||||
fn recenter_playspace(&mut self, data: &mut T) -> anyhow::Result<()>;
|
fn recenter_playspace(&mut self, data: &mut T) -> anyhow::Result<()>;
|
||||||
fn desktop_finder<'a>(&'a mut self, data: &'a mut T) -> &'a mut DesktopFinder;
|
fn desktop_finder<'a>(&'a mut self, data: &'a mut T) -> &'a mut DesktopFinder;
|
||||||
|
fn general_config<'a>(&'a mut self, data: &'a mut T) -> &'a mut GeneralConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type BoxDashInterface<T> = Box<dyn DashInterface<T>>;
|
pub type BoxDashInterface<T> = Box<dyn DashInterface<T>>;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use wayvr_ipc::{
|
|||||||
packet_server::{WvrProcess, WvrProcessHandle, WvrWindow, WvrWindowHandle},
|
packet_server::{WvrProcess, WvrProcessHandle, WvrWindow, WvrWindowHandle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{dash_interface::DashInterface, desktop_finder::DesktopFinder, gen_id};
|
use crate::{config::GeneralConfig, dash_interface::DashInterface, desktop_finder::DesktopFinder, gen_id};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EmuProcess {
|
pub struct EmuProcess {
|
||||||
@@ -55,6 +55,7 @@ pub struct DashInterfaceEmulated {
|
|||||||
processes: EmuProcessVec,
|
processes: EmuProcessVec,
|
||||||
windows: EmuWindowVec,
|
windows: EmuWindowVec,
|
||||||
desktop_finder: DesktopFinder,
|
desktop_finder: DesktopFinder,
|
||||||
|
general_config: GeneralConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DashInterfaceEmulated {
|
impl DashInterfaceEmulated {
|
||||||
@@ -73,10 +74,14 @@ impl DashInterfaceEmulated {
|
|||||||
let mut desktop_finder = DesktopFinder::new();
|
let mut desktop_finder = DesktopFinder::new();
|
||||||
desktop_finder.refresh();
|
desktop_finder.refresh();
|
||||||
|
|
||||||
|
// Use serde defaults
|
||||||
|
let general_config = serde_json::from_str("{}").unwrap();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
processes,
|
processes,
|
||||||
windows,
|
windows,
|
||||||
desktop_finder,
|
desktop_finder,
|
||||||
|
general_config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,4 +174,8 @@ impl DashInterface<()> for DashInterfaceEmulated {
|
|||||||
fn desktop_finder<'a>(&'a mut self, _: &'a mut ()) -> &'a mut DesktopFinder {
|
fn desktop_finder<'a>(&'a mut self, _: &'a mut ()) -> &'a mut DesktopFinder {
|
||||||
&mut self.desktop_finder
|
&mut self.desktop_finder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn general_config<'a>(&'a mut self, _: &'a mut ()) -> &'a mut crate::config::GeneralConfig {
|
||||||
|
&mut self.general_config
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ impl BlitMethod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub click_freeze_time_ms: u32,
|
pub click_freeze_time_ms: i32,
|
||||||
pub keyboard_repeat_delay_ms: u32,
|
pub keyboard_repeat_delay_ms: u32,
|
||||||
pub keyboard_repeat_rate: u32,
|
pub keyboard_repeat_rate: u32,
|
||||||
pub auto_hide_delay: Option<u32>, // if None, auto-hide is disabled
|
pub auto_hide_delay: Option<u32>, // if None, auto-hide is disabled
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
use dash_frontend::{
|
use dash_frontend::frontend::{self, FrontendTask, FrontendUpdateParams};
|
||||||
frontend::{self, FrontendTask, FrontendUpdateParams},
|
|
||||||
settings::{self, SettingsIO},
|
|
||||||
};
|
|
||||||
use glam::{Affine2, Affine3A, Vec2, vec2, vec3};
|
use glam::{Affine2, Affine3A, Vec2, vec2, vec3};
|
||||||
use wayvr_ipc::{
|
use wayvr_ipc::{
|
||||||
packet_client::WvrProcessLaunchParams,
|
packet_client::WvrProcessLaunchParams,
|
||||||
@@ -26,7 +23,6 @@ use wlx_common::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_misc,
|
|
||||||
backend::{
|
backend::{
|
||||||
input::{Haptics, HoverResult, PointerHit, PointerMode},
|
input::{Haptics, HoverResult, PointerHit, PointerMode},
|
||||||
task::{OverlayTask, PlayspaceTask, TaskType},
|
task::{OverlayTask, PlayspaceTask, TaskType},
|
||||||
@@ -53,43 +49,6 @@ pub const DASH_NAME: &str = "Dashboard";
|
|||||||
const DASH_RES_U32A: [u32; 2] = [1920, 1080];
|
const DASH_RES_U32A: [u32; 2] = [1920, 1080];
|
||||||
const DASH_RES_VEC2: Vec2 = vec2(DASH_RES_U32A[0] as _, DASH_RES_U32A[1] as _);
|
const DASH_RES_VEC2: Vec2 = vec2(DASH_RES_U32A[0] as _, DASH_RES_U32A[1] as _);
|
||||||
|
|
||||||
//FIXME: replace with proper impl
|
|
||||||
struct SimpleSettingsIO {
|
|
||||||
settings: settings::Settings,
|
|
||||||
}
|
|
||||||
impl SimpleSettingsIO {
|
|
||||||
fn new() -> Self {
|
|
||||||
let mut res = Self {
|
|
||||||
settings: settings::Settings::default(),
|
|
||||||
};
|
|
||||||
res.read_from_disk();
|
|
||||||
res
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl settings::SettingsIO for SimpleSettingsIO {
|
|
||||||
fn get_mut(&mut self) -> &mut settings::Settings {
|
|
||||||
&mut self.settings
|
|
||||||
}
|
|
||||||
fn get(&self) -> &dash_frontend::settings::Settings {
|
|
||||||
&self.settings
|
|
||||||
}
|
|
||||||
fn save_to_disk(&mut self) {
|
|
||||||
log::info!("saving settings");
|
|
||||||
let data = self.settings.save();
|
|
||||||
std::fs::write("/tmp/testbed_settings.json", data).unwrap();
|
|
||||||
}
|
|
||||||
fn read_from_disk(&mut self) {
|
|
||||||
log::info!("loading settings");
|
|
||||||
if let Ok(res) = std::fs::read("/tmp/testbed_settings.json") {
|
|
||||||
let data = String::from_utf8(res).unwrap();
|
|
||||||
self.settings = settings::Settings::load(&data).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn mark_as_dirty(&mut self) {
|
|
||||||
self.save_to_disk();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DashFrontend {
|
pub struct DashFrontend {
|
||||||
inner: frontend::Frontend<AppState>,
|
inner: frontend::Frontend<AppState>,
|
||||||
initialized: bool,
|
initialized: bool,
|
||||||
@@ -103,13 +62,14 @@ const GUI_SCALE: f32 = 2.0;
|
|||||||
|
|
||||||
impl DashFrontend {
|
impl DashFrontend {
|
||||||
fn new(app: &mut AppState) -> anyhow::Result<Self> {
|
fn new(app: &mut AppState) -> anyhow::Result<Self> {
|
||||||
let settings = SimpleSettingsIO::new();
|
|
||||||
let interface = DashInterfaceLive::new();
|
let interface = DashInterfaceLive::new();
|
||||||
|
|
||||||
let frontend = frontend::Frontend::new(frontend::InitParams {
|
let frontend = frontend::Frontend::new(
|
||||||
settings: Box::new(settings),
|
frontend::InitParams {
|
||||||
interface: Box::new(interface),
|
interface: Box::new(interface),
|
||||||
})?;
|
},
|
||||||
|
app,
|
||||||
|
)?;
|
||||||
|
|
||||||
frontend
|
frontend
|
||||||
.tasks
|
.tasks
|
||||||
@@ -448,4 +408,11 @@ impl DashInterface<AppState> for DashInterfaceLive {
|
|||||||
) -> &'a mut wlx_common::desktop_finder::DesktopFinder {
|
) -> &'a mut wlx_common::desktop_finder::DesktopFinder {
|
||||||
&mut data.desktop_finder
|
&mut data.desktop_finder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn general_config<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
data: &'a mut AppState,
|
||||||
|
) -> &'a mut wlx_common::config::GeneralConfig {
|
||||||
|
&mut data.session.config
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ impl OverlayBackend for ScreenBackend {
|
|||||||
{
|
{
|
||||||
let pos = self.mouse_transform.transform_point2(hit.uv);
|
let pos = self.mouse_transform.transform_point2(hit.uv);
|
||||||
app.hid_provider.inner.mouse_move(pos);
|
app.hid_provider.inner.mouse_move(pos);
|
||||||
set_next_move(u64::from(app.session.config.mouse_move_interval_ms));
|
set_next_move(app.session.config.mouse_move_interval_ms as _);
|
||||||
}
|
}
|
||||||
HoverResult {
|
HoverResult {
|
||||||
consume: true,
|
consume: true,
|
||||||
@@ -290,7 +290,7 @@ impl OverlayBackend for ScreenBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pressed {
|
if pressed {
|
||||||
set_next_move(u64::from(app.session.config.click_freeze_time_ms));
|
set_next_move(app.session.config.click_freeze_time_ms as _);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.hid_provider.inner.send_button(btn, pressed);
|
app.hid_provider.inner.send_button(btn, pressed);
|
||||||
|
|||||||
Reference in New Issue
Block a user