1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-18 19:05:06 +00:00
serenity/Userland/Applications/TerminalSettings/TerminalSettingsWidget.cpp
DexesTTP 7ceeb74535 AK: Use an enum instead of a bool for String::replace(all_occurences)
This commit has no behavior changes.

In particular, this does not fix any of the wrong uses of the previous
default parameter (which used to be 'false', meaning "only replace the
first occurence in the string"). It simply replaces the default uses by
String::replace(..., ReplaceMode::FirstOnly), leaving them incorrect.
2022-07-06 11:12:45 +02:00

302 lines
13 KiB
C++

/*
* Copyright (c) 2018-2021, the SerenityOS developers.
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "TerminalSettingsWidget.h"
#include <AK/Assertions.h>
#include <AK/JsonObject.h>
#include <AK/QuickSort.h>
#include <Applications/TerminalSettings/TerminalSettingsMainGML.h>
#include <Applications/TerminalSettings/TerminalSettingsViewGML.h>
#include <LibConfig/Client.h>
#include <LibCore/DirIterator.h>
#include <LibCore/File.h>
#include <LibGUI/Application.h>
#include <LibGUI/Button.h>
#include <LibGUI/CheckBox.h>
#include <LibGUI/FontPicker.h>
#include <LibGUI/ItemListModel.h>
#include <LibGUI/Label.h>
#include <LibGUI/MessageBox.h>
#include <LibGUI/OpacitySlider.h>
#include <LibGUI/RadioButton.h>
#include <LibGUI/SpinBox.h>
#include <LibGUI/Widget.h>
#include <LibGfx/Font/Font.h>
#include <LibGfx/Font/FontDatabase.h>
#include <LibKeyboard/CharacterMap.h>
#include <LibVT/TerminalWidget.h>
#include <spawn.h>
TerminalSettingsMainWidget::TerminalSettingsMainWidget()
{
load_from_gml(terminal_settings_main_gml);
auto& beep_bell_radio = *find_descendant_of_type_named<GUI::RadioButton>("beep_bell_radio");
auto& visual_bell_radio = *find_descendant_of_type_named<GUI::RadioButton>("visual_bell_radio");
auto& no_bell_radio = *find_descendant_of_type_named<GUI::RadioButton>("no_bell_radio");
m_bell_mode = parse_bell(Config::read_string("Terminal", "Window", "Bell"));
m_original_bell_mode = m_bell_mode;
switch (m_bell_mode) {
case VT::TerminalWidget::BellMode::Visible:
visual_bell_radio.set_checked(true, GUI::AllowCallback::No);
break;
case VT::TerminalWidget::BellMode::AudibleBeep:
beep_bell_radio.set_checked(true, GUI::AllowCallback::No);
break;
case VT::TerminalWidget::BellMode::Disabled:
no_bell_radio.set_checked(true, GUI::AllowCallback::No);
break;
}
beep_bell_radio.on_checked = [this](bool) {
m_bell_mode = VT::TerminalWidget::BellMode::AudibleBeep;
Config::write_string("Terminal", "Window", "Bell", stringify_bell(m_bell_mode));
set_modified(true);
};
visual_bell_radio.on_checked = [this](bool) {
m_bell_mode = VT::TerminalWidget::BellMode::Visible;
Config::write_string("Terminal", "Window", "Bell", stringify_bell(m_bell_mode));
set_modified(true);
};
no_bell_radio.on_checked = [this](bool) {
m_bell_mode = VT::TerminalWidget::BellMode::Disabled;
Config::write_string("Terminal", "Window", "Bell", stringify_bell(m_bell_mode));
set_modified(true);
};
m_max_history_size = Config::read_i32("Terminal", "Terminal", "MaxHistorySize");
m_original_max_history_size = m_max_history_size;
auto& history_size_spinbox = *find_descendant_of_type_named<GUI::SpinBox>("history_size_spinbox");
history_size_spinbox.set_value(m_max_history_size, GUI::AllowCallback::No);
history_size_spinbox.on_change = [this](int value) {
m_max_history_size = value;
Config::write_i32("Terminal", "Terminal", "MaxHistorySize", static_cast<i32>(m_max_history_size));
set_modified(true);
};
m_show_scrollbar = Config::read_bool("Terminal", "Terminal", "ShowScrollBar", true);
m_orignal_show_scrollbar = m_show_scrollbar;
auto& show_scrollbar_checkbox = *find_descendant_of_type_named<GUI::CheckBox>("terminal_show_scrollbar");
show_scrollbar_checkbox.on_checked = [&](bool show_scrollbar) {
m_show_scrollbar = show_scrollbar;
Config::write_bool("Terminal", "Terminal", "ShowScrollBar", show_scrollbar);
set_modified(true);
};
show_scrollbar_checkbox.set_checked(m_show_scrollbar, GUI::AllowCallback::No);
m_confirm_close = Config::read_bool("Terminal", "Terminal", "ConfirmClose", true);
m_orignal_confirm_close = m_confirm_close;
auto& confirm_close_checkbox = *find_descendant_of_type_named<GUI::CheckBox>("terminal_confirm_close");
confirm_close_checkbox.on_checked = [&](bool confirm_close) {
m_confirm_close = confirm_close;
Config::write_bool("Terminal", "Terminal", "ConfirmClose", confirm_close);
set_modified(true);
};
confirm_close_checkbox.set_checked(m_confirm_close, GUI::AllowCallback::No);
}
TerminalSettingsViewWidget::TerminalSettingsViewWidget()
{
load_from_gml(terminal_settings_view_gml);
auto& slider = *find_descendant_of_type_named<GUI::OpacitySlider>("background_opacity_slider");
m_opacity = Config::read_i32("Terminal", "Window", "Opacity");
m_original_opacity = m_opacity;
slider.set_value(m_opacity);
slider.on_change = [this](int value) {
m_opacity = value;
Config::write_i32("Terminal", "Window", "Opacity", static_cast<i32>(m_opacity));
set_modified(true);
};
m_color_scheme = Config::read_string("Terminal", "Window", "ColorScheme");
m_original_color_scheme = m_color_scheme;
// The settings window takes a reference to this vector, so it needs to outlive this scope.
// As long as we ensure that only one settings window may be open at a time (which we do),
// this should cause no problems.
static Vector<String> color_scheme_names;
color_scheme_names.clear();
Core::DirIterator iterator("/res/terminal-colors", Core::DirIterator::SkipParentAndBaseDir);
while (iterator.has_next()) {
auto path = iterator.next_path();
color_scheme_names.append(path.replace(".ini", "", ReplaceMode::FirstOnly));
}
quick_sort(color_scheme_names);
auto& color_scheme_combo = *find_descendant_of_type_named<GUI::ComboBox>("color_scheme_combo");
color_scheme_combo.set_only_allow_values_from_model(true);
color_scheme_combo.set_model(*GUI::ItemListModel<String>::create(color_scheme_names));
color_scheme_combo.set_selected_index(color_scheme_names.find_first_index(m_color_scheme).value());
color_scheme_combo.set_enabled(color_scheme_names.size() > 1);
color_scheme_combo.on_change = [&](auto&, const GUI::ModelIndex& index) {
m_color_scheme = index.data().as_string();
Config::write_string("Terminal", "Window", "ColorScheme", m_color_scheme);
set_modified(true);
};
auto& font_button = *find_descendant_of_type_named<GUI::Button>("terminal_font_button");
auto& font_text = *find_descendant_of_type_named<GUI::Label>("terminal_font_label");
auto font_name = Config::read_string("Terminal", "Text", "Font");
if (font_name.is_empty())
m_font = Gfx::FontDatabase::the().default_fixed_width_font();
else
m_font = Gfx::FontDatabase::the().get_by_name(font_name);
m_original_font = m_font;
font_text.set_text(m_font->human_readable_name());
font_text.set_font(m_font);
font_button.on_click = [&](auto) {
auto picker = GUI::FontPicker::construct(window(), m_font.ptr(), true);
if (picker->exec() == GUI::Dialog::ExecResult::OK) {
m_font = picker->font();
font_text.set_text(m_font->human_readable_name());
font_text.set_font(m_font);
Config::write_string("Terminal", "Text", "Font", m_font->qualified_name());
set_modified(true);
}
};
auto& font_selection = *find_descendant_of_type_named<GUI::Widget>("terminal_font_selection");
auto& use_default_font_button = *find_descendant_of_type_named<GUI::CheckBox>("terminal_font_defaulted");
use_default_font_button.on_checked = [&, font_name](bool use_default_font) {
if (use_default_font) {
font_selection.set_enabled(false);
m_font = Gfx::FontDatabase::the().default_fixed_width_font();
font_text.set_text(m_font->human_readable_name());
font_text.set_font(m_font);
Config::write_string("Terminal", "Text", "Font", m_font->qualified_name());
} else {
font_selection.set_enabled(true);
m_font = font_name.is_empty()
? Gfx::FontDatabase::the().default_fixed_width_font()
: Gfx::FontDatabase::the().get_by_name(font_name);
Config::write_string("Terminal", "Text", "Font", m_font->qualified_name());
}
set_modified(true);
};
// The "use default font" setting is not stored itself - we automatically set it if the actually present font is the default,
// whether that was filled in by the above defaulting code or by the user.
use_default_font_button.set_checked(m_font == Gfx::FontDatabase::the().default_fixed_width_font(), GUI::AllowCallback::No);
font_selection.set_enabled(!use_default_font_button.is_checked());
auto& terminal_cursor_block = *find_descendant_of_type_named<GUI::RadioButton>("terminal_cursor_block");
auto& terminal_cursor_underline = *find_descendant_of_type_named<GUI::RadioButton>("terminal_cursor_underline");
auto& terminal_cursor_bar = *find_descendant_of_type_named<GUI::RadioButton>("terminal_cursor_bar");
auto& terminal_cursor_blinking = *find_descendant_of_type_named<GUI::CheckBox>("terminal_cursor_blinking");
m_cursor_shape = VT::TerminalWidget::parse_cursor_shape(Config::read_string("Terminal", "Cursor", "Shape")).value_or(VT::CursorShape::Block);
m_original_cursor_shape = m_cursor_shape;
m_cursor_is_blinking_set = Config::read_bool("Terminal", "Cursor", "Blinking", true);
m_original_cursor_is_blinking_set = m_cursor_is_blinking_set;
switch (m_cursor_shape) {
case VT::CursorShape::Underline:
terminal_cursor_underline.set_checked(true);
break;
case VT::CursorShape::Bar:
terminal_cursor_bar.set_checked(true);
break;
default:
terminal_cursor_block.set_checked(true);
}
terminal_cursor_blinking.on_checked = [&](bool is_checked) {
set_modified(true);
m_cursor_is_blinking_set = is_checked;
Config::write_bool("Terminal", "Cursor", "Blinking", is_checked);
};
terminal_cursor_blinking.set_checked(Config::read_bool("Terminal", "Cursor", "Blinking", true));
terminal_cursor_block.on_checked = [&](bool) {
set_modified(true);
m_cursor_shape = VT::CursorShape::Block;
Config::write_string("Terminal", "Cursor", "Shape", "Block");
};
terminal_cursor_block.set_checked(Config::read_string("Terminal", "Cursor", "Shape") == "Block");
terminal_cursor_underline.on_checked = [&](bool) {
set_modified(true);
m_cursor_shape = VT::CursorShape::Underline;
Config::write_string("Terminal", "Cursor", "Shape", "Underline");
};
terminal_cursor_underline.set_checked(Config::read_string("Terminal", "Cursor", "Shape") == "Underline");
terminal_cursor_bar.on_checked = [&](bool) {
set_modified(true);
m_cursor_shape = VT::CursorShape::Bar;
Config::write_string("Terminal", "Cursor", "Shape", "Bar");
};
terminal_cursor_bar.set_checked(Config::read_string("Terminal", "Cursor", "Shape") == "Bar");
}
VT::TerminalWidget::BellMode TerminalSettingsMainWidget::parse_bell(StringView bell_string)
{
if (bell_string == "AudibleBeep")
return VT::TerminalWidget::BellMode::AudibleBeep;
if (bell_string == "Visible")
return VT::TerminalWidget::BellMode::Visible;
if (bell_string == "Disabled")
return VT::TerminalWidget::BellMode::Disabled;
VERIFY_NOT_REACHED();
}
String TerminalSettingsMainWidget::stringify_bell(VT::TerminalWidget::BellMode bell_mode)
{
if (bell_mode == VT::TerminalWidget::BellMode::AudibleBeep)
return "AudibleBeep";
if (bell_mode == VT::TerminalWidget::BellMode::Disabled)
return "Disabled";
if (bell_mode == VT::TerminalWidget::BellMode::Visible)
return "Visible";
VERIFY_NOT_REACHED();
}
void TerminalSettingsMainWidget::apply_settings()
{
m_original_max_history_size = m_max_history_size;
m_orignal_show_scrollbar = m_show_scrollbar;
m_original_bell_mode = m_bell_mode;
m_orignal_confirm_close = m_confirm_close;
write_back_settings();
}
void TerminalSettingsMainWidget::write_back_settings() const
{
Config::write_i32("Terminal", "Terminal", "MaxHistorySize", static_cast<i32>(m_original_max_history_size));
Config::write_bool("Terminal", "Terminal", "ShowScrollBar", m_orignal_show_scrollbar);
Config::write_bool("Terminal", "Terminal", "ConfirmClose", m_orignal_confirm_close);
Config::write_string("Terminal", "Window", "Bell", stringify_bell(m_original_bell_mode));
}
void TerminalSettingsMainWidget::cancel_settings()
{
write_back_settings();
}
void TerminalSettingsViewWidget::apply_settings()
{
m_original_opacity = m_opacity;
m_original_font = m_font;
m_original_color_scheme = m_color_scheme;
m_original_cursor_shape = m_cursor_shape;
m_original_cursor_is_blinking_set = m_cursor_is_blinking_set;
write_back_settings();
}
void TerminalSettingsViewWidget::write_back_settings() const
{
Config::write_i32("Terminal", "Window", "Opacity", static_cast<i32>(m_original_opacity));
Config::write_string("Terminal", "Text", "Font", m_original_font->qualified_name());
Config::write_string("Terminal", "Window", "ColorScheme", m_original_color_scheme);
Config::write_string("Terminal", "Cursor", "Shape", VT::TerminalWidget::stringify_cursor_shape(m_original_cursor_shape));
Config::write_bool("Terminal", "Cursor", "Blinking", m_original_cursor_is_blinking_set);
}
void TerminalSettingsViewWidget::cancel_settings()
{
write_back_settings();
}