diff --git a/dash-frontend/assets/gui/view/game_launcher.xml b/dash-frontend/assets/gui/view/game_launcher.xml
new file mode 100644
index 0000000..6e214e5
--- /dev/null
+++ b/dash-frontend/assets/gui/view/game_launcher.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/dash-frontend/assets/gui/view/popup_window.xml b/dash-frontend/assets/gui/view/popup_window.xml
index c58377e..1f1f6fe 100644
--- a/dash-frontend/assets/gui/view/popup_window.xml
+++ b/dash-frontend/assets/gui/view/popup_window.xml
@@ -14,7 +14,6 @@
diff --git a/dash-frontend/src/tab/apps.rs b/dash-frontend/src/tab/apps.rs
index 566f102..9b650cf 100644
--- a/dash-frontend/src/tab/apps.rs
+++ b/dash-frontend/src/tab/apps.rs
@@ -26,21 +26,16 @@ enum Task {
}
struct State {
- launcher: Option<(PopupHandle, views::app_launcher::View)>,
+ view_launcher: Option<(PopupHandle, views::app_launcher::View)>,
}
pub struct TabApps {
#[allow(dead_code)]
- pub parser_state: ParserState,
+ parser_state: ParserState,
- #[allow(dead_code)]
state: Rc>,
-
- #[allow(dead_code)]
entries: Vec,
- #[allow(dead_code)]
app_list: AppList,
-
tasks: Tasks,
}
@@ -54,11 +49,11 @@ impl Tab for TabApps {
for task in self.tasks.drain() {
match task {
- Task::CloseLauncher => state.launcher = None,
+ Task::CloseLauncher => state.view_launcher = None,
}
}
- if let Some((_, launcher)) = &mut state.launcher {
+ if let Some((_, launcher)) = &mut state.view_launcher {
launcher.update(&mut frontend.layout, &mut frontend.interface)?;
}
Ok(())
@@ -105,7 +100,7 @@ fn on_app_click(
on_launched,
})?;
- state.borrow_mut().launcher = Some((data.handle, view));
+ state.borrow_mut().view_launcher = Some((data.handle, view));
Ok(())
})
},
@@ -129,7 +124,7 @@ impl TabApps {
let globals = frontend.layout.state.globals.clone();
let tasks = Tasks::new();
- let state = Rc::new(RefCell::new(State { launcher: None }));
+ let state = Rc::new(RefCell::new(State { view_launcher: None }));
let mut parser_state = wgui::parser::parse_from_assets(doc_params, &mut frontend.layout, parent_id)?;
let app_list_parent = parser_state.fetch_widget(&frontend.layout.state, "app_list_parent")?;
diff --git a/dash-frontend/src/tab/games.rs b/dash-frontend/src/tab/games.rs
index 528d885..f09742d 100644
--- a/dash-frontend/src/tab/games.rs
+++ b/dash-frontend/src/tab/games.rs
@@ -23,10 +23,7 @@ impl Tab for TabGames {
}
fn update(&mut self, frontend: &mut Frontend) -> anyhow::Result<()> {
- self
- .view_game_list
- .update(&mut frontend.layout, &mut frontend.executor)?;
-
+ self.view_game_list.update(&mut frontend.layout, &frontend.executor)?;
Ok(())
}
}
@@ -46,6 +43,7 @@ impl TabGames {
let game_list_parent = state.get_widget_id("game_list_parent")?;
let view_game_list = game_list::View::new(game_list::Params {
+ executor: frontend.executor.clone(),
frontend_tasks: frontend.tasks.clone(),
globals: frontend.layout.state.globals.clone(),
layout: &mut frontend.layout,
diff --git a/dash-frontend/src/tab/home.rs b/dash-frontend/src/tab/home.rs
index 180abc3..d3d5d2f 100644
--- a/dash-frontend/src/tab/home.rs
+++ b/dash-frontend/src/tab/home.rs
@@ -40,7 +40,7 @@ fn configure_label_hello(common: &mut CallbackDataCommon, label_hello: Widget, s
common.i18n().translate("HELLO").to_string()
};
- let mut label_hello = label_hello.get_as_mut::().unwrap();
+ let mut label_hello = label_hello.get_as::().unwrap();
label_hello.set_text(common, Translation::from_raw_text(&translated));
}
diff --git a/dash-frontend/src/util/cached_fetcher.rs b/dash-frontend/src/util/cached_fetcher.rs
new file mode 100644
index 0000000..d1a2ee3
--- /dev/null
+++ b/dash-frontend/src/util/cached_fetcher.rs
@@ -0,0 +1,103 @@
+use anyhow::Context;
+use serde::Deserialize;
+use wlx_common::cache_dir;
+
+use crate::util::{http_client, steam_utils::AppID, various::AsyncExecutor};
+
+pub struct CoverArt {
+ // can be empty in case if data couldn't be fetched (use a fallback image then)
+ pub compressed_image_data: Vec,
+}
+
+pub async fn request_image(executor: AsyncExecutor, app_id: AppID) -> anyhow::Result {
+ let cache_file_path = format!("cover_arts/{}.bin", app_id);
+
+ // check if file already exists in cache directory
+ if let Some(data) = cache_dir::get_data(&cache_file_path).await {
+ return Ok(CoverArt {
+ compressed_image_data: data,
+ });
+ }
+
+ let url = format!(
+ "https://shared.steamstatic.com/store_item_assets/steam/apps/{}/library_600x900.jpg",
+ app_id
+ );
+
+ match http_client::get(&executor, &url).await {
+ Ok(response) => {
+ log::info!("Success");
+ cache_dir::set_data(&cache_file_path, &response.data).await?;
+ Ok(CoverArt {
+ compressed_image_data: response.data,
+ })
+ }
+ Err(e) => {
+ // fetch failed, write an empty file
+ log::error!("CoverArtFetcher: failed fetch for AppID {}: {}", app_id, e);
+ cache_dir::set_data(&cache_file_path, &[]).await?;
+ Ok(CoverArt {
+ compressed_image_data: Vec::new(),
+ })
+ }
+ }
+}
+
+#[derive(Deserialize, Clone)]
+pub struct AppDetailsJSONData {
+ #[allow(dead_code)]
+ pub r#type: String, // "game"
+ #[allow(dead_code)]
+ pub name: String, // "Half-Life 3"
+ #[allow(dead_code)]
+ pub is_free: Option, // "false"
+ pub detailed_description: Option, //
+ pub short_description: Option, //
+ pub developers: Vec, // ["Valve"]
+}
+
+async fn get_app_details_json_internal(
+ executor: AsyncExecutor,
+ cache_file_path: &str,
+ app_id: AppID,
+) -> anyhow::Result {
+ // check if file already exists in cache directory
+ if let Some(data) = cache_dir::get_data(cache_file_path).await {
+ return Ok(serde_json::from_value(serde_json::from_slice(&data)?)?);
+ }
+
+ // Fetch from Steam API
+ log::info!("Fetching app detail ID {}", app_id);
+ let url = format!("https://store.steampowered.com/api/appdetails?appids={}", app_id);
+ let response = http_client::get(&executor, &url).await?;
+ let res_utf8 = String::from_utf8(response.data)?;
+ let root = serde_json::from_str::(&res_utf8)?;
+ let body = root.get(&app_id).context("invalid body")?;
+
+ if !body.get("success").is_some_and(|v| v.as_bool().unwrap_or(false)) {
+ anyhow::bail!("Failed");
+ }
+
+ let data = body.get("data").context("data null")?;
+
+ let data_bytes = serde_json::to_vec(&data)?;
+ let app_details: AppDetailsJSONData = serde_json::from_value(data.clone())?;
+
+ // cache for future use
+ cache_dir::set_data(cache_file_path, &data_bytes).await?;
+
+ Ok(app_details)
+}
+
+pub async fn get_app_details_json(executor: AsyncExecutor, app_id: AppID) -> Option {
+ let cache_file_path = format!("app_details/{}.json", app_id);
+
+ match get_app_details_json_internal(executor, &cache_file_path, app_id).await {
+ Ok(r) => Some(r),
+ Err(e) => {
+ log::error!("Failed to get app details: {:?}", e);
+ let _ = cache_dir::set_data(&cache_file_path, &[]).await; // write empty data
+ None
+ }
+ }
+}
diff --git a/dash-frontend/src/util/cover_art_fetcher.rs b/dash-frontend/src/util/cover_art_fetcher.rs
deleted file mode 100644
index 734604f..0000000
--- a/dash-frontend/src/util/cover_art_fetcher.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-use wlx_common::cache_dir;
-
-use crate::util::{http_client, steam_utils::AppID, various::AsyncExecutor};
-
-pub struct CoverArt {
- // can be empty in case if data couldn't be fetched (use a fallback image then)
- pub compressed_image_data: Vec,
-}
-
-pub async fn request_image(executor: AsyncExecutor, app_id: AppID) -> anyhow::Result {
- let cache_file_path = format!("cover_arts/{}.bin", app_id);
-
- // check if file already exists in cache directory
- if let Some(data) = cache_dir::get_data(&cache_file_path).await {
- return Ok(CoverArt {
- compressed_image_data: data,
- });
- }
-
- let url = format!(
- "https://shared.steamstatic.com/store_item_assets/steam/apps/{}/library_600x900.jpg",
- app_id
- );
-
- match http_client::get(&executor, &url).await {
- Ok(response) => {
- log::info!("Success");
- cache_dir::set_data(&cache_file_path, &response.data).await?;
- Ok(CoverArt {
- compressed_image_data: response.data,
- })
- }
- Err(e) => {
- // fetch failed, write an empty file
- log::error!("CoverArtFetcher: failed fetch for AppID {}: {}", app_id, e);
- cache_dir::set_data(&cache_file_path, &[]).await?;
- Ok(CoverArt {
- compressed_image_data: Vec::new(),
- })
- }
- }
-}
diff --git a/dash-frontend/src/util/mod.rs b/dash-frontend/src/util/mod.rs
index 3577d01..4314dbe 100644
--- a/dash-frontend/src/util/mod.rs
+++ b/dash-frontend/src/util/mod.rs
@@ -1,4 +1,4 @@
-pub mod cover_art_fetcher;
+pub mod cached_fetcher;
pub mod desktop_finder;
pub mod http_client;
pub mod pactl_wrapper;
diff --git a/dash-frontend/src/views/game_launcher.rs b/dash-frontend/src/views/game_launcher.rs
new file mode 100644
index 0000000..dcfc322
--- /dev/null
+++ b/dash-frontend/src/views/game_launcher.rs
@@ -0,0 +1,158 @@
+use crate::{
+ frontend::{FrontendTask, FrontendTasks},
+ util::{
+ cached_fetcher::{self},
+ steam_utils::{AppID, AppManifest},
+ various::AsyncExecutor,
+ },
+};
+use wgui::{
+ assets::AssetPath,
+ components::button::ComponentButton,
+ globals::WguiGlobals,
+ i18n::Translation,
+ layout::{Layout, WidgetID},
+ parser::{Fetchable, ParseDocumentParams, ParserState},
+ task::Tasks,
+ widget::label::WidgetLabel,
+};
+
+#[derive(Clone)]
+enum Task {
+ FillAppDetails(cached_fetcher::AppDetailsJSONData),
+ Launch,
+}
+
+pub struct Params<'a> {
+ pub globals: &'a WguiGlobals,
+ pub executor: AsyncExecutor,
+ pub manifest: AppManifest,
+ pub layout: &'a mut Layout,
+ pub parent_id: WidgetID,
+ pub frontend_tasks: &'a FrontendTasks,
+ pub on_launched: Box,
+}
+pub struct View {
+ #[allow(dead_code)]
+ state: ParserState,
+ tasks: Tasks,
+ on_launched: Box,
+ frontend_tasks: FrontendTasks,
+
+ #[allow(dead_code)]
+ id_cover_art_parent: WidgetID,
+ #[allow(dead_code)]
+ executor: AsyncExecutor,
+ #[allow(dead_code)]
+ globals: WguiGlobals,
+ #[allow(dead_code)]
+ manifest: AppManifest,
+}
+
+impl View {
+ async fn fetch_details(executor: AsyncExecutor, tasks: Tasks, app_id: AppID) {
+ let Some(details) = cached_fetcher::get_app_details_json(executor, app_id).await else {
+ return;
+ };
+
+ tasks.push(Task::FillAppDetails(details));
+ }
+
+ pub fn new(params: Params) -> anyhow::Result {
+ let doc_params = &ParseDocumentParams {
+ globals: params.globals.clone(),
+ path: AssetPath::BuiltIn("gui/view/game_launcher.xml"),
+ extra: Default::default(),
+ };
+
+ let state = wgui::parser::parse_from_assets(doc_params, params.layout, params.parent_id)?;
+
+ let mut label_title = state.fetch_widget_as::(¶ms.layout.state, "label_title")?;
+ label_title.set_text_simple(
+ &mut params.globals.get(),
+ Translation::from_raw_text(¶ms.manifest.name),
+ );
+
+ let tasks = Tasks::new();
+
+ // fetch details from the web
+ let fut = View::fetch_details(params.executor.clone(), tasks.clone(), params.manifest.app_id.clone());
+ params.executor.spawn(fut).detach();
+
+ let id_cover_art_parent = state.get_widget_id("cover_art_parent")?;
+ let btn_launch = state.fetch_component_as::("btn_launch")?;
+
+ tasks.handle_button(&btn_launch, Task::Launch);
+
+ Ok(Self {
+ state,
+ tasks,
+ on_launched: params.on_launched,
+ id_cover_art_parent,
+ frontend_tasks: params.frontend_tasks.clone(),
+ executor: params.executor.clone(),
+ globals: params.globals.clone(),
+ manifest: params.manifest,
+ })
+ }
+
+ pub fn update(&mut self, layout: &mut Layout) -> anyhow::Result<()> {
+ loop {
+ let tasks = self.tasks.drain();
+ if tasks.is_empty() {
+ break;
+ }
+ for task in tasks {
+ match task {
+ Task::FillAppDetails(details) => self.action_fill_app_details(layout, details)?,
+ Task::Launch => self.action_launch(),
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ fn action_fill_app_details(
+ &mut self,
+ layout: &mut Layout,
+ mut details: cached_fetcher::AppDetailsJSONData,
+ ) -> anyhow::Result<()> {
+ let mut c = layout.start_common();
+
+ {
+ let label_author = self.state.fetch_widget(&c.layout.state, "label_author")?.widget;
+ let label_description = self.state.fetch_widget(&c.layout.state, "label_description")?.widget;
+
+ if let Some(developer) = details.developers.pop() {
+ label_author
+ .cast::()?
+ .set_text(&mut c.common(), Translation::from_raw_text_string(developer));
+ }
+
+ let desc = if let Some(desc) = &details.short_description {
+ Some(desc)
+ } else if let Some(desc) = &details.detailed_description {
+ Some(desc)
+ } else {
+ None
+ };
+
+ if let Some(desc) = desc {
+ label_description
+ .cast::()?
+ .set_text(&mut c.common(), Translation::from_raw_text(desc));
+ }
+ }
+
+ c.finish()?;
+ Ok(())
+ }
+
+ fn action_launch(&mut self) {
+ self
+ .frontend_tasks
+ .push(FrontendTask::PushToast(Translation::from_raw_text("Game launch TODO")));
+ (*self.on_launched)();
+ }
+}
diff --git a/dash-frontend/src/views/game_list.rs b/dash-frontend/src/views/game_list.rs
index 2ddbfad..fa2fc45 100644
--- a/dash-frontend/src/views/game_list.rs
+++ b/dash-frontend/src/views/game_list.rs
@@ -1,4 +1,4 @@
-use std::{collections::HashMap, rc::Rc};
+use std::{cell::RefCell, collections::HashMap, rc::Rc};
use wgui::{
assets::AssetPath,
@@ -34,43 +34,51 @@ use wgui::{
use crate::{
frontend::{FrontendTask, FrontendTasks},
util::{
- cover_art_fetcher::{self, CoverArt},
- popup_manager::MountPopupParams,
+ cached_fetcher::{self, CoverArt},
+ popup_manager::{MountPopupParams, PopupHandle},
steam_utils::{self, AppID, AppManifest, SteamUtils},
various::AsyncExecutor,
},
+ views::{self, game_launcher},
};
#[derive(Clone)]
enum Task {
AppManifestClicked(steam_utils::AppManifest),
SetCoverArt((AppID, Rc)),
+ CloseLauncher,
Refresh,
}
pub struct Params<'a> {
pub globals: WguiGlobals,
+ pub executor: AsyncExecutor,
pub frontend_tasks: FrontendTasks,
pub layout: &'a mut Layout,
pub parent_id: WidgetID,
}
-struct Cell {
+pub struct Cell {
image_parent: WidgetID,
manifest: AppManifest,
}
+struct State {
+ view_launcher: Option<(PopupHandle, views::game_launcher::View)>,
+}
+
pub struct View {
#[allow(dead_code)]
- pub parser_state: ParserState,
+ parser_state: ParserState,
tasks: Tasks,
frontend_tasks: FrontendTasks,
globals: WguiGlobals,
id_list_parent: WidgetID,
steam_utils: steam_utils::SteamUtils,
-
cells: HashMap,
img_placeholder: Option,
+ executor: AsyncExecutor,
+ state: Rc>,
}
impl View {
@@ -99,6 +107,8 @@ impl View {
steam_utils,
cells: HashMap::new(),
img_placeholder: None,
+ state: Rc::new(RefCell::new(State { view_launcher: None })),
+ executor: params.executor,
})
}
@@ -113,10 +123,16 @@ impl View {
Task::Refresh => self.refresh(layout, executor)?,
Task::AppManifestClicked(manifest) => self.action_app_manifest_clicked(manifest)?,
Task::SetCoverArt((app_id, cover_art)) => self.action_set_cover_art(layout, &app_id, cover_art)?,
+ Task::CloseLauncher => self.state.borrow_mut().view_launcher = None,
}
}
}
+ let mut state = self.state.borrow_mut();
+ if let Some((_, view)) = &mut state.view_launcher {
+ view.update(layout)?;
+ }
+
Ok(())
}
}
@@ -131,8 +147,12 @@ const BORDER_COLOR_HOVERED: drawing::Color = drawing::Color::new(1.0, 1.0, 1.0,
const GAME_COVER_SIZE_X: f32 = 140.0;
const GAME_COVER_SIZE_Y: f32 = 210.0;
-async fn request_cover_image(executor: AsyncExecutor, manifest: steam_utils::AppManifest, tasks: Tasks) {
- let cover_art = match cover_art_fetcher::request_image(executor, manifest.app_id.clone()).await {
+async fn request_cover_image(
+ executor: AsyncExecutor,
+ manifest: steam_utils::AppManifest,
+ on_loaded: Box,
+) {
+ let cover_art = match cached_fetcher::request_image(executor, manifest.app_id.clone()).await {
Ok(cover_art) => cover_art,
Err(e) => {
log::error!("request_cover_image failed: {:?}", e);
@@ -140,15 +160,15 @@ async fn request_cover_image(executor: AsyncExecutor, manifest: steam_utils::App
}
};
- tasks.push(Task::SetCoverArt((manifest.app_id, Rc::from(cover_art))));
+ on_loaded(cover_art)
}
-fn construct_game_cover(
+pub fn construct_game_cover(
ess: &mut ConstructEssentials,
executor: &AsyncExecutor,
- tasks: &Tasks,
_globals: &WguiGlobals,
manifest: &steam_utils::AppManifest,
+ on_loaded: Box,
) -> anyhow::Result<(WidgetPair, Rc, Cell)> {
let (widget_button, button) = components::button::construct(
ess,
@@ -257,7 +277,7 @@ fn construct_game_cover(
// request cover image data from the internet or disk cache
executor
- .spawn(request_cover_image(executor.clone(), manifest.clone(), tasks.clone()))
+ .spawn(request_cover_image(executor.clone(), manifest.clone(), on_loaded))
.detach();
Ok((
@@ -279,7 +299,15 @@ fn fill_game_list(
tasks: &Tasks,
) -> anyhow::Result<()> {
for manifest in &games.manifests {
- let (_, button, cell) = construct_game_cover(ess, executor, tasks, globals, manifest)?;
+ let on_loaded = {
+ let app_id = manifest.app_id.clone();
+ let tasks = tasks.clone();
+ move |cover_art: CoverArt| {
+ tasks.push(Task::SetCoverArt((app_id, Rc::from(cover_art))));
+ }
+ };
+
+ let (_, button, cell) = construct_game_cover(ess, executor, globals, manifest, Box::new(on_loaded))?;
button.on_click({
let tasks = tasks.clone();
@@ -352,8 +380,29 @@ impl View {
self.frontend_tasks.push(FrontendTask::MountPopup(MountPopupParams {
title: Translation::from_raw_text(&manifest.name),
on_content: {
- Rc::new(move |_data| {
- // todo
+ let state = self.state.clone();
+ let tasks = self.tasks.clone();
+ let executor = self.executor.clone();
+ let globals = self.globals.clone();
+ let frontend_tasks = self.frontend_tasks.clone();
+
+ Rc::new(move |data| {
+ let on_launched = {
+ let tasks = tasks.clone();
+ Box::new(move || tasks.push(Task::CloseLauncher))
+ };
+
+ let view = game_launcher::View::new(game_launcher::Params {
+ manifest: manifest.clone(),
+ executor: executor.clone(),
+ globals: &globals,
+ layout: data.layout,
+ parent_id: data.id_content,
+ frontend_tasks: &frontend_tasks,
+ on_launched,
+ })?;
+
+ state.borrow_mut().view_launcher = Some((data.handle, view));
Ok(())
})
},
diff --git a/dash-frontend/src/views/mod.rs b/dash-frontend/src/views/mod.rs
index 87c536a..c853011 100644
--- a/dash-frontend/src/views/mod.rs
+++ b/dash-frontend/src/views/mod.rs
@@ -1,5 +1,6 @@
pub mod app_launcher;
pub mod audio_settings;
+pub mod game_launcher;
pub mod game_list;
pub mod process_list;
pub mod window_list;
diff --git a/uidev/src/testbed/testbed_generic.rs b/uidev/src/testbed/testbed_generic.rs
index 98d13ba..b0f7116 100644
--- a/uidev/src/testbed/testbed_generic.rs
+++ b/uidev/src/testbed/testbed_generic.rs
@@ -51,7 +51,7 @@ fn button_click_callback(
) -> ButtonClickCallback {
Box::new(move |common, _e| {
label
- .get_as_mut::()
+ .get_as::()
.unwrap()
.set_text(common, Translation::from_raw_text(text));
@@ -161,7 +161,7 @@ impl TestbedGeneric {
let cb_first = state.fetch_component_as::("cb_first")?;
let label = label_cur_option.widget.clone();
cb_first.on_toggle(Box::new(move |common, e| {
- let mut widget = label.get_as_mut::().unwrap();
+ let mut widget = label.get_as::().unwrap();
let text = format!("checkbox toggle: {}", e.checked);
widget.set_text(common, Translation::from_raw_text(&text));
Ok(())
diff --git a/wgui/src/components/button.rs b/wgui/src/components/button.rs
index 78eeeae..cb1f924 100644
--- a/wgui/src/components/button.rs
+++ b/wgui/src/components/button.rs
@@ -340,6 +340,7 @@ fn register_event_mouse_press(state: Rc>, listeners: &mut EventLi
if state.hovered {
state.down = true;
state.last_pressed = Instant::now();
+ state.active_tooltip = None;
Ok(EventResult::Consumed)
} else {
Ok(EventResult::Pass)
diff --git a/wgui/src/layout.rs b/wgui/src/layout.rs
index 2fbf5af..1fe1dd5 100644
--- a/wgui/src/layout.rs
+++ b/wgui/src/layout.rs
@@ -14,6 +14,7 @@ use crate::{
widget::{self, EventParams, EventResult, WidgetObj, WidgetState, WidgetStateFlags, div::WidgetDiv},
};
+use anyhow::Context;
use glam::{Vec2, vec2};
use slotmap::{HopSlotMap, SecondaryMap, new_key_type};
use taffy::{NodeId, TaffyTree, TraversePartialTree};
@@ -31,10 +32,14 @@ impl Widget {
Self(Rc::new(RefCell::new(widget_state)))
}
- pub fn get_as_mut(&self) -> Option> {
+ pub fn get_as(&self) -> Option> {
RefMut::filter_map(self.0.borrow_mut(), |w| w.obj.get_as_mut::()).ok()
}
+ pub fn cast(&self) -> anyhow::Result> {
+ self.get_as().context("Widget cast failed")
+ }
+
pub fn downgrade(&self) -> WeakWidget {
WeakWidget(Rc::downgrade(&self.0))
}
@@ -65,7 +70,7 @@ impl WidgetMap {
}
pub fn get_as(&self, handle: WidgetID) -> Option> {
- self.0.get(handle)?.get_as_mut::()
+ self.0.get(handle)?.get_as::()
}
pub fn get(&self, handle: WidgetID) -> Option<&Widget> {
@@ -97,7 +102,7 @@ impl WidgetMap {
return;
};
- if let Some(mut casted) = widget.get_as_mut::() {
+ if let Some(mut casted) = widget.get_as::() {
func(&mut casted);
}
}
diff --git a/wgui/src/parser/mod.rs b/wgui/src/parser/mod.rs
index 77684ba..0c5a501 100644
--- a/wgui/src/parser/mod.rs
+++ b/wgui/src/parser/mod.rs
@@ -9,7 +9,7 @@ mod widget_rectangle;
mod widget_sprite;
use crate::{
- assets::{normalize_path, AssetPath, AssetPathOwned},
+ assets::{AssetPath, AssetPathOwned, normalize_path},
components::{Component, ComponentWeak},
drawing::{self},
globals::WguiGlobals,
@@ -183,7 +183,7 @@ impl Fetchable for ParserData {
.ok_or_else(|| anyhow::anyhow!("fetch_widget_as({id}): widget not found"))?;
let casted = widget
- .get_as_mut::()
+ .get_as::()
.ok_or_else(|| anyhow::anyhow!("fetch_widget_as({id}): failed to cast"))?;
Ok(casted)
@@ -1002,7 +1002,7 @@ impl CustomAttribsInfo<'_> {
}
pub fn get_widget_as(&self) -> Option> {
- self.widgets.get(self.widget_id)?.get_as_mut::()
+ self.widgets.get(self.widget_id)?.get_as::()
}
pub fn get_value(&self, attrib_name: &str) -> Option> {
diff --git a/wlx-overlay-s/src/overlays/custom.rs b/wlx-overlay-s/src/overlays/custom.rs
index ae8290b..7b464d0 100644
--- a/wlx-overlay-s/src/overlays/custom.rs
+++ b/wlx-overlay-s/src/overlays/custom.rs
@@ -105,7 +105,7 @@ fn apply_custom_command(
label.set_text(&mut com, Translation::from_raw_text(text));
} else if let Ok(button) = panel
.parser_state
- .fetch_component_as::(&element)
+ .fetch_component_as::(element)
{
button.set_text(&mut com, Translation::from_raw_text(text));
} else {
@@ -118,15 +118,15 @@ fn apply_custom_command(
.fetch_widget(&panel.layout.state, element)
{
let content = CustomGlyphContent::from_assets(
- &mut app.wgui_globals,
- wgui::assets::AssetPath::File(&path),
+ &app.wgui_globals,
+ wgui::assets::AssetPath::File(path),
)
.context("Could not load content from supplied path.")?;
let data = CustomGlyphData::new(content);
- if let Some(mut sprite) = pair.widget.get_as_mut::() {
+ if let Some(mut sprite) = pair.widget.get_as::() {
sprite.set_content(&mut com, Some(data));
- } else if let Some(mut image) = pair.widget.get_as_mut::() {
+ } else if let Some(mut image) = pair.widget.get_as::() {
image.set_content(&mut com, Some(data));
} else {
anyhow::bail!("No or with such id.");
@@ -136,18 +136,18 @@ fn apply_custom_command(
}
}
ModifyPanelCommand::SetColor(color) => {
- let color = parse_color_hex(&color)
+ let color = parse_color_hex(color)
.context("Invalid color format, must be a html hex color!")?;
if let Ok(pair) = panel
.parser_state
.fetch_widget(&panel.layout.state, element)
{
- if let Some(mut rect) = pair.widget.get_as_mut::() {
+ if let Some(mut rect) = pair.widget.get_as::() {
rect.set_color(&mut com, color);
- } else if let Some(mut label) = pair.widget.get_as_mut::() {
+ } else if let Some(mut label) = pair.widget.get_as::() {
label.set_color(&mut com, color, true);
- } else if let Some(mut sprite) = pair.widget.get_as_mut::() {
+ } else if let Some(mut sprite) = pair.widget.get_as::() {
sprite.set_color(&mut com, color);
} else {
anyhow::bail!("No or