Skip to content

Commit

Permalink
Merge pull request #670 from o-sdn-o/gui-bridge
Browse files Browse the repository at this point in the history
Make hotkeys configurable
  • Loading branch information
o-sdn-o authored Nov 4, 2024
2 parents ce888b0 + 74b3b48 commit c0c02b0
Show file tree
Hide file tree
Showing 14 changed files with 845 additions and 491 deletions.
245 changes: 155 additions & 90 deletions doc/apps.md

Large diffs are not rendered by default.

14 changes: 6 additions & 8 deletions doc/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,6 @@ The value of the `cfg` menu item attribute (or a whole `<config>` subsection) wi

### Configuration example

Note: The following configuration sections are not implemented yet:
- `<config/.../hotkeys/>`

#### Minimal configuration

`~/.config/vtm/settings.xml`:
Expand Down Expand Up @@ -473,7 +470,7 @@ Notes
<selection>
<mode=/config/set/selection/mode/> <!-- Clipboard copy format: "text" | "ansi" | "rich" | "html" | "protected" | "none" . -->
</selection>
<hotkeys> <!-- not implemented -->
<hotkeys>
<key="Alt+RightArrow" action="TerminalFindNext()"/>
<key="Alt+LeftArrow" action="TerminalFindPrev()"/>
</hotkeys>
Expand Down Expand Up @@ -576,10 +573,11 @@ Notes
<opacity=105.5/> <!-- Opacity level (alpha) [0.0 - 255.0]. Default is "105.5". -->
<offset=2,1/> <!-- 2D offset relative to the window (in cells). Default is "2,1". -->
</shadow>
<hotkeys key*> <!-- not implemented -->
<key="Ctrl+PgUp" action="vtm.PrevWindow()"/>
<key="Ctrl+PgDn" action="vtm.NextWindow()"/>
<key="Ctrl+T" action="vtm.Start(\"Term\")"/>
<hotkeys key*>
<key="Ctrl+PgUp" action="FocusPrevWindow()"/>
<key="Ctrl+PgDn" action="FocusNextWindow()"/>
<key="Shift+F7" action="Disconnect()"/>
<key="F10" action="TryQuit()"/>
</hotkeys>
</desktop>
<term> <!-- Base settings for the Term app. It can be partially overridden by the menu item's config subarg. -->
Expand Down
9 changes: 5 additions & 4 deletions src/netxs/apps.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -606,7 +606,7 @@ namespace netxs::app::shared
auto items = scroll->attach(ui::list::ctor());
auto title_grid = items->attach(ui::fork::ctor(axis::Y));
auto title_data = title_grid->attach(slot::_1, ui::item::ctor("Keyboard Test")->setpad({ 2, 0, 1, 0 }));
auto chord_grid = title_grid->attach(slot::_2, ui::grid::ctor(twod{ 5, 3 }))
auto chord_grid = title_grid->attach(slot::_2, ui::grid::ctor())
->setpad({ 4, 5, 0, 2})
->active()
->template plugin<pro::focus>()
Expand Down Expand Up @@ -654,9 +654,9 @@ namespace netxs::app::shared
auto released = std::to_array({ field(), field(), field(), field() });
auto pressed_label = label( "pressed:")->alignment({ snap::tail, snap::both });
auto released_label = label("released:");
chord_grid->attach_cells({ {}, label("Generic"), label("Literal"), label("Specific"), label("Scancodes"),
pressed_label, pressed[0], pressed[1], pressed[2], pressed[3],
released_label, released[0], released[1], released[2], released[3]});
chord_grid->attach_cells({ 5, 3 }, { {}, label("Generic"), label("Literal"), label("Specific"), label("Scancodes"),
pressed_label, pressed[0], pressed[1], pressed[2], pressed[3],
released_label, released[0], released[1], released[2], released[3] });
released[0]->set("<Press any keys>")->hidden = faux;;
auto update = [pressed, released](auto& boss, hids& gear, bool is_key_event)
{
Expand Down Expand Up @@ -726,6 +726,7 @@ namespace netxs::app::shared
boss.LISTEN(tier::release, hids::events::keybd::key::any, gear, -, (update, esc_pressed)) //todo MS VS2019 can't capture static 'auto update =...'.
{
auto changed = faux;
//todo key
if (gear.chord(input::key::Esc))
{
if (gear.keystat == input::key::released && gear.vkchord.size())
Expand Down
4 changes: 4 additions & 0 deletions src/netxs/apps/term.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,10 @@ namespace netxs::app::terminal
auto cwd_path_ptr = ptr::shared<os::fs::path>();
auto& cwd_sync = *cwd_sync_ptr;
auto& cwd_path = *cwd_path_ptr;
boss.LISTEN(tier::preview, ui::term::events::toggle::cwdsync, state, -)
{
boss.bell::signal(tier::anycast, terminal::events::preview::cwdsync, !cwd_sync);
};
boss.LISTEN(tier::anycast, terminal::events::preview::cwdsync, state, -, (cwd_commands))
{
if (cwd_sync != state)
Expand Down
2 changes: 1 addition & 1 deletion src/netxs/desktopio/application.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace netxs::app

namespace netxs::app::shared
{
static const auto version = "v0.9.99.36";
static const auto version = "v0.9.99.37";
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;
Expand Down
3 changes: 2 additions & 1 deletion src/netxs/desktopio/consrv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1060,7 +1060,8 @@ struct impl : consrv
toWIDE.clear();
if constexpr (isreal()) // Copy/Paste by Ctrl/Shift+Insert in cooked read mode.
{
if (incook && gear.keystat && gear.keycode == input::key::Insert)
//todo key
if (incook && gear.keystat && gear.keycode == input::key::KeyInsert)
{
if (gear.meta(input::hids::anyShift))
{
Expand Down
194 changes: 148 additions & 46 deletions src/netxs/desktopio/controls.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1814,6 +1814,120 @@ namespace netxs::ui
}
};

// pro: Keyboard events.
class keybd
: public skill
{
using func = std::function<void(hids&)>;
using wptr = netxs::wptr<func>;
using sptr = netxs::sptr<func>;
using skill::boss,
skill::memo;

std::unordered_map<text, std::list<wptr>, qiew::hash, qiew::equal> handlers_preview;
std::unordered_map<text, std::list<wptr>, qiew::hash, qiew::equal> handlers_release;
std::unordered_map<text, sptr, qiew::hash, qiew::equal> api_map;
std::vector<sptr> chord_handlers;

template<si32 Tier = tier::release>
auto _set(qiew chord_str, sptr handler_ptr)
{
auto& handlers = Tier == tier::release ? handlers_release : handlers_preview;
auto chords = input::key::kmap::chord_list(chord_str);
//log("Chord: ", chord_str);
if (chords.size())
{
//auto handler_ptr = ptr::shared(std::move(handler));
for (auto& chord : chords)
{
//log("\t", input::key::kmap::to_string(chord, faux));
handlers[chord].push_back(handler_ptr);
}
return true;//handler_ptr;
}
else
{
log("%%Unknown key chord: '%chord%'", prompt::user, chord_str);
return faux;//sptr{};
}
}
template<si32 Tier = tier::release>
void _dispatch(hids& gear, qiew chord)
{
auto& handlers = Tier == tier::release ? handlers_release : handlers_preview;
auto iter = handlers.find(chord);
if (iter != handlers.end())
{
auto& procs = iter->second;
std::erase_if(procs, [&](auto& proc_wptr)
{
auto proc_ptr = proc_wptr.lock();
if (proc_ptr)
{
(*proc_ptr)(gear);
}
return !proc_ptr;
});
if (procs.empty()) handlers.erase(iter);
}
}

public:
keybd(base&&) = delete;
keybd(base& boss)
: skill{ boss }
{
boss.LISTEN(tier::release, hids::events::keybd::key::post, gear, memo)
{
if (gear.payload == input::keybd::type::keypress)
{
if (gear.keystat) _dispatch<tier::release>(gear, gear.vkchord);
if (gear.keystat) _dispatch<tier::release>(gear, gear.chchord);
if (gear.keystat) _dispatch<tier::release>(gear, gear.scchord);
}
};
boss.LISTEN(tier::preview, hids::events::keybd::key::any, gear, memo)
{
if (gear.payload == input::keybd::type::keypress)
{
if (gear.keystat) _dispatch<tier::preview>(gear, gear.vkchord);
if (gear.keystat) _dispatch<tier::preview>(gear, gear.chchord);
if (gear.keystat) _dispatch<tier::preview>(gear, gear.scchord);
}
};
}

auto proc(qiew name, func proc)
{
api_map[name] = ptr::shared(std::move(proc));
}
//template<class ...Args>
//auto bind(qiew chord_str, func handler, Args&&... chords_handlers)
//{
// auto handler_ptr = ptr::shared(std::move(handler));
// if (_set(chord_str, handler_ptr)) chord_handlers.push_back(handler_ptr);
// if constexpr (sizeof...(Args)) bind(std::forward<Args>(chords_handlers)...);
//}
template<si32 Tier = tier::release>
auto bind(qiew chord_str, qiew proc_name)
{
if (auto iter = api_map.find(proc_name); iter != api_map.end())
{
if (_set<Tier>(chord_str, iter->second))
{
//chord_handlers.push_back(iter->second);
}
}
else log("%%Function '%proc%' not found", prompt::user, proc_name);
}
auto reset()
{
chord_handlers.clear();
handlers_release.clear();
handlers_preview.clear();
}
};

// pro: Glow gradient filter.
class grade
: public skill
Expand Down Expand Up @@ -2791,37 +2905,29 @@ namespace netxs::ui
class grid
: public form<grid>
{
struct size
{
si32 max;
si32 min;
si32 val;
};
struct elem
{
twod coor; // elem: Grid cell coordinates for placing the object.
twod span; // elem: The number of adjacent grid cells occupied by the object.
rect area; // elem: Object slot.
bool done; // elem: Object resized.
};
auto cellsz(twod coor, twod span)
{
auto s = dot_00;
auto m = coor + span;
for (auto x = coor.x; x < m.x; x++) s.x += widths[x].val;
for (auto y = coor.y; y < m.y; y++) s.y += heights[y].val;
return s;
auto x = std::accumulate(widths.begin() + coor.x, widths.begin() + coor.x + span.x, 0);
auto y = std::accumulate(heights.begin() + coor.y, heights.begin() + coor.y + span.y, 0);
return twod{ x, y };
}
std::vector<size> widths; // grid: Grid column widths.
std::vector<size> heights; // grid: Grid row heights.
std::vector<si32> widths; // grid: Grid column widths.
std::vector<si32> heights; // grid: Grid row heights.
std::vector<elem> blocks; // grid: Geometry of stored objects.

protected:
// grid: .
void deform(rect& new_area) override
{
for (auto& h : heights) h = {};
for (auto& w : widths) w = {};
//log("DEFORM==================================");
widths.clear();
heights.clear();
auto recalc = [&](auto object_iter, auto tail2, auto elem_iter)
{
auto changed = faux;
Expand All @@ -2830,41 +2936,44 @@ namespace netxs::ui
auto& object = *(*object_iter++);
auto& elem = *elem_iter++;
if (elem.span.x < 1 || elem.span.y < 1) continue;
auto dimension = elem.coor + elem.span;
if (dimension.x > (si32)widths.size()) widths.resize(dimension.x);
if (dimension.y > (si32)heights.size()) heights.resize(dimension.y);
auto area_size = cellsz(elem.coor, elem.span);
if (elem.done && elem.area.size == area_size) continue;
elem.area.size = area_size;
elem.done = true;
object.base::recalc(elem.area);
//log("elem.area=", elem.area);
auto delta = elem.area.size - area_size;
if (delta.x > 0)
{
changed = true;
auto tail = widths.end();
auto head = widths.begin() + elem.coor.x + elem.span.x - 1;
(*head++).val += delta.x;
changed = true;//head != tail;
*head++ += delta.x;
while (delta.x && head != tail)
{
auto& w = (*head++).val;
auto& w = *head++;
auto dx = std::min(w, delta.x);
w -= dx;
delta.x -= dx;
}
}
if (delta.y > 0)
{
changed = true;
auto tail = heights.end();
auto head = heights.begin() + elem.coor.y + elem.span.y - 1;
(*head++).val += delta.y;
changed = true;//head != tail;
*head++ += delta.y;
while (delta.y && head != tail)
{
auto& w = (*head++).val;
auto dx = std::min(w, delta.y);
w -= dx;
delta.y -= dx;
auto& h = *head++;
auto dy = std::min(h, delta.y);
h -= dy;
delta.y -= dy;
}
}
}
//log("-------------------");
return changed;
};
auto recoor = [&](auto object_iter, auto tail, auto elem_iter)
Expand All @@ -2874,13 +2983,12 @@ namespace netxs::ui
auto& object = *(*object_iter++);
auto& elem = *elem_iter++;
elem.area.coor = cellsz(dot_00, elem.coor);
elem.done = {};
object.base::recalc(elem.area);
}
};
//todo optimize
while (recalc(subset.begin(), subset.end(), blocks.begin()))
while (recalc(subset.rbegin(), subset.rend(), blocks.rbegin()))
{ }
//recalc(subset.rbegin(), subset.rend(), blocks.rbegin());
recoor(subset.begin(), subset.end(), blocks.begin());
new_area.size = std::max(new_area.size, cellsz(dot_00, { widths.size(), heights.size() }));
}
Expand All @@ -2896,9 +3004,7 @@ namespace netxs::ui
}

public:
grid(twod grid_size)
: widths(grid_size.x),
heights(grid_size.y)
grid()
{
LISTEN(tier::release, e2::render::any, parent_canvas)
{
Expand Down Expand Up @@ -2947,29 +3053,25 @@ namespace netxs::ui
return std::pair{ sptr{}, elem{} };
}
// grid: Attach specified item.
auto attach(auto object, twod coor, twod span = dot_11)
auto attach(auto object, elem conf = { .span = dot_11 })
{
auto size = coor + span;
if ((si32)widths.size() < size.x) widths.resize(size.x);
if ((si32)heights.size() < size.y) heights.resize(size.y);
blocks.push_back({ coor, span });
blocks.push_back(conf);
subset.push_back(object);
object->bell::signal(tier::release, e2::form::upon::vtree::attached, This());
return object;
}
// grid: Attach item grid.
void attach_cells(std::vector<sptr> objects)
void attach_cells(twod size, std::vector<sptr> object_list)
{
if (widths.empty() || heights.empty()) return;
auto coor = dot_00;
auto conf = elem{ .span = dot_11, .done = faux };
auto temp = std::exchange(base::hidden, true); // Suppress reflowing during attaching.
for (auto object : objects)
for (auto object : object_list)
{
if (object) attach(object, coor);
if (++coor.x == (si32)widths.size())
if (object) attach(object, conf);
if (++conf.coor.x == size.x)
{
coor.x = 0;
if (++coor.y == (si32)heights.size()) break;
conf.coor.x = 0;
if (++conf.coor.y == size.y) break;
}
}
base::hidden = temp;
Expand Down
Loading

0 comments on commit c0c02b0

Please sign in to comment.