dash-frontend: application list grouping

This commit is contained in:
Aleksander
2026-01-06 16:23:01 +01:00
parent addcc7eed6
commit 46ab3ce960
5 changed files with 78 additions and 39 deletions

View File

@@ -99,6 +99,7 @@
</rectangle> </rectangle>
<!-- BOTTOM PANEL --> <!-- BOTTOM PANEL -->
<rectangle <rectangle
consume_mouse_events="1"
width="100%" width="100%"
height="48" height="48"
min_height="48" min_height="48"

View File

@@ -1,22 +1,33 @@
<layout> <layout>
<include src="t_tab_title.xml" /> <include src="t_tab_title.xml" />
<include src="../theme.xml" />
<template name="AppEntry"> <template name="AppEntry">
<Button <Button
id="button" width="116" max_width="140" min_height="100" flex_grow="1" id="button" width="116" max_width="140" min_height="100" flex_grow="1"
flex_direction="column" overflow="visible" align_items="center" justify_content="center" gap="4"> flex_direction="column" overflow="visible" align_items="center" justify_content="center" gap="4"
color="#3385FF10"
>
<div> <div>
<sprite src="${src}" src_ext="${src_ext}" width="64" height="64" /> <sprite src="${src}" src_ext="${src_ext}" width="64" height="64" />
</div> </div>
<div align_items="center" justify_content="center"> <div align_items="center" justify_content="center">
<label width="116" weight="bold" text="${name}" size="12" wrap="1" align="center" padding_left="16" padding_right="16"/> <label width="116" weight="bold" text="${name}" size="12" wrap="1" align="center" padding_left="16" padding_right="16" />
</div> </div>
</Button> </Button>
</template> </template>
<template name="CategoryText">
<rectangle width="100%" flex_direction="column" round="8" border="2" gradient="vertical" color2="#4477FF09" color="#5588FF10" border_color="#FFFFFF00">
<label margin="8" text="${text}" weight="bold" size="22" />
<rectangle height="2" color="~color_accent" margin_left="4" margin_right="4" />
</rectangle>
</template>
<elements> <elements>
<TabTitle translation="APPLICATIONS" icon="dashboard/apps.svg" /> <TabTitle translation="APPLICATIONS" icon="dashboard/apps.svg" />
<!-- placeholders for now --> <!-- placeholders for now -->
<!--
<div gap="4" align_items="center"> <div gap="4" align_items="center">
<Button width="48" height="38"> <Button width="48" height="38">
<sprite src_builtin="dashboard/alphabetical.svg" width="24" height="24" /> <sprite src_builtin="dashboard/alphabetical.svg" width="24" height="24" />
@@ -25,16 +36,15 @@
<sprite src_builtin="dashboard/category_search.svg" width="24" height="24" /> <sprite src_builtin="dashboard/category_search.svg" width="24" height="24" />
</Button> </Button>
<sprite src_builtin="dashboard/search.svg" width="24" height="24" /> <sprite src_builtin="dashboard/search.svg" width="24" height="24" />
<!-- placeholder editbox -->
<rectangle flex_grow="1" height="100%" color="#1d2e51" border_color="#294774" border="2" round="4" align_items="center" padding_left="12"> <rectangle flex_grow="1" height="100%" color="#1d2e51" border_color="#294774" border="2" round="4" align_items="center" padding_left="12">
<label text="Search" color="#FFFFFF88" weight="bold" /> <label text="Search" color="#FFFFFF88" weight="bold" />
</rectangle> </rectangle>
</div> </div>
-->
<div <div
id="app_list_parent" id="app_list_parent"
flex_direction="row" flex_direction="row"
flex_wrap="wrap" flex_wrap="wrap"
justify_content="center"
gap="4" gap="4"
overflow_y="scroll" overflow_y="scroll"
/> />

View File

@@ -7,7 +7,7 @@
</template> </template>
<template name="ApplicationIcon"> <template name="ApplicationIcon">
<sprite src_ext="${path}" width="128" height="128" /> <sprite src_ext="${path}" width="96" height="96" />
</template> </template>
<include src="../t_separator.xml" /> <include src="../t_separator.xml" />
@@ -15,7 +15,7 @@
<elements> <elements>
<div flex_direction="row" gap="16"> <div flex_direction="row" gap="16">
<rectangle macro="group_box" id="icon_parent" padding="8" color="#0033aa66" color2="#00000022" gradient="vertical" justify_content="center"> <rectangle macro="group_box" id="icon_parent" padding="16" color="#0033aa66" color2="#00000022" gradient="vertical" justify_content="center">
</rectangle> </rectangle>
<div flex_direction="column" gap="8"> <div flex_direction="column" gap="8">
@@ -25,7 +25,7 @@
<Separator /> <Separator />
<RadioGroup id="radio_compositor" flex_direction="row" gap="16"> <RadioGroup id="radio_compositor" flex_direction="row" gap="16">
<RadioBox text="Native mode" value="Native" checked="1" /> <RadioBox text="Native mode" value="Native" checked="1" />
<RadioBox text="Compatibility mode" value="Cage"/> <!-- TODO: tooltips --> <RadioBox text="Compatibility mode" value="Cage" /> <!-- TODO: tooltips -->
</RadioGroup> </RadioGroup>
<Separator /> <Separator />
<label text="Resolution" /> <label text="Resolution" />

View File

@@ -70,6 +70,7 @@ struct AppList {
//data: Vec<ParserData>, //data: Vec<ParserData>,
entries_to_mount: VecDeque<DesktopEntry>, entries_to_mount: VecDeque<DesktopEntry>,
list_parent: WidgetPair, list_parent: WidgetPair,
prev_first_letter: char,
} }
// called after the user clicks any desktop entry // called after the user clicks any desktop entry
@@ -130,12 +131,21 @@ impl<T> TabApps<T> {
let tasks = Tasks::new(); let tasks = Tasks::new();
let state = Rc::new(RefCell::new(State { view_launcher: None })); let state = Rc::new(RefCell::new(State { view_launcher: None }));
let mut entries = frontend.interface.desktop_finder(data).find_entries();
let parser_state = wgui::parser::parse_from_assets(&doc_params(globals.clone()), &mut frontend.layout, parent_id)?; let parser_state = wgui::parser::parse_from_assets(&doc_params(globals.clone()), &mut frontend.layout, parent_id)?;
let app_list_parent = parser_state.fetch_widget(&frontend.layout.state, "app_list_parent")?; let app_list_parent = parser_state.fetch_widget(&frontend.layout.state, "app_list_parent")?;
let mut entries_sorted: Vec<_> = frontend
.interface
.desktop_finder(data)
.find_entries()
.into_values()
.collect();
entries_sorted.sort_by(|a, b| a.app_name.cmp(&b.app_name));
let app_list = AppList { let app_list = AppList {
entries_to_mount: entries.into_values().collect(), entries_to_mount: entries_sorted.drain(..).collect(),
list_parent: app_list_parent, list_parent: app_list_parent,
prev_first_letter: ' ',
}; };
Ok(Self { Ok(Self {
@@ -156,37 +166,55 @@ impl AppList {
doc_params: &ParseDocumentParams, doc_params: &ParseDocumentParams,
entry: &DesktopEntry, entry: &DesktopEntry,
) -> anyhow::Result<Rc<ComponentButton>> { ) -> anyhow::Result<Rc<ComponentButton>> {
let mut template_params = HashMap::new(); if let Some(ch) = entry.app_name.chars().next()
&& self.prev_first_letter != ch
{
self.prev_first_letter = ch;
let mut params = HashMap::<Rc<str>, Rc<str>>::new();
params.insert("text".into(), format!("{}", ch).into());
// entry icon parser_state.parse_template(
template_params.insert( doc_params,
Rc::from("src_ext"), "CategoryText",
entry &mut frontend.layout,
.icon_path self.list_parent.id,
.as_ref() params,
.map_or_else(|| Rc::from(""), |icon_path| icon_path.clone()), )?;
); }
// entry fallback (question mark) icon {
template_params.insert( let mut params = HashMap::new();
Rc::from("src"),
if entry.icon_path.is_none() {
Rc::from("dashboard/terminal.svg")
} else {
Rc::from("")
},
);
template_params.insert(Rc::from("name"), entry.app_name.clone()); // entry icon
params.insert(
"src_ext".into(),
entry
.icon_path
.as_ref()
.map_or_else(|| "".into(), |icon_path| icon_path.clone()),
);
let data = parser_state.parse_template( // entry fallback (question mark) icon
doc_params, params.insert(
"AppEntry", "src".into(),
&mut frontend.layout, if entry.icon_path.is_none() {
self.list_parent.id, "dashboard/terminal.svg".into()
template_params, } else {
)?; "".into()
data.fetch_component_as::<ComponentButton>("button") },
);
params.insert("name".into(), entry.app_name.clone());
let data = parser_state.parse_template(
doc_params,
"AppEntry",
&mut frontend.layout,
self.list_parent.id,
params,
)?;
data.fetch_component_as::<ComponentButton>("button")
}
} }
fn tick<T>( fn tick<T>(

View File

@@ -79,7 +79,7 @@ fn handle_button_click(button: Rc<ComponentButton>, label: Widget, text: &'stati
} }
impl TestbedGeneric { impl TestbedGeneric {
fn doc_params(globals: &WguiGlobals, extra: ParseDocumentExtra) -> ParseDocumentParams { fn doc_params(globals: &'_ WguiGlobals, extra: ParseDocumentExtra) -> ParseDocumentParams<'_> {
ParseDocumentParams { ParseDocumentParams {
globals: globals.clone(), globals: globals.clone(),
path: AssetPath::BuiltIn("gui/various_widgets.xml"), path: AssetPath::BuiltIn("gui/various_widgets.xml"),