Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
graphics.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2
3#include "graphics.h"
4
6#include <cairomm/context.h>
7#include <cairomm/surface.h>
8
9#include "colors/color.h"
10#include "display/cairo-utils.h"
11#include "helper/geom.h"
12#include "ui/util.h"
13#include "util.h"
14
15namespace Inkscape::UI::Widget {
16
17namespace {
18
19// Convert an rgba into a pattern, turning transparency into checkerboard-ness.
20Cairo::RefPtr<Cairo::Pattern> rgba_to_pattern(std::uint32_t const rgba)
21{
22 if (SP_RGBA32_A_U(rgba) == 255) {
23 return Cairo::SolidPattern::create_rgb(SP_RGBA32_R_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_B_F(rgba));
24 }
25
26 int constexpr w = 6;
27 int constexpr h = 6;
28
29 auto color = Colors::Color(rgba);
30 auto dark = checkerboard_darken(color);
31 color.enableOpacity(false);
32
33 auto surface = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32, 2 * w, 2 * h);
34
35 auto cr = Cairo::Context::create(surface);
36 cr->set_operator(Cairo::Context::Operator::SOURCE);
38 cr->paint();
40 cr->rectangle(0, 0, w, h);
41 cr->rectangle(w, h, w, h);
42 cr->fill();
43
44 auto pattern = Cairo::SurfacePattern::create(surface);
45 pattern->set_extend(Cairo::Pattern::Extend::REPEAT);
46 pattern->set_filter(Cairo::SurfacePattern::Filter::NEAREST);
47
48 return pattern;
49}
50
51} // namespace
52
53// Paint the background and pages using Cairo into the given fragment.
55 std::uint32_t const page, std::uint32_t const desk,
56 Cairo::RefPtr<Cairo::Context> const &cr)
57{
58 cr->save();
59 cr->set_operator(Cairo::Context::Operator::SOURCE);
60 cr->rectangle(0, 0, fragment.rect.width(), fragment.rect.height());
61 cr->clip();
62
63 if (desk == page || check_single_page(fragment, pi)) {
64 // Desk and page are the same, or a single page fills the whole screen; just clear the fragment to page.
65 cr->set_source(rgba_to_pattern(page));
66 cr->paint();
67 } else {
68 // Paint the background to the complement of the pages. (Slightly overpaints when pages overlap.)
69 cr->save();
70 cr->set_source(rgba_to_pattern(desk));
71 cr->set_fill_rule(Cairo::Context::FillRule::EVEN_ODD);
72 cr->rectangle(0, 0, fragment.rect.width(), fragment.rect.height());
73 cr->translate(-fragment.rect.left(), -fragment.rect.top());
74 cr->transform(geom_to_cairo(fragment.affine));
75 for (auto &rect : pi.pages) {
76 cr->rectangle(rect.left(), rect.top(), rect.width(), rect.height());
77 }
78 cr->fill();
79 cr->restore();
80
81 // Paint the pages.
82 cr->save();
83 cr->set_source(rgba_to_pattern(page));
84 cr->translate(-fragment.rect.left(), -fragment.rect.top());
85 cr->transform(geom_to_cairo(fragment.affine));
86 for (auto &rect : pi.pages) {
87 cr->rectangle(rect.left(), rect.top(), rect.width(), rect.height());
88 }
89 cr->fill();
90 cr->restore();
91 }
92
93 cr->restore();
94}
95
96std::pair<Geom::IntRect, Geom::IntRect> Graphics::calc_splitview_cliprects(Geom::IntPoint const &size, Geom::Point const &split_frac, SplitDirection split_direction)
97{
98 auto window = Geom::IntRect({0, 0}, size);
99
100 auto content = window;
101 auto outline = window;
102 auto split = [&] (Geom::Dim2 dim, Geom::IntRect &lo, Geom::IntRect &hi) {
103 int s = std::round(split_frac[dim] * size[dim]);
104 lo[dim].setMax(s);
105 hi[dim].setMin(s);
106 };
107
108 switch (split_direction) {
109 case Inkscape::SplitDirection::NORTH: split(Geom::Y, content, outline); break;
110 case Inkscape::SplitDirection::EAST: split(Geom::X, outline, content); break;
111 case Inkscape::SplitDirection::SOUTH: split(Geom::Y, outline, content); break;
112 case Inkscape::SplitDirection::WEST: split(Geom::X, content, outline); break;
113 default: assert(false); break;
114 }
115
116 return std::make_pair(content, outline);
117}
118
119void Graphics::paint_splitview_controller(Geom::IntPoint const &size, Geom::Point const &split_frac, SplitDirection split_direction, SplitDirection hover_direction, Cairo::RefPtr<Cairo::Context> const &cr)
120{
121 auto split_position = (split_frac * size).round();
122
123 // Add dividing line.
124 cr->set_source_rgb(0.0, 0.0, 0.0);
125 cr->set_line_width(1.0);
126 if (split_direction == Inkscape::SplitDirection::EAST ||
127 split_direction == Inkscape::SplitDirection::WEST) {
128 cr->move_to(split_position.x() + 0.5, 0.0 );
129 cr->line_to(split_position.x() + 0.5, size.y());
130 cr->stroke();
131 } else {
132 cr->move_to(0.0 , split_position.y() + 0.5);
133 cr->line_to(size.x(), split_position.y() + 0.5);
134 cr->stroke();
135 }
136
137 // Add controller image.
138 double a = hover_direction == Inkscape::SplitDirection::NONE ? 0.5 : 1.0;
139 cr->set_source_rgba(0.2, 0.2, 0.2, a);
140 cr->arc(split_position.x(), split_position.y(), 20, 0, 2 * M_PI);
141 cr->fill();
142
143 for (int i = 0; i < 4; i++) {
144 // The four direction triangles.
145 cr->save();
146
147 // Position triangle.
148 cr->translate(split_position.x(), split_position.y());
149 cr->rotate((i + 2) * M_PI / 2);
150
151 // Draw triangle.
152 cr->move_to(-5, 8);
153 cr->line_to( 0, 18);
154 cr->line_to( 5, 8);
155 cr->close_path();
156
157 double b = (int)hover_direction == (i + 1) ? 0.9 : 0.7;
158 cr->set_source_rgba(b, b, b, a);
159 cr->fill();
160
161 cr->restore();
162 }
163}
164
166{
167 auto pl = Geom::Parallelogram(view.rect) * view.affine.inverse();
168 return std::any_of(pi.pages.begin(), pi.pages.end(), [&] (auto &rect) {
169 return Geom::Parallelogram(rect).contains(pl);
170 });
171}
172
173} // namespace Inkscape::UI::Widget
void ink_cairo_set_source_color(Cairo::RefPtr< Cairo::Context > ctx, Inkscape::Colors::Color const &color, double opacity)
The following functions interact between Inkscape color model, and cairo surface rendering.
Cairo integration helpers.
Cairo::RefPtr< Cairo::ImageSurface > surface
Definition canvas.cpp:137
uint64_t page
Definition canvas.cpp:171
uint64_t desk
Definition canvas.cpp:171
Fragment fragment
Definition canvas.cpp:136
Affine inverse() const
Compute the inverse matrix.
Definition affine.cpp:388
Axis aligned, non-empty, generic rectangle.
Two-dimensional point with integer coordinates.
Definition int-point.h:57
Paralellogram, representing a linear transformation of a rectangle.
Two-dimensional point that doubles as a vector.
Definition point.h:66
static void paint_splitview_controller(Geom::IntPoint const &size, Geom::Point const &splitfrac, SplitDirection splitdir, SplitDirection hoverdir, Cairo::RefPtr< Cairo::Context > const &cr)
Definition graphics.cpp:119
static bool check_single_page(Fragment const &view, PageInfo const &pi)
Definition graphics.cpp:165
static void paint_background(Fragment const &fragment, PageInfo const &pi, std::uint32_t page, std::uint32_t desk, Cairo::RefPtr< Cairo::Context > const &cr)
Definition graphics.cpp:54
static std::pair< Geom::IntRect, Geom::IntRect > calc_splitview_cliprects(Geom::IntPoint const &size, Geom::Point const &splitfrac, SplitDirection splitdir)
Definition graphics.cpp:96
constexpr double SP_RGBA32_G_F(uint32_t v)
Definition utils.h:47
constexpr double SP_RGBA32_R_F(uint32_t v)
Definition utils.h:43
constexpr uint32_t SP_RGBA32_A_U(uint32_t v)
Definition utils.h:39
constexpr double SP_RGBA32_B_F(uint32_t v)
Definition utils.h:51
const double w
Definition conic-4.cpp:19
Dim2
2D axis enumeration (X or Y).
Definition coord.h:48
@ Y
Definition coord.h:48
@ X
Definition coord.h:48
Specific geometry functions for Inkscape, not provided my lib2geom.
GenericRect< IntCoord > IntRect
Definition forward.h:57
Custom widgets.
Definition desktop.h:126
Colors::Color checkerboard_darken(Colors::Color color)
Definition util.cpp:45
Geom::PathVector outline(Geom::Path const &input, double width, double miter, LineJoinType join, LineCapType butt, double tolerance)
Strokes the path given by input.
A "fragment" is a rectangle of drawn content at a specfic place.
Definition fragment.h:12
Cairo::RectangleInt geom_to_cairo(const Geom::IntRect &rect)
Definition util.cpp:352