sculpt: make Popup_view::Menu reusable

This commit is contained in:
Norman Feske 2023-03-21 16:54:55 +01:00 committed by Christian Helmuth
parent 9be7ce54c2
commit b91e5353ba
3 changed files with 95 additions and 67 deletions

View File

@ -0,0 +1,82 @@
/*
* \brief State needed for traversing an index menu
* \author Norman Feske
* \date 2023-03-21
*/
/*
* Copyright (C) 2023 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__INDEX_MENU_H_
#define _MODEL__INDEX_MENU_H_
/* Genode includes */
#include <depot/archive.h>
/* local includes */
#include <types.h>
namespace Sculpt { struct Index_menu; }
struct Sculpt::Index_menu
{
enum { MAX_LEVELS = 5 };
unsigned _level = 0;
using Name = String<64>;
using User = Depot::Archive::User;
Name _selected[MAX_LEVELS] { };
void print(Output &out) const
{
using Genode::print;
for (unsigned i = 0; i < _level; i++) {
print(out, _selected[i]);
if (i + 1 < _level)
print(out, " ");
}
}
template <typename FN>
void _for_each_item(Xml_node const &index, FN const &fn, unsigned level) const
{
if (level == _level) {
index.for_each_sub_node(fn);
return;
}
index.for_each_sub_node("index", [&] (Xml_node const &index) {
if (index.attribute_value("name", Name()) == _selected[level])
_for_each_item(index, fn, level + 1); });
}
template <typename FN>
void for_each_item(Xml_node const &index, User const &user, FN const &fn) const
{
/*
* The index may contain duplicates, evaluate only the first match.
*/
bool first = true;
index.for_each_sub_node("index", [&] (Xml_node const &index) {
if (index.attribute_value("user", User()) != user)
return;
if (first)
_for_each_item(index, fn, 0);
first = false;
});
}
unsigned level() const { return _level; }
};
#endif /* _MODEL__INDEX_MENU_H_ */

View File

@ -35,7 +35,7 @@ void Popup_dialog::_gen_pkg_elements(Xml_generator &xml,
{ {
typedef Component::Info Info; typedef Component::Info Info;
_gen_sub_menu_title(xml, "back", Menu::Name("Add ", Pretty(_construction_name))); _gen_sub_menu_title(xml, "back", Index_menu::Name("Add ", Pretty(_construction_name)));
_gen_pkg_info(xml, component); _gen_pkg_info(xml, component);
@ -186,9 +186,9 @@ void Popup_dialog::_gen_menu_elements(Xml_generator &xml, Xml_node const &depot_
* Title of index * Title of index
*/ */
if (_state >= INDEX_SHOWN && _state < PKG_SHOWN) { if (_state >= INDEX_SHOWN && _state < PKG_SHOWN) {
Menu::Name title("Depot ", _selected_user); Index_menu::Name title("Depot ", _selected_user);
if (_menu._level) if (_menu._level)
title = Menu::Name(title, " ", _menu, " "); title = Index_menu::Name(title, " ", _menu, " ");
_gen_sub_menu_title(xml, "back", title); _gen_sub_menu_title(xml, "back", title);
} }
@ -204,8 +204,8 @@ void Popup_dialog::_gen_menu_elements(Xml_generator &xml, Xml_node const &depot_
Hoverable_item::Id const id(cnt); Hoverable_item::Id const id(cnt);
if (item.has_type("index")) { if (item.has_type("index")) {
auto const name = item.attribute_value("name", Menu::Name()); auto const name = item.attribute_value("name", Index_menu::Name());
_gen_menu_entry(xml, id, Menu::Name(name, " ..."), false); _gen_menu_entry(xml, id, Index_menu::Name(name, " ..."), false);
} }
if (item.has_type("pkg")) { if (item.has_type("pkg")) {
@ -369,13 +369,13 @@ void Popup_dialog::click(Action &action)
/* go one menu up */ /* go one menu up */
if (clicked == "back") { if (clicked == "back") {
_menu._selected[_menu._level] = Menu::Name(); _menu._selected[_menu._level] = Index_menu::Name();
_menu._level--; _menu._level--;
action.discard_construction(); action.discard_construction();
} else { } else {
/* enter sub menu of index */ /* enter sub menu of index */
if (_menu._level < Menu::MAX_LEVELS - 1) { if (_menu._level < Index_menu::MAX_LEVELS - 1) {
unsigned cnt = 0; unsigned cnt = 0;
_for_each_menu_item([&] (Xml_node item) { _for_each_menu_item([&] (Xml_node item) {
@ -384,8 +384,8 @@ void Popup_dialog::click(Action &action)
if (item.has_type("index")) { if (item.has_type("index")) {
Menu::Name const name = Index_menu::Name const name =
item.attribute_value("name", Menu::Name()); item.attribute_value("name", Index_menu::Name());
_menu._selected[_menu._level] = name; _menu._selected[_menu._level] = name;
_menu._level++; _menu._level++;

View File

@ -26,6 +26,7 @@
#include <model/runtime_config.h> #include <model/runtime_config.h>
#include <model/download_queue.h> #include <model/download_queue.h>
#include <model/nic_state.h> #include <model/nic_state.h>
#include <model/index_menu.h>
#include <view/dialog.h> #include <view/dialog.h>
#include <view/activatable_item.h> #include <view/activatable_item.h>
#include <depot_query.h> #include <depot_query.h>
@ -158,47 +159,7 @@ struct Sculpt::Popup_dialog : Dialog
fn(route); }); }); fn(route); }); });
} }
struct Menu Index_menu _menu { };
{
enum { MAX_LEVELS = 5 };
unsigned _level = 0;
typedef String<64> Name;
Name _selected[MAX_LEVELS] { };
void print(Output &out) const
{
using Genode::print;
for (unsigned i = 0; i < _level; i++) {
print(out, _selected[i]);
if (i + 1 < _level)
print(out, " ");
}
}
template <typename FN>
void _for_each_item(Xml_node index, FN const &fn, unsigned level) const
{
if (level == _level) {
index.for_each_sub_node(fn);
return;
}
index.for_each_sub_node("index", [&] (Xml_node index) {
if (index.attribute_value("name", Name()) == _selected[level])
_for_each_item(index, fn, level + 1); });
}
template <typename FN>
void for_each_item(Xml_node index, FN const &fn) const
{
_for_each_item(index, fn, 0);
}
};
Menu _menu { };
Hover_result hover(Xml_node hover) override Hover_result hover(Xml_node hover) override
{ {
@ -233,7 +194,7 @@ struct Sculpt::Popup_dialog : Dialog
void _handle_index() void _handle_index()
{ {
/* prevent modifications of index while browing it */ /* prevent modifications of index while browsing it */
if (_state >= INDEX_SHOWN) if (_state >= INDEX_SHOWN)
return; return;
@ -343,22 +304,7 @@ struct Sculpt::Popup_dialog : Dialog
template <typename FN> template <typename FN>
void _for_each_menu_item(FN const &fn) const void _for_each_menu_item(FN const &fn) const
{ {
Xml_node index = _index_rom.xml(); _menu.for_each_item(_index_rom.xml(), _selected_user, fn);
/*
* The index may contain duplicates, evaluate only the first match.
*/
bool first = true;
index.for_each_sub_node("index", [&] (Xml_node index) {
if (index.attribute_value("user", User()) != _selected_user)
return;
if (first)
_menu.for_each_item(index, fn);
first = false;
});
} }
static void _gen_info_label(Xml_generator &xml, char const *name, static void _gen_info_label(Xml_generator &xml, char const *name,