From 43d51c4499e68e46ddf651855852432a12edf33a Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Thu, 27 Apr 2023 17:39:13 +0200 Subject: [PATCH] sculpt: refine keyboard entry of new depot URL This patch includes the system dialog in the global keyboard focus handling, supports hovering of the "Edit" and "Add" buttons, allows the use of the enter key to finish URL editing, and triggers a re-scan of depot users after adding a new one. Issue #4820 --- .../src/app/sculpt_manager/keyboard_focus.h | 17 ++++++-- repos/gems/src/app/sculpt_manager/main.cc | 36 +++++++++++++++-- .../app/sculpt_manager/model/download_queue.h | 1 + .../sculpt_manager/model/index_update_queue.h | 1 + .../sculpt_manager/view/depot_users_dialog.h | 40 +++++++++++++------ 5 files changed, 76 insertions(+), 19 deletions(-) diff --git a/repos/gems/src/app/sculpt_manager/keyboard_focus.h b/repos/gems/src/app/sculpt_manager/keyboard_focus.h index 3720dfdfa0..32ab961c3a 100644 --- a/repos/gems/src/app/sculpt_manager/keyboard_focus.h +++ b/repos/gems/src/app/sculpt_manager/keyboard_focus.h @@ -22,18 +22,21 @@ #include #include #include +#include namespace Sculpt { struct Keyboard_focus; } struct Sculpt::Keyboard_focus { - enum Target { INITIAL, WPA_PASSPHRASE, WM } target { INITIAL }; + enum Target { INITIAL, WPA_PASSPHRASE, SYSTEM_DIALOG, WM } target { INITIAL }; Expanding_reporter _focus_reporter; Network_dialog const &_network_dialog; Wpa_passphrase &_wpa_passphrase; Panel_dialog::State const &_panel; + System_dialog const &_system_dialog; + bool const &_system_visible; void update() { @@ -44,6 +47,9 @@ struct Sculpt::Keyboard_focus if (_panel.network_visible() && _network_dialog.need_keyboard_focus_for_passphrase()) target = WPA_PASSPHRASE; + if (_system_dialog.keyboard_needed() && _system_visible) + target = SYSTEM_DIALOG; + if (orig_target == target) return; @@ -54,6 +60,7 @@ struct Sculpt::Keyboard_focus switch (target) { case WPA_PASSPHRASE: + case SYSTEM_DIALOG: xml.attribute("label", "manager -> input"); break; @@ -68,12 +75,16 @@ struct Sculpt::Keyboard_focus Keyboard_focus(Env &env, Network_dialog const &network_dialog, Wpa_passphrase &wpa_passphrase, - Panel_dialog::State const &panel) + Panel_dialog::State const &panel, + System_dialog const &system_dialog, + bool const &system_visible) : _focus_reporter(env, "focus", "focus"), _network_dialog(network_dialog), _wpa_passphrase(wpa_passphrase), - _panel(panel) + _panel(panel), + _system_dialog(system_dialog), + _system_visible(system_visible) { update(); } diff --git a/repos/gems/src/app/sculpt_manager/main.cc b/repos/gems/src/app/sculpt_manager/main.cc index b4f58f6b36..556c34c057 100644 --- a/repos/gems/src/app/sculpt_manager/main.cc +++ b/repos/gems/src/app/sculpt_manager/main.cc @@ -672,7 +672,8 @@ struct Sculpt::Main : Input_event_handler, _try_handle_click(); } - Keyboard_focus _keyboard_focus { _env, _network.dialog, _network.wpa_passphrase, *this }; + Keyboard_focus _keyboard_focus { _env, _network.dialog, _network.wpa_passphrase, + *this, _system_dialog, _system_visible }; Constructible _clicked_seq_number { }; Constructible _clacked_seq_number { }; @@ -784,11 +785,34 @@ struct Sculpt::Main : Input_event_handler, } } + bool _keyboard_input_consumed_by_sculpt_manager() const + { + return (_keyboard_focus.target == Keyboard_focus::WPA_PASSPHRASE) + || (_system_visible && _system_dialog.keyboard_needed()); + } + + struct Keyboard_focus_guard + { + Main &_main; + + bool const _orig = _main._keyboard_input_consumed_by_sculpt_manager(); + + Keyboard_focus_guard(Main &main) : _main(main) { } + + ~Keyboard_focus_guard() + { + if (_orig != _main._keyboard_input_consumed_by_sculpt_manager()) + _main._keyboard_focus.update(); + } + }; + /** * Menu_view::Hover_update_handler interface */ void menu_view_hover_updated() override { + Keyboard_focus_guard focus_guard { *this }; + if (_clicked_seq_number.constructed()) _try_handle_click(); @@ -803,6 +827,8 @@ struct Sculpt::Main : Input_event_handler, { bool need_generate_dialog = false; + Keyboard_focus_guard focus_guard { *this }; + if (ev.key_press(Input::BTN_LEFT) || ev.touch()) { _clicked_seq_number.construct(_global_input_seq_number); _try_handle_click(); @@ -822,9 +848,6 @@ struct Sculpt::Main : Input_event_handler, need_generate_dialog = true; }); - if (ev.press()) - _keyboard_focus.update(); - if (need_generate_dialog) generate_dialog(); } @@ -1710,6 +1733,7 @@ void Sculpt::Main::_handle_window_layout() /* define window-manager focus */ _wm_focus.generate([&] (Xml_generator &xml) { + _window_list.xml().for_each_sub_node("window", [&] (Xml_node win) { Label const label = win.attribute_value("label", Label()); @@ -1988,6 +2012,10 @@ void Sculpt::Main::_handle_runtime_state() if (_index_update_queue.download_count != orig_download_count) _deploy.update_installation(); + /* update depot-user selection after adding new depot URL */ + if (_system_visible) + trigger_depot_query(); + /* * The removal of an index file may have completed, re-query index * files to reflect this change at the depot selection menu. diff --git a/repos/gems/src/app/sculpt_manager/model/download_queue.h b/repos/gems/src/app/sculpt_manager/model/download_queue.h index 3abe016a21..e8b0f38910 100644 --- a/repos/gems/src/app/sculpt_manager/model/download_queue.h +++ b/repos/gems/src/app/sculpt_manager/model/download_queue.h @@ -14,6 +14,7 @@ #ifndef _MODEL__DOWNLOAD_QUEUE_H_ #define _MODEL__DOWNLOAD_QUEUE_H_ +#include #include #include diff --git a/repos/gems/src/app/sculpt_manager/model/index_update_queue.h b/repos/gems/src/app/sculpt_manager/model/index_update_queue.h index e467888621..ec0d5d0395 100644 --- a/repos/gems/src/app/sculpt_manager/model/index_update_queue.h +++ b/repos/gems/src/app/sculpt_manager/model/index_update_queue.h @@ -19,6 +19,7 @@ #define _MODEL__INDEX_UPDATE_QUEUE_H_ #include +#include #include namespace Sculpt { struct Index_update_queue; } diff --git a/repos/gems/src/app/sculpt_manager/view/depot_users_dialog.h b/repos/gems/src/app/sculpt_manager/view/depot_users_dialog.h index 50864d6f85..3ea5996151 100644 --- a/repos/gems/src/app/sculpt_manager/view/depot_users_dialog.h +++ b/repos/gems/src/app/sculpt_manager/view/depot_users_dialog.h @@ -49,6 +49,8 @@ struct Sculpt::Depot_users_dialog bool _unfolded = false; + bool _selected_user_exists = false; + Hoverable_item _user { }; Hoverable_item _button { }; @@ -124,8 +126,9 @@ struct Sculpt::Depot_users_dialog bool const selected = (name == _selected); Url const url = _url(user); Url const label = Depot_url::from_string(url).valid() ? url : Url(name); + bool const show_all = _unfolded || !_selected_user_exists; - if (!selected && !_unfolded) + if (!selected && !show_all) return; _gen_item(xml, name, @@ -133,7 +136,7 @@ struct Sculpt::Depot_users_dialog [&] /* right */ { } ); - if (_unfolded && !last) + if (show_all && !last) _gen_vspacer(xml, String<64>("below ", name).string()); } @@ -173,6 +176,9 @@ struct Sculpt::Depot_users_dialog gen_named_node(xml, "button", "add", [&] { if (!url_valid) xml.attribute("style", "unimportant"); + else + _button.gen_hovered_attr(xml, "add"); + xml.node("label", [&] { if (!url_valid) xml.attribute("style", "unimportant"); @@ -180,6 +186,7 @@ struct Sculpt::Depot_users_dialog }); } else { gen_named_node(xml, "button", "edit", [&] { + _button.gen_hovered_attr(xml, "edit"); xml.node("label", [&] { xml.attribute("text", "Edit"); }); }); } @@ -208,12 +215,12 @@ struct Sculpt::Depot_users_dialog bool const last = (--remain_count == 0); _gen_entry(xml, user, last); }); - if (_unfolded) + if (_unfolded || !_selected_user_exists) _gen_add_entry(xml, depot_users); }); }); - if (!_unfolded && !known_pubkey) { + if (!_unfolded && !known_pubkey && _selected_user_exists) { gen_named_node(xml, "button", "pubkey warning", [&] { xml.attribute("style", "invisible"); xml.node("label", [&] { @@ -240,7 +247,7 @@ struct Sculpt::Depot_users_dialog void generate(Xml_generator &xml) const { _gen_selection(xml); } - bool unfolded() const { return _unfolded; } + bool unfolded() const { return _unfolded || !_selected_user_exists; } struct User_properties { @@ -280,6 +287,7 @@ struct Sculpt::Depot_users_dialog _selected = user; select_fn(user); _unfolded = false; + _selected_user_exists = true; _url_edit_field = _orig_edit_url; }; @@ -324,6 +332,19 @@ struct Sculpt::Depot_users_dialog if (c.value == ' ' || c.value == '"') return; + /* respond to enter key */ + if (c.value == 10) { + Depot_url const depot_url = _depot_url(_depot_users.xml()); + if (depot_url.valid()) { + _action.add_depot_url(depot_url); + _selected = depot_url.user; + _selected_user_exists = true; + _unfolded = false; + _url_edit_field = _orig_edit_url; + } + return; + } + _url_edit_field.apply(c); } @@ -335,16 +356,11 @@ struct Sculpt::Depot_users_dialog * If the selected depot user does not exist in the depot, show * list of available users. */ - bool selected_user_exists = false; + _selected_user_exists = false; _depot_users.xml().for_each_sub_node([&] (Xml_node const &user) { if (_selected == user.attribute_value("name", User())) - selected_user_exists = true; }); - - if (!selected_user_exists) { - _selected = _default_user; - _unfolded = true; - } + _selected_user_exists = true; }); } };