diff --git a/Base/res/graphics/double-click-down-arrow.png b/Base/res/graphics/double-click-down-arrow.png new file mode 100644 index 0000000000..115a6bcbb1 Binary files /dev/null and b/Base/res/graphics/double-click-down-arrow.png differ diff --git a/Base/res/graphics/mouse-cursor-speed.png b/Base/res/graphics/mouse-cursor-speed.png new file mode 100644 index 0000000000..9704e79d0d Binary files /dev/null and b/Base/res/graphics/mouse-cursor-speed.png differ diff --git a/Base/res/graphics/scroll-wheel-step-size.png b/Base/res/graphics/scroll-wheel-step-size.png new file mode 100644 index 0000000000..6f879283ad Binary files /dev/null and b/Base/res/graphics/scroll-wheel-step-size.png differ diff --git a/Userland/Applications/MouseSettings/CMakeLists.txt b/Userland/Applications/MouseSettings/CMakeLists.txt index 398946ae38..dff69c96c1 100644 --- a/Userland/Applications/MouseSettings/CMakeLists.txt +++ b/Userland/Applications/MouseSettings/CMakeLists.txt @@ -8,6 +8,7 @@ compile_gml(MouseSettingsWindow.gml MouseSettingsWindowGML.h mouse_settings_wind set(SOURCES main.cpp + DoubleClickArrowWidget.cpp MouseSettingsWindow.cpp MouseSettingsWindow.h MouseSettingsWindowGML.h diff --git a/Userland/Applications/MouseSettings/DoubleClickArrowWidget.cpp b/Userland/Applications/MouseSettings/DoubleClickArrowWidget.cpp new file mode 100644 index 0000000000..f18f2dbee1 --- /dev/null +++ b/Userland/Applications/MouseSettings/DoubleClickArrowWidget.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "DoubleClickArrowWidget.h" +#include +#include + +REGISTER_WIDGET(MouseSettings, DoubleClickArrowWidget); + +namespace MouseSettings { + +DoubleClickArrowWidget::~DoubleClickArrowWidget() +{ +} + +void DoubleClickArrowWidget::set_double_click_speed(int speed) +{ + if (m_double_click_speed == speed) + return; + m_double_click_speed = speed; + update(); +} + +DoubleClickArrowWidget::DoubleClickArrowWidget() +{ + m_arrow_bitmap = Gfx::Bitmap::load_from_file("/res/graphics/double-click-down-arrow.png"); +} + +void DoubleClickArrowWidget::paint_event(GUI::PaintEvent& event) +{ + GUI::Painter painter(*this); + painter.add_clip_rect(event.rect()); + + auto bottom_arrow_rect = m_arrow_bitmap->rect(); + bottom_arrow_rect.center_within(rect()); + bottom_arrow_rect.translate_by(0, m_arrow_bitmap->height() / 2); + + painter.blit_filtered(bottom_arrow_rect.location(), *m_arrow_bitmap, m_arrow_bitmap->rect(), [&](Color color) { + return m_inverted ? color.inverted() : color; + }); + + auto top_arrow_rect = bottom_arrow_rect; + top_arrow_rect.translate_by(0, -(m_double_click_speed / 50)); + + painter.blit_filtered(top_arrow_rect.location(), *m_arrow_bitmap, m_arrow_bitmap->rect(), [&](Color color) { + return m_inverted ? color.inverted() : color; + }); + + auto text_rect = rect(); + text_rect.set_y(bottom_arrow_rect.bottom()); + text_rect.set_height(font().glyph_height()); +} + +void DoubleClickArrowWidget::doubleclick_event(GUI::MouseEvent&) +{ + m_inverted = !m_inverted; + update(); +} + +} diff --git a/Userland/Applications/MouseSettings/DoubleClickArrowWidget.h b/Userland/Applications/MouseSettings/DoubleClickArrowWidget.h new file mode 100644 index 0000000000..ac8eeaaa58 --- /dev/null +++ b/Userland/Applications/MouseSettings/DoubleClickArrowWidget.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +namespace MouseSettings { + +class DoubleClickArrowWidget final : public GUI::Widget { + C_OBJECT(DoubleClickArrowWidget); + +public: + virtual ~DoubleClickArrowWidget() override; + void set_double_click_speed(int); + +private: + DoubleClickArrowWidget(); + virtual void paint_event(GUI::PaintEvent&) override; + virtual void doubleclick_event(GUI::MouseEvent&) override; + + RefPtr m_arrow_bitmap; + int m_double_click_speed { 0 }; + bool m_inverted { false }; +}; + +} diff --git a/Userland/Applications/MouseSettings/MouseSettingsWindow.cpp b/Userland/Applications/MouseSettings/MouseSettingsWindow.cpp index 3c6f923fa1..63ffe80762 100644 --- a/Userland/Applications/MouseSettings/MouseSettingsWindow.cpp +++ b/Userland/Applications/MouseSettings/MouseSettingsWindow.cpp @@ -1,16 +1,20 @@ /* * Copyright (c) 2020, Idan Horowitz * Copyright (c) 2021, the SerenityOS developers. + * Copyright (c) 2021, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #include "MouseSettingsWindow.h" +#include "DoubleClickArrowWidget.h" #include #include +#include #include #include #include +#include #include #include #include @@ -40,44 +44,74 @@ void MouseSettingsWindow::reset_default_values() MouseSettingsWindow::MouseSettingsWindow() { auto& main_widget = set_main_widget(); - main_widget.load_from_gml(mouse_settings_window_gml); + main_widget.set_fill_with_background_color(true); + main_widget.set_layout(); + main_widget.layout()->set_margins({ 4, 4, 4, 4 }); + main_widget.layout()->set_spacing(6); + + auto& tab_widget = main_widget.add(); + auto& mouse_widget = tab_widget.add_tab("Mouse"); + mouse_widget.load_from_gml(mouse_settings_window_gml); m_speed_label = *main_widget.find_descendant_of_type_named("speed_label"); m_speed_slider = *main_widget.find_descendant_of_type_named("speed_slider"); m_speed_slider->set_range(WindowServer::mouse_accel_min * speed_slider_scale, WindowServer::mouse_accel_max * speed_slider_scale); - m_speed_slider->on_change = [&](const int value) { + m_speed_slider->on_change = [&](int value) { m_speed_label->set_text(String::formatted("{} %", value)); }; const int slider_value = float { speed_slider_scale } * GUI::WindowServerConnection::the().get_mouse_acceleration(); m_speed_slider->set_value(slider_value); + auto& cursor_speed_image_label = *main_widget.find_descendant_of_type_named("cursor_speed_image_label"); + cursor_speed_image_label.set_icon(Gfx::Bitmap::load_from_file("/res/graphics/mouse-cursor-speed.png")); + + auto& scroll_step_size_image_label = *main_widget.find_descendant_of_type_named("scroll_step_size_image_label"); + scroll_step_size_image_label.set_icon(Gfx::Bitmap::load_from_file("/res/graphics/scroll-wheel-step-size.png")); + m_scroll_length_spinbox = *main_widget.find_descendant_of_type_named("scroll_length_spinbox"); m_scroll_length_spinbox->set_min(WindowServer::scroll_step_size_min); m_scroll_length_spinbox->set_value(GUI::WindowServerConnection::the().get_scroll_step_size()); + m_double_click_arrow_widget = *main_widget.find_descendant_of_type_named("double_click_arrow_widget"); m_double_click_speed_label = *main_widget.find_descendant_of_type_named("double_click_speed_label"); m_double_click_speed_slider = *main_widget.find_descendant_of_type_named("double_click_speed_slider"); m_double_click_speed_slider->set_min(WindowServer::double_click_speed_min); m_double_click_speed_slider->set_max(WindowServer::double_click_speed_max); - m_double_click_speed_slider->on_change = [&](const int value) { - m_double_click_speed_label->set_text(String::formatted("{} ms", value)); + m_double_click_speed_slider->on_change = [&](int speed) { + m_double_click_arrow_widget->set_double_click_speed(speed); + m_double_click_speed_label->set_text(String::formatted("{} ms", speed)); }; m_double_click_speed_slider->set_value(GUI::WindowServerConnection::the().get_double_click_speed()); - m_ok_button = *main_widget.find_descendant_of_type_named("ok_button"); - m_ok_button->on_click = [this](auto) { + auto& button_container = main_widget.add(); + button_container.set_shrink_to_fit(true); + button_container.set_layout(); + button_container.layout()->set_spacing(6); + + m_reset_button = button_container.add("Defaults"); + m_reset_button->on_click = [this](auto) { + reset_default_values(); + }; + + button_container.layout()->add_spacer(); + + m_ok_button = button_container.add("OK"); + m_ok_button->set_fixed_width(75); + m_ok_button->on_click = [&](auto) { update_window_server(); GUI::Application::the()->quit(); }; - m_apply_button = *main_widget.find_descendant_of_type_named("apply_button"); - m_apply_button->on_click = [this](auto) { - update_window_server(); + m_cancel_button = button_container.add("Cancel"); + m_cancel_button->set_fixed_width(75); + m_cancel_button->on_click = [&](auto) { + GUI::Application::the()->quit(); }; - m_reset_button = *main_widget.find_descendant_of_type_named("reset_button"); - m_reset_button->on_click = [this](auto) { - reset_default_values(); + m_apply_button = button_container.add("Apply"); + m_apply_button->set_fixed_width(75); + m_apply_button->on_click = [&](auto) { + update_window_server(); }; } diff --git a/Userland/Applications/MouseSettings/MouseSettingsWindow.gml b/Userland/Applications/MouseSettings/MouseSettingsWindow.gml index 96c6ec6e9c..2ac829a11f 100644 --- a/Userland/Applications/MouseSettings/MouseSettingsWindow.gml +++ b/Userland/Applications/MouseSettings/MouseSettingsWindow.gml @@ -1,105 +1,147 @@ -@GUI::Widget { +@GUI::Frame { fill_with_background_color: true - layout: @GUI::VerticalBoxLayout { - margins: [4, 4, 4, 4] + margins: [10, 10, 10, 10] + spacing: 5 } @GUI::GroupBox { - title: "Mouse speed" - fixed_height: 60 + title: "Cursor speed" + fixed_height: 110 - layout: @GUI::HorizontalBoxLayout { - margins: [6, 16, 8, 6] + layout: @GUI::VerticalBoxLayout { + margins: [8, 16, 8, 8] } - @GUI::HorizontalSlider { - name: "speed_slider" - max: 3500 - min: 500 - value: 100 + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + margins: [8, 8, 8, 8] + spacing: 16 + } + + @GUI::Label { + fixed_width: 32 + fixed_height: 32 + name: "cursor_speed_image_label" + } + + @GUI::Label { + text: "The relative speed of the mouse cursor." + text_alignment: "CenterLeft" + } } - @GUI::Label { - name: "speed_label" - text: "100.0 %" - fixed_width: 50 - text_alignment: "CenterRight" + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + } + + @GUI::HorizontalSlider { + name: "speed_slider" + min: 0 + max: 100 + value: 50 + } + + @GUI::Label { + fixed_width: 40 + name: "speed_label" + } } } @GUI::GroupBox { - title: "Scroll length" - fixed_height: 60 + title: "Scroll wheel step size" + fixed_height: 110 - layout: @GUI::HorizontalBoxLayout { - margins: [16, 16, 8, 6] + layout: @GUI::VerticalBoxLayout { + margins: [8, 16, 8, 8] } - @GUI::Label { - text: "Scroll by " - autosize: true - text_alignment: "CenterLeft" + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + margins: [8, 8, 8, 8] + spacing: 16 + } + + @GUI::Label { + fixed_width: 32 + fixed_height: 32 + name: "scroll_step_size_image_label" + } + + @GUI::Label { + text: "The number of steps taken when the scroll wheel is\nmoved a single notch." + text_alignment: "CenterLeft" + } } - @GUI::SpinBox { - name: "scroll_length_spinbox" - max: 32 - min: 1 - value: 4 - text_alignment: "CenterRight" - fixed_width: 80 - } + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + spacing: 8 + } - @GUI::Label { - text: " lines at a time" - text_alignent: "CenterLeft" - autosize: true + @GUI::Widget { + } + + @GUI::Label { + autosize: true + text: "Step size:" + } + + @GUI::SpinBox { + name: "scroll_length_spinbox" + min: 0 + max: 100 + value: 50 + fixed_width: 100 + } + + @GUI::Widget { + } } } @GUI::GroupBox { title: "Double-click speed" - fixed_height: 60 + fixed_height: 110 - layout: @GUI::HorizontalBoxLayout { - margins: [6, 16, 8, 6] + layout: @GUI::VerticalBoxLayout { + margins: [8, 16, 8, 8] } - @GUI::HorizontalSlider { - name: "double_click_speed_slider" - max: 900 - min: 100 - value: 250 + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + margins: [8, 8, 8, 8] + spacing: 16 + } + + @MouseSettings::DoubleClickArrowWidget { + fixed_width: 32 + fixed_height: 32 + name: "double_click_arrow_widget" + } + + @GUI::Label { + text: "The maximum time that may pass between two clicks\nin order for them to become a double-click." + text_alignment: "CenterLeft" + } } - @GUI::Label { - name: "double_click_speed_label" - text: "250 ms" - fixed_width: 50 - text_alignment: "CenterRight" - } - } + @GUI::Widget { + layout: @GUI::HorizontalBoxLayout { + } - @GUI::Widget { - fixed_height: 22 + @GUI::HorizontalSlider { + name: "double_click_speed_slider" + min: 0 + max: 100 + value: 50 + } - layout: @GUI::HorizontalBoxLayout { - } - - @GUI::Button { - name: "ok_button" - text: "OK" - } - - @GUI::Button { - name: "apply_button" - text: "Apply" - } - - @GUI::Button { - name: "reset_button" - text: "Reset" + @GUI::Label { + fixed_width: 40 + name: "double_click_speed_label" + } } } } diff --git a/Userland/Applications/MouseSettings/MouseSettingsWindow.h b/Userland/Applications/MouseSettings/MouseSettingsWindow.h index 433bdc1fa0..2159636034 100644 --- a/Userland/Applications/MouseSettings/MouseSettingsWindow.h +++ b/Userland/Applications/MouseSettings/MouseSettingsWindow.h @@ -7,6 +7,7 @@ #pragma once +#include "DoubleClickArrowWidget.h" #include #include #include @@ -29,6 +30,8 @@ private: RefPtr m_double_click_speed_slider; RefPtr m_double_click_speed_label; RefPtr m_ok_button; + RefPtr m_cancel_button; RefPtr m_apply_button; RefPtr m_reset_button; + RefPtr m_double_click_arrow_widget; }; diff --git a/Userland/Applications/MouseSettings/main.cpp b/Userland/Applications/MouseSettings/main.cpp index 9ed2b4ffd8..4ca4e05f91 100644 --- a/Userland/Applications/MouseSettings/main.cpp +++ b/Userland/Applications/MouseSettings/main.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2020, Idan Horowitz * Copyright (c) 2021, the SerenityOS developers. + * Copyright (c) 2021, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -9,8 +10,6 @@ #include #include #include -#include -#include #include int main(int argc, char** argv) @@ -31,22 +30,11 @@ int main(int argc, char** argv) auto window = MouseSettingsWindow::construct(); window->set_title("Mouse Settings"); - window->resize(300, 220); + window->resize(400, 480); window->set_resizable(false); window->set_minimizable(false); window->set_icon(app_icon.bitmap_for_size(16)); - auto menubar = GUI::Menubar::construct(); - auto& file_menu = menubar->add_menu("&File"); - file_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) { - app->quit(); - })); - - auto& help_menu = menubar->add_menu("&Help"); - help_menu.add_action(GUI::CommonActions::make_about_action("Mouse Settings", app_icon, window)); - - window->set_menubar(move(menubar)); - window->show(); return app->exec(); }