Browse Source

MouseSettings: Give this application a GUI facelift :^)

Note that the double-click "icon" adapts to the double-click speed
and also reacts to double-clicks. :^)
Andreas Kling 4 năm trước cách đây
mục cha
commit
81e6560009

BIN
Base/res/graphics/double-click-down-arrow.png


BIN
Base/res/graphics/mouse-cursor-speed.png


BIN
Base/res/graphics/scroll-wheel-step-size.png


+ 1 - 0
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

+ 63 - 0
Userland/Applications/MouseSettings/DoubleClickArrowWidget.cpp

@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "DoubleClickArrowWidget.h"
+#include <LibGUI/Painter.h>
+#include <LibGfx/Font.h>
+
+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();
+}
+
+}

+ 30 - 0
Userland/Applications/MouseSettings/DoubleClickArrowWidget.h

@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibGUI/Widget.h>
+
+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<Gfx::Bitmap> m_arrow_bitmap;
+    int m_double_click_speed { 0 };
+    bool m_inverted { false };
+};
+
+}

+ 46 - 12
Userland/Applications/MouseSettings/MouseSettingsWindow.cpp

@@ -1,16 +1,20 @@
 /*
  * Copyright (c) 2020, Idan Horowitz <idan.horowitz@serenityos.org>
  * Copyright (c) 2021, the SerenityOS developers.
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
 #include "MouseSettingsWindow.h"
+#include "DoubleClickArrowWidget.h"
 #include <Applications/MouseSettings/MouseSettingsWindowGML.h>
 #include <LibGUI/Application.h>
+#include <LibGUI/BoxLayout.h>
 #include <LibGUI/Button.h>
 #include <LibGUI/Event.h>
 #include <LibGUI/Label.h>
+#include <LibGUI/TabWidget.h>
 #include <LibGUI/Widget.h>
 #include <LibGUI/Window.h>
 #include <LibGUI/WindowServerConnection.h>
@@ -40,44 +44,74 @@ void MouseSettingsWindow::reset_default_values()
 MouseSettingsWindow::MouseSettingsWindow()
 {
     auto& main_widget = set_main_widget<GUI::Widget>();
-    main_widget.load_from_gml(mouse_settings_window_gml);
+    main_widget.set_fill_with_background_color(true);
+    main_widget.set_layout<GUI::VerticalBoxLayout>();
+    main_widget.layout()->set_margins({ 4, 4, 4, 4 });
+    main_widget.layout()->set_spacing(6);
+
+    auto& tab_widget = main_widget.add<GUI::TabWidget>();
+    auto& mouse_widget = tab_widget.add_tab<GUI::Widget>("Mouse");
+    mouse_widget.load_from_gml(mouse_settings_window_gml);
 
     m_speed_label = *main_widget.find_descendant_of_type_named<GUI::Label>("speed_label");
     m_speed_slider = *main_widget.find_descendant_of_type_named<GUI::HorizontalSlider>("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<GUI::Label>("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<GUI::Label>("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<GUI::SpinBox>("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<MouseSettings::DoubleClickArrowWidget>("double_click_arrow_widget");
     m_double_click_speed_label = *main_widget.find_descendant_of_type_named<GUI::Label>("double_click_speed_label");
     m_double_click_speed_slider = *main_widget.find_descendant_of_type_named<GUI::HorizontalSlider>("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<GUI::Button>("ok_button");
-    m_ok_button->on_click = [this](auto) {
+    auto& button_container = main_widget.add<GUI::Widget>();
+    button_container.set_shrink_to_fit(true);
+    button_container.set_layout<GUI::HorizontalBoxLayout>();
+    button_container.layout()->set_spacing(6);
+
+    m_reset_button = button_container.add<GUI::Button>("Defaults");
+    m_reset_button->on_click = [this](auto) {
+        reset_default_values();
+    };
+
+    button_container.layout()->add_spacer();
+
+    m_ok_button = button_container.add<GUI::Button>("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<GUI::Button>("apply_button");
-    m_apply_button->on_click = [this](auto) {
-        update_window_server();
+    m_cancel_button = button_container.add<GUI::Button>("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<GUI::Button>("reset_button");
-    m_reset_button->on_click = [this](auto) {
-        reset_default_values();
+    m_apply_button = button_container.add<GUI::Button>("Apply");
+    m_apply_button->set_fixed_width(75);
+    m_apply_button->on_click = [&](auto) {
+        update_window_server();
     };
 }
 

+ 115 - 73
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
-
-        layout: @GUI::HorizontalBoxLayout {
-            margins: [16, 16, 8, 6]
-        }
+        title: "Scroll wheel step size"
+        fixed_height: 110
 
-        @GUI::Label {
-            text: "Scroll by "
-            autosize: true
-            text_alignment: "CenterLeft"
+        layout: @GUI::VerticalBoxLayout {
+            margins: [8, 16, 8, 8]
         }
 
-        @GUI::SpinBox {
-            name: "scroll_length_spinbox"
-            max: 32
-            min: 1
-            value: 4
-            text_alignment: "CenterRight"
-            fixed_width: 80
+        @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::Label {
-            text: " lines at a time"
-            text_alignent: "CenterLeft"
-            autosize: true
+        @GUI::Widget {
+            layout: @GUI::HorizontalBoxLayout {
+                spacing: 8
+            }
+
+            @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
-
-        layout: @GUI::HorizontalBoxLayout {
-            margins: [6, 16, 8, 6]
-        }
-
-        @GUI::HorizontalSlider {
-            name: "double_click_speed_slider"
-            max: 900
-            min: 100
-            value: 250
-        }
-
-        @GUI::Label {
-            name: "double_click_speed_label"
-            text: "250 ms"
-            fixed_width: 50
-            text_alignment: "CenterRight"
-        }
-    }
-
-    @GUI::Widget {
-        fixed_height: 22
-
-        layout: @GUI::HorizontalBoxLayout {
-        }
+        fixed_height: 110
 
-        @GUI::Button {
-            name: "ok_button"
-            text: "OK"
+        layout: @GUI::VerticalBoxLayout {
+            margins: [8, 16, 8, 8]
         }
 
-        @GUI::Button {
-            name: "apply_button"
-            text: "Apply"
+        @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::Button {
-            name: "reset_button"
-            text: "Reset"
+        @GUI::Widget {
+            layout: @GUI::HorizontalBoxLayout {
+            }
+
+            @GUI::HorizontalSlider {
+                name: "double_click_speed_slider"
+                min: 0
+                max: 100
+                value: 50
+            }
+
+            @GUI::Label {
+                fixed_width: 40
+                name: "double_click_speed_label"
+            }
         }
     }
 }

+ 3 - 0
Userland/Applications/MouseSettings/MouseSettingsWindow.h

@@ -7,6 +7,7 @@
 
 #pragma once
 
+#include "DoubleClickArrowWidget.h"
 #include <LibGUI/Button.h>
 #include <LibGUI/Slider.h>
 #include <LibGUI/SpinBox.h>
@@ -29,6 +30,8 @@ private:
     RefPtr<GUI::HorizontalSlider> m_double_click_speed_slider;
     RefPtr<GUI::Label> m_double_click_speed_label;
     RefPtr<GUI::Button> m_ok_button;
+    RefPtr<GUI::Button> m_cancel_button;
     RefPtr<GUI::Button> m_apply_button;
     RefPtr<GUI::Button> m_reset_button;
+    RefPtr<MouseSettings::DoubleClickArrowWidget> m_double_click_arrow_widget;
 };

+ 2 - 14
Userland/Applications/MouseSettings/main.cpp

@@ -1,6 +1,7 @@
 /*
  * Copyright (c) 2020, Idan Horowitz <idan.horowitz@serenityos.org>
  * Copyright (c) 2021, the SerenityOS developers.
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  *
  * SPDX-License-Identifier: BSD-2-Clause
  */
@@ -9,8 +10,6 @@
 #include <LibGUI/Action.h>
 #include <LibGUI/Application.h>
 #include <LibGUI/Icon.h>
-#include <LibGUI/Menu.h>
-#include <LibGUI/Menubar.h>
 #include <unistd.h>
 
 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();
 }