bar functionality
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
use std::fmt::Debug;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default)]
|
#[derive(Debug, Serialize, Deserialize, Clone, Copy, Default)]
|
||||||
@@ -7,3 +9,33 @@ pub enum LeftRight {
|
|||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait LogErr {
|
||||||
|
fn log_err(self) -> Self;
|
||||||
|
fn log_warn(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E> LogErr for Result<T, E>
|
||||||
|
where
|
||||||
|
E: Debug + Send + Sync + 'static,
|
||||||
|
{
|
||||||
|
fn log_warn(self) -> Result<T, E> {
|
||||||
|
match self {
|
||||||
|
Ok(ok) => Ok(ok),
|
||||||
|
Err(error) => {
|
||||||
|
log::warn!("{error:?}");
|
||||||
|
Err(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log_err(self) -> Result<T, E> {
|
||||||
|
match self {
|
||||||
|
Ok(ok) => Ok(ok),
|
||||||
|
Err(error) => {
|
||||||
|
log::error!("{error:?}");
|
||||||
|
Err(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,14 +88,14 @@
|
|||||||
|
|
||||||
<!-- An app with a single icon. -->
|
<!-- An app with a single icon. -->
|
||||||
<template name="App">
|
<template name="App">
|
||||||
<Button macro="button_style" _press="" tooltip="${tooltip}" tooltip_side="bottom">
|
<Button macro="button_style" id="overlay_${idx}" _press="::OverlayToggle ${name}" tooltip="${name}" tooltip_side="bottom">
|
||||||
<sprite width="56" height="56" color="~text_color" src_ext="${src}" />
|
<sprite width="56" height="56" color="~text_color" src_ext="${src}" />
|
||||||
</Button>
|
</Button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- A screen with a shortened connector name, e.g. "H1" for HDMI-A-1 or "D2" for DP-2 -->
|
<!-- A screen with a shortened connector name, e.g. "H1" for HDMI-A-1 or "D2" for DP-2 -->
|
||||||
<template name="Screen">
|
<template name="Screen">
|
||||||
<Button macro="button_style" tooltip="${tooltip}" tooltip_side="bottom">
|
<Button macro="button_style" id="overlay_${idx}" _press="::OverlayToggle ${name}" tooltip="${name}" tooltip_side="bottom">
|
||||||
<sprite width="56" height="56" color="~text_color" src_builtin="edit/screen.svg" />
|
<sprite width="56" height="56" color="~text_color" src_builtin="edit/screen.svg" />
|
||||||
<div position="absolute" margin_top="-10">
|
<div position="absolute" margin_top="-10">
|
||||||
<label text="${display}" size="26" color="~color_faded_20" weight="bold" />
|
<label text="${display}" size="26" color="~color_faded_20" weight="bold" />
|
||||||
@@ -104,13 +104,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template name="Panel">
|
<template name="Panel">
|
||||||
<Button macro="button_style" tooltip="${tooltip}" tooltip_side="bottom">
|
<Button macro="button_style" id="overlay_${idx}" _press="::OverlayToggle ${name}" tooltip="${name}" tooltip_side="bottom">
|
||||||
<sprite width="56" height="56" color="~text_color" src_builtin="edit/panel.svg" />
|
<sprite width="56" height="56" color="~text_color" src_builtin="edit/panel.svg" />
|
||||||
</Button>
|
</Button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template name="Mirror">
|
<template name="Mirror">
|
||||||
<Button macro="button_style" _press="" tooltip="${tooltip}" tooltip_side="bottom">
|
<Button macro="button_style" id="overlay_${idx}" _press="::OverlayToggle ${name}" tooltip="${name}" tooltip_side="bottom">
|
||||||
<sprite width="56" height="56" color="~text_color" src_builtin="edit/mirror.svg" />
|
<sprite width="56" height="56" color="~text_color" src_builtin="edit/mirror.svg" />
|
||||||
<div position="absolute" margin_top="7" margin_left="20">
|
<div position="absolute" margin_top="7" margin_left="20">
|
||||||
<label text="${display}" size="26" color="~color_faded_20" weight="bold" />
|
<label text="${display}" size="26" color="~color_faded_20" weight="bold" />
|
||||||
@@ -131,17 +131,17 @@
|
|||||||
<div flex_direction="column" interactable="0">
|
<div flex_direction="column" interactable="0">
|
||||||
<rectangle macro="bg_rect" padding="16" align_items="center" justify_content="space_between">
|
<rectangle macro="bg_rect" padding="16" align_items="center" justify_content="space_between">
|
||||||
<div gap="16">
|
<div gap="16">
|
||||||
<div id="panels_root_TODO" gap="8">
|
<div id="panels_root" gap="8">
|
||||||
<Screen idx="0" display="H1" tooltip="Screen: HDMI-A-1" />
|
<Screen idx="0" display="H1" name="HDMI-A-1" />
|
||||||
<Screen idx="1" display="D2" tooltip="Screen: DP-2" />
|
<Screen idx="1" display="D2" name="Screen: DP-2" />
|
||||||
<Mirror idx="1" display="1" tooltip="Mirror: M-1" />
|
<Mirror idx="1" display="1" name="M1" />
|
||||||
<Panel idx="1" display="Test" tooltip="Panel: Test" />
|
<Panel idx="1" display="Test" name="Test" />
|
||||||
</div>
|
</div>
|
||||||
<VerticalSeparator />
|
<VerticalSeparator />
|
||||||
<div id="apps_root_TODO" gap="8">
|
<div id="apps_root" gap="8">
|
||||||
<App id="test1" src="/usr/share/icons/hicolor/scalable/apps/blender-5.0.svg" tooltip="App: Blender" />
|
<App id="test1" name="Blender" src="/usr/share/icons/hicolor/scalable/apps/blender-5.0.svg" />
|
||||||
<App id="test2" src="/usr/share/icons/hicolor/scalable/apps/org.inkscape.Inkscape.svg" tooltip="App: Inkscape" />
|
<App id="test2" name="Inkscape" src="/usr/share/icons/hicolor/scalable/apps/org.inkscape.Inkscape.svg" />
|
||||||
<App id="test3" src="/usr/share/icons/hicolor/scalable/apps/gimp.svg" tooltip="App: GIMP" />
|
<App id="test3" name="GIMP" src="/usr/share/icons/hicolor/scalable/apps/gimp.svg" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="tray_root" flex_direction="row" gap="16">
|
<div id="tray_root" flex_direction="row" gap="16">
|
||||||
@@ -165,4 +165,4 @@
|
|||||||
</div>
|
</div>
|
||||||
</elements>
|
</elements>
|
||||||
|
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
@@ -248,7 +248,8 @@ pub(super) fn setup_custom_button<S: 'static>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
"::OverlayToggle" => {
|
"::OverlayToggle" => {
|
||||||
let Some(arg): Option<Arc<str>> = args.next().map(Into::into) else {
|
let arg: Arc<str> = args.collect::<Vec<_>>().join(" ").into();
|
||||||
|
if arg.len() < 1 {
|
||||||
log::error!("{command} has missing arguments");
|
log::error!("{command} has missing arguments");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -271,6 +272,24 @@ pub(super) fn setup_custom_button<S: 'static>(
|
|||||||
Ok(EventResult::Consumed)
|
Ok(EventResult::Consumed)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
"::OverlaySoftToggle" => {
|
||||||
|
let arg: Arc<str> = args.collect::<Vec<_>>().join(" ").into();
|
||||||
|
if arg.len() < 1 {
|
||||||
|
log::error!("{command} has missing arguments");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
Box::new(move |_common, data, app, _| {
|
||||||
|
if !test_button(data) || !test_duration(&button, app) {
|
||||||
|
return Ok(EventResult::Pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.tasks.enqueue(TaskType::Overlay(OverlayTask::SoftToggleOverlay(
|
||||||
|
OverlaySelector::Name(arg.clone()),
|
||||||
|
)));
|
||||||
|
Ok(EventResult::Consumed)
|
||||||
|
})
|
||||||
|
}
|
||||||
"::EditToggle" => Box::new(move |_common, data, app, _| {
|
"::EditToggle" => Box::new(move |_common, data, app, _| {
|
||||||
if !test_button(data) || !test_duration(&button, app) {
|
if !test_button(data) || !test_duration(&button, app) {
|
||||||
return Ok(EventResult::Pass);
|
return Ok(EventResult::Pass);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use wgui::{
|
|||||||
},
|
},
|
||||||
gfx::cmd::WGfxClearMode,
|
gfx::cmd::WGfxClearMode,
|
||||||
layout::{Layout, LayoutParams, LayoutUpdateParams, WidgetID},
|
layout::{Layout, LayoutParams, LayoutUpdateParams, WidgetID},
|
||||||
parser::{CustomAttribsInfoOwned, Fetchable, ParserState},
|
parser::{CustomAttribsInfoOwned, Fetchable, ParseDocumentExtra, ParserState},
|
||||||
renderer_vk::context::Context as WguiContext,
|
renderer_vk::context::Context as WguiContext,
|
||||||
widget::{EventResult, label::WidgetLabel},
|
widget::{EventResult, label::WidgetLabel},
|
||||||
};
|
};
|
||||||
@@ -52,11 +52,14 @@ pub struct GuiPanel<S> {
|
|||||||
pub gui_scale: f32,
|
pub gui_scale: f32,
|
||||||
pub on_notify: Option<OnNotifyFunc<S>>,
|
pub on_notify: Option<OnNotifyFunc<S>>,
|
||||||
pub initialized: bool,
|
pub initialized: bool,
|
||||||
|
pub doc_extra: Option<ParseDocumentExtra>,
|
||||||
interaction_transform: Option<Affine2>,
|
interaction_transform: Option<Affine2>,
|
||||||
context: WguiContext,
|
context: WguiContext,
|
||||||
timestep: Timestep,
|
timestep: Timestep,
|
||||||
has_focus: [bool; 2],
|
has_focus: [bool; 2],
|
||||||
last_content_size: Vec2,
|
last_content_size: Vec2,
|
||||||
|
custom_elems: Rc<RefCell<Vec<CustomAttribsInfoOwned>>>,
|
||||||
|
on_custom_attrib: Option<OnCustomAttribFunc>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type OnCustomIdFunc<S> = Box<
|
pub type OnCustomIdFunc<S> = Box<
|
||||||
@@ -142,29 +145,10 @@ impl<S: 'static> GuiPanel<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for elem in custom_elems.borrow().iter() {
|
|
||||||
if layout
|
|
||||||
.state
|
|
||||||
.widgets
|
|
||||||
.get_as::<WidgetLabel>(elem.widget_id)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
setup_custom_label::<S>(&mut layout, elem, app);
|
|
||||||
} else if let Ok(button) =
|
|
||||||
parser_state.fetch_component_from_widget_id_as::<ComponentButton>(elem.widget_id)
|
|
||||||
{
|
|
||||||
setup_custom_button::<S>(&mut layout, elem, app, button);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(on_custom_attrib) = ¶ms.on_custom_attrib {
|
|
||||||
on_custom_attrib(&mut layout, &parser_state, elem, app);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
|
let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
|
||||||
let timestep = Timestep::new(60.0);
|
let timestep = Timestep::new(60.0);
|
||||||
|
|
||||||
Ok(Self {
|
let mut me = Self {
|
||||||
layout,
|
layout,
|
||||||
context,
|
context,
|
||||||
timestep,
|
timestep,
|
||||||
@@ -178,38 +162,38 @@ impl<S: 'static> GuiPanel<S> {
|
|||||||
initialized: false,
|
initialized: false,
|
||||||
has_focus: [false, false],
|
has_focus: [false, false],
|
||||||
last_content_size: Vec2::ZERO,
|
last_content_size: Vec2::ZERO,
|
||||||
})
|
doc_extra: Some(doc_params.extra),
|
||||||
|
custom_elems,
|
||||||
|
on_custom_attrib: params.on_custom_attrib,
|
||||||
|
};
|
||||||
|
me.process_custom_elems(app);
|
||||||
|
|
||||||
|
Ok(me)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_blank(
|
pub fn process_custom_elems(&mut self, app: &mut AppState) {
|
||||||
app: &mut AppState,
|
let mut elems = self.custom_elems.borrow_mut();
|
||||||
state: S,
|
for elem in elems.iter() {
|
||||||
params: NewGuiPanelParams<S>,
|
if self
|
||||||
) -> anyhow::Result<Self> {
|
.layout
|
||||||
let layout = Layout::new(
|
.state
|
||||||
app.wgui_globals.clone(),
|
.widgets
|
||||||
&LayoutParams {
|
.get_as::<WidgetLabel>(elem.widget_id)
|
||||||
resize_to_parent: params.resize_to_parent,
|
.is_some()
|
||||||
},
|
{
|
||||||
)?;
|
setup_custom_label::<S>(&mut self.layout, elem, app);
|
||||||
let context = WguiContext::new(&mut app.wgui_shared, 1.0)?;
|
} else if let Ok(button) = self
|
||||||
let timestep = Timestep::new(60.0);
|
.parser_state
|
||||||
|
.fetch_component_from_widget_id_as::<ComponentButton>(elem.widget_id)
|
||||||
|
{
|
||||||
|
setup_custom_button::<S>(&mut self.layout, elem, app, button);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Self {
|
if let Some(on_custom_attrib) = &self.on_custom_attrib {
|
||||||
layout,
|
on_custom_attrib(&mut self.layout, &self.parser_state, elem, app);
|
||||||
context,
|
}
|
||||||
timestep,
|
}
|
||||||
state,
|
elems.clear();
|
||||||
parser_state: ParserState::default(),
|
|
||||||
max_size: vec2(DEFAULT_MAX_SIZE as _, DEFAULT_MAX_SIZE as _),
|
|
||||||
timers: vec![],
|
|
||||||
on_notify: None,
|
|
||||||
interaction_transform: None,
|
|
||||||
gui_scale: params.gui_scale,
|
|
||||||
initialized: false,
|
|
||||||
has_focus: [false, false],
|
|
||||||
last_content_size: Vec2::ZERO,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_layout(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
pub fn update_layout(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||||
|
|||||||
@@ -1,28 +1,15 @@
|
|||||||
use std::{collections::HashMap, rc::Rc};
|
use std::{collections::{HashMap}, rc::Rc, time::Duration};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_misc,
|
app_misc,
|
||||||
gui::panel::{GuiPanel, NewGuiPanelParams},
|
gui::{panel::{GuiPanel, NewGuiPanelParams}, timer::GuiTimer},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
subsystem::hid::XkbKeymap,
|
subsystem::hid::XkbKeymap, windowing::{backend::OverlayEventData, window::OverlayCategory},
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use glam::{FloatExt, Mat4, Vec2, vec2, vec3};
|
use glam::{FloatExt, Mat4, Vec2, vec2, vec3};
|
||||||
use wgui::{
|
use wgui::{
|
||||||
animation::{Animation, AnimationEasing},
|
animation::{Animation, AnimationEasing}, assets::AssetPath, components::button::ComponentButton, drawing::{self, Color}, event::{self, CallbackDataCommon, CallbackMetadata, EventAlterables, EventListenerKind}, layout::LayoutUpdateParams, parser::{Fetchable, ParseDocumentExtra, ParseDocumentParams}, renderer_vk::util, taffy::{self, prelude::length}, widget::{div::WidgetDiv, rectangle::WidgetRectangle, EventResult}
|
||||||
assets::AssetPath,
|
|
||||||
drawing::{self, Color},
|
|
||||||
event::{self, CallbackMetadata, EventListenerKind},
|
|
||||||
layout::{LayoutParams, LayoutUpdateParams},
|
|
||||||
parser::{Fetchable, ParseDocumentExtra, ParseDocumentParams},
|
|
||||||
renderer_vk::util,
|
|
||||||
taffy::{self, prelude::length},
|
|
||||||
widget::{
|
|
||||||
EventResult,
|
|
||||||
div::WidgetDiv,
|
|
||||||
rectangle::{WidgetRectangle, WidgetRectangleParams},
|
|
||||||
util::WLength,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@@ -32,6 +19,14 @@ use super::{
|
|||||||
|
|
||||||
const PIXELS_PER_UNIT: f32 = 80.;
|
const PIXELS_PER_UNIT: f32 = 80.;
|
||||||
|
|
||||||
|
fn new_doc_params(panel: &mut GuiPanel<KeyboardState>) -> ParseDocumentParams<'static> {
|
||||||
|
ParseDocumentParams {
|
||||||
|
globals: panel.layout.state.globals.clone(),
|
||||||
|
path: AssetPath::FileOrBuiltIn("gui/keyboard.xml"),
|
||||||
|
extra: panel.doc_extra.take().unwrap_or_default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_lines, clippy::significant_drop_tightening)]
|
#[allow(clippy::too_many_lines, clippy::significant_drop_tightening)]
|
||||||
pub(super) fn create_keyboard_panel(
|
pub(super) fn create_keyboard_panel(
|
||||||
app: &mut AppState,
|
app: &mut AppState,
|
||||||
@@ -42,11 +37,7 @@ pub(super) fn create_keyboard_panel(
|
|||||||
let mut panel =
|
let mut panel =
|
||||||
GuiPanel::new_from_template(app, "gui/keyboard.xml", state, NewGuiPanelParams::default())?;
|
GuiPanel::new_from_template(app, "gui/keyboard.xml", state, NewGuiPanelParams::default())?;
|
||||||
|
|
||||||
let doc_params = ParseDocumentParams {
|
let doc_params = new_doc_params(&mut panel);
|
||||||
globals: app.wgui_globals.clone(),
|
|
||||||
path: AssetPath::FileOrBuiltIn("gui/keyboard.xml"),
|
|
||||||
extra: ParseDocumentExtra::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let globals = app.wgui_globals.clone();
|
let globals = app.wgui_globals.clone();
|
||||||
let accent_color = globals.get().defaults.accent_color;
|
let accent_color = globals.get().defaults.accent_color;
|
||||||
@@ -256,6 +247,133 @@ pub(super) fn create_keyboard_panel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
panel.on_notify = Some(Box::new(move |panel, app, event_data| {
|
||||||
|
let mut alterables = EventAlterables::default();
|
||||||
|
|
||||||
|
match event_data {
|
||||||
|
OverlayEventData::ActiveSetChanged(current_set) => {
|
||||||
|
let mut com = CallbackDataCommon {
|
||||||
|
alterables: &mut alterables,
|
||||||
|
state: &panel.layout.state,
|
||||||
|
};
|
||||||
|
if let Some(old_set) = panel.state.current_set.take()
|
||||||
|
&& let Some(old_set) = panel.state.set_buttons.get_mut(old_set)
|
||||||
|
{
|
||||||
|
old_set.set_sticky_state(&mut com, false);
|
||||||
|
}
|
||||||
|
if let Some(new_set) = current_set
|
||||||
|
&& let Some(new_set) = panel.state.set_buttons.get_mut(new_set)
|
||||||
|
{
|
||||||
|
new_set.set_sticky_state(&mut com, true);
|
||||||
|
}
|
||||||
|
panel.state.current_set = current_set;
|
||||||
|
}
|
||||||
|
OverlayEventData::NumSetsChanged(num_sets) => {
|
||||||
|
let sets_root = panel.parser_state.get_widget_id("sets_root")?;
|
||||||
|
panel.layout.remove_children(sets_root);
|
||||||
|
panel.state.set_buttons.clear();
|
||||||
|
|
||||||
|
for i in 0..num_sets {
|
||||||
|
let mut params = HashMap::new();
|
||||||
|
params.insert("idx".into(), i.to_string().into());
|
||||||
|
params.insert("display".into(), (i+1).to_string().into());
|
||||||
|
panel.parser_state.instantiate_template(
|
||||||
|
&doc_params,
|
||||||
|
"Set",
|
||||||
|
&mut panel.layout,
|
||||||
|
sets_root,
|
||||||
|
params,
|
||||||
|
)?;
|
||||||
|
let set_button = panel.parser_state.fetch_component_as::<ComponentButton>(&format!("set_{i}"))?;
|
||||||
|
if panel.state.current_set == Some(i) {
|
||||||
|
let mut com = CallbackDataCommon {
|
||||||
|
alterables: &mut alterables,
|
||||||
|
state: &panel.layout.state,
|
||||||
|
};
|
||||||
|
set_button.set_sticky_state(&mut com, true);
|
||||||
|
}
|
||||||
|
panel.state.set_buttons.push(set_button);
|
||||||
|
}
|
||||||
|
panel.process_custom_elems(app);
|
||||||
|
}
|
||||||
|
OverlayEventData::OverlaysChanged(metas) => {
|
||||||
|
let panels_root = panel.parser_state.get_widget_id("panels_root")?;
|
||||||
|
let apps_root = panel.parser_state.get_widget_id("apps_root")?;
|
||||||
|
panel.layout.remove_children(panels_root);
|
||||||
|
panel.layout.remove_children(apps_root);
|
||||||
|
panel.state.overlay_buttons.clear();
|
||||||
|
|
||||||
|
for (i, meta) in metas.iter().enumerate() {
|
||||||
|
let mut params = HashMap::new();
|
||||||
|
|
||||||
|
let (template, root) = match meta.category {
|
||||||
|
OverlayCategory::Screen => {
|
||||||
|
params.insert("display".into(), format!("{}{}", (*meta.name).chars().next().unwrap_or_default(), (*meta.name).chars().last().unwrap_or_default()).into());
|
||||||
|
("Screen", panels_root)
|
||||||
|
},
|
||||||
|
OverlayCategory::Mirror => {
|
||||||
|
params.insert("display".into(), meta.name.as_ref().into());
|
||||||
|
("Mirror", panels_root)
|
||||||
|
},
|
||||||
|
OverlayCategory::Panel => {
|
||||||
|
("Panel", panels_root)
|
||||||
|
},
|
||||||
|
OverlayCategory::WayVR => {
|
||||||
|
("App", apps_root)
|
||||||
|
},
|
||||||
|
_ => continue
|
||||||
|
};
|
||||||
|
|
||||||
|
params.insert("idx".into(), i.to_string().into());
|
||||||
|
params.insert("name".into(), meta.name.as_ref().into());
|
||||||
|
panel.parser_state.instantiate_template(
|
||||||
|
&doc_params,
|
||||||
|
template,
|
||||||
|
&mut panel.layout,
|
||||||
|
root,
|
||||||
|
params,
|
||||||
|
)?;
|
||||||
|
let overlay_buttons = panel.parser_state.fetch_component_as::<ComponentButton>(&format!("overlay_{i}"))?;
|
||||||
|
if meta.visible {
|
||||||
|
let mut com = CallbackDataCommon {
|
||||||
|
alterables: &mut alterables,
|
||||||
|
state: &panel.layout.state,
|
||||||
|
};
|
||||||
|
overlay_buttons.set_sticky_state(&mut com, true);
|
||||||
|
}
|
||||||
|
panel.state.overlay_buttons.insert(meta.id, overlay_buttons);
|
||||||
|
}
|
||||||
|
panel.process_custom_elems(app);
|
||||||
|
}
|
||||||
|
OverlayEventData::VisibleOverlaysChanged(overlays) => {
|
||||||
|
let mut com = CallbackDataCommon {
|
||||||
|
alterables: &mut alterables,
|
||||||
|
state: &panel.layout.state,
|
||||||
|
};
|
||||||
|
let mut overlay_buttons = panel.state.overlay_buttons.clone();
|
||||||
|
|
||||||
|
for visible in &*overlays {
|
||||||
|
if let Some(btn) = overlay_buttons.remove(*visible)
|
||||||
|
{
|
||||||
|
btn.set_sticky_state(&mut com, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for btn in overlay_buttons.values() {
|
||||||
|
btn.set_sticky_state(&mut com, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
panel.layout.process_alterables(alterables)?;
|
||||||
|
Ok(())
|
||||||
|
}));
|
||||||
|
|
||||||
|
panel
|
||||||
|
.timers
|
||||||
|
.push(GuiTimer::new(Duration::from_millis(100), 0));
|
||||||
|
|
||||||
app_misc::process_layout_result(
|
app_misc::process_layout_result(
|
||||||
app,
|
app,
|
||||||
panel.layout.update(&mut LayoutUpdateParams {
|
panel.layout.update(&mut LayoutUpdateParams {
|
||||||
|
|||||||
@@ -1,35 +1,24 @@
|
|||||||
use std::{
|
use std::{
|
||||||
cell::Cell,
|
cell::Cell, collections::HashMap, process::{Child, Command}, rc::Rc, sync::atomic::Ordering
|
||||||
collections::HashMap,
|
|
||||||
process::{Child, Command},
|
|
||||||
sync::atomic::Ordering,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
KEYMAP_CHANGE,
|
backend::input::{HoverResult, PointerHit}, gui::panel::GuiPanel, overlays::keyboard::{builder::create_keyboard_panel, layout::AltModifier}, state::AppState, subsystem::{
|
||||||
backend::input::{HoverResult, PointerHit},
|
|
||||||
gui::panel::GuiPanel,
|
|
||||||
overlays::keyboard::{builder::create_keyboard_panel, layout::AltModifier},
|
|
||||||
state::AppState,
|
|
||||||
subsystem::{
|
|
||||||
dbus::DbusConnector,
|
dbus::DbusConnector,
|
||||||
hid::{
|
hid::{
|
||||||
ALT, CTRL, KeyModifier, META, SHIFT, SUPER, VirtualKey, WheelDelta, XkbKeymap,
|
get_keymap_wl, get_keymap_x11, KeyModifier, VirtualKey, WheelDelta, XkbKeymap, ALT, CTRL, META, SHIFT, SUPER
|
||||||
get_keymap_wl, get_keymap_x11,
|
|
||||||
},
|
},
|
||||||
},
|
}, windowing::{
|
||||||
windowing::{
|
backend::{FrameMeta, OverlayBackend, OverlayEventData, OverlayMeta, RenderResources, ShouldRender},
|
||||||
backend::{FrameMeta, OverlayBackend, OverlayEventData, RenderResources, ShouldRender},
|
window::{OverlayCategory, OverlayWindowConfig}, OverlayID,
|
||||||
window::{OverlayCategory, OverlayWindowConfig},
|
}, KEYMAP_CHANGE
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use glam::{Affine3A, Quat, Vec3, vec3};
|
use glam::{Affine3A, Quat, Vec3, vec3};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use slotmap::{SlotMap, new_key_type};
|
use slotmap::{new_key_type, SecondaryMap, SlotMap};
|
||||||
use wgui::{
|
use wgui::{
|
||||||
drawing,
|
components::button::ComponentButton, drawing, event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex}
|
||||||
event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex},
|
|
||||||
};
|
};
|
||||||
use wlx_common::overlays::{BackendAttrib, BackendAttribValue};
|
use wlx_common::overlays::{BackendAttrib, BackendAttribValue};
|
||||||
use wlx_common::windowing::{OverlayWindowState, Positioning};
|
use wlx_common::windowing::{OverlayWindowState, Positioning};
|
||||||
@@ -54,6 +43,10 @@ pub fn create_keyboard(app: &mut AppState, wayland: bool) -> anyhow::Result<Over
|
|||||||
_ => 0,
|
_ => 0,
|
||||||
},
|
},
|
||||||
processes: vec![],
|
processes: vec![],
|
||||||
|
set_buttons: vec![],
|
||||||
|
overlay_buttons: SecondaryMap::new(),
|
||||||
|
overlay_metas: SecondaryMap::new(),
|
||||||
|
current_set: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let auto_labels = layout.auto_labels.unwrap_or(true);
|
let auto_labels = layout.auto_labels.unwrap_or(true);
|
||||||
@@ -309,10 +302,14 @@ struct KeyboardState {
|
|||||||
modifiers: KeyModifier,
|
modifiers: KeyModifier,
|
||||||
alt_modifier: KeyModifier,
|
alt_modifier: KeyModifier,
|
||||||
processes: Vec<Child>,
|
processes: Vec<Child>,
|
||||||
|
set_buttons: Vec<Rc<ComponentButton>>,
|
||||||
|
overlay_buttons: SecondaryMap<OverlayID, Rc<ComponentButton>>,
|
||||||
|
overlay_metas: SecondaryMap<OverlayID, OverlayMeta>,
|
||||||
|
current_set: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyboardState {
|
impl KeyboardState {
|
||||||
const fn take(&mut self) -> Self {
|
fn take(&mut self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
modifiers: self.modifiers,
|
modifiers: self.modifiers,
|
||||||
alt_modifier: self.alt_modifier,
|
alt_modifier: self.alt_modifier,
|
||||||
@@ -321,6 +318,22 @@ impl KeyboardState {
|
|||||||
std::mem::swap(&mut processes, &mut self.processes);
|
std::mem::swap(&mut processes, &mut self.processes);
|
||||||
processes
|
processes
|
||||||
},
|
},
|
||||||
|
set_buttons: {
|
||||||
|
let mut set_buttons = vec![];
|
||||||
|
std::mem::swap(&mut set_buttons, &mut self.set_buttons);
|
||||||
|
set_buttons
|
||||||
|
},
|
||||||
|
overlay_buttons: {
|
||||||
|
let mut overlay_buttons = SecondaryMap::new();
|
||||||
|
std::mem::swap(&mut overlay_buttons, &mut self.overlay_buttons);
|
||||||
|
overlay_buttons
|
||||||
|
},
|
||||||
|
overlay_metas: {
|
||||||
|
let mut overlay_metas= SecondaryMap::new();
|
||||||
|
std::mem::swap(&mut overlay_metas, &mut self.overlay_metas);
|
||||||
|
overlay_metas
|
||||||
|
},
|
||||||
|
current_set: self.current_set.take(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
|||||||
}
|
}
|
||||||
OverlayEventData::OverlaysChanged(metas) => {
|
OverlayEventData::OverlaysChanged(metas) => {
|
||||||
panel.state.overlay_metas.clear();
|
panel.state.overlay_metas.clear();
|
||||||
for meta in metas {
|
for meta in &*metas {
|
||||||
match meta.category {
|
match meta.category {
|
||||||
OverlayCategory::Keyboard => {
|
OverlayCategory::Keyboard => {
|
||||||
panel.state.keyboard_oid = meta.id;
|
panel.state.keyboard_oid = meta.id;
|
||||||
@@ -440,7 +440,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
|||||||
panel.state.dashboard_oid = meta.id;
|
panel.state.dashboard_oid = meta.id;
|
||||||
}
|
}
|
||||||
OverlayCategory::Internal => {}
|
OverlayCategory::Internal => {}
|
||||||
_ => panel.state.overlay_metas.push(meta),
|
_ => panel.state.overlay_metas.push(meta.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,7 +494,7 @@ pub fn create_watch(app: &mut AppState) -> anyhow::Result<OverlayWindowConfig> {
|
|||||||
let mut keyboard_visible = false;
|
let mut keyboard_visible = false;
|
||||||
let mut dashboard_visible = false;
|
let mut dashboard_visible = false;
|
||||||
|
|
||||||
for visible in &overlays {
|
for visible in &*overlays {
|
||||||
if let Some(idx) = panel.state.overlay_indices.get(*visible)
|
if let Some(idx) = panel.state.overlay_indices.get(*visible)
|
||||||
&& let Some(o) = panel.state.overlay_metas.get_mut(*idx)
|
&& let Some(o) = panel.state.overlay_metas.get_mut(*idx)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use glam::{Affine2, Affine3A, Vec2};
|
use glam::{Affine2, Affine3A, Vec2};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{any::Any, sync::Arc};
|
use std::{any::Any, rc::Rc, sync::Arc};
|
||||||
use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::view::ImageView};
|
use vulkano::{command_buffer::CommandBufferUsage, format::Format, image::view::ImageView};
|
||||||
use wgui::gfx::{
|
use wgui::gfx::{
|
||||||
WGfx,
|
WGfx,
|
||||||
@@ -106,6 +106,7 @@ macro_rules! attrib_value {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct OverlayMeta {
|
pub struct OverlayMeta {
|
||||||
pub id: OverlayID,
|
pub id: OverlayID,
|
||||||
pub name: Arc<str>,
|
pub name: Arc<str>,
|
||||||
@@ -120,8 +121,8 @@ pub enum OverlayEventData {
|
|||||||
ActiveSetChanged(Option<usize>),
|
ActiveSetChanged(Option<usize>),
|
||||||
NumSetsChanged(usize),
|
NumSetsChanged(usize),
|
||||||
EditModeChanged(bool),
|
EditModeChanged(bool),
|
||||||
OverlaysChanged(Vec<OverlayMeta>),
|
OverlaysChanged(Rc<[OverlayMeta]>),
|
||||||
VisibleOverlaysChanged(Vec<OverlayID>),
|
VisibleOverlaysChanged(Rc<[OverlayID]>),
|
||||||
DevicesChanged,
|
DevicesChanged,
|
||||||
OverlayGrabbed {
|
OverlayGrabbed {
|
||||||
name: Arc<str>,
|
name: Arc<str>,
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, VecDeque},
|
collections::{HashMap, VecDeque}, rc::Rc, sync::atomic::Ordering
|
||||||
sync::atomic::Ordering,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
use glam::{Affine3A, Vec3, Vec3A};
|
use glam::{Affine3A, Vec3, Vec3A};
|
||||||
use slotmap::{HopSlotMap, Key, SecondaryMap};
|
use slotmap::{HopSlotMap, Key, SecondaryMap};
|
||||||
use wlx_common::{
|
use wlx_common::{
|
||||||
astr_containers::{AStrMap, AStrMapExt},
|
astr_containers::{AStrMap, AStrMapExt}, common::LogErr, config::SerializedWindowSet, overlays::{BackendAttrib, ToastTopic}
|
||||||
config::SerializedWindowSet,
|
|
||||||
overlays::{BackendAttrib, ToastTopic},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -48,6 +46,7 @@ pub struct OverlayWindowManager<T> {
|
|||||||
restore_set: usize,
|
restore_set: usize,
|
||||||
anchor_local: Affine3A,
|
anchor_local: Affine3A,
|
||||||
watch_id: OverlayID,
|
watch_id: OverlayID,
|
||||||
|
keyboard_id: OverlayID,
|
||||||
edit_mode: bool,
|
edit_mode: bool,
|
||||||
dropped_overlays: VecDeque<OverlayWindowData<T>>,
|
dropped_overlays: VecDeque<OverlayWindowData<T>>,
|
||||||
initialized: bool,
|
initialized: bool,
|
||||||
@@ -66,6 +65,7 @@ where
|
|||||||
sets: vec![OverlayWindowSet::default()],
|
sets: vec![OverlayWindowSet::default()],
|
||||||
anchor_local: Affine3A::from_translation(Vec3::NEG_Z),
|
anchor_local: Affine3A::from_translation(Vec3::NEG_Z),
|
||||||
watch_id: OverlayID::null(), // set down below
|
watch_id: OverlayID::null(), // set down below
|
||||||
|
keyboard_id: OverlayID::null(), // set down below
|
||||||
edit_mode: false,
|
edit_mode: false,
|
||||||
dropped_overlays: VecDeque::with_capacity(8),
|
dropped_overlays: VecDeque::with_capacity(8),
|
||||||
initialized: false,
|
initialized: false,
|
||||||
@@ -101,7 +101,7 @@ where
|
|||||||
|
|
||||||
let mut keyboard = OverlayWindowData::from_config(create_keyboard(app, wayland)?);
|
let mut keyboard = OverlayWindowData::from_config(create_keyboard(app, wayland)?);
|
||||||
keyboard.config.show_on_spawn = true;
|
keyboard.config.show_on_spawn = true;
|
||||||
let keyboard_id = me.add(keyboard, app);
|
me.keyboard_id = me.add(keyboard, app);
|
||||||
|
|
||||||
// is this needed?
|
// is this needed?
|
||||||
me.switch_to_set(app, None, false);
|
me.switch_to_set(app, None, false);
|
||||||
@@ -110,11 +110,11 @@ where
|
|||||||
let kbd_state = me
|
let kbd_state = me
|
||||||
.sets
|
.sets
|
||||||
.last()
|
.last()
|
||||||
.and_then(|s| s.overlays.get(keyboard_id))
|
.and_then(|s| s.overlays.get(me.keyboard_id))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.clone();
|
.clone();
|
||||||
for set in &mut me.sets {
|
for set in &mut me.sets {
|
||||||
set.overlays.insert(keyboard_id, kbd_state.clone());
|
set.overlays.insert(me.keyboard_id, kbd_state.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let anchor = OverlayWindowData::from_config(create_anchor(app)?);
|
let anchor = OverlayWindowData::from_config(create_anchor(app)?);
|
||||||
@@ -142,16 +142,18 @@ where
|
|||||||
me.restore_layout(app);
|
me.restore_layout(app);
|
||||||
me.overlays_changed(app)?;
|
me.overlays_changed(app)?;
|
||||||
|
|
||||||
for ev in [
|
for id in [me.watch_id, me.keyboard_id] {
|
||||||
OverlayEventData::NumSetsChanged(me.sets.len()),
|
for ev in [
|
||||||
OverlayEventData::EditModeChanged(false),
|
OverlayEventData::NumSetsChanged(me.sets.len()),
|
||||||
OverlayEventData::DevicesChanged,
|
OverlayEventData::EditModeChanged(false),
|
||||||
] {
|
OverlayEventData::DevicesChanged,
|
||||||
me.mut_by_id(me.watch_id)
|
] {
|
||||||
.unwrap()
|
me.mut_by_id(id)
|
||||||
.config
|
.unwrap()
|
||||||
.backend
|
.config
|
||||||
.notify(app, ev)?;
|
.backend
|
||||||
|
.notify(app, ev)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
me.initialized = true;
|
me.initialized = true;
|
||||||
@@ -191,6 +193,7 @@ where
|
|||||||
// no saved state
|
// no saved state
|
||||||
o.config.activate(app);
|
o.config.activate(app);
|
||||||
}
|
}
|
||||||
|
self.visible_overlays_changed(app)?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -200,11 +203,12 @@ where
|
|||||||
OverlayTask::AddSet => {
|
OverlayTask::AddSet => {
|
||||||
self.sets.push(OverlayWindowSet::default());
|
self.sets.push(OverlayWindowSet::default());
|
||||||
let len = self.sets.len();
|
let len = self.sets.len();
|
||||||
if let Some(watch) = self.mut_by_id(self.watch_id) {
|
for id in [self.watch_id, self.keyboard_id] {
|
||||||
watch
|
self.mut_by_id(id).and_then(|o| o
|
||||||
.config
|
.config
|
||||||
.backend
|
.backend
|
||||||
.notify(app, OverlayEventData::NumSetsChanged(len))?;
|
.notify(app, OverlayEventData::NumSetsChanged(len)).log_err().ok())
|
||||||
|
.context("Could not notify NumSetsChanged")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OverlayTask::DeleteActiveSet => {
|
OverlayTask::DeleteActiveSet => {
|
||||||
@@ -235,11 +239,12 @@ where
|
|||||||
self.switch_to_set(app, None, false);
|
self.switch_to_set(app, None, false);
|
||||||
self.sets.remove(set);
|
self.sets.remove(set);
|
||||||
let len = self.sets.len();
|
let len = self.sets.len();
|
||||||
if let Some(watch) = self.mut_by_id(self.watch_id) {
|
for id in [self.watch_id, self.keyboard_id] {
|
||||||
watch
|
self.mut_by_id(id).and_then(|o| o
|
||||||
.config
|
.config
|
||||||
.backend
|
.backend
|
||||||
.notify(app, OverlayEventData::NumSetsChanged(len))?;
|
.notify(app, OverlayEventData::NumSetsChanged(len)).log_err().ok())
|
||||||
|
.context("Could not notify NumSetsChanged")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OverlayTask::CleanupMirrors => {
|
OverlayTask::CleanupMirrors => {
|
||||||
@@ -733,12 +738,13 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
}
|
}
|
||||||
self.current_set = new_set;
|
self.current_set = new_set;
|
||||||
|
|
||||||
if let Some(watch) = self.mut_by_id(self.watch_id) {
|
for id in [self.watch_id, self.keyboard_id] {
|
||||||
watch
|
let _ = self.mut_by_id(id)
|
||||||
.config
|
.context("Missing overlay")
|
||||||
|
.and_then(|o|
|
||||||
|
o.config
|
||||||
.backend
|
.backend
|
||||||
.notify(app, OverlayEventData::ActiveSetChanged(new_set))
|
.notify(app, OverlayEventData::ActiveSetChanged(new_set)));
|
||||||
.unwrap(); // TODO: handle this
|
|
||||||
|
|
||||||
let _ = self
|
let _ = self
|
||||||
.visible_overlays_changed(app)
|
.visible_overlays_changed(app)
|
||||||
@@ -775,11 +781,14 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(watch) = self.mut_by_id(self.watch_id) {
|
let meta: Rc<[OverlayMeta]> = meta.into();
|
||||||
watch
|
for id in [self.watch_id, self.keyboard_id] {
|
||||||
|
let _ = self.mut_by_id(id)
|
||||||
|
.context("Missing overlay")
|
||||||
|
.and_then(|o| o
|
||||||
.config
|
.config
|
||||||
.backend
|
.backend
|
||||||
.notify(app, OverlayEventData::OverlaysChanged(meta))?;
|
.notify(app, OverlayEventData::OverlaysChanged(meta.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -797,11 +806,14 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
vis.push(id);
|
vis.push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(watch) = self.mut_by_id(self.watch_id) {
|
let vis: Rc<[OverlayID]> = vis.into();
|
||||||
watch
|
for id in [self.watch_id, self.keyboard_id] {
|
||||||
|
let _ = self.mut_by_id(id)
|
||||||
|
.context("Missing overlay")
|
||||||
|
.and_then(|o| o
|
||||||
.config
|
.config
|
||||||
.backend
|
.backend
|
||||||
.notify(app, OverlayEventData::VisibleOverlaysChanged(vis))?;
|
.notify(app, OverlayEventData::VisibleOverlaysChanged(vis.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -809,10 +821,10 @@ impl<T> OverlayWindowManager<T> {
|
|||||||
|
|
||||||
pub fn devices_changed(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
pub fn devices_changed(&mut self, app: &mut AppState) -> anyhow::Result<()> {
|
||||||
if let Some(watch) = self.mut_by_id(self.watch_id) {
|
if let Some(watch) = self.mut_by_id(self.watch_id) {
|
||||||
watch
|
let _ = watch
|
||||||
.config
|
.config
|
||||||
.backend
|
.backend
|
||||||
.notify(app, OverlayEventData::DevicesChanged)?;
|
.notify(app, OverlayEventData::DevicesChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user