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

View File

@ -26,6 +26,7 @@
#include <model/runtime_config.h>
#include <model/download_queue.h>
#include <model/nic_state.h>
#include <model/index_menu.h>
#include <view/dialog.h>
#include <view/activatable_item.h>
#include <depot_query.h>
@ -158,47 +159,7 @@ struct Sculpt::Popup_dialog : Dialog
fn(route); }); });
}
struct 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 { };
Index_menu _menu { };
Hover_result hover(Xml_node hover) override
{
@ -233,7 +194,7 @@ struct Sculpt::Popup_dialog : Dialog
void _handle_index()
{
/* prevent modifications of index while browing it */
/* prevent modifications of index while browsing it */
if (_state >= INDEX_SHOWN)
return;
@ -343,22 +304,7 @@ struct Sculpt::Popup_dialog : Dialog
template <typename FN>
void _for_each_menu_item(FN const &fn) const
{
Xml_node index = _index_rom.xml();
/*
* 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;
});
_menu.for_each_item(_index_rom.xml(), _selected_user, fn);
}
static void _gen_info_label(Xml_generator &xml, char const *name,