mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-06-10 10:01:13 +09:00
HackStudio: Move editors inside tab widgets
This will move the editors inside a tab widget and the user will be able to add new editors as tabs as well as add new tab widgets. The user will be able to easily switch between editors as well as the tab widgets.
This commit is contained in:
parent
da714f771d
commit
23643cf21b
Notes:
sideshowbarker
2024-07-17 17:49:11 +09:00
Author: https://github.com/ry-sev
Commit: 23643cf21b
Pull-request: https://github.com/SerenityOS/serenity/pull/12938
Reviewed-by: https://github.com/itamar8910 ✅
5 changed files with 182 additions and 78 deletions
|
@ -111,11 +111,13 @@ HackStudioWidget::HackStudioWidget(String path_to_project)
|
|||
|
||||
m_editors_splitter = m_right_hand_stack->add<GUI::VerticalSplitter>();
|
||||
m_editors_splitter->layout()->set_margins({ 3, 0, 0 });
|
||||
add_new_editor(*m_editors_splitter);
|
||||
add_new_editor_tab_widget(*m_editors_splitter);
|
||||
|
||||
m_switch_to_next_editor_tab_widget = create_switch_to_next_editor_tab_widget_action();
|
||||
m_switch_to_next_editor = create_switch_to_next_editor_action();
|
||||
m_switch_to_previous_editor = create_switch_to_previous_editor_action();
|
||||
|
||||
m_remove_current_editor_tab_widget_action = create_remove_current_editor_tab_widget_action();
|
||||
m_remove_current_editor_action = create_remove_current_editor_action();
|
||||
m_open_action = create_open_action();
|
||||
m_save_action = create_save_action();
|
||||
|
@ -124,6 +126,7 @@ HackStudioWidget::HackStudioWidget(String path_to_project)
|
|||
|
||||
create_action_tab(*m_right_hand_splitter);
|
||||
|
||||
m_add_editor_tab_widget_action = create_add_editor_tab_widget_action();
|
||||
m_add_editor_action = create_add_editor_action();
|
||||
m_add_terminal_action = create_add_terminal_action();
|
||||
m_remove_current_terminal_action = create_remove_current_terminal_action();
|
||||
|
@ -358,7 +361,7 @@ bool HackStudioWidget::open_file(const String& full_filename, size_t line, size_
|
|||
m_project_tree_view->update();
|
||||
|
||||
current_editor_wrapper().set_filename(filename);
|
||||
|
||||
update_current_editor_title();
|
||||
current_editor().set_focus(true);
|
||||
|
||||
current_editor().on_cursor_change = [this] { on_cursor_change(); };
|
||||
|
@ -396,6 +399,18 @@ void HackStudioWidget::close_file_in_all_editors(String const& filename)
|
|||
m_open_files_view->model()->invalidate();
|
||||
}
|
||||
|
||||
GUI::TabWidget& HackStudioWidget::current_editor_tab_widget()
|
||||
{
|
||||
VERIFY(m_current_editor_tab_widget);
|
||||
return *m_current_editor_tab_widget;
|
||||
}
|
||||
|
||||
GUI::TabWidget const& HackStudioWidget::current_editor_tab_widget() const
|
||||
{
|
||||
VERIFY(m_current_editor_tab_widget);
|
||||
return *m_current_editor_tab_widget;
|
||||
}
|
||||
|
||||
EditorWrapper& HackStudioWidget::current_editor_wrapper()
|
||||
{
|
||||
VERIFY(m_current_editor_wrapper);
|
||||
|
@ -643,70 +658,137 @@ NonnullRefPtr<GUI::Action> HackStudioWidget::create_new_project_action()
|
|||
});
|
||||
}
|
||||
|
||||
void HackStudioWidget::add_new_editor(GUI::Widget& parent)
|
||||
NonnullRefPtr<GUI::Action> HackStudioWidget::create_remove_current_editor_tab_widget_action()
|
||||
{
|
||||
auto wrapper = EditorWrapper::construct();
|
||||
return GUI::Action::create("Switch to Next Editor Group", { Mod_Alt | Mod_Shift, Key_Backslash }, [this](auto&) {
|
||||
if (m_all_editor_tab_widgets.size() <= 1)
|
||||
return;
|
||||
auto tab_widget = m_current_editor_tab_widget;
|
||||
while (tab_widget->children().size() > 1) {
|
||||
auto active_wrapper = tab_widget->active_widget();
|
||||
tab_widget->remove_tab(*active_wrapper);
|
||||
m_all_editor_wrappers.remove_first_matching([&active_wrapper](auto& entry) { return entry == active_wrapper; });
|
||||
}
|
||||
tab_widget->on_tab_close_click(*tab_widget->active_widget());
|
||||
});
|
||||
}
|
||||
|
||||
void HackStudioWidget::add_new_editor_tab_widget(GUI::Widget& parent)
|
||||
{
|
||||
auto tab_widget = GUI::TabWidget::construct();
|
||||
if (m_action_tab_widget) {
|
||||
parent.insert_child_before(wrapper, *m_action_tab_widget);
|
||||
parent.insert_child_before(tab_widget, *m_action_tab_widget);
|
||||
} else {
|
||||
parent.add_child(wrapper);
|
||||
parent.add_child(tab_widget);
|
||||
}
|
||||
|
||||
m_current_editor_tab_widget = tab_widget;
|
||||
m_all_editor_tab_widgets.append(tab_widget);
|
||||
|
||||
tab_widget->set_reorder_allowed(true);
|
||||
|
||||
if (m_all_editor_tab_widgets.size() > 1) {
|
||||
for (auto& widget : m_all_editor_tab_widgets)
|
||||
widget.set_close_button_enabled(true);
|
||||
}
|
||||
|
||||
tab_widget->on_change = [&](auto& widget) {
|
||||
auto& wrapper = static_cast<EditorWrapper&>(widget);
|
||||
set_current_editor_wrapper(wrapper);
|
||||
current_editor().set_focus(true);
|
||||
};
|
||||
|
||||
tab_widget->on_middle_click = [](auto& widget) {
|
||||
auto& wrapper = static_cast<EditorWrapper&>(widget);
|
||||
wrapper.on_tab_close_request(wrapper);
|
||||
};
|
||||
|
||||
tab_widget->on_tab_close_click = [](auto& widget) {
|
||||
auto& wrapper = static_cast<EditorWrapper&>(widget);
|
||||
wrapper.on_tab_close_request(wrapper);
|
||||
};
|
||||
|
||||
add_new_editor(*m_current_editor_tab_widget);
|
||||
}
|
||||
|
||||
void HackStudioWidget::add_new_editor(GUI::TabWidget& parent)
|
||||
{
|
||||
auto& wrapper = parent.add_tab<EditorWrapper>("(Untitled)");
|
||||
parent.set_active_widget(&wrapper);
|
||||
if (parent.children().size() > 1 || m_all_editor_tab_widgets.size() > 1)
|
||||
parent.set_close_button_enabled(true);
|
||||
|
||||
auto previous_editor_wrapper = m_current_editor_wrapper;
|
||||
m_current_editor_wrapper = wrapper;
|
||||
m_all_editor_wrappers.append(wrapper);
|
||||
wrapper->editor().set_focus(true);
|
||||
wrapper->editor().set_font(*m_editor_font);
|
||||
wrapper->set_project_root(m_project->root_path());
|
||||
wrapper->editor().on_cursor_change = [this] { on_cursor_change(); };
|
||||
wrapper->on_change = [this] { update_gml_preview(); };
|
||||
wrapper.editor().set_focus(true);
|
||||
wrapper.editor().set_font(*m_editor_font);
|
||||
wrapper.set_project_root(m_project->root_path());
|
||||
wrapper.editor().on_cursor_change = [this] { on_cursor_change(); };
|
||||
wrapper.on_change = [this] { update_gml_preview(); };
|
||||
set_edit_mode(EditMode::Text);
|
||||
if (previous_editor_wrapper && previous_editor_wrapper->editor().editing_engine()->is_regular())
|
||||
wrapper->editor().set_editing_engine(make<GUI::RegularEditingEngine>());
|
||||
wrapper.editor().set_editing_engine(make<GUI::RegularEditingEngine>());
|
||||
else if (previous_editor_wrapper && previous_editor_wrapper->editor().editing_engine()->is_vim())
|
||||
wrapper->editor().set_editing_engine(make<GUI::VimEditingEngine>());
|
||||
wrapper.editor().set_editing_engine(make<GUI::VimEditingEngine>());
|
||||
else
|
||||
wrapper->editor().set_editing_engine(make<GUI::RegularEditingEngine>());
|
||||
wrapper.editor().set_editing_engine(make<GUI::RegularEditingEngine>());
|
||||
|
||||
wrapper.on_tab_close_request = [this, &parent](auto& tab) {
|
||||
parent.deferred_invoke([this, &parent, &tab] {
|
||||
set_current_editor_wrapper(tab);
|
||||
parent.remove_tab(tab);
|
||||
m_all_editor_wrappers.remove_first_matching([&tab](auto& entry) { return entry == &tab; });
|
||||
if (parent.children().is_empty()) {
|
||||
m_switch_to_next_editor_tab_widget->activate();
|
||||
m_editors_splitter->remove_child(parent);
|
||||
m_all_editor_tab_widgets.remove_first_matching([&parent](auto& entry) { return entry == &parent; });
|
||||
if (m_current_editor_tab_widget->children().size() == 1)
|
||||
m_current_editor_tab_widget->set_close_button_enabled(false);
|
||||
}
|
||||
if (parent.children().size() == 1 && m_all_editor_tab_widgets.size() <= 1)
|
||||
parent.set_close_button_enabled(false);
|
||||
update_actions();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
NonnullRefPtr<GUI::Action> HackStudioWidget::create_switch_to_next_editor_tab_widget_action()
|
||||
{
|
||||
return GUI::Action::create("Switch to Next Editor Group", { Mod_Ctrl | Mod_Shift, Key_T }, [this](auto&) {
|
||||
if (m_all_editor_tab_widgets.size() <= 1)
|
||||
return;
|
||||
Vector<GUI::TabWidget&> tab_widgets;
|
||||
m_editors_splitter->for_each_child_of_type<GUI::TabWidget>([&tab_widgets](auto& child) {
|
||||
tab_widgets.append(child);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
for (size_t i = 0; i < tab_widgets.size(); ++i) {
|
||||
if (m_current_editor_tab_widget.ptr() == &tab_widgets[i]) {
|
||||
if (i == tab_widgets.size() - 1)
|
||||
m_current_editor_tab_widget = tab_widgets[0];
|
||||
else
|
||||
m_current_editor_tab_widget = tab_widgets[i + 1];
|
||||
auto wrapper = static_cast<EditorWrapper*>(m_current_editor_tab_widget->active_widget());
|
||||
set_current_editor_wrapper(wrapper);
|
||||
current_editor().set_focus(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
NonnullRefPtr<GUI::Action> HackStudioWidget::create_switch_to_next_editor_action()
|
||||
{
|
||||
return GUI::Action::create("Switch to &Next Editor", { Mod_Ctrl, Key_E }, [this](auto&) {
|
||||
if (m_all_editor_wrappers.size() <= 1)
|
||||
return;
|
||||
Vector<EditorWrapper&> wrappers;
|
||||
m_editors_splitter->for_each_child_of_type<EditorWrapper>([&wrappers](auto& child) {
|
||||
wrappers.append(child);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
for (size_t i = 0; i < wrappers.size(); ++i) {
|
||||
if (m_current_editor_wrapper.ptr() == &wrappers[i]) {
|
||||
if (i == wrappers.size() - 1)
|
||||
wrappers[0].editor().set_focus(true);
|
||||
else
|
||||
wrappers[i + 1].editor().set_focus(true);
|
||||
}
|
||||
}
|
||||
m_current_editor_tab_widget->activate_next_tab();
|
||||
});
|
||||
}
|
||||
|
||||
NonnullRefPtr<GUI::Action> HackStudioWidget::create_switch_to_previous_editor_action()
|
||||
{
|
||||
return GUI::Action::create("Switch to &Previous Editor", { Mod_Ctrl | Mod_Shift, Key_E }, [this](auto&) {
|
||||
if (m_all_editor_wrappers.size() <= 1)
|
||||
return;
|
||||
Vector<EditorWrapper&> wrappers;
|
||||
m_editors_splitter->for_each_child_of_type<EditorWrapper>([&wrappers](auto& child) {
|
||||
wrappers.append(child);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
for (int i = wrappers.size() - 1; i >= 0; --i) {
|
||||
if (m_current_editor_wrapper.ptr() == &wrappers[i]) {
|
||||
if (i == 0)
|
||||
wrappers.last().editor().set_focus(true);
|
||||
else
|
||||
wrappers[i - 1].editor().set_focus(true);
|
||||
}
|
||||
}
|
||||
m_current_editor_tab_widget->activate_previous_tab();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -715,10 +797,10 @@ NonnullRefPtr<GUI::Action> HackStudioWidget::create_remove_current_editor_action
|
|||
return GUI::Action::create("&Remove Current Editor", { Mod_Alt | Mod_Shift, Key_E }, Gfx::Bitmap::try_load_from_file("/res/icons/hackstudio/remove-editor.png").release_value_but_fixme_should_propagate_errors(), [this](auto&) {
|
||||
if (m_all_editor_wrappers.size() <= 1)
|
||||
return;
|
||||
auto wrapper = m_current_editor_wrapper;
|
||||
m_switch_to_next_editor->activate();
|
||||
m_editors_splitter->remove_child(*wrapper);
|
||||
m_all_editor_wrappers.remove_first_matching([&wrapper](auto& entry) { return entry == wrapper.ptr(); });
|
||||
auto tab_widget = m_current_editor_tab_widget;
|
||||
auto* active_wrapper = tab_widget->active_widget();
|
||||
VERIFY(active_wrapper);
|
||||
tab_widget->on_tab_close_click(*active_wrapper);
|
||||
update_actions();
|
||||
});
|
||||
}
|
||||
|
@ -782,6 +864,7 @@ NonnullRefPtr<GUI::Action> HackStudioWidget::create_save_as_action()
|
|||
m_open_files_vector.remove_all_matching([&old_filename](auto const& element) { return element == old_filename; });
|
||||
|
||||
update_window_title();
|
||||
update_current_editor_title();
|
||||
|
||||
m_project->model().invalidate();
|
||||
update_tree_view();
|
||||
|
@ -804,12 +887,21 @@ NonnullRefPtr<GUI::Action> HackStudioWidget::create_remove_current_terminal_acti
|
|||
});
|
||||
}
|
||||
|
||||
NonnullRefPtr<GUI::Action> HackStudioWidget::create_add_editor_tab_widget_action()
|
||||
{
|
||||
return GUI::Action::create("Add New Editor Group", { Mod_Ctrl | Mod_Alt, Key_Backslash },
|
||||
[this](auto&) {
|
||||
add_new_editor_tab_widget(*m_editors_splitter);
|
||||
update_actions();
|
||||
});
|
||||
}
|
||||
|
||||
NonnullRefPtr<GUI::Action> HackStudioWidget::create_add_editor_action()
|
||||
{
|
||||
return GUI::Action::create("Add New &Editor", { Mod_Ctrl | Mod_Alt, Key_E },
|
||||
Gfx::Bitmap::try_load_from_file("/res/icons/hackstudio/add-editor.png").release_value_but_fixme_should_propagate_errors(),
|
||||
[this](auto&) {
|
||||
add_new_editor(*m_editors_splitter);
|
||||
add_new_editor(*m_current_editor_tab_widget);
|
||||
update_actions();
|
||||
});
|
||||
}
|
||||
|
@ -1003,11 +1095,19 @@ Project& HackStudioWidget::project()
|
|||
return *m_project;
|
||||
}
|
||||
|
||||
void HackStudioWidget::set_current_editor_tab_widget(RefPtr<GUI::TabWidget> tab_widget)
|
||||
{
|
||||
m_current_editor_tab_widget = tab_widget;
|
||||
}
|
||||
|
||||
void HackStudioWidget::set_current_editor_wrapper(RefPtr<EditorWrapper> editor_wrapper)
|
||||
{
|
||||
m_current_editor_wrapper = editor_wrapper;
|
||||
update_window_title();
|
||||
update_current_editor_title();
|
||||
update_tree_view();
|
||||
set_current_editor_tab_widget(static_cast<GUI::TabWidget*>(m_current_editor_wrapper->parent()));
|
||||
update_statusbar();
|
||||
}
|
||||
|
||||
void HackStudioWidget::file_renamed(String const& old_name, String const& new_name)
|
||||
|
@ -1034,6 +1134,9 @@ void HackStudioWidget::file_renamed(String const& old_name, String const& new_na
|
|||
VERIFY(!m_file_watcher->remove_watch(old_name).is_error());
|
||||
VERIFY(!m_file_watcher->add_watch(new_name, Core::FileWatcherEvent::Type::Deleted).is_error());
|
||||
}
|
||||
|
||||
update_window_title();
|
||||
update_current_editor_title();
|
||||
}
|
||||
|
||||
void HackStudioWidget::configure_project_tree_view()
|
||||
|
@ -1331,6 +1434,7 @@ void HackStudioWidget::create_view_menu(GUI::Window& window)
|
|||
view_menu.add_action(*m_editor_font_action);
|
||||
|
||||
view_menu.add_separator();
|
||||
view_menu.add_action(*m_add_editor_tab_widget_action);
|
||||
view_menu.add_action(*m_add_editor_action);
|
||||
view_menu.add_action(*m_remove_current_editor_action);
|
||||
view_menu.add_action(*m_add_terminal_action);
|
||||
|
@ -1412,7 +1516,7 @@ void HackStudioWidget::close_current_project()
|
|||
m_all_editor_wrappers.clear();
|
||||
m_open_files.clear();
|
||||
m_open_files_vector.clear();
|
||||
add_new_editor(*m_editors_splitter);
|
||||
add_new_editor(*m_current_editor_tab_widget);
|
||||
m_find_in_files_widget->reset();
|
||||
m_todo_entries_widget->clear();
|
||||
m_terminal_wrapper->clear_including_history();
|
||||
|
@ -1470,7 +1574,12 @@ void HackStudioWidget::update_tree_view()
|
|||
|
||||
void HackStudioWidget::update_window_title()
|
||||
{
|
||||
window()->set_title(String::formatted("{} - {} - Hack Studio", m_current_editor_wrapper->filename_label().text(), m_project->name()));
|
||||
window()->set_title(String::formatted("{} - {} - Hack Studio", m_current_editor_wrapper->filename_title(), m_project->name()));
|
||||
}
|
||||
|
||||
void HackStudioWidget::update_current_editor_title()
|
||||
{
|
||||
current_editor_tab_widget().set_tab_title(current_editor_wrapper(), current_editor_wrapper().filename_title());
|
||||
}
|
||||
|
||||
void HackStudioWidget::on_cursor_change()
|
||||
|
@ -1614,5 +1723,4 @@ bool HackStudioWidget::semantic_syntax_highlighting_is_enabled() const
|
|||
{
|
||||
return m_toggle_semantic_highlighting_action->is_checked();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue