Bläddra i källkod

Userland: Implement a magnifier app

This utility is useful for making sure those UI elements are pixel
perfect. A simple 2x/4x magnification around the mouse cursor, shown in
a window.
Valtteri Koskivuori 4 år sedan
förälder
incheckning
4d01183f5c

+ 1 - 0
Base/etc/shellrc

@@ -2,6 +2,7 @@
 
 alias fm=FileManager
 alias irc=IRCClient
+alias mag=Magnifier
 alias ms=Minesweeper
 alias sh=Shell
 alias sn=Snake

+ 1 - 0
Userland/Applications/CMakeLists.txt

@@ -13,6 +13,7 @@ add_subdirectory(HexEditor)
 add_subdirectory(IRCClient)
 add_subdirectory(KeyboardMapper)
 add_subdirectory(KeyboardSettings)
+add_subdirectory(Magnifier)
 add_subdirectory(MouseSettings)
 add_subdirectory(Piano)
 add_subdirectory(PixelPaint)

+ 8 - 0
Userland/Applications/Magnifier/CMakeLists.txt

@@ -0,0 +1,8 @@
+set(SOURCES
+    MagnifierWidget.cpp
+    MagnifierWidget.h
+    main.cpp
+)
+
+serenity_app(Magnifier ICON find)
+target_link_libraries(Magnifier LibGUI)

+ 57 - 0
Userland/Applications/Magnifier/MagnifierWidget.cpp

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, Valtteri Koskivuori <vkoskiv@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "MagnifierWidget.h"
+#include <LibGUI/Painter.h>
+#include <LibGUI/Window.h>
+#include <LibGUI/WindowServerConnection.h>
+#include <LibGfx/AffineTransform.h>
+#include <math.h>
+
+MagnifierWidget::MagnifierWidget()
+{
+}
+
+MagnifierWidget::~MagnifierWidget()
+{
+}
+
+void MagnifierWidget::track_cursor_globally()
+{
+    VERIFY(window());
+    auto window_id = window()->window_id();
+    VERIFY(window_id >= 0);
+
+    set_global_cursor_tracking(true);
+    GUI::WindowServerConnection::the().set_global_cursor_tracking(window_id, true);
+}
+
+void MagnifierWidget::set_scale_factor(int scale_factor)
+{
+    VERIFY(scale_factor == 2 || scale_factor == 4);
+    m_scale_factor = scale_factor;
+    update();
+}
+
+void MagnifierWidget::timer_event(Core::TimerEvent&)
+{
+    m_mouse_position = GUI::WindowServerConnection::the().get_global_cursor_position();
+    update();
+}
+
+void MagnifierWidget::paint_event(GUI::PaintEvent&)
+{
+    GUI::Painter painter(*this);
+
+    int grab_frame_size = 200;
+
+    grab_frame_size /= m_scale_factor;
+
+    // Paint our screenshot
+    Gfx::Rect region { m_mouse_position.x() - (grab_frame_size / 2), m_mouse_position.y() - (grab_frame_size / 2), grab_frame_size, grab_frame_size };
+    auto map = GUI::WindowServerConnection::the().get_screen_bitmap(region);
+    painter.draw_scaled_bitmap(rect(), *map.bitmap(), map.bitmap()->rect());
+}

+ 27 - 0
Userland/Applications/Magnifier/MagnifierWidget.h

@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021, Valtteri Koskivuori <vkoskiv@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibGUI/Widget.h>
+#include <LibGfx/Point.h>
+
+class MagnifierWidget final : public GUI::Widget {
+    C_OBJECT(MagnifierWidget)
+
+public:
+    MagnifierWidget();
+    virtual ~MagnifierWidget();
+    void set_scale_factor(int scale_factor);
+    void track_cursor_globally();
+
+private:
+    virtual void timer_event(Core::TimerEvent&) override;
+    virtual void paint_event(GUI::PaintEvent&) override;
+
+    Gfx::IntPoint m_mouse_position;
+    int m_scale_factor { 2 };
+};

+ 89 - 0
Userland/Applications/Magnifier/main.cpp

@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2021, Valtteri Koskivuori <vkoskiv@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include "MagnifierWidget.h"
+#include <LibGUI/ActionGroup.h>
+#include <LibGUI/Application.h>
+#include <LibGUI/Icon.h>
+#include <LibGUI/Menu.h>
+#include <LibGUI/Menubar.h>
+#include <LibGUI/Window.h>
+#include <unistd.h>
+
+int main(int argc, char** argv)
+{
+    if (pledge("stdio cpath rpath recvfd sendfd unix fattr", nullptr) < 0) {
+        perror("pledge");
+        return 1;
+    }
+
+    auto app = GUI::Application::construct(argc, argv);
+
+    if (pledge("stdio cpath rpath recvfd sendfd", nullptr) < 0) {
+        perror("pledge");
+        return 1;
+    }
+
+    if (unveil("/res", "r") < 0) {
+        perror("unveil");
+        return 1;
+    }
+
+    if (unveil(nullptr, nullptr) < 0) {
+        perror("unveil");
+        return 1;
+    }
+
+    // Sneaky!
+    // FIXME: Doesn't have a 32x32 icon yet, need to make one!
+    auto app_icon = GUI::Icon::default_icon("find");
+
+    // 4px on each side for padding
+    constexpr int window_dimensions = 200 + 4 + 4;
+    auto window = GUI::Window::construct();
+    window->set_title("Magnifier");
+    window->resize(window_dimensions, window_dimensions);
+    window->set_resizable(false);
+    window->set_minimizable(false);
+    window->set_icon(app_icon.bitmap_for_size(16));
+    auto& magnifier = window->set_main_widget<MagnifierWidget>();
+
+    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 size_action_group = make<GUI::ActionGroup>();
+
+    auto two_x_action = GUI::Action::create_checkable(
+        "&2x", [&](auto&) {
+            magnifier.set_scale_factor(2);
+        });
+
+    auto four_x_action = GUI::Action::create_checkable(
+        "&4x", [&](auto&) {
+            magnifier.set_scale_factor(4);
+        });
+
+    size_action_group->add_action(two_x_action);
+    size_action_group->add_action(four_x_action);
+    size_action_group->set_exclusive(true);
+
+    auto& view_menu = menubar->add_menu("&View");
+    view_menu.add_action(two_x_action);
+    view_menu.add_action(four_x_action);
+    two_x_action->set_checked(true);
+
+    auto& help_menu = menubar->add_menu("&Help");
+    help_menu.add_action(GUI::CommonActions::make_about_action("Magnifier", app_icon, window));
+    window->set_menubar(move(menubar));
+
+    window->show();
+    magnifier.track_cursor_globally();
+    magnifier.start_timer(16);
+    return app->exec();
+}