diff --git a/repos/gems/recipes/pkg/sculpt/archives b/repos/gems/recipes/pkg/sculpt/archives
index 21c673f1d..cc7c81ee4 100644
--- a/repos/gems/recipes/pkg/sculpt/archives
+++ b/repos/gems/recipes/pkg/sculpt/archives
@@ -2,6 +2,7 @@ _/pkg/drivers_managed-pc
_/pkg/wifi
_/pkg/depot_download
_/pkg/terminal
+_/pkg/backdrop
_/src/report_rom
_/src/clipboard
_/src/init
@@ -48,3 +49,5 @@ _/src/gpt_write
_/src/sculpt_manager
_/src/fs_query
_/src/fs_tool
+_/src/text_area
+_/src/sandbox
diff --git a/repos/gems/run/leitzentrale.run b/repos/gems/run/leitzentrale.run
index 02b727f80..e9767bcd8 100644
--- a/repos/gems/run/leitzentrale.run
+++ b/repos/gems/run/leitzentrale.run
@@ -3,6 +3,7 @@ create_boot_directory
import_from_depot [depot_user]/src/[base_src] \
[depot_user]/pkg/[drivers_interactive_pkg] \
[depot_user]/pkg/fonts_fs \
+ [depot_user]/pkg/backdrop \
[depot_user]/src/dynamic_rom \
[depot_user]/src/report_rom \
[depot_user]/src/fs_rom \
@@ -19,6 +20,7 @@ import_from_depot [depot_user]/src/[base_src] \
[depot_user]/src/libpng \
[depot_user]/src/zlib \
[depot_user]/src/menu_view \
+ [depot_user]/src/fs_query \
[depot_user]/src/rom_filter \
[depot_user]/src/noux \
[depot_user]/src/terminal \
@@ -33,6 +35,8 @@ import_from_depot [depot_user]/src/[base_src] \
[depot_user]/src/coreutils-minimal \
[depot_user]/src/e2fsprogs-minimal \
[depot_user]/src/gpt_write \
+ [depot_user]/src/text_area \
+ [depot_user]/src/sandbox \
[depot_user]/src/window_layouter
install_config {
@@ -82,10 +86,7 @@ install_config {
report="nitpicker -> hover"/>
-
-
+
@@ -148,8 +149,9 @@ install_config {
-
See the core log for messages.
+
+
@@ -191,12 +193,13 @@ install_config {
+
-
+
@@ -219,10 +222,15 @@ install_config {
-
+
-
-
+
+
+
+
+
+
+
@@ -233,9 +241,7 @@ install_config {
-
-
-
+
@@ -253,8 +259,6 @@ install_config {
-
-
@@ -267,14 +271,20 @@ install_config {
-
-
-
-
+
+
+
+
+
+
+
+
+
+
@@ -282,6 +292,8 @@ install_config {
+
+
diff --git a/repos/gems/run/sculpt.run b/repos/gems/run/sculpt.run
index 546a63cc3..24789588e 100644
--- a/repos/gems/run/sculpt.run
+++ b/repos/gems/run/sculpt.run
@@ -75,10 +75,6 @@ install_config {
report="global_keys_handler -> slides"/>
-
-
@@ -397,11 +393,16 @@ install_config {
-
+
-
+
-
+
+
+
+
+
+
@@ -418,10 +419,6 @@ install_config {
-
-
-
-
@@ -452,8 +449,6 @@ install_config {
-
-
@@ -474,12 +469,20 @@ install_config {
+
+
+
+
-
-
+
+
+
+
+
+
diff --git a/repos/gems/run/sculpt/leitzentrale.config b/repos/gems/run/sculpt/leitzentrale.config
index d463d9b09..d0755d3c9 100644
--- a/repos/gems/run/sculpt/leitzentrale.config
+++ b/repos/gems/run/sculpt/leitzentrale.config
@@ -23,6 +23,14 @@
+
+
+
+
+
+
+
+
@@ -32,7 +40,7 @@
-
+
@@ -46,7 +54,7 @@
-
+
@@ -83,7 +91,7 @@
-
+
@@ -94,19 +102,42 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
@@ -123,9 +154,9 @@
-
+
-
+
@@ -140,10 +171,14 @@
-
-
-
-
+
+
+
+
+
+
+
+
@@ -192,13 +227,10 @@
-
-
-
-
+
@@ -217,19 +249,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -285,6 +304,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/repos/gems/run/sculpt/nitpicker.config b/repos/gems/run/sculpt/nitpicker.config
index fdb0dfe43..9d8c3ea80 100644
--- a/repos/gems/run/sculpt/nitpicker.config
+++ b/repos/gems/run/sculpt/nitpicker.config
@@ -1,6 +1,6 @@
-
+
diff --git a/repos/gems/src/app/sculpt_manager/deploy.h b/repos/gems/src/app/sculpt_manager/deploy.h
index c8805b29f..2c636abfa 100644
--- a/repos/gems/src/app/sculpt_manager/deploy.h
+++ b/repos/gems/src/app/sculpt_manager/deploy.h
@@ -39,6 +39,8 @@ struct Sculpt::Deploy
Allocator &_alloc;
+ Registry &_child_states;
+
Runtime_info const &_runtime_info;
Dialog::Generator &_dialog_generator;
@@ -56,10 +58,10 @@ struct Sculpt::Deploy
Arch _arch { };
Child_state cached_depot_rom_state {
- "depot_rom", Ram_quota{24*1024*1024}, Cap_quota{200} };
+ _child_states, "depot_rom", Ram_quota{24*1024*1024}, Cap_quota{200} };
Child_state uncached_depot_rom_state {
- "dynamic_depot_rom", Ram_quota{8*1024*1024}, Cap_quota{200} };
+ _child_states, "dynamic_depot_rom", Ram_quota{8*1024*1024}, Cap_quota{200} };
/*
* Report written to '/config/managed/deploy'
@@ -227,7 +229,8 @@ struct Sculpt::Deploy
});
}
- Deploy(Env &env, Allocator &alloc, Runtime_info const &runtime_info,
+ Deploy(Env &env, Allocator &alloc, Registry &child_states,
+ Runtime_info const &runtime_info,
Dialog::Generator &dialog_generator,
Runtime_config_generator &runtime_config_generator,
Depot_query &depot_query,
@@ -235,7 +238,8 @@ struct Sculpt::Deploy
Attached_rom_dataspace const &blueprint_rom,
Download_queue const &download_queue)
:
- _env(env), _alloc(alloc), _runtime_info(runtime_info),
+ _env(env), _alloc(alloc), _child_states(child_states),
+ _runtime_info(runtime_info),
_dialog_generator(dialog_generator),
_runtime_config_generator(runtime_config_generator),
_depot_query(depot_query),
diff --git a/repos/gems/src/app/sculpt_manager/graph.cc b/repos/gems/src/app/sculpt_manager/graph.cc
new file mode 100644
index 000000000..941b9706c
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/graph.cc
@@ -0,0 +1,374 @@
+/*
+ * \brief Graph view of runtime state
+ * \author Norman Feske
+ * \date 2018-07-05
+ */
+
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include
+#include
+
+using namespace Sculpt;
+
+
+void Graph::_gen_selected_node_content(Xml_generator &xml, Start_name const &name,
+ Runtime_state::Info const &info) const
+{
+ bool const removable = _deploy_children.exists(name);
+
+ if (removable) {
+ gen_named_node(xml, "frame", "operations", [&] () {
+ xml.node("vbox", [&] () {
+ gen_named_node(xml, "button", "remove", [&] () {
+ _remove_item.gen_button_attr(xml, "remove");
+ xml.node("label", [&] () {
+ xml.attribute("text", "Remove");
+ });
+ });
+ });
+ });
+ }
+
+ if (name == "ram_fs")
+ gen_named_node(xml, "frame", "ram_fs_operations", [&] () {
+ xml.node("vbox", [&] () {
+ _ram_fs_dialog.generate(xml, _ram_fs_state); }); });
+
+ String<100> const
+ ram (Capacity{info.assigned_ram - info.avail_ram}, " / ",
+ Capacity{info.assigned_ram}),
+ caps(info.assigned_caps - info.avail_caps, " / ",
+ info.assigned_caps, " caps");
+
+ gen_named_node(xml, "label", "hspace", [&] () {
+ xml.attribute("min_ex", 25); });
+
+ gen_named_node(xml, "label", "ram", [&] () {
+ xml.attribute("text", ram); });
+
+ gen_named_node(xml, "label", "caps", [&] () {
+ xml.attribute("text", caps); });
+}
+
+
+void Graph::_gen_parent_node(Xml_generator &xml, Start_name const &name,
+ Label const &label) const
+{
+ gen_named_node(xml, "frame", name, [&] () {
+ xml.node("label", [&] () {
+ xml.attribute("text", Start_name(" ", label, " ")); }); });
+}
+
+
+void Graph::_gen_storage_node(Xml_generator &xml) const
+{
+ char const * const name = "storage";
+
+ bool const any_selected = _runtime_state.selected().valid();
+ bool const unimportant = any_selected && !_runtime_state.storage_in_tcb();
+
+ gen_named_node(xml, "frame", name, [&] () {
+
+ if (unimportant)
+ xml.attribute("style", "unimportant");
+
+ xml.node("vbox", [&] () {
+
+ gen_named_node(xml, "button", name, [&] () {
+
+ _node_button_item.gen_button_attr(xml, name);
+
+ if (unimportant)
+ xml.attribute("style", "unimportant");
+
+ if (_storage_selected)
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () { xml.attribute("text", "Storage"); });
+ });
+
+ if (_storage_selected)
+ gen_named_node(xml, "frame", "storage_operations", [&] () {
+ xml.node("vbox", [&] () {
+ _storage_dialog->gen_block_devices(xml); }); });
+ });
+ });
+}
+
+
+void Graph::_gen_usb_node(Xml_generator &xml) const
+{
+ char const * const name = "usb";
+
+ bool const any_selected = _runtime_state.selected().valid();
+ bool const unimportant = any_selected && !_runtime_state.usb_in_tcb();
+
+ gen_named_node(xml, "frame", name, [&] () {
+
+ if (unimportant)
+ xml.attribute("style", "unimportant");
+
+ xml.node("vbox", [&] () {
+
+ gen_named_node(xml, "button", name, [&] () {
+
+ _node_button_item.gen_button_attr(xml, name);
+
+ if (unimportant)
+ xml.attribute("style", "unimportant");
+
+ if (_usb_selected)
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () { xml.attribute("text", "USB"); });
+ });
+
+ if (_usb_selected)
+ gen_named_node(xml, "frame", "usb_operations", [&] () {
+ xml.node("vbox", [&] () {
+ _storage_dialog->gen_usb_storage_devices(xml); }); });
+ });
+ });
+}
+
+
+void Graph::generate(Xml_generator &xml) const
+{
+ xml.node("depgraph", [&] () {
+
+ if (_sculpt_partition.valid()) {
+ gen_named_node(xml, "button", "global+", [&] () {
+ _add_button_item.gen_button_attr(xml, "global+");
+
+ if (_popup_state == Popup::VISIBLE)
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () {
+ xml.attribute("text", "+"); }); });
+ }
+
+ _gen_storage_node(xml);
+
+ if (_storage_devices.usb_present)
+ _gen_usb_node(xml);
+ else
+ _gen_parent_node(xml, "usb", "USB");
+
+ /* parent roles */
+ _gen_parent_node(xml, "hardware", "Hardware");
+ _gen_parent_node(xml, "config", "Config");
+ _gen_parent_node(xml, "info", "Info");
+ _gen_parent_node(xml, "GUI", "GUI");
+
+ typedef Runtime_config::Component Component;
+
+ bool const any_selected = _runtime_state.selected().valid();
+
+ _runtime_config.for_each_component([&] (Component const &component) {
+
+ Start_name const name = component.name;
+ Start_name const pretty_name { Pretty(name) };
+
+ /* omit sculpt's helpers from the graph */
+ bool const blacklisted = (name == "runtime_view"
+ || name == "popup_view"
+ || name == "menu_view"
+ || name == "panel_view"
+ || name == "settings_view"
+ || name == "network_view"
+ || name == "file_browser_view"
+ || name == "editor"
+ || name == "launcher_query"
+ || name == "update"
+ || name == "fs_tool"
+ || name == "depot_rw"
+ || name == "public_rw"
+ || name == "depot_rom"
+ || name == "dynamic_depot_rom"
+ || name == "depot_query");
+ if (blacklisted)
+ return;
+
+ Runtime_state::Info const info = _runtime_state.info(name);
+
+ bool const unimportant = any_selected && !info.tcb;
+
+ gen_named_node(xml, "frame", name, [&] () {
+
+ if (unimportant)
+ xml.attribute("style", "unimportant");
+
+ Start_name primary_dep = component.primary_dependency;
+
+ if (primary_dep == "default_fs_rw")
+ primary_dep = _sculpt_partition.fs();
+
+ if (primary_dep.valid()) {
+ xml.attribute("dep", primary_dep);
+ if (unimportant)
+ xml.attribute("dep_visible", false);
+ }
+
+ xml.node("vbox", [&] () {
+
+ gen_named_node(xml, "button", name, [&] () {
+
+ if (unimportant)
+ xml.attribute("style", "unimportant");
+
+ _node_button_item.gen_button_attr(xml, name);
+
+ if (info.selected)
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () {
+ xml.attribute("text", pretty_name);
+ });
+ });
+
+ if (info.selected)
+ _gen_selected_node_content(xml, name, info);
+ });
+ });
+ });
+
+ _runtime_config.for_each_component([&] (Component const &component) {
+
+ Start_name const name = component.name;
+
+ Runtime_state::Info const info = _runtime_state.info(name);
+
+ bool const show_details = info.tcb;
+
+ if (show_details) {
+ component.for_each_secondary_dep([&] (Start_name dep) {
+
+ if (Runtime_state::blacklisted_from_graph(dep))
+ return;
+
+ if (dep == "default_fs_rw")
+ dep = _sculpt_partition.fs();
+
+ xml.node("dep", [&] () {
+ xml.attribute("node", name);
+ xml.attribute("on", dep);
+ });
+ });
+ }
+ });
+ });
+}
+
+
+Dialog::Hover_result Graph::hover(Xml_node hover)
+{
+ Hover_result const storage_dialog_hover_result =
+ _storage_dialog->match_sub_dialog(hover, "depgraph", "frame", "vbox", "frame", "vbox");
+
+ Dialog::Hover_result const hover_result = Dialog::any_hover_changed(
+ storage_dialog_hover_result,
+ _ram_fs_dialog.match_sub_dialog(hover, "depgraph", "frame", "vbox", "frame", "vbox"),
+ _node_button_item.match(hover, "depgraph", "frame", "vbox", "button", "name"),
+ _add_button_item .match(hover, "depgraph", "button", "name"),
+ _remove_item .match(hover, "depgraph", "frame", "vbox",
+ "frame", "vbox", "button", "name"));
+
+ if (_add_button_item.hovered("global+")) {
+
+ /* update anchor geometry of popup menu */
+ auto hovered_rect = [] (Xml_node const hover) {
+
+ auto point_from_xml = [] (Xml_node node) {
+ return Point(node.attribute_value("xpos", 0L),
+ node.attribute_value("ypos", 0L)); };
+
+ auto area_from_xml = [] (Xml_node node) {
+ return Area(node.attribute_value("width", 0UL),
+ node.attribute_value("height", 0UL)); };
+
+ if (!hover.has_sub_node("dialog")) return Rect();
+ Xml_node const dialog = hover.sub_node("dialog");
+
+ if (!dialog.has_sub_node("depgraph")) return Rect();
+ Xml_node const depgraph = dialog.sub_node("depgraph");
+
+ if (!depgraph.has_sub_node("button")) return Rect();
+ Xml_node const button = depgraph.sub_node("button");
+
+ return Rect(point_from_xml(dialog) + point_from_xml(depgraph) +
+ point_from_xml(button),
+ area_from_xml(button));
+ };
+
+ _popup_anchor = hovered_rect(hover);
+ }
+
+ return hover_result;
+}
+
+
+void Graph::click(Action &action)
+{
+ if (_ram_fs_dialog.click(action) == Click_result::CONSUMED)
+ return;
+
+ if (_storage_dialog_visible())
+ if (_storage_dialog->click(action) == Click_result::CONSUMED)
+ return;
+
+ if (_add_button_item._hovered.valid())
+ action.toggle_launcher_selector(_popup_anchor);
+
+ if (_node_button_item._hovered.valid()) {
+
+ _storage_selected = !_storage_selected && _node_button_item.hovered("storage");
+ _usb_selected = !_usb_selected && _node_button_item.hovered("usb");
+
+ /* reset storage dialog */
+ if (_usb_selected || _storage_selected)
+ _storage_dialog.construct(_storage_devices, _sculpt_partition);
+
+ _runtime_state.toggle_selection(_node_button_item._hovered,
+ _runtime_config);
+ _remove_item.reset();
+ }
+
+ if (_remove_item.hovered("remove"))
+ _remove_item.propose_activation_on_click();
+}
+
+
+void Graph::clack(Action &action, Ram_fs_dialog::Action &ram_fs_action)
+{
+ if (_ram_fs_dialog.clack(ram_fs_action) == Clack_result::CONSUMED)
+ return;
+
+ if (_storage_dialog_visible())
+ if (_storage_dialog->clack(action) == Clack_result::CONSUMED)
+ return;
+
+ if (_remove_item.hovered("remove")) {
+
+ _remove_item.confirm_activation_on_clack();
+
+ if (_remove_item.activated("remove")) {
+ action.remove_deployed_component(_runtime_state.selected());
+
+ /*
+ * Unselect the removed component to bring graph into
+ * default state.
+ */
+ _runtime_state.toggle_selection(_runtime_state.selected(),
+ _runtime_config);
+ }
+ } else {
+ _remove_item.reset();
+ }
+}
+
diff --git a/repos/gems/src/app/sculpt_manager/graph.h b/repos/gems/src/app/sculpt_manager/graph.h
index 4803f0f33..04989b1ca 100644
--- a/repos/gems/src/app/sculpt_manager/graph.h
+++ b/repos/gems/src/app/sculpt_manager/graph.h
@@ -2,9 +2,6 @@
* \brief Graph view of runtime state
* \author Norman Feske
* \date 2018-07-05
- *
- * The GUI is based on a dynamically configured init component, which hosts
- * one menu-view component for each dialog.
*/
/*
@@ -19,38 +16,40 @@
/* Genode includes */
#include
+#include
+
+/* included from depot_deploy tool */
+#include
/* local includes */
#include
#include
+#include
+#include
+#include
#include
#include
#include
+#include
+#include
#include
namespace Sculpt { struct Graph; }
-struct Sculpt::Graph
+struct Sculpt::Graph : Dialog
{
- Env &_env;
-
Runtime_state &_runtime_state;
Runtime_config const &_runtime_config;
- Storage_target const &_sculpt_partition;
+ Storage_devices const &_storage_devices;
+ Storage_target const &_sculpt_partition;
+ Ram_fs_state const &_ram_fs_state;
Popup::State const &_popup_state;
Depot_deploy::Children const &_deploy_children;
- Expanding_reporter _graph_dialog_reporter { _env, "dialog", "runtime_view_dialog" };
-
- Attached_rom_dataspace _hover_rom { _env, "runtime_view_hover" };
-
- Signal_handler _hover_handler {
- _env.ep(), *this, &Graph::_handle_hover };
-
Hoverable_item _node_button_item { };
Hoverable_item _add_button_item { };
Activatable_item _remove_item { };
@@ -60,275 +59,58 @@ struct Sculpt::Graph
*/
Rect _popup_anchor { };
- bool _hovered = false;
+ Ram_fs_dialog _ram_fs_dialog;
- void _gen_selected_node_content(Xml_generator &xml, Start_name const &name,
- Runtime_state::Info const &info) const
+ bool _storage_selected = false;
+ bool _usb_selected = false;
+
+ bool _storage_dialog_visible() const { return _storage_selected || _usb_selected; }
+
+ Reconstructible _storage_dialog { _storage_devices, _sculpt_partition };
+
+ void _gen_selected_node_content(Xml_generator &, Start_name const &,
+ Runtime_state::Info const &) const;
+
+ void _gen_parent_node(Xml_generator &, Start_name const &, Label const &) const;
+ void _gen_storage_node(Xml_generator &) const;
+ void _gen_usb_node(Xml_generator &) const;
+
+ void generate(Xml_generator &) const override;
+
+ Hover_result hover(Xml_node) override;
+
+ void reset() override { }
+
+ void reset_operation()
{
- bool const removable = _deploy_children.exists(name);
-
- if (removable) {
- gen_named_node(xml, "frame", "operations", [&] () {
- xml.node("vbox", [&] () {
- gen_named_node(xml, "button", "remove", [&] () {
- _remove_item.gen_button_attr(xml, "remove");
- xml.node("label", [&] () {
- xml.attribute("text", "Remove");
- });
- });
- });
- });
- }
-
- String<100> const
- ram (Capacity{info.assigned_ram - info.avail_ram}, " / ",
- Capacity{info.assigned_ram}),
- caps(info.assigned_caps - info.avail_caps, " / ",
- info.assigned_caps, " caps");
-
- gen_named_node(xml, "label", "ram", [&] () {
- xml.attribute("text", ram); });
-
- gen_named_node(xml, "label", "caps", [&] () {
- xml.attribute("text", caps); });
+ if (_storage_dialog.constructed())
+ _storage_dialog->reset_operation();
}
- void _gen_parent_node(Xml_generator &xml, Start_name const &name) const
- {
- gen_named_node(xml, "frame", name, [&] () {
- xml.node("label", [&] () {
- xml.attribute("text", Start_name(" ", name, " ")); }); });
- }
-
- void _gen_graph_dialog()
- {
- _graph_dialog_reporter.generate([&] (Xml_generator &xml) {
-
- xml.node("depgraph", [&] () {
-
- if (_sculpt_partition.valid()) {
- gen_named_node(xml, "button", "global+", [&] () {
- _add_button_item.gen_button_attr(xml, "global+");
-
- if (_popup_state == Popup::VISIBLE)
- xml.attribute("selected", "yes");
-
- xml.node("label", [&] () {
- xml.attribute("text", "+"); }); });
- }
-
- /* parent roles */
- _gen_parent_node(xml, "hardware");
- _gen_parent_node(xml, "config");
- _gen_parent_node(xml, "info");
- _gen_parent_node(xml, "GUI");
-
- typedef Runtime_config::Component Component;
-
- bool const any_selected = _runtime_state.selected().valid();
-
- _runtime_config.for_each_component([&] (Component const &component) {
-
- Start_name const name = component.name;
- Start_name const pretty_name { Pretty(name) };
-
- /* omit sculpt's helpers from the graph */
- bool const blacklisted = (name == "runtime_view"
- || name == "launcher_query"
- || name == "update"
- || name == "fs_tool"
- || name == "depot_rw"
- || name == "public_rw"
- || name == "depot_rom"
- || name == "dynamic_depot_rom"
- || name == "depot_query");
- if (blacklisted)
- return;
-
- Runtime_state::Info const info = _runtime_state.info(name);
-
- bool const unimportant = any_selected && !info.tcb;
-
- gen_named_node(xml, "frame", name, [&] () {
-
- if (unimportant)
- xml.attribute("style", "unimportant");
-
- Start_name primary_dep = component.primary_dependency;
-
- if (primary_dep == "default_fs_rw")
- primary_dep = _sculpt_partition.fs();
-
- if (primary_dep.valid()) {
- xml.attribute("dep", primary_dep);
- if (unimportant)
- xml.attribute("dep_visible", false);
- }
-
- xml.node("vbox", [&] () {
-
- gen_named_node(xml, "button", name, [&] () {
-
- if (unimportant)
- xml.attribute("style", "unimportant");
-
- _node_button_item.gen_button_attr(xml, name);
-
- if (info.selected)
- xml.attribute("selected", "yes");
-
- xml.node("label", [&] () {
- xml.attribute("text", pretty_name);
- });
- });
-
- if (info.selected)
- _gen_selected_node_content(xml, name, info);
- });
- });
- });
-
- _runtime_config.for_each_component([&] (Component const &component) {
-
- Start_name const name = component.name;
-
- Runtime_state::Info const info = _runtime_state.info(name);
-
- bool const show_details = info.tcb;
-
- if (show_details) {
- component.for_each_secondary_dep([&] (Start_name const &dep) {
-
- if (Runtime_state::blacklisted_from_graph(dep))
- return;
-
- xml.node("dep", [&] () {
- xml.attribute("node", name);
- xml.attribute("on", dep);
- });
- });
- }
- });
- });
- });
- }
-
- void _handle_hover()
- {
- _hover_rom.update();
-
- Xml_node const hover = _hover_rom.xml();
-
- _hovered = (hover.num_sub_nodes() != 0);
-
- bool const changed =
- _node_button_item.match(hover, "dialog", "depgraph", "frame", "vbox", "button", "name") |
- _add_button_item .match(hover, "dialog", "depgraph", "button", "name") |
- _remove_item .match(hover, "dialog", "depgraph", "frame", "vbox",
- "frame", "vbox", "button", "name");
-
- if (_add_button_item.hovered("global+")) {
-
- /* update anchor geometry of popup menu */
- auto hovered_rect = [] (Xml_node const hover) {
-
- auto point_from_xml = [] (Xml_node node) {
- return Point(node.attribute_value("xpos", 0L),
- node.attribute_value("ypos", 0L)); };
-
- auto area_from_xml = [] (Xml_node node) {
- return Area(node.attribute_value("width", 0UL),
- node.attribute_value("height", 0UL)); };
-
- if (!hover.has_sub_node("dialog")) return Rect();
- Xml_node const dialog = hover.sub_node("dialog");
-
- if (!dialog.has_sub_node("depgraph")) return Rect();
- Xml_node const depgraph = dialog.sub_node("depgraph");
-
- if (!depgraph.has_sub_node("button")) return Rect();
- Xml_node const button = depgraph.sub_node("button");
-
- return Rect(point_from_xml(dialog) + point_from_xml(depgraph) +
- point_from_xml(button),
- area_from_xml(button));
- };
-
- _popup_anchor = hovered_rect(hover);
- }
-
- if (changed)
- _gen_graph_dialog();
- }
-
- Graph(Env &env,
- Runtime_state &runtime_state,
+ Graph(Runtime_state &runtime_state,
Runtime_config const &runtime_config,
+ Storage_devices const &storage_devices,
Storage_target const &sculpt_partition,
+ Ram_fs_state const &ram_fs_state,
Popup::State const &popup_state,
Depot_deploy::Children const &deploy_children)
:
- _env(env), _runtime_state(runtime_state), _runtime_config(runtime_config),
- _sculpt_partition(sculpt_partition),
- _popup_state(popup_state), _deploy_children(deploy_children)
- {
- _hover_rom.sigh(_hover_handler);
- }
-
- bool hovered() const { return _hovered; }
+ _runtime_state(runtime_state), _runtime_config(runtime_config),
+ _storage_devices(storage_devices), _sculpt_partition(sculpt_partition),
+ _ram_fs_state(ram_fs_state), _popup_state(popup_state),
+ _deploy_children(deploy_children), _ram_fs_dialog(sculpt_partition)
+ { }
bool add_button_hovered() const { return _add_button_item._hovered.valid(); }
- struct Action : Interface
+ struct Action : Storage_dialog::Action
{
virtual void remove_deployed_component(Start_name const &) = 0;
virtual void toggle_launcher_selector(Rect) = 0;
};
- void click(Action &action)
- {
- if (_add_button_item._hovered.valid()) {
- action.toggle_launcher_selector(_popup_anchor);
- }
-
- if (_node_button_item._hovered.valid()) {
- _runtime_state.toggle_selection(_node_button_item._hovered,
- _runtime_config);
- _remove_item.reset();
- _gen_graph_dialog();
- }
-
- if (_remove_item.hovered("remove")) {
- _remove_item.propose_activation_on_click();
- _gen_graph_dialog();
- }
- }
-
- void clack(Action &action)
- {
- if (_remove_item.hovered("remove")) {
-
- _remove_item.confirm_activation_on_clack();
-
- if (_remove_item.activated("remove")) {
- action.remove_deployed_component(_runtime_state.selected());
-
- /*
- * Unselect the removed component to bring graph into
- * default state.
- */
- _runtime_state.toggle_selection(_runtime_state.selected(),
- _runtime_config);
- }
-
- } else {
- _remove_item.reset();
- }
-
- _gen_graph_dialog();
- }
-
- void gen_dialog() { _gen_graph_dialog(); }
+ void click(Action &action);
+ void clack(Action &action, Ram_fs_dialog::Action &);
};
#endif /* _GRAPH_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/gui.cc b/repos/gems/src/app/sculpt_manager/gui.cc
deleted file mode 100644
index 3b6f81b45..000000000
--- a/repos/gems/src/app/sculpt_manager/gui.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * \brief Sculpt GUI management
- * \author Norman Feske
- * \date 2018-04-30
- *
- * The GUI is based on a dynamically configured init component, which hosts
- * one menu-view component for each dialog.
- */
-
-/*
- * Copyright (C) 2018 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.
- */
-
-/* Genode includes */
-#include
-
-/* local includes */
-#include
-
-
-void Sculpt::Gui::_gen_menu_view_start_content(Xml_generator &xml,
- Label const &label,
- Point pos,
- unsigned width) const
-{
- xml.attribute("version", version.value);
-
- gen_common_start_content(xml, label, Cap_quota{150}, Ram_quota{12*1024*1024});
-
- gen_named_node(xml, "binary", "menu_view");
-
- xml.node("config", [&] () {
- xml.attribute("xpos", pos.x());
- xml.attribute("ypos", pos.y());
- if (width)
- xml.attribute("width", width);
- xml.node("libc", [&] () { xml.attribute("stderr", "/dev/log"); });
- xml.node("report", [&] () { xml.attribute("hover", "yes"); });
- xml.node("vfs", [&] () {
- gen_named_node(xml, "tar", "menu_view_styles.tar");
- gen_named_node(xml, "dir", "styles", [&] () {
- gen_named_node(xml, "dir", "frame", [&] () {
- gen_named_node(xml, "dir", "logo", [&] () {
- gen_named_node(xml, "rom", "background.png", [&] () {
- xml.attribute("label", "genode_logo.png"); }); }); }); });
-
- gen_named_node(xml, "dir", "fonts", [&] () {
- xml.node("fs", [&] () {
- xml.attribute("label", "fonts"); }); });
- gen_named_node(xml, "dir", "dev", [&] () {
- xml.node("log", [&] () { }); });
- });
- });
-
- xml.node("route", [&] () {
- gen_parent_rom_route(xml, "menu_view");
- gen_parent_rom_route(xml, "ld.lib.so");
- gen_parent_rom_route(xml, "vfs.lib.so");
- gen_parent_rom_route(xml, "libc.lib.so");
- gen_parent_rom_route(xml, "libm.lib.so");
- gen_parent_rom_route(xml, "libpng.lib.so");
- gen_parent_rom_route(xml, "zlib.lib.so");
- gen_parent_rom_route(xml, "menu_view_styles.tar");
- gen_parent_rom_route(xml, "genode_logo.png");
- gen_parent_route (xml);
- gen_parent_route (xml);
- gen_parent_route (xml);
- gen_parent_route (xml);
- gen_parent_route (xml);
-
- gen_service_node(xml, [&] () {
- xml.attribute("label", "dialog");
- xml.node("parent", [&] () { }); });
-
- gen_service_node(xml, [&] () {
- xml.attribute("label", "hover");
- xml.node("parent", [&] () { }); });
-
- gen_service_node<::File_system::Session>(xml, [&] () {
- xml.attribute("label", "fonts");
- xml.node("parent", [&] () {
- xml.attribute("label", "fonts"); }); });
- });
-}
-
-
-void Sculpt::Gui::_generate_config(Xml_generator &xml) const
-{
- xml.node("parent-provides", [&] () {
- gen_parent_service(xml);
- gen_parent_service(xml);
- gen_parent_service(xml);
- gen_parent_service(xml);
- gen_parent_service(xml);
- gen_parent_service(xml);
- gen_parent_service(xml);
- gen_parent_service<::File_system::Session>(xml);
- });
-
- xml.node("resource", [&] () {
- xml.attribute("name", "RAM");
- xml.attribute("preserve", "1M");
- });
-
- xml.node("start", [&] () {
- _gen_menu_view_start_content(xml, "menu", Point(0, 0), menu_width); });
-
- xml.node("start", [&] () {
- _gen_menu_view_start_content(xml, "popup", Point(0, 0), 0); });
-}
-
diff --git a/repos/gems/src/app/sculpt_manager/gui.h b/repos/gems/src/app/sculpt_manager/gui.h
deleted file mode 100644
index b55df6aa1..000000000
--- a/repos/gems/src/app/sculpt_manager/gui.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * \brief Sculpt GUI management
- * \author Norman Feske
- * \date 2018-04-30
- *
- * The GUI is based on a dynamically configured init component, which hosts
- * one menu-view component for each dialog.
- */
-
-/*
- * Copyright (C) 2018 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 _GUI_H_
-#define _GUI_H_
-
-/* Genode includes */
-#include
-
-/* local includes */
-#include
-#include
-
-namespace Sculpt { struct Gui; }
-
-
-struct Sculpt::Gui
-{
- Env &_env;
-
- Expanding_reporter _config { _env, "config", "gui_config" };
-
- float _font_size_px = 14;
-
- typedef String<32> Label;
-
- struct Version { unsigned value; } version { 0 };
-
- unsigned menu_width = 0;
-
- void _gen_menu_view_start_content(Xml_generator &, Label const &, Point,
- unsigned) const;
-
- void _generate_config(Xml_generator &) const;
-
- void generate_config()
- {
- _config.generate([&] (Xml_generator &xml) { _generate_config(xml); });
- }
-
- float font_size() const { return _font_size_px; }
-
- void font_size(float px)
- {
- _font_size_px = px;
- menu_width = max(px*21, 320.0);
- }
-
- Gui(Env &env) : _env(env) { }
-};
-
-#endif /* _GUI_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/keyboard_focus.h b/repos/gems/src/app/sculpt_manager/keyboard_focus.h
index de6315138..183e899bb 100644
--- a/repos/gems/src/app/sculpt_manager/keyboard_focus.h
+++ b/repos/gems/src/app/sculpt_manager/keyboard_focus.h
@@ -20,6 +20,7 @@
/* local includes */
#include
#include
+#include
namespace Sculpt { struct Keyboard_focus; }
@@ -29,8 +30,9 @@ struct Sculpt::Keyboard_focus
Expanding_reporter _focus_reporter;
- Network_dialog const &_network_dialog;
- Wpa_passphrase &_wpa_passphrase;
+ Network_dialog const &_network_dialog;
+ Wpa_passphrase &_wpa_passphrase;
+ Panel_dialog::State const &_panel;
void update()
{
@@ -38,7 +40,7 @@ struct Sculpt::Keyboard_focus
target = WM;
- if (_network_dialog.need_keyboard_focus_for_passphrase())
+ if (_panel.network_visible() && _network_dialog.need_keyboard_focus_for_passphrase())
target = WPA_PASSPHRASE;
if (orig_target == target)
@@ -63,12 +65,14 @@ struct Sculpt::Keyboard_focus
}
Keyboard_focus(Env &env,
- Network_dialog const &network_dialog,
- Wpa_passphrase &wpa_passphrase)
+ Network_dialog const &network_dialog,
+ Wpa_passphrase &wpa_passphrase,
+ Panel_dialog::State const &panel)
:
_focus_reporter(env, "focus", "focus"),
_network_dialog(network_dialog),
- _wpa_passphrase(wpa_passphrase)
+ _wpa_passphrase(wpa_passphrase),
+ _panel(panel)
{
update();
}
diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc
index 67fbfe0b2..5b2ca4494 100644
--- a/repos/gems/src/app/sculpt_manager/main.cc
+++ b/repos/gems/src/app/sculpt_manager/main.cc
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -27,9 +28,13 @@
#include
#include
#include
+#include
#include
#include
-#include
+#include
+#include
+#include
+#include
#include
#include
#include
@@ -45,9 +50,15 @@ struct Sculpt::Main : Input_event_handler,
Runtime_config_generator,
Storage::Target_user,
Graph::Action,
+ Panel_dialog::Action,
Popup_dialog::Action,
+ Settings_dialog::Action,
+ File_browser_dialog::Action,
Popup_dialog::Construction_info,
- Depot_query
+ Depot_query,
+ Panel_dialog::State,
+ Dialog,
+ Popup_dialog::Refresh
{
Env &_env;
@@ -55,6 +66,8 @@ struct Sculpt::Main : Input_event_handler,
Sculpt_version const _sculpt_version { _env };
+ Registry _child_states { };
+
Constructible _nitpicker { };
Signal_handler _input_handler {
@@ -88,7 +101,7 @@ struct Sculpt::Main : Input_event_handler,
type.for_each_sub_node("ttf", [&] (Xml_node ttf) {
float const px = ttf.attribute_value("size_px", 0.0);
if (px > 0.0)
- _gui.font_size(px); }); } }); } }); });
+ _font_size_px = px; }); } }); } }); });
_handle_nitpicker_mode();
}
@@ -131,6 +144,8 @@ struct Sculpt::Main : Input_event_handler,
if (device.attribute_value("class_code", 0UL) == 0x28000)
_pci_info.wifi_present = true;
});
+
+ _network.update_view();
}
@@ -147,7 +162,7 @@ struct Sculpt::Main : Input_event_handler,
}
- Storage _storage { _env, _heap, *this, *this, *this };
+ Storage _storage { _env, _heap, _child_states, *this, *this, *this };
/**
* Storage::Target_user interface
@@ -165,7 +180,7 @@ struct Sculpt::Main : Input_event_handler,
}
- Network _network { _env, _heap, *this, *this, _runtime_state, _pci_info };
+ Network _network { _env, _heap, _child_states, *this, _runtime_state, _pci_info };
/************
@@ -307,12 +322,12 @@ struct Sculpt::Main : Input_event_handler,
_launchers.update_from_xml(dir);
}
- _popup_dialog.generate();
+ _popup_menu_view.generate();
_deploy._handle_managed_deploy();
}
- Deploy _deploy { _env, _heap, _runtime_state, *this, *this, *this,
+ Deploy _deploy { _env, _heap, _child_states, _runtime_state, *this, *this, *this,
_launcher_listing_rom, _blueprint_rom, _download_queue };
Attached_rom_dataspace _manual_deploy_rom { _env, "config -> deploy" };
@@ -332,102 +347,103 @@ struct Sculpt::Main : Input_event_handler,
** Global **
************/
- Gui _gui { _env };
+ Font_size _font_size = Font_size::MEDIUM;
- Expanding_reporter _menu_dialog_reporter { _env, "dialog", "menu_dialog" };
+ float _font_size_px = 14;
- Attached_rom_dataspace _hover_rom { _env, "menu_view_hover" };
+ Area _screen_size { };
- Signal_handler _hover_handler {
- _env.ep(), *this, &Main::_handle_hover };
+ Panel_dialog::Tab _selected_tab = Panel_dialog::Tab::COMPONENTS;
- struct Hovered { enum Dialog { NONE, LOGO, STORAGE, NETWORK, RUNTIME } value; };
+ bool _log_visible = false;
+ bool _network_visible = false;
+ bool _settings_visible = false;
- Hovered::Dialog _hovered_dialog { Hovered::NONE };
+ File_browser_state _file_browser_state { };
- template
- void _apply_to_hovered_dialog(Hovered::Dialog dialog, FN const &fn)
+ Attached_rom_dataspace _editor_saved_rom { _env, "report -> runtime/editor/saved" };
+
+
+ /**
+ * Panel_dialog::State interface
+ */
+ bool log_visible() const override { return _log_visible; }
+
+ bool network_visible() const override { return _network_visible; }
+
+ bool settings_visible() const override { return _settings_visible; }
+
+ bool inspect_tab_visible() const override { return _storage.any_file_system_inspected(); }
+
+ Panel_dialog::Tab selected_tab() const override { return _selected_tab; }
+
+ /**
+ * Dialog interface
+ */
+ Hover_result hover(Xml_node) override;
+
+ void reset() override { }
+
+ /**
+ * Dialog interface
+ */
+ void generate(Xml_generator &xml) const override
{
- if (dialog == Hovered::STORAGE) fn(_storage.dialog);
- if (dialog == Hovered::NETWORK) fn(_network.dialog);
- }
+ xml.node("vbox", [&] () {
+ if (_manually_managed_runtime)
+ return;
- void _handle_hover();
+ bool const network_missing = _deploy.update_needed()
+ && !_network._nic_state.ready();
+ bool const show_diagnostics =
+ _deploy.any_unsatisfied_child() || network_missing;
+
+ auto gen_network_diagnostics = [&] (Xml_generator &xml)
+ {
+ if (!network_missing)
+ return;
+
+ gen_named_node(xml, "hbox", "network", [&] () {
+ gen_named_node(xml, "float", "left", [&] () {
+ xml.attribute("west", "yes");
+ xml.node("label", [&] () {
+ xml.attribute("text", "network needed for installation");
+ xml.attribute("font", "annotation/regular");
+ });
+ });
+ });
+ };
+
+ if (show_diagnostics) {
+ gen_named_node(xml, "frame", "diagnostics", [&] () {
+ xml.node("vbox", [&] () {
+
+ xml.node("label", [&] () {
+ xml.attribute("text", "Diagnostics"); });
+
+ xml.node("float", [&] () {
+ xml.node("vbox", [&] () {
+ gen_network_diagnostics(xml);
+ _deploy.gen_child_diagnostics(xml);
+ });
+ });
+ });
+ });
+ }
+
+ Xml_node const state = _update_state_rom.xml();
+ if (_update_running() && state.attribute_value("progress", false))
+ gen_download_status(xml, state);
+ });
+ }
/**
* Dialog::Generator interface
*/
void generate_dialog() override
{
- _menu_dialog_reporter.generate([&] (Xml_generator &xml) {
-
- xml.node("vbox", [&] () {
- gen_named_node(xml, "frame", "logo", [&] () {
- xml.node("float", [&] () {
- xml.node("frame", [&] () {
- xml.attribute("style", "logo"); }); }); });
-
- if (_manually_managed_runtime)
- return;
-
- bool const storage_dialog_expanded = _last_clicked == Hovered::STORAGE
- || !_storage.any_file_system_inspected();
-
- _storage.dialog.generate(xml, storage_dialog_expanded);
- _network.dialog.generate(xml);
-
- gen_named_node(xml, "frame", "runtime", [&] () {
- xml.node("vbox", [&] () {
- gen_named_node(xml, "label", "title", [&] () {
- xml.attribute("text", "Runtime");
- xml.attribute("font", "title/regular");
- });
-
- bool const network_missing = _deploy.update_needed()
- && !_network._nic_state.ready();
- bool const show_diagnostics =
- _deploy.any_unsatisfied_child() || network_missing;
-
- auto gen_network_diagnostics = [&] (Xml_generator &xml)
- {
- if (!network_missing)
- return;
-
- gen_named_node(xml, "hbox", "network", [&] () {
- gen_named_node(xml, "float", "left", [&] () {
- xml.attribute("west", "yes");
- xml.node("label", [&] () {
- xml.attribute("text", "network needed for installation");
- xml.attribute("font", "annotation/regular");
- });
- });
- });
- };
-
- if (show_diagnostics) {
- gen_named_node(xml, "frame", "diagnostics", [&] () {
- xml.node("vbox", [&] () {
-
- xml.node("label", [&] () {
- xml.attribute("text", "Diagnostics"); });
-
- xml.node("float", [&] () {
- xml.node("vbox", [&] () {
- gen_network_diagnostics(xml);
- _deploy.gen_child_diagnostics(xml);
- });
- });
- });
- });
- }
-
- Xml_node const state = _update_state_rom.xml();
- if (_update_running() && state.attribute_value("progress", false))
- gen_download_status(xml, state);
- });
- });
- });
- });
+ _main_menu_view.generate();
+ _graph_menu_view.generate();
}
Attached_rom_dataspace _runtime_state_rom { _env, "report -> runtime/state" };
@@ -485,7 +501,10 @@ struct Sculpt::Main : Input_event_handler,
{
_runtime_config_rom.update();
_cached_runtime_config.update_from_xml(_runtime_config_rom.xml());
- _graph.gen_dialog();
+ _graph_menu_view.generate();
+
+ if (_selected_tab == Panel_dialog::Tab::FILES)
+ _file_browser_menu_view.generate();
}
@@ -493,9 +512,7 @@ struct Sculpt::Main : Input_event_handler,
** Interactive operations **
****************************/
- Keyboard_focus _keyboard_focus { _env, _network.dialog, _network.wpa_passphrase };
-
- Hovered::Dialog _last_clicked { Hovered::NONE };
+ Keyboard_focus _keyboard_focus { _env, _network.dialog, _network.wpa_passphrase, *this };
/**
* Input_event_handler interface
@@ -506,18 +523,8 @@ struct Sculpt::Main : Input_event_handler,
if (ev.key_press(Input::BTN_LEFT)) {
- if (_hovered_dialog != _last_clicked && _hovered_dialog != Hovered::NONE) {
- _last_clicked = _hovered_dialog;
- _handle_window_layout();
- need_generate_dialog = true;
- }
-
- if (_hovered_dialog == Hovered::STORAGE) _storage.dialog.click(_storage);
- if (_hovered_dialog == Hovered::NETWORK) _network.dialog.click(_network);
- if (_hovered_dialog == Hovered::RUNTIME) _network.dialog.click(_network);
-
/* remove popup dialog when clicking somewhere outside */
- if (!_popup_dialog.hovered() && _popup.state == Popup::VISIBLE
+ if (!_popup_menu_view.hovered() && _popup.state == Popup::VISIBLE
&& !_graph.add_button_hovered()) {
_popup.state = Popup::OFF;
@@ -525,21 +532,50 @@ struct Sculpt::Main : Input_event_handler,
discard_construction();
/* de-select '+' button */
- _graph._gen_graph_dialog();
+ _graph_menu_view.generate();
/* remove popup window from window layout */
_handle_window_layout();
}
- if (_graph.hovered()) _graph.click(*this);
- if (_popup_dialog.hovered()) _popup_dialog.click(*this);
+ if (_main_menu_view.hovered()) {
+ _main_menu_view.generate();
+ }
+ else if (_graph_menu_view.hovered()) {
+ _graph.click(*this);
+ _graph_menu_view.generate();
+ }
+ else if (_popup_menu_view.hovered()) {
+ _popup_dialog.click(*this);
+ _popup_menu_view.generate();
+ }
+ else if (_panel_menu_view.hovered()) {
+ _panel_dialog.click(*this);
+ }
+ else if (_settings_menu_view.hovered()) {
+ _settings_dialog.click(*this);
+ _settings_menu_view.generate();
+ }
+ else if (_network.dialog_hovered()) {
+ _network.dialog.click(_network);
+ _network.update_view();
+ }
+ else if (_file_browser_menu_view.hovered()) {
+ _file_browser_dialog.click(*this);
+ _file_browser_menu_view.generate();
+ }
}
if (ev.key_release(Input::BTN_LEFT)) {
- if (_hovered_dialog == Hovered::STORAGE) _storage.dialog.clack(_storage);
-
- if (_graph.hovered()) _graph.clack(*this);
- if (_popup_dialog.hovered()) _popup_dialog.clack(*this);
+ if (_main_menu_view.hovered()) {
+ _storage.dialog.clack(_storage);
+ _main_menu_view.generate();
+ }
+ else if (_graph_menu_view.hovered()) {
+ _graph.clack(*this, _storage);
+ _graph_menu_view.generate();
+ }
+ else if (_popup_menu_view.hovered()) _popup_dialog.clack(*this);
}
if (_keyboard_focus.target == Keyboard_focus::WPA_PASSPHRASE)
@@ -553,6 +589,52 @@ struct Sculpt::Main : Input_event_handler,
generate_dialog();
}
+ /*
+ * Fs_dialog::Action interface
+ */
+ void toggle_file_browser(Storage_target const &target) override
+ {
+ _storage.toggle_file_browser(target);
+
+ /* refresh visibility to inspect tab */
+ _panel_menu_view.generate();
+ }
+
+ void use(Storage_target const &target) override { _storage.use(target); }
+
+ /*
+ * Storage_dialog::Action interface
+ */
+ void format(Storage_target const &target) override
+ {
+ _storage.format(target);
+ }
+
+ void cancel_format(Storage_target const &target) override
+ {
+ _storage.cancel_format(target);
+ }
+
+ void expand(Storage_target const &target) override
+ {
+ _storage.expand(target);
+ }
+
+ void cancel_expand(Storage_target const &target) override
+ {
+ _storage.cancel_expand(target);
+ }
+
+ void check(Storage_target const &target) override
+ {
+ _storage.check(target);
+ }
+
+ void toggle_default_storage_target(Storage_target const &target) override
+ {
+ _storage.toggle_default_storage_target(target);
+ }
+
/*
* Graph::Action interface
*/
@@ -569,13 +651,214 @@ struct Sculpt::Main : Input_event_handler,
*/
void toggle_launcher_selector(Rect anchor) override
{
- _popup_dialog.generate();
+ _popup_menu_view.generate();
_popup.anchor = anchor;
_popup.toggle();
- _graph._gen_graph_dialog();
+ _graph_menu_view.generate();
_handle_window_layout();
}
+ void _refresh_panel_and_window_layout()
+ {
+ _panel_menu_view.generate();
+ _handle_window_layout();
+ }
+
+ /*
+ * Panel::Action interface
+ */
+ void select_tab(Panel_dialog::Tab tab) override
+ {
+ _selected_tab = tab;
+
+ if (_selected_tab == Panel_dialog::Tab::FILES)
+ _file_browser_menu_view.generate();
+
+ _refresh_panel_and_window_layout();
+ }
+
+ /*
+ * Panel::Action interface
+ */
+ void toggle_log_visibility() override
+ {
+ _log_visible = !_log_visible;
+ _refresh_panel_and_window_layout();
+ }
+
+ /*
+ * Panel::Action interface
+ */
+ void toggle_network_visibility() override
+ {
+ _network_visible = !_network_visible;
+ _refresh_panel_and_window_layout();
+ }
+
+ /*
+ * Panel::Action interface
+ */
+ void toggle_settings_visibility() override
+ {
+ _settings_visible = !_settings_visible;
+ _refresh_panel_and_window_layout();
+ }
+
+ /*
+ * Settings_dialog::Action interface
+ */
+ void select_font_size(Font_size font_size) override
+ {
+ _font_size = font_size;
+ _handle_nitpicker_mode();
+ }
+
+ Signal_handler _fs_query_result_handler {
+ _env.ep(), *this, &Main::_handle_fs_query_result };
+
+ void _handle_fs_query_result()
+ {
+ _file_browser_state.update_query_results();
+ _file_browser_menu_view.generate();
+ }
+
+ Signal_handler _editor_saved_handler {
+ _env.ep(), *this, &Main::_handle_editor_saved };
+
+ void _handle_editor_saved()
+ {
+ _editor_saved_rom.update();
+
+ Xml_node const saved = _editor_saved_rom.xml();
+
+ bool const orig_modified = _file_browser_state.modified;
+
+ _file_browser_state.modified = saved.attribute_value("modified", false);
+ _file_browser_state.last_saved_version = saved.attribute_value("version", 0U);
+
+ if (orig_modified != _file_browser_state.modified)
+ _file_browser_menu_view.generate();
+ }
+
+ void _close_edited_file()
+ {
+ _file_browser_state.edited_file = File_browser_state::File();
+ _file_browser_state.text_area.destruct();
+ _file_browser_state.edit = false;
+ }
+
+ /*
+ * File_browser_dialog::Action interface
+ */
+ void browse_file_system(File_browser_state::Fs_name const &name) override
+ {
+ using Fs_name = File_browser_state::Fs_name;
+
+ _close_edited_file();
+
+ if (name == _file_browser_state.browsed_fs) {
+ _file_browser_state.browsed_fs = Fs_name();
+ _file_browser_state.fs_query.destruct();
+
+ } else {
+ _file_browser_state.browsed_fs = name;
+ _file_browser_state.path = File_browser_state::Path("/");
+
+ Start_name const start_name(name, ".query");
+ _file_browser_state.fs_query.construct(_child_states, start_name,
+ Ram_quota{8*1024*1024}, Cap_quota{200});
+
+ Label const rom_label("report -> /runtime/", start_name, "/listing");
+
+ _file_browser_state.query_result.construct(_env, rom_label.string());
+ _file_browser_state.query_result->sigh(_fs_query_result_handler);
+ _handle_fs_query_result();
+ }
+
+ generate_runtime_config();
+
+ _file_browser_menu_view.generate();
+ }
+
+ void browse_sub_directory(File_browser_state::Sub_dir const &sub_dir) override
+ {
+ _close_edited_file();
+
+ if (_file_browser_state.path == "/")
+ _file_browser_state.path =
+ File_browser_state::Path("/", sub_dir);
+ else
+ _file_browser_state.path =
+ File_browser_state::Path(_file_browser_state.path, "/", sub_dir);
+
+ generate_runtime_config();
+ }
+
+ void browse_parent_directory() override
+ {
+ _close_edited_file();
+
+ Genode::Path<256> path(_file_browser_state.path);
+ path.strip_last_element();
+ _file_browser_state.path = File_browser_state::Path(path);
+
+ generate_runtime_config();
+ }
+
+ void browse_abs_directory(File_browser_state::Path const &path) override
+ {
+ _close_edited_file();
+
+ _file_browser_state.path = path;
+
+ generate_runtime_config();
+ }
+
+ void _view_or_edit_file(File_browser_state::File const &file, bool edit)
+ {
+ if (_file_browser_state.edited_file == file) {
+ _close_edited_file();
+ } else {
+ _file_browser_state.edited_file = file;
+ _file_browser_state.edit = edit;
+ _file_browser_state.save_version = 0;
+
+ if (_file_browser_state.text_area.constructed()) {
+ _file_browser_state.text_area->trigger_restart();
+ } else {
+ Start_name const start_name("editor");
+ _file_browser_state.text_area.construct(_child_states, start_name,
+ Ram_quota{16*1024*1024}, Cap_quota{250});
+ }
+ }
+
+ generate_runtime_config();
+ }
+
+ void view_file(File_browser_state::File const &file) override
+ {
+ _view_or_edit_file(file, false);
+ }
+
+ void edit_file(File_browser_state::File const &file) override
+ {
+ _view_or_edit_file(file, true);
+ }
+
+ void revert_edited_file() override
+ {
+ if (_file_browser_state.text_area.constructed())
+ _file_browser_state.text_area->trigger_restart();
+
+ generate_runtime_config();
+ }
+
+ void save_edited_file() override
+ {
+ _file_browser_state.save_version = _file_browser_state.last_saved_version + 1;
+ generate_runtime_config();
+ }
+
void _close_popup_dialog()
{
/* close popup menu */
@@ -584,7 +867,7 @@ struct Sculpt::Main : Input_event_handler,
_handle_window_layout();
/* reset state of the '+' button */
- _graph._gen_graph_dialog();
+ _graph_menu_view.generate();
}
/*
@@ -656,11 +939,42 @@ struct Sculpt::Main : Input_event_handler,
_runtime_state.with_construction([&] (Component const &c) { fn.with(c); });
}
- Popup_dialog _popup_dialog { _env, _heap, _launchers,
+ Panel_dialog _panel_dialog { *this };
+
+ Menu_view _panel_menu_view { _env, _child_states, _panel_dialog, "panel_view",
+ Ram_quota{4*1024*1024}, Cap_quota{150},
+ "panel_dialog", "panel_view_hover" };
+
+ Settings_dialog _settings_dialog { _font_size };
+
+ Menu_view _settings_menu_view { _env, _child_states, _settings_dialog, "settings_view",
+ Ram_quota{4*1024*1024}, Cap_quota{150},
+ "settings_dialog", "settings_view_hover" };
+
+ Menu_view _main_menu_view { _env, _child_states, *this, "menu_view",
+ Ram_quota{4*1024*1024}, Cap_quota{150},
+ "menu_dialog", "menu_view_hover" };
+
+ Popup_dialog _popup_dialog { _env, *this, _launchers,
_network._nic_state, _network._nic_target,
_runtime_state, _cached_runtime_config,
_download_queue, *this, *this };
+ Menu_view _popup_menu_view { _env, _child_states, _popup_dialog, "popup_view",
+ Ram_quota{4*1024*1024}, Cap_quota{150},
+ "popup_dialog", "popup_view_hover" };
+
+ File_browser_dialog _file_browser_dialog { _cached_runtime_config, _file_browser_state };
+
+ Menu_view _file_browser_menu_view { _env, _child_states, _file_browser_dialog, "file_browser_view",
+ Ram_quota{8*1024*1024}, Cap_quota{150},
+ "file_browser_dialog", "file_browser_view_hover" };
+
+ /**
+ * Popup_dialog::Refresh interface
+ */
+ void refresh_popup_dialog() override { _popup_menu_view.generate(); }
+
Managed_config _fb_drv_config {
_env, "config", "fb_drv", *this, &Main::_handle_fb_drv_config };
@@ -704,7 +1018,7 @@ struct Sculpt::Main : Input_event_handler,
*/
static Nitpicker::Root gui_nitpicker(_env, _heap, *this);
- _gui.generate_config();
+ generate_runtime_config();
}
void _handle_window_layout();
@@ -738,13 +1052,13 @@ struct Sculpt::Main : Input_event_handler,
Popup _popup { };
- Graph _graph { _env, _runtime_state, _cached_runtime_config,
- _storage._sculpt_partition, _popup.state, _deploy._children };
-
- Child_state _runtime_view_state {
- "runtime_view", Ram_quota{8*1024*1024}, Cap_quota{200} };
-
+ Graph _graph { _runtime_state, _cached_runtime_config, _storage._storage_devices,
+ _storage._sculpt_partition, _storage._ram_fs_state,
+ _popup.state, _deploy._children };
+ Menu_view _graph_menu_view { _env, _child_states, _graph, "runtime_view",
+ Ram_quota{8*1024*1024}, Cap_quota{200},
+ "runtime_dialog", "runtime_view_hover" };
Main(Env &env) : _env(env)
{
_manual_deploy_rom.sigh(_manual_deploy_handler);
@@ -757,12 +1071,12 @@ struct Sculpt::Main : Input_event_handler,
*/
_update_state_rom .sigh(_update_state_handler);
_nitpicker_hover .sigh(_nitpicker_hover_handler);
- _hover_rom .sigh(_hover_handler);
_pci_devices .sigh(_pci_devices_handler);
_window_list .sigh(_window_list_handler);
_decorator_margins .sigh(_decorator_margins_handler);
_launcher_listing_rom.sigh(_launcher_listing_handler);
_blueprint_rom .sigh(_blueprint_handler);
+ _editor_saved_rom .sigh(_editor_saved_handler);
/*
* Generate initial configurations
@@ -812,56 +1126,64 @@ void Sculpt::Main::_handle_window_layout()
_decorator_margins.update();
Decorator_margins const margins(_decorator_margins.xml());
- unsigned const log_min_w = 400, log_min_h = 200;
+ unsigned const log_min_w = 400;
if (!_nitpicker.constructed())
return;
+ typedef String<128> Label;
+ Label const
+ inspect_label ("runtime -> leitzentrale -> inspect"),
+ runtime_view_label ("runtime -> leitzentrale -> runtime_view"),
+ panel_view_label ("runtime -> leitzentrale -> panel_view"),
+ menu_view_label ("runtime -> leitzentrale -> menu_view"),
+ popup_view_label ("runtime -> leitzentrale -> popup_view"),
+ settings_view_label ("runtime -> leitzentrale -> settings_view"),
+ network_view_label ("runtime -> leitzentrale -> network_view"),
+ file_browser_view_label("runtime -> leitzentrale -> file_browser_view"),
+ editor_view_label ("runtime -> leitzentrale -> editor"),
+ logo_label ("logo");
+
+ _window_list.update();
+ Xml_node const window_list = _window_list.xml();
+
+ auto win_size = [&] (Xml_node win) {
+ return Area(win.attribute_value("width", 0UL),
+ win.attribute_value("height", 0UL)); };
+
+ unsigned panel_height = 0;
+ _with_window(window_list, panel_view_label, [&] (Xml_node win) {
+ panel_height = win_size(win).h(); });
+
+ /* suppress intermediate states during the restart of the panel */
+ if (panel_height == 0)
+ return;
+
Framebuffer::Mode const mode = _nitpicker->mode();
- /* area preserved for the menu */
- Rect const menu(Point(0, 0), Area(_gui.menu_width, mode.height()));
+ /* area reserved for the panel */
+ Rect const panel(Point(0, 0), Area(mode.width(), panel_height));
/* available space on the right of the menu */
- Rect avail(Point(_gui.menu_width, 0),
+ Rect avail(Point(0, panel.h()),
Point(mode.width() - 1, mode.height() - 1));
- /*
- * When the screen width is at least twice the log width, place the
- * log at the right side of the screen. Otherwise, with resolutions
- * as low as 1024x768, place it to the bottom to allow the inspect
- * window to use the available screen width to the maximum extend.
- */
- bool const log_at_right =
- (avail.w() > 2*(log_min_w + margins.left + margins.right));
+ Point const log_offset = _log_visible
+ ? Point(0, 0)
+ : Point(log_min_w + margins.left + margins.right, 0);
- /* the upper-left point depends on whether the log is at the right or bottom */
- Point const log_p1 =
- log_at_right ? Point(avail.x2() - log_min_w - margins.right + 1,
- margins.top)
- : Point(_gui.menu_width + margins.left,
- avail.y2() - log_min_h - margins.bottom + 1);
-
- /* the lower-right point (p2) of the log is always the same */
- Point const log_p2(mode.width() - margins.right - 1,
+ Point const log_p1(avail.x2() - log_min_w - margins.right + 1 + log_offset.x(),
+ avail.y1() + margins.top);
+ Point const log_p2(mode.width() - margins.right - 1 + log_offset.x(),
mode.height() - margins.bottom - 1);
/* position of the inspect window */
- Point const inspect_p1(avail.x1() + margins.right, margins.top);
+ Point const inspect_p1(avail.x1() + margins.left, avail.y1() + margins.top);
+ Point const inspect_p2(avail.x2() - margins.right - 1,
+ avail.y2() - margins.bottom - 1);
- Point const inspect_p2 =
- log_at_right ? Point(log_p1.x() - margins.right - margins.left - 1, log_p2.y())
- : Point(log_p2.x(), log_p1.y() - margins.bottom - margins.top - 1);
-
- typedef String<128> Label;
- Label const inspect_label ("runtime -> leitzentrale -> inspect");
- Label const runtime_view_label("runtime -> leitzentrale -> runtime_view");
-
- _window_list.update();
_window_layout.generate([&] (Xml_generator &xml) {
- Xml_node const window_list = _window_list.xml();
-
auto gen_window = [&] (Xml_node win, Rect rect) {
if (rect.valid()) {
xml.node("window", [&] () {
@@ -875,10 +1197,6 @@ void Sculpt::Main::_handle_window_layout()
}
};
- auto win_size = [&] (Xml_node win) {
- return Area(win.attribute_value("width", 0UL),
- win.attribute_value("height", 0UL)); };
-
/* window size limited to space unobstructed by the menu and log */
auto constrained_win_size = [&] (Xml_node win) {
@@ -889,8 +1207,62 @@ void Sculpt::Main::_handle_window_layout()
return Area(min(inspect_w, size.w()), min(inspect_h, size.h()));
};
- _with_window(window_list, Label("gui -> menu -> "), [&] (Xml_node win) {
- gen_window(win, menu); });
+ _with_window(window_list, panel_view_label, [&] (Xml_node win) {
+ gen_window(win, panel); });
+
+ _with_window(window_list, Label("log"), [&] (Xml_node win) {
+ gen_window(win, Rect(log_p1, log_p2)); });
+
+ _with_window(window_list, settings_view_label, [&] (Xml_node win) {
+ Area const size = win_size(win);
+ Point const pos = _settings_visible
+ ? Point(0, avail.y1())
+ : Point(-size.w(), avail.y1());
+ gen_window(win, Rect(pos, size));
+ });
+
+ _with_window(window_list, network_view_label, [&] (Xml_node win) {
+ Area const size = win_size(win);
+ Point const pos = _network_visible
+ ? Point(log_p1.x() - size.w(), avail.y1())
+ : Point(mode.width(), avail.y1());
+ gen_window(win, Rect(pos, size));
+ });
+
+ _with_window(window_list, file_browser_view_label, [&] (Xml_node win) {
+ if (_selected_tab == Panel_dialog::Tab::FILES) {
+
+ Area const size = constrained_win_size(win);
+ Point const pos = Rect(inspect_p1, inspect_p2).center(size);
+
+ Point const offset = _file_browser_state.text_area.constructed()
+ ? Point((2*avail.w())/3 - pos.x(), 0)
+ : Point(0, 0);
+
+ gen_window(win, Rect(pos - offset, size));
+ }
+ });
+
+ _with_window(window_list, editor_view_label, [&] (Xml_node win) {
+ if (_selected_tab == Panel_dialog::Tab::FILES) {
+ Area const size = constrained_win_size(win);
+ Point const pos = Rect(inspect_p1 + Point(400, 0), inspect_p2).center(size);
+
+ Point const offset = _file_browser_state.text_area.constructed()
+ ? Point(avail.w()/3 - pos.x(), 0)
+ : Point(0, 0);
+
+ gen_window(win, Rect(pos + offset, size));
+ }
+ });
+
+ _with_window(window_list, menu_view_label, [&] (Xml_node win) {
+ if (_selected_tab == Panel_dialog::Tab::COMPONENTS) {
+ Area const size = win_size(win);
+ Point const pos(0, avail.y2() - size.h());
+ gen_window(win, Rect(pos, size));
+ }
+ });
/*
* Calculate centered runtime view within the available main (inspect)
@@ -903,20 +1275,20 @@ void Sculpt::Main::_handle_window_layout()
});
if (_popup.state == Popup::VISIBLE) {
- _with_window(window_list, Label("gui -> popup -> "), [&] (Xml_node win) {
+ _with_window(window_list, popup_view_label, [&] (Xml_node win) {
Area const size = win_size(win);
int const anchor_y_center = (_popup.anchor.y1() + _popup.anchor.y2())/2;
int const x = runtime_view_pos.x() + _popup.anchor.x2();
- int const y = max(0, runtime_view_pos.y() + anchor_y_center - (int)size.h()/2);
+ int const y = max((int)panel_height, runtime_view_pos.y() + anchor_y_center - (int)size.h()/2);
gen_window(win, Rect(Point(x, y), size));
});
}
- if (_last_clicked == Hovered::STORAGE)
- _with_window(window_list, inspect_label, [&] (Xml_node win) {
+ _with_window(window_list, inspect_label, [&] (Xml_node win) {
+ if (_selected_tab == Panel_dialog::Tab::INSPECT)
gen_window(win, Rect(inspect_p1, inspect_p2)); });
/*
@@ -924,17 +1296,26 @@ void Sculpt::Main::_handle_window_layout()
* the overlapping of the log area. (use the menu view's 'win_size').
*/
_with_window(window_list, runtime_view_label, [&] (Xml_node win) {
- gen_window(win, Rect(runtime_view_pos, win_size(win))); });
+ if (_selected_tab == Panel_dialog::Tab::COMPONENTS)
+ gen_window(win, Rect(runtime_view_pos, win_size(win))); });
- _with_window(window_list, Label("log"), [&] (Xml_node win) {
- gen_window(win, Rect(log_p1, log_p2)); });
+ _with_window(window_list, logo_label, [&] (Xml_node win) {
+ Area const size = win_size(win);
+ Point const pos(mode.width() - size.w(), mode.height() - size.h());
+ gen_window(win, Rect(pos, size));
+ });
});
/* define window-manager focus */
_wm_focus.generate([&] (Xml_generator &xml) {
_window_list.xml().for_each_sub_node("window", [&] (Xml_node win) {
Label const label = win.attribute_value("label", Label());
- if (label == inspect_label)
+
+ if (label == inspect_label && _selected_tab == Panel_dialog::Tab::INSPECT)
+ xml.node("window", [&] () {
+ xml.attribute("id", win.attribute_value("id", 0UL)); });
+
+ if (label == editor_view_label && _selected_tab == Panel_dialog::Tab::FILES)
xml.node("window", [&] () {
xml.attribute("id", win.attribute_value("id", 0UL)); });
});
@@ -953,9 +1334,17 @@ void Sculpt::Main::_handle_nitpicker_mode()
if (!_fonts_config.try_generate_manually_managed()) {
- float const text_size = (float)mode.height() / 60.0;
+ _font_size_px = (float)mode.height() / 60.0;
- _gui.font_size(text_size);
+ if (_font_size == Font_size::SMALL) _font_size_px *= 0.85;
+ if (_font_size == Font_size::LARGE) _font_size_px *= 1.35;
+
+ Area const size(mode.width(), mode.height());
+ _screen_size = size;
+ _panel_menu_view.min_width = size.w();
+ unsigned const menu_width = max(_font_size_px*21, 320.0);
+ _main_menu_view.min_width = menu_width;
+ _network.min_dialog_width(menu_width);
_fonts_config.generate([&] (Xml_generator &xml) {
xml.attribute("copy", true);
@@ -977,10 +1366,10 @@ void Sculpt::Main::_handle_nitpicker_mode()
});
};
- gen_ttf_dir("title", "/Vera.ttf", text_size*1.25);
- gen_ttf_dir("text", "/Vera.ttf", text_size);
- gen_ttf_dir("annotation", "/Vera.ttf", text_size*0.8);
- gen_ttf_dir("monospace", "/VeraMono.ttf", text_size);
+ gen_ttf_dir("title", "/Vera.ttf", _font_size_px*1.25);
+ gen_ttf_dir("text", "/Vera.ttf", _font_size_px);
+ gen_ttf_dir("annotation", "/Vera.ttf", _font_size_px*0.8);
+ gen_ttf_dir("monospace", "/VeraMono.ttf", _font_size_px);
});
});
xml.node("default-policy", [&] () { xml.attribute("root", "/fonts"); });
@@ -1001,35 +1390,22 @@ void Sculpt::Main::_handle_nitpicker_mode()
});
}
- _gui.version.value++;
- _gui.generate_config();
+ /* font size may has changed */
+ _panel_menu_view.trigger_restart();
+ _main_menu_view.trigger_restart();
+ _file_browser_menu_view.trigger_restart();
+ _network.trigger_dialog_restart();
+ _graph_menu_view.trigger_restart();
+ _popup_menu_view.trigger_restart();
+ _settings_menu_view.trigger_restart();
+
+ generate_runtime_config();
}
-void Sculpt::Main::_handle_hover()
+Sculpt::Dialog::Hover_result Sculpt::Main::hover(Xml_node hover)
{
- _hover_rom.update();
- Xml_node const hover = _hover_rom.xml();
-
- Hovered::Dialog const orig_hovered_dialog = _hovered_dialog;
-
- typedef String<32> Top_level_frame;
- Top_level_frame const top_level_frame =
- query_attribute(hover, "dialog", "vbox", "frame", "name");
-
- _hovered_dialog = Hovered::NONE;
- if (top_level_frame == "network") _hovered_dialog = Hovered::NETWORK;
- if (top_level_frame == "storage") _hovered_dialog = Hovered::STORAGE;
- if (top_level_frame == "runtime") _hovered_dialog = Hovered::RUNTIME;
- if (top_level_frame == "logo") _hovered_dialog = Hovered::LOGO;
-
- if (orig_hovered_dialog != _hovered_dialog)
- _apply_to_hovered_dialog(orig_hovered_dialog, [&] (Dialog &dialog) {
- dialog.hover(Xml_node("")); });
-
- _apply_to_hovered_dialog(_hovered_dialog, [&] (Dialog &dialog) {
- dialog.hover(hover.sub_node("dialog").sub_node("vbox")
- .sub_node("frame")); });
+ return _storage.dialog.match_sub_dialog(hover, "vbox", "frame", "vbox");
}
@@ -1122,6 +1498,7 @@ void Sculpt::Main::_handle_runtime_state()
partition.check_in_progress = 0;
reconfigure_runtime = true;
_storage.dialog.reset_operation();
+ _graph.reset_operation();
}
}
@@ -1141,6 +1518,7 @@ void Sculpt::Main::_handle_runtime_state()
reconfigure_runtime = true;
_storage.dialog.reset_operation();
+ _graph.reset_operation();
}
}
@@ -1152,6 +1530,7 @@ void Sculpt::Main::_handle_runtime_state()
reconfigure_runtime = true;
device.rediscover();
_storage.dialog.reset_operation();
+ _graph.reset_operation();
}
}
@@ -1164,6 +1543,7 @@ void Sculpt::Main::_handle_runtime_state()
device.rediscover();
reconfigure_runtime = true;
_storage.dialog.reset_operation();
+ _graph.reset_operation();
}
}
@@ -1182,6 +1562,7 @@ void Sculpt::Main::_handle_runtime_state()
reconfigure_runtime = true;
_storage.dialog.reset_operation();
+ _graph.reset_operation();
}
}
@@ -1239,12 +1620,12 @@ void Sculpt::Main::_handle_runtime_state()
/* upgrade RAM and cap quota on demand */
state.for_each_sub_node("child", [&] (Xml_node child) {
- /* use binary OR (|), not logical OR (||), to always execute all elements */
- if (_storage._ram_fs_state.apply_child_state_report(child)
- | _deploy.cached_depot_rom_state.apply_child_state_report(child)
- | _deploy.uncached_depot_rom_state.apply_child_state_report(child)
- | _runtime_view_state.apply_child_state_report(child)) {
+ bool reconfiguration_needed = false;
+ _child_states.for_each([&] (Child_state &child_state) {
+ if (child_state.apply_child_state_report(child))
+ reconfiguration_needed = true; });
+ if (reconfiguration_needed) {
reconfigure_runtime = true;
regenerate_dialog = true;
}
@@ -1261,8 +1642,10 @@ void Sculpt::Main::_handle_runtime_state()
regenerate_dialog = true;
}
- if (regenerate_dialog)
+ if (regenerate_dialog) {
generate_dialog();
+ _graph_menu_view.generate();
+ }
if (reconfigure_runtime)
generate_runtime_config();
@@ -1311,9 +1694,17 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
});
xml.node("start", [&] () {
- gen_runtime_view_start_content(xml, _runtime_view_state, _gui.font_size()); });
+ gen_runtime_view_start_content(xml, _graph_menu_view._child_state, _font_size_px); });
+
+ _panel_menu_view.gen_start_node(xml);
+ _main_menu_view.gen_start_node(xml);
+ _settings_menu_view.gen_start_node(xml);
+ _network._menu_view.gen_start_node(xml);
+ _popup_menu_view.gen_start_node(xml);
+ _file_browser_menu_view.gen_start_node(xml);
_storage.gen_runtime_start_nodes(xml);
+ _file_browser_state.gen_start_nodes(xml);
/*
* Load configuration and update depot config on the sculpt partition
diff --git a/repos/gems/src/app/sculpt_manager/menu_view.cc b/repos/gems/src/app/sculpt_manager/menu_view.cc
new file mode 100644
index 000000000..7f5ae8d15
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/menu_view.cc
@@ -0,0 +1,152 @@
+/*
+ * \brief Menu-view dialog handling
+ * \author Norman Feske
+ * \date 2018-05-18
+ */
+
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include
+
+using namespace Sculpt;
+
+
+void Menu_view::_handle_hover()
+{
+ using Hover_result = Dialog::Hover_result;
+
+ _hover_rom.update();
+
+ bool const orig_hovered = _hovered;
+
+ _hovered = false;
+
+ Hover_result hover_result = Hover_result::UNMODIFIED;
+
+ _hover_rom.xml().with_sub_node("dialog", [&] (Xml_node hover) {
+ _hovered = true;
+ hover_result = _dialog.hover(hover);
+ });
+
+ if (!_hovered)
+ _dialog.hover(Xml_node(""));
+
+ bool const dialog_hover_changed = (_hovered != orig_hovered),
+ widget_hover_changed = (hover_result == Hover_result::CHANGED);
+
+ if (dialog_hover_changed || widget_hover_changed)
+ generate();
+}
+
+
+Menu_view::Menu_view(Env &env, Registry ®istry,
+ Dialog &dialog, Start_name const &name,
+ Ram_quota ram_quota, Cap_quota cap_quota,
+ Session_label const &dialog_report_name,
+ Session_label const &hover_rom_name)
+:
+ _dialog(dialog),
+ _child_state(registry, name, ram_quota, cap_quota),
+ _dialog_reporter(env, "dialog", dialog_report_name.string()),
+ _hover_rom(env, hover_rom_name.string()),
+ _hover_handler(env.ep(), *this, &Menu_view::_handle_hover)
+{
+ _hover_rom.sigh(_hover_handler);
+
+ generate();
+}
+
+
+void Menu_view::generate()
+{
+ _dialog_reporter.generate([&] (Xml_generator &xml) {
+ _dialog.generate(xml); });
+}
+
+
+void Menu_view::reset()
+{
+ _hovered = false;
+ _dialog.hover(Xml_node(""));
+ _dialog.reset();
+}
+
+
+void Menu_view::gen_start_node(Xml_generator &xml) const
+{
+ xml.node("start", [&] () {
+ _gen_start_node_content(xml); });
+}
+
+
+void Menu_view::_gen_start_node_content(Xml_generator &xml) const
+{
+ _child_state.gen_start_node_content(xml);
+
+ gen_named_node(xml, "binary", "menu_view");
+
+ xml.node("config", [&] () {
+ if (min_width) xml.attribute("width", min_width);
+ if (min_height) xml.attribute("height", min_height);
+
+ xml.node("libc", [&] () { xml.attribute("stderr", "/dev/log"); });
+ xml.node("report", [&] () { xml.attribute("hover", "yes"); });
+ xml.node("vfs", [&] () {
+ gen_named_node(xml, "tar", "menu_view_styles.tar");
+
+ gen_named_node(xml, "dir", "fonts", [&] () {
+ xml.node("fs", [&] () {
+ xml.attribute("label", "fonts"); }); });
+
+ gen_named_node(xml, "dir", "dev", [&] () {
+ xml.node("log", [&] () { }); });
+ });
+ });
+
+ xml.node("route", [&] () {
+ gen_parent_rom_route(xml, "menu_view");
+ gen_parent_rom_route(xml, "ld.lib.so");
+ gen_parent_rom_route(xml, "vfs.lib.so");
+ gen_parent_rom_route(xml, "libc.lib.so");
+ gen_parent_rom_route(xml, "libm.lib.so");
+ gen_parent_rom_route(xml, "libpng.lib.so");
+ gen_parent_rom_route(xml, "zlib.lib.so");
+ gen_parent_rom_route(xml, "menu_view_styles.tar");
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+
+ using Label = String<128>;
+
+ Label const label = _child_state.name();
+
+ gen_service_node(xml, [&] () {
+ xml.node("parent", [&] () {
+ xml.attribute("label", Label("leitzentrale -> ", label)); }); });
+
+ gen_service_node(xml, [&] () {
+ xml.attribute("label", "dialog");
+ xml.node("parent", [&] () {
+ xml.attribute("label", Label("leitzentrale -> ", label, " -> dialog"));
+ });
+ });
+
+ gen_service_node(xml, [&] () {
+ xml.attribute("label", "hover");
+ xml.node("parent", [&] () {
+ xml.attribute("label", Label("leitzentrale -> ", label, " -> hover"));
+ });
+ });
+
+ gen_service_node<::File_system::Session>(xml, [&] () {
+ xml.attribute("label", "fonts");
+ xml.node("parent", [&] () {
+ xml.attribute("label", "leitzentrale -> fonts"); }); });
+ });
+}
diff --git a/repos/gems/src/app/sculpt_manager/menu_view.h b/repos/gems/src/app/sculpt_manager/menu_view.h
new file mode 100644
index 000000000..b74383512
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/menu_view.h
@@ -0,0 +1,72 @@
+/*
+ * \brief Menu-view dialog handling
+ * \author Norman Feske
+ * \date 2018-05-18
+ */
+
+/*
+ * Copyright (C) 2018 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 _MENU_VIEW_H_
+#define _MENU_VIEW_H_
+
+/* Genode includes */
+#include
+#include
+#include
+
+/* local includes */
+#include "types.h"
+#include
+#include
+
+namespace Sculpt { struct Menu_view; }
+
+
+struct Sculpt::Menu_view : Noncopyable
+{
+ Dialog &_dialog;
+
+ Child_state _child_state;
+
+ Expanding_reporter _dialog_reporter;
+
+ Attached_rom_dataspace _hover_rom;
+
+ Signal_handler _hover_handler;
+
+ bool _hovered = false;
+
+ unsigned min_width = 0;
+ unsigned min_height = 0;
+
+ void _handle_hover();
+
+ void _gen_start_node_content(Xml_generator &) const;
+
+ Menu_view(Env &, Registry ®istry,
+ Dialog &, Start_name const &, Ram_quota, Cap_quota,
+ Session_label const &dialog_report_name,
+ Session_label const &hover_rom_name);
+
+ void generate();
+
+ bool hovered() const { return _hovered; }
+
+ void reset();
+
+ void gen_start_node(Xml_generator &) const;
+
+ bool apply_child_state_report(Xml_node report)
+ {
+ return _child_state.apply_child_state_report(report);
+ }
+
+ void trigger_restart() { _child_state.trigger_restart(); }
+};
+
+#endif /* _MENU_VIEW_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/model/child_state.h b/repos/gems/src/app/sculpt_manager/model/child_state.h
index 30a300388..50dd81980 100644
--- a/repos/gems/src/app/sculpt_manager/model/child_state.h
+++ b/repos/gems/src/app/sculpt_manager/model/child_state.h
@@ -16,6 +16,7 @@
/* Genode includes */
#include
+#include
/* local includes */
#include "types.h"
@@ -26,6 +27,8 @@ struct Sculpt::Child_state : Noncopyable
{
private:
+ Registry::Element _element;
+
Start_name const _name;
Ram_quota const _initial_ram_quota;
@@ -44,9 +47,10 @@ struct Sculpt::Child_state : Noncopyable
* \param ram_quota initial RAM quota
* \param cap_quota initial capability quota
*/
- Child_state(Start_name const &name,
+ Child_state(Registry ®istry, Start_name const &name,
Ram_quota ram_quota, Cap_quota cap_quota)
:
+ _element(registry, *this),
_name(name),
_initial_ram_quota(ram_quota), _initial_cap_quota(cap_quota)
{ }
@@ -58,12 +62,17 @@ struct Sculpt::Child_state : Noncopyable
_cap_quota = _initial_cap_quota;
}
+ void gen_start_node_version(Xml_generator &xml) const
+ {
+ if (_version.value)
+ xml.attribute("version", _version.value);
+ }
+
void gen_start_node_content(Xml_generator &xml) const
{
xml.attribute("name", _name);
- if (_version.value)
- xml.attribute("version", _version.value);
+ gen_start_node_version(xml);
xml.attribute("caps", _cap_quota.value);
gen_named_node(xml, "resource", "RAM", [&] () {
@@ -102,6 +111,8 @@ struct Sculpt::Child_state : Noncopyable
}
Ram_quota ram_quota() const { return _ram_quota; }
+
+ Start_name name() const { return _name; }
};
#endif /* _MODEL__CHILD_STATE_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/model/file_browser_state.h b/repos/gems/src/app/sculpt_manager/model/file_browser_state.h
new file mode 100644
index 000000000..c094477a7
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/model/file_browser_state.h
@@ -0,0 +1,217 @@
+/*
+ * \brief File_browser state
+ * \author Norman Feske
+ * \date 2020-01-31
+ */
+
+/*
+ * Copyright (C) 2020 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__FILE_BROWSER_STATE_H_
+#define _MODEL__FILE_BROWSER_STATE_H_
+
+#include "types.h"
+#include
+
+namespace Sculpt { struct File_browser_state; }
+
+struct Sculpt::File_browser_state : Noncopyable
+{
+ using Fs_name = Start_name;
+ using Path = String<256>;
+ using File = Path;
+ using Sub_dir = Path;
+
+ Fs_name browsed_fs { };
+
+ Constructible fs_query { };
+ Constructible text_area { };
+
+ Constructible query_result { };
+
+ File_browser_state() { };
+
+ Path path { };
+
+ /*
+ * File viewing and editing
+ */
+
+ File edited_file { };
+
+ bool edit = false;
+ bool modified = false; /* edited file has unsaved modifications */
+ unsigned save_version = 0; /* version used for next save request */
+ unsigned last_saved_version = 0; /* last version successfully saved */
+
+ void update_query_results()
+ {
+ if (query_result.constructed())
+ query_result->update();
+ }
+
+ template
+ void with_query_result(FN const &fn) const
+ {
+ if (query_result.constructed())
+ fn(query_result->xml());
+ }
+
+ using Index = Label;
+
+ template
+ void with_entry_at_index(Index index, FN const &fn) const
+ {
+ unsigned cnt = 0;
+ with_query_result([&] (Xml_node node) {
+ node.with_sub_node("dir", [&] (Xml_node listing) {
+ listing.for_each_sub_node([&] (Xml_node entry) {
+ if (Index(cnt++) == index)
+ fn(entry); }); }); });
+ }
+
+ bool any_browsed_fs() const { return browsed_fs.length() > 0; }
+
+ void gen_start_nodes(Xml_generator &xml) const
+ {
+ if (!fs_query.constructed() || !any_browsed_fs())
+ return;
+
+ xml.node("start", [&] () {
+ fs_query->gen_start_node_content(xml);
+
+ gen_named_node(xml, "binary", "fs_query");
+
+ xml.node("config", [&] () {
+ xml.node("vfs", [&] () {
+ xml.node("fs", [&] () {}); });
+
+ xml.node("query", [&] () {
+ xml.attribute("path", path);
+ });
+ });
+
+ xml.node("route", [&] () {
+ gen_parent_rom_route(xml, "fs_query");
+ gen_parent_rom_route(xml, "ld.lib.so");
+ gen_parent_rom_route(xml, "vfs.lib.so");
+
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+
+ gen_service_node<::File_system::Session>(xml, [&] () {
+
+ if (browsed_fs == "config") {
+ xml.node("parent", [&] () {
+ xml.attribute("label", "config"); });
+ }
+ else if (browsed_fs == "report") {
+ xml.node("parent", [&] () {
+ xml.attribute("label", "report"); });
+ }
+ else {
+ xml.node("child", [&] () {
+ xml.attribute("name", browsed_fs); });
+ }
+ });
+ });
+ });
+
+ if (edited_file.length() <= 1 || !text_area.constructed())
+ return;
+
+ xml.node("start", [&] () {
+ xml.attribute("name", text_area->name());
+
+ text_area->gen_start_node_version(xml);
+
+ xml.attribute("caps", 350);
+ gen_named_node(xml, "resource", "RAM", [&] () {
+ xml.attribute("quantum", String<64>(22*1024*1024UL)); });
+
+ gen_named_node(xml, "binary", "text_area");
+
+ xml.node("config", [&] () {
+ Path const file_path = (path == "/")
+ ? Path("/", edited_file)
+ : Path(path, "/", edited_file);
+ xml.attribute("path", file_path);
+ xml.attribute("max_lines", 40);
+ xml.attribute("min_width", 600);
+ xml.attribute("copy", "yes");
+
+ if (edit)
+ xml.attribute("paste", "yes");
+ else
+ xml.attribute("watch", "yes");
+
+ if (edit) {
+ xml.node("save", [&] () {
+ xml.attribute("version", save_version); });
+
+ xml.node("report", [&] () {
+ xml.attribute("saved", "yes"); });
+ }
+
+ xml.node("vfs", [&] () {
+ xml.node("fs", [&] () {}); });
+ });
+
+ xml.node("route", [&] () {
+ gen_parent_rom_route(xml, "text_area");
+ gen_parent_rom_route(xml, "ld.lib.so");
+ gen_parent_rom_route(xml, "vfs.lib.so");
+ gen_parent_rom_route(xml, "sandbox.lib.so");
+ gen_parent_rom_route(xml, "menu_view");
+ gen_parent_rom_route(xml, "libc.lib.so");
+ gen_parent_rom_route(xml, "libm.lib.so");
+ gen_parent_rom_route(xml, "libpng.lib.so");
+ gen_parent_rom_route(xml, "zlib.lib.so");
+ gen_parent_rom_route(xml, "menu_view_styles.tar");
+
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+ gen_parent_route (xml);
+
+ gen_service_node(xml, [&] () {
+ xml.attribute("label", "clipboard");
+ xml.node("parent", [&] () { }); });
+
+ gen_service_node(xml, [&] () {
+ xml.node("parent", [&] () {
+ xml.attribute("label", Label("leitzentrale -> editor")); }); });
+
+ gen_service_node<::File_system::Session>(xml, [&] () {
+ xml.attribute("label", "fonts");
+ xml.node("parent", [&] () {
+ xml.attribute("label", "leitzentrale -> fonts"); }); });
+
+ gen_service_node<::File_system::Session>(xml, [&] () {
+
+ if (browsed_fs == "config") {
+ xml.node("parent", [&] () {
+ xml.attribute("label", "config"); });
+ }
+ else if (browsed_fs == "report") {
+ xml.node("parent", [&] () {
+ xml.attribute("label", "report"); });
+ }
+ else {
+ xml.node("child", [&] () {
+ xml.attribute("name", browsed_fs); });
+ }
+ });
+ });
+ });
+ }
+};
+
+#endif /* _MODEL__FILE_BROWSER_STATE_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/model/partition.h b/repos/gems/src/app/sculpt_manager/model/partition.h
index 5d4941dbc..9a0657e81 100644
--- a/repos/gems/src/app/sculpt_manager/model/partition.h
+++ b/repos/gems/src/app/sculpt_manager/model/partition.h
@@ -31,6 +31,8 @@ struct Sculpt::File_system
{
enum Type { UNKNOWN, EXT2, FAT32, GEMDOS } type;
+ bool inspected = false;
+
bool accessible() const { return type == EXT2 || type == FAT32 || type == GEMDOS; }
bool expandable() const { return type == EXT2; }
@@ -58,7 +60,6 @@ struct Sculpt::Partition : List_model::Element
bool check_in_progress = false;
bool format_in_progress = false;
- bool file_system_inspected = false;
bool gpt_expand_in_progress = false;
bool fs_resize_in_progress = false;
@@ -76,7 +77,7 @@ struct Sculpt::Partition : List_model::Element
bool idle() const { return !check_in_progress
&& !format_in_progress
- && !file_system_inspected
+ && !file_system.inspected
&& !relabel_in_progress(); }
bool genode_default() const { return label == "GENODE*"; }
diff --git a/repos/gems/src/app/sculpt_manager/model/ram_fs_state.h b/repos/gems/src/app/sculpt_manager/model/ram_fs_state.h
index a3789cb00..85d7bd852 100644
--- a/repos/gems/src/app/sculpt_manager/model/ram_fs_state.h
+++ b/repos/gems/src/app/sculpt_manager/model/ram_fs_state.h
@@ -20,15 +20,17 @@
/* local includes */
#include
#include
+#include
namespace Sculpt { struct Ram_fs_state; }
-struct Sculpt::Ram_fs_state : Child_state
+struct Sculpt::Ram_fs_state : Child_state, File_system
{
- bool inspected = false;
-
- Ram_fs_state(Start_name const &name)
- : Child_state(name, Ram_quota{1024*1024}, Cap_quota{300}) { }
+ Ram_fs_state(Registry ®istry, Start_name const &name)
+ :
+ Child_state(registry, name, Ram_quota{1024*1024}, Cap_quota{300}),
+ File_system(File_system::UNKNOWN)
+ { }
};
#endif /* _MODEL__RAM_FS_STATE_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/model/runtime_config.h b/repos/gems/src/app/sculpt_manager/model/runtime_config.h
index fa86ce574..c9eec3aae 100644
--- a/repos/gems/src/app/sculpt_manager/model/runtime_config.h
+++ b/repos/gems/src/app/sculpt_manager/model/runtime_config.h
@@ -69,9 +69,7 @@ class Sculpt::Runtime_config
if (ignored_service)
return;
- bool const hardware = (service == "Block")
- || (service == "USB")
- || (service == "Platform")
+ bool const hardware = (service == "Platform")
|| (service == "IO_PORT")
|| (service == "IO_MEM")
|| (service == "Rtc")
@@ -82,6 +80,18 @@ class Sculpt::Runtime_config
return;
}
+ bool const usb = (service == "Usb");
+ if (usb) {
+ result = "usb";
+ return;
+ }
+
+ bool const storage = (service == "Block");
+ if (storage) {
+ result = "storage";
+ return;
+ }
+
if (service == "ROM") {
/*
@@ -347,6 +357,10 @@ class Sculpt::Runtime_config
} _parent_services { };
+ Service const _used_fs_service { "default_fs_rw",
+ Service::Type::FILE_SYSTEM,
+ Label(), "used file system" };
+
public:
Runtime_config(Allocator &alloc) : _alloc(alloc) { }
@@ -375,10 +389,12 @@ class Sculpt::Runtime_config
template
void for_each_service(FN const &fn) const
{
+ _parent_services.for_each(fn);
+
+ fn(_used_fs_service);
+
_components.for_each([&] (Component const &component) {
component.for_each_service(fn); });
-
- _parent_services.for_each(fn);
}
};
diff --git a/repos/gems/src/app/sculpt_manager/model/runtime_state.h b/repos/gems/src/app/sculpt_manager/model/runtime_state.h
index 5c6e9119a..be182fc97 100644
--- a/repos/gems/src/app/sculpt_manager/model/runtime_state.h
+++ b/repos/gems/src/app/sculpt_manager/model/runtime_state.h
@@ -70,6 +70,9 @@ class Sculpt::Runtime_state : public Runtime_info
List_model _children { };
+ bool _usb_in_tcb = false;
+ bool _storage_in_tcb = false;
+
/**
* Child present in initial deploy config but interactively removed
*/
@@ -264,6 +267,9 @@ class Sculpt::Runtime_state : public Runtime_info
return result;
}
+ bool usb_in_tcb() const { return _usb_in_tcb; }
+ bool storage_in_tcb() const { return _storage_in_tcb; }
+
static bool blacklisted_from_graph(Start_name const &name)
{
/*
@@ -281,6 +287,8 @@ class Sculpt::Runtime_state : public Runtime_info
child.info.tcb_updated = false;
});
+ _usb_in_tcb = _storage_in_tcb = false;
+
/*
* Update the TCB flag of the selected child's transitive
* dependencies.
@@ -315,6 +323,15 @@ class Sculpt::Runtime_state : public Runtime_info
child.info.tcb = true; });
});
}
+
+ _children.for_each([&] (Child const &child) {
+ if (child.info.tcb) {
+ config.for_each_dependency(child.name, [&] (Start_name dep) {
+ if (dep == "usb") _usb_in_tcb = true;
+ if (dep == "storage") _storage_in_tcb = true;
+ });
+ }
+ });
}
void abandon(Start_name const &name)
diff --git a/repos/gems/src/app/sculpt_manager/model/service.h b/repos/gems/src/app/sculpt_manager/model/service.h
index 0267b6e2c..a57aa6b69 100644
--- a/repos/gems/src/app/sculpt_manager/model/service.h
+++ b/repos/gems/src/app/sculpt_manager/model/service.h
@@ -72,6 +72,12 @@ struct Sculpt::Service
Service(Start_name const &server, Type type, Label const &label)
: server(server), type(type), label(label), info(Subst("_", " ", server)) { }
+ /**
+ * Constructor for default_fs_rw
+ */
+ Service(Start_name const &server, Type type, Label const &label, Info const &info)
+ : server(server), type(type), label(label), info(info) { }
+
/**
* Constructor for parent service
*/
diff --git a/repos/gems/src/app/sculpt_manager/model/settings.h b/repos/gems/src/app/sculpt_manager/model/settings.h
new file mode 100644
index 000000000..4f82e6419
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/model/settings.h
@@ -0,0 +1,23 @@
+/*
+ * \brief Settings state
+ * \author Norman Feske
+ * \date 2020-01-30
+ */
+
+/*
+ * Copyright (C) 2020 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__SETTINGS_H_
+#define _MODEL__SETTINGS_H_
+
+#include "types.h"
+
+namespace Sculpt { enum class Font_size; }
+
+enum class Sculpt::Font_size { SMALL, MEDIUM, LARGE };
+
+#endif /* _MODEL__SETTINGS_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/model/storage_device.h b/repos/gems/src/app/sculpt_manager/model/storage_device.h
index 95762972f..721496bce 100644
--- a/repos/gems/src/app/sculpt_manager/model/storage_device.h
+++ b/repos/gems/src/app/sculpt_manager/model/storage_device.h
@@ -83,7 +83,7 @@ struct Sculpt::Storage_device
*
* Ignore reports that come in while the device is in use. Otherwise,
* the reconstruction of 'whole_device_partition' would wrongly reset
- * the partition state such as the 'file_system_inspected' flag.
+ * the partition state such as the 'file_system.inspected' flag.
*/
if (!whole_device_partition.constructed() || whole_device_partition->idle()) {
whole_device_partition.construct(Partition::Args::whole_device(capacity));
@@ -130,7 +130,7 @@ struct Sculpt::Storage_device
partitions.for_each([&] (Partition const &partition) {
needed_for_access |= partition.check_in_progress;
needed_for_access |= partition.format_in_progress;
- needed_for_access |= partition.file_system_inspected;
+ needed_for_access |= partition.file_system.inspected;
needed_for_access |= partition.fs_resize_in_progress;
});
diff --git a/repos/gems/src/app/sculpt_manager/model/storage_devices.h b/repos/gems/src/app/sculpt_manager/model/storage_devices.h
index e6051470a..ca69af954 100644
--- a/repos/gems/src/app/sculpt_manager/model/storage_devices.h
+++ b/repos/gems/src/app/sculpt_manager/model/storage_devices.h
@@ -29,6 +29,8 @@ struct Sculpt::Storage_devices
bool _block_devices_report_valid = false;
bool _usb_active_config_valid = false;
+ bool usb_present = false;
+
/**
* Update 'block_devices' from 'block_devices' report
*/
@@ -51,6 +53,10 @@ struct Sculpt::Storage_devices
if (node.has_type("raw"))
_usb_active_config_valid = true;
+
+ usb_present = false;
+ usb_storage_devices.for_each([&] (Storage_device const &) {
+ usb_present = true; });
}
/**
diff --git a/repos/gems/src/app/sculpt_manager/model/usb_storage_device.h b/repos/gems/src/app/sculpt_manager/model/usb_storage_device.h
index 6e89452ab..faf5428cd 100644
--- a/repos/gems/src/app/sculpt_manager/model/usb_storage_device.h
+++ b/repos/gems/src/app/sculpt_manager/model/usb_storage_device.h
@@ -74,7 +74,7 @@ struct Sculpt::Usb_storage_device : List_model::Element,
for_each_partition([&] (Partition const &partition) {
drv_needed |= partition.check_in_progress
|| partition.format_in_progress
- || partition.file_system_inspected
+ || partition.file_system.inspected
|| partition.relabel_in_progress()
|| partition.expand_in_progress(); });
@@ -123,6 +123,10 @@ void Sculpt::Usb_storage_device::gen_usb_block_drv_start_content(Xml_generator &
gen_provides(xml);
xml.node("route", [&] () {
+ gen_service_node(xml, [&] () {
+ xml.node("parent", [&] () {
+ xml.attribute("label", label); }); });
+
gen_parent_rom_route(xml, "usb_block_drv");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route (xml);
@@ -130,10 +134,6 @@ void Sculpt::Usb_storage_device::gen_usb_block_drv_start_content(Xml_generator &
gen_parent_route (xml);
gen_parent_route (xml);
- gen_service_node(xml, [&] () {
- xml.node("parent", [&] () {
- xml.attribute("label", label); }); });
-
gen_service_node(xml, [&] () {
xml.node("parent", [&] () { }); });
});
diff --git a/repos/gems/src/app/sculpt_manager/network.cc b/repos/gems/src/app/sculpt_manager/network.cc
index 1aaeb17b2..f3ba783dc 100644
--- a/repos/gems/src/app/sculpt_manager/network.cc
+++ b/repos/gems/src/app/sculpt_manager/network.cc
@@ -50,7 +50,7 @@ void Sculpt::Network::handle_key_press(Codepoint code)
if (_wifi_connection.state == Wifi_connection::CONNECTING)
wifi_connect(_wifi_connection.bssid);
- _dialog_generator.generate_dialog();
+ _menu_view.generate();
}
@@ -136,7 +136,7 @@ void Sculpt::Network::_handle_wlan_accesspoints()
Access_point_update_policy policy(_alloc);
_access_points.update_from_xml(policy, _wlan_accesspoints_rom.xml());
- _dialog_generator.generate_dialog();
+ _menu_view.generate();
}
@@ -144,7 +144,7 @@ void Sculpt::Network::_handle_wlan_state()
{
_wlan_state_rom.update();
_wifi_connection = Wifi_connection::from_xml(_wlan_state_rom.xml());
- _dialog_generator.generate_dialog();
+ _menu_view.generate();
}
@@ -156,7 +156,7 @@ void Sculpt::Network::_handle_nic_router_state()
_nic_state = Nic_state::from_xml(_nic_router_state_rom.xml());
if (_nic_state.ipv4 != old_nic_state.ipv4)
- _dialog_generator.generate_dialog();
+ _menu_view.generate();
/* if the nic state becomes ready, consider spawning the update subsystem */
if (old_nic_state.ready() != _nic_state.ready())
@@ -210,7 +210,7 @@ void Sculpt::Network::_handle_nic_router_config(Xml_node config)
nic_target(target);
_generate_nic_router_config();
_runtime_config_generator.generate_runtime_config();
- _dialog_generator.generate_dialog();
+ _menu_view.generate();
}
diff --git a/repos/gems/src/app/sculpt_manager/network.h b/repos/gems/src/app/sculpt_manager/network.h
index 0608be3d0..a3b569f33 100644
--- a/repos/gems/src/app/sculpt_manager/network.h
+++ b/repos/gems/src/app/sculpt_manager/network.h
@@ -21,7 +21,7 @@
/* local includes */
#include
#include
-#include
+#include
#include
#include
#include
@@ -35,7 +35,7 @@ struct Sculpt::Network : Network_dialog::Action
Allocator &_alloc;
- Dialog::Generator &_dialog_generator;
+ Registry &_child_states;
Runtime_config_generator &_runtime_config_generator;
@@ -97,10 +97,22 @@ struct Sculpt::Network : Network_dialog::Action
Network_dialog::WLAN_CONFIG_MANAGED;
Network_dialog dialog {
- _env, _dialog_generator, _nic_target, _access_points,
+ _nic_target, _access_points,
_wifi_connection, _nic_state, wpa_passphrase, _wlan_config_policy,
_pci_info };
+ Menu_view _menu_view { _env, _child_states, dialog, "network_view",
+ Ram_quota{4*1024*1024}, Cap_quota{150},
+ "network_dialog", "network_view_hover" };
+
+ void min_dialog_width(unsigned value) { _menu_view.min_width = value; }
+
+ bool dialog_hovered() const { return _menu_view.hovered(); }
+
+ void update_view() { _menu_view.generate(); }
+
+ void trigger_dialog_restart() { _menu_view.trigger_restart(); }
+
Managed_config _wlan_config {
_env, "config", "wifi", *this, &Network::_handle_wlan_config };
@@ -108,7 +120,7 @@ struct Sculpt::Network : Network_dialog::Action
{
if (_wlan_config.try_generate_manually_managed()) {
_wlan_config_policy = Network_dialog::WLAN_CONFIG_MANUAL;
- _dialog_generator.generate_dialog();
+ _menu_view.generate();
return;
}
@@ -142,7 +154,7 @@ struct Sculpt::Network : Network_dialog::Action
_nic_target.managed_type = type;
_generate_nic_router_config();
_runtime_config_generator.generate_runtime_config();
- _dialog_generator.generate_dialog();
+ _menu_view.generate();
}
}
@@ -207,11 +219,11 @@ struct Sculpt::Network : Network_dialog::Action
_runtime_config_generator.generate_runtime_config();
}
- Network(Env &env, Allocator &alloc, Dialog::Generator &dialog_generator,
+ Network(Env &env, Allocator &alloc, Registry &child_states,
Runtime_config_generator &runtime_config_generator,
Runtime_info const &runtime_info, Pci_info const &pci_info)
:
- _env(env), _alloc(alloc), _dialog_generator(dialog_generator),
+ _env(env), _alloc(alloc), _child_states(child_states),
_runtime_config_generator(runtime_config_generator),
_runtime_info(runtime_info), _pci_info(pci_info)
{
diff --git a/repos/gems/src/app/sculpt_manager/runtime/file_browser.cc b/repos/gems/src/app/sculpt_manager/runtime/file_browser.cc
index 7db7fcc13..d3d568225 100644
--- a/repos/gems/src/app/sculpt_manager/runtime/file_browser.cc
+++ b/repos/gems/src/app/sculpt_manager/runtime/file_browser.cc
@@ -20,7 +20,7 @@ namespace Sculpt {
{
devices.for_each([&] (Storage_device const &device) {
device.for_each_partition([&] (Partition const &partition) {
- if (partition.file_system_inspected)
+ if (partition.file_system.inspected)
fn(Storage_target { device.label, partition.number }); }); });
}
diff --git a/repos/gems/src/app/sculpt_manager/runtime/runtime_view.cc b/repos/gems/src/app/sculpt_manager/runtime/runtime_view.cc
index 062d9cecc..0e5d1f2d0 100644
--- a/repos/gems/src/app/sculpt_manager/runtime/runtime_view.cc
+++ b/repos/gems/src/app/sculpt_manager/runtime/runtime_view.cc
@@ -52,11 +52,13 @@ void Sculpt::gen_runtime_view_start_content(Xml_generator &xml,
gen_service_node(xml, [&] () {
xml.attribute("label", "dialog");
- xml.node("parent", [&] () { }); });
+ xml.node("parent", [&] () {
+ xml.attribute("label", "leitzentrale -> runtime_view -> dialog"); }); });
gen_service_node(xml, [&] () {
xml.attribute("label", "hover");
- xml.node("parent", [&] () { }); });
+ xml.node("parent", [&] () {
+ xml.attribute("label", "leitzentrale -> runtime_view -> hover"); }); });
gen_parent_rom_route(xml, "menu_view");
gen_parent_rom_route(xml, "ld.lib.so");
diff --git a/repos/gems/src/app/sculpt_manager/storage.cc b/repos/gems/src/app/sculpt_manager/storage.cc
index e24688818..b5f42ff58 100644
--- a/repos/gems/src/app/sculpt_manager/storage.cc
+++ b/repos/gems/src/app/sculpt_manager/storage.cc
@@ -140,7 +140,7 @@ void Sculpt::Storage::gen_runtime_start_nodes(Xml_generator &xml) const
gen_resize2fs_start_content(xml, target); }); }
if (partition.file_system.type != File_system::UNKNOWN) {
- if (partition.file_system_inspected || target == _sculpt_partition)
+ if (partition.file_system.inspected || target == _sculpt_partition)
xml.node("start", [&] () {
gen_fs_start_content(xml, target, partition.file_system.type); });
diff --git a/repos/gems/src/app/sculpt_manager/storage.h b/repos/gems/src/app/sculpt_manager/storage.h
index a65a35044..6c1bad0eb 100644
--- a/repos/gems/src/app/sculpt_manager/storage.h
+++ b/repos/gems/src/app/sculpt_manager/storage.h
@@ -21,12 +21,13 @@
/* local includes */
#include
#include
+#include
#include
namespace Sculpt { struct Storage; }
-struct Sculpt::Storage : Storage_dialog::Action
+struct Sculpt::Storage : Storage_dialog::Action, Ram_fs_dialog::Action
{
Env &_env;
@@ -49,7 +50,7 @@ struct Sculpt::Storage : Storage_dialog::Action
Storage_devices _storage_devices { };
- Ram_fs_state _ram_fs_state { "ram_fs" };
+ Ram_fs_state _ram_fs_state;
Storage_target _sculpt_partition { };
@@ -57,8 +58,7 @@ struct Sculpt::Storage : Storage_dialog::Action
File_browser_version _file_browser_version { 0 };
- Storage_dialog dialog {
- _env, _dialog_generator, _storage_devices, _ram_fs_state, _sculpt_partition };
+ Storage_dialog dialog { _storage_devices, _sculpt_partition };
void handle_storage_devices_update();
@@ -73,7 +73,7 @@ struct Sculpt::Storage : Storage_dialog::Action
bool result = _ram_fs_state.inspected;
_storage_devices.for_each([&] (Storage_device const &device) {
device.for_each_partition([&] (Partition const &partition) {
- result |= partition.file_system_inspected; }); });
+ result |= partition.file_system.inspected; }); });
return result;
}
@@ -159,7 +159,7 @@ struct Sculpt::Storage : Storage_dialog::Action
}
_apply_partition(target, [&] (Partition &partition) {
- partition.file_system_inspected = !partition.file_system_inspected;
+ partition.file_system.inspected = !partition.file_system.inspected;
_file_browser_version.value++;
});
@@ -189,14 +189,17 @@ struct Sculpt::Storage : Storage_dialog::Action
}
- Storage(Env &env, Allocator &alloc, Dialog::Generator &dialog_generator,
+ Storage(Env &env, Allocator &alloc,
+ Registry &child_states,
+ Dialog::Generator &dialog_generator,
Runtime_config_generator &runtime_config_generator,
- Target_user &target_user)
+ Target_user &target_user)
:
_env(env), _alloc(alloc),
_dialog_generator(dialog_generator),
_runtime_config_generator(runtime_config_generator),
- _target_user(target_user)
+ _target_user(target_user),
+ _ram_fs_state(child_states, "ram_fs")
{
_block_devices_rom .sigh(_storage_device_update_handler);
_usb_active_config_rom.sigh(_storage_device_update_handler);
diff --git a/repos/gems/src/app/sculpt_manager/view/dialog.h b/repos/gems/src/app/sculpt_manager/view/dialog.h
index 674e1a646..57ce424c7 100644
--- a/repos/gems/src/app/sculpt_manager/view/dialog.h
+++ b/repos/gems/src/app/sculpt_manager/view/dialog.h
@@ -16,9 +16,11 @@
/* Genode includes */
#include
+#include
/* local includes */
#include "types.h"
+#include
namespace Sculpt { struct Dialog; }
@@ -33,7 +35,68 @@ struct Sculpt::Dialog : Interface
*/
struct Generator : Interface { virtual void generate_dialog() = 0; };
- virtual void hover(Xml_node hover) = 0;
+ bool hovered = false;
+
+ enum class Click_result { CONSUMED, IGNORED };
+ enum class Clack_result { CONSUMED, IGNORED };
+
+ using Hover_result = Hoverable_item::Hover_result;
+
+ virtual void reset() = 0;
+
+ virtual Hover_result hover(Xml_node hover) = 0;
+
+ virtual void generate(Xml_generator &xml) const = 0;
+
+ static Hover_result any_hover_changed(Hover_result head)
+ {
+ return head;
+ }
+
+ template
+ static Hover_result any_hover_changed(Hover_result head, TAIL... args)
+ {
+ if (head == Hover_result::CHANGED)
+ return Hover_result::CHANGED;
+
+ return any_hover_changed(args...);
+ }
+
+ Hover_result _match_sub_dialog(Xml_node node)
+ {
+ hovered = true;
+ return hover(node);
+ }
+
+ template
+ Hover_result _match_sub_dialog(Xml_node hover, char const *sub_node,
+ TAIL &&... tail)
+ {
+ Hover_result result = Hover_result::UNMODIFIED;
+
+ hover.with_sub_node(sub_node, [&] (Xml_node sub_hover) {
+ if (_match_sub_dialog(sub_hover, tail...) == Hover_result::CHANGED)
+ result = Hover_result::CHANGED; });
+
+ return result;
+ }
+
+ template
+ Hover_result match_sub_dialog(ARGS &&... args)
+ {
+ bool const orig_hovered = hovered;
+
+ hovered = false;
+
+ Hover_result const result = _match_sub_dialog(args...);
+
+ /* reset internal hover state of the dialog if no longer hovered */
+ if (orig_hovered && !hovered)
+ (void)this->hover(Xml_node(""));
+
+ return result;
+ }
+
};
#endif /* _VIEW__DIALOG_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/view/file_browser_dialog.h b/repos/gems/src/app/sculpt_manager/view/file_browser_dialog.h
new file mode 100644
index 000000000..7b0c8e056
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/file_browser_dialog.h
@@ -0,0 +1,381 @@
+/*
+ * \brief File-browser dialog
+ * \author Norman Feske
+ * \date 2020-01-31
+ */
+
+/*
+ * Copyright (C) 2020 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 _VIEW__FILE_BROWSER_DIALOG_H_
+#define _VIEW__FILE_BROWSER_DIALOG_H_
+
+#include
+#include
+#include
+
+namespace Sculpt { struct File_browser_dialog; }
+
+
+struct Sculpt::File_browser_dialog : Noncopyable, Dialog
+{
+ Runtime_config const &_runtime_config;
+ File_browser_state const &_state;
+
+ Hoverable_item _fs_button { };
+ Hoverable_item _entry { };
+ Hoverable_item _path_elem { };
+ Hoverable_item _action_button { };
+
+ void reset() override { }
+
+ using Fs_name = File_browser_state::Fs_name;
+ using Index = File_browser_state::Index;
+ using Sub_dir = File_browser_state::Path;
+ using Path = File_browser_state::Path;
+ using File = File_browser_state::Path;
+
+ struct Action : Interface, Noncopyable
+ {
+ virtual void browse_file_system(Fs_name const &) = 0;
+
+ virtual void browse_sub_directory(Sub_dir const &) = 0;
+
+ virtual void browse_abs_directory(Path const &) = 0;
+
+ virtual void browse_parent_directory() = 0;
+
+ virtual void view_file(File const &) = 0;
+
+ virtual void edit_file(File const &) = 0;
+
+ virtual void revert_edited_file() = 0;
+
+ virtual void save_edited_file() = 0;
+ };
+
+ using Name = String<128>;
+
+ template
+ void _for_each_path_elem(FN const &fn) const
+ {
+ char const *curr = _state.path.string();
+
+ fn(Path("/"));
+
+ for (;;) {
+
+ if (*curr != '/')
+ return;
+
+ curr++; /* skip '/' */
+
+ /* search next '/' */
+ size_t len = 0;
+ for (; curr[len] != 0 && curr[len] != '/'; len++);
+
+ fn(Path(Cstring(curr, len)));
+
+ curr += len;
+ }
+ }
+
+ Path _path_elem_at_index(unsigned index) const
+ {
+ Path result { };
+ unsigned i = 0;
+
+ _for_each_path_elem([&] (Path const &elem) {
+ if (i++ == index)
+ result = elem; });
+
+ return result;
+ }
+
+ void _gen_path_elements(Xml_generator &xml) const
+ {
+ gen_named_node(xml, "hbox", "back", [&] () {
+ unsigned i = 0;
+ _for_each_path_elem([&] (Path const elem) {
+
+ gen_named_node(xml, "button", Index(i), [&] () {
+ if (!_state.modified)
+ _path_elem.gen_hovered_attr(xml, Index(i));
+ xml.node("label", [&] () {
+ xml.attribute("text", elem);
+ });
+ });
+ i++;
+ });
+ });
+ }
+
+ void _gen_back_entry(Xml_generator &xml) const
+ {
+ gen_named_node(xml, "hbox", "back", [&] () {
+
+ gen_named_node(xml, "float", "left", [&] () {
+ xml.attribute("west", "yes");
+
+ xml.node("hbox", [&] () {
+ if (!_state.modified) {
+ gen_named_node(xml, "button", "button", [&] () {
+ xml.attribute("style", "back");
+ _entry.gen_hovered_attr(xml, "back");
+ xml.node("hbox", [&] () { });
+ });
+ }
+
+ _gen_path_elements(xml);
+ });
+ });
+
+ gen_named_node(xml, "hbox", "right", [&] () { });
+ });
+ }
+
+ void _gen_entry(Xml_generator &xml, Xml_node node, Index const &index,
+ char const *style) const
+ {
+ Name const name = node.attribute_value("name", Name());
+
+ bool const entry_edited = (name == _state.edited_file);
+
+ /* while editing one file, hide all others */
+ if (!entry_edited && _state.modified)
+ return;
+
+ gen_named_node(xml, "hbox", index, [&] () {
+
+ gen_named_node(xml, "float", "left", [&] () {
+ xml.attribute("west", "yes");
+
+ xml.node("hbox", [&] () {
+ gen_named_node(xml, "button", "button", [&] () {
+
+ bool const selected = (name == _state.edited_file);
+ if (selected)
+ xml.attribute("selected", "yes");
+
+ xml.attribute("style", style);
+
+ if (!_state.modified)
+ _entry.gen_hovered_attr(xml, index);
+
+ xml.node("hbox", [&] () { });
+ });
+ gen_named_node(xml, "label", "name", [&] () {
+ xml.attribute("text", Path(" ", name)); });
+ });
+ });
+
+ gen_named_node(xml, "hbox", "middle", [&] () { });
+
+ gen_named_node(xml, "float", "right", [&] () {
+ xml.attribute("east", "yes");
+
+ /* show no operation buttons for directories */
+ if (node.type() == "dir")
+ return;
+
+ gen_named_node(xml, "hbox", "right", [&] () {
+
+ bool const entry_hovered = _entry.hovered(index);
+ bool const interesting = entry_hovered || entry_edited;
+ bool const writeable = node.attribute_value("writeable", false);
+
+ if (writeable) {
+
+ if (!_state.modified) {
+ gen_named_node(xml, "button", "edit", [&] () {
+ if (interesting) {
+ _action_button.gen_hovered_attr(xml, "edit");
+ if (entry_edited)
+ xml.attribute("selected", "yes");
+ } else {
+ xml.attribute("style", "invisible");
+ }
+
+ gen_named_node(xml, "label", "name", [&] () {
+ xml.attribute("text", "Edit");
+ if (!interesting)
+ xml.attribute("style", "invisible");
+ });
+ });
+ }
+
+ if (entry_edited && _state.modified) {
+
+ auto gen_action_button = [&] (auto id, auto text)
+ {
+ gen_named_node(xml, "button", id, [&] () {
+ _action_button.gen_hovered_attr(xml, id);
+ gen_named_node(xml, "label", "name", [&] () {
+ xml.attribute("text", text); }); });
+ };
+
+ gen_action_button("revert", "Revert");
+ gen_action_button("save", "Save");
+ }
+
+ } else {
+ gen_named_node(xml, "button", "view", [&] () {
+
+ if (interesting) {
+ _action_button.gen_hovered_attr(xml, "view");
+ if (entry_edited)
+ xml.attribute("selected", "yes");
+ } else {
+ xml.attribute("style", "invisible");
+ }
+
+ gen_named_node(xml, "label", "name", [&] () {
+ xml.attribute("text", "View");
+ if (!interesting)
+ xml.attribute("style", "invisible");
+ });
+ });
+ }
+ });
+ });
+ });
+ }
+
+ void _gen_file_system(Xml_generator &xml, Service const &service) const
+ {
+ bool const parent = !service.server.valid();
+ Label const name = parent ? Start_name(service.label) : service.server;
+
+ Start_name const pretty_name { Pretty(name) };
+
+ bool const selected = (_state.browsed_fs == name);
+
+ if (_state.text_area.constructed() && _state.modified && !selected)
+ return;
+
+ gen_named_node(xml, "frame", name, [&] () {
+ xml.node("vbox", [&] () {
+ xml.node("label", [&] () {
+ xml.attribute("min_ex", "50"); });
+
+ gen_named_node(xml, "button", name, [&] () {
+ if (!_state.modified)
+ _fs_button.gen_hovered_attr(xml, name);
+
+ if (selected)
+ xml.attribute("selected", true);
+
+ xml.node("label", [&] () {
+ xml.attribute("text", pretty_name);
+ xml.attribute("style", "title");
+ });
+ });
+
+ if (selected) {
+ unsigned cnt = 0;
+
+ _state.with_query_result([&] (Xml_node node) {
+ node.with_sub_node("dir", [&] (Xml_node listing) {
+
+ if (_state.path != "/")
+ _gen_back_entry(xml);
+
+ listing.for_each_sub_node("dir", [&] (Xml_node dir) {
+ _gen_entry(xml, dir, Index(cnt++), "enter"); });
+
+ listing.for_each_sub_node("file", [&] (Xml_node file) {
+ _gen_entry(xml, file, Index(cnt++), "radio"); });
+ });
+ });
+ }
+ });
+ });
+ }
+
+ void generate(Xml_generator &xml) const override
+ {
+ xml.node("vbox", [&] () {
+ _runtime_config.for_each_service([&] (Service const &service) {
+ if (service.type == Service::Type::FILE_SYSTEM)
+ _gen_file_system(xml, service); }); });
+ }
+
+ Hover_result hover(Xml_node hover) override
+ {
+ return any_hover_changed(
+ _entry.match(hover, "vbox", "frame", "vbox", "hbox", "name"),
+ _path_elem.match(hover, "vbox", "frame", "vbox", "hbox", "float", "hbox", "hbox", "button", "name"),
+ _fs_button.match(hover, "vbox", "frame", "vbox", "button", "name"),
+ _action_button.match(hover, "vbox", "frame", "vbox", "hbox", "float", "hbox", "button", "name"));
+ }
+
+ Click_result click(Action &action)
+ {
+ Click_result result = Click_result::IGNORED;
+
+ Fs_name const fs_name = _fs_button._hovered;
+ if (fs_name.length() > 1) {
+ if (!_state.modified)
+ action.browse_file_system(fs_name);
+ return Click_result::CONSUMED;
+ }
+
+ Index const path_elem_idx = _path_elem._hovered;
+ if (path_elem_idx.length() > 1) {
+
+ Genode::Path<256> abs_path { "/" };
+ for (unsigned i = 0; i < 20; i++) {
+ abs_path.append_element(_path_elem_at_index(i).string());
+ if (Index(i) == path_elem_idx)
+ break;
+ }
+ if (!_state.modified)
+ action.browse_abs_directory(Path(abs_path));
+
+ return Click_result::CONSUMED;
+ }
+
+ Index const index = _entry._hovered;
+ if (index == "back") {
+ if (!_state.modified)
+ action.browse_parent_directory();
+ }
+ else if (index.length() > 1) {
+ _state.with_entry_at_index(index, [&] (Xml_node entry) {
+
+ if (entry.has_type("dir"))
+ action.browse_sub_directory(entry.attribute_value("name", Sub_dir()));
+
+ if (entry.has_type("file")) {
+ if (_action_button.hovered("edit"))
+ action.edit_file(entry.attribute_value("name", Name()));
+
+ if (_action_button.hovered("view"))
+ action.view_file(entry.attribute_value("name", Name()));
+
+ if (_action_button.hovered("revert"))
+ action.revert_edited_file();
+
+ if (_action_button.hovered("save"))
+ action.save_edited_file();
+ }
+ });
+
+ return Click_result::CONSUMED;
+ }
+
+ return result;
+ }
+
+ File_browser_dialog(Runtime_config const &runtime_config,
+ File_browser_state const &state)
+ :
+ _runtime_config(runtime_config), _state(state)
+ { }
+};
+
+#endif /* _VIEW__FILE_BROWSER_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/view/fs_dialog.h b/repos/gems/src/app/sculpt_manager/view/fs_dialog.h
new file mode 100644
index 000000000..e13663ccd
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/fs_dialog.h
@@ -0,0 +1,89 @@
+/*
+ * \brief Common part of file-system management dialogs
+ * \author Norman Feske
+ * \date 2020-01-28
+ */
+
+/*
+ * Copyright (C) 2020 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 _VIEW__FS_DIALOG_H_
+#define _VIEW__FS_DIALOG_H_
+
+#include
+#include
+
+namespace Sculpt { struct Fs_dialog; }
+
+
+struct Sculpt::Fs_dialog : Noncopyable, Dialog
+{
+ Storage_target const _target;
+ Storage_target const &_used_target;
+
+ Hoverable_item _inspect_item { };
+ Hoverable_item _use_item { };
+
+ Hover_result hover(Xml_node hover) override
+ {
+ return any_hover_changed(
+ _inspect_item.match(hover, "button", "name"),
+ _use_item .match(hover, "button", "name"));
+ }
+
+ void reset() override { }
+
+ struct Action : Interface
+ {
+ virtual void toggle_file_browser(Storage_target const &) = 0;
+
+ virtual void use(Storage_target const &) = 0;
+ };
+
+ void generate(Xml_generator &) const override { }
+
+ void generate(Xml_generator &xml, File_system const &file_system) const
+ {
+ xml.node("button", [&] () {
+ _inspect_item.gen_button_attr(xml, "browse");
+
+ if (file_system.inspected)
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
+ });
+
+ if (!_used_target.valid() || _used_target == _target) {
+ xml.node("button", [&] () {
+ _use_item.gen_button_attr(xml, "use");
+ if (_used_target == _target)
+ xml.attribute("selected", "yes");
+ xml.node("label", [&] () { xml.attribute("text", "Use"); });
+ });
+ }
+ }
+
+ Click_result click(Action &action)
+ {
+ if (_inspect_item.hovered("browse"))
+ action.toggle_file_browser(_target);
+
+ else if (_use_item.hovered("use"))
+ action.use((_used_target == _target) ? Storage_target{ } : _target);
+
+ else return Click_result::IGNORED;
+
+ return Click_result::CONSUMED;
+ }
+
+ Fs_dialog(Storage_target target, Storage_target const &used_target)
+ :
+ _target(target), _used_target(used_target)
+ { }
+};
+
+#endif /* _VIEW__FS_DIALOG_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/view/hoverable_item.h b/repos/gems/src/app/sculpt_manager/view/hoverable_item.h
index b34c9472b..c5f66dde1 100644
--- a/repos/gems/src/app/sculpt_manager/view/hoverable_item.h
+++ b/repos/gems/src/app/sculpt_manager/view/hoverable_item.h
@@ -26,17 +26,19 @@ struct Sculpt::Hoverable_item
Id _hovered { };
+ enum class Hover_result { CHANGED, UNMODIFIED };
+
/**
* Set ID to matching hover sub node name
*
* \return true if hovering changed
*/
template
- bool match(Xml_node hover, ARGS &&... args)
+ Hover_result match(Xml_node hover, ARGS &&... args)
{
Id const orig = _hovered;
_hovered = query_attribute(hover, args...);
- return _hovered != orig;
+ return (_hovered != orig) ? Hover_result::CHANGED : Hover_result::UNMODIFIED;
}
/**
diff --git a/repos/gems/src/app/sculpt_manager/view/network_dialog.cc b/repos/gems/src/app/sculpt_manager/view/network_dialog.cc
index cf368a208..49bd64b57 100644
--- a/repos/gems/src/app/sculpt_manager/view/network_dialog.cc
+++ b/repos/gems/src/app/sculpt_manager/view/network_dialog.cc
@@ -17,8 +17,10 @@
/* local includes */
#include "network_dialog.h"
-void Sculpt::Network_dialog::_gen_access_point(Xml_generator &xml,
- Access_point const &ap) const
+using namespace Sculpt;
+
+void Network_dialog::_gen_access_point(Xml_generator &xml,
+ Access_point const &ap) const
{
gen_named_node(xml, "hbox", ap.bssid, [&] () {
@@ -59,7 +61,7 @@ void Sculpt::Network_dialog::_gen_access_point(Xml_generator &xml,
}
-bool Sculpt::Network_dialog::_selected_ap_visible() const
+bool Network_dialog::_selected_ap_visible() const
{
unsigned cnt = 0;
return _for_each_ap([&] (Access_point const &ap) {
@@ -67,14 +69,14 @@ bool Sculpt::Network_dialog::_selected_ap_visible() const
}
-bool Sculpt::Network_dialog::_selected_ap_unprotected() const
+bool Network_dialog::_selected_ap_unprotected() const
{
return _for_each_ap([&] (Access_point const &ap) {
return _ap_item.selected(ap.bssid) && ap.unprotected(); });
}
-bool Sculpt::Network_dialog::need_keyboard_focus_for_passphrase() const
+bool Network_dialog::need_keyboard_focus_for_passphrase() const
{
if ( _wifi_connection.state == Wifi_connection::CONNECTED
|| _wifi_connection.state == Wifi_connection::CONNECTING)
@@ -88,8 +90,8 @@ bool Sculpt::Network_dialog::need_keyboard_focus_for_passphrase() const
}
-void Sculpt::Network_dialog::_gen_access_point_list(Xml_generator &xml,
- bool auth_failure) const
+void Network_dialog::_gen_access_point_list(Xml_generator &xml,
+ bool auth_failure) const
{
if (_wlan_config_policy == WLAN_CONFIG_MANUAL)
return;
@@ -133,7 +135,11 @@ void Sculpt::Network_dialog::_gen_access_point_list(Xml_generator &xml,
xml.attribute("west", "yes");
xml.node("label", [&] () {
xml.attribute("font", "title/regular");
- xml.attribute("text", String<3*64>(" ", _wpa_passphrase));
+ String<3*64> const passphrase(" ", _wpa_passphrase);
+ xml.attribute("text", passphrase);
+ xml.node("cursor", [&] () {
+ xml.attribute("at", passphrase.length() - 1);
+ });
});
});
});
@@ -165,7 +171,7 @@ void Sculpt::Network_dialog::_gen_access_point_list(Xml_generator &xml,
}
-void Sculpt::Network_dialog::_gen_connected_ap(Xml_generator &xml, bool connected) const
+void Network_dialog::_gen_connected_ap(Xml_generator &xml, bool connected) const
{
bool done = false;
@@ -196,14 +202,10 @@ void Sculpt::Network_dialog::_gen_connected_ap(Xml_generator &xml, bool connecte
}
-void Sculpt::Network_dialog::generate(Xml_generator &xml) const
+void Network_dialog::generate(Xml_generator &xml) const
{
gen_named_node(xml, "frame", "network", [&] () {
xml.node("vbox", [&] () {
- gen_named_node(xml, "label", "title", [&] () {
- xml.attribute("text", "Network");
- xml.attribute("font", "title/regular");
- });
gen_named_node(xml, "hbox", "type", [&] () {
@@ -270,21 +272,20 @@ void Sculpt::Network_dialog::generate(Xml_generator &xml) const
}
-void Sculpt::Network_dialog::hover(Xml_node hover)
+Dialog::Hover_result Network_dialog::hover(Xml_node hover)
{
- bool const changed =
- _nic_item .match(hover, "vbox", "hbox", "button", "name") |
- _ap_item .match(hover, "vbox", "frame", "vbox", "hbox", "name") |
- _connect_item.match(hover, "vbox", "frame", "vbox", "button", "name");
+ Dialog::Hover_result const hover_result = Dialog::any_hover_changed(
+ _nic_item .match(hover, "frame", "vbox", "hbox", "button", "name"),
+ _ap_item .match(hover, "frame", "vbox", "frame", "vbox", "hbox", "name"),
+ _connect_item.match(hover, "frame", "vbox", "frame", "vbox", "button", "name"));
_nic_info.match(hover, "vbox", "frame", "name");
- if (changed)
- _dialog_generator.generate_dialog();
+ return hover_result;
}
-void Sculpt::Network_dialog::click(Action &action)
+void Network_dialog::click(Action &action)
{
if (_nic_item.hovered("off")) action.nic_target(Nic_target::OFF);
if (_nic_item.hovered("local")) action.nic_target(Nic_target::LOCAL);
@@ -304,6 +305,5 @@ void Sculpt::Network_dialog::click(Action &action)
if (_connect_item.hovered("connect"))
action.wifi_connect(selected_ap());
-
- _dialog_generator.generate_dialog();
}
+
diff --git a/repos/gems/src/app/sculpt_manager/view/network_dialog.h b/repos/gems/src/app/sculpt_manager/view/network_dialog.h
index 44e17c897..07b15f39e 100644
--- a/repos/gems/src/app/sculpt_manager/view/network_dialog.h
+++ b/repos/gems/src/app/sculpt_manager/view/network_dialog.h
@@ -14,24 +14,21 @@
#ifndef _VIEW__NETWORK_DIALOG_H_
#define _VIEW__NETWORK_DIALOG_H_
+/* local includes */
#include
#include
#include
#include
#include
#include
-#include
#include
+#include
namespace Sculpt { struct Network_dialog; }
struct Sculpt::Network_dialog : Dialog
{
- Env &_env;
-
- Dialog::Generator &_dialog_generator;
-
enum Wlan_config_policy { WLAN_CONFIG_MANAGED, WLAN_CONFIG_MANUAL };
Nic_target const &_nic_target;
@@ -76,15 +73,14 @@ struct Sculpt::Network_dialog : Dialog
void _gen_connected_ap(Xml_generator &, bool) const;
void _gen_access_point_list(Xml_generator &, bool) const;
- void generate(Xml_generator &) const;
+ Hover_result hover(Xml_node) override;
+
+ void generate(Xml_generator &) const override;
+
+ void reset() override { }
bool need_keyboard_focus_for_passphrase() const;
- /**
- * Dialog interface
- */
- void hover(Xml_node hover) override;
-
struct Action : Interface
{
virtual void nic_target(Nic_target::Type) = 0;
@@ -96,9 +92,7 @@ struct Sculpt::Network_dialog : Dialog
void click(Action &action);
- Network_dialog(Env &env,
- Dialog::Generator &dialog_generator,
- Nic_target const &nic_target,
+ Network_dialog(Nic_target const &nic_target,
Access_points const &access_points,
Wifi_connection const &wifi_connection,
Nic_state const &nic_state,
@@ -106,7 +100,6 @@ struct Sculpt::Network_dialog : Dialog
Wlan_config_policy const &wlan_config_policy,
Pci_info const &pci_info)
:
- _env(env), _dialog_generator(dialog_generator),
_nic_target(nic_target), _access_points(access_points),
_wifi_connection(wifi_connection), _nic_state(nic_state),
_wpa_passphrase(wpa_passphrase), _wlan_config_policy(wlan_config_policy),
diff --git a/repos/gems/src/app/sculpt_manager/view/panel_dialog.cc b/repos/gems/src/app/sculpt_manager/view/panel_dialog.cc
new file mode 100644
index 000000000..c3988b21c
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/panel_dialog.cc
@@ -0,0 +1,87 @@
+/*
+ * \brief Panel dialog
+ * \author Norman Feske
+ * \date 2020-01-26
+ */
+
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include
+
+using namespace Sculpt;
+
+
+void Panel_dialog::generate(Xml_generator &xml) const
+{
+ xml.node("frame", [&] () {
+ xml.attribute("style", "unimportant");
+
+ gen_named_node(xml, "float", "left", [&] () {
+ xml.attribute("west", true);
+ xml.node("hbox", [&] () {
+ xml.node("button", [&] () {
+ _item.gen_button_attr(xml, "settings");
+ if (_state.settings_visible())
+ xml.attribute("selected", true);
+ xml.node("label", [&] () {
+ xml.attribute("text", "Settings");
+ });
+ });
+ });
+ });
+
+ gen_named_node(xml, "float", "center", [&] () {
+ xml.node("hbox", [&] () {
+
+ auto gen_tab = [&] (auto name, auto text, Tab tab) {
+
+ gen_named_node(xml, "button", name, [&] () {
+
+ if (_state.selected_tab() == tab)
+ xml.attribute("selected", true);
+ else
+ _item.gen_hovered_attr(xml, name);
+
+ xml.node("label", [&] () {
+ xml.attribute("text", text);
+ });
+ });
+ };
+
+ gen_tab("files", "Files", Tab::FILES);
+ gen_tab("components", "Components", Tab::COMPONENTS);
+
+ if (_state.inspect_tab_visible())
+ gen_tab("inspect", "Inspect", Tab::INSPECT);
+ });
+ });
+
+ gen_named_node(xml, "float", "right", [&] () {
+ xml.attribute("east", true);
+ xml.node("hbox", [&] () {
+ xml.node("button", [&] () {
+ _item.gen_button_attr(xml, "network");
+ if (_state.network_visible())
+ xml.attribute("selected", true);
+ xml.node("label", [&] () {
+ xml.attribute("text", "Network");
+ });
+ });
+ xml.node("button", [&] () {
+ _item.gen_button_attr(xml, "log");
+ if (_state.log_visible())
+ xml.attribute("selected", true);
+ xml.node("label", [&] () {
+ xml.attribute("text", "Log");
+ });
+ });
+ });
+ });
+ });
+}
+
diff --git a/repos/gems/src/app/sculpt_manager/view/panel_dialog.h b/repos/gems/src/app/sculpt_manager/view/panel_dialog.h
new file mode 100644
index 000000000..6369a3019
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/panel_dialog.h
@@ -0,0 +1,81 @@
+/*
+ * \brief Panel dialog
+ * \author Norman Feske
+ * \date 2020-01-26
+ */
+
+/*
+ * Copyright (C) 2020 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 _VIEW__PANEL_DIALOG_H_
+#define _VIEW__PANEL_DIALOG_H_
+
+/* Genode includes */
+#include
+
+/* local includes */
+#include
+#include
+#include
+
+namespace Sculpt { struct Panel_dialog; }
+
+
+struct Sculpt::Panel_dialog : Dialog
+{
+ enum class Tab { FILES, COMPONENTS, INSPECT };
+
+ struct State : Interface, Noncopyable
+ {
+ virtual Tab selected_tab() const = 0;
+ virtual bool log_visible() const = 0;
+ virtual bool settings_visible() const = 0;
+ virtual bool network_visible() const = 0;
+ virtual bool inspect_tab_visible() const = 0;
+ };
+
+ State const &_state;
+
+ struct Action : Interface
+ {
+ virtual void select_tab(Tab) = 0;
+ virtual void toggle_log_visibility() = 0;
+ virtual void toggle_settings_visibility() = 0;
+ virtual void toggle_network_visibility() = 0;
+ };
+
+ Hoverable_item _item { };
+ Activatable_item _action_item { };
+
+ Hover_result hover(Xml_node hover) override
+ {
+ return any_hover_changed(
+ _item.match(hover, "frame", "float", "hbox", "button", "name"));
+ }
+
+ void generate(Xml_generator &) const override;
+
+ void click(Action &action)
+ {
+ if (_item.hovered("components")) action.select_tab(Tab::COMPONENTS);
+ if (_item.hovered("files")) action.select_tab(Tab::FILES);
+ if (_item.hovered("inspect")) action.select_tab(Tab::INSPECT);
+ if (_item.hovered("log")) action.toggle_log_visibility();
+ if (_item.hovered("settings")) action.toggle_settings_visibility();
+ if (_item.hovered("network")) action.toggle_network_visibility();
+ }
+
+ void reset() override
+ {
+ _item._hovered = Hoverable_item::Id();
+ _action_item.reset();
+ }
+
+ Panel_dialog(State const &state) : _state(state) { }
+};
+
+#endif /* _VIEW__PANEL_DIALOG_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/view/partition_dialog.cc b/repos/gems/src/app/sculpt_manager/view/partition_dialog.cc
new file mode 100644
index 000000000..c5491adf4
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/partition_dialog.cc
@@ -0,0 +1,238 @@
+/*
+ * \brief Partition management dialog
+ * \author Norman Feske
+ * \date 2020-01-29
+ */
+
+/*
+ * Copyright (C) 2020 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.
+ */
+
+/* Genode includes */
+#include
+
+/* local includes */
+#include "partition_dialog.h"
+
+using namespace Sculpt;
+
+
+void Partition_dialog::gen_operations(Xml_generator &xml,
+ Storage_device const &device,
+ Partition const &partition) const
+{
+ String<16> const version(device.label, ".", partition.number);
+
+ bool const whole_device = !partition.number.valid();
+
+ bool const device_in_use = (_used_target.device == device.label);
+
+ bool const target_in_use = (_used_target == _partition)
+ || (whole_device && device_in_use)
+ || partition.file_system.inspected;
+
+ bool const relabel_in_progress = device.relabel_in_progress();
+
+ bool const expand_in_progress = device.expand_in_progress();
+
+ bool const format_selected = _operation_item.selected("format");
+
+ bool const expand_selected = _operation_item.selected("expand");
+
+ if (partition.file_system.accessible()
+ && !format_selected && !expand_selected && !expand_in_progress) {
+
+ if (!partition.check_in_progress
+ && !partition.format_in_progress
+ && !relabel_in_progress) {
+
+ _fs_dialog.generate(xml, partition.file_system);
+ }
+
+ if ((device.all_partitions_idle() || partition.relabel_in_progress())
+ && partition.genode() && !device_in_use) {
+
+ xml.node("button", [&] () {
+
+ /* support hovering only if no relabeling is in progress */
+ if (partition.relabel_in_progress())
+ xml.attribute("name", "relabel");
+ else
+ _relabel_item.gen_button_attr(xml, "relabel");
+
+ xml.attribute("version", version);
+
+ if (partition.genode_default() || partition.relabel_in_progress())
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () {
+ xml.attribute("text", "Default"); });
+ });
+ if (partition.relabel_in_progress())
+ xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
+ }
+
+ if (!target_in_use && !partition.format_in_progress && partition.checkable()
+ && !relabel_in_progress) {
+
+ xml.node("button", [&] () {
+ _operation_item.gen_button_attr(xml, "check");
+ xml.attribute("version", version);
+
+ if (partition.check_in_progress)
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () { xml.attribute("text", "Check"); });
+ });
+ if (partition.check_in_progress)
+ xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
+ }
+ }
+
+ bool const whole_device_with_partition_in_use =
+ whole_device && !device.all_partitions_idle();
+
+ bool const format_button_visible = !target_in_use
+ && !whole_device_with_partition_in_use
+ && !partition.check_in_progress
+ && !expand_in_progress
+ && !relabel_in_progress
+ && !_operation_item.selected("expand");
+
+ bool const expand_button_visible = !target_in_use
+ && !whole_device
+ && !partition.check_in_progress
+ && !partition.format_in_progress
+ && !relabel_in_progress
+ && partition.expandable()
+ && !_operation_item.selected("format");
+
+ bool const progress_msg_visible =
+ (_operation_item.selected("format") && partition.format_in_progress)
+ || (_operation_item.selected("expand") && partition.expand_in_progress());
+
+ bool const confirm_visible =
+ (_operation_item.selected("format") && !partition.format_in_progress)
+ || (_operation_item.selected("expand") && !partition.expand_in_progress());
+
+ if (format_button_visible) {
+ xml.node("button", [&] () {
+ _operation_item.gen_button_attr(xml, "format");
+ xml.attribute("version", version);
+
+ if (partition.format_in_progress)
+ xml.attribute("selected", "yes");
+
+ if (whole_device) {
+ xml.node("label", [&] () { xml.attribute("text", "Format device ..."); });
+ } else {
+ xml.node("label", [&] () { xml.attribute("text", "Format partition ..."); });
+ }
+ });
+ }
+
+ if (expand_button_visible) {
+ xml.node("button", [&] () {
+ _operation_item.gen_button_attr(xml, "expand");
+ xml.attribute("version", version);
+
+ if (partition.expand_in_progress())
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () { xml.attribute("text", "Expand ..."); });
+ });
+ }
+
+ if (progress_msg_visible)
+ xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
+
+ if (confirm_visible) {
+ xml.node("button", [&] () {
+ _confirm_item.gen_button_attr(xml, "confirm");
+ xml.attribute("version", version);
+ xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
+ });
+ }
+}
+
+
+Dialog::Hover_result Partition_dialog::hover(Xml_node hover)
+{
+ Hover_result const hover_result = any_hover_changed(
+ _fs_dialog.hover(hover),
+ _relabel_item .match(hover, "button", "name"),
+ _operation_item.match(hover, "button", "name"),
+ _confirm_item .match(hover, "button", "name"));
+
+ return hover_result;
+}
+
+
+Dialog::Click_result Partition_dialog::click(Action &action)
+{
+ if (_fs_dialog.click(action) == Click_result::CONSUMED)
+ return Click_result::CONSUMED;
+
+ if (_operation_item.hovered("format")) {
+ if (_operation_item.selected("format"))
+ action.cancel_format(_partition);
+ else
+ _operation_item.toggle_selection_on_click();
+ return Click_result::CONSUMED;
+ }
+
+ if (_operation_item.hovered("expand")) {
+ if (_operation_item.selected("expand"))
+ action.cancel_expand(_partition);
+ else
+ _operation_item.toggle_selection_on_click();
+ return Click_result::CONSUMED;
+ }
+
+ if (_operation_item.hovered("check")) {
+ action.check(_partition);
+ return Click_result::CONSUMED;
+ }
+
+ if (_relabel_item.hovered("relabel")) {
+ action.toggle_default_storage_target(_partition);
+ return Click_result::CONSUMED;
+ }
+
+ if (_confirm_item.hovered("confirm")) {
+ _confirm_item.propose_activation_on_click();
+ return Click_result::CONSUMED;
+ }
+
+ return Click_result::IGNORED;
+}
+
+
+Dialog::Clack_result Partition_dialog::clack(Action &action)
+{
+ if (_confirm_item.hovered("confirm")) {
+
+ _confirm_item.confirm_activation_on_clack();
+
+ if (_confirm_item.activated("confirm")) {
+
+ if (_operation_item.selected("format")) {
+ action.format(_partition);
+ return Clack_result::CONSUMED;
+ }
+
+ if (_operation_item.selected("expand")) {
+ action.expand(_partition);
+ return Clack_result::CONSUMED;
+ }
+ }
+ } else {
+ _confirm_item.reset();
+ }
+
+ return Clack_result::IGNORED;
+}
+
diff --git a/repos/gems/src/app/sculpt_manager/view/partition_dialog.h b/repos/gems/src/app/sculpt_manager/view/partition_dialog.h
new file mode 100644
index 000000000..86127b55e
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/partition_dialog.h
@@ -0,0 +1,77 @@
+/*
+ * \brief Partition management dialog
+ * \author Norman Feske
+ * \date 2020-01-29
+ */
+
+/*
+ * Copyright (C) 2020 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 _VIEW__PARTITION_DIALOG_H_
+#define _VIEW__PARTITION_DIALOG_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Sculpt { struct Partition_dialog; }
+
+
+struct Sculpt::Partition_dialog : Dialog
+{
+ Storage_target const _partition;
+ Storage_devices const &_storage_devices;
+ Storage_target const &_used_target;
+
+ Hoverable_item _relabel_item { };
+ Selectable_item _operation_item { };
+ Activatable_item _confirm_item { };
+
+ Fs_dialog _fs_dialog { _partition, _used_target };
+
+ void generate(Xml_generator &) const override { }
+
+ void gen_operations(Xml_generator &, Storage_device const &, Partition const &) const;
+
+ Hover_result hover(Xml_node hover) override;
+
+ struct Action : Fs_dialog::Action
+ {
+ virtual void format(Storage_target const &) = 0;
+
+ virtual void cancel_format(Storage_target const &) = 0;
+
+ virtual void expand(Storage_target const &) = 0;
+
+ virtual void cancel_expand(Storage_target const &) = 0;
+
+ virtual void check(Storage_target const &) = 0;
+
+ virtual void toggle_default_storage_target(Storage_target const &) = 0;
+ };
+
+ void reset() override { }
+
+ void reset_operation() { _operation_item.reset(); }
+
+ Click_result click(Action &action);
+ Clack_result clack(Action &action);
+
+ Partition_dialog(Storage_target const partition,
+ Storage_devices const &storage_devices,
+ Storage_target const &used)
+ :
+ _partition(partition),
+ _storage_devices(storage_devices),
+ _used_target(used)
+ { }
+};
+
+#endif /* _VIEW__PARTITION_DIALOG_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/view/popup_dialog.cc b/repos/gems/src/app/sculpt_manager/view/popup_dialog.cc
index 4cbe59501..1b7b64bce 100644
--- a/repos/gems/src/app/sculpt_manager/view/popup_dialog.cc
+++ b/repos/gems/src/app/sculpt_manager/view/popup_dialog.cc
@@ -460,6 +460,4 @@ void Popup_dialog::click(Action &action)
}
}
}
-
- generate();
}
diff --git a/repos/gems/src/app/sculpt_manager/view/popup_dialog.h b/repos/gems/src/app/sculpt_manager/view/popup_dialog.h
index 8f3bf6200..be14bcb84 100644
--- a/repos/gems/src/app/sculpt_manager/view/popup_dialog.h
+++ b/repos/gems/src/app/sculpt_manager/view/popup_dialog.h
@@ -33,12 +33,10 @@
namespace Sculpt { struct Popup_dialog; }
-struct Sculpt::Popup_dialog
+struct Sculpt::Popup_dialog : Dialog
{
Env &_env;
- Allocator &_alloc;
-
Sculpt_version const _sculpt_version { _env };
Launchers const &_launchers;
@@ -71,6 +69,13 @@ struct Sculpt::Popup_dialog
}
};
+ struct Refresh : Interface, Noncopyable
+ {
+ virtual void refresh_popup_dialog() = 0;
+ };
+
+ Refresh &_refresh;
+
struct Action : Interface
{
virtual void launch_global(Path const &launcher) = 0;
@@ -103,20 +108,11 @@ struct Sculpt::Popup_dialog
Construction_info const &_construction_info;
- Expanding_reporter _dialog_reporter { _env, "dialog", "popup_dialog" };
-
- Attached_rom_dataspace _hover_rom { _env, "popup_view_hover" };
-
- Signal_handler _hover_handler {
- _env.ep(), *this, &Popup_dialog::_handle_hover };
-
Hoverable_item _item { };
Activatable_item _action_item { };
Activatable_item _install_item { };
Hoverable_item _route_item { };
- bool _hovered = false;
-
enum State { TOP_LEVEL, DEPOT_REQUESTED, DEPOT_SHOWN, DEPOT_SELECTION,
INDEX_REQUESTED, INDEX_SHOWN,
PKG_REQUESTED, PKG_SHOWN, ROUTE_SELECTED };
@@ -190,26 +186,17 @@ struct Sculpt::Popup_dialog
Menu _menu { };
- void _handle_hover()
+ Hover_result hover(Xml_node hover) override
{
- _hover_rom.update();
+ Dialog::Hover_result const hover_result = Dialog::any_hover_changed(
+ _item .match(hover, "frame", "vbox", "hbox", "name"),
+ _action_item .match(hover, "frame", "vbox", "button", "name"),
+ _install_item.match(hover, "frame", "vbox", "float", "vbox", "float", "button", "name"),
+ _route_item .match(hover, "frame", "vbox", "frame", "vbox", "hbox", "name"));
- Xml_node const hover = _hover_rom.xml();
-
- _hovered = hover.has_sub_node("dialog");
-
- bool const changed =
- _item .match(hover, "dialog", "frame", "vbox", "hbox", "name") |
- _action_item .match(hover, "dialog", "frame", "vbox", "button", "name") |
- _install_item.match(hover, "dialog", "frame", "vbox", "float", "vbox", "float", "button", "name") |
- _route_item .match(hover, "dialog", "frame", "vbox", "frame", "vbox", "hbox", "name");
-
- if (changed)
- generate();
+ return hover_result;
}
- bool hovered() const { return _hovered; };
-
Attached_rom_dataspace _scan_rom { _env, "report -> runtime/depot_query/scan" };
Signal_handler _scan_handler {
@@ -223,7 +210,7 @@ struct Sculpt::Popup_dialog
_state = DEPOT_SHOWN;
if (_state != TOP_LEVEL)
- generate();
+ _refresh.refresh_popup_dialog();
}
Attached_rom_dataspace _index_rom { _env, "report -> runtime/depot_query/index" };
@@ -242,7 +229,7 @@ struct Sculpt::Popup_dialog
if (_state == INDEX_REQUESTED)
_state = INDEX_SHOWN;
- generate();
+ _refresh.refresh_popup_dialog();
}
bool _index_avail(User const &user) const
@@ -373,12 +360,11 @@ struct Sculpt::Popup_dialog
void _gen_pkg_elements (Xml_generator &, Component const &) const;
void _gen_menu_elements(Xml_generator &) const;
- void generate()
+ void generate(Xml_generator &xml) const override
{
- _dialog_reporter.generate([&] (Xml_generator &xml) {
- xml.node("frame", [&] () {
- xml.node("vbox", [&] () {
- _gen_menu_elements(xml); }); }); });
+ xml.node("frame", [&] () {
+ xml.node("vbox", [&] () {
+ _gen_menu_elements(xml); }); });
}
void click(Action &action);
@@ -397,25 +383,24 @@ struct Sculpt::Popup_dialog
_construction_info.with_construction([&] (Component const &component) {
action.trigger_download(component.path);
_install_item.reset();
- generate();
+ _refresh.refresh_popup_dialog();
});
}
}
- void reset()
+ void reset() override
{
_item._hovered = Hoverable_item::Id();
_route_item._hovered = Hoverable_item::Id();
_action_item.reset();
_install_item.reset();
- _hovered = false;
_state = TOP_LEVEL;
_selected_user = User();
_selected_route.destruct();
_menu._level = 0;
}
- Popup_dialog(Env &env, Allocator &alloc,
+ Popup_dialog(Env &env, Refresh &refresh,
Launchers const &launchers,
Nic_state const &nic_state,
Nic_target const &nic_target,
@@ -425,17 +410,14 @@ struct Sculpt::Popup_dialog
Depot_query &depot_query,
Construction_info const &construction_info)
:
- _env(env), _alloc(alloc), _launchers(launchers),
+ _env(env), _launchers(launchers),
_nic_state(nic_state), _nic_target(nic_target),
_runtime_info(runtime_info), _runtime_config(runtime_config),
_download_queue(download_queue), _depot_query(depot_query),
- _construction_info(construction_info)
+ _refresh(refresh), _construction_info(construction_info)
{
- _hover_rom.sigh(_hover_handler);
_scan_rom.sigh(_scan_handler);
_index_rom.sigh(_index_handler);
-
- generate();
}
void gen_depot_query(Xml_generator &xml) const
@@ -473,7 +455,7 @@ struct Sculpt::Popup_dialog
if (construction.blueprint_known && !_pkg_missing && !_pkg_rom_missing)
_state = PKG_SHOWN;
- generate();
+ _refresh.refresh_popup_dialog();
}
bool interested_in_download() const
diff --git a/repos/gems/src/app/sculpt_manager/view/ram_fs_dialog.h b/repos/gems/src/app/sculpt_manager/view/ram_fs_dialog.h
new file mode 100644
index 000000000..dfa39ac91
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/ram_fs_dialog.h
@@ -0,0 +1,119 @@
+/*
+ * \brief RAM file-system management dialog
+ * \author Norman Feske
+ * \date 2020-01-28
+ */
+
+/*
+ * Copyright (C) 2020 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 _VIEW__RAM_FS_DIALOG_H_
+#define _VIEW__RAM_FS_DIALOG_H_
+
+#include
+#include
+
+namespace Sculpt { struct Ram_fs_dialog; }
+
+
+struct Sculpt::Ram_fs_dialog : Noncopyable, Dialog
+{
+ Storage_target const &_used_target;
+
+ Storage_target const _target { "ram_fs", Partition::Number() };
+
+ Fs_dialog _fs_dialog;
+
+ Selectable_item _operation_item { };
+ Activatable_item _confirm_item { };
+
+ Hover_result hover(Xml_node hover) override
+ {
+ return any_hover_changed(
+ _fs_dialog.match_sub_dialog(hover),
+ _operation_item.match(hover, "button", "name"),
+ _confirm_item .match(hover, "button", "name"));
+ }
+
+ void reset() override
+ {
+ _operation_item.reset();
+ _confirm_item.reset();
+ }
+
+ struct Action : Interface, Noncopyable
+ {
+ virtual void reset_ram_fs() = 0;
+ };
+
+ void generate(Xml_generator &) const override { }
+
+ void generate(Xml_generator &xml, Ram_fs_state const &ram_fs_state) const
+ {
+ _fs_dialog.generate(xml, ram_fs_state);
+
+ if (!_used_target.ram_fs() && !ram_fs_state.inspected) {
+ xml.node("button", [&] () {
+ _operation_item.gen_button_attr(xml, "reset");
+
+ xml.node("label", [&] () { xml.attribute("text", "Reset ..."); });
+ });
+
+ if (_operation_item.selected("reset")) {
+ xml.node("button", [&] () {
+ _confirm_item.gen_button_attr(xml, "confirm");
+ xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
+ });
+ }
+ }
+ }
+
+ Click_result click(Fs_dialog::Action &fs_action)
+ {
+ if (_fs_dialog.click(fs_action) == Click_result::CONSUMED)
+ return Click_result::CONSUMED;
+
+ /* toggle confirmation button when clicking on ram_fs reset */
+ else if (_operation_item.hovered("reset"))
+ _operation_item.toggle_selection_on_click();
+
+ else if (_confirm_item.hovered("confirm"))
+ _confirm_item.propose_activation_on_click();
+
+ else return Click_result::IGNORED;
+
+ return Click_result::CONSUMED;
+ }
+
+ Clack_result clack(Action &action)
+ {
+ if (_confirm_item.hovered("confirm")) {
+
+ _confirm_item.confirm_activation_on_clack();
+
+ if (_confirm_item.activated("confirm")) {
+ if (_operation_item.selected("reset")) {
+ action.reset_ram_fs();
+ _operation_item.reset();
+ _confirm_item.reset();
+ return Clack_result::CONSUMED;
+ }
+ }
+ } else {
+ _confirm_item.reset();
+ }
+
+ return Clack_result::IGNORED;
+ }
+
+ Ram_fs_dialog(Storage_target const &used_target)
+ :
+ _used_target(used_target), _fs_dialog(_target, used_target)
+ { }
+};
+
+#endif /* _VIEW__RAM_FS_DIALOG_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/view/settings_dialog.h b/repos/gems/src/app/sculpt_manager/view/settings_dialog.h
new file mode 100644
index 000000000..e42ba1049
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/settings_dialog.h
@@ -0,0 +1,107 @@
+/*
+ * \brief Settings dialog
+ * \author Norman Feske
+ * \date 2020-01-30
+ */
+
+/*
+ * Copyright (C) 2020 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 _VIEW__SETTINGS_DIALOG_H_
+#define _VIEW__SETTINGS_DIALOG_H_
+
+#include
+#include
+
+namespace Sculpt { struct Settings_dialog; }
+
+
+struct Sculpt::Settings_dialog : Noncopyable, Dialog
+{
+ Font_size const &_current_font_size;
+
+ Hoverable_item _item { };
+
+ static Hoverable_item::Id _font_size_id(Font_size font_size)
+ {
+ switch (font_size) {
+ case Font_size::SMALL: return "small";
+ case Font_size::MEDIUM: return "medium";
+ case Font_size::LARGE: return "large";
+ }
+ return Hoverable_item::Id();
+ }
+
+ Hover_result hover(Xml_node hover) override
+ {
+ return any_hover_changed(
+ _item.match(hover, "frame", "vbox", "hbox", "button", "name"));
+ }
+
+ void reset() override { }
+
+ struct Action : Interface, Noncopyable
+ {
+ virtual void select_font_size(Font_size) = 0;
+ };
+
+ void generate(Xml_generator &xml) const override
+ {
+ gen_named_node(xml, "frame", "network", [&] () {
+ xml.node("vbox", [&] () {
+ gen_named_node(xml, "hbox", "font_size", [&] () {
+ gen_named_node(xml, "label", "label", [&] () {
+ xml.attribute("text", " Font size "); });
+
+ auto gen_font_size_button = [&] (Font_size font_size)
+ {
+ Label const label = _font_size_id(font_size);
+ gen_named_node(xml, "button", label, [&] () {
+ _item.gen_hovered_attr(xml, label);
+
+ if (font_size == _current_font_size)
+ xml.attribute("selected", true);
+
+ xml.node("label", [&] () {
+ xml.attribute("text", label); });
+ });
+ };
+
+ gen_font_size_button(Font_size::SMALL);
+ gen_font_size_button(Font_size::MEDIUM);
+ gen_font_size_button(Font_size::LARGE);
+ });
+ });
+ });
+ }
+
+ Click_result click(Action &action)
+ {
+ Click_result result = Click_result::IGNORED;
+
+ auto apply_font_size = [&] (Font_size font_size)
+ {
+ if (_item.hovered(_font_size_id(font_size))) {
+ action.select_font_size(font_size);
+ result = Click_result::CONSUMED;
+ }
+ };
+
+ apply_font_size(Font_size::SMALL);
+ apply_font_size(Font_size::MEDIUM);
+ apply_font_size(Font_size::LARGE);
+
+ return result;
+ }
+
+ Settings_dialog(Font_size const ¤t_font_size)
+ :
+ _current_font_size(current_font_size)
+ { }
+};
+
+#endif /* _VIEW__RAM_FS_DIALOG_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/view/storage_device_dialog.cc b/repos/gems/src/app/sculpt_manager/view/storage_device_dialog.cc
new file mode 100644
index 000000000..70c543acf
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/storage_device_dialog.cc
@@ -0,0 +1,122 @@
+/*
+ * \brief Storage-device management dialog
+ * \author Norman Feske
+ * \date 2018-04-30
+ */
+
+/*
+ * Copyright (C) 2018 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.
+ */
+
+/* Genode includes */
+#include
+
+/* local includes */
+#include "storage_device_dialog.h"
+
+using namespace Sculpt;
+
+
+void Storage_device_dialog::_gen_partition(Xml_generator &xml,
+ Storage_device const &device,
+ Partition const &partition) const
+{
+ bool const selected = _partition_item.selected(partition.number);
+
+ gen_named_node(xml, "hbox", partition.number, [&] () {
+ gen_named_node(xml, "float", "left", [&] () {
+ xml.attribute("west", "yes");
+ xml.node("hbox", [&] () {
+ gen_named_node(xml, "button", "button", [&] () {
+
+ if (_partition_item.hovered(partition.number))
+ xml.attribute("hovered", "yes");
+
+ if (selected)
+ xml.attribute("selected", "yes");
+
+ xml.node("label", [&] () { xml.attribute("text", partition.number); });
+ });
+
+ if (partition.label.length() > 1)
+ gen_named_node(xml, "label", "label", [&] () {
+ xml.attribute("text", String<80>(" (", partition.label, ") ")); });
+
+ Storage_target const target { device.label, partition.number };
+ if (_used_target == target)
+ gen_named_node(xml, "label", "used", [&] () { xml.attribute("text", "* "); });
+ });
+ });
+
+ gen_named_node(xml, "float", "right", [&] () {
+ xml.attribute("east", "yes");
+ xml.node("label", [&] () {
+ xml.attribute("text", String<64>(partition.capacity, " ")); });
+ });
+ });
+
+ if (selected && _partition_dialog.constructed())
+ _partition_dialog->gen_operations(xml, device, partition);
+}
+
+
+void Storage_device_dialog::generate(Xml_generator &xml, Storage_device const &dev) const
+{
+ xml.node("frame", [&] () {
+ xml.attribute("name", dev.label);
+ xml.attribute("style", "invisible");
+ xml.node("vbox", [&] () {
+ dev.partitions.for_each([&] (Partition const &partition) {
+ _gen_partition(xml, dev, partition); });
+
+ if (!_partition_item.any_selected() && _partition_dialog.constructed())
+ _partition_dialog->gen_operations(xml, dev, *dev.whole_device_partition);
+ });
+ });
+}
+
+
+Dialog::Hover_result Storage_device_dialog::hover(Xml_node hover)
+{
+ Hover_result result = Hover_result::UNMODIFIED;
+
+ if (_partition_dialog.constructed() &&
+ _partition_dialog->match_sub_dialog(hover, "frame", "vbox") == Hover_result::CHANGED)
+ result = Hover_result::CHANGED;
+
+ return any_hover_changed(
+ result,
+ _partition_item.match(hover, "frame", "vbox", "hbox", "name"));
+}
+
+
+Dialog::Click_result Storage_device_dialog::click(Action &action)
+{
+ Storage_target const orig_selected_target = _selected_storage_target();
+
+ _partition_item.toggle_selection_on_click();
+
+ if (_selected_storage_target() != orig_selected_target) {
+ _partition_dialog.construct(_selected_storage_target(),
+ _storage_devices, _used_target);
+ return Click_result::CONSUMED;
+ }
+
+ if (_partition_dialog.constructed())
+ return _partition_dialog->click(action);
+
+ return Click_result::IGNORED;
+}
+
+
+Dialog::Clack_result Storage_device_dialog::clack(Action &action)
+{
+ if (_partition_dialog.constructed())
+ return _partition_dialog->clack(action);
+
+ return Clack_result::IGNORED;
+}
+
diff --git a/repos/gems/src/app/sculpt_manager/view/storage_device_dialog.h b/repos/gems/src/app/sculpt_manager/view/storage_device_dialog.h
new file mode 100644
index 000000000..801859b0b
--- /dev/null
+++ b/repos/gems/src/app/sculpt_manager/view/storage_device_dialog.h
@@ -0,0 +1,78 @@
+/*
+ * \brief Storage-device management dialog
+ * \author Norman Feske
+ * \date 2020-01-29
+ */
+
+/*
+ * Copyright (C) 2020 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 _VIEW__STORAGE_DEVICE_DIALOG_H_
+#define _VIEW__STORAGE_DEVICE_DIALOG_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Sculpt { struct Storage_device_dialog; }
+
+
+struct Sculpt::Storage_device_dialog : Dialog
+{
+ Storage_device::Label const _device;
+ Storage_devices const &_storage_devices;
+ Storage_target const &_used_target;
+
+ Selectable_item _partition_item { };
+
+ Reconstructible _partition_dialog {
+ _selected_storage_target(), _storage_devices, _used_target };
+
+ void generate(Xml_generator &) const override { }
+
+ void _gen_partition(Xml_generator &, Storage_device const &, Partition const &) const;
+
+ void generate(Xml_generator &, Storage_device const &) const;
+
+ Hover_result hover(Xml_node hover) override;
+
+ using Action = Partition_dialog::Action;
+
+ Storage_target _selected_storage_target() const
+ {
+ Partition::Number partition = (_partition_item._selected == "")
+ ? Partition::Number { }
+ : Partition::Number(_partition_item._selected);
+
+ return Storage_target { _device, partition };
+ }
+
+ void reset() override { }
+
+ void reset_operation()
+ {
+ if (_partition_dialog.constructed())
+ _partition_dialog->reset_operation();
+ }
+
+ Click_result click(Action &action);
+ Clack_result clack(Action &action);
+
+ Storage_device_dialog(Storage_device::Label const &device,
+ Storage_devices const &storage_devices,
+ Storage_target const &used)
+ :
+ _device(device),
+ _storage_devices(storage_devices),
+ _used_target(used)
+ { }
+};
+
+#endif /* _VIEW__STORAGE_DEVICE_DIALOG_H_ */
diff --git a/repos/gems/src/app/sculpt_manager/view/storage_dialog.cc b/repos/gems/src/app/sculpt_manager/view/storage_dialog.cc
index d0d879594..1ce48bb53 100644
--- a/repos/gems/src/app/sculpt_manager/view/storage_dialog.cc
+++ b/repos/gems/src/app/sculpt_manager/view/storage_dialog.cc
@@ -17,213 +17,11 @@
/* local includes */
#include "storage_dialog.h"
-
-void Sculpt::Storage_dialog::_gen_partition_operations(Xml_generator &xml,
- Storage_device const &device,
- Partition const &partition) const
-{
- Storage_target const target { device.label, partition.number };
-
- String<16> const version(device.label, ".", partition.number);
-
- bool const whole_device = !partition.number.valid();
-
- bool const device_in_use = (_used_target.device == device.label);
-
- bool const target_in_use = (_used_target == target)
- || (whole_device && device_in_use)
- || partition.file_system_inspected;
-
- bool const relabel_in_progress = device.relabel_in_progress();
-
- bool const expand_in_progress = device.expand_in_progress();
-
- bool const format_selected = _operation_item.selected("format");
-
- bool const expand_selected = _operation_item.selected("expand");
-
- if (partition.file_system.accessible() && !format_selected
- && !expand_selected && !expand_in_progress) {
-
- if (!partition.check_in_progress && !partition.format_in_progress
- && partition.file_system.accessible() && !relabel_in_progress) {
-
- xml.node("button", [&] () {
- _inspect_item.gen_button_attr(xml, "browse");
- xml.attribute("version", version);
-
- if (partition.file_system_inspected)
- xml.attribute("selected", "yes");
-
- xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
- });
- }
-
- if ((!_used_target.valid() || _used_target == target)
- && !partition.check_in_progress && !partition.format_in_progress
- && !relabel_in_progress) {
-
- xml.node("button", [&] () {
- xml.attribute("version", version);
- _use_item.gen_button_attr(xml, "use");
- if (_used_target == target)
- xml.attribute("selected", "yes");
- xml.node("label", [&] () { xml.attribute("text", "Use"); });
- });
- }
-
- if ((device.all_partitions_idle() || partition.relabel_in_progress())
- && partition.genode() && !device_in_use) {
-
- xml.node("button", [&] () {
-
- /* support hovering only if no relabeling is in progress */
- if (partition.relabel_in_progress())
- xml.attribute("name", "relabel");
- else
- _relabel_item.gen_button_attr(xml, "relabel");
-
- xml.attribute("version", version);
-
- if (partition.genode_default() || partition.relabel_in_progress())
- xml.attribute("selected", "yes");
-
- xml.node("label", [&] () {
- xml.attribute("text", "Default"); });
- });
- if (partition.relabel_in_progress())
- xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
- }
-
- if (!target_in_use && !partition.format_in_progress && partition.checkable()
- && !relabel_in_progress) {
-
- xml.node("button", [&] () {
- _operation_item.gen_button_attr(xml, "check");
- xml.attribute("version", version);
-
- if (partition.check_in_progress)
- xml.attribute("selected", "yes");
-
- xml.node("label", [&] () { xml.attribute("text", "Check"); });
- });
- if (partition.check_in_progress)
- xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
- }
- }
-
- bool const whole_device_with_partition_in_use =
- whole_device && !device.all_partitions_idle();
-
- bool const format_button_visible = !target_in_use
- && !whole_device_with_partition_in_use
- && !partition.check_in_progress
- && !expand_in_progress
- && !relabel_in_progress
- && !_operation_item.selected("expand");
-
- bool const expand_button_visible = !target_in_use
- && !whole_device
- && !partition.check_in_progress
- && !partition.format_in_progress
- && !relabel_in_progress
- && partition.expandable()
- && !_operation_item.selected("format");
-
- bool const progress_msg_visible =
- (_operation_item.selected("format") && partition.format_in_progress)
- || (_operation_item.selected("expand") && partition.expand_in_progress());
-
- bool const confirm_visible =
- (_operation_item.selected("format") && !partition.format_in_progress)
- || (_operation_item.selected("expand") && !partition.expand_in_progress());
-
- if (format_button_visible) {
- xml.node("button", [&] () {
- _operation_item.gen_button_attr(xml, "format");
- xml.attribute("version", version);
-
- if (partition.format_in_progress)
- xml.attribute("selected", "yes");
-
- if (whole_device) {
- xml.node("label", [&] () { xml.attribute("text", "Format device ..."); });
- } else {
- xml.node("label", [&] () { xml.attribute("text", "Format partition ..."); });
- }
- });
- }
-
- if (expand_button_visible) {
- xml.node("button", [&] () {
- _operation_item.gen_button_attr(xml, "expand");
- xml.attribute("version", version);
-
- if (partition.expand_in_progress())
- xml.attribute("selected", "yes");
-
- xml.node("label", [&] () { xml.attribute("text", "Expand ..."); });
- });
- }
-
- if (progress_msg_visible)
- xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
-
- if (confirm_visible) {
- xml.node("button", [&] () {
- _confirm_item.gen_button_attr(xml, "confirm");
- xml.attribute("version", version);
- xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
- });
- }
-}
+using namespace Sculpt;
-void Sculpt::Storage_dialog::_gen_partition(Xml_generator &xml,
- Storage_device const &device,
- Partition const &partition) const
-{
- bool const selected = _partition_item.selected(partition.number);
-
- gen_named_node(xml, "hbox", partition.number, [&] () {
- gen_named_node(xml, "float", "left", [&] () {
- xml.attribute("west", "yes");
- xml.node("hbox", [&] () {
- gen_named_node(xml, "button", "button", [&] () {
-
- if (_partition_item.hovered(partition.number))
- xml.attribute("hovered", "yes");
-
- if (selected)
- xml.attribute("selected", "yes");
-
- xml.node("label", [&] () { xml.attribute("text", partition.number); });
- });
-
- if (partition.label.length() > 1)
- gen_named_node(xml, "label", "label", [&] () {
- xml.attribute("text", String<80>(" (", partition.label, ") ")); });
-
- Storage_target const target { device.label, partition.number };
- if (_used_target == target)
- gen_named_node(xml, "label", "used", [&] () { xml.attribute("text", "* "); });
- });
- });
-
- gen_named_node(xml, "float", "right", [&] () {
- xml.attribute("east", "yes");
- xml.node("label", [&] () {
- xml.attribute("text", String<64>(partition.capacity, " ")); });
- });
- });
-
- if (selected)
- _gen_partition_operations(xml, device, partition);
-}
-
-
-void Sculpt::Storage_dialog::_gen_block_device(Xml_generator &xml,
- Block_device const &dev) const
+void Storage_dialog::_gen_block_device(Xml_generator &xml,
+ Block_device const &dev) const
{
bool const selected = _device_item.selected(dev.label);
@@ -257,23 +55,13 @@ void Sculpt::Storage_dialog::_gen_block_device(Xml_generator &xml,
});
});
- if (selected) {
- xml.node("frame", [&] () {
- xml.attribute("name", dev.label);
- xml.node("vbox", [&] () {
- dev.partitions.for_each([&] (Partition const &partition) {
- _gen_partition(xml, dev, partition); });
-
- if (!_partition_item.any_selected())
- _gen_partition_operations(xml, dev, *dev.whole_device_partition);
- });
- });
- }
+ if (_storage_device_dialog.constructed() && selected)
+ _storage_device_dialog->generate(xml, dev);
}
-void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &xml,
- Usb_storage_device const &dev) const
+void Storage_dialog::_gen_usb_storage_device(Xml_generator &xml,
+ Usb_storage_device const &dev) const
{
bool const discarded = dev.discarded();
bool const selected = !discarded && _device_item.selected(dev.label);
@@ -290,9 +78,7 @@ void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &x
xml.node("hbox", [&] () {
gen_named_node(xml, "float", "info", [&] () {
xml.attribute("west", "yes");
-
xml.node("hbox", [&] () {
-
gen_named_node(xml, "label", "device", [&] () {
xml.attribute("text", dev.label); });
@@ -309,7 +95,8 @@ void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &x
});
typedef String<64> Info;
- Info const info = dev.discarded() ? Info("unsupported") : Info(dev.capacity);
+ Info const info = dev.discarded() ? Info(" unsupported")
+ : Info(" ", dev.capacity);
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
@@ -318,224 +105,68 @@ void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &x
});
});
- if (selected)
- xml.node("frame", [&] () {
- xml.attribute("name", dev.label);
- xml.node("vbox", [&] () {
- dev.partitions.for_each([&] (Partition const &partition) {
- _gen_partition(xml, dev, partition); });
-
- if (!_partition_item.any_selected())
- _gen_partition_operations(xml, dev, *dev.whole_device_partition);
- });
- });
+ if (_storage_device_dialog.constructed() && selected)
+ _storage_device_dialog->generate(xml, dev);
}
-void Sculpt::Storage_dialog::_gen_ram_fs(Xml_generator &xml) const
+void Storage_dialog::gen_block_devices(Xml_generator &xml) const
{
- bool const selected = _device_item.selected("ram_fs");
-
- gen_named_node(xml, "button", "ram_fs", [&] () {
-
- if (_device_item.hovered("ram_fs"))
- xml.attribute("hovered", "yes");
-
- if (selected)
- xml.attribute("selected", "yes");
-
- xml.node("hbox", [&] () {
- gen_named_node(xml, "float", "info", [&] () {
- xml.attribute("west", "yes");
-
- xml.node("hbox", [&] () {
-
- gen_named_node(xml, "label", "device", [&] () {
- xml.attribute("text", "ram (in-memory file system) "); });
-
- if (_used_target.device == "ram_fs")
- gen_named_node(xml, "label", "used", [&] () {
- xml.attribute("text", "* "); });
- });
- });
-
- gen_named_node(xml, "float", "capacity", [&] () {
- xml.attribute("east", "yes");
- xml.node("label", [&] () {
- Capacity const capacity { _ram_fs_state.ram_quota().value };
- xml.attribute("text", String<64>(capacity)); }); });
- });
- });
-
- if (selected) {
- xml.node("frame", [&] () {
- xml.attribute("name", "ram_fs_operations");
- xml.node("vbox", [&] () {
-
- xml.node("button", [&] () {
- _inspect_item.gen_button_attr(xml, "browse");
-
- if (_ram_fs_state.inspected)
- xml.attribute("selected", "yes");
-
- xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
- });
-
- if (!_used_target.valid() || _used_target.ram_fs()) {
- xml.node("button", [&] () {
- _use_item.gen_button_attr(xml, "use");
- if (_used_target.ram_fs())
- xml.attribute("selected", "yes");
- xml.node("label", [&] () { xml.attribute("text", "Use"); });
- });
- }
-
- if (!_used_target.ram_fs() && !_ram_fs_state.inspected) {
- xml.node("button", [&] () {
- _operation_item.gen_button_attr(xml, "reset");
-
- xml.node("label", [&] () { xml.attribute("text", "Reset ..."); });
- });
-
- if (_operation_item.selected("reset")) {
- xml.node("button", [&] () {
- _confirm_item.gen_button_attr(xml, "confirm");
- xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
- });
- }
- }
- });
- });
- }
+ _storage_devices.block_devices.for_each([&] (Block_device const &dev) {
+ _gen_block_device(xml, dev); });
}
-void Sculpt::Storage_dialog::generate(Xml_generator &xml, bool expanded) const
+void Storage_dialog::gen_usb_storage_devices(Xml_generator &xml) const
{
- gen_named_node(xml, "frame", "storage", [&] () {
- xml.node("vbox", [&] () {
- gen_named_node(xml, "label", "title", [&] () {
- xml.attribute("text", "Storage");
- xml.attribute("font", "title/regular");
- });
-
- if (!expanded)
- return;
-
- _storage_devices.block_devices.for_each([&] (Block_device const &dev) {
- _gen_block_device(xml, dev); });
- _storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
- _gen_usb_storage_device(xml, dev); });
-
- _gen_ram_fs(xml);
- });
- });
+ _storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
+ _gen_usb_storage_device(xml, dev); });
}
-void Sculpt::Storage_dialog::hover(Xml_node hover)
+Dialog::Hover_result Storage_dialog::hover(Xml_node hover)
{
- bool const changed =
- _device_item .match(hover, "vbox", "button", "name") |
- _partition_item.match(hover, "vbox", "frame", "vbox", "hbox", "name") |
- _use_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
- _relabel_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
- _inspect_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
- _operation_item.match(hover, "vbox", "frame", "vbox", "button", "name") |
- _confirm_item .match(hover, "vbox", "frame", "vbox", "button", "name");
+ Hover_result result = Hover_result::UNMODIFIED;
- if (changed)
- _dialog_generator.generate_dialog();
+ if (_storage_device_dialog.constructed() &&
+ _storage_device_dialog->hover(hover) == Hover_result::CHANGED)
+ result = Hover_result::CHANGED;
+
+ return any_hover_changed(result, _device_item.match(hover, "button", "name"));
}
-void Sculpt::Storage_dialog::click(Action &action)
+Dialog::Click_result Storage_dialog::click(Action &action)
{
- Selectable_item::Id const old_selected_device = _device_item._selected;
- Selectable_item::Id const old_selected_partition = _partition_item._selected;
+ Selectable_item::Id const old_selected_device = _device_item._selected;
_device_item.toggle_selection_on_click();
- _partition_item.toggle_selection_on_click();
- if (!_device_item.selected(old_selected_device))
- _partition_item.reset();
+ if (old_selected_device != _device_item._selected) {
- if (!_device_item.selected(old_selected_device)
- || !_partition_item.selected(old_selected_partition))
- reset_operation();
-
- Storage_target const target = _selected_storage_target();
-
- if (_operation_item.hovered("format")) {
- if (_operation_item.selected("format"))
- action.cancel_format(_selected_storage_target());
- else
- _operation_item.toggle_selection_on_click();
+ _storage_device_dialog.destruct();
+ _storage_device_dialog.conditional(_device_item.any_selected(),
+ _device_item._selected,
+ _storage_devices, _used_target);
+ return Click_result::CONSUMED;
}
- if (_operation_item.hovered("expand")) {
- if (_operation_item.selected("expand"))
- action.cancel_expand(_selected_storage_target());
- else
- _operation_item.toggle_selection_on_click();
+ if (_storage_device_dialog.constructed()
+ && _storage_device_dialog->click(action) == Click_result::CONSUMED) {
+
+ return Click_result::CONSUMED;
}
- /* toggle confirmation button when clicking on ram_fs reset */
- if (_operation_item.hovered("reset"))
- _operation_item.toggle_selection_on_click();
-
- if (_operation_item.hovered("check"))
- action.check(target);
-
- /* toggle file browser */
- if (_inspect_item.hovered("browse"))
- action.toggle_file_browser(target);
-
- if (_use_item.hovered("use")) {
-
- /* release currently used device */
- if (target.valid() && target == _used_target)
- action.use(Storage_target{});
-
- /* select new used device if none is defined */
- else if (!_used_target.valid())
- action.use(target);
- }
-
- if (_relabel_item.hovered("relabel"))
- action.toggle_default_storage_target(target);
-
- if (_confirm_item.hovered("confirm")) {
- _confirm_item.propose_activation_on_click();
- }
-
- _dialog_generator.generate_dialog();
+ return Click_result::IGNORED;
}
-void Sculpt::Storage_dialog::clack(Action &action)
+Dialog::Clack_result Storage_dialog::clack(Action &action)
{
- if (_confirm_item.hovered("confirm")) {
+ if (_storage_device_dialog.constructed()
+ && _storage_device_dialog->clack(action) == Clack_result::CONSUMED)
+ return Clack_result::CONSUMED;
- _confirm_item.confirm_activation_on_clack();
-
- if (_confirm_item.activated("confirm")) {
-
- Storage_target const target = _selected_storage_target();
-
- if (_operation_item.selected("format"))
- action.format(target);
-
- if (_operation_item.selected("expand"))
- action.expand(target);
-
- if (target.ram_fs() && _operation_item.selected("reset"))
- action.reset_ram_fs();
- }
- } else {
- _confirm_item.reset();
- }
-
- _dialog_generator.generate_dialog();
+ return Clack_result::IGNORED;
}
diff --git a/repos/gems/src/app/sculpt_manager/view/storage_dialog.h b/repos/gems/src/app/sculpt_manager/view/storage_dialog.h
index 24c5639d1..c2968d49b 100644
--- a/repos/gems/src/app/sculpt_manager/view/storage_dialog.h
+++ b/repos/gems/src/app/sculpt_manager/view/storage_dialog.h
@@ -17,98 +17,51 @@
#include
#include
#include
-#include
#include
-#include
-#include
+#include
namespace Sculpt { struct Storage_dialog; }
struct Sculpt::Storage_dialog : Dialog
{
- Env &_env;
-
- Dialog::Generator &_dialog_generator;
-
Storage_devices const &_storage_devices;
- Ram_fs_state const &_ram_fs_state;
-
- Selectable_item _device_item { };
- Selectable_item _partition_item { };
- Hoverable_item _use_item { };
- Hoverable_item _relabel_item { };
- Hoverable_item _inspect_item { };
- Selectable_item _operation_item { };
- Activatable_item _confirm_item { };
-
- void generate(Xml_generator &, bool expanded) const;
-
- void _gen_block_device(Xml_generator &, Block_device const &) const;
-
- void _gen_partition(Xml_generator &, Storage_device const &, Partition const &) const;
-
- void _gen_partition_operations(Xml_generator &, Storage_device const &, Partition const &) const;
-
- void _gen_usb_storage_device(Xml_generator &, Usb_storage_device const &) const;
-
- void _gen_ram_fs(Xml_generator &) const;
-
- void hover(Xml_node hover) override;
+ Selectable_item _device_item { };
Storage_target const &_used_target;
- struct Action : Interface
- {
- virtual void format(Storage_target const &) = 0;
+ Constructible _storage_device_dialog { };
- virtual void cancel_format(Storage_target const &) = 0;
+ void _gen_block_device (Xml_generator &, Block_device const &) const;
+ void _gen_usb_storage_device(Xml_generator &, Usb_storage_device const &) const;
- virtual void expand(Storage_target const &) = 0;
+ void generate(Xml_generator &) const override { };
- virtual void cancel_expand(Storage_target const &) = 0;
+ void gen_block_devices (Xml_generator &) const;
+ void gen_usb_storage_devices(Xml_generator &) const;
- virtual void check(Storage_target const &) = 0;
+ Hover_result hover(Xml_node hover) override;
- virtual void toggle_file_browser(Storage_target const &) = 0;
+ using Action = Storage_device_dialog::Action;
- virtual void toggle_default_storage_target(Storage_target const &) = 0;
-
- virtual void use(Storage_target const &) = 0;
-
- virtual void reset_ram_fs() = 0;
- };
-
- Storage_target _selected_storage_target() const
- {
- Partition::Number partition = (_partition_item._selected == "")
- ? Partition::Number { }
- : Partition::Number(_partition_item._selected);
-
- return Storage_target { _device_item._selected, partition };
- }
+ void reset() override { }
void reset_operation()
{
- _operation_item.reset();
- _confirm_item.reset();
-
- _dialog_generator.generate_dialog();
+ if (_storage_device_dialog.constructed())
+ _storage_device_dialog->reset_operation();
}
- void click(Action &action);
+ Click_result click(Action &);
+ Clack_result clack(Action &);
- void clack(Action &action);
-
- Storage_dialog(Env &env, Dialog::Generator &dialog_generator,
- Storage_devices const &storage_devices,
- Ram_fs_state const &ram_fs_state, Storage_target const &used)
+ Storage_dialog(Storage_devices const &storage_devices,
+ Storage_target const &used)
:
- _env(env), _dialog_generator(dialog_generator),
- _storage_devices(storage_devices), _ram_fs_state(ram_fs_state),
+ _storage_devices(storage_devices),
_used_target(used)
{ }
};
-#endif /* _STORAGE_DIALOG_H_ */
+#endif /* _VIEW__STORAGE_DIALOG_H_ */