sculpt: leitzentrale user-interface redesign

Issue #3650
This commit is contained in:
Norman Feske 2020-01-26 21:14:40 +01:00 committed by Christian Helmuth
parent 103dcdeea8
commit 1d3ce93107
49 changed files with 3312 additions and 1343 deletions

View File

@ -2,6 +2,7 @@ _/pkg/drivers_managed-pc
_/pkg/wifi
_/pkg/depot_download
_/pkg/terminal
_/pkg/backdrop
_/src/report_rom
_/src/clipboard
_/src/init
@ -48,3 +49,5 @@ _/src/gpt_write
_/src/sculpt_manager
_/src/fs_query
_/src/fs_tool
_/src/text_area
_/src/sandbox

View File

@ -3,6 +3,7 @@ create_boot_directory
import_from_depot [depot_user]/src/[base_src] \
[depot_user]/pkg/[drivers_interactive_pkg] \
[depot_user]/pkg/fonts_fs \
[depot_user]/pkg/backdrop \
[depot_user]/src/dynamic_rom \
[depot_user]/src/report_rom \
[depot_user]/src/fs_rom \
@ -19,6 +20,7 @@ import_from_depot [depot_user]/src/[base_src] \
[depot_user]/src/libpng \
[depot_user]/src/zlib \
[depot_user]/src/menu_view \
[depot_user]/src/fs_query \
[depot_user]/src/rom_filter \
[depot_user]/src/noux \
[depot_user]/src/terminal \
@ -33,6 +35,8 @@ import_from_depot [depot_user]/src/[base_src] \
[depot_user]/src/coreutils-minimal \
[depot_user]/src/e2fsprogs-minimal \
[depot_user]/src/gpt_write \
[depot_user]/src/text_area \
[depot_user]/src/sandbox \
[depot_user]/src/window_layouter
install_config {
@ -82,10 +86,7 @@ install_config {
report="nitpicker -> hover"/>
<policy label="leitzentrale -> manager -> displays"
report="nitpicker -> displays"/>
<policy label="leitzentrale -> manager -> runtime_view_hover"
report="runtime -> runtime_view -> hover"/>
<policy label="runtime -> runtime_view -> dialog"
report="leitzentrale -> manager -> runtime_view_dialog"/>
<policy label="clipboard" report="clipboard"/>
</config>
</start>
@ -148,8 +149,9 @@ install_config {
<resource name="RAM" quantum="4M"/>
<provides> <service name="File_system"/> </provides>
<config>
<default-policy root="/" writeable="yes"/>
<content> <inline name="log">See the core log for messages.</inline> </content>
<policy label="ro" root="/"/>
<default-policy root="/" writeable="yes"/>
</config>
</start>
@ -191,12 +193,13 @@ install_config {
<provides> <service name="ROM"/> </provides>
<config>
<rom name="usb_active_config">
<sleep milliseconds="500000" />
<inline description="USB storage present">
<config>
<raw> <policy label_suffix="usb-1-2" class="storage"/> </raw>
</config>
</inline>
<sleep milliseconds="5000" />
<sleep milliseconds="500000" />
<inline description="USB storage absent">
<config/>
</inline>
@ -219,10 +222,15 @@ install_config {
<provides> <service name="Block"/> </provides>
</start>
<start name="leitzentrale" caps="4000">
<start name="leitzentrale" caps="2300">
<binary name="init"/>
<resource name="RAM" quantum="140M"/>
<provides> <service name="Nitpicker"/> </provides>
<resource name="RAM" quantum="122M"/>
<provides>
<service name="Nitpicker"/>
<service name="File_system"/>
<service name="Report"/>
<service name="ROM"/>
</provides>
<route>
<service name="ROM" label="config">
<child name="leitzentrale_config"/> </service>
@ -233,9 +241,7 @@ install_config {
<service name="File_system" label="config">
<child name="config_fs" label="rw"/> </service>
<service name="File_system" label="report">
<child name="report_fs" label="rw"/> </service>
<service name="Report" label="manager -> runtime_view_dialog">
<child name="report_rom"/> </service>
<child name="report_fs" label="ro"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<service name="ROM" label_last="drivers/block_devices">
<parent label="block_devices"/> </service>
@ -253,8 +259,6 @@ install_config {
<child name="report_rom"/> </service>
<service name="ROM" label="manager -> displays">
<child name="report_rom"/> </service>
<service name="ROM" label="manager -> runtime_view_hover">
<child name="report_rom"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
@ -267,14 +271,20 @@ install_config {
<child name="config_rom" label="managed/runtime"/> </service>
<service name="ROM" label_prefix="config -> ">
<child name="config_rom"/> </service>
<service name="ROM" label="runtime_view -> dialog">
<child name="report_rom"/> </service>
<service name="Report" label="runtime_view -> hover">
<child name="report_rom"/> </service>
<service name="ROM" label_prefix="leitzentrale ->">
<child name="leitzentrale"/> </service>
<service name="ROM" label="inspect terminal -> clipboard">
<child name="report_rom" label="clipboard"/> </service>
<service name="ROM" label="editor -> clipboard">
<child name="report_rom" label="clipboard"/> </service>
<service name="Report" label="editor -> clipboard">
<child name="report_rom" label="clipboard"/> </service>
<service name="File_system" label="config">
<child name="config_fs" label="rw"/> </service>
<service name="File_system" label="report">
<child name="report_fs" label="ro"/> </service>
<service name="File_system" label="leitzentrale -> fonts">
<child name="leitzentrale" label="fonts"/> </service>
<service name="Block" label_last="ahci-1"> <child name="ahci-1"/> </service>
<service name="Block" label_last="ahci-2"> <child name="ahci-2"/> </service>
<service name="Block"> <child name="drivers"/> </service>
@ -282,6 +292,8 @@ install_config {
<child name="leitzentrale"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<service name="Report" label_prefix="leitzentrale ->">
<child name="leitzentrale"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<any-service> <parent/> </any-service>

View File

@ -75,10 +75,6 @@ install_config {
report="global_keys_handler -> slides"/>
<policy label="leitzentrale -> manager -> displays"
report="nitpicker -> displays"/>
<policy label="runtime -> runtime_view -> dialog"
report="leitzentrale -> manager -> runtime_view_dialog"/>
<policy label="leitzentrale -> manager -> runtime_view_hover"
report="runtime -> runtime_view -> hover"/>
</config>
</start>
@ -397,11 +393,16 @@ install_config {
</route>
</start>
<start name="leitzentrale" caps="4000" priority="-2">
<start name="leitzentrale" caps="2350" priority="-2">
<binary name="init"/>
<resource name="RAM" quantum="164M"/>
<resource name="RAM" quantum="130M"/>
<affinity xpos="1" width="1"/> <!-- decouple leitzentrale from boot CPU -->
<provides> <service name="Nitpicker"/> </provides>
<provides>
<service name="Nitpicker"/>
<service name="File_system"/> <!-- fonts -->
<service name="ROM"/> <!-- view dialog ROMs -->
<service name="Report"/> <!-- view hover reports -->
</provides>
<route>
<service name="LOG"> <child name="log"/> </service>
<service name="ROM" label="config">
@ -418,10 +419,6 @@ install_config {
<child name="config_fs_rom"/> </service>
<service name="ROM" label="manager -> nitpicker_hover">
<child name="report_rom"/> </service>
<service name="ROM" label="manager -> runtime_view_hover">
<child name="report_rom"/> </service>
<service name="Report" label="manager -> runtime_view_dialog">
<child name="report_rom"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<service name="Timer"> <child name="timer"/> </service>
@ -452,8 +449,6 @@ install_config {
<child name="report_rom"/> </service>
<service name="ROM" label="clicked">
<child name="report_rom"/> </service>
<service name="ROM" label="runtime_view -> dialog">
<child name="report_rom"/> </service>
<service name="File_system" label="config">
<child name="config_fs" label="rw"/> </service>
<service name="File_system" label="report">
@ -474,12 +469,20 @@ install_config {
<service name="Report" label_suffix="-> shape"> <child name="pointer"/> </service>
<service name="Report" label="inspect terminal -> clipboard">
<child name="clipboard" label="leitzentrale -> manager -> fader -> -> clipboard"/> </service>
<service name="Report" label="editor -> clipboard">
<child name="clipboard" label="leitzentrale -> manager -> fader -> -> clipboard"/> </service>
<service name="ROM" label="inspect terminal -> clipboard">
<child name="clipboard" label="leitzentrale -> manager -> fader -> -> clipboard"/> </service>
<service name="ROM" label="editor -> clipboard">
<child name="clipboard" label="leitzentrale -> manager -> fader -> -> clipboard"/> </service>
<service name="Report" label_suffix="-> clipboard"> <child name="clipboard"/> </service>
<service name="ROM" label_suffix="-> clipboard"> <child name="clipboard"/> </service>
<service name="Report" label="runtime_view -> hover">
<child name="report_rom"/> </service>
<service name="Report" label_prefix="leitzentrale ->">
<child name="leitzentrale"/> </service>
<service name="ROM" label_prefix="leitzentrale ->">
<child name="leitzentrale"/> </service>
<service name="File_system" label="leitzentrale -> fonts">
<child name="leitzentrale" label="fonts"/> </service>
<service name="Report"> <child name="fs_report"/> </service>
<service name="LOG" label="unlogged"> <parent/> </service>
<service name="LOG"> <child name="log"/> </service>

View File

@ -23,6 +23,14 @@
<service name="Nitpicker">
<default-policy> <child name="wm"/> </default-policy> </service>
<service name="File_system">
<default-policy> <child name="fonts_fs"/> </default-policy> </service>
<service name="ROM">
<default-policy> <child name="report_rom"/> </default-policy> </service>
<service name="Report">
<default-policy> <child name="report_rom"/> </default-policy> </service>
</inline>
<if>
<has_value input="leitzentrale_enabled" value="yes" />
@ -32,7 +40,7 @@
<binary name="nit_fader"/>
<resource name="RAM" quantum="50M"/>
<provides> <service name="Nitpicker"/> </provides>
<config alpha="210"/>
<config initial_fade_in_steps="100" fade_in_steps="20" alpha="210"/>
<route>
<service name="Nitpicker"> <child name="manager"/> </service>
<any-service> <parent/> </any-service>
@ -46,7 +54,7 @@
<binary name="nit_fader"/>
<resource name="RAM" quantum="50M"/>
<provides> <service name="Nitpicker"/> </provides>
<config alpha="0"/>
<config fade_out_steps="30" alpha="0"/>
<route>
<service name="Nitpicker"> <child name="manager"/> </service>
<any-service> <parent/> </any-service>
@ -83,7 +91,7 @@
</route>
</start>
<start name="report_rom">
<start name="report_rom" caps="200">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Report"/>
@ -94,19 +102,42 @@
<policy label="wm -> resize_request" report="manager -> window_layout"/>
<policy label="wm -> focus" report="manager -> wm_focus"/>
<policy label="decorator -> pointer" report="wm -> pointer"/>
<policy label="gui -> config" report="manager -> gui_config"/>
<policy label="gui -> menu -> dialog" report="manager -> menu_dialog"/>
<policy label="gui -> popup -> dialog" report="manager -> popup_dialog"/>
<policy label="manager -> menu_view_hover" report="gui -> menu -> hover"/>
<policy label="manager -> popup_view_hover" report="gui -> popup -> hover"/>
<policy label="manager -> window_list" report="wm -> window_list"/>
<policy label="manager -> decorator_margins" report="decorator -> decorator_margins"/>
<policy label="nitpicker -> focus" report="manager -> focus"/>
<policy label="runtime -> leitzentrale -> menu_view -> dialog"
report="manager -> menu_dialog"/>
<policy label="runtime -> leitzentrale -> network_view -> dialog"
report="manager -> network_dialog"/>
<policy label="runtime -> leitzentrale -> settings_view -> dialog"
report="manager -> settings_dialog"/>
<policy label="runtime -> leitzentrale -> file_browser_view -> dialog"
report="manager -> file_browser_dialog"/>
<policy label="runtime -> leitzentrale -> popup_view -> dialog"
report="manager -> popup_dialog"/>
<policy label="runtime -> leitzentrale -> panel_view -> dialog"
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 -> network_view_hover"
report="runtime -> leitzentrale -> network_view -> hover"/>
<policy label="manager -> settings_view_hover"
report="runtime -> leitzentrale -> settings_view -> hover"/>
<policy label="manager -> file_browser_view_hover"
report="runtime -> leitzentrale -> file_browser_view -> hover"/>
<policy label="manager -> runtime_view_hover"
report="runtime -> leitzentrale -> runtime_view -> hover"/>
<policy label="manager -> panel_view_hover"
report="runtime -> leitzentrale -> panel_view -> hover"/>
<policy label="manager -> popup_view_hover"
report="runtime -> leitzentrale -> popup_view -> hover"/>
</config>
</start>
<start name="wm" caps="200">
<resource name="RAM" quantum="2M"/>
<start name="wm" caps="300">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Nitpicker"/> <service name="Report"/> <service name="ROM"/>
</provides>
@ -123,9 +154,9 @@
</route>
</start>
<start name="decorator" caps="300">
<start name="decorator" caps="350">
<binary name="themed_decorator"/>
<resource name="RAM" quantum="8M"/>
<resource name="RAM" quantum="10M"/>
<config>
<libc/>
<vfs>
@ -140,10 +171,14 @@
</dir>
<dir name="dev"> <log/> </dir>
</vfs>
<policy label="log" decoration="yes"/>
<policy label="runtime -> leitzentrale -> runtime_view" decoration="no" motion="30"/>
<policy label_prefix="gui -> popup" decoration="no" motion="20"/>
<policy label_prefix="gui" decoration="no"/>
<policy label="log" decoration="yes" motion="20"/>
<policy label="runtime -> leitzentrale -> settings_view" decoration="no" motion="20"/>
<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 -> popup_view" decoration="no" motion="20"/>
<policy label_prefix="logo" decoration="no"/>
<default-policy/>
</config>
<route>
@ -192,13 +227,10 @@
<child name="config_fs_report" label="managed -> installation"/> </service>
<service name="Report" label="depot_query">
<child name="config_fs_report" label="managed -> depot_query"/> </service>
<service name="Report" label="runtime_view_dialog"> <parent/> </service>
<service name="Report"> <child name="report_rom"/> </service>
<service name="ROM" label="nitpicker_hover"> <parent/> </service>
<service name="ROM" label_prefix="report ->"> <parent/> </service>
<service name="ROM" label="menu_view_hover"> <child name="report_rom"/> </service>
<service name="ROM" label="popup_view_hover"> <child name="report_rom"/> </service>
<service name="ROM" label="runtime_view_hover"> <parent/> </service>
<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="Nitpicker"> <parent/> </service>
@ -217,19 +249,6 @@
</route>
</start>
<start name="gui" caps="1400">
<binary name="init"/>
<resource name="RAM" quantum="28M"/>
<route>
<service name="ROM" label="config"> <child name="report_rom"/> </service>
<service name="ROM" label_last="dialog"> <child name="report_rom"/> </service>
<service name="Nitpicker"> <child name="wm"/> </service>
<service name="File_system" label="fonts"> <child name="fonts_fs"/> </service>
<service name="Report" label_last="hover"> <child name="report_rom"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
<start name="log_nit_fb">
<binary name="nit_fb"/>
<resource name="RAM" quantum="4M"/>
@ -285,6 +304,21 @@
</route>
</start>
<start name="backdrop" caps="150">
<resource name="RAM" quantum="4M" />
<config width="300" height="150">
<libc/>
<vfs> <rom name="genode_logo.png"/> </vfs>
<fill color="#272f45"/>
<image png="genode_logo.png" anchor="bottom_right" alpha="100"
xpos="-20" ypos="-20" />
</config>
<route>
<service name="Nitpicker"> <child name="wm" label="logo"/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</inline>
</output>
</config>

View File

@ -1,6 +1,6 @@
<config focus="rom">
<report hover="yes" focus="yes" clicked="yes" keystate="no" displays="yes"/>
<background color="#131415"/>
<background color="#000000"/>
<domain name="pointer" layer="1" content="client" label="no" origin="pointer" />
<domain name="lock" layer="2" content="client" label="no" hover="always" focus="click"/>
<domain name="leitzentrale" layer="3" content="client" label="no" hover="always" focus="click" />

View File

@ -39,6 +39,8 @@ struct Sculpt::Deploy
Allocator &_alloc;
Registry<Child_state> &_child_states;
Runtime_info const &_runtime_info;
Dialog::Generator &_dialog_generator;
@ -56,10 +58,10 @@ struct Sculpt::Deploy
Arch _arch { };
Child_state cached_depot_rom_state {
"depot_rom", Ram_quota{24*1024*1024}, Cap_quota{200} };
_child_states, "depot_rom", Ram_quota{24*1024*1024}, Cap_quota{200} };
Child_state uncached_depot_rom_state {
"dynamic_depot_rom", Ram_quota{8*1024*1024}, Cap_quota{200} };
_child_states, "dynamic_depot_rom", Ram_quota{8*1024*1024}, Cap_quota{200} };
/*
* Report written to '/config/managed/deploy'
@ -227,7 +229,8 @@ struct Sculpt::Deploy
});
}
Deploy(Env &env, Allocator &alloc, Runtime_info const &runtime_info,
Deploy(Env &env, Allocator &alloc, Registry<Child_state> &child_states,
Runtime_info const &runtime_info,
Dialog::Generator &dialog_generator,
Runtime_config_generator &runtime_config_generator,
Depot_query &depot_query,
@ -235,7 +238,8 @@ struct Sculpt::Deploy
Attached_rom_dataspace const &blueprint_rom,
Download_queue const &download_queue)
:
_env(env), _alloc(alloc), _runtime_info(runtime_info),
_env(env), _alloc(alloc), _child_states(child_states),
_runtime_info(runtime_info),
_dialog_generator(dialog_generator),
_runtime_config_generator(runtime_config_generator),
_depot_query(depot_query),

View File

@ -0,0 +1,374 @@
/*
* \brief Graph view of runtime state
* \author Norman Feske
* \date 2018-07-05
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <graph.h>
#include <view/dialog.h>
using namespace Sculpt;
void Graph::_gen_selected_node_content(Xml_generator &xml, Start_name const &name,
Runtime_state::Info const &info) const
{
bool const removable = _deploy_children.exists(name);
if (removable) {
gen_named_node(xml, "frame", "operations", [&] () {
xml.node("vbox", [&] () {
gen_named_node(xml, "button", "remove", [&] () {
_remove_item.gen_button_attr(xml, "remove");
xml.node("label", [&] () {
xml.attribute("text", "Remove");
});
});
});
});
}
if (name == "ram_fs")
gen_named_node(xml, "frame", "ram_fs_operations", [&] () {
xml.node("vbox", [&] () {
_ram_fs_dialog.generate(xml, _ram_fs_state); }); });
String<100> const
ram (Capacity{info.assigned_ram - info.avail_ram}, " / ",
Capacity{info.assigned_ram}),
caps(info.assigned_caps - info.avail_caps, " / ",
info.assigned_caps, " caps");
gen_named_node(xml, "label", "hspace", [&] () {
xml.attribute("min_ex", 25); });
gen_named_node(xml, "label", "ram", [&] () {
xml.attribute("text", ram); });
gen_named_node(xml, "label", "caps", [&] () {
xml.attribute("text", caps); });
}
void Graph::_gen_parent_node(Xml_generator &xml, Start_name const &name,
Label const &label) const
{
gen_named_node(xml, "frame", name, [&] () {
xml.node("label", [&] () {
xml.attribute("text", Start_name(" ", label, " ")); }); });
}
void Graph::_gen_storage_node(Xml_generator &xml) const
{
char const * const name = "storage";
bool const any_selected = _runtime_state.selected().valid();
bool const unimportant = any_selected && !_runtime_state.storage_in_tcb();
gen_named_node(xml, "frame", name, [&] () {
if (unimportant)
xml.attribute("style", "unimportant");
xml.node("vbox", [&] () {
gen_named_node(xml, "button", name, [&] () {
_node_button_item.gen_button_attr(xml, name);
if (unimportant)
xml.attribute("style", "unimportant");
if (_storage_selected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Storage"); });
});
if (_storage_selected)
gen_named_node(xml, "frame", "storage_operations", [&] () {
xml.node("vbox", [&] () {
_storage_dialog->gen_block_devices(xml); }); });
});
});
}
void Graph::_gen_usb_node(Xml_generator &xml) const
{
char const * const name = "usb";
bool const any_selected = _runtime_state.selected().valid();
bool const unimportant = any_selected && !_runtime_state.usb_in_tcb();
gen_named_node(xml, "frame", name, [&] () {
if (unimportant)
xml.attribute("style", "unimportant");
xml.node("vbox", [&] () {
gen_named_node(xml, "button", name, [&] () {
_node_button_item.gen_button_attr(xml, name);
if (unimportant)
xml.attribute("style", "unimportant");
if (_usb_selected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "USB"); });
});
if (_usb_selected)
gen_named_node(xml, "frame", "usb_operations", [&] () {
xml.node("vbox", [&] () {
_storage_dialog->gen_usb_storage_devices(xml); }); });
});
});
}
void Graph::generate(Xml_generator &xml) const
{
xml.node("depgraph", [&] () {
if (_sculpt_partition.valid()) {
gen_named_node(xml, "button", "global+", [&] () {
_add_button_item.gen_button_attr(xml, "global+");
if (_popup_state == Popup::VISIBLE)
xml.attribute("selected", "yes");
xml.node("label", [&] () {
xml.attribute("text", "+"); }); });
}
_gen_storage_node(xml);
if (_storage_devices.usb_present)
_gen_usb_node(xml);
else
_gen_parent_node(xml, "usb", "USB");
/* parent roles */
_gen_parent_node(xml, "hardware", "Hardware");
_gen_parent_node(xml, "config", "Config");
_gen_parent_node(xml, "info", "Info");
_gen_parent_node(xml, "GUI", "GUI");
typedef Runtime_config::Component Component;
bool const any_selected = _runtime_state.selected().valid();
_runtime_config.for_each_component([&] (Component const &component) {
Start_name const name = component.name;
Start_name const pretty_name { Pretty(name) };
/* omit sculpt's helpers from the graph */
bool const blacklisted = (name == "runtime_view"
|| name == "popup_view"
|| name == "menu_view"
|| name == "panel_view"
|| name == "settings_view"
|| name == "network_view"
|| name == "file_browser_view"
|| name == "editor"
|| name == "launcher_query"
|| name == "update"
|| name == "fs_tool"
|| name == "depot_rw"
|| name == "public_rw"
|| name == "depot_rom"
|| name == "dynamic_depot_rom"
|| name == "depot_query");
if (blacklisted)
return;
Runtime_state::Info const info = _runtime_state.info(name);
bool const unimportant = any_selected && !info.tcb;
gen_named_node(xml, "frame", name, [&] () {
if (unimportant)
xml.attribute("style", "unimportant");
Start_name primary_dep = component.primary_dependency;
if (primary_dep == "default_fs_rw")
primary_dep = _sculpt_partition.fs();
if (primary_dep.valid()) {
xml.attribute("dep", primary_dep);
if (unimportant)
xml.attribute("dep_visible", false);
}
xml.node("vbox", [&] () {
gen_named_node(xml, "button", name, [&] () {
if (unimportant)
xml.attribute("style", "unimportant");
_node_button_item.gen_button_attr(xml, name);
if (info.selected)
xml.attribute("selected", "yes");
xml.node("label", [&] () {
xml.attribute("text", pretty_name);
});
});
if (info.selected)
_gen_selected_node_content(xml, name, info);
});
});
});
_runtime_config.for_each_component([&] (Component const &component) {
Start_name const name = component.name;
Runtime_state::Info const info = _runtime_state.info(name);
bool const show_details = info.tcb;
if (show_details) {
component.for_each_secondary_dep([&] (Start_name dep) {
if (Runtime_state::blacklisted_from_graph(dep))
return;
if (dep == "default_fs_rw")
dep = _sculpt_partition.fs();
xml.node("dep", [&] () {
xml.attribute("node", name);
xml.attribute("on", dep);
});
});
}
});
});
}
Dialog::Hover_result Graph::hover(Xml_node hover)
{
Hover_result const storage_dialog_hover_result =
_storage_dialog->match_sub_dialog(hover, "depgraph", "frame", "vbox", "frame", "vbox");
Dialog::Hover_result const hover_result = Dialog::any_hover_changed(
storage_dialog_hover_result,
_ram_fs_dialog.match_sub_dialog(hover, "depgraph", "frame", "vbox", "frame", "vbox"),
_node_button_item.match(hover, "depgraph", "frame", "vbox", "button", "name"),
_add_button_item .match(hover, "depgraph", "button", "name"),
_remove_item .match(hover, "depgraph", "frame", "vbox",
"frame", "vbox", "button", "name"));
if (_add_button_item.hovered("global+")) {
/* update anchor geometry of popup menu */
auto hovered_rect = [] (Xml_node const hover) {
auto point_from_xml = [] (Xml_node node) {
return Point(node.attribute_value("xpos", 0L),
node.attribute_value("ypos", 0L)); };
auto area_from_xml = [] (Xml_node node) {
return Area(node.attribute_value("width", 0UL),
node.attribute_value("height", 0UL)); };
if (!hover.has_sub_node("dialog")) return Rect();
Xml_node const dialog = hover.sub_node("dialog");
if (!dialog.has_sub_node("depgraph")) return Rect();
Xml_node const depgraph = dialog.sub_node("depgraph");
if (!depgraph.has_sub_node("button")) return Rect();
Xml_node const button = depgraph.sub_node("button");
return Rect(point_from_xml(dialog) + point_from_xml(depgraph) +
point_from_xml(button),
area_from_xml(button));
};
_popup_anchor = hovered_rect(hover);
}
return hover_result;
}
void Graph::click(Action &action)
{
if (_ram_fs_dialog.click(action) == Click_result::CONSUMED)
return;
if (_storage_dialog_visible())
if (_storage_dialog->click(action) == Click_result::CONSUMED)
return;
if (_add_button_item._hovered.valid())
action.toggle_launcher_selector(_popup_anchor);
if (_node_button_item._hovered.valid()) {
_storage_selected = !_storage_selected && _node_button_item.hovered("storage");
_usb_selected = !_usb_selected && _node_button_item.hovered("usb");
/* reset storage dialog */
if (_usb_selected || _storage_selected)
_storage_dialog.construct(_storage_devices, _sculpt_partition);
_runtime_state.toggle_selection(_node_button_item._hovered,
_runtime_config);
_remove_item.reset();
}
if (_remove_item.hovered("remove"))
_remove_item.propose_activation_on_click();
}
void Graph::clack(Action &action, Ram_fs_dialog::Action &ram_fs_action)
{
if (_ram_fs_dialog.clack(ram_fs_action) == Clack_result::CONSUMED)
return;
if (_storage_dialog_visible())
if (_storage_dialog->clack(action) == Clack_result::CONSUMED)
return;
if (_remove_item.hovered("remove")) {
_remove_item.confirm_activation_on_clack();
if (_remove_item.activated("remove")) {
action.remove_deployed_component(_runtime_state.selected());
/*
* Unselect the removed component to bring graph into
* default state.
*/
_runtime_state.toggle_selection(_runtime_state.selected(),
_runtime_config);
}
} else {
_remove_item.reset();
}
}

View File

@ -2,9 +2,6 @@
* \brief Graph view of runtime state
* \author Norman Feske
* \date 2018-07-05
*
* The GUI is based on a dynamically configured init component, which hosts
* one menu-view component for each dialog.
*/
/*
@ -19,38 +16,40 @@
/* Genode includes */
#include <os/reporter.h>
#include <depot/archive.h>
/* included from depot_deploy tool */
#include <children.h>
/* local includes */
#include <types.h>
#include <xml.h>
#include <view/activatable_item.h>
#include <view/storage_dialog.h>
#include <view/ram_fs_dialog.h>
#include <model/capacity.h>
#include <model/popup.h>
#include <model/runtime_config.h>
#include <model/runtime_state.h>
#include <model/component.h>
#include <string.h>
namespace Sculpt { struct Graph; }
struct Sculpt::Graph
struct Sculpt::Graph : Dialog
{
Env &_env;
Runtime_state &_runtime_state;
Runtime_config const &_runtime_config;
Storage_target const &_sculpt_partition;
Storage_devices const &_storage_devices;
Storage_target const &_sculpt_partition;
Ram_fs_state const &_ram_fs_state;
Popup::State const &_popup_state;
Depot_deploy::Children const &_deploy_children;
Expanding_reporter _graph_dialog_reporter { _env, "dialog", "runtime_view_dialog" };
Attached_rom_dataspace _hover_rom { _env, "runtime_view_hover" };
Signal_handler<Graph> _hover_handler {
_env.ep(), *this, &Graph::_handle_hover };
Hoverable_item _node_button_item { };
Hoverable_item _add_button_item { };
Activatable_item _remove_item { };
@ -60,275 +59,58 @@ struct Sculpt::Graph
*/
Rect _popup_anchor { };
bool _hovered = false;
Ram_fs_dialog _ram_fs_dialog;
void _gen_selected_node_content(Xml_generator &xml, Start_name const &name,
Runtime_state::Info const &info) const
bool _storage_selected = false;
bool _usb_selected = false;
bool _storage_dialog_visible() const { return _storage_selected || _usb_selected; }
Reconstructible<Storage_dialog> _storage_dialog { _storage_devices, _sculpt_partition };
void _gen_selected_node_content(Xml_generator &, Start_name const &,
Runtime_state::Info const &) const;
void _gen_parent_node(Xml_generator &, Start_name const &, Label const &) const;
void _gen_storage_node(Xml_generator &) const;
void _gen_usb_node(Xml_generator &) const;
void generate(Xml_generator &) const override;
Hover_result hover(Xml_node) override;
void reset() override { }
void reset_operation()
{
bool const removable = _deploy_children.exists(name);
if (removable) {
gen_named_node(xml, "frame", "operations", [&] () {
xml.node("vbox", [&] () {
gen_named_node(xml, "button", "remove", [&] () {
_remove_item.gen_button_attr(xml, "remove");
xml.node("label", [&] () {
xml.attribute("text", "Remove");
});
});
});
});
}
String<100> const
ram (Capacity{info.assigned_ram - info.avail_ram}, " / ",
Capacity{info.assigned_ram}),
caps(info.assigned_caps - info.avail_caps, " / ",
info.assigned_caps, " caps");
gen_named_node(xml, "label", "ram", [&] () {
xml.attribute("text", ram); });
gen_named_node(xml, "label", "caps", [&] () {
xml.attribute("text", caps); });
if (_storage_dialog.constructed())
_storage_dialog->reset_operation();
}
void _gen_parent_node(Xml_generator &xml, Start_name const &name) const
{
gen_named_node(xml, "frame", name, [&] () {
xml.node("label", [&] () {
xml.attribute("text", Start_name(" ", name, " ")); }); });
}
void _gen_graph_dialog()
{
_graph_dialog_reporter.generate([&] (Xml_generator &xml) {
xml.node("depgraph", [&] () {
if (_sculpt_partition.valid()) {
gen_named_node(xml, "button", "global+", [&] () {
_add_button_item.gen_button_attr(xml, "global+");
if (_popup_state == Popup::VISIBLE)
xml.attribute("selected", "yes");
xml.node("label", [&] () {
xml.attribute("text", "+"); }); });
}
/* parent roles */
_gen_parent_node(xml, "hardware");
_gen_parent_node(xml, "config");
_gen_parent_node(xml, "info");
_gen_parent_node(xml, "GUI");
typedef Runtime_config::Component Component;
bool const any_selected = _runtime_state.selected().valid();
_runtime_config.for_each_component([&] (Component const &component) {
Start_name const name = component.name;
Start_name const pretty_name { Pretty(name) };
/* omit sculpt's helpers from the graph */
bool const blacklisted = (name == "runtime_view"
|| name == "launcher_query"
|| name == "update"
|| name == "fs_tool"
|| name == "depot_rw"
|| name == "public_rw"
|| name == "depot_rom"
|| name == "dynamic_depot_rom"
|| name == "depot_query");
if (blacklisted)
return;
Runtime_state::Info const info = _runtime_state.info(name);
bool const unimportant = any_selected && !info.tcb;
gen_named_node(xml, "frame", name, [&] () {
if (unimportant)
xml.attribute("style", "unimportant");
Start_name primary_dep = component.primary_dependency;
if (primary_dep == "default_fs_rw")
primary_dep = _sculpt_partition.fs();
if (primary_dep.valid()) {
xml.attribute("dep", primary_dep);
if (unimportant)
xml.attribute("dep_visible", false);
}
xml.node("vbox", [&] () {
gen_named_node(xml, "button", name, [&] () {
if (unimportant)
xml.attribute("style", "unimportant");
_node_button_item.gen_button_attr(xml, name);
if (info.selected)
xml.attribute("selected", "yes");
xml.node("label", [&] () {
xml.attribute("text", pretty_name);
});
});
if (info.selected)
_gen_selected_node_content(xml, name, info);
});
});
});
_runtime_config.for_each_component([&] (Component const &component) {
Start_name const name = component.name;
Runtime_state::Info const info = _runtime_state.info(name);
bool const show_details = info.tcb;
if (show_details) {
component.for_each_secondary_dep([&] (Start_name const &dep) {
if (Runtime_state::blacklisted_from_graph(dep))
return;
xml.node("dep", [&] () {
xml.attribute("node", name);
xml.attribute("on", dep);
});
});
}
});
});
});
}
void _handle_hover()
{
_hover_rom.update();
Xml_node const hover = _hover_rom.xml();
_hovered = (hover.num_sub_nodes() != 0);
bool const changed =
_node_button_item.match(hover, "dialog", "depgraph", "frame", "vbox", "button", "name") |
_add_button_item .match(hover, "dialog", "depgraph", "button", "name") |
_remove_item .match(hover, "dialog", "depgraph", "frame", "vbox",
"frame", "vbox", "button", "name");
if (_add_button_item.hovered("global+")) {
/* update anchor geometry of popup menu */
auto hovered_rect = [] (Xml_node const hover) {
auto point_from_xml = [] (Xml_node node) {
return Point(node.attribute_value("xpos", 0L),
node.attribute_value("ypos", 0L)); };
auto area_from_xml = [] (Xml_node node) {
return Area(node.attribute_value("width", 0UL),
node.attribute_value("height", 0UL)); };
if (!hover.has_sub_node("dialog")) return Rect();
Xml_node const dialog = hover.sub_node("dialog");
if (!dialog.has_sub_node("depgraph")) return Rect();
Xml_node const depgraph = dialog.sub_node("depgraph");
if (!depgraph.has_sub_node("button")) return Rect();
Xml_node const button = depgraph.sub_node("button");
return Rect(point_from_xml(dialog) + point_from_xml(depgraph) +
point_from_xml(button),
area_from_xml(button));
};
_popup_anchor = hovered_rect(hover);
}
if (changed)
_gen_graph_dialog();
}
Graph(Env &env,
Runtime_state &runtime_state,
Graph(Runtime_state &runtime_state,
Runtime_config const &runtime_config,
Storage_devices const &storage_devices,
Storage_target const &sculpt_partition,
Ram_fs_state const &ram_fs_state,
Popup::State const &popup_state,
Depot_deploy::Children const &deploy_children)
:
_env(env), _runtime_state(runtime_state), _runtime_config(runtime_config),
_sculpt_partition(sculpt_partition),
_popup_state(popup_state), _deploy_children(deploy_children)
{
_hover_rom.sigh(_hover_handler);
}
bool hovered() const { return _hovered; }
_runtime_state(runtime_state), _runtime_config(runtime_config),
_storage_devices(storage_devices), _sculpt_partition(sculpt_partition),
_ram_fs_state(ram_fs_state), _popup_state(popup_state),
_deploy_children(deploy_children), _ram_fs_dialog(sculpt_partition)
{ }
bool add_button_hovered() const { return _add_button_item._hovered.valid(); }
struct Action : Interface
struct Action : Storage_dialog::Action
{
virtual void remove_deployed_component(Start_name const &) = 0;
virtual void toggle_launcher_selector(Rect) = 0;
};
void click(Action &action)
{
if (_add_button_item._hovered.valid()) {
action.toggle_launcher_selector(_popup_anchor);
}
if (_node_button_item._hovered.valid()) {
_runtime_state.toggle_selection(_node_button_item._hovered,
_runtime_config);
_remove_item.reset();
_gen_graph_dialog();
}
if (_remove_item.hovered("remove")) {
_remove_item.propose_activation_on_click();
_gen_graph_dialog();
}
}
void clack(Action &action)
{
if (_remove_item.hovered("remove")) {
_remove_item.confirm_activation_on_clack();
if (_remove_item.activated("remove")) {
action.remove_deployed_component(_runtime_state.selected());
/*
* Unselect the removed component to bring graph into
* default state.
*/
_runtime_state.toggle_selection(_runtime_state.selected(),
_runtime_config);
}
} else {
_remove_item.reset();
}
_gen_graph_dialog();
}
void gen_dialog() { _gen_graph_dialog(); }
void click(Action &action);
void clack(Action &action, Ram_fs_dialog::Action &);
};
#endif /* _GRAPH_H_ */

View File

@ -1,114 +0,0 @@
/*
* \brief Sculpt GUI management
* \author Norman Feske
* \date 2018-04-30
*
* The GUI is based on a dynamically configured init component, which hosts
* one menu-view component for each dialog.
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
/* local includes */
#include <gui.h>
void Sculpt::Gui::_gen_menu_view_start_content(Xml_generator &xml,
Label const &label,
Point pos,
unsigned width) const
{
xml.attribute("version", version.value);
gen_common_start_content(xml, label, Cap_quota{150}, Ram_quota{12*1024*1024});
gen_named_node(xml, "binary", "menu_view");
xml.node("config", [&] () {
xml.attribute("xpos", pos.x());
xml.attribute("ypos", pos.y());
if (width)
xml.attribute("width", width);
xml.node("libc", [&] () { xml.attribute("stderr", "/dev/log"); });
xml.node("report", [&] () { xml.attribute("hover", "yes"); });
xml.node("vfs", [&] () {
gen_named_node(xml, "tar", "menu_view_styles.tar");
gen_named_node(xml, "dir", "styles", [&] () {
gen_named_node(xml, "dir", "frame", [&] () {
gen_named_node(xml, "dir", "logo", [&] () {
gen_named_node(xml, "rom", "background.png", [&] () {
xml.attribute("label", "genode_logo.png"); }); }); }); });
gen_named_node(xml, "dir", "fonts", [&] () {
xml.node("fs", [&] () {
xml.attribute("label", "fonts"); }); });
gen_named_node(xml, "dir", "dev", [&] () {
xml.node("log", [&] () { }); });
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "menu_view");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "libpng.lib.so");
gen_parent_rom_route(xml, "zlib.lib.so");
gen_parent_rom_route(xml, "menu_view_styles.tar");
gen_parent_rom_route(xml, "genode_logo.png");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_parent_route<Nitpicker::Session> (xml);
gen_service_node<Rom_session>(xml, [&] () {
xml.attribute("label", "dialog");
xml.node("parent", [&] () { }); });
gen_service_node<Report::Session>(xml, [&] () {
xml.attribute("label", "hover");
xml.node("parent", [&] () { }); });
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "fonts");
xml.node("parent", [&] () {
xml.attribute("label", "fonts"); }); });
});
}
void Sculpt::Gui::_generate_config(Xml_generator &xml) const
{
xml.node("parent-provides", [&] () {
gen_parent_service<Rom_session>(xml);
gen_parent_service<Cpu_session>(xml);
gen_parent_service<Pd_session>(xml);
gen_parent_service<Log_session>(xml);
gen_parent_service<Timer::Session>(xml);
gen_parent_service<Report::Session>(xml);
gen_parent_service<Nitpicker::Session>(xml);
gen_parent_service<::File_system::Session>(xml);
});
xml.node("resource", [&] () {
xml.attribute("name", "RAM");
xml.attribute("preserve", "1M");
});
xml.node("start", [&] () {
_gen_menu_view_start_content(xml, "menu", Point(0, 0), menu_width); });
xml.node("start", [&] () {
_gen_menu_view_start_content(xml, "popup", Point(0, 0), 0); });
}

View File

@ -1,65 +0,0 @@
/*
* \brief Sculpt GUI management
* \author Norman Feske
* \date 2018-04-30
*
* The GUI is based on a dynamically configured init component, which hosts
* one menu-view component for each dialog.
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _GUI_H_
#define _GUI_H_
/* Genode includes */
#include <os/reporter.h>
/* local includes */
#include <types.h>
#include <xml.h>
namespace Sculpt { struct Gui; }
struct Sculpt::Gui
{
Env &_env;
Expanding_reporter _config { _env, "config", "gui_config" };
float _font_size_px = 14;
typedef String<32> Label;
struct Version { unsigned value; } version { 0 };
unsigned menu_width = 0;
void _gen_menu_view_start_content(Xml_generator &, Label const &, Point,
unsigned) const;
void _generate_config(Xml_generator &) const;
void generate_config()
{
_config.generate([&] (Xml_generator &xml) { _generate_config(xml); });
}
float font_size() const { return _font_size_px; }
void font_size(float px)
{
_font_size_px = px;
menu_width = max(px*21, 320.0);
}
Gui(Env &env) : _env(env) { }
};
#endif /* _GUI_H_ */

View File

@ -20,6 +20,7 @@
/* local includes */
#include <types.h>
#include <view/network_dialog.h>
#include <view/panel_dialog.h>
namespace Sculpt { struct Keyboard_focus; }
@ -29,8 +30,9 @@ struct Sculpt::Keyboard_focus
Expanding_reporter _focus_reporter;
Network_dialog const &_network_dialog;
Wpa_passphrase &_wpa_passphrase;
Network_dialog const &_network_dialog;
Wpa_passphrase &_wpa_passphrase;
Panel_dialog::State const &_panel;
void update()
{
@ -38,7 +40,7 @@ struct Sculpt::Keyboard_focus
target = WM;
if (_network_dialog.need_keyboard_focus_for_passphrase())
if (_panel.network_visible() && _network_dialog.need_keyboard_focus_for_passphrase())
target = WPA_PASSPHRASE;
if (orig_target == target)
@ -63,12 +65,14 @@ struct Sculpt::Keyboard_focus
}
Keyboard_focus(Env &env,
Network_dialog const &network_dialog,
Wpa_passphrase &wpa_passphrase)
Network_dialog const &network_dialog,
Wpa_passphrase &wpa_passphrase,
Panel_dialog::State const &panel)
:
_focus_reporter(env, "focus", "focus"),
_network_dialog(network_dialog),
_wpa_passphrase(wpa_passphrase)
_wpa_passphrase(wpa_passphrase),
_panel(panel)
{
update();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,152 @@
/*
* \brief Menu-view dialog handling
* \author Norman Feske
* \date 2018-05-18
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <menu_view.h>
using namespace Sculpt;
void Menu_view::_handle_hover()
{
using Hover_result = Dialog::Hover_result;
_hover_rom.update();
bool const orig_hovered = _hovered;
_hovered = false;
Hover_result hover_result = Hover_result::UNMODIFIED;
_hover_rom.xml().with_sub_node("dialog", [&] (Xml_node hover) {
_hovered = true;
hover_result = _dialog.hover(hover);
});
if (!_hovered)
_dialog.hover(Xml_node("<empty/>"));
bool const dialog_hover_changed = (_hovered != orig_hovered),
widget_hover_changed = (hover_result == Hover_result::CHANGED);
if (dialog_hover_changed || widget_hover_changed)
generate();
}
Menu_view::Menu_view(Env &env, Registry<Child_state> &registry,
Dialog &dialog, Start_name const &name,
Ram_quota ram_quota, Cap_quota cap_quota,
Session_label const &dialog_report_name,
Session_label const &hover_rom_name)
:
_dialog(dialog),
_child_state(registry, name, ram_quota, cap_quota),
_dialog_reporter(env, "dialog", dialog_report_name.string()),
_hover_rom(env, hover_rom_name.string()),
_hover_handler(env.ep(), *this, &Menu_view::_handle_hover)
{
_hover_rom.sigh(_hover_handler);
generate();
}
void Menu_view::generate()
{
_dialog_reporter.generate([&] (Xml_generator &xml) {
_dialog.generate(xml); });
}
void Menu_view::reset()
{
_hovered = false;
_dialog.hover(Xml_node("<empty/>"));
_dialog.reset();
}
void Menu_view::gen_start_node(Xml_generator &xml) const
{
xml.node("start", [&] () {
_gen_start_node_content(xml); });
}
void Menu_view::_gen_start_node_content(Xml_generator &xml) const
{
_child_state.gen_start_node_content(xml);
gen_named_node(xml, "binary", "menu_view");
xml.node("config", [&] () {
if (min_width) xml.attribute("width", min_width);
if (min_height) xml.attribute("height", min_height);
xml.node("libc", [&] () { xml.attribute("stderr", "/dev/log"); });
xml.node("report", [&] () { xml.attribute("hover", "yes"); });
xml.node("vfs", [&] () {
gen_named_node(xml, "tar", "menu_view_styles.tar");
gen_named_node(xml, "dir", "fonts", [&] () {
xml.node("fs", [&] () {
xml.attribute("label", "fonts"); }); });
gen_named_node(xml, "dir", "dev", [&] () {
xml.node("log", [&] () { }); });
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "menu_view");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "libpng.lib.so");
gen_parent_rom_route(xml, "zlib.lib.so");
gen_parent_rom_route(xml, "menu_view_styles.tar");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
using Label = String<128>;
Label const label = _child_state.name();
gen_service_node<Nitpicker::Session>(xml, [&] () {
xml.node("parent", [&] () {
xml.attribute("label", Label("leitzentrale -> ", label)); }); });
gen_service_node<Rom_session>(xml, [&] () {
xml.attribute("label", "dialog");
xml.node("parent", [&] () {
xml.attribute("label", Label("leitzentrale -> ", label, " -> dialog"));
});
});
gen_service_node<Report::Session>(xml, [&] () {
xml.attribute("label", "hover");
xml.node("parent", [&] () {
xml.attribute("label", Label("leitzentrale -> ", label, " -> hover"));
});
});
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "fonts");
xml.node("parent", [&] () {
xml.attribute("label", "leitzentrale -> fonts"); }); });
});
}

View File

@ -0,0 +1,72 @@
/*
* \brief Menu-view dialog handling
* \author Norman Feske
* \date 2018-05-18
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MENU_VIEW_H_
#define _MENU_VIEW_H_
/* Genode includes */
#include <base/session_label.h>
#include <os/reporter.h>
#include <base/attached_rom_dataspace.h>
/* local includes */
#include "types.h"
#include <view/dialog.h>
#include <model/child_state.h>
namespace Sculpt { struct Menu_view; }
struct Sculpt::Menu_view : Noncopyable
{
Dialog &_dialog;
Child_state _child_state;
Expanding_reporter _dialog_reporter;
Attached_rom_dataspace _hover_rom;
Signal_handler<Menu_view> _hover_handler;
bool _hovered = false;
unsigned min_width = 0;
unsigned min_height = 0;
void _handle_hover();
void _gen_start_node_content(Xml_generator &) const;
Menu_view(Env &, Registry<Child_state> &registry,
Dialog &, Start_name const &, Ram_quota, Cap_quota,
Session_label const &dialog_report_name,
Session_label const &hover_rom_name);
void generate();
bool hovered() const { return _hovered; }
void reset();
void gen_start_node(Xml_generator &) const;
bool apply_child_state_report(Xml_node report)
{
return _child_state.apply_child_state_report(report);
}
void trigger_restart() { _child_state.trigger_restart(); }
};
#endif /* _MENU_VIEW_H_ */

View File

@ -16,6 +16,7 @@
/* Genode includes */
#include <util/xml_node.h>
#include <base/registry.h>
/* local includes */
#include "types.h"
@ -26,6 +27,8 @@ struct Sculpt::Child_state : Noncopyable
{
private:
Registry<Child_state>::Element _element;
Start_name const _name;
Ram_quota const _initial_ram_quota;
@ -44,9 +47,10 @@ struct Sculpt::Child_state : Noncopyable
* \param ram_quota initial RAM quota
* \param cap_quota initial capability quota
*/
Child_state(Start_name const &name,
Child_state(Registry<Child_state> &registry, Start_name const &name,
Ram_quota ram_quota, Cap_quota cap_quota)
:
_element(registry, *this),
_name(name),
_initial_ram_quota(ram_quota), _initial_cap_quota(cap_quota)
{ }
@ -58,12 +62,17 @@ struct Sculpt::Child_state : Noncopyable
_cap_quota = _initial_cap_quota;
}
void gen_start_node_version(Xml_generator &xml) const
{
if (_version.value)
xml.attribute("version", _version.value);
}
void gen_start_node_content(Xml_generator &xml) const
{
xml.attribute("name", _name);
if (_version.value)
xml.attribute("version", _version.value);
gen_start_node_version(xml);
xml.attribute("caps", _cap_quota.value);
gen_named_node(xml, "resource", "RAM", [&] () {
@ -102,6 +111,8 @@ struct Sculpt::Child_state : Noncopyable
}
Ram_quota ram_quota() const { return _ram_quota; }
Start_name name() const { return _name; }
};
#endif /* _MODEL__CHILD_STATE_H_ */

View File

@ -0,0 +1,217 @@
/*
* \brief File_browser state
* \author Norman Feske
* \date 2020-01-31
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__FILE_BROWSER_STATE_H_
#define _MODEL__FILE_BROWSER_STATE_H_
#include "types.h"
#include <model/child_state.h>
namespace Sculpt { struct File_browser_state; }
struct Sculpt::File_browser_state : Noncopyable
{
using Fs_name = Start_name;
using Path = String<256>;
using File = Path;
using Sub_dir = Path;
Fs_name browsed_fs { };
Constructible<Child_state> fs_query { };
Constructible<Child_state> text_area { };
Constructible<Attached_rom_dataspace> query_result { };
File_browser_state() { };
Path path { };
/*
* File viewing and editing
*/
File edited_file { };
bool edit = false;
bool modified = false; /* edited file has unsaved modifications */
unsigned save_version = 0; /* version used for next save request */
unsigned last_saved_version = 0; /* last version successfully saved */
void update_query_results()
{
if (query_result.constructed())
query_result->update();
}
template <typename FN>
void with_query_result(FN const &fn) const
{
if (query_result.constructed())
fn(query_result->xml());
}
using Index = Label;
template <typename FN>
void with_entry_at_index(Index index, FN const &fn) const
{
unsigned cnt = 0;
with_query_result([&] (Xml_node node) {
node.with_sub_node("dir", [&] (Xml_node listing) {
listing.for_each_sub_node([&] (Xml_node entry) {
if (Index(cnt++) == index)
fn(entry); }); }); });
}
bool any_browsed_fs() const { return browsed_fs.length() > 0; }
void gen_start_nodes(Xml_generator &xml) const
{
if (!fs_query.constructed() || !any_browsed_fs())
return;
xml.node("start", [&] () {
fs_query->gen_start_node_content(xml);
gen_named_node(xml, "binary", "fs_query");
xml.node("config", [&] () {
xml.node("vfs", [&] () {
xml.node("fs", [&] () {}); });
xml.node("query", [&] () {
xml.attribute("path", path);
});
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "fs_query");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Report::Session> (xml);
gen_service_node<::File_system::Session>(xml, [&] () {
if (browsed_fs == "config") {
xml.node("parent", [&] () {
xml.attribute("label", "config"); });
}
else if (browsed_fs == "report") {
xml.node("parent", [&] () {
xml.attribute("label", "report"); });
}
else {
xml.node("child", [&] () {
xml.attribute("name", browsed_fs); });
}
});
});
});
if (edited_file.length() <= 1 || !text_area.constructed())
return;
xml.node("start", [&] () {
xml.attribute("name", text_area->name());
text_area->gen_start_node_version(xml);
xml.attribute("caps", 350);
gen_named_node(xml, "resource", "RAM", [&] () {
xml.attribute("quantum", String<64>(22*1024*1024UL)); });
gen_named_node(xml, "binary", "text_area");
xml.node("config", [&] () {
Path const file_path = (path == "/")
? Path("/", edited_file)
: Path(path, "/", edited_file);
xml.attribute("path", file_path);
xml.attribute("max_lines", 40);
xml.attribute("min_width", 600);
xml.attribute("copy", "yes");
if (edit)
xml.attribute("paste", "yes");
else
xml.attribute("watch", "yes");
if (edit) {
xml.node("save", [&] () {
xml.attribute("version", save_version); });
xml.node("report", [&] () {
xml.attribute("saved", "yes"); });
}
xml.node("vfs", [&] () {
xml.node("fs", [&] () {}); });
});
xml.node("route", [&] () {
gen_parent_rom_route(xml, "text_area");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_rom_route(xml, "vfs.lib.so");
gen_parent_rom_route(xml, "sandbox.lib.so");
gen_parent_rom_route(xml, "menu_view");
gen_parent_rom_route(xml, "libc.lib.so");
gen_parent_rom_route(xml, "libm.lib.so");
gen_parent_rom_route(xml, "libpng.lib.so");
gen_parent_rom_route(xml, "zlib.lib.so");
gen_parent_rom_route(xml, "menu_view_styles.tar");
gen_parent_route<Cpu_session> (xml);
gen_parent_route<Pd_session> (xml);
gen_parent_route<Log_session> (xml);
gen_parent_route<Report::Session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_service_node<Rom_session>(xml, [&] () {
xml.attribute("label", "clipboard");
xml.node("parent", [&] () { }); });
gen_service_node<Nitpicker::Session>(xml, [&] () {
xml.node("parent", [&] () {
xml.attribute("label", Label("leitzentrale -> editor")); }); });
gen_service_node<::File_system::Session>(xml, [&] () {
xml.attribute("label", "fonts");
xml.node("parent", [&] () {
xml.attribute("label", "leitzentrale -> fonts"); }); });
gen_service_node<::File_system::Session>(xml, [&] () {
if (browsed_fs == "config") {
xml.node("parent", [&] () {
xml.attribute("label", "config"); });
}
else if (browsed_fs == "report") {
xml.node("parent", [&] () {
xml.attribute("label", "report"); });
}
else {
xml.node("child", [&] () {
xml.attribute("name", browsed_fs); });
}
});
});
});
}
};
#endif /* _MODEL__FILE_BROWSER_STATE_H_ */

View File

@ -31,6 +31,8 @@ struct Sculpt::File_system
{
enum Type { UNKNOWN, EXT2, FAT32, GEMDOS } type;
bool inspected = false;
bool accessible() const { return type == EXT2 || type == FAT32 || type == GEMDOS; }
bool expandable() const { return type == EXT2; }
@ -58,7 +60,6 @@ struct Sculpt::Partition : List_model<Partition>::Element
bool check_in_progress = false;
bool format_in_progress = false;
bool file_system_inspected = false;
bool gpt_expand_in_progress = false;
bool fs_resize_in_progress = false;
@ -76,7 +77,7 @@ struct Sculpt::Partition : List_model<Partition>::Element
bool idle() const { return !check_in_progress
&& !format_in_progress
&& !file_system_inspected
&& !file_system.inspected
&& !relabel_in_progress(); }
bool genode_default() const { return label == "GENODE*"; }

View File

@ -20,15 +20,17 @@
/* local includes */
#include <types.h>
#include <model/child_state.h>
#include <model/partition.h>
namespace Sculpt { struct Ram_fs_state; }
struct Sculpt::Ram_fs_state : Child_state
struct Sculpt::Ram_fs_state : Child_state, File_system
{
bool inspected = false;
Ram_fs_state(Start_name const &name)
: Child_state(name, Ram_quota{1024*1024}, Cap_quota{300}) { }
Ram_fs_state(Registry<Child_state> &registry, Start_name const &name)
:
Child_state(registry, name, Ram_quota{1024*1024}, Cap_quota{300}),
File_system(File_system::UNKNOWN)
{ }
};
#endif /* _MODEL__RAM_FS_STATE_H_ */

View File

@ -69,9 +69,7 @@ class Sculpt::Runtime_config
if (ignored_service)
return;
bool const hardware = (service == "Block")
|| (service == "USB")
|| (service == "Platform")
bool const hardware = (service == "Platform")
|| (service == "IO_PORT")
|| (service == "IO_MEM")
|| (service == "Rtc")
@ -82,6 +80,18 @@ class Sculpt::Runtime_config
return;
}
bool const usb = (service == "Usb");
if (usb) {
result = "usb";
return;
}
bool const storage = (service == "Block");
if (storage) {
result = "storage";
return;
}
if (service == "ROM") {
/*
@ -347,6 +357,10 @@ class Sculpt::Runtime_config
} _parent_services { };
Service const _used_fs_service { "default_fs_rw",
Service::Type::FILE_SYSTEM,
Label(), "used file system" };
public:
Runtime_config(Allocator &alloc) : _alloc(alloc) { }
@ -375,10 +389,12 @@ class Sculpt::Runtime_config
template <typename FN>
void for_each_service(FN const &fn) const
{
_parent_services.for_each(fn);
fn(_used_fs_service);
_components.for_each([&] (Component const &component) {
component.for_each_service(fn); });
_parent_services.for_each(fn);
}
};

View File

@ -70,6 +70,9 @@ class Sculpt::Runtime_state : public Runtime_info
List_model<Child> _children { };
bool _usb_in_tcb = false;
bool _storage_in_tcb = false;
/**
* Child present in initial deploy config but interactively removed
*/
@ -264,6 +267,9 @@ class Sculpt::Runtime_state : public Runtime_info
return result;
}
bool usb_in_tcb() const { return _usb_in_tcb; }
bool storage_in_tcb() const { return _storage_in_tcb; }
static bool blacklisted_from_graph(Start_name const &name)
{
/*
@ -281,6 +287,8 @@ class Sculpt::Runtime_state : public Runtime_info
child.info.tcb_updated = false;
});
_usb_in_tcb = _storage_in_tcb = false;
/*
* Update the TCB flag of the selected child's transitive
* dependencies.
@ -315,6 +323,15 @@ class Sculpt::Runtime_state : public Runtime_info
child.info.tcb = true; });
});
}
_children.for_each([&] (Child const &child) {
if (child.info.tcb) {
config.for_each_dependency(child.name, [&] (Start_name dep) {
if (dep == "usb") _usb_in_tcb = true;
if (dep == "storage") _storage_in_tcb = true;
});
}
});
}
void abandon(Start_name const &name)

View File

@ -72,6 +72,12 @@ struct Sculpt::Service
Service(Start_name const &server, Type type, Label const &label)
: server(server), type(type), label(label), info(Subst("_", " ", server)) { }
/**
* Constructor for default_fs_rw
*/
Service(Start_name const &server, Type type, Label const &label, Info const &info)
: server(server), type(type), label(label), info(info) { }
/**
* Constructor for parent service
*/

View File

@ -0,0 +1,23 @@
/*
* \brief Settings state
* \author Norman Feske
* \date 2020-01-30
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _MODEL__SETTINGS_H_
#define _MODEL__SETTINGS_H_
#include "types.h"
namespace Sculpt { enum class Font_size; }
enum class Sculpt::Font_size { SMALL, MEDIUM, LARGE };
#endif /* _MODEL__SETTINGS_H_ */

View File

@ -83,7 +83,7 @@ struct Sculpt::Storage_device
*
* Ignore reports that come in while the device is in use. Otherwise,
* the reconstruction of 'whole_device_partition' would wrongly reset
* the partition state such as the 'file_system_inspected' flag.
* the partition state such as the 'file_system.inspected' flag.
*/
if (!whole_device_partition.constructed() || whole_device_partition->idle()) {
whole_device_partition.construct(Partition::Args::whole_device(capacity));
@ -130,7 +130,7 @@ struct Sculpt::Storage_device
partitions.for_each([&] (Partition const &partition) {
needed_for_access |= partition.check_in_progress;
needed_for_access |= partition.format_in_progress;
needed_for_access |= partition.file_system_inspected;
needed_for_access |= partition.file_system.inspected;
needed_for_access |= partition.fs_resize_in_progress;
});

View File

@ -29,6 +29,8 @@ struct Sculpt::Storage_devices
bool _block_devices_report_valid = false;
bool _usb_active_config_valid = false;
bool usb_present = false;
/**
* Update 'block_devices' from 'block_devices' report
*/
@ -51,6 +53,10 @@ struct Sculpt::Storage_devices
if (node.has_type("raw"))
_usb_active_config_valid = true;
usb_present = false;
usb_storage_devices.for_each([&] (Storage_device const &) {
usb_present = true; });
}
/**

View File

@ -74,7 +74,7 @@ struct Sculpt::Usb_storage_device : List_model<Usb_storage_device>::Element,
for_each_partition([&] (Partition const &partition) {
drv_needed |= partition.check_in_progress
|| partition.format_in_progress
|| partition.file_system_inspected
|| partition.file_system.inspected
|| partition.relabel_in_progress()
|| partition.expand_in_progress(); });
@ -123,6 +123,10 @@ void Sculpt::Usb_storage_device::gen_usb_block_drv_start_content(Xml_generator &
gen_provides<Block::Session>(xml);
xml.node("route", [&] () {
gen_service_node<Usb::Session>(xml, [&] () {
xml.node("parent", [&] () {
xml.attribute("label", label); }); });
gen_parent_rom_route(xml, "usb_block_drv");
gen_parent_rom_route(xml, "ld.lib.so");
gen_parent_route<Cpu_session> (xml);
@ -130,10 +134,6 @@ void Sculpt::Usb_storage_device::gen_usb_block_drv_start_content(Xml_generator &
gen_parent_route<Log_session> (xml);
gen_parent_route<Timer::Session> (xml);
gen_service_node<Usb::Session>(xml, [&] () {
xml.node("parent", [&] () {
xml.attribute("label", label); }); });
gen_service_node<Report::Session>(xml, [&] () {
xml.node("parent", [&] () { }); });
});

View File

@ -50,7 +50,7 @@ void Sculpt::Network::handle_key_press(Codepoint code)
if (_wifi_connection.state == Wifi_connection::CONNECTING)
wifi_connect(_wifi_connection.bssid);
_dialog_generator.generate_dialog();
_menu_view.generate();
}
@ -136,7 +136,7 @@ void Sculpt::Network::_handle_wlan_accesspoints()
Access_point_update_policy policy(_alloc);
_access_points.update_from_xml(policy, _wlan_accesspoints_rom.xml());
_dialog_generator.generate_dialog();
_menu_view.generate();
}
@ -144,7 +144,7 @@ void Sculpt::Network::_handle_wlan_state()
{
_wlan_state_rom.update();
_wifi_connection = Wifi_connection::from_xml(_wlan_state_rom.xml());
_dialog_generator.generate_dialog();
_menu_view.generate();
}
@ -156,7 +156,7 @@ void Sculpt::Network::_handle_nic_router_state()
_nic_state = Nic_state::from_xml(_nic_router_state_rom.xml());
if (_nic_state.ipv4 != old_nic_state.ipv4)
_dialog_generator.generate_dialog();
_menu_view.generate();
/* if the nic state becomes ready, consider spawning the update subsystem */
if (old_nic_state.ready() != _nic_state.ready())
@ -210,7 +210,7 @@ void Sculpt::Network::_handle_nic_router_config(Xml_node config)
nic_target(target);
_generate_nic_router_config();
_runtime_config_generator.generate_runtime_config();
_dialog_generator.generate_dialog();
_menu_view.generate();
}

View File

@ -21,7 +21,7 @@
/* local includes */
#include <model/child_exit_state.h>
#include <view/network_dialog.h>
#include <gui.h>
#include <menu_view.h>
#include <runtime.h>
#include <keyboard_focus.h>
#include <managed_config.h>
@ -35,7 +35,7 @@ struct Sculpt::Network : Network_dialog::Action
Allocator &_alloc;
Dialog::Generator &_dialog_generator;
Registry<Child_state> &_child_states;
Runtime_config_generator &_runtime_config_generator;
@ -97,10 +97,22 @@ struct Sculpt::Network : Network_dialog::Action
Network_dialog::WLAN_CONFIG_MANAGED;
Network_dialog dialog {
_env, _dialog_generator, _nic_target, _access_points,
_nic_target, _access_points,
_wifi_connection, _nic_state, wpa_passphrase, _wlan_config_policy,
_pci_info };
Menu_view _menu_view { _env, _child_states, dialog, "network_view",
Ram_quota{4*1024*1024}, Cap_quota{150},
"network_dialog", "network_view_hover" };
void min_dialog_width(unsigned value) { _menu_view.min_width = value; }
bool dialog_hovered() const { return _menu_view.hovered(); }
void update_view() { _menu_view.generate(); }
void trigger_dialog_restart() { _menu_view.trigger_restart(); }
Managed_config<Network> _wlan_config {
_env, "config", "wifi", *this, &Network::_handle_wlan_config };
@ -108,7 +120,7 @@ struct Sculpt::Network : Network_dialog::Action
{
if (_wlan_config.try_generate_manually_managed()) {
_wlan_config_policy = Network_dialog::WLAN_CONFIG_MANUAL;
_dialog_generator.generate_dialog();
_menu_view.generate();
return;
}
@ -142,7 +154,7 @@ struct Sculpt::Network : Network_dialog::Action
_nic_target.managed_type = type;
_generate_nic_router_config();
_runtime_config_generator.generate_runtime_config();
_dialog_generator.generate_dialog();
_menu_view.generate();
}
}
@ -207,11 +219,11 @@ struct Sculpt::Network : Network_dialog::Action
_runtime_config_generator.generate_runtime_config();
}
Network(Env &env, Allocator &alloc, Dialog::Generator &dialog_generator,
Network(Env &env, Allocator &alloc, Registry<Child_state> &child_states,
Runtime_config_generator &runtime_config_generator,
Runtime_info const &runtime_info, Pci_info const &pci_info)
:
_env(env), _alloc(alloc), _dialog_generator(dialog_generator),
_env(env), _alloc(alloc), _child_states(child_states),
_runtime_config_generator(runtime_config_generator),
_runtime_info(runtime_info), _pci_info(pci_info)
{

View File

@ -20,7 +20,7 @@ namespace Sculpt {
{
devices.for_each([&] (Storage_device const &device) {
device.for_each_partition([&] (Partition const &partition) {
if (partition.file_system_inspected)
if (partition.file_system.inspected)
fn(Storage_target { device.label, partition.number }); }); });
}

View File

@ -52,11 +52,13 @@ void Sculpt::gen_runtime_view_start_content(Xml_generator &xml,
gen_service_node<Rom_session>(xml, [&] () {
xml.attribute("label", "dialog");
xml.node("parent", [&] () { }); });
xml.node("parent", [&] () {
xml.attribute("label", "leitzentrale -> runtime_view -> dialog"); }); });
gen_service_node<Report::Session>(xml, [&] () {
xml.attribute("label", "hover");
xml.node("parent", [&] () { }); });
xml.node("parent", [&] () {
xml.attribute("label", "leitzentrale -> runtime_view -> hover"); }); });
gen_parent_rom_route(xml, "menu_view");
gen_parent_rom_route(xml, "ld.lib.so");

View File

@ -140,7 +140,7 @@ void Sculpt::Storage::gen_runtime_start_nodes(Xml_generator &xml) const
gen_resize2fs_start_content(xml, target); }); }
if (partition.file_system.type != File_system::UNKNOWN) {
if (partition.file_system_inspected || target == _sculpt_partition)
if (partition.file_system.inspected || target == _sculpt_partition)
xml.node("start", [&] () {
gen_fs_start_content(xml, target, partition.file_system.type); });

View File

@ -21,12 +21,13 @@
/* local includes */
#include <model/discovery_state.h>
#include <view/storage_dialog.h>
#include <view/ram_fs_dialog.h>
#include <runtime.h>
namespace Sculpt { struct Storage; }
struct Sculpt::Storage : Storage_dialog::Action
struct Sculpt::Storage : Storage_dialog::Action, Ram_fs_dialog::Action
{
Env &_env;
@ -49,7 +50,7 @@ struct Sculpt::Storage : Storage_dialog::Action
Storage_devices _storage_devices { };
Ram_fs_state _ram_fs_state { "ram_fs" };
Ram_fs_state _ram_fs_state;
Storage_target _sculpt_partition { };
@ -57,8 +58,7 @@ struct Sculpt::Storage : Storage_dialog::Action
File_browser_version _file_browser_version { 0 };
Storage_dialog dialog {
_env, _dialog_generator, _storage_devices, _ram_fs_state, _sculpt_partition };
Storage_dialog dialog { _storage_devices, _sculpt_partition };
void handle_storage_devices_update();
@ -73,7 +73,7 @@ struct Sculpt::Storage : Storage_dialog::Action
bool result = _ram_fs_state.inspected;
_storage_devices.for_each([&] (Storage_device const &device) {
device.for_each_partition([&] (Partition const &partition) {
result |= partition.file_system_inspected; }); });
result |= partition.file_system.inspected; }); });
return result;
}
@ -159,7 +159,7 @@ struct Sculpt::Storage : Storage_dialog::Action
}
_apply_partition(target, [&] (Partition &partition) {
partition.file_system_inspected = !partition.file_system_inspected;
partition.file_system.inspected = !partition.file_system.inspected;
_file_browser_version.value++;
});
@ -189,14 +189,17 @@ struct Sculpt::Storage : Storage_dialog::Action
}
Storage(Env &env, Allocator &alloc, Dialog::Generator &dialog_generator,
Storage(Env &env, Allocator &alloc,
Registry<Child_state> &child_states,
Dialog::Generator &dialog_generator,
Runtime_config_generator &runtime_config_generator,
Target_user &target_user)
Target_user &target_user)
:
_env(env), _alloc(alloc),
_dialog_generator(dialog_generator),
_runtime_config_generator(runtime_config_generator),
_target_user(target_user)
_target_user(target_user),
_ram_fs_state(child_states, "ram_fs")
{
_block_devices_rom .sigh(_storage_device_update_handler);
_usb_active_config_rom.sigh(_storage_device_update_handler);

View File

@ -16,9 +16,11 @@
/* Genode includes */
#include <input/event.h>
#include <util/xml_generator.h>
/* local includes */
#include "types.h"
#include <view/hoverable_item.h>
namespace Sculpt { struct Dialog; }
@ -33,7 +35,68 @@ struct Sculpt::Dialog : Interface
*/
struct Generator : Interface { virtual void generate_dialog() = 0; };
virtual void hover(Xml_node hover) = 0;
bool hovered = false;
enum class Click_result { CONSUMED, IGNORED };
enum class Clack_result { CONSUMED, IGNORED };
using Hover_result = Hoverable_item::Hover_result;
virtual void reset() = 0;
virtual Hover_result hover(Xml_node hover) = 0;
virtual void generate(Xml_generator &xml) const = 0;
static Hover_result any_hover_changed(Hover_result head)
{
return head;
}
template <typename... TAIL>
static Hover_result any_hover_changed(Hover_result head, TAIL... args)
{
if (head == Hover_result::CHANGED)
return Hover_result::CHANGED;
return any_hover_changed(args...);
}
Hover_result _match_sub_dialog(Xml_node node)
{
hovered = true;
return hover(node);
}
template <typename... TAIL>
Hover_result _match_sub_dialog(Xml_node hover, char const *sub_node,
TAIL &&... tail)
{
Hover_result result = Hover_result::UNMODIFIED;
hover.with_sub_node(sub_node, [&] (Xml_node sub_hover) {
if (_match_sub_dialog(sub_hover, tail...) == Hover_result::CHANGED)
result = Hover_result::CHANGED; });
return result;
}
template <typename... ARGS>
Hover_result match_sub_dialog(ARGS &&... args)
{
bool const orig_hovered = hovered;
hovered = false;
Hover_result const result = _match_sub_dialog(args...);
/* reset internal hover state of the dialog if no longer hovered */
if (orig_hovered && !hovered)
(void)this->hover(Xml_node("<empty/>"));
return result;
}
};
#endif /* _VIEW__DIALOG_H_ */

View File

@ -0,0 +1,381 @@
/*
* \brief File-browser dialog
* \author Norman Feske
* \date 2020-01-31
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__FILE_BROWSER_DIALOG_H_
#define _VIEW__FILE_BROWSER_DIALOG_H_
#include <view/dialog.h>
#include <model/runtime_config.h>
#include <model/file_browser_state.h>
namespace Sculpt { struct File_browser_dialog; }
struct Sculpt::File_browser_dialog : Noncopyable, Dialog
{
Runtime_config const &_runtime_config;
File_browser_state const &_state;
Hoverable_item _fs_button { };
Hoverable_item _entry { };
Hoverable_item _path_elem { };
Hoverable_item _action_button { };
void reset() override { }
using Fs_name = File_browser_state::Fs_name;
using Index = File_browser_state::Index;
using Sub_dir = File_browser_state::Path;
using Path = File_browser_state::Path;
using File = File_browser_state::Path;
struct Action : Interface, Noncopyable
{
virtual void browse_file_system(Fs_name const &) = 0;
virtual void browse_sub_directory(Sub_dir const &) = 0;
virtual void browse_abs_directory(Path const &) = 0;
virtual void browse_parent_directory() = 0;
virtual void view_file(File const &) = 0;
virtual void edit_file(File const &) = 0;
virtual void revert_edited_file() = 0;
virtual void save_edited_file() = 0;
};
using Name = String<128>;
template <typename FN>
void _for_each_path_elem(FN const &fn) const
{
char const *curr = _state.path.string();
fn(Path("/"));
for (;;) {
if (*curr != '/')
return;
curr++; /* skip '/' */
/* search next '/' */
size_t len = 0;
for (; curr[len] != 0 && curr[len] != '/'; len++);
fn(Path(Cstring(curr, len)));
curr += len;
}
}
Path _path_elem_at_index(unsigned index) const
{
Path result { };
unsigned i = 0;
_for_each_path_elem([&] (Path const &elem) {
if (i++ == index)
result = elem; });
return result;
}
void _gen_path_elements(Xml_generator &xml) const
{
gen_named_node(xml, "hbox", "back", [&] () {
unsigned i = 0;
_for_each_path_elem([&] (Path const elem) {
gen_named_node(xml, "button", Index(i), [&] () {
if (!_state.modified)
_path_elem.gen_hovered_attr(xml, Index(i));
xml.node("label", [&] () {
xml.attribute("text", elem);
});
});
i++;
});
});
}
void _gen_back_entry(Xml_generator &xml) const
{
gen_named_node(xml, "hbox", "back", [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
if (!_state.modified) {
gen_named_node(xml, "button", "button", [&] () {
xml.attribute("style", "back");
_entry.gen_hovered_attr(xml, "back");
xml.node("hbox", [&] () { });
});
}
_gen_path_elements(xml);
});
});
gen_named_node(xml, "hbox", "right", [&] () { });
});
}
void _gen_entry(Xml_generator &xml, Xml_node node, Index const &index,
char const *style) const
{
Name const name = node.attribute_value("name", Name());
bool const entry_edited = (name == _state.edited_file);
/* while editing one file, hide all others */
if (!entry_edited && _state.modified)
return;
gen_named_node(xml, "hbox", index, [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "button", "button", [&] () {
bool const selected = (name == _state.edited_file);
if (selected)
xml.attribute("selected", "yes");
xml.attribute("style", style);
if (!_state.modified)
_entry.gen_hovered_attr(xml, index);
xml.node("hbox", [&] () { });
});
gen_named_node(xml, "label", "name", [&] () {
xml.attribute("text", Path(" ", name)); });
});
});
gen_named_node(xml, "hbox", "middle", [&] () { });
gen_named_node(xml, "float", "right", [&] () {
xml.attribute("east", "yes");
/* show no operation buttons for directories */
if (node.type() == "dir")
return;
gen_named_node(xml, "hbox", "right", [&] () {
bool const entry_hovered = _entry.hovered(index);
bool const interesting = entry_hovered || entry_edited;
bool const writeable = node.attribute_value("writeable", false);
if (writeable) {
if (!_state.modified) {
gen_named_node(xml, "button", "edit", [&] () {
if (interesting) {
_action_button.gen_hovered_attr(xml, "edit");
if (entry_edited)
xml.attribute("selected", "yes");
} else {
xml.attribute("style", "invisible");
}
gen_named_node(xml, "label", "name", [&] () {
xml.attribute("text", "Edit");
if (!interesting)
xml.attribute("style", "invisible");
});
});
}
if (entry_edited && _state.modified) {
auto gen_action_button = [&] (auto id, auto text)
{
gen_named_node(xml, "button", id, [&] () {
_action_button.gen_hovered_attr(xml, id);
gen_named_node(xml, "label", "name", [&] () {
xml.attribute("text", text); }); });
};
gen_action_button("revert", "Revert");
gen_action_button("save", "Save");
}
} else {
gen_named_node(xml, "button", "view", [&] () {
if (interesting) {
_action_button.gen_hovered_attr(xml, "view");
if (entry_edited)
xml.attribute("selected", "yes");
} else {
xml.attribute("style", "invisible");
}
gen_named_node(xml, "label", "name", [&] () {
xml.attribute("text", "View");
if (!interesting)
xml.attribute("style", "invisible");
});
});
}
});
});
});
}
void _gen_file_system(Xml_generator &xml, Service const &service) const
{
bool const parent = !service.server.valid();
Label const name = parent ? Start_name(service.label) : service.server;
Start_name const pretty_name { Pretty(name) };
bool const selected = (_state.browsed_fs == name);
if (_state.text_area.constructed() && _state.modified && !selected)
return;
gen_named_node(xml, "frame", name, [&] () {
xml.node("vbox", [&] () {
xml.node("label", [&] () {
xml.attribute("min_ex", "50"); });
gen_named_node(xml, "button", name, [&] () {
if (!_state.modified)
_fs_button.gen_hovered_attr(xml, name);
if (selected)
xml.attribute("selected", true);
xml.node("label", [&] () {
xml.attribute("text", pretty_name);
xml.attribute("style", "title");
});
});
if (selected) {
unsigned cnt = 0;
_state.with_query_result([&] (Xml_node node) {
node.with_sub_node("dir", [&] (Xml_node listing) {
if (_state.path != "/")
_gen_back_entry(xml);
listing.for_each_sub_node("dir", [&] (Xml_node dir) {
_gen_entry(xml, dir, Index(cnt++), "enter"); });
listing.for_each_sub_node("file", [&] (Xml_node file) {
_gen_entry(xml, file, Index(cnt++), "radio"); });
});
});
}
});
});
}
void generate(Xml_generator &xml) const override
{
xml.node("vbox", [&] () {
_runtime_config.for_each_service([&] (Service const &service) {
if (service.type == Service::Type::FILE_SYSTEM)
_gen_file_system(xml, service); }); });
}
Hover_result hover(Xml_node hover) override
{
return any_hover_changed(
_entry.match(hover, "vbox", "frame", "vbox", "hbox", "name"),
_path_elem.match(hover, "vbox", "frame", "vbox", "hbox", "float", "hbox", "hbox", "button", "name"),
_fs_button.match(hover, "vbox", "frame", "vbox", "button", "name"),
_action_button.match(hover, "vbox", "frame", "vbox", "hbox", "float", "hbox", "button", "name"));
}
Click_result click(Action &action)
{
Click_result result = Click_result::IGNORED;
Fs_name const fs_name = _fs_button._hovered;
if (fs_name.length() > 1) {
if (!_state.modified)
action.browse_file_system(fs_name);
return Click_result::CONSUMED;
}
Index const path_elem_idx = _path_elem._hovered;
if (path_elem_idx.length() > 1) {
Genode::Path<256> abs_path { "/" };
for (unsigned i = 0; i < 20; i++) {
abs_path.append_element(_path_elem_at_index(i).string());
if (Index(i) == path_elem_idx)
break;
}
if (!_state.modified)
action.browse_abs_directory(Path(abs_path));
return Click_result::CONSUMED;
}
Index const index = _entry._hovered;
if (index == "back") {
if (!_state.modified)
action.browse_parent_directory();
}
else if (index.length() > 1) {
_state.with_entry_at_index(index, [&] (Xml_node entry) {
if (entry.has_type("dir"))
action.browse_sub_directory(entry.attribute_value("name", Sub_dir()));
if (entry.has_type("file")) {
if (_action_button.hovered("edit"))
action.edit_file(entry.attribute_value("name", Name()));
if (_action_button.hovered("view"))
action.view_file(entry.attribute_value("name", Name()));
if (_action_button.hovered("revert"))
action.revert_edited_file();
if (_action_button.hovered("save"))
action.save_edited_file();
}
});
return Click_result::CONSUMED;
}
return result;
}
File_browser_dialog(Runtime_config const &runtime_config,
File_browser_state const &state)
:
_runtime_config(runtime_config), _state(state)
{ }
};
#endif /* _VIEW__FILE_BROWSER_H_ */

View File

@ -0,0 +1,89 @@
/*
* \brief Common part of file-system management dialogs
* \author Norman Feske
* \date 2020-01-28
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__FS_DIALOG_H_
#define _VIEW__FS_DIALOG_H_
#include <view/dialog.h>
#include <model/storage_target.h>
namespace Sculpt { struct Fs_dialog; }
struct Sculpt::Fs_dialog : Noncopyable, Dialog
{
Storage_target const _target;
Storage_target const &_used_target;
Hoverable_item _inspect_item { };
Hoverable_item _use_item { };
Hover_result hover(Xml_node hover) override
{
return any_hover_changed(
_inspect_item.match(hover, "button", "name"),
_use_item .match(hover, "button", "name"));
}
void reset() override { }
struct Action : Interface
{
virtual void toggle_file_browser(Storage_target const &) = 0;
virtual void use(Storage_target const &) = 0;
};
void generate(Xml_generator &) const override { }
void generate(Xml_generator &xml, File_system const &file_system) const
{
xml.node("button", [&] () {
_inspect_item.gen_button_attr(xml, "browse");
if (file_system.inspected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
});
if (!_used_target.valid() || _used_target == _target) {
xml.node("button", [&] () {
_use_item.gen_button_attr(xml, "use");
if (_used_target == _target)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Use"); });
});
}
}
Click_result click(Action &action)
{
if (_inspect_item.hovered("browse"))
action.toggle_file_browser(_target);
else if (_use_item.hovered("use"))
action.use((_used_target == _target) ? Storage_target{ } : _target);
else return Click_result::IGNORED;
return Click_result::CONSUMED;
}
Fs_dialog(Storage_target target, Storage_target const &used_target)
:
_target(target), _used_target(used_target)
{ }
};
#endif /* _VIEW__FS_DIALOG_H_ */

View File

@ -26,17 +26,19 @@ struct Sculpt::Hoverable_item
Id _hovered { };
enum class Hover_result { CHANGED, UNMODIFIED };
/**
* Set ID to matching hover sub node name
*
* \return true if hovering changed
*/
template <typename... ARGS>
bool match(Xml_node hover, ARGS &&... args)
Hover_result match(Xml_node hover, ARGS &&... args)
{
Id const orig = _hovered;
_hovered = query_attribute<Id>(hover, args...);
return _hovered != orig;
return (_hovered != orig) ? Hover_result::CHANGED : Hover_result::UNMODIFIED;
}
/**

View File

@ -17,8 +17,10 @@
/* local includes */
#include "network_dialog.h"
void Sculpt::Network_dialog::_gen_access_point(Xml_generator &xml,
Access_point const &ap) const
using namespace Sculpt;
void Network_dialog::_gen_access_point(Xml_generator &xml,
Access_point const &ap) const
{
gen_named_node(xml, "hbox", ap.bssid, [&] () {
@ -59,7 +61,7 @@ void Sculpt::Network_dialog::_gen_access_point(Xml_generator &xml,
}
bool Sculpt::Network_dialog::_selected_ap_visible() const
bool Network_dialog::_selected_ap_visible() const
{
unsigned cnt = 0;
return _for_each_ap([&] (Access_point const &ap) {
@ -67,14 +69,14 @@ bool Sculpt::Network_dialog::_selected_ap_visible() const
}
bool Sculpt::Network_dialog::_selected_ap_unprotected() const
bool Network_dialog::_selected_ap_unprotected() const
{
return _for_each_ap([&] (Access_point const &ap) {
return _ap_item.selected(ap.bssid) && ap.unprotected(); });
}
bool Sculpt::Network_dialog::need_keyboard_focus_for_passphrase() const
bool Network_dialog::need_keyboard_focus_for_passphrase() const
{
if ( _wifi_connection.state == Wifi_connection::CONNECTED
|| _wifi_connection.state == Wifi_connection::CONNECTING)
@ -88,8 +90,8 @@ bool Sculpt::Network_dialog::need_keyboard_focus_for_passphrase() const
}
void Sculpt::Network_dialog::_gen_access_point_list(Xml_generator &xml,
bool auth_failure) const
void Network_dialog::_gen_access_point_list(Xml_generator &xml,
bool auth_failure) const
{
if (_wlan_config_policy == WLAN_CONFIG_MANUAL)
return;
@ -133,7 +135,11 @@ void Sculpt::Network_dialog::_gen_access_point_list(Xml_generator &xml,
xml.attribute("west", "yes");
xml.node("label", [&] () {
xml.attribute("font", "title/regular");
xml.attribute("text", String<3*64>(" ", _wpa_passphrase));
String<3*64> const passphrase(" ", _wpa_passphrase);
xml.attribute("text", passphrase);
xml.node("cursor", [&] () {
xml.attribute("at", passphrase.length() - 1);
});
});
});
});
@ -165,7 +171,7 @@ void Sculpt::Network_dialog::_gen_access_point_list(Xml_generator &xml,
}
void Sculpt::Network_dialog::_gen_connected_ap(Xml_generator &xml, bool connected) const
void Network_dialog::_gen_connected_ap(Xml_generator &xml, bool connected) const
{
bool done = false;
@ -196,14 +202,10 @@ void Sculpt::Network_dialog::_gen_connected_ap(Xml_generator &xml, bool connecte
}
void Sculpt::Network_dialog::generate(Xml_generator &xml) const
void Network_dialog::generate(Xml_generator &xml) const
{
gen_named_node(xml, "frame", "network", [&] () {
xml.node("vbox", [&] () {
gen_named_node(xml, "label", "title", [&] () {
xml.attribute("text", "Network");
xml.attribute("font", "title/regular");
});
gen_named_node(xml, "hbox", "type", [&] () {
@ -270,21 +272,20 @@ void Sculpt::Network_dialog::generate(Xml_generator &xml) const
}
void Sculpt::Network_dialog::hover(Xml_node hover)
Dialog::Hover_result Network_dialog::hover(Xml_node hover)
{
bool const changed =
_nic_item .match(hover, "vbox", "hbox", "button", "name") |
_ap_item .match(hover, "vbox", "frame", "vbox", "hbox", "name") |
_connect_item.match(hover, "vbox", "frame", "vbox", "button", "name");
Dialog::Hover_result const hover_result = Dialog::any_hover_changed(
_nic_item .match(hover, "frame", "vbox", "hbox", "button", "name"),
_ap_item .match(hover, "frame", "vbox", "frame", "vbox", "hbox", "name"),
_connect_item.match(hover, "frame", "vbox", "frame", "vbox", "button", "name"));
_nic_info.match(hover, "vbox", "frame", "name");
if (changed)
_dialog_generator.generate_dialog();
return hover_result;
}
void Sculpt::Network_dialog::click(Action &action)
void Network_dialog::click(Action &action)
{
if (_nic_item.hovered("off")) action.nic_target(Nic_target::OFF);
if (_nic_item.hovered("local")) action.nic_target(Nic_target::LOCAL);
@ -304,6 +305,5 @@ void Sculpt::Network_dialog::click(Action &action)
if (_connect_item.hovered("connect"))
action.wifi_connect(selected_ap());
_dialog_generator.generate_dialog();
}

View File

@ -14,24 +14,21 @@
#ifndef _VIEW__NETWORK_DIALOG_H_
#define _VIEW__NETWORK_DIALOG_H_
/* local includes */
#include <types.h>
#include <model/nic_target.h>
#include <model/nic_state.h>
#include <model/wifi_connection.h>
#include <model/wpa_passphrase.h>
#include <model/pci_info.h>
#include <view/dialog.h>
#include <view/selectable_item.h>
#include <view/dialog.h>
namespace Sculpt { struct Network_dialog; }
struct Sculpt::Network_dialog : Dialog
{
Env &_env;
Dialog::Generator &_dialog_generator;
enum Wlan_config_policy { WLAN_CONFIG_MANAGED, WLAN_CONFIG_MANUAL };
Nic_target const &_nic_target;
@ -76,15 +73,14 @@ struct Sculpt::Network_dialog : Dialog
void _gen_connected_ap(Xml_generator &, bool) const;
void _gen_access_point_list(Xml_generator &, bool) const;
void generate(Xml_generator &) const;
Hover_result hover(Xml_node) override;
void generate(Xml_generator &) const override;
void reset() override { }
bool need_keyboard_focus_for_passphrase() const;
/**
* Dialog interface
*/
void hover(Xml_node hover) override;
struct Action : Interface
{
virtual void nic_target(Nic_target::Type) = 0;
@ -96,9 +92,7 @@ struct Sculpt::Network_dialog : Dialog
void click(Action &action);
Network_dialog(Env &env,
Dialog::Generator &dialog_generator,
Nic_target const &nic_target,
Network_dialog(Nic_target const &nic_target,
Access_points const &access_points,
Wifi_connection const &wifi_connection,
Nic_state const &nic_state,
@ -106,7 +100,6 @@ struct Sculpt::Network_dialog : Dialog
Wlan_config_policy const &wlan_config_policy,
Pci_info const &pci_info)
:
_env(env), _dialog_generator(dialog_generator),
_nic_target(nic_target), _access_points(access_points),
_wifi_connection(wifi_connection), _nic_state(nic_state),
_wpa_passphrase(wpa_passphrase), _wlan_config_policy(wlan_config_policy),

View File

@ -0,0 +1,87 @@
/*
* \brief Panel dialog
* \author Norman Feske
* \date 2020-01-26
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#include <view/panel_dialog.h>
using namespace Sculpt;
void Panel_dialog::generate(Xml_generator &xml) const
{
xml.node("frame", [&] () {
xml.attribute("style", "unimportant");
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", true);
xml.node("hbox", [&] () {
xml.node("button", [&] () {
_item.gen_button_attr(xml, "settings");
if (_state.settings_visible())
xml.attribute("selected", true);
xml.node("label", [&] () {
xml.attribute("text", "Settings");
});
});
});
});
gen_named_node(xml, "float", "center", [&] () {
xml.node("hbox", [&] () {
auto gen_tab = [&] (auto name, auto text, Tab tab) {
gen_named_node(xml, "button", name, [&] () {
if (_state.selected_tab() == tab)
xml.attribute("selected", true);
else
_item.gen_hovered_attr(xml, name);
xml.node("label", [&] () {
xml.attribute("text", text);
});
});
};
gen_tab("files", "Files", Tab::FILES);
gen_tab("components", "Components", Tab::COMPONENTS);
if (_state.inspect_tab_visible())
gen_tab("inspect", "Inspect", Tab::INSPECT);
});
});
gen_named_node(xml, "float", "right", [&] () {
xml.attribute("east", true);
xml.node("hbox", [&] () {
xml.node("button", [&] () {
_item.gen_button_attr(xml, "network");
if (_state.network_visible())
xml.attribute("selected", true);
xml.node("label", [&] () {
xml.attribute("text", "Network");
});
});
xml.node("button", [&] () {
_item.gen_button_attr(xml, "log");
if (_state.log_visible())
xml.attribute("selected", true);
xml.node("label", [&] () {
xml.attribute("text", "Log");
});
});
});
});
});
}

View File

@ -0,0 +1,81 @@
/*
* \brief Panel dialog
* \author Norman Feske
* \date 2020-01-26
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__PANEL_DIALOG_H_
#define _VIEW__PANEL_DIALOG_H_
/* Genode includes */
#include <os/reporter.h>
/* local includes */
#include <types.h>
#include <view/dialog.h>
#include <view/activatable_item.h>
namespace Sculpt { struct Panel_dialog; }
struct Sculpt::Panel_dialog : Dialog
{
enum class Tab { FILES, COMPONENTS, INSPECT };
struct State : Interface, Noncopyable
{
virtual Tab selected_tab() const = 0;
virtual bool log_visible() const = 0;
virtual bool settings_visible() const = 0;
virtual bool network_visible() const = 0;
virtual bool inspect_tab_visible() const = 0;
};
State const &_state;
struct Action : Interface
{
virtual void select_tab(Tab) = 0;
virtual void toggle_log_visibility() = 0;
virtual void toggle_settings_visibility() = 0;
virtual void toggle_network_visibility() = 0;
};
Hoverable_item _item { };
Activatable_item _action_item { };
Hover_result hover(Xml_node hover) override
{
return any_hover_changed(
_item.match(hover, "frame", "float", "hbox", "button", "name"));
}
void generate(Xml_generator &) const override;
void click(Action &action)
{
if (_item.hovered("components")) action.select_tab(Tab::COMPONENTS);
if (_item.hovered("files")) action.select_tab(Tab::FILES);
if (_item.hovered("inspect")) action.select_tab(Tab::INSPECT);
if (_item.hovered("log")) action.toggle_log_visibility();
if (_item.hovered("settings")) action.toggle_settings_visibility();
if (_item.hovered("network")) action.toggle_network_visibility();
}
void reset() override
{
_item._hovered = Hoverable_item::Id();
_action_item.reset();
}
Panel_dialog(State const &state) : _state(state) { }
};
#endif /* _VIEW__PANEL_DIALOG_H_ */

View File

@ -0,0 +1,238 @@
/*
* \brief Partition management dialog
* \author Norman Feske
* \date 2020-01-29
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <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", "In progress..."); });
}
if (!target_in_use && !partition.format_in_progress && partition.checkable()
&& !relabel_in_progress) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "check");
xml.attribute("version", version);
if (partition.check_in_progress)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Check"); });
});
if (partition.check_in_progress)
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
}
}
bool const whole_device_with_partition_in_use =
whole_device && !device.all_partitions_idle();
bool const format_button_visible = !target_in_use
&& !whole_device_with_partition_in_use
&& !partition.check_in_progress
&& !expand_in_progress
&& !relabel_in_progress
&& !_operation_item.selected("expand");
bool const expand_button_visible = !target_in_use
&& !whole_device
&& !partition.check_in_progress
&& !partition.format_in_progress
&& !relabel_in_progress
&& partition.expandable()
&& !_operation_item.selected("format");
bool const progress_msg_visible =
(_operation_item.selected("format") && partition.format_in_progress)
|| (_operation_item.selected("expand") && partition.expand_in_progress());
bool const confirm_visible =
(_operation_item.selected("format") && !partition.format_in_progress)
|| (_operation_item.selected("expand") && !partition.expand_in_progress());
if (format_button_visible) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "format");
xml.attribute("version", version);
if (partition.format_in_progress)
xml.attribute("selected", "yes");
if (whole_device) {
xml.node("label", [&] () { xml.attribute("text", "Format device ..."); });
} else {
xml.node("label", [&] () { xml.attribute("text", "Format partition ..."); });
}
});
}
if (expand_button_visible) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "expand");
xml.attribute("version", version);
if (partition.expand_in_progress())
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Expand ..."); });
});
}
if (progress_msg_visible)
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
if (confirm_visible) {
xml.node("button", [&] () {
_confirm_item.gen_button_attr(xml, "confirm");
xml.attribute("version", version);
xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
});
}
}
Dialog::Hover_result Partition_dialog::hover(Xml_node hover)
{
Hover_result const hover_result = any_hover_changed(
_fs_dialog.hover(hover),
_relabel_item .match(hover, "button", "name"),
_operation_item.match(hover, "button", "name"),
_confirm_item .match(hover, "button", "name"));
return hover_result;
}
Dialog::Click_result Partition_dialog::click(Action &action)
{
if (_fs_dialog.click(action) == Click_result::CONSUMED)
return Click_result::CONSUMED;
if (_operation_item.hovered("format")) {
if (_operation_item.selected("format"))
action.cancel_format(_partition);
else
_operation_item.toggle_selection_on_click();
return Click_result::CONSUMED;
}
if (_operation_item.hovered("expand")) {
if (_operation_item.selected("expand"))
action.cancel_expand(_partition);
else
_operation_item.toggle_selection_on_click();
return Click_result::CONSUMED;
}
if (_operation_item.hovered("check")) {
action.check(_partition);
return Click_result::CONSUMED;
}
if (_relabel_item.hovered("relabel")) {
action.toggle_default_storage_target(_partition);
return Click_result::CONSUMED;
}
if (_confirm_item.hovered("confirm")) {
_confirm_item.propose_activation_on_click();
return Click_result::CONSUMED;
}
return Click_result::IGNORED;
}
Dialog::Clack_result Partition_dialog::clack(Action &action)
{
if (_confirm_item.hovered("confirm")) {
_confirm_item.confirm_activation_on_clack();
if (_confirm_item.activated("confirm")) {
if (_operation_item.selected("format")) {
action.format(_partition);
return Clack_result::CONSUMED;
}
if (_operation_item.selected("expand")) {
action.expand(_partition);
return Clack_result::CONSUMED;
}
}
} else {
_confirm_item.reset();
}
return Clack_result::IGNORED;
}

View File

@ -0,0 +1,77 @@
/*
* \brief Partition management dialog
* \author Norman Feske
* \date 2020-01-29
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__PARTITION_DIALOG_H_
#define _VIEW__PARTITION_DIALOG_H_
#include <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 : 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

@ -460,6 +460,4 @@ void Popup_dialog::click(Action &action)
}
}
}
generate();
}

View File

@ -33,12 +33,10 @@
namespace Sculpt { struct Popup_dialog; }
struct Sculpt::Popup_dialog
struct Sculpt::Popup_dialog : Dialog
{
Env &_env;
Allocator &_alloc;
Sculpt_version const _sculpt_version { _env };
Launchers const &_launchers;
@ -71,6 +69,13 @@ struct Sculpt::Popup_dialog
}
};
struct Refresh : Interface, Noncopyable
{
virtual void refresh_popup_dialog() = 0;
};
Refresh &_refresh;
struct Action : Interface
{
virtual void launch_global(Path const &launcher) = 0;
@ -103,20 +108,11 @@ struct Sculpt::Popup_dialog
Construction_info const &_construction_info;
Expanding_reporter _dialog_reporter { _env, "dialog", "popup_dialog" };
Attached_rom_dataspace _hover_rom { _env, "popup_view_hover" };
Signal_handler<Popup_dialog> _hover_handler {
_env.ep(), *this, &Popup_dialog::_handle_hover };
Hoverable_item _item { };
Activatable_item _action_item { };
Activatable_item _install_item { };
Hoverable_item _route_item { };
bool _hovered = false;
enum State { TOP_LEVEL, DEPOT_REQUESTED, DEPOT_SHOWN, DEPOT_SELECTION,
INDEX_REQUESTED, INDEX_SHOWN,
PKG_REQUESTED, PKG_SHOWN, ROUTE_SELECTED };
@ -190,26 +186,17 @@ struct Sculpt::Popup_dialog
Menu _menu { };
void _handle_hover()
Hover_result hover(Xml_node hover) override
{
_hover_rom.update();
Dialog::Hover_result const hover_result = Dialog::any_hover_changed(
_item .match(hover, "frame", "vbox", "hbox", "name"),
_action_item .match(hover, "frame", "vbox", "button", "name"),
_install_item.match(hover, "frame", "vbox", "float", "vbox", "float", "button", "name"),
_route_item .match(hover, "frame", "vbox", "frame", "vbox", "hbox", "name"));
Xml_node const hover = _hover_rom.xml();
_hovered = hover.has_sub_node("dialog");
bool const changed =
_item .match(hover, "dialog", "frame", "vbox", "hbox", "name") |
_action_item .match(hover, "dialog", "frame", "vbox", "button", "name") |
_install_item.match(hover, "dialog", "frame", "vbox", "float", "vbox", "float", "button", "name") |
_route_item .match(hover, "dialog", "frame", "vbox", "frame", "vbox", "hbox", "name");
if (changed)
generate();
return hover_result;
}
bool hovered() const { return _hovered; };
Attached_rom_dataspace _scan_rom { _env, "report -> runtime/depot_query/scan" };
Signal_handler<Popup_dialog> _scan_handler {
@ -223,7 +210,7 @@ struct Sculpt::Popup_dialog
_state = DEPOT_SHOWN;
if (_state != TOP_LEVEL)
generate();
_refresh.refresh_popup_dialog();
}
Attached_rom_dataspace _index_rom { _env, "report -> runtime/depot_query/index" };
@ -242,7 +229,7 @@ struct Sculpt::Popup_dialog
if (_state == INDEX_REQUESTED)
_state = INDEX_SHOWN;
generate();
_refresh.refresh_popup_dialog();
}
bool _index_avail(User const &user) const
@ -373,12 +360,11 @@ struct Sculpt::Popup_dialog
void _gen_pkg_elements (Xml_generator &, Component const &) const;
void _gen_menu_elements(Xml_generator &) const;
void generate()
void generate(Xml_generator &xml) const override
{
_dialog_reporter.generate([&] (Xml_generator &xml) {
xml.node("frame", [&] () {
xml.node("vbox", [&] () {
_gen_menu_elements(xml); }); }); });
xml.node("frame", [&] () {
xml.node("vbox", [&] () {
_gen_menu_elements(xml); }); });
}
void click(Action &action);
@ -397,25 +383,24 @@ struct Sculpt::Popup_dialog
_construction_info.with_construction([&] (Component const &component) {
action.trigger_download(component.path);
_install_item.reset();
generate();
_refresh.refresh_popup_dialog();
});
}
}
void reset()
void reset() override
{
_item._hovered = Hoverable_item::Id();
_route_item._hovered = Hoverable_item::Id();
_action_item.reset();
_install_item.reset();
_hovered = false;
_state = TOP_LEVEL;
_selected_user = User();
_selected_route.destruct();
_menu._level = 0;
}
Popup_dialog(Env &env, Allocator &alloc,
Popup_dialog(Env &env, Refresh &refresh,
Launchers const &launchers,
Nic_state const &nic_state,
Nic_target const &nic_target,
@ -425,17 +410,14 @@ struct Sculpt::Popup_dialog
Depot_query &depot_query,
Construction_info const &construction_info)
:
_env(env), _alloc(alloc), _launchers(launchers),
_env(env), _launchers(launchers),
_nic_state(nic_state), _nic_target(nic_target),
_runtime_info(runtime_info), _runtime_config(runtime_config),
_download_queue(download_queue), _depot_query(depot_query),
_construction_info(construction_info)
_refresh(refresh), _construction_info(construction_info)
{
_hover_rom.sigh(_hover_handler);
_scan_rom.sigh(_scan_handler);
_index_rom.sigh(_index_handler);
generate();
}
void gen_depot_query(Xml_generator &xml) const
@ -473,7 +455,7 @@ struct Sculpt::Popup_dialog
if (construction.blueprint_known && !_pkg_missing && !_pkg_rom_missing)
_state = PKG_SHOWN;
generate();
_refresh.refresh_popup_dialog();
}
bool interested_in_download() const

View File

@ -0,0 +1,119 @@
/*
* \brief RAM file-system management dialog
* \author Norman Feske
* \date 2020-01-28
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__RAM_FS_DIALOG_H_
#define _VIEW__RAM_FS_DIALOG_H_
#include <view/fs_dialog.h>
#include <model/ram_fs_state.h>
namespace Sculpt { struct Ram_fs_dialog; }
struct Sculpt::Ram_fs_dialog : Noncopyable, Dialog
{
Storage_target const &_used_target;
Storage_target const _target { "ram_fs", Partition::Number() };
Fs_dialog _fs_dialog;
Selectable_item _operation_item { };
Activatable_item _confirm_item { };
Hover_result hover(Xml_node hover) override
{
return any_hover_changed(
_fs_dialog.match_sub_dialog(hover),
_operation_item.match(hover, "button", "name"),
_confirm_item .match(hover, "button", "name"));
}
void reset() override
{
_operation_item.reset();
_confirm_item.reset();
}
struct Action : Interface, Noncopyable
{
virtual void reset_ram_fs() = 0;
};
void generate(Xml_generator &) const override { }
void generate(Xml_generator &xml, Ram_fs_state const &ram_fs_state) const
{
_fs_dialog.generate(xml, ram_fs_state);
if (!_used_target.ram_fs() && !ram_fs_state.inspected) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "reset");
xml.node("label", [&] () { xml.attribute("text", "Reset ..."); });
});
if (_operation_item.selected("reset")) {
xml.node("button", [&] () {
_confirm_item.gen_button_attr(xml, "confirm");
xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
});
}
}
}
Click_result click(Fs_dialog::Action &fs_action)
{
if (_fs_dialog.click(fs_action) == Click_result::CONSUMED)
return Click_result::CONSUMED;
/* toggle confirmation button when clicking on ram_fs reset */
else if (_operation_item.hovered("reset"))
_operation_item.toggle_selection_on_click();
else if (_confirm_item.hovered("confirm"))
_confirm_item.propose_activation_on_click();
else return Click_result::IGNORED;
return Click_result::CONSUMED;
}
Clack_result clack(Action &action)
{
if (_confirm_item.hovered("confirm")) {
_confirm_item.confirm_activation_on_clack();
if (_confirm_item.activated("confirm")) {
if (_operation_item.selected("reset")) {
action.reset_ram_fs();
_operation_item.reset();
_confirm_item.reset();
return Clack_result::CONSUMED;
}
}
} else {
_confirm_item.reset();
}
return Clack_result::IGNORED;
}
Ram_fs_dialog(Storage_target const &used_target)
:
_used_target(used_target), _fs_dialog(_target, used_target)
{ }
};
#endif /* _VIEW__RAM_FS_DIALOG_H_ */

View File

@ -0,0 +1,107 @@
/*
* \brief Settings dialog
* \author Norman Feske
* \date 2020-01-30
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__SETTINGS_DIALOG_H_
#define _VIEW__SETTINGS_DIALOG_H_
#include <view/dialog.h>
#include <model/settings.h>
namespace Sculpt { struct Settings_dialog; }
struct Sculpt::Settings_dialog : Noncopyable, Dialog
{
Font_size const &_current_font_size;
Hoverable_item _item { };
static Hoverable_item::Id _font_size_id(Font_size font_size)
{
switch (font_size) {
case Font_size::SMALL: return "small";
case Font_size::MEDIUM: return "medium";
case Font_size::LARGE: return "large";
}
return Hoverable_item::Id();
}
Hover_result hover(Xml_node hover) override
{
return any_hover_changed(
_item.match(hover, "frame", "vbox", "hbox", "button", "name"));
}
void reset() override { }
struct Action : Interface, Noncopyable
{
virtual void select_font_size(Font_size) = 0;
};
void generate(Xml_generator &xml) const override
{
gen_named_node(xml, "frame", "network", [&] () {
xml.node("vbox", [&] () {
gen_named_node(xml, "hbox", "font_size", [&] () {
gen_named_node(xml, "label", "label", [&] () {
xml.attribute("text", " Font size "); });
auto gen_font_size_button = [&] (Font_size font_size)
{
Label const label = _font_size_id(font_size);
gen_named_node(xml, "button", label, [&] () {
_item.gen_hovered_attr(xml, label);
if (font_size == _current_font_size)
xml.attribute("selected", true);
xml.node("label", [&] () {
xml.attribute("text", label); });
});
};
gen_font_size_button(Font_size::SMALL);
gen_font_size_button(Font_size::MEDIUM);
gen_font_size_button(Font_size::LARGE);
});
});
});
}
Click_result click(Action &action)
{
Click_result result = Click_result::IGNORED;
auto apply_font_size = [&] (Font_size font_size)
{
if (_item.hovered(_font_size_id(font_size))) {
action.select_font_size(font_size);
result = Click_result::CONSUMED;
}
};
apply_font_size(Font_size::SMALL);
apply_font_size(Font_size::MEDIUM);
apply_font_size(Font_size::LARGE);
return result;
}
Settings_dialog(Font_size const &current_font_size)
:
_current_font_size(current_font_size)
{ }
};
#endif /* _VIEW__RAM_FS_DIALOG_H_ */

View File

@ -0,0 +1,122 @@
/*
* \brief Storage-device management dialog
* \author Norman Feske
* \date 2018-04-30
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
/* local includes */
#include "storage_device_dialog.h"
using namespace Sculpt;
void Storage_device_dialog::_gen_partition(Xml_generator &xml,
Storage_device const &device,
Partition const &partition) const
{
bool const selected = _partition_item.selected(partition.number);
gen_named_node(xml, "hbox", partition.number, [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "button", "button", [&] () {
if (_partition_item.hovered(partition.number))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", partition.number); });
});
if (partition.label.length() > 1)
gen_named_node(xml, "label", "label", [&] () {
xml.attribute("text", String<80>(" (", partition.label, ") ")); });
Storage_target const target { device.label, partition.number };
if (_used_target == target)
gen_named_node(xml, "label", "used", [&] () { xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "right", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(partition.capacity, " ")); });
});
});
if (selected && _partition_dialog.constructed())
_partition_dialog->gen_operations(xml, device, partition);
}
void Storage_device_dialog::generate(Xml_generator &xml, Storage_device const &dev) const
{
xml.node("frame", [&] () {
xml.attribute("name", dev.label);
xml.attribute("style", "invisible");
xml.node("vbox", [&] () {
dev.partitions.for_each([&] (Partition const &partition) {
_gen_partition(xml, dev, partition); });
if (!_partition_item.any_selected() && _partition_dialog.constructed())
_partition_dialog->gen_operations(xml, dev, *dev.whole_device_partition);
});
});
}
Dialog::Hover_result Storage_device_dialog::hover(Xml_node hover)
{
Hover_result result = Hover_result::UNMODIFIED;
if (_partition_dialog.constructed() &&
_partition_dialog->match_sub_dialog(hover, "frame", "vbox") == Hover_result::CHANGED)
result = Hover_result::CHANGED;
return any_hover_changed(
result,
_partition_item.match(hover, "frame", "vbox", "hbox", "name"));
}
Dialog::Click_result Storage_device_dialog::click(Action &action)
{
Storage_target const orig_selected_target = _selected_storage_target();
_partition_item.toggle_selection_on_click();
if (_selected_storage_target() != orig_selected_target) {
_partition_dialog.construct(_selected_storage_target(),
_storage_devices, _used_target);
return Click_result::CONSUMED;
}
if (_partition_dialog.constructed())
return _partition_dialog->click(action);
return Click_result::IGNORED;
}
Dialog::Clack_result Storage_device_dialog::clack(Action &action)
{
if (_partition_dialog.constructed())
return _partition_dialog->clack(action);
return Clack_result::IGNORED;
}

View File

@ -0,0 +1,78 @@
/*
* \brief Storage-device management dialog
* \author Norman Feske
* \date 2020-01-29
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _VIEW__STORAGE_DEVICE_DIALOG_H_
#define _VIEW__STORAGE_DEVICE_DIALOG_H_
#include <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>
namespace Sculpt { struct Storage_device_dialog; }
struct Sculpt::Storage_device_dialog : Dialog
{
Storage_device::Label const _device;
Storage_devices const &_storage_devices;
Storage_target const &_used_target;
Selectable_item _partition_item { };
Reconstructible<Partition_dialog> _partition_dialog {
_selected_storage_target(), _storage_devices, _used_target };
void generate(Xml_generator &) const override { }
void _gen_partition(Xml_generator &, Storage_device const &, Partition const &) const;
void generate(Xml_generator &, Storage_device const &) const;
Hover_result hover(Xml_node hover) override;
using Action = Partition_dialog::Action;
Storage_target _selected_storage_target() const
{
Partition::Number partition = (_partition_item._selected == "")
? Partition::Number { }
: Partition::Number(_partition_item._selected);
return Storage_target { _device, partition };
}
void reset() override { }
void reset_operation()
{
if (_partition_dialog.constructed())
_partition_dialog->reset_operation();
}
Click_result click(Action &action);
Clack_result clack(Action &action);
Storage_device_dialog(Storage_device::Label const &device,
Storage_devices const &storage_devices,
Storage_target const &used)
:
_device(device),
_storage_devices(storage_devices),
_used_target(used)
{ }
};
#endif /* _VIEW__STORAGE_DEVICE_DIALOG_H_ */

View File

@ -17,213 +17,11 @@
/* local includes */
#include "storage_dialog.h"
void Sculpt::Storage_dialog::_gen_partition_operations(Xml_generator &xml,
Storage_device const &device,
Partition const &partition) const
{
Storage_target const target { device.label, partition.number };
String<16> const version(device.label, ".", partition.number);
bool const whole_device = !partition.number.valid();
bool const device_in_use = (_used_target.device == device.label);
bool const target_in_use = (_used_target == target)
|| (whole_device && device_in_use)
|| partition.file_system_inspected;
bool const relabel_in_progress = device.relabel_in_progress();
bool const expand_in_progress = device.expand_in_progress();
bool const format_selected = _operation_item.selected("format");
bool const expand_selected = _operation_item.selected("expand");
if (partition.file_system.accessible() && !format_selected
&& !expand_selected && !expand_in_progress) {
if (!partition.check_in_progress && !partition.format_in_progress
&& partition.file_system.accessible() && !relabel_in_progress) {
xml.node("button", [&] () {
_inspect_item.gen_button_attr(xml, "browse");
xml.attribute("version", version);
if (partition.file_system_inspected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
});
}
if ((!_used_target.valid() || _used_target == target)
&& !partition.check_in_progress && !partition.format_in_progress
&& !relabel_in_progress) {
xml.node("button", [&] () {
xml.attribute("version", version);
_use_item.gen_button_attr(xml, "use");
if (_used_target == target)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Use"); });
});
}
if ((device.all_partitions_idle() || partition.relabel_in_progress())
&& partition.genode() && !device_in_use) {
xml.node("button", [&] () {
/* support hovering only if no relabeling is in progress */
if (partition.relabel_in_progress())
xml.attribute("name", "relabel");
else
_relabel_item.gen_button_attr(xml, "relabel");
xml.attribute("version", version);
if (partition.genode_default() || partition.relabel_in_progress())
xml.attribute("selected", "yes");
xml.node("label", [&] () {
xml.attribute("text", "Default"); });
});
if (partition.relabel_in_progress())
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
}
if (!target_in_use && !partition.format_in_progress && partition.checkable()
&& !relabel_in_progress) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "check");
xml.attribute("version", version);
if (partition.check_in_progress)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Check"); });
});
if (partition.check_in_progress)
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
}
}
bool const whole_device_with_partition_in_use =
whole_device && !device.all_partitions_idle();
bool const format_button_visible = !target_in_use
&& !whole_device_with_partition_in_use
&& !partition.check_in_progress
&& !expand_in_progress
&& !relabel_in_progress
&& !_operation_item.selected("expand");
bool const expand_button_visible = !target_in_use
&& !whole_device
&& !partition.check_in_progress
&& !partition.format_in_progress
&& !relabel_in_progress
&& partition.expandable()
&& !_operation_item.selected("format");
bool const progress_msg_visible =
(_operation_item.selected("format") && partition.format_in_progress)
|| (_operation_item.selected("expand") && partition.expand_in_progress());
bool const confirm_visible =
(_operation_item.selected("format") && !partition.format_in_progress)
|| (_operation_item.selected("expand") && !partition.expand_in_progress());
if (format_button_visible) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "format");
xml.attribute("version", version);
if (partition.format_in_progress)
xml.attribute("selected", "yes");
if (whole_device) {
xml.node("label", [&] () { xml.attribute("text", "Format device ..."); });
} else {
xml.node("label", [&] () { xml.attribute("text", "Format partition ..."); });
}
});
}
if (expand_button_visible) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "expand");
xml.attribute("version", version);
if (partition.expand_in_progress())
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Expand ..."); });
});
}
if (progress_msg_visible)
xml.node("label", [&] () { xml.attribute("text", "In progress..."); });
if (confirm_visible) {
xml.node("button", [&] () {
_confirm_item.gen_button_attr(xml, "confirm");
xml.attribute("version", version);
xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
});
}
}
using namespace Sculpt;
void Sculpt::Storage_dialog::_gen_partition(Xml_generator &xml,
Storage_device const &device,
Partition const &partition) const
{
bool const selected = _partition_item.selected(partition.number);
gen_named_node(xml, "hbox", partition.number, [&] () {
gen_named_node(xml, "float", "left", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "button", "button", [&] () {
if (_partition_item.hovered(partition.number))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", partition.number); });
});
if (partition.label.length() > 1)
gen_named_node(xml, "label", "label", [&] () {
xml.attribute("text", String<80>(" (", partition.label, ") ")); });
Storage_target const target { device.label, partition.number };
if (_used_target == target)
gen_named_node(xml, "label", "used", [&] () { xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "right", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
xml.attribute("text", String<64>(partition.capacity, " ")); });
});
});
if (selected)
_gen_partition_operations(xml, device, partition);
}
void Sculpt::Storage_dialog::_gen_block_device(Xml_generator &xml,
Block_device const &dev) const
void Storage_dialog::_gen_block_device(Xml_generator &xml,
Block_device const &dev) const
{
bool const selected = _device_item.selected(dev.label);
@ -257,23 +55,13 @@ void Sculpt::Storage_dialog::_gen_block_device(Xml_generator &xml,
});
});
if (selected) {
xml.node("frame", [&] () {
xml.attribute("name", dev.label);
xml.node("vbox", [&] () {
dev.partitions.for_each([&] (Partition const &partition) {
_gen_partition(xml, dev, partition); });
if (!_partition_item.any_selected())
_gen_partition_operations(xml, dev, *dev.whole_device_partition);
});
});
}
if (_storage_device_dialog.constructed() && selected)
_storage_device_dialog->generate(xml, dev);
}
void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &xml,
Usb_storage_device const &dev) const
void Storage_dialog::_gen_usb_storage_device(Xml_generator &xml,
Usb_storage_device const &dev) const
{
bool const discarded = dev.discarded();
bool const selected = !discarded && _device_item.selected(dev.label);
@ -290,9 +78,7 @@ void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &x
xml.node("hbox", [&] () {
gen_named_node(xml, "float", "info", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "label", "device", [&] () {
xml.attribute("text", dev.label); });
@ -309,7 +95,8 @@ void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &x
});
typedef String<64> Info;
Info const info = dev.discarded() ? Info("unsupported") : Info(dev.capacity);
Info const info = dev.discarded() ? Info(" unsupported")
: Info(" ", dev.capacity);
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
@ -318,224 +105,68 @@ void Sculpt::Storage_dialog::_gen_usb_storage_device(Xml_generator &x
});
});
if (selected)
xml.node("frame", [&] () {
xml.attribute("name", dev.label);
xml.node("vbox", [&] () {
dev.partitions.for_each([&] (Partition const &partition) {
_gen_partition(xml, dev, partition); });
if (!_partition_item.any_selected())
_gen_partition_operations(xml, dev, *dev.whole_device_partition);
});
});
if (_storage_device_dialog.constructed() && selected)
_storage_device_dialog->generate(xml, dev);
}
void Sculpt::Storage_dialog::_gen_ram_fs(Xml_generator &xml) const
void Storage_dialog::gen_block_devices(Xml_generator &xml) const
{
bool const selected = _device_item.selected("ram_fs");
gen_named_node(xml, "button", "ram_fs", [&] () {
if (_device_item.hovered("ram_fs"))
xml.attribute("hovered", "yes");
if (selected)
xml.attribute("selected", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "float", "info", [&] () {
xml.attribute("west", "yes");
xml.node("hbox", [&] () {
gen_named_node(xml, "label", "device", [&] () {
xml.attribute("text", "ram (in-memory file system) "); });
if (_used_target.device == "ram_fs")
gen_named_node(xml, "label", "used", [&] () {
xml.attribute("text", "* "); });
});
});
gen_named_node(xml, "float", "capacity", [&] () {
xml.attribute("east", "yes");
xml.node("label", [&] () {
Capacity const capacity { _ram_fs_state.ram_quota().value };
xml.attribute("text", String<64>(capacity)); }); });
});
});
if (selected) {
xml.node("frame", [&] () {
xml.attribute("name", "ram_fs_operations");
xml.node("vbox", [&] () {
xml.node("button", [&] () {
_inspect_item.gen_button_attr(xml, "browse");
if (_ram_fs_state.inspected)
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Inspect"); });
});
if (!_used_target.valid() || _used_target.ram_fs()) {
xml.node("button", [&] () {
_use_item.gen_button_attr(xml, "use");
if (_used_target.ram_fs())
xml.attribute("selected", "yes");
xml.node("label", [&] () { xml.attribute("text", "Use"); });
});
}
if (!_used_target.ram_fs() && !_ram_fs_state.inspected) {
xml.node("button", [&] () {
_operation_item.gen_button_attr(xml, "reset");
xml.node("label", [&] () { xml.attribute("text", "Reset ..."); });
});
if (_operation_item.selected("reset")) {
xml.node("button", [&] () {
_confirm_item.gen_button_attr(xml, "confirm");
xml.node("label", [&] () { xml.attribute("text", "Confirm"); });
});
}
}
});
});
}
_storage_devices.block_devices.for_each([&] (Block_device const &dev) {
_gen_block_device(xml, dev); });
}
void Sculpt::Storage_dialog::generate(Xml_generator &xml, bool expanded) const
void Storage_dialog::gen_usb_storage_devices(Xml_generator &xml) const
{
gen_named_node(xml, "frame", "storage", [&] () {
xml.node("vbox", [&] () {
gen_named_node(xml, "label", "title", [&] () {
xml.attribute("text", "Storage");
xml.attribute("font", "title/regular");
});
if (!expanded)
return;
_storage_devices.block_devices.for_each([&] (Block_device const &dev) {
_gen_block_device(xml, dev); });
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
_gen_usb_storage_device(xml, dev); });
_gen_ram_fs(xml);
});
});
_storage_devices.usb_storage_devices.for_each([&] (Usb_storage_device const &dev) {
_gen_usb_storage_device(xml, dev); });
}
void Sculpt::Storage_dialog::hover(Xml_node hover)
Dialog::Hover_result Storage_dialog::hover(Xml_node hover)
{
bool const changed =
_device_item .match(hover, "vbox", "button", "name") |
_partition_item.match(hover, "vbox", "frame", "vbox", "hbox", "name") |
_use_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
_relabel_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
_inspect_item .match(hover, "vbox", "frame", "vbox", "button", "name") |
_operation_item.match(hover, "vbox", "frame", "vbox", "button", "name") |
_confirm_item .match(hover, "vbox", "frame", "vbox", "button", "name");
Hover_result result = Hover_result::UNMODIFIED;
if (changed)
_dialog_generator.generate_dialog();
if (_storage_device_dialog.constructed() &&
_storage_device_dialog->hover(hover) == Hover_result::CHANGED)
result = Hover_result::CHANGED;
return any_hover_changed(result, _device_item.match(hover, "button", "name"));
}
void Sculpt::Storage_dialog::click(Action &action)
Dialog::Click_result Storage_dialog::click(Action &action)
{
Selectable_item::Id const old_selected_device = _device_item._selected;
Selectable_item::Id const old_selected_partition = _partition_item._selected;
Selectable_item::Id const old_selected_device = _device_item._selected;
_device_item.toggle_selection_on_click();
_partition_item.toggle_selection_on_click();
if (!_device_item.selected(old_selected_device))
_partition_item.reset();
if (old_selected_device != _device_item._selected) {
if (!_device_item.selected(old_selected_device)
|| !_partition_item.selected(old_selected_partition))
reset_operation();
Storage_target const target = _selected_storage_target();
if (_operation_item.hovered("format")) {
if (_operation_item.selected("format"))
action.cancel_format(_selected_storage_target());
else
_operation_item.toggle_selection_on_click();
_storage_device_dialog.destruct();
_storage_device_dialog.conditional(_device_item.any_selected(),
_device_item._selected,
_storage_devices, _used_target);
return Click_result::CONSUMED;
}
if (_operation_item.hovered("expand")) {
if (_operation_item.selected("expand"))
action.cancel_expand(_selected_storage_target());
else
_operation_item.toggle_selection_on_click();
if (_storage_device_dialog.constructed()
&& _storage_device_dialog->click(action) == Click_result::CONSUMED) {
return Click_result::CONSUMED;
}
/* toggle confirmation button when clicking on ram_fs reset */
if (_operation_item.hovered("reset"))
_operation_item.toggle_selection_on_click();
if (_operation_item.hovered("check"))
action.check(target);
/* toggle file browser */
if (_inspect_item.hovered("browse"))
action.toggle_file_browser(target);
if (_use_item.hovered("use")) {
/* release currently used device */
if (target.valid() && target == _used_target)
action.use(Storage_target{});
/* select new used device if none is defined */
else if (!_used_target.valid())
action.use(target);
}
if (_relabel_item.hovered("relabel"))
action.toggle_default_storage_target(target);
if (_confirm_item.hovered("confirm")) {
_confirm_item.propose_activation_on_click();
}
_dialog_generator.generate_dialog();
return Click_result::IGNORED;
}
void Sculpt::Storage_dialog::clack(Action &action)
Dialog::Clack_result Storage_dialog::clack(Action &action)
{
if (_confirm_item.hovered("confirm")) {
if (_storage_device_dialog.constructed()
&& _storage_device_dialog->clack(action) == Clack_result::CONSUMED)
return Clack_result::CONSUMED;
_confirm_item.confirm_activation_on_clack();
if (_confirm_item.activated("confirm")) {
Storage_target const target = _selected_storage_target();
if (_operation_item.selected("format"))
action.format(target);
if (_operation_item.selected("expand"))
action.expand(target);
if (target.ram_fs() && _operation_item.selected("reset"))
action.reset_ram_fs();
}
} else {
_confirm_item.reset();
}
_dialog_generator.generate_dialog();
return Clack_result::IGNORED;
}

View File

@ -17,98 +17,51 @@
#include <types.h>
#include <model/storage_devices.h>
#include <model/storage_target.h>
#include <model/ram_fs_state.h>
#include <view/selectable_item.h>
#include <view/activatable_item.h>
#include <view/dialog.h>
#include <view/storage_device_dialog.h>
namespace Sculpt { struct Storage_dialog; }
struct Sculpt::Storage_dialog : Dialog
{
Env &_env;
Dialog::Generator &_dialog_generator;
Storage_devices const &_storage_devices;
Ram_fs_state const &_ram_fs_state;
Selectable_item _device_item { };
Selectable_item _partition_item { };
Hoverable_item _use_item { };
Hoverable_item _relabel_item { };
Hoverable_item _inspect_item { };
Selectable_item _operation_item { };
Activatable_item _confirm_item { };
void generate(Xml_generator &, bool expanded) const;
void _gen_block_device(Xml_generator &, Block_device const &) const;
void _gen_partition(Xml_generator &, Storage_device const &, Partition const &) const;
void _gen_partition_operations(Xml_generator &, Storage_device const &, Partition const &) const;
void _gen_usb_storage_device(Xml_generator &, Usb_storage_device const &) const;
void _gen_ram_fs(Xml_generator &) const;
void hover(Xml_node hover) override;
Selectable_item _device_item { };
Storage_target const &_used_target;
struct Action : Interface
{
virtual void format(Storage_target const &) = 0;
Constructible<Storage_device_dialog> _storage_device_dialog { };
virtual void cancel_format(Storage_target const &) = 0;
void _gen_block_device (Xml_generator &, Block_device const &) const;
void _gen_usb_storage_device(Xml_generator &, Usb_storage_device const &) const;
virtual void expand(Storage_target const &) = 0;
void generate(Xml_generator &) const override { };
virtual void cancel_expand(Storage_target const &) = 0;
void gen_block_devices (Xml_generator &) const;
void gen_usb_storage_devices(Xml_generator &) const;
virtual void check(Storage_target const &) = 0;
Hover_result hover(Xml_node hover) override;
virtual void toggle_file_browser(Storage_target const &) = 0;
using Action = Storage_device_dialog::Action;
virtual void toggle_default_storage_target(Storage_target const &) = 0;
virtual void use(Storage_target const &) = 0;
virtual void reset_ram_fs() = 0;
};
Storage_target _selected_storage_target() const
{
Partition::Number partition = (_partition_item._selected == "")
? Partition::Number { }
: Partition::Number(_partition_item._selected);
return Storage_target { _device_item._selected, partition };
}
void reset() override { }
void reset_operation()
{
_operation_item.reset();
_confirm_item.reset();
_dialog_generator.generate_dialog();
if (_storage_device_dialog.constructed())
_storage_device_dialog->reset_operation();
}
void click(Action &action);
Click_result click(Action &);
Clack_result clack(Action &);
void clack(Action &action);
Storage_dialog(Env &env, Dialog::Generator &dialog_generator,
Storage_devices const &storage_devices,
Ram_fs_state const &ram_fs_state, Storage_target const &used)
Storage_dialog(Storage_devices const &storage_devices,
Storage_target const &used)
:
_env(env), _dialog_generator(dialog_generator),
_storage_devices(storage_devices), _ram_fs_state(ram_fs_state),
_storage_devices(storage_devices),
_used_target(used)
{ }
};
#endif /* _STORAGE_DIALOG_H_ */
#endif /* _VIEW__STORAGE_DIALOG_H_ */