1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 04:57:44 +00:00

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. :^)
This commit is contained in:
Andreas Kling 2021-07-20 21:35:00 +02:00
parent 3652ab8b2a
commit 81e6560009
10 changed files with 257 additions and 96 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

View file

@ -8,6 +8,7 @@ compile_gml(MouseSettingsWindow.gml MouseSettingsWindowGML.h mouse_settings_wind
set(SOURCES set(SOURCES
main.cpp main.cpp
DoubleClickArrowWidget.cpp
MouseSettingsWindow.cpp MouseSettingsWindow.cpp
MouseSettingsWindow.h MouseSettingsWindow.h
MouseSettingsWindowGML.h MouseSettingsWindowGML.h

View file

@ -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();
}
}

View file

@ -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 };
};
}

View file

@ -1,16 +1,20 @@
/* /*
* Copyright (c) 2020, Idan Horowitz <idan.horowitz@serenityos.org> * Copyright (c) 2020, Idan Horowitz <idan.horowitz@serenityos.org>
* Copyright (c) 2021, the SerenityOS developers. * Copyright (c) 2021, the SerenityOS developers.
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include "MouseSettingsWindow.h" #include "MouseSettingsWindow.h"
#include "DoubleClickArrowWidget.h"
#include <Applications/MouseSettings/MouseSettingsWindowGML.h> #include <Applications/MouseSettings/MouseSettingsWindowGML.h>
#include <LibGUI/Application.h> #include <LibGUI/Application.h>
#include <LibGUI/BoxLayout.h>
#include <LibGUI/Button.h> #include <LibGUI/Button.h>
#include <LibGUI/Event.h> #include <LibGUI/Event.h>
#include <LibGUI/Label.h> #include <LibGUI/Label.h>
#include <LibGUI/TabWidget.h>
#include <LibGUI/Widget.h> #include <LibGUI/Widget.h>
#include <LibGUI/Window.h> #include <LibGUI/Window.h>
#include <LibGUI/WindowServerConnection.h> #include <LibGUI/WindowServerConnection.h>
@ -40,44 +44,74 @@ void MouseSettingsWindow::reset_default_values()
MouseSettingsWindow::MouseSettingsWindow() MouseSettingsWindow::MouseSettingsWindow()
{ {
auto& main_widget = set_main_widget<GUI::Widget>(); 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_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 = *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->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)); m_speed_label->set_text(String::formatted("{} %", value));
}; };
const int slider_value = float { speed_slider_scale } * GUI::WindowServerConnection::the().get_mouse_acceleration(); const int slider_value = float { speed_slider_scale } * GUI::WindowServerConnection::the().get_mouse_acceleration();
m_speed_slider->set_value(slider_value); 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 = *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_min(WindowServer::scroll_step_size_min);
m_scroll_length_spinbox->set_value(GUI::WindowServerConnection::the().get_scroll_step_size()); 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_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 = *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_min(WindowServer::double_click_speed_min);
m_double_click_speed_slider->set_max(WindowServer::double_click_speed_max); 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_slider->on_change = [&](int speed) {
m_double_click_speed_label->set_text(String::formatted("{} ms", value)); 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_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"); auto& button_container = main_widget.add<GUI::Widget>();
m_ok_button->on_click = [this](auto) { 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(); update_window_server();
GUI::Application::the()->quit(); GUI::Application::the()->quit();
}; };
m_apply_button = *main_widget.find_descendant_of_type_named<GUI::Button>("apply_button"); m_cancel_button = button_container.add<GUI::Button>("Cancel");
m_apply_button->on_click = [this](auto) { m_cancel_button->set_fixed_width(75);
update_window_server(); 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_apply_button = button_container.add<GUI::Button>("Apply");
m_reset_button->on_click = [this](auto) { m_apply_button->set_fixed_width(75);
reset_default_values(); m_apply_button->on_click = [&](auto) {
update_window_server();
}; };
} }

View file

@ -1,105 +1,147 @@
@GUI::Widget { @GUI::Frame {
fill_with_background_color: true fill_with_background_color: true
layout: @GUI::VerticalBoxLayout { layout: @GUI::VerticalBoxLayout {
margins: [4, 4, 4, 4] margins: [10, 10, 10, 10]
spacing: 5
} }
@GUI::GroupBox { @GUI::GroupBox {
title: "Mouse speed" title: "Cursor speed"
fixed_height: 60 fixed_height: 110
layout: @GUI::HorizontalBoxLayout { layout: @GUI::VerticalBoxLayout {
margins: [6, 16, 8, 6] margins: [8, 16, 8, 8]
} }
@GUI::HorizontalSlider { @GUI::Widget {
name: "speed_slider" layout: @GUI::HorizontalBoxLayout {
max: 3500 margins: [8, 8, 8, 8]
min: 500 spacing: 16
value: 100 }
@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 { @GUI::Widget {
name: "speed_label" layout: @GUI::HorizontalBoxLayout {
text: "100.0 %" }
fixed_width: 50
text_alignment: "CenterRight" @GUI::HorizontalSlider {
name: "speed_slider"
min: 0
max: 100
value: 50
}
@GUI::Label {
fixed_width: 40
name: "speed_label"
}
} }
} }
@GUI::GroupBox { @GUI::GroupBox {
title: "Scroll length" title: "Scroll wheel step size"
fixed_height: 60 fixed_height: 110
layout: @GUI::HorizontalBoxLayout { layout: @GUI::VerticalBoxLayout {
margins: [16, 16, 8, 6] margins: [8, 16, 8, 8]
} }
@GUI::Label { @GUI::Widget {
text: "Scroll by " layout: @GUI::HorizontalBoxLayout {
autosize: true margins: [8, 8, 8, 8]
text_alignment: "CenterLeft" 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 { @GUI::Widget {
name: "scroll_length_spinbox" layout: @GUI::HorizontalBoxLayout {
max: 32 spacing: 8
min: 1 }
value: 4
text_alignment: "CenterRight"
fixed_width: 80
}
@GUI::Label { @GUI::Widget {
text: " lines at a time" }
text_alignent: "CenterLeft"
autosize: true @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 { @GUI::GroupBox {
title: "Double-click speed" title: "Double-click speed"
fixed_height: 60 fixed_height: 110
layout: @GUI::HorizontalBoxLayout { layout: @GUI::VerticalBoxLayout {
margins: [6, 16, 8, 6] margins: [8, 16, 8, 8]
} }
@GUI::HorizontalSlider { @GUI::Widget {
name: "double_click_speed_slider" layout: @GUI::HorizontalBoxLayout {
max: 900 margins: [8, 8, 8, 8]
min: 100 spacing: 16
value: 250 }
@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 { @GUI::Widget {
name: "double_click_speed_label" layout: @GUI::HorizontalBoxLayout {
text: "250 ms" }
fixed_width: 50
text_alignment: "CenterRight"
}
}
@GUI::Widget { @GUI::HorizontalSlider {
fixed_height: 22 name: "double_click_speed_slider"
min: 0
max: 100
value: 50
}
layout: @GUI::HorizontalBoxLayout { @GUI::Label {
} fixed_width: 40
name: "double_click_speed_label"
@GUI::Button { }
name: "ok_button"
text: "OK"
}
@GUI::Button {
name: "apply_button"
text: "Apply"
}
@GUI::Button {
name: "reset_button"
text: "Reset"
} }
} }
} }

View file

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

View file

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2020, Idan Horowitz <idan.horowitz@serenityos.org> * Copyright (c) 2020, Idan Horowitz <idan.horowitz@serenityos.org>
* Copyright (c) 2021, the SerenityOS developers. * Copyright (c) 2021, the SerenityOS developers.
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -9,8 +10,6 @@
#include <LibGUI/Action.h> #include <LibGUI/Action.h>
#include <LibGUI/Application.h> #include <LibGUI/Application.h>
#include <LibGUI/Icon.h> #include <LibGUI/Icon.h>
#include <LibGUI/Menu.h>
#include <LibGUI/Menubar.h>
#include <unistd.h> #include <unistd.h>
int main(int argc, char** argv) int main(int argc, char** argv)
@ -31,22 +30,11 @@ int main(int argc, char** argv)
auto window = MouseSettingsWindow::construct(); auto window = MouseSettingsWindow::construct();
window->set_title("Mouse Settings"); window->set_title("Mouse Settings");
window->resize(300, 220); window->resize(400, 480);
window->set_resizable(false); window->set_resizable(false);
window->set_minimizable(false); window->set_minimizable(false);
window->set_icon(app_icon.bitmap_for_size(16)); 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(); window->show();
return app->exec(); return app->exec();
} }