From 72264661fdc86049dec1e17b6b8906eb6b86e658 Mon Sep 17 00:00:00 2001 From: faissaloo Date: Mon, 3 Jun 2019 16:02:49 +0100 Subject: [PATCH] GWindow: Add SerenityKeys minimum functionality --- Applications/About/main.cpp | 1 + LibGUI/GAbstractButton.h | 1 + LibGUI/GButton.cpp | 4 ++ LibGUI/GWidget.h | 1 + LibGUI/GWindow.cpp | 97 +++++++++++++++++++++++++++++++++++-- LibGUI/GWindow.h | 9 ++++ 6 files changed, 109 insertions(+), 4 deletions(-) diff --git a/Applications/About/main.cpp b/Applications/About/main.cpp index e05fd3a7fc..e6c22966cb 100644 --- a/Applications/About/main.cpp +++ b/Applications/About/main.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include int main(int argc, char** argv) diff --git a/LibGUI/GAbstractButton.h b/LibGUI/GAbstractButton.h index fdbb6a7a8c..40f9869f28 100644 --- a/LibGUI/GAbstractButton.h +++ b/LibGUI/GAbstractButton.h @@ -26,6 +26,7 @@ public: virtual void click() = 0; virtual const char* class_name() const override { return "GAbstractButton"; } virtual bool accepts_focus() const override { return true; } + virtual bool accepts_keyboard_select() const { return true; } protected: explicit GAbstractButton(GWidget* parent); diff --git a/LibGUI/GButton.cpp b/LibGUI/GButton.cpp index 62e521702d..4522a9b7fc 100644 --- a/LibGUI/GButton.cpp +++ b/LibGUI/GButton.cpp @@ -64,6 +64,10 @@ void GButton::click() on_click(*this); } +/*bool GButton::accepts_keyboard_select() const { + return is_enabled(); +}*/ + void GButton::set_action(GAction& action) { m_action = action.make_weak_ptr(); diff --git a/LibGUI/GWidget.h b/LibGUI/GWidget.h index 6e73c7e4c1..11524fb005 100644 --- a/LibGUI/GWidget.h +++ b/LibGUI/GWidget.h @@ -106,6 +106,7 @@ public: void update(const Rect&); virtual bool accepts_focus() const { return false; } + virtual bool accepts_keyboard_select() const { return false; } bool is_focused() const; void set_focus(bool); diff --git a/LibGUI/GWindow.cpp b/LibGUI/GWindow.cpp index cccb2fda24..a015152242 100644 --- a/LibGUI/GWindow.cpp +++ b/LibGUI/GWindow.cpp @@ -230,6 +230,19 @@ void GWindow::event(CEvent& event) for (auto& rect : rects) m_main_widget->event(*make(rect)); + if (m_keybind_mode) { + //If we're in keybind mode indicate widgets in m_potential_keybind_widgets + GPainter painter(*m_main_widget); + painter.draw_text(Rect(20,20,20,20), m_entered_keybind.characters(), TextAlignment::TopLeft, Color::Green); + + for (auto& keypair: m_hashed_potential_keybind_widgets) { + auto widget = keypair.value; + auto rect = Rect(widget->x()-5, widget->y()-5, 12, 12); + painter.draw_text(rect, keypair.key.characters(), TextAlignment::TopLeft, Color::Black); + } + + } + if (m_double_buffering_enabled) flip(rects); else if (created_new_backing_store) @@ -251,10 +264,44 @@ void GWindow::event(CEvent& event) } if (event.type() == GEvent::KeyUp || event.type() == GEvent::KeyDown) { - if (m_focused_widget) - return m_focused_widget->event(event); - if (m_main_widget) - return m_main_widget->event(event); + auto keyevent = static_cast(event); + if (keyevent.logo() && event.type() == GEvent::KeyUp) { + if (m_keybind_mode) { + m_keybind_mode = false; + } else { + m_keybind_mode = true; + find_keyboard_selectable(); + m_entered_keybind = ""; + } + update(); + return; + } + + if (m_keybind_mode) { + StringBuilder builder; + //Y u no work + builder.append(m_entered_keybind); + builder.append(keyevent.text()); + m_entered_keybind = builder.to_string(); + + auto found_widget = m_hashed_potential_keybind_widgets.find(m_entered_keybind); + if (found_widget != m_hashed_potential_keybind_widgets.end()) { + m_keybind_mode = false; + const auto& point = Point(); + auto event = make(GEvent::MouseDown, point, 0, GMouseButton::Left, 0, 0); + found_widget->value->event(*event); + event = make(GEvent::MouseUp, point, 0, GMouseButton::Left, 0, 0); + found_widget->value->event(*event); + //Call click on the found widget + } + //m_entered_keybind.append(keyevent.text()); + update(); + } else { + if (m_focused_widget) + return m_focused_widget->event(event); + if (m_main_widget) + return m_main_widget->event(event); + } return; } @@ -296,6 +343,44 @@ void GWindow::event(CEvent& event) CObject::event(event); } +void GWindow::find_keyboard_selectable() { + m_potential_keybind_widgets.clear(); + m_hashed_potential_keybind_widgets.clear(); + find_keyboard_selectable_children(m_main_widget); + + size_t buffer_length = ceil_div(m_potential_keybind_widgets.size(), ('z'-'a'))+1; + char keybind_buffer[buffer_length]; + for (size_t i = 0; i < buffer_length-1; i++) { + keybind_buffer[i] = 'a'; + } + keybind_buffer[buffer_length-1] = '\0'; + + for (auto& widget: m_potential_keybind_widgets) { + m_hashed_potential_keybind_widgets.set(String(keybind_buffer), widget); + + for (size_t i = 0; i < buffer_length-1; i++) { + if (keybind_buffer[i] >= 'z') { + keybind_buffer[i] = 'a'; + } else { + keybind_buffer[i]++; + break; + } + } + } +} + +void GWindow::find_keyboard_selectable_children(GWidget* widget) { + //Rather than painting immediately we need a step to collect all the keybinds first + widget -> for_each_child_widget([&] (auto& child) { + if (child.accepts_keyboard_select()) { + //auto rect = Rect(child.x()-5, child.y()-5, 10, 10); + m_potential_keybind_widgets.append(&child); + find_keyboard_selectable_children(&child); + } + return IterationDecision::Continue; + }); +} + bool GWindow::is_visible() const { return false; @@ -305,6 +390,10 @@ void GWindow::update(const Rect& a_rect) { if (!m_window_id) return; + + //We probably shouldn't clear the buffer on updates + //find_keyboard_selectable(); + for (auto& pending_rect : m_pending_paint_event_rects) { if (pending_rect.contains(a_rect)) { #ifdef UPDATE_COALESCING_DEBUG diff --git a/LibGUI/GWindow.h b/LibGUI/GWindow.h index 200bec1a77..1415fadd03 100644 --- a/LibGUI/GWindow.h +++ b/LibGUI/GWindow.h @@ -1,12 +1,15 @@ #pragma once #include +#include +#include #include #include #include #include #include +class GPainter; class GWidget; class GWMEvent; @@ -130,6 +133,8 @@ protected: private: virtual bool is_window() const override final { return true; } + void find_keyboard_selectable(); + void find_keyboard_selectable_children(GWidget* widget); Retained create_backing_bitmap(const Size&); void set_current_backing_bitmap(GraphicsBitmap&, bool flush_immediately = false); void flip(const Vector& dirty_rects); @@ -159,4 +164,8 @@ private: bool m_resizable { true }; bool m_fullscreen { false }; bool m_show_titlebar { true }; + bool m_keybind_mode { false }; + String m_entered_keybind; + Vector m_potential_keybind_widgets; + HashMap m_hashed_potential_keybind_widgets; };