sculpt: apply Dialog API to diag, panel, and graph

This patch partially converts the Sculpt manager to the dialog API.
At this stage, both the old utilities and the new dialog API are still
used simultaneously.

Issue #5008
This commit is contained in:
Norman Feske 2023-07-19 17:08:27 +02:00 committed by Christian Helmuth
parent 0c40d52010
commit ffc25fde53
31 changed files with 1454 additions and 1590 deletions

View File

@ -2,7 +2,7 @@ SRC_DIR := src/app/sculpt_manager
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
MIRROR_FROM_REP_DIR := include/depot src/app/depot_deploy
MIRROR_FROM_REP_DIR := include/depot src/app/depot_deploy include/dialog
content: $(MIRROR_FROM_REP_DIR)

View File

@ -95,7 +95,6 @@
<default-policy domain="default"/>
<capture/>
<event/>
<report clicked="yes"/>
</config>
<route>
<service name="Input"> <child name="gui_fb"/> </service>
@ -119,10 +118,9 @@
<policy label="decorator -> pointer" report="wm -> pointer"/>
<policy label="manager -> window_list" report="wm -> window_list"/>
<policy label="manager -> decorator_margins" report="decorator -> decorator_margins"/>
<policy label="manager -> clicked" report="nitpicker -> clicked"/>
<policy label="nitpicker -> focus" report="manager -> focus"/>
<policy label="runtime -> leitzentrale -> menu_view -> dialog"
report="manager -> menu_dialog"/>
<policy label="runtime -> leitzentrale -> diag_view -> dialog"
report="manager -> diag_dialog"/>
<policy label="runtime -> leitzentrale -> network_view -> dialog"
report="manager -> network_dialog"/>
<policy label="runtime -> leitzentrale -> settings_view -> dialog"
@ -137,8 +135,8 @@
report="manager -> panel_dialog"/>
<policy label="runtime -> leitzentrale -> runtime_view -> dialog"
report="manager -> runtime_dialog"/>
<policy label="manager -> menu_view_hover"
report="runtime -> leitzentrale -> menu_view -> hover"/>
<policy label="manager -> diag_view_hover"
report="runtime -> leitzentrale -> diag_view -> hover"/>
<policy label="manager -> network_view_hover"
report="runtime -> leitzentrale -> network_view -> hover"/>
<policy label="manager -> settings_view_hover"
@ -198,7 +196,7 @@
<policy label="runtime -> leitzentrale -> file_browser_view" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> network_view" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> runtime_view" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> menu_view" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> diag_view" decoration="no" motion="30"/>
<policy label="runtime -> leitzentrale -> popup_view" decoration="no" motion="20"/>
<policy label="runtime -> leitzentrale -> panel_view" decoration="no" motion="20"/>
<policy label_prefix="logo" decoration="no"/>
@ -259,7 +257,6 @@
<service name="ROM" label_suffix="_hover"> <child name="report_rom"/> </service>
<service name="ROM" label="window_list"> <child name="report_rom"/> </service>
<service name="ROM" label="decorator_margins"> <child name="report_rom"/> </service>
<service name="ROM" label="clicked"> <child name="report_rom"/> </service>
<service name="Gui"> <parent/> </service>
<any-service> <parent/> </any-service>
</route>

View File

@ -33,7 +33,7 @@ bool Sculpt::Deploy::update_child_conditions()
}
void Sculpt::Deploy::gen_child_diagnostics(Xml_generator &xml) const
void Sculpt::Deploy::view_diag(Scope<> &s) const
{
/*
* Collect messages in registry, avoiding duplicates
@ -59,7 +59,7 @@ void Sculpt::Deploy::gen_child_diagnostics(Xml_generator &xml) const
};
_children.for_each_unsatisfied_child([&] (Xml_node start, Xml_node launcher,
Start_name const &name) {
Start_name const &name) {
gen_missing_dependencies(start, name);
gen_missing_dependencies(launcher, name);
});
@ -67,17 +67,8 @@ void Sculpt::Deploy::gen_child_diagnostics(Xml_generator &xml) const
/*
* Generate dialog elements, drop consumed messages from the registry
*/
int count = 0;
messages.for_each([&] (Registered_message &message) {
gen_named_node(xml, "hbox", String<20>(count++), [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("label", [&] () {
xml.attribute("text", message);
xml.attribute("font", "annotation/regular");
});
});
});
s.sub_scope<Left_annotation>(message);
destroy(_alloc, &message);
});
}
@ -170,7 +161,7 @@ void Sculpt::Deploy::handle_deploy()
/* apply runtime condition checks */
update_child_conditions();
_dialog_generator.generate_dialog();
_action.refresh_deploy_dialog();
_runtime_config_generator.generate_runtime_config();
}
}

View File

@ -45,7 +45,9 @@ struct Sculpt::Deploy
Runtime_info const &_runtime_info;
Deprecated_dialog::Generator &_dialog_generator;
struct Action : Interface { virtual void refresh_deploy_dialog() = 0; };
Action &_action;
Runtime_config_generator &_runtime_config_generator;
@ -248,7 +250,7 @@ struct Sculpt::Deploy
return !all_satisfied;
}
void gen_child_diagnostics(Xml_generator &xml) const;
void view_diag(Scope<> &) const;
void gen_runtime_start_nodes(Xml_generator &, Prio_levels, Affinity::Space) const;
@ -291,7 +293,7 @@ struct Sculpt::Deploy
Deploy(Env &env, Allocator &alloc, Registry<Child_state> &child_states,
Runtime_info const &runtime_info,
Deprecated_dialog::Generator &dialog_generator,
Action &action,
Runtime_config_generator &runtime_config_generator,
Depot_query &depot_query,
Attached_rom_dataspace const &launcher_listing_rom,
@ -300,7 +302,7 @@ struct Sculpt::Deploy
:
_env(env), _alloc(alloc), _child_states(child_states),
_runtime_info(runtime_info),
_dialog_generator(dialog_generator),
_action(action),
_runtime_config_generator(runtime_config_generator),
_depot_query(depot_query),
_launcher_listing_rom(launcher_listing_rom),

View File

@ -18,43 +18,90 @@
using namespace Sculpt;
void Graph::_gen_selected_node_content(Xml_generator &xml, Start_name const &name,
Runtime_state::Info const &info) const
namespace Dialog { struct Parent_node; }
struct Dialog::Parent_node : Sub_scope
{
template <typename SCOPE, typename TEXT>
static void view_sub_scope(SCOPE &s, TEXT const &text)
{
s.node("frame", [&] {
s.sub_node("label", [&] {
s.attribute("text", Sculpt::Start_name(" ", text, " ")); }); });
}
template <typename AT, typename FN>
static void with_narrowed_at(AT const &, FN const &) { }
};
namespace Dialog { struct Selectable_node; }
struct Dialog::Selectable_node
{
struct Attr
{
bool selected;
bool important;
Start_name primary_dep;
Start_name pretty_name;
};
template <typename FN>
static void view(Scope<Depgraph> &s, Id const &id,
Attr const &attr, FN const &selected_fn)
{
s.sub_scope<Frame>(id, [&] (Scope<Depgraph, Frame> &s) {
if (!attr.important)
s.attribute("style", "unimportant");
if (attr.primary_dep.valid()) {
s.attribute("dep", attr.primary_dep);
if (!attr.important)
s.attribute("dep_visible", false);
}
s.sub_scope<Vbox>([&] (Scope<Depgraph, Frame, Vbox> &s) {
s.sub_scope<Button>(id, [&] (Scope<Depgraph, Frame, Vbox, Button> &s) {
if (!attr.important) s.attribute("style", "unimportant");
if (s.hovered()) s.attribute("hovered", "yes");
if (attr.selected) s.attribute("selected", "yes");
s.sub_scope<Dialog::Label>(attr.pretty_name);
});
if (attr.selected)
selected_fn(s);
});
});
}
};
void Graph::_view_selected_node_content(Scope<Depgraph, Frame, Vbox> &s,
Start_name const &name,
Runtime_state::Info const &info) const
{
if (_deploy_children.exists(name)) {
gen_named_node(xml, "frame", "operations", [&] () {
xml.node("hbox", [&] () {
gen_named_node(xml, "button", "remove", [&] () {
_action_item.gen_button_attr(xml, "remove");
xml.node("label", [&] () {
xml.attribute("text", "Remove"); }); });
gen_named_node(xml, "button", "restart", [&] () {
_action_item.gen_button_attr(xml, "restart");
xml.node("label", [&] () {
xml.attribute("text", "Restart"); }); });
});
});
s.sub_scope<Frame>([&] (Scope<Depgraph, Frame, Vbox, Frame> &s) {
s.sub_scope<Hbox>([&] (Scope<Depgraph, Frame, Vbox, Frame, Hbox> &s) {
s.widget(_remove);
s.widget(_restart); }); });
} else if (name == "nic_drv" ||
name == "wifi_drv") {
gen_named_node(xml, "frame", "operations", [&] () {
xml.node("hbox", [&] () {
gen_named_node(xml, "button", "restart", [&] () {
_action_item.gen_button_attr(xml, "restart");
xml.node("label", [&] () {
xml.attribute("text", "Restart"); }); });
});
});
s.sub_scope<Frame>([&] (Scope<Depgraph, Frame, Vbox, Frame> &s) {
s.sub_scope<Hbox>([&] (Scope<Depgraph, Frame, Vbox, Frame, Hbox> &s) {
s.widget(_restart); }); });
}
if (name == "ram_fs")
gen_named_node(xml, "frame", "ram_fs_operations", [&] () {
xml.node("vbox", [&] () {
_ram_fs_dialog.generate(xml, _ram_fs_state); }); });
s.widget(_ram_fs_dialog, _sculpt_partition, _ram_fs_state);
String<100> const
ram (Capacity{info.assigned_ram - info.avail_ram}, " / ",
@ -62,341 +109,221 @@ void Graph::_gen_selected_node_content(Xml_generator &xml, Start_name const &nam
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); });
s.sub_scope<Min_ex>(25);
s.sub_scope<Dialog::Label>(ram);
s.sub_scope<Dialog::Label>(caps);
}
void Graph::_gen_parent_node(Xml_generator &xml, Start_name const &name,
Label const &label) const
void Graph::_view_storage_node(Scope<Depgraph> &s) 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 (Feature::PRESENT_PLUS_MENU && _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", "+"); }); });
}
if (Feature::STORAGE_DIALOG_HOSTED_IN_GRAPH)
_gen_storage_node(xml);
else
_gen_parent_node(xml, "storage", "Storage");
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 hidden = (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"
|| name == "system_view"
|| name == "manager_keyboard");
if (hidden)
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;
if (name == "ram_fs")
return;
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);
});
});
}
});
});
}
Deprecated_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");
Deprecated_dialog::Hover_result const hover_result = Deprecated_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"),
_action_item .match(hover, "depgraph", "frame", "vbox",
"frame", "hbox", "button", "name"));
if (_add_button_item.hovered("global+")) {
/* update anchor geometry of popup menu */
auto hovered_rect = [] (Xml_node const dialog)
Selectable_node::view(s, Id { "storage" },
{
if (!dialog.has_type("dialog"))
return Rect();
.selected = _storage_selected,
.important = !any_selected || _runtime_state.storage_in_tcb(),
.primary_dep = { },
.pretty_name = "Storage"
},
[&] (Scope<Depgraph, Frame, Vbox> &s) {
s.sub_scope<Frame>([&] (Scope<Depgraph, Frame, Vbox, Frame> &s) {
s.widget(_block_devices_dialog); });
}
);
}
if (!dialog.has_sub_node("depgraph"))
return Rect();
Xml_node const depgraph = dialog.sub_node("depgraph");
void Graph::_view_usb_node(Scope<Depgraph> &s) const
{
bool const any_selected = _runtime_state.selected().valid();
if (!depgraph.has_sub_node("button"))
return Rect();
Selectable_node::view(s, Id { "usb" },
{
.selected = _usb_selected,
.important = !any_selected || _runtime_state.usb_in_tcb(),
.primary_dep = { },
.pretty_name = "USB"
},
[&] (Scope<Depgraph, Frame, Vbox> &s) {
s.sub_scope<Frame>([&] (Scope<Depgraph, Frame, Vbox, Frame> &s) {
s.widget(_usb_devices_dialog); });
}
);
}
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));
void Graph::view(Scope<Depgraph> &s) const
{
if (Feature::PRESENT_PLUS_MENU && _sculpt_partition.valid())
s.widget(_plus, _popup_state == Popup::VISIBLE);
if (Feature::STORAGE_DIALOG_HOSTED_IN_GRAPH)
_view_storage_node(s);
else
s.sub_scope<Parent_node>(Id { "storage" }, "Storage");
if (_storage_devices.usb_present)
_view_usb_node(s);
else
s.sub_scope<Parent_node>(Id { "usb" }, "USB");
/* parent roles */
s.sub_scope<Parent_node>(Id { "hardware" }, "Hardware");
s.sub_scope<Parent_node>(Id { "hardware" }, "Hardware");
s.sub_scope<Parent_node>(Id { "config" }, "Config");
s.sub_scope<Parent_node>(Id { "info" }, "Info");
s.sub_scope<Parent_node>(Id { "GUI" }, "GUI");
using Component = Runtime_config::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 pretty_name { Pretty(name) };
if (name == "mmcblk0.part_block")
pretty_name = "mmcblk0";
if (name == "mmcblk0.1.fs")
pretty_name = "1.fs";
/* omit sculpt's helpers from the graph */
bool const hidden = (name == "runtime_view"
|| name == "popup_view"
|| name == "main_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"
|| name == "system_view"
|| name == "diag_view"
|| name == "manager_keyboard");
if (hidden)
return;
Runtime_state::Info const info = _runtime_state.info(name);
bool const unimportant = any_selected && !info.tcb;
Start_name primary_dep = component.primary_dependency;
if (primary_dep == "default_fs_rw")
primary_dep = _sculpt_partition.fs();
Selectable_node::view(s, Id { name },
{
.selected = info.selected,
.important = !unimportant,
.primary_dep = primary_dep,
.pretty_name = pretty_name
},
[&] (Scope<Depgraph, Frame, Vbox> &s) {
_view_selected_node_content(s, name, info);
}
);
});
_runtime_config.for_each_component([&] (Component const &component) {
Start_name const name = component.name;
if (name == "ram_fs")
return;
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();
s.node("dep", [&] () {
s.attribute("node", name);
s.attribute("on", dep);
});
});
}
});
}
void Graph::click(Clicked_at const &at, Action &action)
{
/* select node */
Id const id = at.matching_id<Depgraph, Frame, Vbox, Button>();
if (id.valid()) {
_storage_selected = !_storage_selected && (id.value == "storage");
_usb_selected = !_usb_selected && (id.value == "usb");
if (_usb_selected) _usb_devices_dialog .reset();
if (_storage_selected) _block_devices_dialog.reset();
_runtime_state.toggle_selection(id.value, _runtime_config);
}
_plus.propagate(at, [&] {
auto popup_anchor = [] (Xml_node const dialog)
{
Rect result { };
dialog.with_optional_sub_node("depgraph", [&] (Xml_node const &depgraph) {
depgraph.with_optional_sub_node("button", [&] (Xml_node const &button) {
result = Rect(Point::from_xml(dialog) + Point::from_xml(depgraph) +
Point::from_xml(button),
Area::from_xml(button)); });
});
return result;
};
_popup_anchor = hovered_rect(hover);
}
action.open_popup_dialog(popup_anchor(at._location));
});
return hover_result;
_ram_fs_dialog .propagate(at, _sculpt_partition, action);
_block_devices_dialog.propagate(at, action);
_usb_devices_dialog .propagate(at, action);
_remove .propagate(at);
_restart.propagate(at);
}
void Graph::click(Action &action)
void Graph::clack(Clacked_at const &at, Action &action, Ram_fs_dialog::Action &ram_fs_action)
{
if (_ram_fs_dialog.click(action) == Click_result::CONSUMED)
return;
_ram_fs_dialog .propagate(at, ram_fs_action);
_block_devices_dialog.propagate(at, action);
_usb_devices_dialog .propagate(at, action);
if (_storage_dialog_visible())
if (_storage_dialog->click(action) == Click_result::CONSUMED)
return;
_remove.propagate(at, [&] {
action.remove_deployed_component(_runtime_state.selected());
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,
/*
* Unselect the removed component to bring graph into
* default state.
*/
_runtime_state.toggle_selection(_runtime_state.selected(),
_runtime_config);
_action_item.reset();
}
});
if (_action_item.hovered("remove") || _action_item.hovered("restart"))
_action_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 (_action_item.hovered("remove")) {
_action_item.confirm_activation_on_clack();
if (_action_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);
}
}
if (_action_item.hovered("restart")) {
_action_item.confirm_activation_on_clack();
if (_action_item.activated("restart"))
action.restart_deployed_component(_runtime_state.selected());
}
_action_item.reset();
_restart.propagate(at, [&] {
action.restart_deployed_component(_runtime_state.selected());
});
}

View File

@ -37,55 +37,42 @@
namespace Sculpt { struct Graph; }
struct Sculpt::Graph : Deprecated_dialog
struct Sculpt::Graph : Widget<Depgraph>
{
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;
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;
Hoverable_item _node_button_item { };
Hoverable_item _add_button_item { };
Activatable_item _action_item { };
Hosted<Depgraph, Toggle_button> _plus { Id { "+" } };
/*
* Defined when '+' button is hovered
*/
Rect _popup_anchor { };
Hosted<Depgraph, Frame, Vbox, Ram_fs_dialog>
_ram_fs_dialog { Id { "ram_fs_dialog" } };
Ram_fs_dialog _ram_fs_dialog;
Hosted<Depgraph, Frame, Vbox, Frame, Hbox, Deferred_action_button>
_remove { Id { "Remove" } },
_restart { Id { "Restart" } };
Hosted<Depgraph, Frame, Vbox, Frame, Block_devices_dialog>
_block_devices_dialog { Id { "block_devices" },
_storage_devices, _sculpt_partition };
Hosted<Depgraph, Frame, Vbox, Frame, Usb_devices_dialog>
_usb_devices_dialog { Id { "usb_devices" },
_storage_devices, _sculpt_partition };
bool _storage_selected = false;
bool _usb_selected = false;
bool _storage_dialog_visible() const { return _storage_selected || _usb_selected; }
void _view_selected_node_content(Scope<Depgraph, Frame, Vbox> &,
Start_name const &,
Runtime_state::Info const &) const;
Reconstructible<Storage_dialog> _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_storage_operation()
{
if (_storage_dialog.constructed())
_storage_dialog->reset_operation();
}
void _view_storage_node(Scope<Depgraph> &) const;
void _view_usb_node(Scope<Depgraph> &) const;
Graph(Runtime_state &runtime_state,
Runtime_config const &runtime_config,
@ -98,20 +85,26 @@ struct Sculpt::Graph : Deprecated_dialog
_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)
_deploy_children(deploy_children)
{ }
bool add_button_hovered() const { return _add_button_item._hovered.valid(); }
void view(Scope<Depgraph> &) const;
struct Action : Storage_dialog::Action
struct Action : Storage_device_dialog::Action
{
virtual void remove_deployed_component(Start_name const &) = 0;
virtual void restart_deployed_component(Start_name const &) = 0;
virtual void toggle_launcher_selector(Rect) = 0;
virtual void open_popup_dialog(Rect) = 0;
};
void click(Action &action);
void clack(Action &action, Ram_fs_dialog::Action &);
void click(Clicked_at const &, Action &);
void clack(Clacked_at const &, Action &, Ram_fs_dialog::Action &);
void reset_storage_operation()
{
_block_devices_dialog.reset_operation();
_usb_devices_dialog.reset_operation();
}
};
#endif /* _GRAPH_H_ */

View File

@ -26,6 +26,7 @@
#include <gpu_session/gpu_session.h>
#include <pin_state_session/pin_state_session.h>
#include <pin_control_session/pin_control_session.h>
#include <dialog/distant_runtime.h>
/* included from depot_deploy tool */
#include <children.h>
@ -37,7 +38,7 @@
#include <model/settings.h>
#include <model/presets.h>
#include <model/screensaver.h>
#include <view/download_status.h>
#include <view/download_status_dialog.h>
#include <view/popup_dialog.h>
#include <view/panel_dialog.h>
#include <view/settings_dialog.h>
@ -55,9 +56,9 @@ namespace Sculpt { struct Main; }
struct Sculpt::Main : Input_event_handler,
Deprecated_dialog::Generator,
Runtime_config_generator,
Storage::Target_user,
Deploy::Action,
Storage::Action,
Network::Action,
Graph::Action,
Panel_dialog::Action,
@ -70,7 +71,6 @@ struct Sculpt::Main : Input_event_handler,
Popup_dialog::Construction_info,
Depot_query,
Panel_dialog::State,
Deprecated_dialog,
Popup_dialog::Refresh,
Menu_view::Hover_update_handler,
Screensaver::Action
@ -229,10 +229,10 @@ struct Sculpt::Main : Input_event_handler,
return _prepare_version.value != _prepare_completed.value;
}
Storage _storage { _env, _heap, _child_states, *this, *this, *this };
Storage _storage { _env, _heap, _child_states, *this, *this };
/**
* Storage::Target_user interface
* Storage::Action interface
*/
void use_storage_target(Storage_target const &target) override
{
@ -245,9 +245,14 @@ struct Sculpt::Main : Input_event_handler,
_deploy.restart();
generate_runtime_config();
generate_dialog();
_generate_dialog();
}
/**
* Storage::Action interface
*/
void refresh_storage_dialog() override { _generate_dialog(); }
Network _network { _env, _heap, *this, _child_states, *this, _runtime_state, _pci_info };
Menu_view _network_menu_view { _env, _child_states, _network.dialog, "network_view",
@ -464,6 +469,11 @@ struct Sculpt::Main : Input_event_handler,
Deploy _deploy { _env, _heap, _child_states, _runtime_state, *this, *this, *this,
_launcher_listing_rom, _blueprint_rom, _download_queue };
/**
* Deploy::Action interface
*/
void refresh_deploy_dialog() override { _generate_dialog(); }
Attached_rom_dataspace _manual_deploy_rom { _env, "config -> deploy" };
void _handle_manual_deploy()
@ -525,77 +535,58 @@ struct Sculpt::Main : Input_event_handler,
return _storage._sculpt_partition.valid() && !_prepare_in_progress();
}
/**
* Deprecated_dialog interface
*/
Hover_result hover(Xml_node) override { return Hover_result::UNMODIFIED; }
void reset() override { }
/**
* Deprecated_dialog interface
*/
void generate(Xml_generator &xml) const override
struct Diag_dialog : Top_level_dialog
{
xml.node("vbox", [&] () {
if (_manually_managed_runtime)
return;
Main const &_main;
bool const network_missing = _deploy.update_needed()
&& !_network._nic_state.ready();
bool const show_diagnostics = _deploy.any_unsatisfied_child()
|| network_missing;
Allocator &_alloc;
auto gen_network_diagnostics = [&] (Xml_generator &xml)
{
if (!network_missing)
Diag_dialog(Main const &main, Allocator &alloc)
: Top_level_dialog("diag"), _main(main), _alloc(alloc) { }
void view(Scope<> &s) const override
{
s.sub_scope<Vbox>([&] (Scope<Vbox> &s) {
if (_main._manually_managed_runtime)
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");
});
bool const network_missing = _main._deploy.update_needed()
&& !_main._network._nic_state.ready();
bool const show_diagnostics = _main._deploy.any_unsatisfied_child()
|| network_missing;
if (show_diagnostics) {
Hosted<Vbox, Titled_frame> diag { Id { "Diagnostics" } };
s.widget(diag, [&] {
if (network_missing)
s.sub_scope<Left_annotation>("network needed for installation");
s.as_new_scope([&] (Scope<> &s) { _main._deploy.view_diag(s); });
});
});
};
}
if (show_diagnostics) {
gen_named_node(xml, "frame", "diagnostics", [&] () {
xml.node("vbox", [&] () {
Xml_node const state = _main._update_state_rom.xml();
xml.node("label", [&] () {
xml.attribute("text", "Diagnostics"); });
bool const download_in_progress =
_main._update_running() && state.attribute_value("progress", false);
xml.node("float", [&] () {
xml.node("vbox", [&] () {
gen_network_diagnostics(xml);
_deploy.gen_child_diagnostics(xml);
});
});
});
});
}
if (download_in_progress || _main._download_queue.any_failed_download()) {
Xml_node const state = _update_state_rom.xml();
Hosted<Vbox, Download_status_dialog> download_status { Id { "Download" } };
bool const download_in_progress =
(_update_running() && state.attribute_value("progress", false));
s.widget(download_status, state, _main._download_queue);
}
});
}
};
if (download_in_progress || _download_queue.any_failed_download())
gen_download_status(xml, state, _download_queue);
});
}
/**
* Deprecated_dialog::Generator interface
*/
void generate_dialog() override
void _generate_dialog()
{
_main_menu_view.generate();
_graph_menu_view.generate();
_diag_dialog.refresh();
_graph_view.refresh();
if (_system_visible)
_system_menu_view.generate();
@ -614,7 +605,7 @@ struct Sculpt::Main : Input_event_handler,
{
_manually_managed_runtime = !config.has_type("empty");
generate_runtime_config();
generate_dialog();
_generate_dialog();
}
void _generate_runtime_config(Xml_generator &) const;
@ -657,7 +648,7 @@ struct Sculpt::Main : Input_event_handler,
{
_runtime_config_rom.update();
_cached_runtime_config.update_from_xml(_runtime_config_rom.xml());
_graph_menu_view.generate();
_graph_view.refresh();
if (_selected_tab == Panel_dialog::Tab::FILES)
_file_browser_menu_view.generate();
@ -668,21 +659,7 @@ struct Sculpt::Main : Input_event_handler,
** Interactive operations **
****************************/
/*
* Track nitpicker's "clicked" report to reliably detect clicks outside
* any menu view (closing the popup window).
*/
Attached_rom_dataspace _clicked_rom { _env, "clicked" };
Signal_handler<Main> _clicked_handler {
_env.ep(), *this, &Main::_handle_clicked };
void _handle_clicked()
{
_clicked_rom.update();
_try_handle_click();
}
Dialog::Distant_runtime _dialog_runtime { _env };
Keyboard_focus _keyboard_focus { _env, _network.dialog, _network.wpa_passphrase,
*this, _system_dialog, _system_visible };
@ -697,56 +674,15 @@ struct Sculpt::Main : Input_event_handler,
Input::Seq_number const seq = *_clicked_seq_number;
auto click_outside_popup = [&] ()
{
Xml_node const clicked = _clicked_rom.xml();
/* used to detect clicks outside the popup dialog (for closing it) */
bool popup_dialog_clicked = false;
bool const popup_opened = (_popup_opened_seq_number.value == seq.value);
if (!clicked.has_attribute("seq"))
return false;
if (clicked.attribute_value("seq", 0u) != seq.value)
return false;
Label const popup_label { "wm -> runtime -> leitzentrale -> popup_view" };
if (clicked.attribute_value("label", Label()) == popup_label)
return false;
return true;
};
/* remove popup dialog when clicking somewhere outside */
if (click_outside_popup() && _popup.state == Popup::VISIBLE
&& !_graph.add_button_hovered()) {
_popup.state = Popup::OFF;
_popup_dialog.reset();
discard_construction();
/* de-select '+' button */
_graph_menu_view.generate();
/* remove popup window from window layout */
_handle_window_layout();
}
if (_main_menu_view.hovered(seq)) {
_main_menu_view.generate();
_clicked_seq_number.destruct();
}
else if (_graph_menu_view.hovered(seq)) {
_graph.click(*this);
_graph_menu_view.generate();
_clicked_seq_number.destruct();
}
else if (_popup_menu_view.hovered(seq)) {
if (_popup_menu_view.hovered(seq)) {
_popup_dialog.click(*this);
_popup_menu_view.generate();
_clicked_seq_number.destruct();
}
else if (_panel_menu_view.hovered(seq)) {
_panel_dialog.click(*this);
_clicked_seq_number.destruct();
popup_dialog_clicked = true;
}
else if (_settings_menu_view.hovered(seq)) {
_settings_dialog.click(*this);
@ -768,6 +704,20 @@ struct Sculpt::Main : Input_event_handler,
_file_browser_menu_view.generate();
_clicked_seq_number.destruct();
}
/* remove popup dialog when clicking somewhere outside */
if (!popup_dialog_clicked && !_popup_menu_view._hovered && !popup_opened) {
_popup.state = Popup::OFF;
_popup_dialog.reset();
discard_construction();
/* de-select '+' button */
_graph_view.refresh();
/* remove popup window from window layout */
_handle_window_layout();
_clicked_seq_number.destruct();
}
}
void _try_handle_clack()
@ -777,16 +727,7 @@ struct Sculpt::Main : Input_event_handler,
Input::Seq_number const seq = *_clacked_seq_number;
if (_main_menu_view.hovered(seq)) {
_main_menu_view.generate();
_clacked_seq_number.destruct();
}
else if (_graph_menu_view.hovered(seq)) {
_graph.clack(*this, _storage);
_graph_menu_view.generate();
_clacked_seq_number.destruct();
}
else if (_system_menu_view.hovered(seq)) {
if (_system_menu_view.hovered(seq)) {
_system_dialog.clack();
_system_menu_view.generate();
_clacked_seq_number.destruct();
@ -825,10 +766,12 @@ struct Sculpt::Main : Input_event_handler,
*/
void handle_input_event(Input::Event const &ev) override
{
bool need_generate_dialog = false;
Keyboard_focus_guard focus_guard { *this };
Dialog::Event::Seq_number const seq_number { _global_input_seq_number.value };
_dialog_runtime.route_input_event(seq_number, ev);
if (ev.key_press(Input::BTN_LEFT) || ev.touch()) {
_clicked_seq_number.construct(_global_input_seq_number);
_try_handle_click();
@ -839,6 +782,8 @@ struct Sculpt::Main : Input_event_handler,
_try_handle_clack();
}
bool need_generate_dialog = false;
ev.handle_press([&] (Input::Keycode, Codepoint code) {
if (_keyboard_focus.target == Keyboard_focus::WPA_PASSPHRASE)
_network.handle_key_press(code);
@ -849,7 +794,7 @@ struct Sculpt::Main : Input_event_handler,
});
if (need_generate_dialog)
generate_dialog();
_generate_dialog();
}
/*
@ -859,8 +804,8 @@ struct Sculpt::Main : Input_event_handler,
{
_storage.toggle_inspect_view(target);
/* refresh visibility to inspect tab */
_panel_menu_view.generate();
/* refresh visibility of inspect tab */
_panel_dialog.refresh();
}
void use(Storage_target const &target) override
@ -870,7 +815,7 @@ struct Sculpt::Main : Input_event_handler,
_storage.use(target);
/* hide system panel button and system dialog when "un-using" */
_panel_menu_view.generate();
_panel_dialog.refresh();
_system_menu_view.generate();
_handle_window_layout();
}
@ -955,21 +900,28 @@ struct Sculpt::Main : Input_event_handler,
}
}
/* used to prevent closing the popup immediatedly after opened */
Input::Seq_number _popup_opened_seq_number { };
/*
* Graph::Action interface
*/
void toggle_launcher_selector(Rect anchor) override
void open_popup_dialog(Rect anchor) override
{
if (_popup.state == Popup::VISIBLE)
return;
_popup_opened_seq_number = _global_input_seq_number;
_popup_menu_view.generate();
_popup.anchor = anchor;
_popup.toggle();
_graph_menu_view.generate();
_popup.state = Popup::VISIBLE;
_graph_view.refresh();
_handle_window_layout();
}
void _refresh_panel_and_window_layout()
{
_panel_menu_view.generate();
_panel_dialog.refresh();
_handle_window_layout();
}
@ -1287,7 +1239,7 @@ struct Sculpt::Main : Input_event_handler,
_handle_window_layout();
/* reset state of the '+' button */
_graph_menu_view.generate();
_graph_view.refresh();
}
/*
@ -1336,7 +1288,7 @@ struct Sculpt::Main : Input_event_handler,
_deploy.update_installation();
generate_runtime_config();
generate_dialog();
_generate_dialog();
}
void remove_index(Depot::Archive::User const &user) override
@ -1362,11 +1314,18 @@ struct Sculpt::Main : Input_event_handler,
_runtime_state.with_construction([&] (Component const &c) { fn.with(c); });
}
Panel_dialog _panel_dialog { *this };
template <typename TOP_LEVEL_DIALOG>
struct Dialog_view : TOP_LEVEL_DIALOG, private Distant_runtime::View
{
template <typename... ARGS>
Dialog_view(Distant_runtime &runtime, ARGS &&... args)
: TOP_LEVEL_DIALOG(args...), Distant_runtime::View(runtime, *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", *this };
using Distant_runtime::View::refresh;
using Distant_runtime::View::min_width;
};
Dialog_view<Panel_dialog> _panel_dialog { _dialog_runtime, *this, *this };
Settings_dialog _settings_dialog { _settings };
@ -1383,9 +1342,7 @@ struct Sculpt::Main : Input_event_handler,
Ram_quota{4*1024*1024}, Cap_quota{150},
"system_dialog", "system_view_hover", *this };
Menu_view _main_menu_view { _env, _child_states, *this, "menu_view",
Ram_quota{4*1024*1024}, Cap_quota{150},
"menu_dialog", "menu_view_hover", *this };
Dialog_view<Diag_dialog> _diag_dialog { _dialog_runtime, *this, _heap };
Popup_dialog _popup_dialog { _env, *this, _launchers,
_network._nic_state, _network._nic_target,
@ -1450,9 +1407,36 @@ struct Sculpt::Main : Input_event_handler,
_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", *this };
struct Graph_dialog : Dialog::Top_level_dialog
{
Graph &_graph;
Graph::Action &_action;
Ram_fs_dialog::Action &_ram_fs_action;
Graph_dialog(Graph &graph, Graph::Action &action, Ram_fs_dialog::Action &ram_fs_action)
:
Top_level_dialog("runtime"),
_graph(graph), _action(action), _ram_fs_action(ram_fs_action)
{ }
void view(Scope<> &s) const override
{
s.sub_scope<Depgraph>([&] (Scope<Depgraph> &s) {
_graph.view(s); });
}
void click(Clicked_at const &at) override { _graph.click(at, _action); }
void clack(Clacked_at const &at) override { _graph.clack(at, _action, _ram_fs_action); }
void drag (Dragged_at const &) override { }
} _graph_dialog { _graph, *this, _storage };
Dialog::Distant_runtime::View
_graph_view { _dialog_runtime, _graph_dialog,
{ .opaque = false,
.background = { },
.initial_ram = { 8*1024*1024 } } };
Main(Env &env) : _env(env)
{
_manual_deploy_rom.sigh(_manual_deploy_handler);
@ -1473,7 +1457,6 @@ struct Sculpt::Main : Input_event_handler,
_blueprint_rom .sigh(_blueprint_handler);
_image_index_rom .sigh(_image_index_handler);
_editor_saved_rom .sigh(_editor_saved_handler);
_clicked_rom .sigh(_clicked_handler);
/*
* Generate initial configurations
@ -1488,7 +1471,6 @@ struct Sculpt::Main : Input_event_handler,
_storage.handle_storage_devices_update();
_handle_pci_devices();
_handle_runtime_config();
_handle_clicked();
/*
* Read static platform information
@ -1504,7 +1486,7 @@ struct Sculpt::Main : Input_event_handler,
_handle_manual_deploy();
generate_runtime_config();
generate_dialog();
_generate_dialog();
}
};
@ -1544,7 +1526,7 @@ void Sculpt::Main::_handle_window_layout()
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"),
diag_view_label ("runtime -> leitzentrale -> diag_view"),
popup_view_label ("runtime -> leitzentrale -> popup_view"),
system_view_label ("runtime -> leitzentrale -> system_view"),
settings_view_label ("runtime -> leitzentrale -> settings_view"),
@ -1683,7 +1665,7 @@ void Sculpt::Main::_handle_window_layout()
}
});
_with_window(window_list, menu_view_label, [&] (Xml_node win) {
_with_window(window_list, diag_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());
@ -1820,9 +1802,9 @@ void Sculpt::Main::_handle_gui_mode()
}
_screen_size = mode.area;
_panel_menu_view.min_width = _screen_size.w();
_panel_dialog.min_width = _screen_size.w();
unsigned const menu_width = max((unsigned)(_font_size_px*21.0), 320u);
_main_menu_view.min_width = menu_width;
_diag_dialog.min_width = menu_width;
_network_menu_view.min_width = menu_width;
/* font size may has changed, propagate fonts config of runtime view */
@ -1833,7 +1815,7 @@ void Sculpt::Main::_handle_gui_mode()
void Sculpt::Main::_handle_update_state()
{
_update_state_rom.update();
generate_dialog();
_generate_dialog();
Xml_node const update_state = _update_state_rom.xml();
@ -1858,7 +1840,7 @@ void Sculpt::Main::_handle_update_state()
_deploy.reattempt_after_installation();
}
generate_dialog();
_generate_dialog();
}
@ -1989,7 +1971,7 @@ void Sculpt::Main::_handle_runtime_state()
/* trigger update and deploy */
reconfigure_runtime = true;
_panel_menu_view.generate(); /* show "System" button */
_panel_dialog.refresh(); /* show "System" button */
}
}
@ -2047,12 +2029,15 @@ void Sculpt::Main::_handle_runtime_state()
regenerate_dialog = true;
}
if (_dialog_runtime.apply_runtime_state(state))
reconfigure_runtime = true;
if (refresh_storage)
_storage.handle_storage_devices_update();
if (regenerate_dialog) {
generate_dialog();
_graph_menu_view.generate();
_generate_dialog();
_graph_view.refresh();
}
if (reconfigure_runtime)
@ -2108,11 +2093,7 @@ void Sculpt::Main::_generate_runtime_config(Xml_generator &xml) const
xml.attribute("height", _affinity_space.height());
});
xml.node("start", [&] () {
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);
_dialog_runtime.gen_start_nodes(xml);
_settings_menu_view.gen_start_node(xml);
_system_menu_view.gen_start_node(xml);
_network_menu_view.gen_start_node(xml);

View File

@ -26,8 +26,6 @@ struct Sculpt::Popup : Noncopyable
Popup() { }
Rect anchor { };
void toggle() { state = (state == OFF) ? VISIBLE : OFF; }
};
#endif /* _MODEL__POPUP_H_ */

View File

@ -90,10 +90,10 @@ void Sculpt::Storage::handle_storage_devices_update()
}
}
_dialog_generator.generate_dialog();
_action.refresh_storage_dialog();
if (reconfigure_runtime)
_runtime_config_generator.generate_runtime_config();
_runtime.generate_runtime_config();
}

View File

@ -27,22 +27,21 @@
namespace Sculpt { struct Storage; }
struct Sculpt::Storage : Storage_dialog::Action, Ram_fs_dialog::Action
struct Sculpt::Storage : Storage_device_dialog::Action, Ram_fs_dialog::Action
{
Env &_env;
Allocator &_alloc;
Deprecated_dialog::Generator &_dialog_generator;
Runtime_config_generator &_runtime_config_generator;
struct Target_user : Interface
struct Action : Interface
{
virtual void use_storage_target(Storage_target const &) = 0;
virtual void refresh_storage_dialog() = 0;
};
Target_user &_target_user;
Action &_action;
Runtime_config_generator &_runtime;
Attached_rom_dataspace _block_devices_rom { _env, "report -> drivers/block_devices" };
@ -95,7 +94,7 @@ struct Sculpt::Storage : Storage_dialog::Action, Ram_fs_dialog::Action
if (whole_device || partition_matches) {
fn(partition);
_runtime_config_generator.generate_runtime_config();
_runtime.generate_runtime_config();
}
});
});
@ -162,7 +161,7 @@ struct Sculpt::Storage : Storage_dialog::Action, Ram_fs_dialog::Action
if (orig_version.value == _inspect_view_version.value)
return;
_runtime_config_generator.generate_runtime_config();
_runtime.generate_runtime_config();
}
void toggle_default_storage_target(Storage_target const &target) override
@ -173,27 +172,21 @@ struct Sculpt::Storage : Storage_dialog::Action, Ram_fs_dialog::Action
void use(Storage_target const &target) override
{
_target_user.use_storage_target(target);
_action.use_storage_target(target);
}
void reset_ram_fs() override
{
_ram_fs_state.trigger_restart();
_runtime_config_generator.generate_runtime_config();
_runtime.generate_runtime_config();
}
Storage(Env &env, Allocator &alloc,
Registry<Child_state> &child_states,
Deprecated_dialog::Generator &dialog_generator,
Runtime_config_generator &runtime_config_generator,
Target_user &target_user)
Storage(Env &env, Allocator &alloc, Registry<Child_state> &child_states,
Action &action, Runtime_config_generator &runtime)
:
_env(env), _alloc(alloc),
_dialog_generator(dialog_generator),
_runtime_config_generator(runtime_config_generator),
_target_user(target_user),
_env(env), _alloc(alloc), _action(action), _runtime(runtime),
_ram_fs_state(child_states, "ram_fs")
{
_block_devices_rom .sigh(_storage_device_update_handler);

View File

@ -1,5 +1,6 @@
TARGET := sculpt_manager
SRC_CC := $(notdir $(wildcard $(PRG_DIR)/*.cc))
SRC_CC += $(addprefix view/, $(notdir $(wildcard $(PRG_DIR)/view/*.cc)))
SRC_CC += $(addprefix view/, $(notdir $(wildcard $(PRG_DIR)/view/*.cc)))
SRC_CC += $(addprefix dialog/, $(notdir $(wildcard $(PRG_DIR)/dialog/*.cc)))
LIBS += base
INC_DIR += $(PRG_DIR) $(REP_DIR)/src/app/depot_deploy

View File

@ -27,14 +27,6 @@ namespace Sculpt { struct Deprecated_dialog; }
struct Sculpt::Deprecated_dialog : Interface
{
/**
* Interface for triggering the (re-)generation of a menu-view dialog
*
* This interface ls implemented by a top-level dialog and called by a sub
* dialog.
*/
struct Generator : Interface { virtual void generate_dialog() = 0; };
bool hovered = false;
enum class Click_result { CONSUMED, IGNORED };

View File

@ -14,7 +14,363 @@
#ifndef _VIEW__DIALOG_H_
#define _VIEW__DIALOG_H_
#include <dialog/widgets.h>
namespace Sculpt { using namespace Dialog; }
namespace Dialog {
struct Annotation;
struct Left_annotation;
struct Left_right_annotation;
struct Left_floating_text;
struct Left_floating_hbox;
struct Right_floating_hbox;
struct Vgap;
struct Centered_info_vbox;
struct Centered_dialog_vbox;
struct Titled_frame;
struct Pin_button;
struct Pin_row;
struct Doublechecked_action_button;
template <typename> struct Radio_select_button;
}
struct Dialog::Annotation : Sub_scope
{
template <typename SCOPE, typename TEXT>
static void sub_node(SCOPE &s, TEXT const &text)
{
s.sub_node("label", [&] {
s.attribute("text", text);
s.attribute("font", "annotation/regular"); });
}
};
struct Dialog::Left_annotation : Sub_scope
{
template <typename SCOPE, typename TEXT>
static void view_sub_scope(SCOPE &s, TEXT const &text)
{
s.node("hbox", [&] {
s.sub_node("float", [&] () {
s.attribute("west", "yes");
Annotation::sub_node(s, text); }); });
}
template <typename AT, typename FN>
static void with_narrowed_at(AT const &, FN const &) { }
};
struct Dialog::Left_right_annotation : Sub_scope
{
template <typename SCOPE, typename LEFT_TEXT, typename RIGHT_TEXT>
static void view_sub_scope(SCOPE &s, LEFT_TEXT const &left, RIGHT_TEXT const &right)
{
s.node("hbox", [&] {
s.named_sub_node("float", "left", [&] () {
s.attribute("west", "yes");
Annotation::sub_node(s, left); });
s.named_sub_node("float", "right", [&] () {
s.attribute("east", "yes");
Annotation::sub_node(s, right); });
});
}
template <typename AT, typename FN>
static void with_narrowed_at(AT const &, FN const &) { }
};
struct Dialog::Left_floating_text : Sub_scope
{
template <typename SCOPE, typename TEXT>
static void view_sub_scope(SCOPE &s, TEXT const &text)
{
s.node("float", [&] {
s.attribute("west", "yes");
s.named_sub_node("label", "label", [&] {
s.attribute("text", String<30>(" ", text));
s.attribute("min_ex", "15"); }); });
}
template <typename AT, typename FN>
static void with_narrowed_at(AT const &, FN const &) { }
};
struct Dialog::Left_floating_hbox : Sub_scope
{
template <typename SCOPE, typename FN>
static void view_sub_scope(SCOPE &s, FN const &fn)
{
s.node("float", [&] {
s.attribute("west", "yes");
s.named_sub_node("hbox", s.id.value, [&] {
fn(s); }); });
}
template <typename AT, typename FN>
static void with_narrowed_at(AT const &at, FN const &fn)
{
with_narrowed_xml(at, "float", [&] (AT const &at) {
with_narrowed_xml(at, "hbox", fn); });
}
};
struct Dialog::Right_floating_hbox : Sub_scope
{
template <typename SCOPE, typename FN>
static void view_sub_scope(SCOPE &s, FN const &fn)
{
s.node("float", [&] {
s.attribute("east", "yes");
s.named_sub_node("hbox", s.id.value, [&] {
fn(s); }); });
}
template <typename AT, typename FN>
static void with_narrowed_at(AT const &at, FN const &fn)
{
with_narrowed_xml(at, "float", [&] (AT const &at) {
with_narrowed_xml(at, "hbox", fn); });
}
};
struct Dialog::Vgap : Sub_scope
{
template <typename SCOPE>
static void view_sub_scope(SCOPE &s)
{
s.node("label", [&] { s.attribute("text", " "); });
}
template <typename AT, typename FN>
static void with_narrowed_at(AT const &, FN const &) { }
};
struct Dialog::Centered_info_vbox : Sub_scope
{
template <typename SCOPE, typename FN>
static void view_sub_scope(SCOPE &s, FN const &fn)
{
s.node("float", [&] {
s.sub_node("frame", [&] {
s.attribute("style", "unimportant");
s.named_sub_node("vbox", s.id.value, [&] {
fn(s); }); }); });
}
template <typename AT, typename FN>
static void with_narrowed_at(AT const &, FN const &) { }
};
struct Dialog::Centered_dialog_vbox : Sub_scope
{
template <typename SCOPE, typename FN>
static void view_sub_scope(SCOPE &s, FN const &fn)
{
s.node("float", [&] {
s.sub_node("frame", [&] {
s.attribute("style", "important");
s.named_sub_node("vbox", s.id.value, [&] {
fn(s); }); }); });
}
template <typename AT, typename FN>
static void with_narrowed_at(AT const &at, FN const &fn)
{
with_narrowed_xml(at, "float", [&] (AT const &at) {
with_narrowed_xml(at, "frame", [&] (AT const &at) {
with_narrowed_xml(at, "vbox", fn); }); });
}
};
struct Dialog::Titled_frame : Widget<Frame>
{
struct Attr { unsigned min_ex; };
template <typename FN>
static void view(Scope<Frame> &s, Attr const attr, FN const &fn)
{
s.sub_node("vbox", [&] {
if (attr.min_ex)
s.named_sub_node("label", "min_ex", [&] {
s.attribute("min_ex", attr.min_ex); });
s.sub_node("label", [&] { s.attribute("text", s.id.value); });
s.sub_node("float", [&] {
s.sub_node("vbox", [&] () {
fn(); }); }); });
}
template <typename FN>
static void view(Scope<Frame> &s, FN const &fn)
{
view(s, Attr { }, fn);
}
};
template <typename ENUM>
struct Dialog::Radio_select_button : Widget<Left_floating_hbox>
{
ENUM const value;
Radio_select_button(ENUM value) : value(value) { }
template <typename TEXT>
void view(Scope<Left_floating_hbox> &s, ENUM const &selected_value, TEXT const &text) const
{
bool const selected = (selected_value == value),
hovered = (s.hovered() && !s.dragged() && !selected);
s.sub_scope<Float>([&] (Scope<Left_floating_hbox, Float> &s) {
s.sub_scope<Button>([&] (Scope<Left_floating_hbox, Float, Button> &s) {
s.attribute("style", "radio");
if (selected) s.attribute("selected", "yes");
if (hovered) s.attribute("hovered", "yes");
s.sub_scope<Hbox>();
});
});
/* inflate vertical space to button size */
s.sub_scope<Button>([&] (Scope<Left_floating_hbox, Button> &s) {
s.attribute("style", "invisible");
s.sub_scope<Label>(text); });
}
template <typename FN>
void click(Clicked_at const &, FN const &fn) { fn(value); }
};
struct Dialog::Pin_button : Action_button
{
struct Attr { bool visible; };
void view(Scope<Button> &s, Attr attr = { .visible = true }) const
{
if (attr.visible) {
bool const selected = _seq_number == s.hover.seq_number,
hovered = (s.hovered() && (!s.dragged() || selected));
if (selected) s.attribute("selected", "yes");
if (hovered) s.attribute("hovered", "yes");
} else {
s.attribute("style", "invisible");
}
auto const &text = s.id.value;
s.sub_scope<Vbox>([&] (Scope<Button, Vbox> &s) {
s.sub_scope<Min_ex>(10);
s.sub_scope<Vgap>();
s.sub_scope<Dialog::Label>(text, [&] (auto &s) {
if (!attr.visible)
s.attribute("style", "invisible");
s.attribute("font", "title/regular"); });
s.sub_scope<Vgap>();
});
}
};
struct Dialog::Pin_row : Widget<Hbox>
{
Hosted<Hbox, Pin_button> _buttons[3];
template <typename S1, typename S2, typename S3>
Pin_row(S1 const &left, S2 const &middle, S3 const &right)
:
_buttons { Id { left }, Id { middle }, Id { right } }
{ }
struct Visible { bool left, middle, right; };
void view(Scope<Hbox> &s, Visible visible = { true, true, true }) const
{
s.widget(_buttons[0], Pin_button::Attr { visible.left });
s.widget(_buttons[1], Pin_button::Attr { visible.middle });
s.widget(_buttons[2], Pin_button::Attr { visible.right });
}
template <typename FN>
void click(Clicked_at const &at, FN const &fn)
{
for (auto &button : _buttons)
button.propagate(at, [&] { fn(button.id.value); });
}
};
struct Dialog::Doublechecked_action_button
{
bool selected = false;
bool confirmed = false;
Hosted<Vbox, Toggle_button> _operation;
Hosted<Vbox, Deferred_action_button> _confirm_or_cancel;
Doublechecked_action_button(Id::Value const &id_prefix)
:
_operation (Id { Id::Value { id_prefix, " op" } }),
_confirm_or_cancel(Id { Id::Value { id_prefix, " confirm" } })
{ }
void reset() { selected = false, confirmed = false; }
template <typename TEXT>
void view(Scope<Vbox> &s, TEXT const &text) const
{
s.widget(_operation, selected, [&] (Scope<Button> &s) {
s.sub_scope<Dialog::Label>(text); });
if (selected)
s.widget(_confirm_or_cancel, [&] (auto &s) {
s.template sub_scope<Dialog::Label>(confirmed ? " Cancel "
: " Confirm "); });
}
void click(Clicked_at const &at)
{
_operation.propagate(at, [&] {
if (!confirmed)
selected = !selected; });
_confirm_or_cancel.propagate(at);
}
template <typename FN>
void clack(Clacked_at const &at, FN const &activate_fn)
{
_confirm_or_cancel.propagate(at, activate_fn);
}
};
/* local includes */
#include <view/deprecated_dialog.h>
namespace Dialog {
template <typename FN>
static inline void with_dummy_scope(Xml_generator &xml, FN const &fn)
{
static Xml_node const hover("<hover/>");
At const no_hover(Dialog::Event::Seq_number { }, hover);
Scope<> scope(xml, no_hover, Dialog::Event::Dragged { }, Id { });
fn(scope);
}
}
#endif /* _VIEW__DIALOG_H_ */

View File

@ -11,51 +11,28 @@
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__DOWNLOAD_STATUS_H_
#define _VIEW__DOWNLOAD_STATUS_H_
#ifndef _VIEW__DOWNLOAD_STATUS_DIALOG_H_
#define _VIEW__DOWNLOAD_STATUS_DIALOG_H_
/* local includes */
#include <xml.h>
#include <model/download_queue.h>
#include <view/dialog.h>
namespace Sculpt {
static void gen_download_status(Xml_generator &, Xml_node const &, Download_queue const &);
}
namespace Sculpt { struct Download_status_dialog; }
void Sculpt::gen_download_status(Xml_generator &xml, Xml_node const &state,
Download_queue const &download_queue)
struct Sculpt::Download_status_dialog : Titled_frame
{
gen_named_node(xml, "frame", "downloads", [&] () {
xml.node("vbox", [&] () {
xml.node("label", [&] () {
xml.attribute("text", "Download"); });
void view(Scope<Frame> &s, Xml_node const &state, Download_queue const &download_queue) const
{
Titled_frame::view(s, [&] {
using Path = String<40>;
using Info = String<16>;
unsigned count = 0;
auto gen_message = [&] (auto const &path, auto const &info)
{
gen_named_node(xml, "hbox", String<10>(count++), [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("label", [&] () {
xml.attribute("text", path);
xml.attribute("font", "annotation/regular");
});
});
gen_named_node(xml, "float", "right", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", Info(" ", info));
xml.attribute("font", "annotation/regular");
});
});
});
s.sub_scope<Left_right_annotation>(path, Info(" ", info));
};
bool const download_in_progress = state.attribute_value("progress", false);
@ -82,7 +59,7 @@ void Sculpt::gen_download_status(Xml_generator &xml, Xml_node const &state,
gen_message(path, "failed"); });
}
});
});
}
}
};
#endif /* _VIEW__DOWNLOAD_STATUS_H_ */
#endif /* _VIEW__DOWNLOAD_STATUS_DIALOG_H_ */

View File

@ -1,92 +0,0 @@
/*
* \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 <feature.h>
#include <view/dialog.h>
#include <model/storage_target.h>
namespace Sculpt { struct Fs_dialog; }
struct Sculpt::Fs_dialog : Noncopyable, Deprecated_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_inspect_view(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
{
if (Feature::INSPECT_VIEW) {
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_inspect_view(_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_ */

View File

@ -0,0 +1,61 @@
/*
* \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_OPERATIONS_H_
#define _VIEW__FS_OPERATIONS_H_
#include <feature.h>
#include <view/dialog.h>
#include <model/storage_target.h>
namespace Sculpt { struct Fs_operations; }
struct Sculpt::Fs_operations
{
struct Action : Interface
{
virtual void toggle_inspect_view(Storage_target const &) = 0;
virtual void use(Storage_target const &) = 0;
};
Hosted<Vbox, Toggle_button> _inspect { Id { "Inspect" } };
Hosted<Vbox, Toggle_button> _use { Id { "Use" } };
void view(Scope<Vbox> &s,
Storage_target const &target,
Storage_target const &used_target,
File_system const &file_system) const
{
if (Feature::INSPECT_VIEW)
s.widget(_inspect, file_system.inspected);
bool const selected_for_use = (used_target == target);
if (!used_target.valid() || selected_for_use)
s.widget(_use, selected_for_use);
}
void click(Clicked_at const &at,
Storage_target const &target,
Storage_target const &used_target, Action &action)
{
_inspect.propagate(at, [&] {
action.toggle_inspect_view(target); });
_use.propagate(at, [&] {
action.use((used_target == target) ? Storage_target{ } : target); });
}
};
#endif /* _VIEW__FS_OPERATIONS_H_ */

View File

@ -17,32 +17,6 @@
#include <view/dialog.h>
/**
* Arrange content in two columns, each with a minimum width of 'min_ex'
*/
template <typename LEFT_FN, typename RIGHT_FN>
static void gen_left_right(Genode::Xml_generator &xml, unsigned min_ex,
LEFT_FN const &left_fn, RIGHT_FN const &right_fn)
{
using namespace Sculpt;
auto gen_hspacer = [&] {
gen_named_node(xml, "label", "hspacer", [&] {
xml.attribute("min_ex", min_ex); }); };
xml.node("hbox", [&] {
gen_named_node(xml, "vbox", "left", [&] {
gen_hspacer();
left_fn();
});
gen_named_node(xml, "vbox", "right", [&] {
gen_hspacer();
right_fn();
});
});
}
/**
* Inflate vertical spacing using an invisble button
*/

View File

@ -16,84 +16,42 @@
using namespace Sculpt;
void Panel_dialog::generate(Xml_generator &xml) const
void Panel_dialog::view(Scope<> &s) const
{
xml.node("frame", [&] () {
xml.attribute("style", "unimportant");
s.sub_scope<Frame>([&] (Scope<Frame> &s) {
s.attribute("style", "unimportant");
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", true);
xml.node("hbox", [&] () {
if (_state.system_available()) {
xml.node("button", [&] () {
_item.gen_button_attr(xml, "system");
if (_state.system_visible())
xml.attribute("selected", true);
xml.node("label", [&] () {
xml.attribute("text", "System");
});
});
}
if (_state.settings_available()) {
xml.node("button", [&] () {
_item.gen_button_attr(xml, "settings");
if (_state.settings_visible())
xml.attribute("selected", true);
xml.node("label", [&] () {
xml.attribute("text", "Settings");
});
});
}
s.sub_scope<Float>([&] (Scope<Frame, Float> &s) {
s.attribute("west", true);
s.sub_scope<Hbox>([&] (Scope<Frame, Float, Hbox> &s) {
if (_state.system_available())
s.widget(_system_button, _state.system_visible());
if (_state.settings_available())
s.widget(_settings_button, _state.settings_visible());
});
});
gen_named_node(xml, "float", "center", [&] () {
xml.node("hbox", [&] () {
s.sub_scope<Float>([&] (Scope<Frame, Float> &s) {
s.sub_scope<Hbox>([&] (Scope<Frame, Float, Hbox> &s) {
auto gen_tab = [&] (auto name, auto text, Tab tab) {
Tab const tab = _state.selected_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);
s.widget(_files_tab, tab);
s.widget(_components_tab, tab);
if (_state.inspect_tab_visible())
gen_tab("inspect", "Inspect", Tab::INSPECT);
s.widget(_inspect_tab, tab);
});
});
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");
});
});
s.sub_scope<Float>([&] (Scope<Frame, Float> &s) {
s.attribute("east", true);
s.sub_scope<Hbox>([&] (Scope<Frame, Float, Hbox> &s) {
s.widget(_network_button, _state.network_visible());
s.widget(_log_button, _state.log_visible());
});
});
});
}

View File

@ -25,7 +25,7 @@
namespace Sculpt { struct Panel_dialog; }
struct Sculpt::Panel_dialog : Deprecated_dialog
struct Sculpt::Panel_dialog : Top_level_dialog
{
enum class Tab { FILES, COMPONENTS, INSPECT };
@ -52,35 +52,36 @@ struct Sculpt::Panel_dialog : Deprecated_dialog
virtual void toggle_network_visibility() = 0;
};
Hoverable_item _item { };
Activatable_item _action_item { };
Action &_action;
Hover_result hover(Xml_node hover) override
Hosted<Frame, Float, Hbox, Toggle_button>
_system_button { Id { "System" } },
_settings_button { Id { "Settings" } },
_network_button { Id { "Network" } },
_log_button { Id { "Log" } };
using Tab_button = Select_button<Tab>;
Hosted<Frame, Float, Hbox, Tab_button>
_files_tab { Id { "Files" }, Tab::FILES },
_components_tab { Id { "Components" }, Tab::COMPONENTS },
_inspect_tab { Id { "Inspect" }, Tab::INSPECT };
void view(Scope<> &) const override;
void click(Clicked_at const &at) override
{
return any_hover_changed(
_item.match(hover, "frame", "float", "hbox", "button", "name"));
_system_button .propagate(at, [&] { _action.toggle_system_visibility(); });
_settings_button.propagate(at, [&] { _action.toggle_settings_visibility(); });
_network_button .propagate(at, [&] { _action.toggle_network_visibility(); });
_log_button .propagate(at, [&] { _action.toggle_log_visibility(); });
_files_tab .propagate(at, [&] { _action.select_tab(Tab::FILES); });
_components_tab .propagate(at, [&] { _action.select_tab(Tab::COMPONENTS); });
_inspect_tab .propagate(at, [&] { _action.select_tab(Tab::INSPECT); });
}
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("system")) action.toggle_system_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) { }
Panel_dialog(State const &state, Action &action)
: Top_level_dialog("panel"), _state(state), _action(action) { }
};
#endif /* _VIEW__PANEL_DIALOG_H_ */

View File

@ -1,240 +0,0 @@
/*
* \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 <base/log.h>
/* 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", "Relabeling 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", "Check 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 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 (partition.format_in_progress)
xml.node("label", [&] () { xml.attribute("text", "Formatting in progress..."); });
if (partition.gpt_expand_in_progress)
xml.node("label", [&] () { xml.attribute("text", "Expanding partition..."); });
if (partition.fs_resize_in_progress)
xml.node("label", [&] () { xml.attribute("text", "Resizing file system..."); });
if (confirm_visible) {
xml.node("button", [&] () {
_confirm_item.gen_button_attr(xml, "confirm");
xml.attribute("version", version);
xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
});
}
}
Deprecated_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;
}
Deprecated_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;
}
Deprecated_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;
}

View File

@ -1,77 +0,0 @@
/*
* \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 <types.h>
#include <model/storage_devices.h>
#include <model/storage_target.h>
#include <view/selectable_item.h>
#include <view/activatable_item.h>
#include <view/fs_dialog.h>
namespace Sculpt { struct Partition_dialog; }
struct Sculpt::Partition_dialog : Deprecated_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_ */

View File

@ -0,0 +1,161 @@
/*
* \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 <base/log.h>
/* local includes */
#include "partition_operations.h"
using namespace Sculpt;
void Partition_operations::view(Scope<Vbox> &s,
Storage_device const &device,
Partition const &partition,
Storage_target const &used_target) const
{
using Label = Dialog::Label;
String<16> const version(device.label, ".", partition.number);
bool const whole_device = !partition.number.valid();
Storage_target const target { device.label, partition.number };
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();
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_operations.view(s, target, used_target, partition.file_system);
}
if ((device.all_partitions_idle() || partition.relabel_in_progress())
&& partition.genode() && !device_in_use) {
s.widget(_relabel, [&] (Scope<Button> &s) {
s.attribute("version", version);
if (partition.genode_default() || partition.relabel_in_progress())
s.attribute("selected", "yes");
s.sub_scope<Label>("Default");
});
if (partition.relabel_in_progress())
s.sub_scope<Label>("Relabeling in progress...");
}
if (!target_in_use && !partition.format_in_progress && partition.checkable()
&& !relabel_in_progress) {
s.widget(_check, [&] (Scope<Button> &s) {
s.attribute("version", version);
s.sub_scope<Label>("Check");
if (partition.check_in_progress)
s.xml.attribute("selected", "yes");
});
if (partition.check_in_progress)
s.sub_scope<Label>("Check 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
&& !_expand.selected;
bool const expand_button_visible = !target_in_use
&& !whole_device
&& !partition.check_in_progress
&& !partition.format_in_progress
&& !relabel_in_progress
&& partition.expandable()
&& !_format.selected;
if (format_button_visible)
_format.view(s, whole_device ? "Format device ..." : "Format partition ...");
if (expand_button_visible)
_expand.view(s, "Expand ...");
if (partition.format_in_progress)
s.sub_scope<Label>("Formatting in progress...");
if (partition.gpt_expand_in_progress)
s.sub_scope<Label>("Expanding partition...");
if (partition.fs_resize_in_progress)
s.sub_scope<Label>("Resizing file system...");
}
void Partition_operations::click(Clicked_at const &at, Storage_target const &partition,
Storage_target const &used_target, Action &action)
{
_format.click(at);
_expand.click(at);
_fs_operations.click(at, partition, used_target, action);
_check .propagate(at);
_relabel.propagate(at);
}
void Partition_operations::clack(Clacked_at const &at, Storage_target const &partition,
Action &action)
{
_format.clack(at, [&] {
if (_format.confirmed) {
action.cancel_format(partition);
_format.reset();
} else {
action.format(partition);
_format.confirmed = true;
}
});
_expand.clack(at, [&] {
if (_expand.confirmed) {
action.cancel_expand(partition);
_expand.reset();
} else {
action.expand(partition);
_expand.confirmed = true;
}
});
_check.propagate(at, [&] {
action.check(partition); });
_relabel.propagate(at, [&] {
action.toggle_default_storage_target(partition); });
}

View File

@ -0,0 +1,57 @@
/*
* \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_OPERATIONS_H_
#define _VIEW__PARTITION_OPERATIONS_H_
#include <types.h>
#include <model/storage_devices.h>
#include <view/fs_operations.h>
namespace Sculpt { struct Partition_operations; }
struct Sculpt::Partition_operations
{
Hosted<Vbox, Deferred_action_button>
_relabel { Id { "default" } },
_check { Id { "check" } };
Doublechecked_action_button _format { "format" }, _expand { "expand" };
Fs_operations _fs_operations { };
void view(Scope<Vbox> &s, Storage_device const &, Partition const &,
Storage_target const &used_target) const;
struct Action : Fs_operations::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_operation()
{
_format.reset();
_expand.reset();
}
void click(Clicked_at const &, Storage_target const &partition, Storage_target const &, Action &);
void clack(Clacked_at const &, Storage_target const &partition, Action &);
};
#endif /* _VIEW__PARTITION_OPERATIONS_H_ */

View File

@ -14,107 +14,49 @@
#ifndef _VIEW__RAM_FS_DIALOG_H_
#define _VIEW__RAM_FS_DIALOG_H_
#include <view/fs_dialog.h>
#include <view/selectable_item.h>
#include <view/fs_operations.h>
#include <model/ram_fs_state.h>
namespace Sculpt { struct Ram_fs_dialog; }
struct Sculpt::Ram_fs_dialog : Noncopyable, Deprecated_dialog
struct Sculpt::Ram_fs_dialog : Widget<Vbox>
{
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 { }
Fs_operations _fs { };
Doublechecked_action_button _reset { "reset" };
void generate(Xml_generator &xml, Ram_fs_state const &ram_fs_state) const
void view(Scope<Vbox> &s,
Storage_target const &used_target,
Ram_fs_state const &ram_fs_state) const
{
_fs_dialog.generate(xml, ram_fs_state);
_fs.view(s, _target, used_target, 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"); });
});
}
}
if (!used_target.ram_fs() && !ram_fs_state.inspected)
_reset.view(s, "Reset ...");
}
Click_result click(Fs_dialog::Action &fs_action)
void click(Clicked_at const &at,
Storage_target const &used_target,
Fs_operations::Action &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;
_reset.click(at);
_fs.click(at, _target, used_target, action);
}
Clack_result clack(Action &action)
void clack(Clacked_at const &at, 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;
_reset.clack(at, [&] {
action.reset_ram_fs();
_reset.selected = false;
});
}
Ram_fs_dialog(Storage_target const &used_target)
:
_used_target(used_target), _fs_dialog(_target, used_target)
{ }
};
#endif /* _VIEW__RAM_FS_DIALOG_H_ */

View File

@ -21,7 +21,7 @@
namespace Sculpt { struct Software_presets_dialog; }
struct Sculpt::Software_presets_dialog
struct Sculpt::Software_presets_dialog : Widget<Float>
{
Presets const &_presets;

View File

@ -23,7 +23,7 @@
namespace Sculpt { struct Software_update_dialog; }
struct Sculpt::Software_update_dialog
struct Sculpt::Software_update_dialog : Widget<Vbox>
{
using Depot_users = Depot_users_dialog::Depot_users;
using User = Depot_users_dialog::User;

View File

@ -20,7 +20,7 @@
namespace Sculpt { struct Software_version_dialog; }
struct Sculpt::Software_version_dialog
struct Sculpt::Software_version_dialog : Widget<Frame>
{
Build_info const _build_info;

View File

@ -20,103 +20,53 @@
using namespace Sculpt;
void Storage_device_dialog::_gen_partition(Xml_generator &xml,
Storage_device const &device,
Partition const &partition) const
namespace Dialog { struct Partition_button; }
struct Dialog::Partition_button : Widget<Hbox>
{
bool const selected = _partition_item.selected(partition.number);
void view(Scope<Hbox> &s, bool selected, Storage_target const &used_target,
Storage_device const &device, Partition const &partition) const
{
using Label = Dialog::Label;
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", [&] () {
bool const hovered = s.hovered();
if (_partition_item.hovered(partition.number))
xml.attribute("hovered", "yes");
s.sub_scope<Left_floating_hbox>([&] (Scope<Hbox, Left_floating_hbox> &s) {
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", "* "); });
s.sub_scope<Button>([&] (Scope<Hbox, Left_floating_hbox, Button> &s) {
if (hovered) s.attribute("hovered", "yes");
if (selected) s.attribute("selected", "yes");
s.sub_scope<Label>(partition.number);
});
if (partition.label.length() > 1)
s.sub_scope<Label>(String<80>(" (", partition.label, ") "));
Storage_target const target { device.label, partition.number };
if (used_target == target)
s.sub_scope<Label>("* ");
});
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);
});
});
}
Deprecated_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"));
}
Deprecated_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;
s.sub_scope<Right_floating_hbox>([&] (Scope<Hbox, Right_floating_hbox> &s) {
s.sub_scope<Label>(String<64>(partition.capacity, " ")); });
}
if (_partition_dialog.constructed())
return _partition_dialog->click(action);
return Click_result::IGNORED;
}
};
Deprecated_dialog::Clack_result Storage_device_dialog::clack(Action &action)
void Storage_device_dialog::view(Scope<Vbox> &s, Storage_device const &dev,
Storage_target const &used_target) const
{
if (_partition_dialog.constructed())
return _partition_dialog->clack(action);
dev.partitions.for_each([&] (Partition const &partition) {
return Clack_result::IGNORED;
bool const selected = (partition.number == _selected_partition);
Hosted<Vbox, Partition_button> button { Id { partition.number } };
s.widget(button, selected, used_target, dev, partition);
if (selected)
_partition_operations.view(s, dev, partition, used_target);
});
if (!_selected_partition.valid())
_partition_operations.view(s, dev, *dev.whole_device_partition, used_target);
}

View File

@ -15,64 +15,52 @@
#define _VIEW__STORAGE_DEVICE_DIALOG_H_
#include <types.h>
#include <model/storage_devices.h>
#include <model/storage_target.h>
#include <view/selectable_item.h>
#include <view/activatable_item.h>
#include <view/partition_dialog.h>
#include <view/partition_operations.h>
namespace Sculpt { struct Storage_device_dialog; }
struct Sculpt::Storage_device_dialog : Deprecated_dialog
struct Sculpt::Storage_device_dialog : Widget<Vbox>
{
Storage_device::Label const _device;
Storage_devices const &_storage_devices;
Storage_target const &_used_target;
Partition::Number _selected_partition { };
Selectable_item _partition_item { };
Partition_operations _partition_operations { };
Reconstructible<Partition_dialog> _partition_dialog {
_selected_storage_target(), _storage_devices, _used_target };
void view(Scope<Vbox> &, Storage_device const &, Storage_target const &) const;
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 { }
using Action = Partition_operations::Action;
void reset_operation()
{
if (_partition_dialog.constructed())
_partition_dialog->reset_operation();
_partition_operations.reset_operation();
}
Click_result click(Action &action);
Clack_result clack(Action &action);
void click(Clicked_at const &at, Storage_target const &used_target, Action &action)
{
Id const device_id = at.matching_id<Vbox>();
Id const partition_id = at.matching_id<Vbox, Hbox>();
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)
{ }
Storage_target const selected_target { device_id.value, _selected_partition };
if (partition_id.valid()) {
_selected_partition = (partition_id.value == _selected_partition)
? Partition::Number { }
: Partition::Number { partition_id.value };
_partition_operations.reset_operation();
}
_partition_operations.click(at, selected_target, used_target, action);
}
void clack(Clacked_at const &at, Action &action)
{
Id const device_id = at.matching_id<Vbox>();
Storage_target const selected_target { device_id.value, _selected_partition };
_partition_operations.clack(at, selected_target, action);
}
};
#endif /* _VIEW__STORAGE_DEVICE_DIALOG_H_ */

View File

@ -1,172 +0,0 @@
/*
* \brief Storage 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 <base/log.h>
/* local includes */
#include "storage_dialog.h"
using namespace Sculpt;
void Storage_dialog::_gen_block_device(Xml_generator &xml,
Block_device const &dev) const
{
bool const selected = _device_item.selected(dev.label);
xml.node("button", [&] () {
xml.attribute("name", dev.label);
if (_device_item.hovered(dev.label))
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", dev.label); });
gen_named_node(xml, "label", "model", [&] () {
xml.attribute("text", String<80>(" (", dev.model, ") ")); });
if (_used_target.device == dev.label)
gen_named_node(xml, "label", "used", [&] () {
xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(dev.capacity)); }); });
});
});
if (_storage_device_dialog.constructed() && selected)
_storage_device_dialog->generate(xml, dev);
}
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);
xml.node("button", [&] () {
xml.attribute("name", dev.label);
if (_device_item.hovered(dev.label) && !discarded)
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", dev.label); });
if (dev.driver_info.constructed()) {
gen_named_node(xml, "label", "vendor", [&] () {
String<16> const vendor { dev.driver_info->vendor };
xml.attribute("text", String<64>(" (", vendor, ") ")); });
}
if (_used_target.device == dev.label)
gen_named_node(xml, "label", "used", [&] () {
xml.attribute("text", " *"); });
});
});
typedef String<64> Info;
Info const info = dev.discarded() ? Info(" unsupported")
: Info(" ", dev.capacity);
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", info); }); });
});
});
if (_storage_device_dialog.constructed() && selected)
_storage_device_dialog->generate(xml, dev);
}
void Storage_dialog::gen_block_devices(Xml_generator &xml) const
{
_storage_devices.block_devices.for_each([&] (Block_device const &dev) {
_gen_block_device(xml, dev); });
}
void Storage_dialog::gen_usb_storage_devices(Xml_generator &xml) const
{
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
_gen_usb_storage_device(xml, dev); });
}
Deprecated_dialog::Hover_result Storage_dialog::hover(Xml_node hover)
{
Hover_result result = Hover_result::UNMODIFIED;
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"));
}
Deprecated_dialog::Click_result Storage_dialog::click(Action &action)
{
Selectable_item::Id const old_selected_device = _device_item._selected;
_device_item.toggle_selection_on_click();
if (old_selected_device != _device_item._selected) {
_storage_device_dialog.destruct();
_storage_device_dialog.conditional(_device_item.any_selected(),
_device_item._selected,
_storage_devices, _used_target);
return Click_result::CONSUMED;
}
if (_storage_device_dialog.constructed()
&& _storage_device_dialog->click(action) == Click_result::CONSUMED) {
return Click_result::CONSUMED;
}
return Click_result::IGNORED;
}
Deprecated_dialog::Clack_result Storage_dialog::clack(Action &action)
{
if (_storage_device_dialog.constructed()
&& _storage_device_dialog->clack(action) == Clack_result::CONSUMED)
return Clack_result::CONSUMED;
return Clack_result::IGNORED;
}

View File

@ -16,36 +16,64 @@
#include <types.h>
#include <model/storage_devices.h>
#include <model/storage_target.h>
#include <view/selectable_item.h>
#include <view/storage_device_dialog.h>
namespace Sculpt { struct Storage_dialog; }
namespace Sculpt { struct Storage_devices_dialog_base; }
struct Sculpt::Storage_dialog : Deprecated_dialog
struct Sculpt::Storage_devices_dialog_base : Widget<Vbox>
{
Storage_devices const &_storage_devices;
Storage_target const &_used_target;
Selectable_item _device_item { };
Constructible<Hosted<Vbox, Frame, Storage_device_dialog>> _storage_device_dialog { };
Storage_target const &_used_target;
Block_device::Label _selected_device { };
Constructible<Storage_device_dialog> _storage_device_dialog { };
Storage_devices_dialog_base(Storage_devices const &storage_devices,
Storage_target const &used_target)
:
_storage_devices(storage_devices), _used_target(used_target)
{ }
void _gen_block_device (Xml_generator &, Block_device const &) const;
void _gen_usb_storage_device(Xml_generator &, Usb_storage_device const &) const;
template <typename DEVICE, typename BUTTON>
void _view_device(Scope<Vbox> &s, DEVICE const &dev, BUTTON const &button) const
{
bool const selected = ( _selected_device == dev.label );
void generate(Xml_generator &) const override { };
s.widget(button, dev, selected, _used_target);
void gen_block_devices (Xml_generator &) const;
void gen_usb_storage_devices(Xml_generator &) const;
if (_storage_device_dialog.constructed() && selected) {
s.sub_scope<Frame>([&] (Scope<Vbox, Frame> &s) {
s.attribute("style", "invisible");
s.widget(*_storage_device_dialog, dev, _used_target);
});
}
}
Hover_result hover(Xml_node hover) override;
template <typename BUTTON>
void _click_device(Clicked_at const &at, Storage_device_dialog::Action &action)
{
/* select device */
Id const id = at.matching_id<Vbox, BUTTON>();
if (id.valid()) {
if (id.value == _selected_device) {
_selected_device = { };
_storage_device_dialog.destruct();
} else {
_selected_device = id.value;
_storage_device_dialog.construct(Id { id });
}
}
using Action = Storage_device_dialog::Action;
if (_selected_device.valid() && _storage_device_dialog.constructed())
_storage_device_dialog->propagate(at, _used_target, action);
}
void reset() override { }
void _clack_device(Clacked_at const &at, Storage_device_dialog::Action &action)
{
if (_selected_device.valid() && _storage_device_dialog.constructed())
_storage_device_dialog->propagate(at, action);
}
void reset_operation()
{
@ -53,15 +81,132 @@ struct Sculpt::Storage_dialog : Deprecated_dialog
_storage_device_dialog->reset_operation();
}
Click_result click(Action &);
Clack_result clack(Action &);
void reset()
{
_storage_device_dialog.destruct();
_selected_device = { };
}
};
Storage_dialog(Storage_devices const &storage_devices,
Storage_target const &used)
:
_storage_devices(storage_devices),
_used_target(used)
{ }
namespace Sculpt { struct Block_device_button; }
struct Sculpt::Block_device_button : Widget<Button>
{
void view(Scope<Button> &s, Block_device const &dev, bool const selected,
Storage_target const &used_target) const
{
if (s.hovered()) s.attribute("hovered", "yes");
if (selected) s.attribute("selected", "yes");
using Label = Dialog::Label;
s.sub_scope<Hbox>([&] (Scope<Button, Hbox> &s) {
s.sub_scope<Left_floating_hbox>(
[&] (Scope<Button, Hbox, Left_floating_hbox> &s) {
s.sub_scope<Label>(dev.label);
s.sub_scope<Label>(String<80>(" (", dev.model, ") "));
if (used_target.device == dev.label)
s.sub_scope<Label>("* ");
});
s.sub_scope<Right_floating_hbox>(
[&] (Scope<Button, Hbox, Right_floating_hbox> &s) {
s.sub_scope<Label>(String<64>(dev.capacity)); });
});
}
};
namespace Sculpt { struct Block_devices_dialog; }
struct Sculpt::Block_devices_dialog : Storage_devices_dialog_base
{
using Storage_devices_dialog_base::Storage_devices_dialog_base;
void view(Scope<Vbox> &s) const
{
s.sub_scope<Min_ex>(35);
_storage_devices.block_devices.for_each([&] (Block_device const &dev) {
Hosted<Vbox, Block_device_button> button { Id { dev.label } };
_view_device(s, dev, button);
});
}
void click(Clicked_at const &at, Storage_device_dialog::Action &action)
{
_click_device<Block_device_button>(at, action);
}
void clack(Clacked_at const &at, Storage_device_dialog::Action &action)
{
_clack_device(at, action);
}
};
namespace Sculpt { struct Usb_storage_device_button; }
struct Sculpt::Usb_storage_device_button : Widget<Button>
{
void view(Scope<Button> &s, Usb_storage_device const &dev, bool const selected,
Storage_target const &used_target) const
{
bool const discarded = dev.discarded();
if (s.hovered() && !discarded) s.attribute("hovered", "yes");
if (selected) s.attribute("selected", "yes");
using Label = Dialog::Label;
s.sub_scope<Hbox>([&] (Scope<Button, Hbox> &s) {
s.sub_scope<Left_floating_hbox>(
[&] (Scope<Button, Hbox, Left_floating_hbox> &s) {
s.sub_scope<Label>(dev.label);
if (dev.driver_info.constructed()) {
String<16> const vendor { dev.driver_info->vendor };
s.sub_scope<Label>(String<64>(" (", vendor, ") "));
}
if (used_target.device == dev.label)
s.sub_scope<Label>("* ");
});
using Info = String<64>;
Info const info = dev.discarded() ? Info(" unsupported")
: Info(" ", dev.capacity);
s.sub_scope<Right_floating_hbox>(
[&] (Scope<Button, Hbox, Right_floating_hbox> &s) {
s.sub_scope<Label>(info); });
});
}
};
namespace Sculpt { struct Usb_devices_dialog; }
struct Sculpt::Usb_devices_dialog : Storage_devices_dialog_base
{
using Storage_devices_dialog_base::Storage_devices_dialog_base;
void view(Scope<Vbox> &s) const
{
s.sub_scope<Min_ex>(35);
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
Hosted<Vbox, Usb_storage_device_button> button { Id { dev.label } };
_view_device(s, dev, button);
});
}
void click(Clicked_at const &at, Storage_device_dialog::Action &action)
{
_click_device<Usb_storage_device_button>(at, action);
}
void clack(Clacked_at const &at, Storage_device_dialog::Action &action)
{
_clack_device(at, action);
}
};
#endif /* _VIEW__STORAGE_DIALOG_H_ */