+
+
+
+
+
+
\ No newline at end of file
diff --git a/dash-frontend/assets/lang/de.json b/dash-frontend/assets/lang/de.json
index e342707..c7124fb 100644
--- a/dash-frontend/assets/lang/de.json
+++ b/dash-frontend/assets/lang/de.json
@@ -78,12 +78,16 @@
"SCREENCOPY_HELP": "Langsam, keine Bildschirmfreigabe-Popups.\nFunktioniert mit: Hyprland, Niri, River, Sway",
"NONE": "Keine",
"HMD_PINCH": "HMD + Kneifen",
- "EYE_PINCH": "Auge + Kneifen"
+ "EYE_PINCH": "Auge + Kneifen",
+ "EYE_ONLY": "Nur Auge",
+ "HMD_ONLY": "Nur HMD"
},
"AUTOSTART_APPS": "Anwendungen, die beim Start ausgeführt werden sollen",
"HANDSFREE_POINTER": "Freihändige Modus",
"HANDSFREE_POINTER_HELP": "Eingabe, die bei Bewegung\nder Controller verwendet wird, wenn diese nicht verfügbar sind.\nLinkes Kneifen greift, rechtes klickt.",
- "UI_GRADIENT_INTENSITY": "UI-Verlaufsintensität"
+ "UI_GRADIENT_INTENSITY": "UI-Verlaufsintensität",
+ "RESET_PLAYSPACE": "Spielbereich zurücksetzen",
+ "RESET_PLAYSPACE_HELP": "Den Abstand des Spielbereichs zurücksetzen."
},
"HELLO": "Hallo!",
"AUDIO": {
@@ -116,8 +120,7 @@
"CLOSE_WINDOW": "Fenster schließen",
"GAME_LIST": {
"NO_GAMES_FOUND": "Keine Spiele gefunden",
- "RUNNING_GAMES_LIST": "Liste der laufenden Spiele",
- "NO_RUNNING_GAME_FOUND": "Kein laufendes Spiel gefunden"
+ "RUNNING_GAMES_LIST": "Liste der laufenden Spiele"
},
"TERMINATE_PROCESS": "Prozess beenden",
"GAME_LAUNCHED": "Spiel gestartet",
diff --git a/dash-frontend/assets/lang/en.json b/dash-frontend/assets/lang/en.json
index ae16a05..c3e594c 100644
--- a/dash-frontend/assets/lang/en.json
+++ b/dash-frontend/assets/lang/en.json
@@ -132,8 +132,7 @@
"GAME_LAUNCHED": "Game launched",
"GAME_LIST": {
"NO_GAMES_FOUND": "No games found",
- "RUNNING_GAMES_LIST": "List of running games",
- "NO_RUNNING_GAME_FOUND": "No running game found"
+ "RUNNING_GAMES_LIST": "List of running games"
},
"GAMES": "Games",
"GENERAL_SETTINGS": "General settings",
diff --git a/dash-frontend/assets/lang/es.json b/dash-frontend/assets/lang/es.json
index 7f1f747..6ee4e5b 100644
--- a/dash-frontend/assets/lang/es.json
+++ b/dash-frontend/assets/lang/es.json
@@ -78,12 +78,16 @@
"SCREENCOPY_HELP": "Lento, sin ventanas emergentes de uso compartido de pantalla.\nFunciona en: Hyprland, Niri, River, Sway",
"NONE": "Ninguno",
"HMD_PINCH": "HMD + pellizco",
- "EYE_PINCH": "Ojo + pellizco"
+ "EYE_PINCH": "Ojo + pellizco",
+ "EYE_ONLY": "Solo ojo",
+ "HMD_ONLY": "Solo HMD"
},
"AUTOSTART_APPS": "Aplicaciones a ejecutar al inicio",
"HANDSFREE_POINTER": "Modo manos libres",
"HANDSFREE_POINTER_HELP": "Entrada a utilizar cuando no\nestén disponibles los mandos de movimiento.\nPellizco con la izquierda para agarrar, con la derecha para hacer clic.",
- "UI_GRADIENT_INTENSITY": "Intensidad del degradado de la IU"
+ "UI_GRADIENT_INTENSITY": "Intensidad del degradado de la IU",
+ "RESET_PLAYSPACE": "Restablecer espacio de juego",
+ "RESET_PLAYSPACE_HELP": "Borrar el desplazamiento del espacio de juego."
},
"HELLO": "¡Hola!",
"AUDIO": {
@@ -116,8 +120,7 @@
"CLOSE_WINDOW": "Cerrar ventana",
"GAME_LIST": {
"NO_GAMES_FOUND": "No se encontraron juegos",
- "RUNNING_GAMES_LIST": "Lista de juegos en ejecución",
- "NO_RUNNING_GAME_FOUND": "No se encontró ningún juego en ejecución"
+ "RUNNING_GAMES_LIST": "Lista de juegos en ejecución"
},
"TERMINATE_PROCESS": "Finalizar proceso",
"GAME_LAUNCHED": "Juego lanzado",
diff --git a/dash-frontend/assets/lang/it.json b/dash-frontend/assets/lang/it.json
index 7bd173c..787bc1f 100644
--- a/dash-frontend/assets/lang/it.json
+++ b/dash-frontend/assets/lang/it.json
@@ -75,7 +75,9 @@
"SCREENCOPY_HELP": "Lento, nessuna finestra pop-up per la condivisione dello schermo.\nFunziona su: Hyprland, Niri, River, Sway",
"NONE": "Nessuno",
"HMD_PINCH": "HMD + pizzico",
- "EYE_PINCH": "Occhio + pizzico"
+ "EYE_PINCH": "Occhio + pizzico",
+ "EYE_ONLY": "Solo occhio",
+ "HMD_ONLY": "Solo HMD"
},
"POINTER_LERP_FACTOR": "Smussamento puntatore",
"RESTART_SOFTWARE": "Riavvia il software",
@@ -103,7 +105,9 @@
"AUTOSTART_APPS": "App da avviare all'avvio",
"HANDSFREE_POINTER": "Modalità a mani libere",
"HANDSFREE_POINTER_HELP": "Input da usare quando i\ncontroller di movimento non sono disponibili.\nPizzico sinistro per afferrare, destro per cliccare.",
- "UI_GRADIENT_INTENSITY": "Intensità gradiente dell'interfaccia utente"
+ "UI_GRADIENT_INTENSITY": "Intensità gradiente dell'interfaccia utente",
+ "RESET_PLAYSPACE": "Ripristina playspace",
+ "RESET_PLAYSPACE_HELP": "Cancella l'offset dello spazio di gioco."
},
"APPLICATION_LAUNCHER": "Lanciatore applicazioni",
"APPLICATION_STARTED": "Applicazione avviata",
@@ -128,8 +132,7 @@
"GAME_LAUNCHED": "Gioco lanciato",
"GAME_LIST": {
"NO_GAMES_FOUND": "Nessun gioco trovato",
- "RUNNING_GAMES_LIST": "Lista dei giochi in esecuzione",
- "NO_RUNNING_GAME_FOUND": "Nessun gioco in esecuzione trovato"
+ "RUNNING_GAMES_LIST": "Lista dei giochi in esecuzione"
},
"GAMES": "Giochi",
"GENERAL_SETTINGS": "Impostazioni generali",
diff --git a/dash-frontend/assets/lang/ja.json b/dash-frontend/assets/lang/ja.json
index c647069..f8aec23 100644
--- a/dash-frontend/assets/lang/ja.json
+++ b/dash-frontend/assets/lang/ja.json
@@ -78,12 +78,16 @@
"SCREENCOPY_HELP": "遅延あり、画面共有ポップアップなし。\n動作する環境: Hyprland, Niri, River, Sway",
"NONE": "なし",
"HMD_PINCH": "HMD + ピンチ",
- "EYE_PINCH": "つまんで目を合わせる"
+ "EYE_PINCH": "つまんで目を合わせる",
+ "EYE_ONLY": "視野のみ",
+ "HMD_ONLY": "HMDのみ"
},
"AUTOSTART_APPS": "起動時に実行するアプリ",
"HANDSFREE_POINTER": "ハンズフリーモード",
"HANDSFREE_POINTER_HELP": "モーションコントローラーが利用できない場合の入力方法。\n左手のピンチは掴み、右手のピンチはクリックです。",
- "UI_GRADIENT_INTENSITY": "UIグラデーションの強さ"
+ "UI_GRADIENT_INTENSITY": "UIグラデーションの強さ",
+ "RESET_PLAYSPACE": "プレイエリアをリセット",
+ "RESET_PLAYSPACE_HELP": "プレイエリアのオフセットをクリアします。"
},
"HELLO": "こんにちは!",
"AUDIO": {
@@ -116,8 +120,7 @@
"CLOSE_WINDOW": "ウィンドウを閉じる",
"GAME_LIST": {
"NO_GAMES_FOUND": "ゲームが見つかりませんでした",
- "RUNNING_GAMES_LIST": "実行中のゲーム一覧",
- "NO_RUNNING_GAME_FOUND": "実行中のゲームが見つかりません"
+ "RUNNING_GAMES_LIST": "実行中のゲーム一覧"
},
"TERMINATE_PROCESS": "プロセスを終了する",
"GAME_LAUNCHED": "ゲームが起動しました",
diff --git a/dash-frontend/assets/lang/pl.json b/dash-frontend/assets/lang/pl.json
index e9fb87f..30f0baa 100644
--- a/dash-frontend/assets/lang/pl.json
+++ b/dash-frontend/assets/lang/pl.json
@@ -73,12 +73,16 @@
"SCREENCOPY_HELP": "Wolne, bez wyskakujących okienek udostępniania ekranu.\nDziała na: Hyprland, Niri, River, Sway",
"NONE": "Brak",
"HMD_PINCH": "HMD + szczyknięcie",
- "EYE_PINCH": "Ściśnięcie palcami + oko"
+ "EYE_PINCH": "Ściśnięcie palcami + oko",
+ "EYE_ONLY": "Tylko oko",
+ "HMD_ONLY": "Tylko HMD"
},
"AUTOSTART_APPS": "Aplikacje do uruchomienia przy starcie",
"HANDSFREE_POINTER": "Tryb bez użycia rąk",
"HANDSFREE_POINTER_HELP": "Wejście do użycia, gdy kontrolery ruchu\nsą niedostępne. Lewy szczyptak to chwyt,\nprawy to kliknięcie.",
- "UI_GRADIENT_INTENSITY": "Intensywność gradientu UI"
+ "UI_GRADIENT_INTENSITY": "Intensywność gradientu UI",
+ "RESET_PLAYSPACE": "Zresetuj przestrzeń gry",
+ "RESET_PLAYSPACE_HELP": "Wyczyść przesunięcie przestrzeni gry."
},
"APPLICATION_LAUNCHER": "Uruchamiacz aplikacji",
"APPLICATIONS": "Aplikacje",
@@ -116,8 +120,7 @@
"CLOSE_WINDOW": "Zamknij okno",
"GAME_LIST": {
"NO_GAMES_FOUND": "Nie znaleziono gier",
- "RUNNING_GAMES_LIST": "Lista uruchomionych gier",
- "NO_RUNNING_GAME_FOUND": "Nie znaleziono uruchomionej gry"
+ "RUNNING_GAMES_LIST": "Lista uruchomionych gier"
},
"TERMINATE_PROCESS": "Zakończ proces",
"GAME_LAUNCHED": "Gra uruchomiona",
diff --git a/dash-frontend/assets/lang/zh_CN.json b/dash-frontend/assets/lang/zh_CN.json
index faf4b74..64fc5a5 100644
--- a/dash-frontend/assets/lang/zh_CN.json
+++ b/dash-frontend/assets/lang/zh_CN.json
@@ -75,7 +75,9 @@
"SCREENCOPY_HELP": "慢速,无屏幕共享弹窗。\n支持:Hyprland, Niri, River, Sway",
"NONE": "无",
"HMD_PINCH": "HMD + 捏合",
- "EYE_PINCH": "眼睛 + 捏合"
+ "EYE_PINCH": "眼睛 + 捏合",
+ "EYE_ONLY": "仅眼球",
+ "HMD_ONLY": "仅限头显"
},
"POINTER_LERP_FACTOR": "指针平滑",
"RESTART_SOFTWARE": "重启软件",
@@ -103,7 +105,9 @@
"AUTOSTART_APPS": "开机启动应用",
"HANDSFREE_POINTER": "免提模式",
"HANDSFREE_POINTER_HELP": "当运动控制器不可用时使用的输入。\n左手捏合为抓取,右手为点击。",
- "UI_GRADIENT_INTENSITY": "UI 渐变强度"
+ "UI_GRADIENT_INTENSITY": "UI 渐变强度",
+ "RESET_PLAYSPACE": "重置游戏空间",
+ "RESET_PLAYSPACE_HELP": "清除舞台空间偏移。"
},
"APPLICATION_LAUNCHER": "应用启动器",
"APPLICATION_STARTED": "应用已启动",
@@ -128,8 +132,7 @@
"GAME_LAUNCHED": "游戏已启动",
"GAME_LIST": {
"NO_GAMES_FOUND": "未找到游戏",
- "RUNNING_GAMES_LIST": "正在运行的游戏列表",
- "NO_RUNNING_GAME_FOUND": "未找到正在运行的游戏"
+ "RUNNING_GAMES_LIST": "正在运行的游戏列表"
},
"GAMES": "游戏",
"GENERAL_SETTINGS": "通用设置",
diff --git a/dash-frontend/src/frontend.rs b/dash-frontend/src/frontend.rs
index 639e311..070d1ce 100644
--- a/dash-frontend/src/frontend.rs
+++ b/dash-frontend/src/frontend.rs
@@ -1,6 +1,5 @@
use std::{path::PathBuf, rc::Rc};
-use anyhow::Context;
use chrono::Timelike;
use glam::Vec2;
use wgui::{
diff --git a/dash-frontend/src/views/game_list.rs b/dash-frontend/src/views/game_list.rs
index 72e50a5..56dcac3 100644
--- a/dash-frontend/src/views/game_list.rs
+++ b/dash-frontend/src/views/game_list.rs
@@ -2,6 +2,7 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};
use wgui::{
assets::AssetPath,
+ components::button::ComponentButton,
globals::WguiGlobals,
i18n::Translation,
layout::{Layout, WidgetID},
@@ -29,7 +30,10 @@ enum Task {
AppManifestClicked(steam_utils::AppManifest),
SetCoverArt(AppID, Rc
),
CloseLauncher,
- Refresh,
+ LoadManifests,
+ FillPage(u32),
+ PrevPage,
+ NextPage,
}
pub struct Params<'a> {
@@ -40,7 +44,9 @@ pub struct Params<'a> {
pub parent_id: WidgetID,
}
-pub struct Cell {
+const MAX_GAMES_PER_PAGE: u32 = 30;
+
+pub struct GameCoverCell {
view_cover: game_cover::View,
}
@@ -55,10 +61,14 @@ pub struct View {
frontend_tasks: FrontendTasks,
globals: WguiGlobals,
id_list_parent: WidgetID,
- cells: HashMap,
game_cover_view_common: game_cover::ViewCommon,
executor: AsyncExecutor,
state: Rc>,
+ mounted_game_covers: HashMap,
+ all_manifests: Vec,
+ cur_page: u32,
+ page_count: u32,
+ id_label_page: WidgetID,
}
impl View {
@@ -71,10 +81,21 @@ impl View {
let parser_state = wgui::parser::parse_from_assets(doc_params, params.layout, params.parent_id)?;
let list_parent = parser_state.fetch_widget(¶ms.layout.state, "list_parent")?;
+ let id_label_page = parser_state.get_widget_id("label_page")?;
let tasks = Tasks::new();
- tasks.push(Task::Refresh);
+ tasks.handle_button(
+ &parser_state.fetch_component_as::("btn_prev")?,
+ Task::PrevPage,
+ );
+
+ tasks.handle_button(
+ &parser_state.fetch_component_as::("btn_next")?,
+ Task::NextPage,
+ );
+
+ tasks.push(Task::LoadManifests);
Ok(Self {
parser_state,
@@ -82,10 +103,14 @@ impl View {
frontend_tasks: params.frontend_tasks,
globals: params.globals.clone(),
id_list_parent: list_parent.id,
- cells: HashMap::new(),
+ mounted_game_covers: HashMap::new(),
game_cover_view_common: game_cover::ViewCommon::new(params.globals.clone()),
state: Rc::new(RefCell::new(State { view_launcher: None })),
executor: params.executor,
+ all_manifests: Vec::new(),
+ cur_page: 0,
+ page_count: 0,
+ id_label_page,
})
}
@@ -102,10 +127,13 @@ impl View {
}
for task in tasks {
match task {
- Task::Refresh => self.refresh(layout, steam_utils, executor)?,
+ Task::LoadManifests => self.load_manifests(steam_utils),
+ Task::FillPage(page_idx) => self.fill_page(layout, executor, page_idx)?,
Task::AppManifestClicked(manifest) => self.action_app_manifest_clicked(manifest)?,
Task::SetCoverArt(app_id, cover_art) => self.set_cover_art(layout, app_id, cover_art),
Task::CloseLauncher => self.state.borrow_mut().view_launcher = None,
+ Task::PrevPage => self.page_prev(),
+ Task::NextPage => self.page_next(),
}
}
}
@@ -119,18 +147,14 @@ impl View {
}
}
-pub struct Games {
- manifests: Vec,
-}
-
fn fill_game_list(
ess: &mut ConstructEssentials,
executor: &AsyncExecutor,
- cells: &mut HashMap,
- games: &Games,
+ mounted_game_covers: &mut HashMap,
+ manifests: &[steam_utils::AppManifest],
tasks: &Tasks,
) -> anyhow::Result<()> {
- for manifest in &games.manifests {
+ for manifest in manifests {
let on_loaded = {
let app_id = manifest.app_id.clone();
let tasks = tasks.clone();
@@ -156,49 +180,81 @@ fn fill_game_list(
})
});
- cells.insert(manifest.app_id.clone(), Cell { view_cover });
+ mounted_game_covers.insert(manifest.app_id.clone(), GameCoverCell { view_cover });
}
Ok(())
}
impl View {
- fn game_list(&self, steam_utils: &mut SteamUtils) -> anyhow::Result {
- let manifests = steam_utils.list_installed_games(steam_utils::GameSortMethod::PlayDateDesc)?;
-
- Ok(Games { manifests })
+ fn load_manifests(&mut self, steam_utils: &mut SteamUtils) {
+ match steam_utils.list_installed_games(steam_utils::GameSortMethod::PlayDateDesc) {
+ Ok(manifests) => {
+ self.page_count = (manifests.len() as u32 + MAX_GAMES_PER_PAGE) / MAX_GAMES_PER_PAGE;
+ self.all_manifests = manifests;
+ self.tasks.push(Task::FillPage(0));
+ }
+ Err(e) => {
+ log::error!("Failed to list installed games: {e:?}");
+ }
+ }
}
- fn refresh(
- &mut self,
- layout: &mut Layout,
- steam_utils: &mut SteamUtils,
- executor: &AsyncExecutor,
- ) -> anyhow::Result<()> {
+ fn page_prev(&mut self) {
+ if self.cur_page == 0 {
+ return;
+ }
+
+ self.cur_page -= 1;
+ self.tasks.push(Task::FillPage(self.cur_page));
+ }
+
+ fn page_next(&mut self) {
+ if self.cur_page >= self.page_count - 1 {
+ return;
+ }
+ self.cur_page += 1;
+ self.tasks.push(Task::FillPage(self.cur_page));
+ }
+
+ fn fill_page(&mut self, layout: &mut Layout, executor: &AsyncExecutor, page_idx: u32) -> anyhow::Result<()> {
layout.remove_children(self.id_list_parent);
- self.cells.clear();
+ self.mounted_game_covers.clear();
+
+ let idx_from = (page_idx * MAX_GAMES_PER_PAGE).min(self.all_manifests.len() as u32);
+ let idx_to = ((page_idx + 1) * MAX_GAMES_PER_PAGE).min(self.all_manifests.len() as u32);
+
+ let page_manifests = &self.all_manifests[idx_from as usize..idx_to as usize];
let mut text: Option = None;
- match self.game_list(steam_utils) {
- Ok(list) => {
- if list.manifests.is_empty() {
- text = Some(Translation::from_translation_key("GAME_LIST.NO_GAMES_FOUND"))
- } else {
- fill_game_list(
- &mut ConstructEssentials {
- layout,
- parent: self.id_list_parent,
- },
- executor,
- &mut self.cells,
- &list,
- &self.tasks,
- )?
- }
- }
- Err(e) => text = Some(Translation::from_raw_text(&format!("Error: {:?}", e))),
+
+ if page_manifests.is_empty() {
+ text = Some(Translation::from_translation_key("GAME_LIST.NO_GAMES_FOUND"))
}
+ // set page text
+ let mut c = layout.start_common();
+ {
+ let mut common = c.common();
+ let mut widget = common.state.widgets.cast_as::(self.id_label_page)?;
+ widget.set_text(
+ &mut common,
+ Translation::from_raw_text_string(format!("{}/{}", self.cur_page + 1, self.page_count)),
+ );
+ }
+ c.finish()?;
+
+ fill_game_list(
+ &mut ConstructEssentials {
+ layout,
+ parent: self.id_list_parent,
+ },
+ executor,
+ &mut self.mounted_game_covers,
+ page_manifests,
+ &self.tasks,
+ )?;
+
if let Some(text) = text.take() {
layout.add_child(
self.id_list_parent,
@@ -217,11 +273,11 @@ impl View {
}
fn set_cover_art(&mut self, layout: &mut Layout, app_id: AppID, cover_art: Rc) {
- let Some(cell) = &mut self.cells.get_mut(&app_id) else {
+ let Some(cover) = &mut self.mounted_game_covers.get_mut(&app_id) else {
return;
};
- if let Err(e) = cell
+ if let Err(e) = cover
.view_cover
.set_cover_art(&mut self.game_cover_view_common, layout, &cover_art)
{
diff --git a/dash-frontend/src/views/running_games_list.rs b/dash-frontend/src/views/running_games_list.rs
index 45b3241..19f9691 100644
--- a/dash-frontend/src/views/running_games_list.rs
+++ b/dash-frontend/src/views/running_games_list.rs
@@ -1,20 +1,19 @@
use wgui::{
assets::AssetPath,
components::button::ComponentButton,
+ event::StyleSetRequest,
globals::WguiGlobals,
i18n::Translation,
- layout::{Layout, WidgetID},
+ layout::{Layout, LayoutTask, WidgetID},
parser::{Fetchable, ParseDocumentParams, ParserState},
+ taffy::Display,
task::Tasks,
widget::label::WidgetLabel,
};
use crate::{
frontend::{FrontendTask, FrontendTasks},
- util::{
- steam_utils::{self, AppID, AppManifest, GameSortMethod, SteamUtils},
- wgui_simple,
- },
+ util::steam_utils::{self, AppID, AppManifest, GameSortMethod, SteamUtils},
};
#[derive(Clone)]
@@ -39,6 +38,7 @@ pub struct View {
id_list_parent: WidgetID,
installed_games: Vec,
frontend_tasks: FrontendTasks,
+ parent_id: WidgetID,
}
fn doc_params(globals: WguiGlobals) -> ParseDocumentParams<'static> {
@@ -58,7 +58,7 @@ impl View {
let installed_games = params
.steam_utils
.list_installed_games(GameSortMethod::None)
- .unwrap_or(Vec::new());
+ .unwrap_or_default();
let tasks = Tasks::::new();
@@ -72,6 +72,7 @@ impl View {
id_list_parent,
installed_games,
frontend_tasks: params.frontend_tasks,
+ parent_id: params.parent_id,
})
}
@@ -98,7 +99,7 @@ impl View {
Ok(())
}
- fn extract_name_from_appid<'a>(app_id: &AppID, manifests: &[AppManifest]) -> String {
+ fn extract_name_from_appid(app_id: &AppID, manifests: &[AppManifest]) -> String {
for manifest in manifests {
if manifest.app_id == *app_id {
return manifest.name.clone();
@@ -110,14 +111,19 @@ impl View {
fn fill_list(&mut self, layout: &mut Layout, games: Vec) -> anyhow::Result<()> {
if games.is_empty() {
- wgui_simple::create_label(
- layout,
- self.id_list_parent,
- Translation::from_translation_key("GAME_LIST.NO_RUNNING_GAME_FOUND"),
- )?;
+ // hide self
+ layout.tasks.push(LayoutTask::SetWidgetStyle(
+ self.parent_id,
+ StyleSetRequest::Display(Display::None),
+ ));
return Ok(());
}
+ layout.tasks.push(LayoutTask::SetWidgetStyle(
+ self.parent_id,
+ StyleSetRequest::Display(Display::DEFAULT),
+ ));
+
for game in games {
let game_name = View::extract_name_from_appid(&game.app_id, &self.installed_games);
diff --git a/scripts/translator/bun.lock b/scripts/translator/bun.lock
index 8df74b6..cbd723a 100644
--- a/scripts/translator/bun.lock
+++ b/scripts/translator/bun.lock
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
+ "configVersion": 0,
"workspaces": {
"": {
"name": "llm_translator",
diff --git a/wayvr/src/gui/panel/label.rs b/wayvr/src/gui/panel/label.rs
index e8a32b5..c281619 100644
--- a/wayvr/src/gui/panel/label.rs
+++ b/wayvr/src/gui/panel/label.rs
@@ -103,7 +103,8 @@ pub(super) fn setup_custom_label(
layout
.state
.widgets
- .cast_as::(attribs.widget_id)?
+ .cast_as::(attribs.widget_id)
+ .unwrap()
.set_text_simple(&mut globals, Translation::from_raw_text(pretty_tz));
// does not need to be dynamic
diff --git a/wgui/src/components/tooltip.rs b/wgui/src/components/tooltip.rs
index 6eef47c..4f9b40f 100644
--- a/wgui/src/components/tooltip.rs
+++ b/wgui/src/components/tooltip.rs
@@ -195,7 +195,7 @@ pub fn construct(ess: &mut ConstructEssentials, params: Params) -> anyhow::Resul
color: TOOLTIP_COLOR,
border_color: TOOLTIP_BORDER_COLOR,
border: 2.0,
- round: WLength::Percent(1.0),
+ round: WLength::Units(24.0),
..Default::default()
}),
taffy::Style {
diff --git a/wgui/src/layout.rs b/wgui/src/layout.rs
index 45d2e37..18d656d 100644
--- a/wgui/src/layout.rs
+++ b/wgui/src/layout.rs
@@ -138,6 +138,7 @@ pub type ModifyLayoutStateFunc = Box anyhow
pub enum LayoutTask {
RemoveWidget(WidgetID),
+ SetWidgetStyle(WidgetID, event::StyleSetRequest),
ModifyLayoutState(ModifyLayoutStateFunc),
PlaySound(WguiSoundType),
Dispatch(Box anyhow::Result<()>>),
@@ -706,12 +707,51 @@ impl Layout {
func(&mut c.common())?;
c.finish()?;
}
+ LayoutTask::SetWidgetStyle(widget_id, style_request) => {
+ self.set_style_request(widget_id, style_request);
+ }
}
}
Ok(())
}
+ fn set_style_request(&mut self, widget_id: WidgetID, style_request: event::StyleSetRequest) {
+ let Some(node_id) = self.state.nodes.get(widget_id) else {
+ return;
+ };
+
+ // taffy requires us to copy this whole 536-byte style struct.
+ // we can't get `&mut Style` directly from taffy unfortunately
+ let mut cur_style = self.state.tree.style(*node_id).unwrap().clone() /* always safe */;
+
+ match style_request {
+ event::StyleSetRequest::Display(display) => {
+ // refresh the component in case if visibility/display mode has changed
+ if cur_style.display != display
+ && let Some(component) = self.registered_components_to_refresh.get(node_id)
+ {
+ self.components_to_refresh_once.insert(component.clone());
+ }
+
+ cur_style.display = display;
+ }
+ event::StyleSetRequest::Margin(margin) => {
+ cur_style.margin = margin;
+ }
+ event::StyleSetRequest::Width(val) => {
+ cur_style.size.width = val;
+ }
+ event::StyleSetRequest::Height(val) => {
+ cur_style.size.height = val;
+ }
+ }
+
+ if let Err(e) = self.state.tree.set_style(*node_id, cur_style) {
+ log::error!("failed to set style for taffy widget ID {node_id:?}: {e:?}");
+ }
+ }
+
pub fn process_alterables(&mut self, alterables: EventAlterables) -> anyhow::Result<()> {
for task in alterables.tasks {
self.tasks.push(task);
@@ -747,39 +787,7 @@ impl Layout {
}
for (widget_id, style_request) in alterables.style_set_requests {
- let Some(node_id) = self.state.nodes.get(widget_id) else {
- continue;
- };
-
- // taffy requires us to copy this whole 536-byte style struct.
- // we can't get `&mut Style` directly from taffy unfortunately
- let mut cur_style = self.state.tree.style(*node_id).unwrap().clone() /* always safe */;
-
- match style_request {
- event::StyleSetRequest::Display(display) => {
- // refresh the component in case if visibility/display mode has changed
- if cur_style.display != display
- && let Some(component) = self.registered_components_to_refresh.get(node_id)
- {
- self.components_to_refresh_once.insert(component.clone());
- }
-
- cur_style.display = display;
- }
- event::StyleSetRequest::Margin(margin) => {
- cur_style.margin = margin;
- }
- event::StyleSetRequest::Width(val) => {
- cur_style.size.width = val;
- }
- event::StyleSetRequest::Height(val) => {
- cur_style.size.height = val;
- }
- }
-
- if let Err(e) = self.state.tree.set_style(*node_id, cur_style) {
- log::error!("failed to set style for taffy widget ID {node_id:?}: {e:?}");
- }
+ self.set_style_request(widget_id, style_request);
}
Ok(())
diff --git a/wgui/src/widget/rectangle.rs b/wgui/src/widget/rectangle.rs
index fdab121..b5a14a2 100644
--- a/wgui/src/widget/rectangle.rs
+++ b/wgui/src/widget/rectangle.rs
@@ -47,7 +47,7 @@ impl WidgetObj for WidgetRectangle {
let boundary = drawing::Boundary::construct_relative(state.transform_stack);
let round_units = match self.params.round {
- WLength::Units(units) => units as u8,
+ WLength::Units(units) => (f32::min(boundary.size.x, boundary.size.y) as u8 / 2).min(units as u8),
WLength::Percent(percent) => (f32::min(boundary.size.x, boundary.size.y) * percent / 2.0) as u8,
};