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>
<!-- BOTTOM PANEL -->
<rectangle
consume_mouse_events="1"
width="100%"
height="48"
min_height="48"

View File

@@ -1,22 +1,33 @@
<layout>
<include src="t_tab_title.xml" />
<include src="../theme.xml" />
<template name="AppEntry">
<Button
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>
<sprite src="${src}" src_ext="${src_ext}" width="64" height="64" />
</div>
<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>
</Button>
</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>
<TabTitle translation="APPLICATIONS" icon="dashboard/apps.svg" />
<!-- placeholders for now -->
<!--
<div gap="4" align_items="center">
<Button width="48" height="38">
<sprite src_builtin="dashboard/alphabetical.svg" width="24" height="24" />
@@ -25,18 +36,17 @@
<sprite src_builtin="dashboard/category_search.svg" width="24" height="24" />
</Button>
<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">
<label text="Search" color="#FFFFFF88" weight="bold" />
</rectangle>
</div>
-->
<div
id="app_list_parent"
flex_direction="row"
flex_wrap="wrap"
justify_content="center"
gap="4"
overflow_y="scroll"
/>
</elements>
</layout>
</layout>

View File

@@ -7,7 +7,7 @@
</template>
<template name="ApplicationIcon">
<sprite src_ext="${path}" width="128" height="128" />
<sprite src_ext="${path}" width="96" height="96" />
</template>
<include src="../t_separator.xml" />
@@ -15,7 +15,7 @@
<elements>
<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>
<div flex_direction="column" gap="8">
@@ -25,7 +25,7 @@
<Separator />
<RadioGroup id="radio_compositor" flex_direction="row" gap="16">
<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>
<Separator />
<label text="Resolution" />
@@ -51,4 +51,4 @@
</div>
</div>
</elements>
</layout>
</layout>

View File

@@ -70,6 +70,7 @@ struct AppList {
//data: Vec<ParserData>,
entries_to_mount: VecDeque<DesktopEntry>,
list_parent: WidgetPair,
prev_first_letter: char,
}
// called after the user clicks any desktop entry
@@ -130,12 +131,21 @@ impl<T> TabApps<T> {
let tasks = Tasks::new();
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 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 {
entries_to_mount: entries.into_values().collect(),
entries_to_mount: entries_sorted.drain(..).collect(),
list_parent: app_list_parent,
prev_first_letter: ' ',
};
Ok(Self {
@@ -156,37 +166,55 @@ impl AppList {
doc_params: &ParseDocumentParams,
entry: &DesktopEntry,
) -> 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
template_params.insert(
Rc::from("src_ext"),
entry
.icon_path
.as_ref()
.map_or_else(|| Rc::from(""), |icon_path| icon_path.clone()),
);
parser_state.parse_template(
doc_params,
"CategoryText",
&mut frontend.layout,
self.list_parent.id,
params,
)?;
}
// entry fallback (question mark) icon
template_params.insert(
Rc::from("src"),
if entry.icon_path.is_none() {
Rc::from("dashboard/terminal.svg")
} else {
Rc::from("")
},
);
{
let mut params = HashMap::new();
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(
doc_params,
"AppEntry",
&mut frontend.layout,
self.list_parent.id,
template_params,
)?;
data.fetch_component_as::<ComponentButton>("button")
// entry fallback (question mark) icon
params.insert(
"src".into(),
if entry.icon_path.is_none() {
"dashboard/terminal.svg".into()
} else {
"".into()
},
);
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>(

View File

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