summaryrefslogtreecommitdiff
path: root/DevTools/HackStudio
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-10-27 12:55:10 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-10-27 12:55:10 +0100
commite39b1f11f96d7e6865cb9187a8f5a72ea320a6b3 (patch)
tree44c73993a2f19cc7f3814ac9157128105f973dbb /DevTools/HackStudio
parentde2b25e2c1091be248bc9776914995fd6ab3e0ec (diff)
downloadserenity-e39b1f11f96d7e6865cb9187a8f5a72ea320a6b3.zip
HackStudio: Support multiple editors on screen
This patch adds Editor (subclass of GTextEditor) and EditorWrapper. An EditorWrapper is a composite widget that adds a little statusbar above an Editor widget. The statusbar is used for showing the filename and the current cursor position. More things can definitely be added. To get to the currently active editor, call current_editor(). You can also get to the current editor's wrapper by calling.. current_editor_wrapper(). Which editor is current is determined by which was was last focused by the user.
Diffstat (limited to 'DevTools/HackStudio')
-rw-r--r--DevTools/HackStudio/Editor.cpp9
-rw-r--r--DevTools/HackStudio/Editor.h19
-rw-r--r--DevTools/HackStudio/EditorWrapper.cpp62
-rw-r--r--DevTools/HackStudio/EditorWrapper.h24
-rw-r--r--DevTools/HackStudio/FindInFilesWidget.cpp6
-rw-r--r--DevTools/HackStudio/Makefile2
-rw-r--r--DevTools/HackStudio/main.cpp79
7 files changed, 156 insertions, 45 deletions
diff --git a/DevTools/HackStudio/Editor.cpp b/DevTools/HackStudio/Editor.cpp
new file mode 100644
index 0000000000..073658fecf
--- /dev/null
+++ b/DevTools/HackStudio/Editor.cpp
@@ -0,0 +1,9 @@
+#include "Editor.h"
+#include "EditorWrapper.h"
+
+void Editor::focusin_event(CEvent& event)
+{
+ if (on_focus)
+ on_focus();
+ GTextEditor::focusin_event(event);
+}
diff --git a/DevTools/HackStudio/Editor.h b/DevTools/HackStudio/Editor.h
new file mode 100644
index 0000000000..349984eaab
--- /dev/null
+++ b/DevTools/HackStudio/Editor.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <LibGUI/GTextEditor.h>
+
+class Editor final : public GTextEditor {
+ C_OBJECT(Editor)
+public:
+ virtual ~Editor() override {}
+
+ Function<void()> on_focus;
+
+private:
+ virtual void focusin_event(CEvent& event) override;
+
+ Editor(GWidget* parent)
+ : GTextEditor(GTextEditor::MultiLine, parent)
+ {
+ }
+};
diff --git a/DevTools/HackStudio/EditorWrapper.cpp b/DevTools/HackStudio/EditorWrapper.cpp
new file mode 100644
index 0000000000..4192e83f15
--- /dev/null
+++ b/DevTools/HackStudio/EditorWrapper.cpp
@@ -0,0 +1,62 @@
+#include "EditorWrapper.h"
+#include "Editor.h"
+#include <LibGUI/GAction.h>
+#include <LibGUI/GBoxLayout.h>
+#include <LibGUI/GInputBox.h>
+#include <LibGUI/GLabel.h>
+
+extern RefPtr<EditorWrapper> g_current_editor_wrapper;
+
+EditorWrapper::EditorWrapper(GWidget* parent)
+ : GWidget(parent)
+{
+ set_layout(make<GBoxLayout>(Orientation::Vertical));
+
+ auto label_wrapper = GWidget::construct(this);
+ label_wrapper->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
+ label_wrapper->set_preferred_size(0, 16);
+ label_wrapper->set_fill_with_background_color(true);
+ label_wrapper->set_layout(make<GBoxLayout>(Orientation::Horizontal));
+
+ m_filename_label = GLabel::construct("(Untitled)", label_wrapper);
+ m_filename_label->set_font(Font::default_bold_font());
+ m_filename_label->set_text_alignment(TextAlignment::CenterLeft);
+ m_filename_label->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
+ m_filename_label->set_preferred_size(0, 16);
+
+ m_cursor_label = GLabel::construct("(Cursor)", label_wrapper);
+ m_cursor_label->set_text_alignment(TextAlignment::CenterRight);
+ m_cursor_label->set_size_policy(SizePolicy::Fill, SizePolicy::Fixed);
+ m_cursor_label->set_preferred_size(0, 16);
+
+ m_editor = Editor::construct(this);
+ m_editor->set_ruler_visible(true);
+ m_editor->set_line_wrapping_enabled(true);
+ m_editor->set_automatic_indentation_enabled(true);
+
+ m_editor->on_cursor_change = [this] {
+ m_cursor_label->set_text(String::format("Line: %d, Column: %d", m_editor->cursor().line() + 1, m_editor->cursor().column()));
+ };
+
+ m_editor->on_focus = [this] {
+ g_current_editor_wrapper = this;
+ };
+
+ m_editor->add_custom_context_menu_action(GAction::create(
+ "Go to line...", { Mod_Ctrl, Key_L }, GraphicsBitmap::load_from_file("/res/icons/16x16/go-forward.png"), [this](auto&) {
+ auto input_box = GInputBox::construct("Line:", "Go to line", window());
+ auto result = input_box->exec();
+ if (result == GInputBox::ExecOK) {
+ bool ok;
+ auto line_number = input_box->text_value().to_uint(ok);
+ if (ok) {
+ m_editor->set_cursor(line_number - 1, 0);
+ }
+ }
+ },
+ m_editor));
+}
+
+EditorWrapper::~EditorWrapper()
+{
+}
diff --git a/DevTools/HackStudio/EditorWrapper.h b/DevTools/HackStudio/EditorWrapper.h
new file mode 100644
index 0000000000..b0b932525f
--- /dev/null
+++ b/DevTools/HackStudio/EditorWrapper.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <LibGUI/GWidget.h>
+
+class GLabel;
+class Editor;
+
+class EditorWrapper : public GWidget {
+ C_OBJECT(EditorWrapper)
+public:
+ virtual ~EditorWrapper() override;
+
+ Editor& editor() { return *m_editor; }
+ const Editor& editor() const { return *m_editor; }
+
+ GLabel& filename_label() { return *m_filename_label; }
+
+private:
+ explicit EditorWrapper(GWidget* parent = nullptr);
+
+ RefPtr<GLabel> m_filename_label;
+ RefPtr<GLabel> m_cursor_label;
+ RefPtr<Editor> m_editor;
+};
diff --git a/DevTools/HackStudio/FindInFilesWidget.cpp b/DevTools/HackStudio/FindInFilesWidget.cpp
index 666f84fc51..ec89f8866e 100644
--- a/DevTools/HackStudio/FindInFilesWidget.cpp
+++ b/DevTools/HackStudio/FindInFilesWidget.cpp
@@ -5,7 +5,7 @@
#include <LibGUI/GListView.h>
#include <LibGUI/GTextBox.h>
-extern GTextEditor& main_editor();
+extern GTextEditor& current_editor();
extern void open_file(const String&);
extern OwnPtr<Project> g_project;
@@ -71,8 +71,8 @@ FindInFilesWidget::FindInFilesWidget(GWidget* parent)
int line_number = parts[1].to_int(ok);
ASSERT(ok);
open_file(parts[0]);
- main_editor().set_cursor(line_number - 1, 0);
- main_editor().set_focus(true);
+ current_editor().set_cursor(line_number - 1, 0);
+ current_editor().set_focus(true);
};
m_button->on_click = [this](auto&) {
diff --git a/DevTools/HackStudio/Makefile b/DevTools/HackStudio/Makefile
index fa6e23fe76..f5e17f115b 100644
--- a/DevTools/HackStudio/Makefile
+++ b/DevTools/HackStudio/Makefile
@@ -7,6 +7,8 @@ OBJS = \
FindInFilesWidget.o \
ProcessStateWidget.o \
CppLexer.o \
+ Editor.o \
+ EditorWrapper.o \
main.o
APP = HackStudio
diff --git a/DevTools/HackStudio/main.cpp b/DevTools/HackStudio/main.cpp
index c1b78fd77c..9ab890e34d 100644
--- a/DevTools/HackStudio/main.cpp
+++ b/DevTools/HackStudio/main.cpp
@@ -1,4 +1,6 @@
#include "CppLexer.h"
+#include "Editor.h"
+#include "EditorWrapper.h"
#include "FindInFilesWidget.h"
#include "Project.h"
#include "TerminalWrapper.h"
@@ -10,12 +12,12 @@
#include <LibGUI/GButton.h>
#include <LibGUI/GFilePicker.h>
#include <LibGUI/GInputBox.h>
+#include <LibGUI/GLabel.h>
#include <LibGUI/GListView.h>
#include <LibGUI/GMenu.h>
#include <LibGUI/GMenuBar.h>
#include <LibGUI/GMessageBox.h>
#include <LibGUI/GSplitter.h>
-#include <LibGUI/GStatusBar.h>
#include <LibGUI/GTabWidget.h>
#include <LibGUI/GTextBox.h>
#include <LibGUI/GTextEditor.h>
@@ -25,16 +27,28 @@
#include <stdio.h>
#include <unistd.h>
+RefPtr<EditorWrapper> g_current_editor_wrapper;
+
String g_currently_open_file;
OwnPtr<Project> g_project;
RefPtr<GWindow> g_window;
RefPtr<GListView> g_project_list_view;
-RefPtr<GTextEditor> g_text_editor;
-GTextEditor& main_editor()
+void add_new_editor(GWidget& parent)
+{
+ auto wrapper = EditorWrapper::construct(&parent);
+ g_current_editor_wrapper = wrapper;
+}
+
+EditorWrapper& current_editor_wrapper()
+{
+ ASSERT(g_current_editor_wrapper);
+ return *g_current_editor_wrapper;
+}
+
+Editor& current_editor()
{
- ASSERT(g_text_editor);
- return *g_text_editor;
+ return current_editor_wrapper().editor();
}
static void build(TerminalWrapper&);
@@ -72,10 +86,8 @@ int main(int argc, char** argv)
g_project_list_view->set_preferred_size(200, 0);
auto inner_splitter = GSplitter::construct(Orientation::Vertical, outer_splitter);
- g_text_editor = GTextEditor::construct(GTextEditor::MultiLine, inner_splitter);
- g_text_editor->set_ruler_visible(true);
- g_text_editor->set_line_wrapping_enabled(true);
- g_text_editor->set_automatic_indentation_enabled(true);
+ add_new_editor(inner_splitter);
+ add_new_editor(inner_splitter);
auto new_action = GAction::create("Add new file to project...", { Mod_Ctrl, Key_N }, GraphicsBitmap::load_from_file("/res/icons/16x16/new.png"), [&](const GAction&) {
auto input_box = GInputBox::construct("Enter name of new file:", "Add new file to project", g_window);
@@ -110,19 +122,20 @@ int main(int argc, char** argv)
auto save_action = GAction::create("Save", { Mod_Ctrl, Key_S }, GraphicsBitmap::load_from_file("/res/icons/16x16/save.png"), [&](auto&) {
if (g_currently_open_file.is_empty())
return;
- g_text_editor->write_to_file(g_currently_open_file);
+ current_editor().write_to_file(g_currently_open_file);
});
toolbar->add_action(new_action);
toolbar->add_action(add_existing_file_action);
toolbar->add_action(save_action);
toolbar->add_separator();
- toolbar->add_action(g_text_editor->cut_action());
- toolbar->add_action(g_text_editor->copy_action());
- toolbar->add_action(g_text_editor->paste_action());
+
+ toolbar->add_action(GCommonActions::make_cut_action([&](auto&) { current_editor().cut_action().activate(); }));
+ toolbar->add_action(GCommonActions::make_copy_action([&](auto&) { current_editor().copy_action().activate(); }));
+ toolbar->add_action(GCommonActions::make_paste_action([&](auto&) { current_editor().paste_action().activate(); }));
toolbar->add_separator();
- toolbar->add_action(g_text_editor->undo_action());
- toolbar->add_action(g_text_editor->redo_action());
+ toolbar->add_action(GCommonActions::make_undo_action([&](auto&) { current_editor().undo_action().activate(); }));
+ toolbar->add_action(GCommonActions::make_redo_action([&](auto&) { current_editor().redo_action().activate(); }));
toolbar->add_separator();
g_project_list_view->on_activation = [&](auto& index) {
@@ -156,26 +169,6 @@ int main(int argc, char** argv)
auto terminal_wrapper = TerminalWrapper::construct(nullptr);
tab_widget->add_widget("Console", terminal_wrapper);
- auto statusbar = GStatusBar::construct(widget);
-
- g_text_editor->on_cursor_change = [&] {
- statusbar->set_text(String::format("Line: %d, Column: %d", g_text_editor->cursor().line() + 1, g_text_editor->cursor().column()));
- };
-
- g_text_editor->add_custom_context_menu_action(GAction::create(
- "Go to line...", { Mod_Ctrl, Key_L }, GraphicsBitmap::load_from_file("/res/icons/16x16/go-forward.png"), [&](auto&) {
- auto input_box = GInputBox::construct("Line:", "Go to line", g_window);
- auto result = input_box->exec();
- if (result == GInputBox::ExecOK) {
- bool ok;
- auto line_number = input_box->text_value().to_uint(ok);
- if (ok) {
- g_text_editor->set_cursor(line_number - 1, 0);
- }
- }
- },
- g_text_editor));
-
auto menubar = make<GMenuBar>();
auto app_menu = make<GMenu>("HackStudio");
app_menu->add_action(save_action);
@@ -274,7 +267,7 @@ static TextStyle style_for_token_type(CppToken::Type type)
static void rehighlight()
{
- auto text = g_text_editor->text();
+ auto text = current_editor().text();
CppLexer lexer(text);
auto tokens = lexer.lex();
@@ -291,8 +284,8 @@ static void rehighlight()
span.font = style.font;
spans.append(span);
}
- g_text_editor->set_spans(spans);
- g_text_editor->update();
+ current_editor().set_spans(spans);
+ current_editor().update();
}
void open_file(const String& filename)
@@ -303,18 +296,20 @@ void open_file(const String& filename)
return;
}
auto contents = file->read_all();
- g_text_editor->set_text(contents);
+ current_editor().set_text(contents);
if (filename.ends_with(".cpp")) {
- g_text_editor->on_change = [] { rehighlight(); };
+ current_editor().on_change = [] { rehighlight(); };
rehighlight();
} else {
- g_text_editor->on_change = nullptr;
+ current_editor().on_change = nullptr;
}
g_currently_open_file = filename;
g_window->set_title(String::format("%s - HackStudio", g_currently_open_file.characters()));
g_project_list_view->update();
- g_text_editor->set_focus(true);
+ current_editor_wrapper().filename_label().set_text(filename);
+
+ current_editor().set_focus(true);
}