diff --git a/Applications/IRCClient/IRCAppWindow.cpp b/Applications/IRCClient/IRCAppWindow.cpp index e70fe7a2a6..e446a6eee7 100644 --- a/Applications/IRCClient/IRCAppWindow.cpp +++ b/Applications/IRCClient/IRCAppWindow.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include IRCAppWindow::IRCAppWindow() @@ -49,23 +49,26 @@ void IRCAppWindow::setup_client() void IRCAppWindow::setup_actions() { - m_join_action = GAction::create("Join channel", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-join.rgb", { 16, 16 }), [] (auto&) { - printf("FIXME: Implement join action\n"); + m_join_action = GAction::create("Join channel", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-join.rgb", { 16, 16 }), [&] (auto&) { + GInputBox input_box("Enter nickname:", "Join channel"); + if (input_box.exec() == GInputBox::ExecOK) + m_client.handle_join_action(input_box.text_value()); }); m_part_action = GAction::create("Part from channel", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-part.rgb", { 16, 16 }), [] (auto&) { printf("FIXME: Implement part action\n"); }); - m_whois_action = GAction::create("Whois user", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-whois.rgb", { 16, 16 }), [] (auto&) { - printf("FIXME: Implement whois action\n"); - GMessageBox box("Who would you like to WHOIS?", "Whois user"); - int code = box.exec(); - dbgprintf("GMessageBox::exec() returned %d\n", code); + m_whois_action = GAction::create("Whois user", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-whois.rgb", { 16, 16 }), [&] (auto&) { + GInputBox input_box("Enter nickname:", "IRC WHOIS lookup"); + if (input_box.exec() == GInputBox::ExecOK) + m_client.handle_whois_action(input_box.text_value()); }); - m_open_query_action = GAction::create("Open query", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-open-query.rgb", { 16, 16 }), [] (auto&) { - printf("FIXME: Implement open-query action\n"); + m_open_query_action = GAction::create("Open query", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-open-query.rgb", { 16, 16 }), [&] (auto&) { + GInputBox input_box("Enter nickname:", "Open IRC query with..."); + if (input_box.exec() == GInputBox::ExecOK) + m_client.handle_open_query_action(input_box.text_value()); }); m_close_query_action = GAction::create("Close query", GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/16x16/irc-close-query.rgb", { 16, 16 }), [] (auto&) { diff --git a/Applications/IRCClient/IRCClient.cpp b/Applications/IRCClient/IRCClient.cpp index 5892b7771a..25ad440eeb 100644 --- a/Applications/IRCClient/IRCClient.cpp +++ b/Applications/IRCClient/IRCClient.cpp @@ -554,3 +554,29 @@ void IRCClient::handle_user_command(const String& input) return; } } + +void IRCClient::handle_whois_action(const String& nick) +{ + send_whois(nick); +} + +void IRCClient::handle_open_query_action(const String& nick) +{ + ensure_query(nick); +} + +void IRCClient::handle_close_query_action(const String& nick) +{ + m_queries.remove(nick); + m_client_window_list_model->update(); +} + +void IRCClient::handle_join_action(const String& channel) +{ + join_channel(channel); +} + +void IRCClient::handle_part_action(const String& channel) +{ + part_channel(channel); +} diff --git a/Applications/IRCClient/IRCClient.h b/Applications/IRCClient/IRCClient.h index 01f871d59c..2dea2281a6 100644 --- a/Applications/IRCClient/IRCClient.h +++ b/Applications/IRCClient/IRCClient.h @@ -57,6 +57,12 @@ public: void handle_user_input_in_query(const String& query_name, const String&); void handle_user_input_in_server(const String&); + void handle_whois_action(const String&); + void handle_open_query_action(const String&); + void handle_close_query_action(const String&); + void handle_join_action(const String&); + void handle_part_action(const String&); + IRCQuery& ensure_query(const String& name); IRCChannel& ensure_channel(const String& name); diff --git a/LibGUI/GButton.cpp b/LibGUI/GButton.cpp index 9023aaac19..62cda2255e 100644 --- a/LibGUI/GButton.cpp +++ b/LibGUI/GButton.cpp @@ -70,6 +70,12 @@ void GButton::mousedown_event(GMouseEvent& event) GWidget::mousedown_event(event); } +void GButton::click() +{ + if (on_click) + on_click(*this); +} + void GButton::mouseup_event(GMouseEvent& event) { #ifdef GBUTTON_DEBUG @@ -81,10 +87,8 @@ void GButton::mouseup_event(GMouseEvent& event) m_tracking_cursor = false; set_global_cursor_tracking(false); update(); - if (was_being_pressed) { - if (on_click) - on_click(*this); - } + if (was_being_pressed) + click(); } GWidget::mouseup_event(event); } diff --git a/LibGUI/GButton.h b/LibGUI/GButton.h index 3e76476d15..4edb2c719e 100644 --- a/LibGUI/GButton.h +++ b/LibGUI/GButton.h @@ -23,6 +23,8 @@ public: void set_button_style(GButtonStyle style) { m_button_style = style; } GButtonStyle button_style() const { return m_button_style; } + void click(); + virtual const char* class_name() const override { return "GButton"; } private: diff --git a/LibGUI/GInputBox.cpp b/LibGUI/GInputBox.cpp new file mode 100644 index 0000000000..ed37aeded5 --- /dev/null +++ b/LibGUI/GInputBox.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include + +GInputBox::GInputBox(const String& prompt, const String& title, GObject* parent) + : GDialog(parent) + , m_prompt(prompt) +{ + set_title(title); + build(); +} + +GInputBox::~GInputBox() +{ +} + +void GInputBox::build() +{ + auto* widget = new GWidget; + set_main_widget(widget); + + int text_width = widget->font().width(m_prompt); + + set_rect(x(), y(), text_width + 80, 120); + + widget->set_layout(make(Orientation::Vertical)); + widget->set_fill_with_background_color(true); + + widget->layout()->set_margins({ 8, 8, 8, 8 }); + widget->layout()->set_spacing(8); + + auto* label = new GLabel(m_prompt, widget); + label->set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed); + label->set_preferred_size({ text_width, 16 }); + + auto* text_editor = new GTextEditor(GTextEditor::SingleLine, widget); + text_editor->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + text_editor->set_preferred_size({ 0, 16 }); + + auto* button_container_outer = new GWidget(widget); + button_container_outer->set_layout(make(Orientation::Vertical)); + + auto* button_container_inner = new GWidget(button_container_outer); + button_container_inner->set_layout(make(Orientation::Horizontal)); + button_container_inner->layout()->set_spacing(8); + + auto* cancel_button = new GButton(button_container_inner); + cancel_button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + cancel_button->set_preferred_size({ 0, 16 }); + cancel_button->set_caption("Cancel"); + cancel_button->on_click = [&] (auto&) { + fprintf(stderr, "GInputBox: Cancel button clicked\n"); + done(1); + }; + + auto* ok_button = new GButton(button_container_inner); + ok_button->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed); + ok_button->set_preferred_size({ 0, 16 }); + ok_button->set_caption("OK"); + ok_button->on_click = [&] (auto&) { + fprintf(stderr, "GInputBox: OK button clicked\n"); + m_text_value = text_editor->text(); + done(0); + }; + + text_editor->on_return_pressed = [&] (auto&) { + ok_button->click(); + }; + text_editor->on_escape_pressed = [&] (auto&) { + cancel_button->click(); + }; + text_editor->set_focus(true); +} diff --git a/LibGUI/GInputBox.h b/LibGUI/GInputBox.h new file mode 100644 index 0000000000..eb95d8279d --- /dev/null +++ b/LibGUI/GInputBox.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +class GInputBox : public GDialog { +public: + enum ExecResult { ExecOK = 0, ExecCancel = 1 }; + + explicit GInputBox(const String& prompt, const String& title, GObject* parent = nullptr); + virtual ~GInputBox() override; + + String text_value() const { return m_text_value; } + +private: + void build(); + String m_prompt; + String m_text_value; +}; diff --git a/LibGUI/GMessageBox.h b/LibGUI/GMessageBox.h index fbbc371fba..f0b7a6d84b 100644 --- a/LibGUI/GMessageBox.h +++ b/LibGUI/GMessageBox.h @@ -7,10 +7,8 @@ public: explicit GMessageBox(const String& text, const String& title, GObject* parent = nullptr); virtual ~GMessageBox() override; - String text() const { return m_text; } - +private: void build(); -private: String m_text; }; diff --git a/LibGUI/GTextEditor.cpp b/LibGUI/GTextEditor.cpp index f8d1c02a10..1b26201058 100644 --- a/LibGUI/GTextEditor.cpp +++ b/LibGUI/GTextEditor.cpp @@ -17,6 +17,7 @@ GTextEditor::GTextEditor(Type type, GWidget* parent) m_ruler_visible = is_multi_line(); set_font(GFontDatabase::the().get_by_name("Csilla Thin")); m_lines.append(make()); + m_cursor = { 0, 0 }; } GTextEditor::~GTextEditor() @@ -227,6 +228,11 @@ void GTextEditor::toggle_selection_if_needed_for_event(const GKeyEvent& event) void GTextEditor::keydown_event(GKeyEvent& event) { + if (event.key() == KeyCode::Key_Escape) { + if (on_escape_pressed) + on_escape_pressed(*this); + return; + } if (event.key() == KeyCode::Key_Up) { if (m_cursor.line() > 0) { int new_line = m_cursor.line() - 1; diff --git a/LibGUI/GTextEditor.h b/LibGUI/GTextEditor.h index b4eb35b5d3..9b1ddcf904 100644 --- a/LibGUI/GTextEditor.h +++ b/LibGUI/GTextEditor.h @@ -95,6 +95,7 @@ public: void paste(); Function on_return_pressed; + Function on_escape_pressed; virtual const char* class_name() const override { return "GTextEditor"; } diff --git a/LibGUI/Makefile b/LibGUI/Makefile index 025391745a..d0479b07bf 100644 --- a/LibGUI/Makefile +++ b/LibGUI/Makefile @@ -43,6 +43,7 @@ LIBGUI_OBJS = \ GSocket.o \ GTCPSocket.o \ GMessageBox.o \ + GInputBox.o \ GDialog.o \ GWindow.o