From d185e756ed3e908d15066fd0df950d756812ae7d Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 00:36:21 +0500 Subject: [PATCH 01/13] #86 WIP: Introduce action=TerminalToggleMaximize --- doc/apps.md | 2 ++ doc/settings.md | 2 ++ src/netxs/desktopio/terminal.hpp | 1 + src/vtm.xml | 1 + 4 files changed, 6 insertions(+) diff --git a/doc/apps.md b/doc/apps.md index 434cfbddf9..f354a225fa 100644 --- a/doc/apps.md +++ b/doc/apps.md @@ -191,6 +191,7 @@ TerminalToggleCwdSync | x | TerminalToggleWrapMode | x | | Toggle terminal scrollback lines wrapping mode. Applied to the active selection if it is. The argument is boolean. TerminalToggleSelectionMode | x | | Toggle between linear(0) and rectangular(1) selection form. TerminalToggleFullscreen | x | | Toggle fullscreen mode. +TerminalToggleMaximize | x | | Toggle between maximized and normal window size. TerminalToggleStdioLog | x | | Stdin/stdout log toggle. TerminalQuit | | | Terminate runnning console apps and close terminal. TerminalRestart | | | Terminate runnning console apps and restart current session. @@ -331,6 +332,7 @@ TerminalSelectionOneShot | | + diff --git a/doc/settings.md b/doc/settings.md index 4b7c3dc786..03b225c02f 100644 --- a/doc/settings.md +++ b/doc/settings.md @@ -359,6 +359,7 @@ Action | Default key combination | Available at level `TerminalToggleWrapMode` | | Application | Toggle terminal scrollback lines wrapping mode. Applied to the active selection if it is. `TerminalToggleSelectionMode` | | Application | Toggle between linear and rectangular selection form. `TerminalToggleFullscreen` | | Application | Toggle fullscreen mode. +`TerminalToggleMaximize` | | Application | Toggle between maximized and normal window size. `TerminalToggleStdioLog` | | Application | Stdin/stdout log toggle. `TerminalQuit` | | Application | Terminate runnning console apps and close terminal. `TerminalRestart` | | Application | Terminate runnning console apps and restart current session. @@ -805,6 +806,7 @@ Notes + diff --git a/src/netxs/desktopio/terminal.hpp b/src/netxs/desktopio/terminal.hpp index 513f02520e..70cf1953c7 100644 --- a/src/netxs/desktopio/terminal.hpp +++ b/src/netxs/desktopio/terminal.hpp @@ -7735,6 +7735,7 @@ namespace netxs::ui chords.proc("TerminalQuit", [&](hids& gear){ gear.set_handled(); exec_cmd(commands::ui::sighup); }); chords.proc("TerminalRestart", [&](hids& gear){ gear.set_handled(); exec_cmd(commands::ui::restart); }); chords.proc("TerminalToggleFullscreen", [&](hids& gear){ gear.set_handled(); base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); + chords.proc("TerminalToggleMaximize", [&](hids& gear){ gear.set_handled(); base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); chords.proc("TerminalUndo", [&](hids& gear){ gear.set_handled(); exec_cmd(commands::ui::undo); }); chords.proc("TerminalRedo", [&](hids& gear){ gear.set_handled(); exec_cmd(commands::ui::redo); }); chords.proc("TerminalClipboardPaste", [&](hids& gear){ gear.set_handled(); paste(gear); }); diff --git a/src/vtm.xml b/src/vtm.xml index a3ee06da87..b35883f48a 100644 --- a/src/vtm.xml +++ b/src/vtm.xml @@ -415,6 +415,7 @@ R"==( + From 1edab56a6289e1a02ec5eb03dfb461c496bc635e Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 09:46:13 +0500 Subject: [PATCH 02/13] Add action=TerminalToggleMaximize. Rename TerminalFullscreen to TerminalToggleFullscreen --- doc/apps.md | 5 +++-- src/netxs/apps/term.hpp | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/doc/apps.md b/doc/apps.md index f354a225fa..adf7c0224c 100644 --- a/doc/apps.md +++ b/doc/apps.md @@ -124,7 +124,8 @@ TerminalOutput | x | Direct output the `data=` value TerminalSendKey | x | Simulating keypresses using the `data=` string. TerminalQuit | | Terminate runnning console apps and close terminal. TerminalRestart | | Terminate runnning console apps and restart current session. -TerminalFullscreen | | Toggle fullscreen mode. +TerminalToggleFullscreen | | Toggle fullscreen mode. +TerminalToggleMaximize | | Toggle between maximized and normal window size. TerminalUndo | | (Win32 Cooked/ENABLE_LINE_INPUT mode only) Discard the last input. TerminalRedo | | (Win32 Cooked/ENABLE_LINE_INPUT mode only) Discard the last Undo command. TerminalClipboardPaste | | Paste from clipboard. @@ -280,7 +281,7 @@ TerminalSelectionOneShot | | - + diff --git a/src/netxs/apps/term.hpp b/src/netxs/apps/term.hpp index 7f38b22344..3a3e38a0b8 100644 --- a/src/netxs/apps/term.hpp +++ b/src/netxs/apps/term.hpp @@ -206,7 +206,8 @@ namespace netxs::app::terminal X(Noop ) /* */ \ X(TerminalQuit ) /* */ \ X(TerminalCwdSync ) /* */ \ - X(TerminalFullscreen ) /* */ \ + X(TerminalToggleFullscreen ) /* */ \ + X(TerminalToggleMaximize ) /* */ \ X(TerminalRestart ) /* */ \ X(TerminalSendKey ) /* */ \ X(TerminalWrapMode ) /* */ \ @@ -342,13 +343,20 @@ namespace netxs::app::terminal boss.bell::signal(tier::anycast, terminal::events::cmd, ui::term::commands::ui::commands::sighup); }); } - static void TerminalFullscreen(ui::item& boss, menu::item& item) + static void TerminalToggleFullscreen(ui::item& boss, menu::item& item) { _submit(boss, item, [](auto& boss, auto& /*item*/, auto& gear) { boss.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); } + static void TerminalToggleMaximize(ui::item& boss, menu::item& item) + { + _submit(boss, item, [](auto& boss, auto& /*item*/, auto& gear) + { + boss.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); + }); + } static void TerminalRestart(ui::item& boss, menu::item& item) { _submit(boss, item, [](auto& boss, auto& /*item*/, auto& /*gear*/) From 0f513df54d83881de46cadf546244d533a2a7d32 Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 10:01:31 +0500 Subject: [PATCH 03/13] Add Maximize/Fullscreen toggle to info-page (F11/F12) --- src/netxs/apps.hpp | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/netxs/apps.hpp b/src/netxs/apps.hpp index 8e9252a013..83db8725de 100644 --- a/src/netxs/apps.hpp +++ b/src/netxs/apps.hpp @@ -776,22 +776,30 @@ namespace netxs::app::shared keybd.template bind( "Esc", "WindowClosePreview"); keybd.template bind("-Esc", "WindowClose"); keybd.template bind( "Any", "UpdateChordPreview"); - keybd.proc("ScrollPageUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0, 1 }}); } }); - keybd.proc("ScrollPageDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0,-1 }}); } }); - keybd.proc("ScrollLineUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0, 3 }}); } }); - keybd.proc("ScrollLineDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0,-3 }}); } }); - keybd.proc("ScrollCharLeft" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = { 3, 0 }}); } }); - keybd.proc("ScrollCharRight", [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = {-3, 0 }}); } }); - keybd.proc("ScrollTop" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_top::y); } }); - keybd.proc("ScrollEnd" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_end::y); } }); - keybd.bind("PageUp" , "ScrollPageUp" ); - keybd.bind("PageDown" , "ScrollPageDown" ); - keybd.bind("UpArrow" , "ScrollLineUp" ); - keybd.bind("DownArrow" , "ScrollLineDown" ); - keybd.bind("LeftArrow" , "ScrollCharLeft" ); - keybd.bind("RightArrow", "ScrollCharRight"); - keybd.bind("Home" , "ScrollTop" ); - keybd.bind("End" , "ScrollEnd" ); + keybd.proc("ScrollPageUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0, 1 }}); } }); + keybd.proc("ScrollPageDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0,-1 }}); } }); + keybd.proc("ScrollLineUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0, 3 }}); } }); + keybd.proc("ScrollLineDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0,-3 }}); } }); + keybd.proc("ScrollCharLeft" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = { 3, 0 }}); } }); + keybd.proc("ScrollCharRight" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = {-3, 0 }}); } }); + keybd.proc("ScrollTop" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_top::y); } }); + keybd.proc("ScrollEnd" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_end::y); } }); + keybd.proc("ToogleMaximize" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); } }); + keybd.proc("ToogleFullscreen", [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); } }); + keybd.bind("PageUp" , "ScrollPageUp" ); + keybd.bind("PageDown" , "ScrollPageDown" ); + keybd.bind("UpArrow" , "ScrollLineUp" ); + keybd.bind("DownArrow" , "ScrollLineDown" ); + keybd.bind("LeftArrow" , "ScrollCharLeft" ); + keybd.bind("RightArrow", "ScrollCharRight" ); + keybd.bind("Home" , "DropIfRepeats" ); + keybd.bind("Home" , "ScrollTop" ); + keybd.bind("End" , "DropIfRepeats" ); + keybd.bind("End" , "ScrollEnd" ); + keybd.bind("F11" , "DropIfRepeats" ); + keybd.bind("F11" , "ToogleMaximize" ); + keybd.bind("F12" , "DropIfRepeats" ); + keybd.bind("F12" , "ToogleFullscreen"); }); inside->attach(slot::_2, ui::post::ctor()) ->limits({ -1, 1 }) From 495e6e8f38d811027b0353f4f35f46ff7253d3d3 Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:31:21 +0500 Subject: [PATCH 04/13] Fix window focus after fullscreen --- src/netxs/apps.hpp | 4 ++-- src/netxs/apps/desk.hpp | 2 +- src/netxs/desktopio/controls.hpp | 8 ++++++++ src/netxs/desktopio/terminal.hpp | 4 ++-- src/vtm.hpp | 12 ++++++++---- 5 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/netxs/apps.hpp b/src/netxs/apps.hpp index 83db8725de..f9656a8dfa 100644 --- a/src/netxs/apps.hpp +++ b/src/netxs/apps.hpp @@ -784,8 +784,8 @@ namespace netxs::app::shared keybd.proc("ScrollCharRight" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = {-3, 0 }}); } }); keybd.proc("ScrollTop" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_top::y); } }); keybd.proc("ScrollEnd" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_end::y); } }); - keybd.proc("ToogleMaximize" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); } }); - keybd.proc("ToogleFullscreen", [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); } }); + keybd.proc("ToogleMaximize" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); }}); // Refocus-related operations require execution outside of keyboard events. + keybd.proc("ToogleFullscreen", [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); }}); keybd.bind("PageUp" , "ScrollPageUp" ); keybd.bind("PageDown" , "ScrollPageDown" ); keybd.bind("UpArrow" , "ScrollLineUp" ); diff --git a/src/netxs/apps/desk.hpp b/src/netxs/apps/desk.hpp index b5479c97c1..38858a50d2 100644 --- a/src/netxs/apps/desk.hpp +++ b/src/netxs/apps/desk.hpp @@ -550,7 +550,7 @@ namespace netxs::app::desk { auto appid = "info"s; auto label = "Info"s; - auto title = ansi::jet(bias::right).add(label); + auto title = ansi::add(label); auto ground = background(appid, label, title); // It can't be a child - it has exclusive rendering (first of all). boss.LISTEN(tier::release, e2::form::upon::vtree::attached, parent_ptr, -, (size_config_ptr/*owns ptr*/, ground, current_default = text{}, previous_default = text{}, selected = text{ menu_selected }, usrcfg)) { diff --git a/src/netxs/desktopio/controls.hpp b/src/netxs/desktopio/controls.hpp index 982c2833da..6fadc215e3 100644 --- a/src/netxs/desktopio/controls.hpp +++ b/src/netxs/desktopio/controls.hpp @@ -1279,6 +1279,14 @@ namespace netxs::ui //if constexpr (debugmode) log(prompt::foci, "Full defocus item:", item_ptr->id); return gear_id_list; } + // pro::focus: Defocus all gears except specified. + static auto one(sptr item_ptr, id_t gear_id) + { + auto gear_id_list = item_ptr->base::riseup(tier::request, e2::form::state::keybd::enlist); + std::erase_if(gear_id_list, [&](auto& id){ return gear_id == id; }); + pro::focus::off(item_ptr, gear_id_list); + //if constexpr (debugmode) log(prompt::foci, "Full defocus item:", item_ptr->id); + } static auto get(sptr item_ptr, bool remove_default = faux) { auto gear_id_list = item_ptr->base::riseup(tier::request, e2::form::state::keybd::enlist); diff --git a/src/netxs/desktopio/terminal.hpp b/src/netxs/desktopio/terminal.hpp index 70cf1953c7..c77e962436 100644 --- a/src/netxs/desktopio/terminal.hpp +++ b/src/netxs/desktopio/terminal.hpp @@ -7734,8 +7734,8 @@ namespace netxs::ui chords.proc("TerminalToggleWrapMode", [&](hids& gear){ gear.set_handled(); exec_cmd(commands::ui::togglewrp); }); chords.proc("TerminalQuit", [&](hids& gear){ gear.set_handled(); exec_cmd(commands::ui::sighup); }); chords.proc("TerminalRestart", [&](hids& gear){ gear.set_handled(); exec_cmd(commands::ui::restart); }); - chords.proc("TerminalToggleFullscreen", [&](hids& gear){ gear.set_handled(); base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); - chords.proc("TerminalToggleMaximize", [&](hids& gear){ gear.set_handled(); base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); + chords.proc("TerminalToggleFullscreen", [&](hids& gear){ gear.set_handled(); bell::enqueue(This(), [&](auto& /*boss*/){ base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); }); // Refocus-related operations require execution outside of keyboard events. + chords.proc("TerminalToggleMaximize", [&](hids& gear){ gear.set_handled(); bell::enqueue(This(), [&](auto& /*boss*/){ base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); }); chords.proc("TerminalUndo", [&](hids& gear){ gear.set_handled(); exec_cmd(commands::ui::undo); }); chords.proc("TerminalRedo", [&](hids& gear){ gear.set_handled(); exec_cmd(commands::ui::redo); }); chords.proc("TerminalClipboardPaste", [&](hids& gear){ gear.set_handled(); paste(gear); }); diff --git a/src/vtm.hpp b/src/vtm.hpp index af9220402a..eb5fef2e28 100644 --- a/src/vtm.hpp +++ b/src/vtm.hpp @@ -1404,15 +1404,18 @@ namespace netxs::app::vtm what_copy.applet = {}; boss.LISTEN(tier::preview, e2::form::size::enlarge::fullscreen, gear, -, (what_copy, maximize_token_ptr, saved_area_ptr, viewport_area_ptr)) { + auto window_ptr = boss.This(); if (maximize_token) // Restore maximized window. { - boss.bell::signal(tier::release, e2::form::size::restore, boss.This()); + boss.bell::signal(tier::release, e2::form::size::restore, window_ptr); } - auto window_ptr = boss.This(); - auto gear_id_list = pro::focus::get(window_ptr, true); // Expropriate all foci. + pro::focus::one(window_ptr, gear.id); // Drop all unrelated foci. auto what = what_copy; what.applet = window_ptr; - pro::focus::set(window_ptr, gear.id, pro::focus::solo::on, pro::focus::flip::off, true); // Refocus. + boss.bell::enqueue(boss.This(), [&](auto& /*boss*/) + { + pro::focus::set(boss.This(), gear.id, pro::focus::solo::on, pro::focus::flip::off, true); // Refocus to demultifocus. + }); window_ptr->base::riseup(tier::request, e2::form::prop::ui::header, what.header); window_ptr->base::riseup(tier::request, e2::form::prop::ui::footer, what.footer); gear.owner.bell::signal(tier::release, vtm::events::gate::fullscreen, what); @@ -1463,6 +1466,7 @@ namespace netxs::app::vtm } else { + boss.base::riseup(tier::preview, e2::form::layout::expose); // Multiple windows coubld be maximized at the same time. pro::focus::set(window_ptr, gear.id, pro::focus::solo::on, pro::focus::flip::off, true); auto owner_id = gear.owner.id; saved_area = boss.base::area(); From 94cdb14c6e80a5effe00d0465c07d7d9026b911b Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 12:35:28 +0500 Subject: [PATCH 05/13] Typo --- src/netxs/apps.hpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/netxs/apps.hpp b/src/netxs/apps.hpp index f9656a8dfa..db444a7b59 100644 --- a/src/netxs/apps.hpp +++ b/src/netxs/apps.hpp @@ -784,8 +784,8 @@ namespace netxs::app::shared keybd.proc("ScrollCharRight" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = {-3, 0 }}); } }); keybd.proc("ScrollTop" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_top::y); } }); keybd.proc("ScrollEnd" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_end::y); } }); - keybd.proc("ToogleMaximize" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); }}); // Refocus-related operations require execution outside of keyboard events. - keybd.proc("ToogleFullscreen", [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); }}); + keybd.proc("ToggleMaximize" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); }}); // Refocus-related operations require execution outside of keyboard events. + keybd.proc("ToggleFullscreen", [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); }}); keybd.bind("PageUp" , "ScrollPageUp" ); keybd.bind("PageDown" , "ScrollPageDown" ); keybd.bind("UpArrow" , "ScrollLineUp" ); @@ -797,9 +797,10 @@ namespace netxs::app::shared keybd.bind("End" , "DropIfRepeats" ); keybd.bind("End" , "ScrollEnd" ); keybd.bind("F11" , "DropIfRepeats" ); - keybd.bind("F11" , "ToogleMaximize" ); + keybd.bind("F11" , "ToggleMaximize" ); keybd.bind("F12" , "DropIfRepeats" ); - keybd.bind("F12" , "ToogleFullscreen"); + keybd.bind("F12" , "ToggleFullscreen"); + //keybd.bind("Ctrl-Alt" , "ToggleExclusiveKeybd"); }); inside->attach(slot::_2, ui::post::ctor()) ->limits({ -1, 1 }) From 6d1f125db54369305b47721f61fa38030117a183 Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:43:50 +0500 Subject: [PATCH 06/13] #86 WIP: Introduce action=ToggleExclusiveKeybd --- doc/apps.md | 13 +++++--- doc/settings.md | 21 +++++++++++++ src/netxs/apps.hpp | 52 +++++++++++++++++--------------- src/netxs/desktopio/terminal.hpp | 1 + src/vtm.xml | 2 ++ 5 files changed, 60 insertions(+), 29 deletions(-) diff --git a/doc/apps.md b/doc/apps.md index adf7c0224c..1b147795dc 100644 --- a/doc/apps.md +++ b/doc/apps.md @@ -171,6 +171,9 @@ The list of hotkey actions is slightly different from the list of window menu ac Value | Unique for hotkeys | Default Hotkey | Description -----------------------------|--------------------|------------------------------|------------ +Drop | | | Drop all events for the specified key combination. No further processing. +DropIfRepeats | | | Drop `Key Repeat` events for the specified key combination. This binding should be specified before the main action for the key combination. +ToggleExclusiveKeybd | x | `Ctrl-Alt`, `Alt-Ctrl` | Toggle exclusive keyboard mode. In exclusive mode, all keyboard events are ignored by higher levels. TerminalFindNext | | `Alt+RightArrow` | Highlight next match of selected text fragment. Clipboard content is used if no active selection. TerminalFindPrev | | `Alt+LeftArrow` | Highlight previous match of selected text fragment. Clipboard content is used if no active selection. TerminalViewportOnePageUp | x | `Shift+Ctrl+PageUp` | Scroll one page up. @@ -189,17 +192,17 @@ TerminalClipboardWipe | | TerminalUndo | | | (Win32 Cooked/ENABLE_LINE_INPUT mode only) Discard the last input. TerminalRedo | | | (Win32 Cooked/ENABLE_LINE_INPUT mode only) Discard the last Undo command. TerminalToggleCwdSync | x | | Toggle the current working directory sync mode. -TerminalToggleWrapMode | x | | Toggle terminal scrollback lines wrapping mode. Applied to the active selection if it is. The argument is boolean. -TerminalToggleSelectionMode | x | | Toggle between linear(0) and rectangular(1) selection form. +TerminalToggleWrapMode | x | | Toggle terminal scrollback lines wrapping mode. Applied to the active selection if it is. +TerminalToggleSelectionMode | x | | Toggle between linear and rectangular selection form. TerminalToggleFullscreen | x | | Toggle fullscreen mode. TerminalToggleMaximize | x | | Toggle between maximized and normal window size. TerminalToggleStdioLog | x | | Stdin/stdout log toggle. TerminalQuit | | | Terminate runnning console apps and close terminal. TerminalRestart | | | Terminate runnning console apps and restart current session. -TerminalSwitchCopyMode | x | | Set terminal text selection mode. The argument can be the one of the following values 0:'none', 1:'text', 2:'ansi', 3:'rich', 4:'html', 5:'protected'. +TerminalSwitchCopyMode | x | | Switch terminal text selection mode. TerminalSelectionCopy | | | Сopy selection to clipboard. TerminalSelectionCancel | | `Esc` | Deselect a selection. -TerminalSelectionOneShot | | | One-shot toggle to copy text while mouse tracking is active. Keep selection if `Ctrl` key is pressed.
The `data=` attribute can have the following values `none`, `text`, `ansi`, `rich`, `html`, `protected`. +TerminalSelectionOneShot | | | One-shot toggle to copy text while mouse tracking is active. Keep selection if `Ctrl` key is pressed. #### Terminal configuration example ```xml @@ -341,6 +344,8 @@ TerminalSelectionOneShot | | + + diff --git a/doc/settings.md b/doc/settings.md index 03b225c02f..29174243c0 100644 --- a/doc/settings.md +++ b/doc/settings.md @@ -310,6 +310,24 @@ Tag | Value `key` | The text string containing the key combination. `action` | The action name. +The following joiners are allowed for combining keys: + +Joiner | Meaning +-------|-------- +`+` | The subsequent key is in pressed state. +`-` | The subsequent key is in released state. This joiner is allowed for the last key only. + +Key combinations can be of the following types: + +Type | Example |Description +------------|------------------------|----------- +`Generic` | `Ctrl+A` | A generic key combination without distinction left/right and numpad. +`Literal` | `Alt+'a'` | A generic key combination without distinction left/right and numpad, except for the last key represented as a single-quoted character/string generated by the key. +`Specific` | `LeftShift+RightShift` | A key combination with explicitly specified physical keys. +`Scancodes` | `0x3B+0x3C` | A key combination represented solely by scan codes of physical keys in hexadecimal format. + +Generic, literal and specific key sequences can be mixed in any order. + The required key combination sequence can be generated on the Info page, accessible by clicking on the label in the lower right corner of the vtm desktop. #### Interpretation @@ -327,6 +345,7 @@ Action | Default key combination | Available at level -------------------------------|--------------------------|---------------------|------------ `Drop` | | All levels | Drop all events for the specified key combination. No further processing. `DropIfRepeats` | | All levels | Drop `Key Repeat` events for the specified key combination. This binding should be specified before the main action for the key combination. +`ToggleExclusiveKeybd` | `Ctrl-Alt`, `Alt-Ctrl` | Application | Toggle exclusive keyboard mode. In exclusive mode, all keyboard events are ignored by higher levels. `IncreaseCellHeight` | `CapsLock+UpArrow` | Native GUI window | Increase the text cell height by one pixel. `DecreaseCellHeight` | `CapsLock+DownArrow` | Native GUI window | Decrease the text cell height by one pixel. `ResetCellHeight` | `Ctrl+Key0` | Native GUI window | Reset text cell height. @@ -814,6 +833,8 @@ Notes + + diff --git a/src/netxs/apps.hpp b/src/netxs/apps.hpp index db444a7b59..cc85836627 100644 --- a/src/netxs/apps.hpp +++ b/src/netxs/apps.hpp @@ -776,31 +776,33 @@ namespace netxs::app::shared keybd.template bind( "Esc", "WindowClosePreview"); keybd.template bind("-Esc", "WindowClose"); keybd.template bind( "Any", "UpdateChordPreview"); - keybd.proc("ScrollPageUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0, 1 }}); } }); - keybd.proc("ScrollPageDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0,-1 }}); } }); - keybd.proc("ScrollLineUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0, 3 }}); } }); - keybd.proc("ScrollLineDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0,-3 }}); } }); - keybd.proc("ScrollCharLeft" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = { 3, 0 }}); } }); - keybd.proc("ScrollCharRight" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = {-3, 0 }}); } }); - keybd.proc("ScrollTop" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_top::y); } }); - keybd.proc("ScrollEnd" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_end::y); } }); - keybd.proc("ToggleMaximize" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); }}); // Refocus-related operations require execution outside of keyboard events. - keybd.proc("ToggleFullscreen", [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); }}); - keybd.bind("PageUp" , "ScrollPageUp" ); - keybd.bind("PageDown" , "ScrollPageDown" ); - keybd.bind("UpArrow" , "ScrollLineUp" ); - keybd.bind("DownArrow" , "ScrollLineDown" ); - keybd.bind("LeftArrow" , "ScrollCharLeft" ); - keybd.bind("RightArrow", "ScrollCharRight" ); - keybd.bind("Home" , "DropIfRepeats" ); - keybd.bind("Home" , "ScrollTop" ); - keybd.bind("End" , "DropIfRepeats" ); - keybd.bind("End" , "ScrollEnd" ); - keybd.bind("F11" , "DropIfRepeats" ); - keybd.bind("F11" , "ToggleMaximize" ); - keybd.bind("F12" , "DropIfRepeats" ); - keybd.bind("F12" , "ToggleFullscreen"); - //keybd.bind("Ctrl-Alt" , "ToggleExclusiveKeybd"); + keybd.proc("ScrollPageUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0, 1 }}); } }); + keybd.proc("ScrollPageDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0,-1 }}); } }); + keybd.proc("ScrollLineUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0, 3 }}); } }); + keybd.proc("ScrollLineDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0,-3 }}); } }); + keybd.proc("ScrollCharLeft" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = { 3, 0 }}); } }); + keybd.proc("ScrollCharRight" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = {-3, 0 }}); } }); + keybd.proc("ScrollTop" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_top::y); } }); + keybd.proc("ScrollEnd" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_end::y); } }); + keybd.proc("ToggleMaximize" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); }}); // Refocus-related operations require execution outside of keyboard events. + keybd.proc("ToggleFullscreen" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); }}); + keybd.proc("ToggleExclusiveKeybd", [&](hids& gear){ if (!gear.is_exclusive()) gear.set_exclusive(boss.This()); else gear.set_exclusive(); }); + keybd.bind("PageUp" , "ScrollPageUp" ); + keybd.bind("PageDown" , "ScrollPageDown" ); + keybd.bind("UpArrow" , "ScrollLineUp" ); + keybd.bind("DownArrow" , "ScrollLineDown" ); + keybd.bind("LeftArrow" , "ScrollCharLeft" ); + keybd.bind("RightArrow", "ScrollCharRight" ); + keybd.bind("Home" , "DropIfRepeats" ); + keybd.bind("Home" , "ScrollTop" ); + keybd.bind("End" , "DropIfRepeats" ); + keybd.bind("End" , "ScrollEnd" ); + keybd.bind("F11" , "DropIfRepeats" ); + keybd.bind("F11" , "ToggleMaximize" ); + keybd.bind("F12" , "DropIfRepeats" ); + keybd.bind("F12" , "ToggleFullscreen" ); + keybd.bind("Ctrl-Alt" , "ToggleExclusiveKeybd"); + keybd.bind("Alt-Ctrl" , "ToggleExclusiveKeybd"); }); inside->attach(slot::_2, ui::post::ctor()) ->limits({ -1, 1 }) diff --git a/src/netxs/desktopio/terminal.hpp b/src/netxs/desktopio/terminal.hpp index c77e962436..6b22e88427 100644 --- a/src/netxs/desktopio/terminal.hpp +++ b/src/netxs/desktopio/terminal.hpp @@ -7746,6 +7746,7 @@ namespace netxs::ui chords.proc("TerminalSelectionOneShot", [&](hids& gear){ gear.set_handled(); set_oneshot(mime::textonly); }); chords.proc("TerminalViewportCopy", [&](hids& gear){ gear.set_handled(); prnscrn(gear); }); chords.proc("TerminalToggleStdioLog", [&](hids& gear){ gear.set_handled(); set_log(!io_log); ondata(); }); + chords.proc("ToggleExclusiveKeybd", [&](hids& gear){ if (!gear.is_exclusive()) gear.set_exclusive(This()); else gear.set_exclusive(); }); chords.load(xml_config, "/config/term/hotkeys/key"); LISTEN(tier::general, e2::timer::tick, timestamp) // Update before world rendering. diff --git a/src/vtm.xml b/src/vtm.xml index b35883f48a..afae9259b9 100644 --- a/src/vtm.xml +++ b/src/vtm.xml @@ -423,6 +423,8 @@ R"==( + + From be68aaafe142c523849fb8379392b2331437c0aa Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 14:37:20 +0500 Subject: [PATCH 07/13] #86 WIP: Generalize keyboard navigation --- src/netxs/apps.hpp | 60 +++++------------------------ src/netxs/apps/calc.hpp | 7 +++- src/netxs/apps/shop.hpp | 7 +++- src/netxs/apps/test.hpp | 8 +++- src/netxs/apps/text.hpp | 7 +++- src/netxs/desktopio/application.hpp | 55 +++++++++++++++++++++++++- 6 files changed, 87 insertions(+), 57 deletions(-) diff --git a/src/netxs/apps.hpp b/src/netxs/apps.hpp index cc85836627..477eea5eae 100644 --- a/src/netxs/apps.hpp +++ b/src/netxs/apps.hpp @@ -235,7 +235,7 @@ namespace netxs::app::shared auto window = ui::cake::ctor(); window->plugin(pro::focus::mode::focused) - //->plugin() + ->plugin() //->plugin() ->plugin() ->invoke([](auto& boss) @@ -257,6 +257,11 @@ namespace netxs::app::shared auto sb = layers->attach(ui::fork::ctor()); auto vt = sb->attach(slot::_2, ui::grip::ctor(scroll)); auto hz = test_stat_area->attach(slot::_2, ui::grip::ctor(scroll)); + window->invoke([&](auto& boss) + { + auto& keybd = boss.template plugins(); + app::shared::base_kb_navigation(keybd, scroll, boss); + }); return window; }; @@ -544,7 +549,7 @@ namespace netxs::app::shared { menu::item{ menu::item::type::Command, true, 0, std::vector{{ .label = "×", .notes = " Close ", .hover = c1 }}}, [window, c1](auto& boss, auto& /*item*/) { - boss.shader(cell::shaders::color(c1), e2::form::state::keybd::command::close, window); + boss.shader(cell::shaders::color(c1), e2::form::state::keybd::command::close, boss.This()); boss.LISTEN(tier::release, hids::events::mouse::button::click::left, gear) { auto backup = boss.This(); @@ -749,60 +754,13 @@ namespace netxs::app::shared window->invoke([&](auto& boss) { auto& items_inst = *items; - auto& scroll_inst = *scroll; - auto esc_pressed = ptr::shared(faux); auto& keybd = boss.template plugins(); - keybd.proc("WindowClose", [&, esc_pressed](hids& gear) - { - if (!gear.is_exclusive() && *esc_pressed) - { - boss.bell::signal(tier::anycast, e2::form::proceed::quit::one, true); - gear.set_handled(true); - } - }); - keybd.proc("WindowClosePreview", [&, esc_pressed](hids& /*gear*/) - { - if (std::exchange(*esc_pressed, true) != *esc_pressed) - { - boss.bell::signal(tier::release, e2::form::state::keybd::command::close, *esc_pressed); - } - }); - keybd.proc("UpdateChordPreview", [&, esc_pressed, update_ptr](hids& gear) + app::shared::base_kb_navigation(keybd, scroll, boss); + keybd.proc("UpdateChordPreview", [&, update_ptr](hids& gear) { - if (std::exchange(*esc_pressed, faux) != *esc_pressed) boss.bell::signal(tier::release, e2::form::state::keybd::command::close, *esc_pressed); if (gear.keystat != input::key::repeated) (*update_ptr)(items_inst, gear, true); }); - keybd.template bind( "Esc", "DropIfRepeats"); - keybd.template bind( "Esc", "WindowClosePreview"); - keybd.template bind("-Esc", "WindowClose"); keybd.template bind( "Any", "UpdateChordPreview"); - keybd.proc("ScrollPageUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0, 1 }}); } }); - keybd.proc("ScrollPageDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0,-1 }}); } }); - keybd.proc("ScrollLineUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0, 3 }}); } }); - keybd.proc("ScrollLineDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0,-3 }}); } }); - keybd.proc("ScrollCharLeft" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = { 3, 0 }}); } }); - keybd.proc("ScrollCharRight" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = {-3, 0 }}); } }); - keybd.proc("ScrollTop" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_top::y); } }); - keybd.proc("ScrollEnd" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::signal(tier::preview, e2::form::upon::scroll::to_end::y); } }); - keybd.proc("ToggleMaximize" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); }}); // Refocus-related operations require execution outside of keyboard events. - keybd.proc("ToggleFullscreen" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); }}); - keybd.proc("ToggleExclusiveKeybd", [&](hids& gear){ if (!gear.is_exclusive()) gear.set_exclusive(boss.This()); else gear.set_exclusive(); }); - keybd.bind("PageUp" , "ScrollPageUp" ); - keybd.bind("PageDown" , "ScrollPageDown" ); - keybd.bind("UpArrow" , "ScrollLineUp" ); - keybd.bind("DownArrow" , "ScrollLineDown" ); - keybd.bind("LeftArrow" , "ScrollCharLeft" ); - keybd.bind("RightArrow", "ScrollCharRight" ); - keybd.bind("Home" , "DropIfRepeats" ); - keybd.bind("Home" , "ScrollTop" ); - keybd.bind("End" , "DropIfRepeats" ); - keybd.bind("End" , "ScrollEnd" ); - keybd.bind("F11" , "DropIfRepeats" ); - keybd.bind("F11" , "ToggleMaximize" ); - keybd.bind("F12" , "DropIfRepeats" ); - keybd.bind("F12" , "ToggleFullscreen" ); - keybd.bind("Ctrl-Alt" , "ToggleExclusiveKeybd"); - keybd.bind("Alt-Ctrl" , "ToggleExclusiveKeybd"); }); inside->attach(slot::_2, ui::post::ctor()) ->limits({ -1, 1 }) diff --git a/src/netxs/apps/calc.hpp b/src/netxs/apps/calc.hpp index d4ed2885d1..cdb8d5c6f5 100644 --- a/src/netxs/apps/calc.hpp +++ b/src/netxs/apps/calc.hpp @@ -333,7 +333,7 @@ namespace netxs::app::calc window->plugin(pro::focus::mode::focused) ->colors(whitelt, 0x60'00'5f'1A) ->limits({ 10,7 }, { -1,-1 }) - //->plugin() + ->plugin() ->shader(c3, e2::form::state::keybd::focus::count) //->plugin() ->plugin() @@ -424,6 +424,11 @@ namespace netxs::app::calc auto pad = plus_pad->attach(slot::_2, ui::mock::ctor()) ->limits({ 1,1 }, { 1,1 }); layers->attach(app::shared::scroll_bars(scroll)); + window->invoke([&](auto& boss) + { + auto& keybd = boss.template plugins(); + app::shared::base_kb_navigation(keybd, scroll, boss); + }); return window; }; } diff --git a/src/netxs/apps/shop.hpp b/src/netxs/apps/shop.hpp index 4a6a04d046..8e7fdc6d05 100644 --- a/src/netxs/apps/shop.hpp +++ b/src/netxs/apps/shop.hpp @@ -195,7 +195,7 @@ namespace netxs::app::shop auto window = ui::cake::ctor(); window->plugin(pro::focus::mode::focused) ->colors(whitelt, 0x60000000) - //->plugin() + ->plugin() ->plugin() ->plugin() ->invoke([](auto& boss) @@ -231,6 +231,11 @@ namespace netxs::app::shop ->upload(desktopio_body) ->plugin(); layers->attach(app::shared::scroll_bars(scroll)); + window->invoke([&](auto& boss) + { + auto& keybd = boss.template plugins(); + app::shared::base_kb_navigation(keybd, scroll, boss); + }); return window; }; }; diff --git a/src/netxs/apps/test.hpp b/src/netxs/apps/test.hpp index befe96cb2b..dbc2e6fe28 100644 --- a/src/netxs/apps/test.hpp +++ b/src/netxs/apps/test.hpp @@ -600,7 +600,7 @@ namespace netxs::app::test auto topic = get_text(); auto window = ui::cake::ctor() ->plugin(pro::focus::mode::focused) - //->plugin() + ->plugin() //->plugin() ->plugin() ->invoke([](auto& boss) @@ -655,7 +655,11 @@ namespace netxs::app::test b.grad(argb{ 0xFF00FFFF }, argb{ 0x40FFFFFF }); b[{5, 0}].alpha(0); b[{5, 1}].alpha(0); - + window->invoke([&](auto& boss) + { + auto& keybd = boss.template plugins(); + app::shared::base_kb_navigation(keybd, scroll, boss); + }); return window; }; } diff --git a/src/netxs/apps/text.hpp b/src/netxs/apps/text.hpp index 8d21c3f8ed..49b6cfe7db 100644 --- a/src/netxs/apps/text.hpp +++ b/src/netxs/apps/text.hpp @@ -87,7 +87,7 @@ displaying the requested definition in a popup window or temporary buffer. Some auto window = ui::cake::ctor(); window->plugin(pro::focus::mode::focused) - //->plugin() + ->plugin() ->shader(c3, e2::form::state::keybd::focus::count) //->plugin() ->plugin() @@ -126,6 +126,11 @@ displaying the requested definition in a popup window or temporary buffer. Some ->upload(ansi::wrp(wrap::off).mgl(1).mgr(1).jet(bias::right).fgc(whitedk) .add("INS Sel: 0:0 Col: 26 Ln: 2/148").nil()); layers->attach(app::shared::scroll_bars(scroll)); + window->invoke([&](auto& boss) + { + auto& keybd = boss.template plugins(); + app::shared::base_kb_navigation(keybd, scroll, boss); + }); return window; }; } diff --git a/src/netxs/desktopio/application.hpp b/src/netxs/desktopio/application.hpp index 4d2ac2ed68..707bd625a5 100644 --- a/src/netxs/desktopio/application.hpp +++ b/src/netxs/desktopio/application.hpp @@ -110,6 +110,58 @@ namespace netxs::app::shared } } }; + const auto base_kb_navigation = [](ui::pro::keybd& keybd, netxs::sptr scroll, base& boss) + { + auto& scroll_inst = *scroll; + auto esc_pressed = ptr::shared(faux); + keybd.proc("WindowClose", [&, esc_pressed](hids& gear) + { + if (!gear.is_exclusive() && *esc_pressed) + { + boss.bell::signal(tier::anycast, e2::form::proceed::quit::one, true); + gear.set_handled(true); + } + }); + keybd.proc("WindowClosePreview", [&, esc_pressed](hids& /*gear*/) + { + if (std::exchange(*esc_pressed, true) != *esc_pressed) boss.bell::signal(tier::anycast, e2::form::state::keybd::command::close, *esc_pressed); + }); + keybd.proc("CancelWindowClose", [&, esc_pressed](hids& /*gear*/) + { + if (std::exchange(*esc_pressed, faux) != *esc_pressed) boss.bell::signal(tier::anycast, e2::form::state::keybd::command::close, *esc_pressed); + }); + keybd.template bind( "Esc", "DropIfRepeats"); + keybd.template bind( "Esc", "WindowClosePreview"); + keybd.template bind("-Esc", "WindowClose"); + keybd.template bind( "Any", "CancelWindowClose"); + keybd.proc("ScrollPageUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0, 1 }}); } }); + keybd.proc("ScrollPageDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::upon::scroll::bypage::y, { .vector = { 0,-1 }}); } }); + keybd.proc("ScrollLineUp" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0, 3 }}); } }); + keybd.proc("ScrollLineDown" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::upon::scroll::bystep::y, { .vector = { 0,-3 }}); } }); + keybd.proc("ScrollCharLeft" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = { 3, 0 }}); } }); + keybd.proc("ScrollCharRight" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::upon::scroll::bystep::x, { .vector = {-3, 0 }}); } }); + keybd.proc("ScrollTop" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::upon::scroll::to_top::y); } }); + keybd.proc("ScrollEnd" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.base::riseup(tier::preview, e2::form::upon::scroll::to_end::y); } }); + keybd.proc("ToggleMaximize" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::maximize, gear); }); }}); // Refocus-related operations require execution outside of keyboard events. + keybd.proc("ToggleFullscreen" , [&](hids& gear){ if (!gear.is_exclusive()) { scroll_inst.bell::enqueue(boss.This(), [&](auto& /*boss*/){ scroll_inst.base::riseup(tier::preview, e2::form::size::enlarge::fullscreen, gear); }); }}); + keybd.proc("ToggleExclusiveKeybd", [&](hids& gear){ if (!gear.is_exclusive()) gear.set_exclusive(boss.This()); else gear.set_exclusive(); }); + keybd.bind("PageUp" , "ScrollPageUp" ); + keybd.bind("PageDown" , "ScrollPageDown" ); + keybd.bind("UpArrow" , "ScrollLineUp" ); + keybd.bind("DownArrow" , "ScrollLineDown" ); + keybd.bind("LeftArrow" , "ScrollCharLeft" ); + keybd.bind("RightArrow", "ScrollCharRight" ); + keybd.bind("Home" , "DropIfRepeats" ); + keybd.bind("Home" , "ScrollTop" ); + keybd.bind("End" , "DropIfRepeats" ); + keybd.bind("End" , "ScrollEnd" ); + keybd.bind("F11" , "DropIfRepeats" ); + keybd.bind("F11" , "ToggleMaximize" ); + keybd.bind("F12" , "DropIfRepeats" ); + keybd.bind("F12" , "ToggleFullscreen" ); + keybd.bind("Ctrl-Alt" , "ToggleExclusiveKeybd"); + keybd.bind("Alt-Ctrl" , "ToggleExclusiveKeybd"); + }; using builder_t = std::function; @@ -281,8 +333,9 @@ namespace netxs::app::shared }; }}, { menu::item{ menu::item::type::Command, true, 0, std::vector{{ .label = "×", .notes = " Close ", .hover = c1 }}}, - [](auto& boss, auto& /*item*/) + [c1](auto& boss, auto& /*item*/) { + boss.shader(cell::shaders::color(c1), e2::form::state::keybd::command::close); boss.LISTEN(tier::release, hids::events::mouse::button::click::left, gear) { auto backup = boss.This(); From b670a101a30de4e4127f4422fd9922fb70792288 Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:17:59 +0500 Subject: [PATCH 08/13] Fix title alignment after fullscreen --- src/netxs/desktopio/ansivt.hpp | 4 +++- src/netxs/desktopio/richtext.hpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/netxs/desktopio/ansivt.hpp b/src/netxs/desktopio/ansivt.hpp index 7cee555dc6..baf0e413da 100644 --- a/src/netxs/desktopio/ansivt.hpp +++ b/src/netxs/desktopio/ansivt.hpp @@ -1730,9 +1730,11 @@ namespace netxs::ansi data(n * wdt, proto_cells); proto_cells.clear(); } - void reset(cell c) + void reset(cell c = {}) { brush.reset(c); + style.rst(); + state.rst(); proto_count = 0; proto_cells.clear(); } diff --git a/src/netxs/desktopio/richtext.hpp b/src/netxs/desktopio/richtext.hpp index 0f9442689c..38358c86e7 100644 --- a/src/netxs/desktopio/richtext.hpp +++ b/src/netxs/desktopio/richtext.hpp @@ -2034,7 +2034,7 @@ namespace netxs::ui // page: Clear the list of paragraphs. page& clear(bool preserve_state = faux) { - if (!preserve_state) parser::brush.reset(); + if (!preserve_state) parser::reset(); parts.clear(); batch.resize(1); layer = batch.begin(); From b82dd6b6aa742a44c71eff34b4fe17b74d6ce94b Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:32:36 +0500 Subject: [PATCH 09/13] Update user-interface.md --- doc/user-interface.md | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/doc/user-interface.md b/doc/user-interface.md index 833daf9347..d29b4b1f45 100644 --- a/doc/user-interface.md +++ b/doc/user-interface.md @@ -24,15 +24,19 @@ - F10 + Ctrl-Alt ² + Toggle exclusive keyboard mode + + + F10 ² Disconnect all users and shutdown if there are no apps running - Shift+F7 + Shift+F7 ² Leave current session - Ctrl+PgUp/PgDn + Ctrl+PageUp/PageDown ² Switch focus between running apps @@ -162,19 +166,19 @@ - Alt+Enter + Alt+Enter ² Toggle fullscreen mode - Ctrl+CapsLock + Ctrl+CapsLock ² Toggle antialiasing mode - CapsLock+Up/DownArrow + CapsLock+UpArrow/DownArrow ² Scale cell size - CapsLock+0 + CapsLock+0 ² Reset cell size @@ -189,10 +193,6 @@ DoubleLeftClick Toggle fullscreen mode (if unhandled) - - Home+End - Close GUI window - AnyDrag
Left+RightDrag Move GUI window (if unhandled) @@ -214,4 +214,5 @@ -¹ — In fullscreen mode, the GUI window reserves a 1px high area at the top for forwarding mouse events. \ No newline at end of file +¹ — In fullscreen mode, the GUI window reserves a 1px high area at the top for forwarding mouse events. +² — Key bindings can be customized using the settings. \ No newline at end of file From 31f6002f52a707f7f8ee29d15d4279e9870ad5c4 Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:33:17 +0500 Subject: [PATCH 10/13] v0.9.99.42 --- src/netxs/desktopio/application.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netxs/desktopio/application.hpp b/src/netxs/desktopio/application.hpp index 707bd625a5..2f5a05d770 100644 --- a/src/netxs/desktopio/application.hpp +++ b/src/netxs/desktopio/application.hpp @@ -24,7 +24,7 @@ namespace netxs::app namespace netxs::app::shared { - static const auto version = "v0.9.99.41"; + static const auto version = "v0.9.99.42"; static const auto repository = "https://github.com/directvt/vtm"; static const auto usr_config = "~/.config/vtm/settings.xml"s; static const auto sys_config = "/etc/vtm/settings.xml"s; From be103bcccfc0ac0c343add4b97e9aab22e6c3d90 Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:46:21 +0500 Subject: [PATCH 11/13] Fix unix builds --- src/netxs/apps.hpp | 2 +- src/netxs/apps/desk.hpp | 2 +- src/netxs/desktopio/application.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/netxs/apps.hpp b/src/netxs/apps.hpp index 477eea5eae..74ef10e9c3 100644 --- a/src/netxs/apps.hpp +++ b/src/netxs/apps.hpp @@ -549,7 +549,7 @@ namespace netxs::app::shared { menu::item{ menu::item::type::Command, true, 0, std::vector{{ .label = "×", .notes = " Close ", .hover = c1 }}}, [window, c1](auto& boss, auto& /*item*/) { - boss.shader(cell::shaders::color(c1), e2::form::state::keybd::command::close, boss.This()); + boss.template shader(cell::shaders::color(c1), e2::form::state::keybd::command::close, boss.This()); boss.LISTEN(tier::release, hids::events::mouse::button::click::left, gear) { auto backup = boss.This(); diff --git a/src/netxs/apps/desk.hpp b/src/netxs/apps/desk.hpp index 38858a50d2..092e554b0d 100644 --- a/src/netxs/apps/desk.hpp +++ b/src/netxs/apps/desk.hpp @@ -80,7 +80,7 @@ namespace netxs::app::desk auto item_area = ui::fork::ctor(axis::X, 0, 1, 0) ->active(cE) ->shader(cell::shaders::xlight, e2::form::state::hover) - ->shader(cell::shaders::disabled, e2::form::state::disabled) + ->shader(cell::shaders::disabled, e2::form::state::disabled) ->plugin() ->setpad({ 0, 0, 0, 0 }, { 0, 0, -tall, 0 }) ->invoke([&](auto& boss) diff --git a/src/netxs/desktopio/application.hpp b/src/netxs/desktopio/application.hpp index 2f5a05d770..595925d4bc 100644 --- a/src/netxs/desktopio/application.hpp +++ b/src/netxs/desktopio/application.hpp @@ -335,7 +335,7 @@ namespace netxs::app::shared { menu::item{ menu::item::type::Command, true, 0, std::vector{{ .label = "×", .notes = " Close ", .hover = c1 }}}, [c1](auto& boss, auto& /*item*/) { - boss.shader(cell::shaders::color(c1), e2::form::state::keybd::command::close); + boss.template shader(cell::shaders::color(c1), e2::form::state::keybd::command::close); boss.LISTEN(tier::release, hids::events::mouse::button::click::left, gear) { auto backup = boss.This(); From 0e3c623cb779789dafc2d45cf0e1dee42541ac5d Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 15:48:27 +0500 Subject: [PATCH 12/13] Fix unix builds --- src/netxs/desktopio/controls.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/netxs/desktopio/controls.hpp b/src/netxs/desktopio/controls.hpp index 6fadc215e3..579661bbf5 100644 --- a/src/netxs/desktopio/controls.hpp +++ b/src/netxs/desktopio/controls.hpp @@ -2412,7 +2412,7 @@ namespace netxs::ui return backup; } // form: Fill object region using parametrized fx. - template> + template> auto shader(Fx&& fx, Event sync = {}, sptr source_ptr = {}) { static constexpr auto is_cell = std::is_same_v>; From 495e7e99a0c2074bd5ddf18da17ec5017acf967e Mon Sep 17 00:00:00 2001 From: Dmitry Sapozhnikov <11535558+o-sdn-o@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:03:54 +0500 Subject: [PATCH 13/13] Minor edits --- doc/settings.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/settings.md b/doc/settings.md index 29174243c0..f5485ed8a0 100644 --- a/doc/settings.md +++ b/doc/settings.md @@ -345,7 +345,7 @@ Action | Default key combination | Available at level -------------------------------|--------------------------|---------------------|------------ `Drop` | | All levels | Drop all events for the specified key combination. No further processing. `DropIfRepeats` | | All levels | Drop `Key Repeat` events for the specified key combination. This binding should be specified before the main action for the key combination. -`ToggleExclusiveKeybd` | `Ctrl-Alt`, `Alt-Ctrl` | Application | Toggle exclusive keyboard mode. In exclusive mode, all keyboard events are ignored by higher levels. +`ToggleExclusiveKeybd` | `Ctrl-Alt`, `Alt-Ctrl` | Application | Toggle exclusive keyboard mode. In exclusive mode, all keyboard events are ignored by higher levels. Exclusive keyboard mode is automatically disabled when refocusing. `IncreaseCellHeight` | `CapsLock+UpArrow` | Native GUI window | Increase the text cell height by one pixel. `DecreaseCellHeight` | `CapsLock+DownArrow` | Native GUI window | Decrease the text cell height by one pixel. `ResetCellHeight` | `Ctrl+Key0` | Native GUI window | Reset text cell height.