LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2020, Nico Weber <thakis@chromium.org>
|
|
|
|
|
*
|
2021-04-22 05:24:48 -03:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
*/
|
|
|
|
|
|
2021-04-30 19:53:18 -03:00
|
|
|
#include <LibGUI/Action.h>
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
#include <LibGUI/Application.h>
|
|
|
|
|
#include <LibGUI/Icon.h>
|
2021-04-30 19:53:18 -03:00
|
|
|
#include <LibGUI/Menu.h>
|
|
|
|
|
#include <LibGUI/Menubar.h>
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
#include <LibGUI/Painter.h>
|
|
|
|
|
#include <LibGUI/Widget.h>
|
|
|
|
|
#include <LibGUI/Window.h>
|
|
|
|
|
#include <LibGfx/Bitmap.h>
|
|
|
|
|
#include <LibGfx/Font.h>
|
|
|
|
|
#include <LibGfx/Painter.h>
|
|
|
|
|
#include <LibGfx/Palette.h>
|
|
|
|
|
#include <LibGfx/Path.h>
|
2021-01-12 22:22:15 -03:00
|
|
|
#include <LibGfx/SystemTheme.h>
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
#include <LibGfx/WindowTheme.h>
|
2021-03-12 13:29:37 -03:00
|
|
|
#include <unistd.h>
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
|
|
|
|
|
const int WIDTH = 300;
|
|
|
|
|
const int HEIGHT = 200;
|
|
|
|
|
|
|
|
|
|
class Canvas final : public GUI::Widget {
|
|
|
|
|
C_OBJECT(Canvas)
|
|
|
|
|
public:
|
|
|
|
|
virtual ~Canvas() override;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Canvas();
|
|
|
|
|
RefPtr<Gfx::Bitmap> m_bitmap_1x;
|
|
|
|
|
RefPtr<Gfx::Bitmap> m_bitmap_2x;
|
2021-01-19 14:10:47 -03:00
|
|
|
RefPtr<Gfx::Bitmap> m_bitmap_2x_as_1x;
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
|
|
|
|
|
void draw(Gfx::Painter& painter);
|
|
|
|
|
virtual void paint_event(GUI::PaintEvent&) override;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Canvas::Canvas()
|
|
|
|
|
{
|
2021-07-21 13:02:15 -03:00
|
|
|
m_bitmap_1x = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, { WIDTH, HEIGHT }, 1);
|
|
|
|
|
m_bitmap_2x = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRx8888, { WIDTH, HEIGHT }, 2);
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
|
2021-01-19 14:10:47 -03:00
|
|
|
// m_bitmap_1x and m_bitmap_2x have the same logical size, so LibGfx will try to draw them at the same physical size:
|
|
|
|
|
// When drawing on a 2x backing store it'd scale m_bitmap_1x up 2x and paint m_bitmap_2x at its physical size.
|
|
|
|
|
// When drawing on a 1x backing store it'd draw m_bitmap_1x at its physical size, and it would have to scale down m_bitmap_2x to 0.5x its size.
|
|
|
|
|
// But the system can't current scale down, and we want to draw the 2x bitmap at twice the size of the 1x bitmap in this particular application,
|
|
|
|
|
// so make a 1x alias of the 2x bitmap to make LibGfx paint it without any scaling at paint time, mapping once pixel to one pixel.
|
2021-07-21 13:02:15 -03:00
|
|
|
m_bitmap_2x_as_1x = Gfx::Bitmap::try_create_wrapper(Gfx::BitmapFormat::BGRx8888, m_bitmap_2x->physical_size(), 1, m_bitmap_2x->pitch(), m_bitmap_2x->scanline(0));
|
2021-01-19 14:10:47 -03:00
|
|
|
|
|
|
|
|
Gfx::Painter painter_1x(*m_bitmap_1x);
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
draw(painter_1x);
|
|
|
|
|
|
2021-01-19 14:10:47 -03:00
|
|
|
Gfx::Painter painter_2x(*m_bitmap_2x);
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
draw(painter_2x);
|
|
|
|
|
|
|
|
|
|
update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Canvas::~Canvas()
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::paint_event(GUI::PaintEvent& event)
|
|
|
|
|
{
|
|
|
|
|
GUI::Painter painter(*this);
|
|
|
|
|
painter.add_clip_rect(event.rect());
|
|
|
|
|
painter.fill_rect(event.rect(), Color::Magenta);
|
|
|
|
|
painter.blit({ 0, 0 }, *m_bitmap_1x, m_bitmap_1x->rect());
|
2021-01-19 14:10:47 -03:00
|
|
|
painter.blit({ 0, HEIGHT }, *m_bitmap_2x_as_1x, m_bitmap_2x_as_1x->rect());
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Canvas::draw(Gfx::Painter& painter)
|
|
|
|
|
{
|
2021-07-21 13:02:15 -03:00
|
|
|
auto active_window_icon = Gfx::Bitmap::try_load_from_file("/res/icons/16x16/window.png");
|
2021-05-01 14:01:43 -03:00
|
|
|
Gfx::WindowTheme::current().paint_normal_frame(painter, Gfx::WindowTheme::WindowState::Active, { 4, 18, WIDTH - 8, HEIGHT - 29 }, "Well hello friends 🐞", *active_window_icon, palette(), { WIDTH - 20, 6, 16, 16 }, 0, false);
|
2021-01-12 22:22:15 -03:00
|
|
|
|
|
|
|
|
painter.draw_rect({ 20, 34, WIDTH - 40, HEIGHT - 45 }, palette().color(Gfx::ColorRole::Selection), true);
|
|
|
|
|
painter.draw_rect({ 24, 38, WIDTH - 48, HEIGHT - 53 }, palette().color(Gfx::ColorRole::Selection));
|
2021-01-20 11:07:00 -03:00
|
|
|
|
2021-01-24 23:41:38 -03:00
|
|
|
// buggie.png has an alpha channel.
|
2021-07-21 13:02:15 -03:00
|
|
|
auto buggie = Gfx::Bitmap::try_load_from_file("/res/graphics/buggie.png");
|
2021-01-20 11:07:00 -03:00
|
|
|
painter.blit({ 25, 39 }, *buggie, { 2, 30, 62, 20 });
|
LibGfx: Add a draw_scaled_bitmap() variant that takes a FloatRect as src_rect
Consider
draw_scaled_bitmap({0, 0, 10, 10}, source, {0, 0, 5, 5}).
Imagine wanting to split that up into two calls, like e.g. the
compositor when redrawing the background with damage rects. You really
want to be able to say
draw_scaled_bitmap({0, 0, 5, 10}, source, {0, 0, 2.5, 5})
but up to now you couldn't. Now you can.
This makes painting very low-res images (such as tile.png) in mode
"stretch" work much better.
2021-01-22 17:13:47 -03:00
|
|
|
painter.draw_scaled_bitmap({ 88, 39, 62 * 2, 20 * 2 }, *buggie, Gfx::IntRect { 2, 30, 62, 20 });
|
|
|
|
|
painter.draw_scaled_bitmap({ 202, 39, 80, 40 }, *buggie, Gfx::IntRect { 2, 30, 62, 20 });
|
2021-01-22 20:53:09 -03:00
|
|
|
|
|
|
|
|
painter.draw_tiled_bitmap({ 25, 60, WIDTH - 50, 40 }, *buggie);
|
2021-01-22 20:56:01 -03:00
|
|
|
|
|
|
|
|
painter.blit({ 25, 101 }, *buggie, { 2, 30, 3 * buggie->width(), 20 });
|
2021-01-24 23:41:38 -03:00
|
|
|
|
2021-01-25 14:25:56 -03:00
|
|
|
// grid does not have an alpha channel.
|
2021-07-21 13:02:15 -03:00
|
|
|
auto grid = Gfx::Bitmap::try_load_from_file("/res/wallpapers/grid.png");
|
2021-02-23 16:42:32 -03:00
|
|
|
VERIFY(!grid->has_alpha_channel());
|
2021-01-25 14:25:56 -03:00
|
|
|
painter.fill_rect({ 25, 122, 62, 20 }, Color::Green);
|
|
|
|
|
painter.blit({ 25, 122 }, *grid, { (grid->width() - 62) / 2, (grid->height() - 20) / 2 + 40, 62, 20 }, 0.9);
|
2021-01-25 16:54:38 -03:00
|
|
|
|
|
|
|
|
painter.blit_brightened({ 88, 122 }, *buggie, { 2, 30, 62, 20 });
|
|
|
|
|
painter.blit_dimmed({ 140, 122 }, *buggie, { 2, 30, 62, 20 });
|
|
|
|
|
painter.blit_disabled({ 192, 122 }, *buggie, { 2, 30, 62, 20 }, palette());
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
|
{
|
|
|
|
|
auto app = GUI::Application::construct(argc, argv);
|
|
|
|
|
|
2021-01-16 13:42:31 -03:00
|
|
|
if (pledge("stdio recvfd sendfd rpath", nullptr) < 0) {
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
perror("pledge");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unveil("/res", "r") < 0) {
|
|
|
|
|
perror("unveil");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (unveil(nullptr, nullptr) < 0) {
|
|
|
|
|
perror("unveil");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto window = GUI::Window::construct();
|
|
|
|
|
window->set_title("LibGfx Scale Demo");
|
|
|
|
|
window->set_resizable(false);
|
|
|
|
|
window->resize(WIDTH * 2, HEIGHT * 3);
|
|
|
|
|
|
2021-07-21 16:21:03 -03:00
|
|
|
auto& file_menu = window->add_menu("&File");
|
2021-05-12 13:50:48 -03:00
|
|
|
file_menu.add_action(GUI::CommonActions::make_quit_action([&](auto&) { app->quit(); }));
|
2021-04-30 19:53:18 -03:00
|
|
|
|
LibGfx: Make it possible to apply an (integer) scale to a Painter
This adds a scale factor to Painter, which will be used for HighDPI
support. It's also a step towards general affine transforms on Painters.
All of Painter's public API takes logical coordinates, while some
internals deal with physical coordinates now. If scale == 1, logical
and physical coordinates are the same. For scale == 2, a 200x100 bitmap
would be covered by a logical {0, 0, 100, 50} rect, while its physical
size would be {0, 0, 200, 100}.
Most of Painter's functions just assert that scale() == 1 is for now,
but most functions called by WindowServer are updated to handle
arbitrary (integer) scale.
Also add a new Demo "LibGfxScaleDemo" that covers the converted
functions and that can be used to iteratively add scaling support
to more functions.
To make Painter's interface deal with logical coordinates only,
make translation() and clip_rect() non-public.
2021-01-12 17:53:07 -03:00
|
|
|
auto app_icon = GUI::Icon::default_icon("app-libgfx-demo");
|
|
|
|
|
window->set_icon(app_icon.bitmap_for_size(16));
|
|
|
|
|
window->set_main_widget<Canvas>();
|
|
|
|
|
window->show();
|
|
|
|
|
|
|
|
|
|
return app->exec();
|
|
|
|
|
}
|