Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
canvas-item-text.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
6/*
7 * Author:
8 * Tavmjong Bah
9 *
10 * Copyright (C) 2020 Tavmjong Bah
11 *
12 * Rewrite of SPCtrlTextr
13 *
14 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
15 */
16
17#include "canvas-item-text.h"
18
19#include <cmath>
20#include <utility> // std::move
21#include <glibmm/i18n.h>
22
23#include "display/cairo-utils.h"
24#include "ui/util.h"
25
26namespace Inkscape {
27
32 : CanvasItem(group)
33{
34 _name = "CanvasItemText";
35 _fill = 0x33337fff; // Override CanvasItem default.
36}
37
41CanvasItemText::CanvasItemText(CanvasItemGroup *group, Geom::Point const &p, Glib::ustring text, bool scaled)
42 : CanvasItem(group)
43 , _p(p)
44 , _text(std::move(text))
45 , _scaled(scaled)
46{
47 _name = "CanvasItemText";
48 _fill = 0x33337fff; // Override CanvasItem default.
49
51}
52
57{
58 defer([=, this] {
59 if (_p == p) return;
60 _p = p;
62 });
63}
64
69{
70 defer([=, this] {
71 if (_bg_rad == rad) return;
72 _bg_rad = rad;
74 });
75}
76
80bool CanvasItemText::contains(Geom::Point const &p, double tolerance)
81{
82 return false; // We never select text.
83}
84
89{
90 // Queue redraw of old area (erase previous content).
92
93 // Point needs to be scaled manually if not cairo scaling
94 Geom::Point p = _scaled ? _p : _p * affine();
95
96 // Measure text size
98
99 // Offset relative to requested point
100 double offset_x = -(_anchor_position.x() * _text_box.width());
101 double offset_y = -(_anchor_position.y() * _text_box.height());
102 offset_x += p.x() + _adjust_offset.x();
103 offset_y += p.y() + _adjust_offset.y();
104 _text_box *= Geom::Translate(Geom::Point(offset_x, offset_y).floor());
105
106 // Pixel alignment of background. Avoid aliasing artifacts on redraw.
108
109 // Don't apply affine here, to keep text at the same size in screen coords.
111 if (_scaled && _bounds) {
112 *_bounds *= affine();
113 _bounds = _bounds->roundOutwards();
114 }
115
116 // Queue redraw of new area
118}
119
124{
125 buf.cr->save();
126
127 // Screen to desktop coords.
128 buf.cr->translate(-buf.rect.left(), -buf.rect.top());
129
130 if (_scaled) {
131 // Convert from canvas space to document space
132 buf.cr->transform(geom_to_cairo(affine()));
133 }
134
135 double x = _text_box.min().x();
136 double y = _text_box.min().y();
137 double w = _text_box.width();
138 double h = _text_box.height();
139
140 // Background
141 if (_use_background) {
142 if (_bg_rad == 0.0) {
143 buf.cr->rectangle(x, y, w, h);
144 } else {
145 double radius = _bg_rad * (std::min(w ,h) / 2);
146 buf.cr->arc(x + w - radius, y + radius, radius, -M_PI_2, 0);
147 buf.cr->arc(x + w - radius, y + h - radius, radius, 0, M_PI_2);
148 buf.cr->arc(x + radius, y + h - radius, radius, M_PI_2, M_PI);
149 buf.cr->arc(x + radius, y + radius, radius, M_PI, 3*M_PI_2);
150 }
151 buf.cr->set_line_width(2);
153 buf.cr->fill();
154 }
155
156 // Center the text inside the draw background box
157 auto bx = x + w / 2.0;
158 auto by = y + h / 2.0 + 1;
159 buf.cr->move_to(int(bx - _text_size.x_bearing - _text_size.width/2.0),
160 int(by - _text_size.y_bearing - _text_extent.height/2.0));
161
162 buf.cr->select_font_face(_fontname, Cairo::ToyFontFace::Slant::NORMAL, Cairo::ToyFontFace::Weight::NORMAL);
163 buf.cr->set_font_size(_fontsize);
164 buf.cr->text_path(_text);
165
167 buf.cr->fill();
168 buf.cr->restore();
169}
170
171void CanvasItemText::set_text(Glib::ustring text)
172{
173 defer([this, text = std::move(text)] () mutable {
174 if (_text == text) return;
175 _text = std::move(text);
176 request_update(); // Might be larger than before!
177 });
178}
179
180void CanvasItemText::set_fontsize(double fontsize)
181{
182 defer([=, this] {
183 if (_fontsize == fontsize) return;
184 _fontsize = fontsize;
185 request_update(); // Might be larger than before!
186 });
187}
188
190 return Geom::Rect::from_xywh(0, 0,
191 _text_size.x_advance + _border * 2,
192 _text_extent.height + _border * 2);
193}
194
199{
200 auto surface = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32, 1, 1);
201 auto context = Cairo::Context::create(surface);
202 context->select_font_face(_fontname, Cairo::ToyFontFace::Slant::NORMAL, Cairo::ToyFontFace::Weight::NORMAL);
203 context->set_font_size(_fontsize);
204 context->get_text_extents(_text, _text_size);
205
206 if (_fixed_line) {
207 // TRANSLATORS: This is a set of letters to test for font ascender and descenders.
208 context->get_text_extents(_("lg1p$"), _text_extent);
209 } else {
211 }
212
213 return Geom::Rect::from_xywh(0, 0,
214 _text_size.x_advance + _border * 2,
215 _text_extent.height + _border * 2);
216}
217
218void CanvasItemText::set_background(uint32_t background)
219{
220 defer([=, this] {
221 if (_background != background) {
222 _background = background;
224 }
225 _use_background = true;
226 });
227}
228
233{
234 defer([=, this] {
235 if (_anchor_position == anchor_pt) return;
236 _anchor_position = anchor_pt;
238 });
239}
240
242{
243 defer([=, this] {
244 if (_adjust_offset == adjust_pt) return;
245 _adjust_offset = adjust_pt;
247 });
248}
249
251{
252 defer([=, this] {
253 if (_fixed_line == fixed_line) return;
254 _fixed_line = fixed_line;
256 });
257}
258
260{
261 defer([=, this] {
262 if (_border == border) return;
263 _border = border;
265 });
266}
267
268} // namespace Inkscape
269
270/* FROM: http://lists.cairographics.org/archives/cairo-bugs/2009-March/003014.html
271 - Glyph surfaces: In most font rendering systems, glyph surfaces
272 have an origin at (0,0) and a bounding box that is typically
273 represented as (x_bearing,y_bearing,width,height). Depending on
274 which way y progresses in the system, y_bearing may typically be
275 negative (for systems similar to cairo, with origin at top left),
276 or be positive (in systems like PDF with origin at bottom left).
277 No matter which is the case, it is important to note that
278 (x_bearing,y_bearing) is the coordinates of top-left of the glyph
279 relative to the glyph origin. That is, for example:
280
281 Scaled-glyph space:
282
283 (x_bearing,y_bearing) <-- negative numbers
284 +----------------+
285 | . |
286 | . |
287 |......(0,0) <---|-- glyph origin
288 | |
289 | |
290 +----------------+
291 (width+x_bearing,height+y_bearing)
292
293 Note the similarity of the origin to the device space. That is
294 exactly how we use the device_offset to represent scaled glyphs:
295 to use the device-space origin as the glyph origin.
296*/
297
298/*
299 Local Variables:
300 mode:c++
301 c-file-style:"stroustrup"
302 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
303 indent-tabs-mode:nil
304 fill-column:99
305 End:
306*/
307// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
void ink_cairo_set_source_rgba32(cairo_t *ct, guint32 rgba)
Cairo integration helpers.
Cairo::RefPtr< Cairo::ImageSurface > surface
Definition canvas.cpp:137
static CRect from_xywh(Coord x, Coord y, Coord w, Coord h)
Create rectangle from origin and dimensions.
C height() const
Get the vertical extent of the rectangle.
C width() const
Get the horizontal extent of the rectangle.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
Two-dimensional point that doubles as a vector.
Definition point.h:66
constexpr Coord y() const noexcept
Definition point.h:106
constexpr Coord x() const noexcept
Definition point.h:104
Axis aligned, non-empty rectangle.
Definition rect.h:92
IntRect roundOutwards() const
Return the smallest integer rectangle which contains this one.
Definition rect.h:141
Translation by a vector.
Definition transforms.h:115
Geom::Rect get_text_size() const
Cairo::TextExtents _text_size
bool contains(Geom::Point const &p, double tolerance=0) override
Returns true if point p (in canvas units) is within tolerance (canvas units) distance of text.
void set_fontsize(double fontsize)
void set_border(double border)
void set_anchor(Geom::Point const &anchor_pt)
Set the anchor point, x and y between 0.0 and 1.0.
void set_background(uint32_t background)
void _render(Inkscape::CanvasItemBuffer &buf) const override
Render text to screen via Cairo.
CanvasItemText(CanvasItemGroup *group)
Create a null control text.
void set_fixed_line(bool fixed_line)
void set_adjust(Geom::Point const &adjust_pt)
Geom::Rect load_text_extents()
Load the sizes of the text extent using the given font.
void set_text(Glib::ustring text)
void _update(bool propagate) override
Update and redraw control text.
void set_coord(Geom::Point const &p)
Set a text position.
Cairo::TextExtents _text_extent
void set_bg_radius(double rad)
Set a text position.
Geom::OptRect _bounds
Geom::Affine const & affine() const
const double w
Definition conic-4.cpp:19
auto floor(Geom::Rect const &rect)
Definition geom.h:131
Helper class to stream background task notifications as a series of messages.
STL namespace.
int buf
Class used when rendering canvas items.
double border
Cairo::RectangleInt geom_to_cairo(const Geom::IntRect &rect)
Definition util.cpp:338