File: sec-cairo-drawing-lines.html

package info (click to toggle)
gtkmm-documentation 4.12.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 25,772 kB
  • sloc: cpp: 15,541; javascript: 1,208; makefile: 1,080; python: 401; xml: 106; perl: 67; sh: 8
file content (462 lines) | stat: -rw-r--r-- 17,445 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="highlight.min.css">
<script src="highlight.min.js"></script><script>
      hljs.configure({languages: ['cpp']});
      hljs.highlightAll();
    </script><title>Drawing Straight Lines</title>
<link rel="stylesheet" type="text/css" href="style.css">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<link rel="home" href="index.html" title="Programming with gtkmm 4">
<link rel="up" href="chapter-drawingarea.html" title="Chapter 18. The DrawingArea Widget">
<link rel="prev" href="chapter-drawingarea.html" title="Chapter 18. The DrawingArea Widget">
<link rel="next" href="sec-cairo-curved-lines.html" title="Drawing Curved Lines">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">Drawing Straight Lines</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="chapter-drawingarea.html"><img src="icons/prev.png" alt="Prev"></a> </td>
<th width="60%" align="center">Chapter 18. The DrawingArea Widget</th>
<td width="20%" align="right"> <a accesskey="n" href="sec-cairo-curved-lines.html"><img src="icons/next.png" alt="Next"></a>
</td>
</tr>
</table>
<hr>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="sec-cairo-drawing-lines"></a>Drawing Straight Lines</h2></div></div></div>
  
    <p>
        Now that we understand the basics of the Cairo graphics library, we're
        almost ready to start drawing. We'll start with the simplest of
        drawing elements: the straight line. But first you need to know a
        little bit about Cairo's coordinate system. The origin of the Cairo
        coordinate system is located in the upper-left corner of the window
        with positive x values to the right and positive y values going down.
        </p>
<div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="icons/tip.png"></td>
<th align="left">Tip</th>
</tr>
<tr><td align="left" valign="top">
            <p>Since the Cairo graphics library was written with support for
            multiple output targets (the X window system, PNG images, OpenGL,
            etc), there is a distinction between user-space and device-space
            coordinates. The mapping between these two coordinate systems
            defaults to one-to-one so that integer values map roughly to pixels
            on the screen, but this setting can be adjusted if desired.
            Sometimes it may be useful to scale the coordinates so that the
            full width and height of a window both range from 0 to 1 (the 'unit
            square') or some other mapping that works for your application.
            This can be done with the
            <code class="methodname">Cairo::Context::scale()</code> function.</p>
        </td></tr>
</table></div>
<p>
    </p>

    <div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="cairo-example-lines"></a>Example</h3></div></div></div>
    
    <p>
        In this example, we'll construct a small but fully functional <span class="application">gtkmm</span>
        program and draw some lines into the window. The lines are drawn by
        creating a path and then stroking it. A path is created using the
        functions <code class="methodname">Cairo::Context::move_to()</code> and
        <code class="methodname">Cairo::Context::line_to()</code>. The function
        <code class="methodname">move_to()</code> is similar to the act of lifting your
        pen off of the paper and placing it somewhere else -- no line is drawn
        between the point you were at and the point you moved to. To draw a
        line between two points, use the <code class="methodname">line_to()</code>
        function.
    </p>
    <p>
        After you've finished creating your path, you still haven't
        drawn anything visible yet. To make the path visible, you must use the
        function <code class="methodname">stroke()</code> which will stroke the current
        path with the line width and style specified in your
        <code class="classname">Cairo::Context</code> object. After stroking, the
        current path will be cleared so that you can start on your next path.
    </p>
        <div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="icons/tip.png"></td>
<th align="left">Tip</th>
</tr>
<tr><td align="left" valign="top">
            <p>Many Cairo drawing functions have a <code class="methodname">_preserve()</code>
            variant. Normally drawing functions such as
            <code class="methodname">clip()</code>, <code class="methodname">fill()</code>, or
            <code class="methodname">stroke()</code> will clear the current path. If you
            use the <code class="methodname">_preserve()</code> variant, the current path
            will be retained so that you can use the same path with the next
            drawing function.</p>
        </td></tr>
</table></div>

    <div class="figure">
<a name="figure-drawingarea-lines"></a><p class="title"><b>Figure 18.1. Drawing Area - Lines</b></p>
<div class="figure-contents">
      
      <div class="screenshot">
        <div class="mediaobject"><img src="figures/drawingarea_lines.png" alt="Drawing Area - Lines"></div>
      </div>
    </div>
</div>
<br class="figure-break">

<p><a class="ulink" href="https://gitlab.gnome.org/GNOME/gtkmm-documentation/tree/master/examples/book/drawingarea/simple" target="_top">Source Code</a></p>

<p>File: <code class="filename">myarea.h</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#ifndef GTKMM_EXAMPLE_MYAREA_H
#define GTKMM_EXAMPLE_MYAREA_H

#include &lt;gtkmm/drawingarea.h&gt;

class MyArea : public Gtk::DrawingArea
{
public:
  MyArea();
  virtual ~MyArea();

protected:
  void on_draw(const Cairo::RefPtr&lt;Cairo::Context&gt;&amp; cr, int width, int height);
};

#endif // GTKMM_EXAMPLE_MYAREA_H
</code></pre>
<p>File: <code class="filename">main.cc</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "myarea.h"
#include &lt;gtkmm/application.h&gt;
#include &lt;gtkmm/window.h&gt;

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();

protected:
  MyArea m_area;
};

ExampleWindow::ExampleWindow()
{
  set_title("DrawingArea");
  set_child(m_area);
}

int main(int argc, char** argv)
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  return app-&gt;make_window_and_run&lt;ExampleWindow&gt;(argc, argv);
}
</code></pre>
<p>File: <code class="filename">myarea.cc</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "myarea.h"
#include &lt;cairomm/context.h&gt;

MyArea::MyArea()
{
  set_draw_func(sigc::mem_fun(*this, &amp;MyArea::on_draw));
}

MyArea::~MyArea()
{
}

void MyArea::on_draw(const Cairo::RefPtr&lt;Cairo::Context&gt;&amp; cr, int width, int height)
{
  // coordinates for the center of the window
  int xc, yc;
  xc = width / 2;
  yc = height / 2;

  cr-&gt;set_line_width(10.0);

  // draw red lines out from the center of the window
  cr-&gt;set_source_rgb(0.8, 0.0, 0.0);
  cr-&gt;move_to(0, 0);
  cr-&gt;line_to(xc, yc);
  cr-&gt;line_to(0, height);
  cr-&gt;move_to(xc, yc);
  cr-&gt;line_to(width, yc);
  cr-&gt;stroke();
}
</code></pre>


    <p>
        This program contains a single class, <code class="classname">MyArea</code>,
        which is a subclass of <code class="classname">Gtk::DrawingArea</code> and
        contains an <code class="methodname">on_draw()</code> member function.
        This function becomes the draw function by a call to <code class="methodname">set_draw_func()</code>
        in <code class="classname">MyArea</code>'s constructor. <code class="methodname">on_draw()</code>
        is then called whenever the image in the drawing area needs to
        be redrawn. It is passed a <code class="classname">Cairo::RefPtr</code>
        pointer to a <code class="classname">Cairo::Context</code> that we use
        for the drawing.
        The actual drawing code sets the color we want to use for drawing by
        using <code class="methodname">set_source_rgb()</code> which takes arguments
        defining the Red, Green, and Blue components of the desired color
        (valid values are between 0 and 1). After setting the color, we
        created a new path using the functions <code class="methodname">move_to()</code>
        and <code class="methodname">line_to()</code>, and then stroked this path with
        <code class="methodname">stroke()</code>.
    </p>
    <div class="tip" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Tip: Drawing with relative coordinates">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Tip]" src="icons/tip.png"></td>
<th align="left">Drawing with relative coordinates</th>
</tr>
<tr><td align="left" valign="top">
        
        <p>In the example above we drew everything using absolute coordinates. You can also draw using
        relative coordinates. For a straight line, this is done with the
        function <code class="methodname">Cairo::Context::rel_line_to()</code>.</p>
    </td></tr>
</table></div>
    </div>

    <div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="cairo-line-styles"></a>Line styles</h3></div></div></div>
    
        <p>
            In addition to drawing basic straight lines, there are a number of
            things that you can customize about a line. You've already seen
            examples of setting a line's color and width, but there are others
            as well.
        </p>
        <p>
            If you've drawn a series of lines that form a path, you may
            want them to join together in a certain way. Cairo offers
            three different ways to join lines together: Miter, Bevel, and
            Round. These are show below:
        </p>
        <div class="figure">
<a name="figure-cairo-joins"></a><p class="title"><b>Figure 18.2. Different join types in Cairo</b></p>
<div class="figure-contents">
          
            <div class="screenshot">
                <div class="mediaobject"><img src="figures/cairo_joins.png" alt="Different join types in Cairo"></div>
            </div>
        </div>
</div>
<br class="figure-break">
        <p>
            The line join style is set using the function
            <code class="methodname">Cairo::Context::set_line_join()</code>.
        </p>
        <p>
            Line ends can have different styles as well. The default style
            is for the line to start and stop exactly at the destination
            points of the line. This is called a Butt cap. The other
            options are Round (uses a round ending, with the center of the
            circle at the end point) or Square (uses a squared ending, with
            the center of the square at the end point). This setting is set
            using the function
            <code class="methodname">Cairo::Context::set_line_cap()</code>.
        </p>
        <p>
            There are other things you can customize as well, including
            creating dashed lines and other things. For more information, see
            the Cairo API documentation.
        </p>
    </div>

    <div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="sec-cairo-thin-lines"></a>Drawing thin lines</h3></div></div></div>
    
      <p>
        If you try to draw one pixel wide lines, you may notice that the line
        sometimes comes up blurred and wider than it ought to be.
        This happens because Cairo will try to draw from the selected position,
        to both sides (half to each), so if you're positioned right on the
        intersection of the pixels, and want a one pixel wide line, Cairo will try
        to use half of each adjacent pixel, which isn't possible (a pixel is the
        smallest unit possible). This happens when the width of the line is an
        odd number of pixels (not just one pixel).
      </p>
      <p>
        The trick is to position in the middle of the pixel where you want the
        line to be drawn, and thus guaranteeing you get the desired results.
        See <a class="ulink" href="http://cairographics.org/FAQ/#sharp_lines" target="_top">Cairo FAQ</a>.
      </p>

      <div class="figure">
<a name="figure-drawingarea-thin-lines"></a><p class="title"><b>Figure 18.3. Drawing Area - Thin Lines</b></p>
<div class="figure-contents">
        
        <div class="screenshot">
          <div class="mediaobject"><img src="figures/drawingarea_thin_lines.png" alt="Drawing Area - Thin Lines"></div>
        </div>
      </div>
</div>
<br class="figure-break">

<p><a class="ulink" href="https://gitlab.gnome.org/GNOME/gtkmm-documentation/tree/master/examples/book/drawingarea/thin_lines" target="_top">Source Code</a></p>

<p>File: <code class="filename">examplewindow.h</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H

#include &lt;gtkmm/window.h&gt;
#include &lt;gtkmm/box.h&gt;
#include &lt;gtkmm/checkbutton.h&gt;
#include "myarea.h"

class ExampleWindow : public Gtk::Window
{
public:
  ExampleWindow();
  virtual ~ExampleWindow();

protected:
  //Signal handlers:
  void on_button_toggled();

private:
  Gtk::Box m_HBox;
  MyArea m_Area_Lines;
  Gtk::CheckButton m_Button_FixLines;
};

#endif //GTKMM_EXAMPLEWINDOW_H
</code></pre>
<p>File: <code class="filename">myarea.h</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#ifndef GTKMM_EXAMPLE_MYAREA_H
#define GTKMM_EXAMPLE_MYAREA_H

#include &lt;gtkmm/drawingarea.h&gt;

class MyArea : public Gtk::DrawingArea
{
public:
  MyArea();
  virtual ~MyArea();

  void fix_lines(bool fix = true);

protected:
  void on_draw(const Cairo::RefPtr&lt;Cairo::Context&gt;&amp; cr, int width, int height);

private:
  double m_fix;
};

#endif // GTKMM_EXAMPLE_MYAREA_H
</code></pre>
<p>File: <code class="filename">examplewindow.cc</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "examplewindow.h"

ExampleWindow::ExampleWindow()
: m_HBox(Gtk::Orientation::HORIZONTAL),
  m_Button_FixLines("Fix lines")
{
  set_title("Thin lines example");

  m_HBox.append(m_Area_Lines);
  m_HBox.append(m_Button_FixLines);

  set_child(m_HBox);

  m_Button_FixLines.signal_toggled().connect(
    sigc::mem_fun(*this, &amp;ExampleWindow::on_button_toggled));

  // Synchonize the drawing in m_Area_Lines with the state of the toggle button.
  on_button_toggled();
}

ExampleWindow::~ExampleWindow()
{
}

void ExampleWindow::on_button_toggled()
{
  m_Area_Lines.fix_lines(m_Button_FixLines.get_active());
}
</code></pre>
<p>File: <code class="filename">main.cc</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "examplewindow.h"
#include &lt;gtkmm/application.h&gt;

int main(int argc, char* argv[])
{
  auto app = Gtk::Application::create("org.gtkmm.example");

  //Shows the window and returns when it is closed.
  return app-&gt;make_window_and_run&lt;ExampleWindow&gt;(argc, argv);
}
</code></pre>
<p>File: <code class="filename">myarea.cc</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "myarea.h"

MyArea::MyArea()
: m_fix (0)
{
  set_content_width(200);
  set_content_height(100);
  set_draw_func(sigc::mem_fun(*this, &amp;MyArea::on_draw));
}

MyArea::~MyArea()
{
}

void MyArea::on_draw(const Cairo::RefPtr&lt;Cairo::Context&gt;&amp; cr, int width, int height)
{
  cr-&gt;set_line_width(1.0);

  // draw one line, every two pixels
  // without the 'fix', you won't notice any space between the lines,
  // since each one will occupy two pixels (width)
  for (int i = 0; i &lt; width; i += 2)
  {
    cr-&gt;move_to(i + m_fix, 0);
    cr-&gt;line_to(i + m_fix, height);
  }

  cr-&gt;stroke();
}

// Toogle between both values (0 or 0.5)
void MyArea::fix_lines(bool fix)
{
  // to get the width right, we have to draw in the middle of the pixel
  m_fix = fix ? 0.5 : 0.0;

  // force the redraw of the image
  queue_draw();
}
</code></pre>

    </div>
  </div>
<div class="navfooter">
<hr>
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="chapter-drawingarea.html"><img src="icons/prev.png" alt="Prev"></a> </td>
<td width="20%" align="center"><a accesskey="u" href="chapter-drawingarea.html"><img src="icons/up.png" alt="Up"></a></td>
<td width="40%" align="right"> <a accesskey="n" href="sec-cairo-curved-lines.html"><img src="icons/next.png" alt="Next"></a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">Chapter 18. The DrawingArea Widget </td>
<td width="20%" align="center"><a accesskey="h" href="index.html"><img src="icons/home.png" alt="Home"></a></td>
<td width="40%" align="right" valign="top"> Drawing Curved Lines</td>
</tr>
</table>
</div>
</body>
</html>