dash-frontend: Top panel title
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
|
||||
<theme>
|
||||
<var key="side_size" value="48" />
|
||||
<var key="top_size" value="40" />
|
||||
<var key="side_sprite_size" value="26" />
|
||||
<var key="side_button_size" value="48" />
|
||||
</theme>
|
||||
@@ -25,13 +26,6 @@
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<div position="absolute" width="100%" justify_content="space_between">
|
||||
<div />
|
||||
<div padding="6">
|
||||
<Button id="btn_close" sprite_src_builtin="dashboard/close.svg" color="#000000" border="2" border_color="~color_faded" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- left/right separator (menu and rest) -->
|
||||
<div flex_direction="row" gap="8" width="100%" height="100%" padding="4" interactable="0">
|
||||
<!-- LEFT MENU -->
|
||||
@@ -60,15 +54,29 @@
|
||||
</rectangle>
|
||||
</div>
|
||||
<!-- REST -->
|
||||
<!-- content/bottom panel separator -->
|
||||
<!-- top/content/bottom panel separator -->
|
||||
<div
|
||||
flex_direction="column"
|
||||
gap="8"
|
||||
width="100%"
|
||||
height="100%"
|
||||
overflow_x="scroll">
|
||||
<!-- CONTENT -->
|
||||
<!-- TOP PANEL -->
|
||||
<div position="relative" width="100%" height="~top_size" min_height="~top_size" max_height="~top_size" justify_content="end">
|
||||
<!-- Title bar -->
|
||||
<div width="100%" align_items="center" justify_content="center">
|
||||
<rectangle min_width="300" height="100%" consume_mouse_events="1" round="100%" color="~color_top_panel" align_items="center" justify_content="center" gap="8">
|
||||
<sprite id="sprite_titlebar_icon" width="28" height="28" />
|
||||
<label id="label_titlebar_title" weight="bold" size="16" text="Title" />
|
||||
</rectangle>
|
||||
</div>
|
||||
<!-- Close button -->
|
||||
<Button position="absolute" id="btn_close" color="~color_top_panel" round="100%" width="~top_size" height="~top_size" tooltip="CLOSE_WINDOW" tooltip_side="left">
|
||||
<sprite src_builtin="dashboard/close.svg" width="32" height="32" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- CONTENT -->
|
||||
<!-- color and color2 alpha will be modified at runtime -->
|
||||
<rectangle
|
||||
id="rect_content"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
<include src="../theme.xml" />
|
||||
|
||||
<template name="AppEntry">
|
||||
@@ -25,7 +24,6 @@
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<TabTitle translation="APPLICATIONS" icon="dashboard/apps.svg" />
|
||||
<!-- placeholders for now -->
|
||||
<!--
|
||||
<div gap="4" align_items="center">
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
<elements>
|
||||
<TabTitle translation="GAMES" icon="dashboard/games.svg" />
|
||||
<rectangle macro="group_box" id="running_games_list_parent" align_self="center" />
|
||||
<div id="game_list_parent" align_items="center" />
|
||||
</elements>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
<include src="../t_group_box.xml" />
|
||||
|
||||
|
||||
<!-- key: str, value: str -->
|
||||
<template name="BoolFlag">
|
||||
<div flex_direction="row" gap="4">
|
||||
@@ -27,7 +25,6 @@
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<TabTitle translation="MONADO_RUNTIME" icon="dashboard/monado.svg" />
|
||||
<label translation="DISPLAY_BRIGHTNESS" />
|
||||
<Slider id="slider_brightness" width="300" height="24" min_value="0" max_value="140" />
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<layout>
|
||||
<include src="t_tab_title.xml" />
|
||||
<include src="../t_group_box.xml" />
|
||||
<include src="../t_dropdown_button.xml" />
|
||||
|
||||
@@ -46,7 +45,6 @@
|
||||
</template>
|
||||
|
||||
<elements>
|
||||
<TabTitle translation="SETTINGS" icon="dashboard/settings.svg" />
|
||||
<div gap="4">
|
||||
<Tabs id="tabs">
|
||||
<Tab name="look_and_feel" translation="APP_SETTINGS.LOOK_AND_FEEL" sprite_src_builtin="dashboard/palette.svg" />
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<layout>
|
||||
<!-- translation, icon -->
|
||||
<template name="TabTitle">
|
||||
<div gap="8" align_items="center">
|
||||
<sprite src_builtin="${icon}" width="24" height="24" />
|
||||
<label translation="${translation}" size="18" weight="bold" />
|
||||
</div>
|
||||
</template>
|
||||
</layout>
|
||||
@@ -2,6 +2,7 @@
|
||||
<theme>
|
||||
<var key="color_menu_dark" value="#0A0A0ACC" />
|
||||
<var key="color_accent" value="#008cff" />
|
||||
<var key="color_top_panel" value="#00000099" />
|
||||
<var key="color_bottom_panel" value="#141e28" />
|
||||
</theme>
|
||||
</layout>
|
||||
@@ -1,5 +1,6 @@
|
||||
use std::{path::PathBuf, rc::Rc};
|
||||
|
||||
use anyhow::Context;
|
||||
use chrono::Timelike;
|
||||
use glam::Vec2;
|
||||
use wgui::{
|
||||
@@ -10,8 +11,9 @@ use wgui::{
|
||||
i18n::Translation,
|
||||
layout::{Layout, LayoutParams, LayoutUpdateParams, LayoutUpdateResult, WidgetID},
|
||||
parser::{Fetchable, ParseDocumentParams, ParserState},
|
||||
renderer_vk::text::custom_glyph::CustomGlyphData,
|
||||
task::Tasks,
|
||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle},
|
||||
widget::{label::WidgetLabel, rectangle::WidgetRectangle, sprite::WidgetSprite},
|
||||
windowing::window::{WguiWindow, WguiWindowParams, WguiWindowParamsExtra, WguiWindowPlacement},
|
||||
};
|
||||
use wlx_common::{
|
||||
@@ -22,7 +24,7 @@ use wlx_common::{
|
||||
|
||||
use crate::{
|
||||
assets,
|
||||
tab::{apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, settings::TabSettings, Tab, TabType},
|
||||
tab::{Tab, TabType, apps::TabApps, games::TabGames, home::TabHome, monado::TabMonado, settings::TabSettings},
|
||||
util::{
|
||||
popup_manager::{MountPopupParams, PopupManager, PopupManagerParams},
|
||||
toast_manager::ToastManager,
|
||||
@@ -32,8 +34,10 @@ use crate::{
|
||||
};
|
||||
|
||||
pub struct FrontendWidgets {
|
||||
pub id_label_time: WidgetID,
|
||||
pub id_rect_content: WidgetID,
|
||||
id_label_time: WidgetID,
|
||||
id_rect_content: WidgetID,
|
||||
id_sprite_titlebar_icon: WidgetID,
|
||||
id_label_titlebar_title: WidgetID,
|
||||
}
|
||||
|
||||
pub type FrontendTasks = Tasks<FrontendTask>;
|
||||
@@ -148,6 +152,8 @@ impl<T: 'static> Frontend<T> {
|
||||
|
||||
let id_label_time = state.get_widget_id("label_time")?;
|
||||
let id_rect_content = state.get_widget_id("rect_content")?;
|
||||
let id_sprite_titlebar_icon = state.get_widget_id("sprite_titlebar_icon")?;
|
||||
let id_label_titlebar_title = state.get_widget_id("label_titlebar_title")?;
|
||||
|
||||
let timestep = Timestep::new(60.0);
|
||||
|
||||
@@ -161,6 +167,8 @@ impl<T: 'static> Frontend<T> {
|
||||
widgets: FrontendWidgets {
|
||||
id_label_time,
|
||||
id_rect_content,
|
||||
id_sprite_titlebar_icon,
|
||||
id_label_titlebar_title,
|
||||
},
|
||||
timestep,
|
||||
interface: params.interface,
|
||||
@@ -283,9 +291,10 @@ impl<T: 'static> Frontend<T> {
|
||||
let mut common = c.common();
|
||||
|
||||
{
|
||||
let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(self.widgets.id_label_time) else {
|
||||
anyhow::bail!("");
|
||||
};
|
||||
let mut label = common
|
||||
.state
|
||||
.widgets
|
||||
.cast_as::<WidgetLabel>(self.widgets.id_label_time)?;
|
||||
|
||||
let now = chrono::Local::now();
|
||||
let hours = now.hour();
|
||||
@@ -370,11 +379,48 @@ impl<T: 'static> Frontend<T> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_tab_title(&mut self, translation: &str, icon: &str) -> anyhow::Result<()> {
|
||||
let mut c = self.layout.start_common();
|
||||
let mut common = c.common();
|
||||
|
||||
{
|
||||
let mut label = common
|
||||
.state
|
||||
.widgets
|
||||
.cast_as::<WidgetLabel>(self.widgets.id_label_titlebar_title)?;
|
||||
label.set_text(&mut common, Translation::from_translation_key(translation));
|
||||
}
|
||||
|
||||
{
|
||||
let mut sprite = common
|
||||
.state
|
||||
.widgets
|
||||
.cast_as::<WidgetSprite>(self.widgets.id_sprite_titlebar_icon)?;
|
||||
sprite.set_content(
|
||||
&mut common,
|
||||
Some(CustomGlyphData::from_assets(&self.globals, AssetPath::BuiltIn(icon))?),
|
||||
);
|
||||
}
|
||||
|
||||
c.finish()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_tab(&mut self, data: &mut T, tab_type: TabType) -> anyhow::Result<()> {
|
||||
log::info!("Setting tab to {tab_type:?}");
|
||||
let widget_content = self.state.fetch_widget(&self.layout.state, "content")?;
|
||||
self.layout.remove_children(widget_content.id);
|
||||
|
||||
let (tab_translation, icon_path) = match tab_type {
|
||||
TabType::Home => ("HOME_SCREEN", "dashboard/home.svg"),
|
||||
TabType::Apps => ("APPLICATIONS", "dashboard/apps.svg"),
|
||||
TabType::Games => ("GAMES", "dashboard/games.svg"),
|
||||
TabType::Monado => ("MONADO_RUNTIME", "dashboard/monado.svg"),
|
||||
TabType::Settings => ("SETTINGS", "dashboard/settings.svg"),
|
||||
};
|
||||
|
||||
self.set_tab_title(tab_translation, icon_path)?;
|
||||
|
||||
let tab: Box<dyn Tab<T>> = match tab_type {
|
||||
TabType::Home => Box::new(TabHome::new(self, widget_content.id, data)?),
|
||||
TabType::Apps => Box::new(TabApps::new(self, widget_content.id, data)?),
|
||||
|
||||
@@ -55,8 +55,7 @@ fn button_click_callback(
|
||||
) -> ButtonClickCallback {
|
||||
Rc::new(move |common, _e| {
|
||||
label
|
||||
.get_as::<WidgetLabel>()
|
||||
.unwrap()
|
||||
.cast::<WidgetLabel>()?
|
||||
.set_text(common, Translation::from_raw_text(text));
|
||||
|
||||
button.try_cast::<ComponentButton>()?.set_text(
|
||||
@@ -169,7 +168,7 @@ impl TestbedGeneric {
|
||||
let cb_first = parser_state.fetch_component_as::<ComponentCheckbox>("cb_first")?;
|
||||
let label = label_cur_option.widget.clone();
|
||||
cb_first.on_toggle(Box::new(move |common, e| {
|
||||
let mut widget = label.get_as::<WidgetLabel>().unwrap();
|
||||
let mut widget = label.cast::<WidgetLabel>()?;
|
||||
let text = format!("checkbox toggle: {}", e.checked);
|
||||
widget.set_text(common, Translation::from_raw_text(&text));
|
||||
Ok(())
|
||||
|
||||
@@ -103,8 +103,7 @@ pub(super) fn setup_custom_label<S: 'static>(
|
||||
layout
|
||||
.state
|
||||
.widgets
|
||||
.get_as::<WidgetLabel>(attribs.widget_id)
|
||||
.unwrap()
|
||||
.cast_as::<WidgetLabel>(attribs.widget_id)?
|
||||
.set_text_simple(&mut globals, Translation::from_raw_text(pretty_tz));
|
||||
|
||||
// does not need to be dynamic
|
||||
|
||||
@@ -75,6 +75,10 @@ impl WidgetMap {
|
||||
self.0.get(handle)?.get_as::<T>()
|
||||
}
|
||||
|
||||
pub fn cast_as<T: 'static>(&self, handle: WidgetID) -> anyhow::Result<RefMut<'_, T>> {
|
||||
self.get_as(handle).context("Widget cast failed")
|
||||
}
|
||||
|
||||
pub fn get(&self, handle: WidgetID) -> Option<&Widget> {
|
||||
self.0.get(handle)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use anyhow::Context;
|
||||
use glam::Vec2;
|
||||
use taffy::{NodeId, TaffyTree};
|
||||
|
||||
@@ -248,10 +249,18 @@ impl dyn WidgetObj {
|
||||
any.downcast_ref::<T>()
|
||||
}
|
||||
|
||||
pub fn cast<T: 'static>(&self) -> anyhow::Result<&T> {
|
||||
self.get_as().context("cast failed")
|
||||
}
|
||||
|
||||
pub fn get_as_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||
let any = self.as_any_mut();
|
||||
any.downcast_mut::<T>()
|
||||
}
|
||||
|
||||
pub fn cast_mut<T: 'static>(&mut self) -> anyhow::Result<&mut T> {
|
||||
self.get_as_mut().context("cast failed")
|
||||
}
|
||||
}
|
||||
|
||||
struct InvokeData<'a, 'b, U1: 'static, U2: 'static> {
|
||||
|
||||
Reference in New Issue
Block a user