Section 22, 24 and 25 are updated.
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
BIN
docs/image/turtle_snow.png
Normal file
After Width: | Height: | Size: 83 KiB |
|
@ -119,19 +119,18 @@ called custom drawing.</p>
|
|||
<p>GtkDrawingArea provides a cairo drawing context so users can draw
|
||||
images by using cairo functions. In this section, I will explain:</p>
|
||||
<ol type="1">
|
||||
<li>Cairo, but only briefly; and</li>
|
||||
<li>Cairo, but only briefly</li>
|
||||
<li>GtkDrawingArea, with a very simple example.</li>
|
||||
</ol>
|
||||
<h2 id="cairo">Cairo</h2>
|
||||
<p>Cairo is a set of two dimensional graphical drawing functions (or
|
||||
graphics library). There is a lot of documentation on <a
|
||||
graphics library). There are a lot of documents on <a
|
||||
href="https://www.cairographics.org/">Cairo’s website</a>. If you aren’t
|
||||
familiar with Cairo, it is worth reading their <a
|
||||
familiar with Cairo, it is worth reading the <a
|
||||
href="https://www.cairographics.org/tutorial/">tutorial</a>.</p>
|
||||
<p>The following is a gentle introduction to the Cairo library and how
|
||||
to use it. Firstly, in order to use Cairo you need to know about
|
||||
surfaces, sources, masks, destinations, cairo context and
|
||||
transformations.</p>
|
||||
<p>The following is an introduction to the Cairo library and how to use
|
||||
it. First, you need to know about surfaces, sources, masks,
|
||||
destinations, cairo context and transformations.</p>
|
||||
<ul>
|
||||
<li>A surface represents an image. It is like a canvas. We can draw
|
||||
shapes and images with different colors on surfaces.</li>
|
||||
|
@ -169,7 +168,8 @@ the paint in the source to the destination.</li>
|
|||
<li>Save the destination surface to a file if necessary.</li>
|
||||
</ol>
|
||||
<p>Here’s a simple example program that draws a small square and saves
|
||||
it as a png file.</p>
|
||||
it as a png file. The path of the file is
|
||||
<code>src/misc/cairo.c</code>.</p>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="pp">#include </span><span class="im"><cairo.h></span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a></span>
|
||||
|
@ -222,10 +222,10 @@ color depth. Width and height are in pixels and given as integers.</li>
|
|||
<li>14: Creates cairo context. The surface given as an argument will be
|
||||
the destination of the context.</li>
|
||||
<li>18: <code>cairo_set_source_rgb</code> creates a source pattern,
|
||||
which in this case is a solid white paint. The second to fourth argument
|
||||
are red, green and blue color values respectively, and they are of type
|
||||
float. The values are between zero (0.0) and one (1.0), with black being
|
||||
given by (0.0,0.0,0.0) and white by (1.0,1.0,1.0).</li>
|
||||
which in this case is a solid white paint. The second to fourth
|
||||
arguments are red, green and blue color values respectively, and they
|
||||
are of type float. The values are between zero (0.0) and one (1.0), with
|
||||
black being given by (0.0,0.0,0.0) and white by (1.0,1.0,1.0).</li>
|
||||
<li>19: <code>cairo_paint</code> copies everywhere in the source to
|
||||
destination. The destination is filled with white pixels with this
|
||||
command.</li>
|
||||
|
@ -244,14 +244,15 @@ through the rectangle in the mask.</li>
|
|||
destroyed.</li>
|
||||
<li>29: Destroys the surface.</li>
|
||||
</ul>
|
||||
<p>To compile this, type the following.</p>
|
||||
<p>To compile this, change your current directory to
|
||||
<code>src/misc</code> and type the following.</p>
|
||||
<pre><code>$ gcc `pkg-config --cflags cairo` cairo.c `pkg-config --libs cairo`</code></pre>
|
||||
<figure>
|
||||
<img src="image/rectangle.png" alt="rectangle.png" />
|
||||
<figcaption aria-hidden="true">rectangle.png</figcaption>
|
||||
</figure>
|
||||
<p>See the <a href="https://www.cairographics.org/">Cairo’s website</a>
|
||||
for more details.</p>
|
||||
for further information.</p>
|
||||
<h2 id="gtkdrawingarea">GtkDrawingArea</h2>
|
||||
<p>The following is a very simple example.</p>
|
||||
<div class="sourceCode" id="cb3"><pre
|
||||
|
@ -302,15 +303,15 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
functions <code>app_activate</code> and <code>draw_function</code> are
|
||||
important in this example.</p>
|
||||
<ul>
|
||||
<li>18: Creates a GtkDrawingArea instance; and</li>
|
||||
<li>21: Sets a drawing function of the widget. GtkDrawingArea widget
|
||||
<li>22: Creates a GtkDrawingArea instance.</li>
|
||||
<li>25: Sets a drawing function of the widget. GtkDrawingArea widget
|
||||
uses the function to draw the contents of itself whenever its necessary.
|
||||
For example, when a user drag a mouse pointer and resize a top-level
|
||||
window, GtkDrawingArea also changes the size. Then, the whole window
|
||||
needs to be redrawn. For the information of
|
||||
<code>gtk_drawing_area_set_draw_func</code>, see <a
|
||||
href="https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html">Gtk
|
||||
API Reference, gtk_drawing_area_set_draw_func</a>.</li>
|
||||
API Reference – gtk_drawing_area_set_draw_func</a>.</li>
|
||||
</ul>
|
||||
<p>The drawing function has five parameters.</p>
|
||||
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> drawing_function <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> cairo_t <span class="op">*</span>cr<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span></span>
|
||||
|
@ -322,20 +323,20 @@ cairo context given by the widget. The destination surface of the
|
|||
context is connected to the contents of the widget. What you draw to
|
||||
this surface will appear in the widget on the screen. The third and
|
||||
fourth parameters are the size of the destination surface. Now, look at
|
||||
the program example again.</p>
|
||||
the program again.</p>
|
||||
<ul>
|
||||
<li>3-13: The drawing function.</li>
|
||||
<li>3-17: The drawing function.</li>
|
||||
<li>7-8: Sets the source to be white and paint the destination
|
||||
white.</li>
|
||||
<li>9: Sets the line width to be 2.</li>
|
||||
<li>10: Sets the source to be black.</li>
|
||||
<li>11: Adds a rectangle to the mask.</li>
|
||||
<li>12: Draws the rectangle with black color to the destination.</li>
|
||||
<li>11-15: Adds a rectangle to the mask.</li>
|
||||
<li>16: Draws the rectangle with black color to the destination.</li>
|
||||
</ul>
|
||||
<p>Compile and run it, then a window with a black rectangle (square)
|
||||
appears. Try resizing the window. The square always appears at the
|
||||
center of the window because the drawing function is invoked each time
|
||||
the window is resized.</p>
|
||||
<p>The program is src/misc/da1.c. Compile and run it, then a window with
|
||||
a black rectangle (square) appears. Try resizing the window. The square
|
||||
always appears at the center of the window because the drawing function
|
||||
is invoked each time the window is resized.</p>
|
||||
<figure>
|
||||
<img src="image/da1.png" alt="Square in the window" />
|
||||
<figcaption aria-hidden="true">Square in the window</figcaption>
|
||||
|
|
486
docs/sec24.html
|
@ -121,7 +121,7 @@ of GtkDrawingArea changes to the color given by you.</p>
|
|||
<img src="image/color.png" alt="color" />
|
||||
<figcaption aria-hidden="true">color</figcaption>
|
||||
</figure>
|
||||
<p>The following colors are available.</p>
|
||||
<p>The following colors are available. (without new line charactor)</p>
|
||||
<ul>
|
||||
<li>white</li>
|
||||
<li>black</li>
|
||||
|
@ -141,10 +141,9 @@ turtle graphics language like Logo program language.</p>
|
|||
<p>In this section, we focus on how to bind the two objects.</p>
|
||||
<h2 id="color.ui-and-color.gresource.xml">Color.ui and
|
||||
color.gresource.xml</h2>
|
||||
<p>First, We need to make the ui file of the widgets. The image in the
|
||||
previous subsection gives us the structure of the widgets. Title bar,
|
||||
four buttons in the tool bar and two widgets textview and drawing area.
|
||||
The ui file is as follows.</p>
|
||||
<p>First, We need to make the ui file of the widgets. Title bar, four
|
||||
buttons in the tool bar, textview and drawing area. The ui file is as
|
||||
follows.</p>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb1-1"><a href="#cb1-1"></a><span class="fu"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2"></a><<span class="kw">interface</span>></span>
|
||||
|
@ -227,21 +226,22 @@ class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><sp
|
|||
<span id="cb1-79"><a href="#cb1-79"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb1-80"><a href="#cb1-80"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<ul>
|
||||
<li>10-53: This part is the tool bar which has four buttons,
|
||||
<code>Run</code>, <code>Open</code>, <code>Save</code> and
|
||||
<code>Close</code>. This is similar to the toolbar of tfe text editor in
|
||||
<a href="sec9.html">Section 9</a>. There are two differences.
|
||||
<li>10-53: The horizontal box <code>boxh1</code> makes a tool bar which
|
||||
has four buttons, <code>Run</code>, <code>Open</code>, <code>Save</code>
|
||||
and <code>Close</code>. This is similar to the <code>tfe</code> text
|
||||
editor in <a href="sec9.html">Section 9</a>. There are two differences.
|
||||
<code>Run</code> button replaces <code>New</code> button. A signal
|
||||
element is added to each button object. It has “name” attribute which is
|
||||
a signal name and “handler” attribute which is the name of its signal
|
||||
handler function. Options “-WI, –export-dynamic” CFLAG is necessary when
|
||||
you compile the application. You can achieve this by adding
|
||||
“export_dynamic: true” argument to executable function in
|
||||
<code>meson.build</code>. And be careful that the handler must be
|
||||
defined without ‘static’ class.</li>
|
||||
<li>54-76: Puts GtkScrolledWindow and GtkDrawingArea into GtkBox. GtkBox
|
||||
has “homogeneous property” with TRUE value, so the two children have the
|
||||
same width in the box. TfeTextView is a child of GtkScrolledWindow.</li>
|
||||
handler. Options “-WI, –export-dynamic” CFLAG is necessary when you
|
||||
compile the application. You can achieve this by adding “export_dynamic:
|
||||
true” argument to the executable function in <code>meson.build</code>.
|
||||
And be careful that the handler must be defined without ‘static’
|
||||
class.</li>
|
||||
<li>54-76: The horizontal box <code>boxh2</code> includes
|
||||
GtkScrolledWindow and GtkDrawingArea. GtkBox has “homogeneous property”
|
||||
with TRUE value, so the two children have the same width in the box.
|
||||
TfeTextView is a child of GtkScrolledWindow.</li>
|
||||
</ul>
|
||||
<p>The xml file for the resource compiler is almost same as before. Just
|
||||
substitute “color” for “tfe”.</p>
|
||||
|
@ -252,216 +252,278 @@ class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><sp
|
|||
<span id="cb2-4"><a href="#cb2-4"></a> <<span class="kw">file</span>>color.ui</<span class="kw">file</span>></span>
|
||||
<span id="cb2-5"><a href="#cb2-5"></a> </<span class="kw">gresource</span>></span>
|
||||
<span id="cb2-6"><a href="#cb2-6"></a></<span class="kw">gresources</span>></span></code></pre></div>
|
||||
<h2 id="tfetextview.h-tfetextview.c-and-color.h">Tfetextview.h,
|
||||
tfetextview.c and color.h</h2>
|
||||
<p>First two files are the same as before. Color.h just includes
|
||||
tfetextview.h.</p>
|
||||
<h2 id="drawing-function-and-surface">Drawing function and surface</h2>
|
||||
<p>The main point of this program is a drawing function.</p>
|
||||
<div class="sourceCode" id="cb3"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a><span class="pp">#include </span><span class="im">"../tfetextview/tfetextview.h"</span></span></code></pre></div>
|
||||
<h2 id="colorapplication.c">Colorapplication.c</h2>
|
||||
<p>This is the main file. It deals with:</p>
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a>draw_func <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> cairo_t <span class="op">*</span>cr<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb3-6"><a href="#cb3-6"></a> <span class="op">}</span></span>
|
||||
<span id="cb3-7"><a href="#cb3-7"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The <code>surface</code> variable in line 3 is a static variable.</p>
|
||||
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> cairo_surface_t <span class="op">*</span>surface <span class="op">=</span> NULL<span class="op">;</span></span></code></pre></div>
|
||||
<p>The drawing function just copies the <code>surface</code> to its own
|
||||
surface with the <code>cairo_paint</code> function. The surface (pointed
|
||||
by the static variable <code>surface</code>) is built by the
|
||||
<code>run</code> function.</p>
|
||||
<div class="sourceCode" id="cb5"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a>run <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a> GtkTextBuffer <span class="op">*</span>tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a> GtkTextIter start_iter<span class="op">;</span></span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a> GtkTextIter end_iter<span class="op">;</span></span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a> <span class="dt">char</span> <span class="op">*</span>contents<span class="op">;</span></span>
|
||||
<span id="cb5-7"><a href="#cb5-7"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||||
<span id="cb5-8"><a href="#cb5-8"></a></span>
|
||||
<span id="cb5-9"><a href="#cb5-9"></a> gtk_text_buffer_get_bounds <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">);</span></span>
|
||||
<span id="cb5-10"><a href="#cb5-10"></a> contents <span class="op">=</span> gtk_text_buffer_get_text <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">,</span> FALSE<span class="op">);</span></span>
|
||||
<span id="cb5-11"><a href="#cb5-11"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-12"><a href="#cb5-12"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb5-13"><a href="#cb5-13"></a> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"red"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-14"><a href="#cb5-14"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb5-15"><a href="#cb5-15"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"green"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-16"><a href="#cb5-16"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb5-17"><a href="#cb5-17"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"blue"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-18"><a href="#cb5-18"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb5-19"><a href="#cb5-19"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"white"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-20"><a href="#cb5-20"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb5-21"><a href="#cb5-21"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"black"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-22"><a href="#cb5-22"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb5-23"><a href="#cb5-23"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"light"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-24"><a href="#cb5-24"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb5-25"><a href="#cb5-25"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"dark"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-26"><a href="#cb5-26"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb5-27"><a href="#cb5-27"></a> <span class="cf">else</span></span>
|
||||
<span id="cb5-28"><a href="#cb5-28"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb5-29"><a href="#cb5-29"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb5-30"><a href="#cb5-30"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb5-31"><a href="#cb5-31"></a> <span class="op">}</span></span>
|
||||
<span id="cb5-32"><a href="#cb5-32"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
|
||||
<span id="cb5-33"><a href="#cb5-33"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>Building widgets by GtkBuilder.</li>
|
||||
<li>Setting a drawing function of GtkDrawingArea. And connecting a
|
||||
handler to “resize” signal on GtkDrawingArea.</li>
|
||||
<li>Implementing each call back functions. Particularly,
|
||||
<code>Run</code> signal handler is the point in this program.</li>
|
||||
<li>9-10: Gets the string in the GtkTextBuffer and inserts it to
|
||||
<code>contents</code>.</li>
|
||||
<li>11: If the variable <code>surface</code> points a surface instance,
|
||||
it is painted as follows.</li>
|
||||
<li>12- 30: The source is set based on the string <code>contents</code>
|
||||
and copied to the surface with <code>cairo_paint</code>.</li>
|
||||
<li>24,26: Alpha channel is used in “light” and “dark” procedure.</li>
|
||||
</ul>
|
||||
<p>The drawing area just reflects the <code>surface</code>. But one
|
||||
problem is resizing. If a user resizes the main window, the drawing area
|
||||
is also resized. It makes size difference between the surface and the
|
||||
drawing area. So, the surface needs to be resized to fit the drawing
|
||||
area.</p>
|
||||
<p>It is accomplished by connecting the “resize” signal on the drawing
|
||||
area to a handler.</p>
|
||||
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>g_signal_connect <span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>da<span class="op">),</span> <span class="st">"resize"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>resize_cb<span class="op">),</span> NULL<span class="op">);</span></span></code></pre></div>
|
||||
<p>The handler is as follows.</p>
|
||||
<div class="sourceCode" id="cb7"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb7-2"><a href="#cb7-2"></a>resize_cb <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb7-3"><a href="#cb7-3"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb7-4"><a href="#cb7-4"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb7-5"><a href="#cb7-5"></a> surface <span class="op">=</span> cairo_image_surface_create <span class="op">(</span>CAIRO_FORMAT_ARGB32<span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
|
||||
<span id="cb7-6"><a href="#cb7-6"></a> run <span class="op">();</span></span>
|
||||
<span id="cb7-7"><a href="#cb7-7"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>If the variable <code>surface</code> sets a surface instance, it is
|
||||
destroyed. A new surface is created and its size fits the drawing area.
|
||||
The surface is assigned to the variable <code>surface</code>. The
|
||||
function <code>run</code> is called and the surface is colored.</p>
|
||||
<p>The signal is emitted when:</p>
|
||||
<ul>
|
||||
<li>The drawing area is realized (it appears on the display).</li>
|
||||
<li>It is changed (resized) while realized</li>
|
||||
</ul>
|
||||
<p>So, the first surface is created when it is realized.</p>
|
||||
<h2 id="colorapplication.c">Colorapplication.c</h2>
|
||||
<p>This is the main file.</p>
|
||||
<ul>
|
||||
<li>Builds widgets by GtkBuilder.</li>
|
||||
<li>Sets a drawing function for GtkDrawingArea. And connects a handler
|
||||
to the “resize” signal on the GtkDrawingArea instance.</li>
|
||||
<li>Implements each call back function. Particularly, <code>Run</code>
|
||||
signal handler is the point in this program.</li>
|
||||
</ul>
|
||||
<p>The following is <code>colorapplication.c</code>.</p>
|
||||
<div class="sourceCode" id="cb4"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="pp">#include </span><span class="im">"color.h"</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a></span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a><span class="dt">static</span> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a><span class="dt">static</span> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span>
|
||||
<span id="cb4-5"><a href="#cb4-5"></a><span class="dt">static</span> GtkWidget <span class="op">*</span>da<span class="op">;</span></span>
|
||||
<span id="cb4-6"><a href="#cb4-6"></a></span>
|
||||
<span id="cb4-7"><a href="#cb4-7"></a><span class="dt">static</span> cairo_surface_t <span class="op">*</span>surface <span class="op">=</span> NULL<span class="op">;</span></span>
|
||||
<span id="cb4-8"><a href="#cb4-8"></a></span>
|
||||
<span id="cb4-9"><a href="#cb4-9"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-10"><a href="#cb4-10"></a>run <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-11"><a href="#cb4-11"></a> GtkTextBuffer <span class="op">*</span>tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||||
<span id="cb4-12"><a href="#cb4-12"></a> GtkTextIter start_iter<span class="op">;</span></span>
|
||||
<span id="cb4-13"><a href="#cb4-13"></a> GtkTextIter end_iter<span class="op">;</span></span>
|
||||
<span id="cb4-14"><a href="#cb4-14"></a> <span class="dt">char</span> <span class="op">*</span>contents<span class="op">;</span></span>
|
||||
<span id="cb4-15"><a href="#cb4-15"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||||
<span id="cb4-16"><a href="#cb4-16"></a></span>
|
||||
<span id="cb4-17"><a href="#cb4-17"></a> gtk_text_buffer_get_bounds <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">);</span></span>
|
||||
<span id="cb4-18"><a href="#cb4-18"></a> contents <span class="op">=</span> gtk_text_buffer_get_text <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">,</span> FALSE<span class="op">);</span></span>
|
||||
<span id="cb4-19"><a href="#cb4-19"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-20"><a href="#cb4-20"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb4-21"><a href="#cb4-21"></a> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"red"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb4-22"><a href="#cb4-22"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb4-23"><a href="#cb4-23"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"green"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb4-24"><a href="#cb4-24"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb4-25"><a href="#cb4-25"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"blue"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb4-26"><a href="#cb4-26"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb4-27"><a href="#cb4-27"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"white"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb4-28"><a href="#cb4-28"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb4-29"><a href="#cb4-29"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"black"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb4-30"><a href="#cb4-30"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb4-31"><a href="#cb4-31"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"light"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb4-32"><a href="#cb4-32"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb4-33"><a href="#cb4-33"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"dark"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb4-34"><a href="#cb4-34"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb4-35"><a href="#cb4-35"></a> <span class="cf">else</span></span>
|
||||
<span id="cb4-36"><a href="#cb4-36"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb4-37"><a href="#cb4-37"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb4-38"><a href="#cb4-38"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb4-39"><a href="#cb4-39"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-40"><a href="#cb4-40"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
|
||||
<span id="cb4-41"><a href="#cb4-41"></a><span class="op">}</span></span>
|
||||
<span id="cb4-42"><a href="#cb4-42"></a></span>
|
||||
<span id="cb4-43"><a href="#cb4-43"></a><span class="dt">void</span></span>
|
||||
<span id="cb4-44"><a href="#cb4-44"></a>run_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btnr<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-45"><a href="#cb4-45"></a> run <span class="op">();</span></span>
|
||||
<span id="cb4-46"><a href="#cb4-46"></a> gtk_widget_queue_draw <span class="op">(</span>GTK_WIDGET <span class="op">(</span>da<span class="op">));</span></span>
|
||||
<span id="cb4-47"><a href="#cb4-47"></a><span class="op">}</span></span>
|
||||
<span id="cb4-48"><a href="#cb4-48"></a></span>
|
||||
<span id="cb4-49"><a href="#cb4-49"></a><span class="dt">void</span></span>
|
||||
<span id="cb4-50"><a href="#cb4-50"></a>open_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btno<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-51"><a href="#cb4-51"></a> tfe_text_view_open <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb4-52"><a href="#cb4-52"></a><span class="op">}</span></span>
|
||||
<span id="cb4-53"><a href="#cb4-53"></a></span>
|
||||
<span id="cb4-54"><a href="#cb4-54"></a><span class="dt">void</span></span>
|
||||
<span id="cb4-55"><a href="#cb4-55"></a>save_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btns<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-56"><a href="#cb4-56"></a> tfe_text_view_save <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||||
<span id="cb4-57"><a href="#cb4-57"></a><span class="op">}</span></span>
|
||||
<span id="cb4-58"><a href="#cb4-58"></a></span>
|
||||
<span id="cb4-59"><a href="#cb4-59"></a><span class="dt">void</span></span>
|
||||
<span id="cb4-60"><a href="#cb4-60"></a>close_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btnc<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-61"><a href="#cb4-61"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb4-62"><a href="#cb4-62"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb4-63"><a href="#cb4-63"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb4-64"><a href="#cb4-64"></a><span class="op">}</span></span>
|
||||
<span id="cb4-65"><a href="#cb4-65"></a></span>
|
||||
<span id="cb4-66"><a href="#cb4-66"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-67"><a href="#cb4-67"></a>resize_cb <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-68"><a href="#cb4-68"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb4-69"><a href="#cb4-69"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb4-70"><a href="#cb4-70"></a> surface <span class="op">=</span> cairo_image_surface_create <span class="op">(</span>CAIRO_FORMAT_ARGB32<span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
|
||||
<span id="cb4-71"><a href="#cb4-71"></a> run <span class="op">();</span></span>
|
||||
<span id="cb4-72"><a href="#cb4-72"></a><span class="op">}</span></span>
|
||||
<span id="cb4-73"><a href="#cb4-73"></a></span>
|
||||
<span id="cb4-74"><a href="#cb4-74"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-75"><a href="#cb4-75"></a>draw_func <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> cairo_t <span class="op">*</span>cr<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-76"><a href="#cb4-76"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-77"><a href="#cb4-77"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb4-78"><a href="#cb4-78"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb4-79"><a href="#cb4-79"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-80"><a href="#cb4-80"></a><span class="op">}</span></span>
|
||||
<span id="cb4-81"><a href="#cb4-81"></a></span>
|
||||
<span id="cb4-82"><a href="#cb4-82"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-83"><a href="#cb4-83"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-84"><a href="#cb4-84"></a> gtk_widget_show <span class="op">(</span>win<span class="op">);</span></span>
|
||||
<span id="cb4-85"><a href="#cb4-85"></a><span class="op">}</span></span>
|
||||
<span id="cb4-86"><a href="#cb4-86"></a></span>
|
||||
<span id="cb4-87"><a href="#cb4-87"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-88"><a href="#cb4-88"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-89"><a href="#cb4-89"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
|
||||
<span id="cb4-90"><a href="#cb4-90"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||||
<span id="cb4-91"><a href="#cb4-91"></a></span>
|
||||
<span id="cb4-92"><a href="#cb4-92"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/color/color.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb4-93"><a href="#cb4-93"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"win"</span><span class="op">));</span></span>
|
||||
<span id="cb4-94"><a href="#cb4-94"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span>
|
||||
<span id="cb4-95"><a href="#cb4-95"></a> tv <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"tv"</span><span class="op">));</span></span>
|
||||
<span id="cb4-96"><a href="#cb4-96"></a> da <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"da"</span><span class="op">));</span></span>
|
||||
<span id="cb4-97"><a href="#cb4-97"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span>
|
||||
<span id="cb4-98"><a href="#cb4-98"></a> g_signal_connect <span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>da<span class="op">),</span> <span class="st">"resize"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>resize_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb4-99"><a href="#cb4-99"></a> gtk_drawing_area_set_draw_func <span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>da<span class="op">),</span> draw_func<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb4-100"><a href="#cb4-100"></a></span>
|
||||
<span id="cb4-101"><a href="#cb4-101"></a>GdkDisplay <span class="op">*</span>display<span class="op">;</span></span>
|
||||
<span id="cb4-102"><a href="#cb4-102"></a></span>
|
||||
<span id="cb4-103"><a href="#cb4-103"></a> display <span class="op">=</span> gtk_widget_get_display <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb4-104"><a href="#cb4-104"></a> GtkCssProvider <span class="op">*</span>provider <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span>
|
||||
<span id="cb4-105"><a href="#cb4-105"></a> gtk_css_provider_load_from_data <span class="op">(</span>provider<span class="op">,</span> <span class="st">"textview {padding: 10px; font-family: monospace; font-size: 12pt;}"</span><span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb4-106"><a href="#cb4-106"></a> gtk_style_context_add_provider_for_display <span class="op">(</span>display<span class="op">,</span> GTK_STYLE_PROVIDER <span class="op">(</span>provider<span class="op">),</span> GTK_STYLE_PROVIDER_PRIORITY_USER<span class="op">);</span></span>
|
||||
<span id="cb4-107"><a href="#cb4-107"></a><span class="op">}</span></span>
|
||||
<span id="cb4-108"><a href="#cb4-108"></a></span>
|
||||
<span id="cb4-109"><a href="#cb4-109"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.color"</span></span>
|
||||
<span id="cb4-110"><a href="#cb4-110"></a></span>
|
||||
<span id="cb4-111"><a href="#cb4-111"></a><span class="dt">int</span></span>
|
||||
<span id="cb4-112"><a href="#cb4-112"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-113"><a href="#cb4-113"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb4-114"><a href="#cb4-114"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb4-115"><a href="#cb4-115"></a></span>
|
||||
<span id="cb4-116"><a href="#cb4-116"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_FLAGS_NONE<span class="op">);</span></span>
|
||||
<span id="cb4-117"><a href="#cb4-117"></a></span>
|
||||
<span id="cb4-118"><a href="#cb4-118"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"startup"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb4-119"><a href="#cb4-119"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb4-120"><a href="#cb4-120"></a></span>
|
||||
<span id="cb4-121"><a href="#cb4-121"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
|
||||
<span id="cb4-122"><a href="#cb4-122"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb4-123"><a href="#cb4-123"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb4-124"><a href="#cb4-124"></a><span class="op">}</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb8"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb8-2"><a href="#cb8-2"></a><span class="pp">#include </span><span class="im">"../tfetextview/tfetextview.h"</span></span>
|
||||
<span id="cb8-3"><a href="#cb8-3"></a></span>
|
||||
<span id="cb8-4"><a href="#cb8-4"></a><span class="dt">static</span> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb8-5"><a href="#cb8-5"></a><span class="dt">static</span> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span>
|
||||
<span id="cb8-6"><a href="#cb8-6"></a><span class="dt">static</span> GtkWidget <span class="op">*</span>da<span class="op">;</span></span>
|
||||
<span id="cb8-7"><a href="#cb8-7"></a></span>
|
||||
<span id="cb8-8"><a href="#cb8-8"></a><span class="dt">static</span> cairo_surface_t <span class="op">*</span>surface <span class="op">=</span> NULL<span class="op">;</span></span>
|
||||
<span id="cb8-9"><a href="#cb8-9"></a></span>
|
||||
<span id="cb8-10"><a href="#cb8-10"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-11"><a href="#cb8-11"></a>run <span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-12"><a href="#cb8-12"></a> GtkTextBuffer <span class="op">*</span>tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||||
<span id="cb8-13"><a href="#cb8-13"></a> GtkTextIter start_iter<span class="op">;</span></span>
|
||||
<span id="cb8-14"><a href="#cb8-14"></a> GtkTextIter end_iter<span class="op">;</span></span>
|
||||
<span id="cb8-15"><a href="#cb8-15"></a> <span class="dt">char</span> <span class="op">*</span>contents<span class="op">;</span></span>
|
||||
<span id="cb8-16"><a href="#cb8-16"></a> cairo_t <span class="op">*</span>cr<span class="op">;</span></span>
|
||||
<span id="cb8-17"><a href="#cb8-17"></a></span>
|
||||
<span id="cb8-18"><a href="#cb8-18"></a> gtk_text_buffer_get_bounds <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">);</span></span>
|
||||
<span id="cb8-19"><a href="#cb8-19"></a> contents <span class="op">=</span> gtk_text_buffer_get_text <span class="op">(</span>tb<span class="op">,</span> <span class="op">&</span>start_iter<span class="op">,</span> <span class="op">&</span>end_iter<span class="op">,</span> FALSE<span class="op">);</span></span>
|
||||
<span id="cb8-20"><a href="#cb8-20"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-21"><a href="#cb8-21"></a> cr <span class="op">=</span> cairo_create <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb8-22"><a href="#cb8-22"></a> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"red"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-23"><a href="#cb8-23"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-24"><a href="#cb8-24"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"green"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-25"><a href="#cb8-25"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-26"><a href="#cb8-26"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"blue"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-27"><a href="#cb8-27"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb8-28"><a href="#cb8-28"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"white"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-29"><a href="#cb8-29"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb8-30"><a href="#cb8-30"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"black"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-31"><a href="#cb8-31"></a> cairo_set_source_rgb <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-32"><a href="#cb8-32"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"light"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-33"><a href="#cb8-33"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="dv">1</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb8-34"><a href="#cb8-34"></a> <span class="cf">else</span> <span class="cf">if</span> <span class="op">(</span>g_strcmp0 <span class="op">(</span><span class="st">"dark"</span><span class="op">,</span> contents<span class="op">)</span> <span class="op">==</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb8-35"><a href="#cb8-35"></a> cairo_set_source_rgba <span class="op">(</span>cr<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="fl">0.5</span><span class="op">);</span></span>
|
||||
<span id="cb8-36"><a href="#cb8-36"></a> <span class="cf">else</span></span>
|
||||
<span id="cb8-37"><a href="#cb8-37"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-38"><a href="#cb8-38"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb8-39"><a href="#cb8-39"></a> cairo_destroy <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb8-40"><a href="#cb8-40"></a> <span class="op">}</span></span>
|
||||
<span id="cb8-41"><a href="#cb8-41"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
|
||||
<span id="cb8-42"><a href="#cb8-42"></a><span class="op">}</span></span>
|
||||
<span id="cb8-43"><a href="#cb8-43"></a></span>
|
||||
<span id="cb8-44"><a href="#cb8-44"></a><span class="dt">void</span></span>
|
||||
<span id="cb8-45"><a href="#cb8-45"></a>run_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btnr<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-46"><a href="#cb8-46"></a> run <span class="op">();</span></span>
|
||||
<span id="cb8-47"><a href="#cb8-47"></a> gtk_widget_queue_draw <span class="op">(</span>GTK_WIDGET <span class="op">(</span>da<span class="op">));</span></span>
|
||||
<span id="cb8-48"><a href="#cb8-48"></a><span class="op">}</span></span>
|
||||
<span id="cb8-49"><a href="#cb8-49"></a></span>
|
||||
<span id="cb8-50"><a href="#cb8-50"></a><span class="dt">void</span></span>
|
||||
<span id="cb8-51"><a href="#cb8-51"></a>open_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btno<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-52"><a href="#cb8-52"></a> tfe_text_view_open <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb8-53"><a href="#cb8-53"></a><span class="op">}</span></span>
|
||||
<span id="cb8-54"><a href="#cb8-54"></a></span>
|
||||
<span id="cb8-55"><a href="#cb8-55"></a><span class="dt">void</span></span>
|
||||
<span id="cb8-56"><a href="#cb8-56"></a>save_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btns<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-57"><a href="#cb8-57"></a> tfe_text_view_save <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||||
<span id="cb8-58"><a href="#cb8-58"></a><span class="op">}</span></span>
|
||||
<span id="cb8-59"><a href="#cb8-59"></a></span>
|
||||
<span id="cb8-60"><a href="#cb8-60"></a><span class="dt">void</span></span>
|
||||
<span id="cb8-61"><a href="#cb8-61"></a>close_cb <span class="op">(</span>GtkWidget <span class="op">*</span>btnc<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-62"><a href="#cb8-62"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb8-63"><a href="#cb8-63"></a><span class="op">}</span></span>
|
||||
<span id="cb8-64"><a href="#cb8-64"></a></span>
|
||||
<span id="cb8-65"><a href="#cb8-65"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-66"><a href="#cb8-66"></a>resize_cb <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-67"><a href="#cb8-67"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb8-68"><a href="#cb8-68"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb8-69"><a href="#cb8-69"></a> surface <span class="op">=</span> cairo_image_surface_create <span class="op">(</span>CAIRO_FORMAT_ARGB32<span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
|
||||
<span id="cb8-70"><a href="#cb8-70"></a> run <span class="op">();</span></span>
|
||||
<span id="cb8-71"><a href="#cb8-71"></a><span class="op">}</span></span>
|
||||
<span id="cb8-72"><a href="#cb8-72"></a></span>
|
||||
<span id="cb8-73"><a href="#cb8-73"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-74"><a href="#cb8-74"></a>draw_func <span class="op">(</span>GtkDrawingArea <span class="op">*</span>drawing_area<span class="op">,</span> cairo_t <span class="op">*</span>cr<span class="op">,</span> <span class="dt">int</span> width<span class="op">,</span> <span class="dt">int</span> height<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-75"><a href="#cb8-75"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-76"><a href="#cb8-76"></a> cairo_set_source_surface <span class="op">(</span>cr<span class="op">,</span> surface<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb8-77"><a href="#cb8-77"></a> cairo_paint <span class="op">(</span>cr<span class="op">);</span></span>
|
||||
<span id="cb8-78"><a href="#cb8-78"></a> <span class="op">}</span></span>
|
||||
<span id="cb8-79"><a href="#cb8-79"></a><span class="op">}</span></span>
|
||||
<span id="cb8-80"><a href="#cb8-80"></a></span>
|
||||
<span id="cb8-81"><a href="#cb8-81"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-82"><a href="#cb8-82"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-83"><a href="#cb8-83"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||||
<span id="cb8-84"><a href="#cb8-84"></a><span class="op">}</span></span>
|
||||
<span id="cb8-85"><a href="#cb8-85"></a></span>
|
||||
<span id="cb8-86"><a href="#cb8-86"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-87"><a href="#cb8-87"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-88"><a href="#cb8-88"></a> GtkApplication <span class="op">*</span>app <span class="op">=</span> GTK_APPLICATION <span class="op">(</span>application<span class="op">);</span></span>
|
||||
<span id="cb8-89"><a href="#cb8-89"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||||
<span id="cb8-90"><a href="#cb8-90"></a> GdkDisplay <span class="op">*</span>display<span class="op">;</span></span>
|
||||
<span id="cb8-91"><a href="#cb8-91"></a></span>
|
||||
<span id="cb8-92"><a href="#cb8-92"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/color/color.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb8-93"><a href="#cb8-93"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"win"</span><span class="op">));</span></span>
|
||||
<span id="cb8-94"><a href="#cb8-94"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> app<span class="op">);</span></span>
|
||||
<span id="cb8-95"><a href="#cb8-95"></a> tv <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"tv"</span><span class="op">));</span></span>
|
||||
<span id="cb8-96"><a href="#cb8-96"></a> da <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"da"</span><span class="op">));</span></span>
|
||||
<span id="cb8-97"><a href="#cb8-97"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span>
|
||||
<span id="cb8-98"><a href="#cb8-98"></a> g_signal_connect <span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>da<span class="op">),</span> <span class="st">"resize"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>resize_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-99"><a href="#cb8-99"></a> gtk_drawing_area_set_draw_func <span class="op">(</span>GTK_DRAWING_AREA <span class="op">(</span>da<span class="op">),</span> draw_func<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-100"><a href="#cb8-100"></a></span>
|
||||
<span id="cb8-101"><a href="#cb8-101"></a> display <span class="op">=</span> gdk_display_get_default <span class="op">();</span></span>
|
||||
<span id="cb8-102"><a href="#cb8-102"></a> GtkCssProvider <span class="op">*</span>provider <span class="op">=</span> gtk_css_provider_new <span class="op">();</span></span>
|
||||
<span id="cb8-103"><a href="#cb8-103"></a> gtk_css_provider_load_from_data <span class="op">(</span>provider<span class="op">,</span> <span class="st">"textview {padding: 10px; font-family: monospace; font-size: 12pt;}"</span><span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb8-104"><a href="#cb8-104"></a> gtk_style_context_add_provider_for_display <span class="op">(</span>display<span class="op">,</span> GTK_STYLE_PROVIDER <span class="op">(</span>provider<span class="op">),</span> GTK_STYLE_PROVIDER_PRIORITY_USER<span class="op">);</span></span>
|
||||
<span id="cb8-105"><a href="#cb8-105"></a><span class="op">}</span></span>
|
||||
<span id="cb8-106"><a href="#cb8-106"></a></span>
|
||||
<span id="cb8-107"><a href="#cb8-107"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-108"><a href="#cb8-108"></a>app_shutdown <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-109"><a href="#cb8-109"></a> <span class="cf">if</span> <span class="op">(</span>surface<span class="op">)</span></span>
|
||||
<span id="cb8-110"><a href="#cb8-110"></a> cairo_surface_destroy <span class="op">(</span>surface<span class="op">);</span></span>
|
||||
<span id="cb8-111"><a href="#cb8-111"></a><span class="op">}</span></span>
|
||||
<span id="cb8-112"><a href="#cb8-112"></a></span>
|
||||
<span id="cb8-113"><a href="#cb8-113"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.color"</span></span>
|
||||
<span id="cb8-114"><a href="#cb8-114"></a></span>
|
||||
<span id="cb8-115"><a href="#cb8-115"></a><span class="dt">int</span></span>
|
||||
<span id="cb8-116"><a href="#cb8-116"></a>main <span class="op">(</span><span class="dt">int</span> argc<span class="op">,</span> <span class="dt">char</span> <span class="op">**</span>argv<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-117"><a href="#cb8-117"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb8-118"><a href="#cb8-118"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb8-119"><a href="#cb8-119"></a></span>
|
||||
<span id="cb8-120"><a href="#cb8-120"></a> app <span class="op">=</span> gtk_application_new <span class="op">(</span>APPLICATION_ID<span class="op">,</span> G_APPLICATION_DEFAULT_FLAGS<span class="op">);</span></span>
|
||||
<span id="cb8-121"><a href="#cb8-121"></a></span>
|
||||
<span id="cb8-122"><a href="#cb8-122"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"startup"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_startup<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-123"><a href="#cb8-123"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"shutdown"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_shutdown<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-124"><a href="#cb8-124"></a> g_signal_connect <span class="op">(</span>app<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>app_activate<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-125"><a href="#cb8-125"></a></span>
|
||||
<span id="cb8-126"><a href="#cb8-126"></a> stat <span class="op">=</span>g_application_run <span class="op">(</span>G_APPLICATION <span class="op">(</span>app<span class="op">),</span> argc<span class="op">,</span> argv<span class="op">);</span></span>
|
||||
<span id="cb8-127"><a href="#cb8-127"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb8-128"><a href="#cb8-128"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb8-129"><a href="#cb8-129"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>109-124: The function <code>main</code> is almost same as before but
|
||||
there are some differences. The application ID is
|
||||
“com.github.ToshioCP.color”. <code>G_APPLICATION_FLAGS_NONE</code> is
|
||||
specified so no open signal handler is necessary.</li>
|
||||
<li>87-107: Startup handler.</li>
|
||||
<li>92-97: Builds widgets. The pointers of the top window, TfeTextView
|
||||
and GtkDrawingArea objects are stored to static variables
|
||||
<code>win</code>, <code>tv</code> and <code>da</code> respectively. This
|
||||
is because these objects are often used in handlers. They never be
|
||||
rewritten so they’re thread safe.</li>
|
||||
<li>98: connects “resize” signal and the handler.</li>
|
||||
<li>99: sets the drawing function.</li>
|
||||
<li>82-85: Activate handler, which just shows the widgets.</li>
|
||||
<li>74-80: The drawing function. It just copies <code>surface</code> to
|
||||
destination.</li>
|
||||
<li>66-72: Resize handler. Re-creates the surface to fit its width and
|
||||
height for the drawing area and paints by calling the function
|
||||
<code>run</code>.</li>
|
||||
<li>59-64: Close handler. It destroys <code>surface</code> if it exists.
|
||||
Then it destroys the top-level window and quits the application.</li>
|
||||
<li>49-57: Open and save handler. They just call the corresponding
|
||||
functions of TfeTextView.</li>
|
||||
<li>43-47: Run handler. It calls run function to paint the surface.
|
||||
After that <code>gtk_widget_queue_draw</code> is called. This function
|
||||
adds the widget (GtkDrawingArea) to the queue to be redrawn. It is
|
||||
important to know that the window is redrawn whenever it is necessary.
|
||||
For example, when another window is moved and uncovers part of the
|
||||
widget, or when the window containing it is resized. But repainting
|
||||
<code>surface</code> is not automatically notified to gtk. Therefore,
|
||||
you need to call <code>gtk_widget_queue_draw</code> to redraw the
|
||||
widget.</li>
|
||||
<li>9-41: Run function paints the surface. First, it gets the contents
|
||||
of GtkTextBuffer. Then it compares it to “red”, “green” and so on. If it
|
||||
matches the color, then the surface is painted the color. If it matches
|
||||
“light” or “dark”, then the color of the surface is lightened or
|
||||
darkened respectively. Alpha channel is used.</li>
|
||||
<li>4-8: Win, tv, da and surface are defined as static variables.</li>
|
||||
<li>10-42: Run function.</li>
|
||||
<li>44-63: Handlers for button signals.</li>
|
||||
<li>65-71: Resize handler.</li>
|
||||
<li>73-79: Drawing function.</li>
|
||||
<li>81-84: Application activate handler. It just shows the main
|
||||
window.</li>
|
||||
<li>86-105: Application startup handler.</li>
|
||||
<li>92- 97: It builds widgets according to the ui resource. The static
|
||||
variables win, tv and da are assigned instances.</li>
|
||||
<li>98: Connects “resize” signal and a handler.</li>
|
||||
<li>99: Drawing function is set.</li>
|
||||
<li>101-104: CSS for textview padding is set.</li>
|
||||
<li>107-111: Application shutdown handler. If there exists a surface
|
||||
instance, it will be destroyed.</li>
|
||||
<li>116-129: A function <code>main</code>. It creates a new application
|
||||
instance. And connects three signals startup, shutdown and activate to
|
||||
their handlers. It runs the application. It releases the reference to
|
||||
the application and returns with <code>stat</code> value.</li>
|
||||
</ul>
|
||||
<h2 id="meson.build">Meson.build</h2>
|
||||
<p>This file is almost same as before. An argument “export_dynamic:
|
||||
true” is added to executable function.</p>
|
||||
<div class="sourceCode" id="cb5"><pre
|
||||
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb5-1"><a href="#cb5-1"></a>project('color', 'c')</span>
|
||||
<span id="cb5-2"><a href="#cb5-2"></a></span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a>gtkdep = dependency('gtk4')</span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a></span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a>gnome=import('gnome')</span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a>resources = gnome.compile_resources('resources','color.gresource.xml')</span>
|
||||
<span id="cb5-7"><a href="#cb5-7"></a></span>
|
||||
<span id="cb5-8"><a href="#cb5-8"></a>sourcefiles=files('colorapplication.c', '../tfetextview/tfetextview.c')</span>
|
||||
<span id="cb5-9"><a href="#cb5-9"></a></span>
|
||||
<span id="cb5-10"><a href="#cb5-10"></a>executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)</span></code></pre></div>
|
||||
<h2 id="compile-and-execute-it">Compile and execute it</h2>
|
||||
<p>First you need to export some variables (refer to <a
|
||||
href="sec2.html">Section 2</a>) if you’ve installed GTK 4 from the
|
||||
source. If you’ve installed GTK 4 from the distribution packages, you
|
||||
don’t need to do this.</p>
|
||||
<pre><code>$ . env.sh</code></pre>
|
||||
<p>Then type the following to compile it.</p>
|
||||
<div class="sourceCode" id="cb9"><pre
|
||||
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb9-1"><a href="#cb9-1"></a>project('color', 'c')</span>
|
||||
<span id="cb9-2"><a href="#cb9-2"></a></span>
|
||||
<span id="cb9-3"><a href="#cb9-3"></a>gtkdep = dependency('gtk4')</span>
|
||||
<span id="cb9-4"><a href="#cb9-4"></a></span>
|
||||
<span id="cb9-5"><a href="#cb9-5"></a>gnome=import('gnome')</span>
|
||||
<span id="cb9-6"><a href="#cb9-6"></a>resources = gnome.compile_resources('resources','color.gresource.xml')</span>
|
||||
<span id="cb9-7"><a href="#cb9-7"></a></span>
|
||||
<span id="cb9-8"><a href="#cb9-8"></a>sourcefiles=files('colorapplication.c', '../tfetextview/tfetextview.c')</span>
|
||||
<span id="cb9-9"><a href="#cb9-9"></a></span>
|
||||
<span id="cb9-10"><a href="#cb9-10"></a>executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)</span></code></pre></div>
|
||||
<h2 id="build-and-try">Build and try</h2>
|
||||
<p>Type the following to compile the program.</p>
|
||||
<pre><code>$ meson _build
|
||||
$ ninja -C _build</code></pre>
|
||||
<p>The application is made in <code>_build</code> directory. Type the
|
||||
following to execute it.</p>
|
||||
<pre><code>$ _build/color</code></pre>
|
||||
<p>Type “red”, “green”, “blue”, “white”, black”, “light” or “dark” in
|
||||
the TfeTextView. Then, click on <code>Run</code> button. Make sure the
|
||||
color of GtkDrawingArea changes.</p>
|
||||
the TfeTextView. No new line charactor is needed. Then, click on the
|
||||
<code>Run</code> button. Make sure the color of GtkDrawingArea
|
||||
changes.</p>
|
||||
<p>In this program TfeTextView is used to change the color. You can use
|
||||
buttons or menus instead of textview. Probably it is more appropriate.
|
||||
Using textview is unnatural. It is a good practice to make such
|
||||
|
|
2196
docs/sec25.html
32
gfm/sec22.md
|
@ -9,17 +9,17 @@ This is called custom drawing.
|
|||
GtkDrawingArea provides a cairo drawing context so users can draw images by using cairo functions.
|
||||
In this section, I will explain:
|
||||
|
||||
1. Cairo, but only briefly; and
|
||||
1. Cairo, but only briefly
|
||||
2. GtkDrawingArea, with a very simple example.
|
||||
|
||||
## Cairo
|
||||
|
||||
Cairo is a set of two dimensional graphical drawing functions (or graphics library).
|
||||
There is a lot of documentation on [Cairo's website](https://www.cairographics.org/).
|
||||
If you aren't familiar with Cairo, it is worth reading their [tutorial](https://www.cairographics.org/tutorial/).
|
||||
There are a lot of documents on [Cairo's website](https://www.cairographics.org/).
|
||||
If you aren't familiar with Cairo, it is worth reading the [tutorial](https://www.cairographics.org/tutorial/).
|
||||
|
||||
The following is a gentle introduction to the Cairo library and how to use it.
|
||||
Firstly, in order to use Cairo you need to know about surfaces, sources, masks, destinations, cairo context and transformations.
|
||||
The following is an introduction to the Cairo library and how to use it.
|
||||
First, you need to know about surfaces, sources, masks, destinations, cairo context and transformations.
|
||||
|
||||
- A surface represents an image.
|
||||
It is like a canvas.
|
||||
|
@ -50,6 +50,7 @@ This will be the destination.
|
|||
6. Save the destination surface to a file if necessary.
|
||||
|
||||
Here's a simple example program that draws a small square and saves it as a png file.
|
||||
The path of the file is `src/misc/cairo.c`.
|
||||
|
||||
~~~C
|
||||
1 #include <cairo.h>
|
||||
|
@ -103,7 +104,7 @@ Width and height are in pixels and given as integers.
|
|||
- 14: Creates cairo context.
|
||||
The surface given as an argument will be the destination of the context.
|
||||
- 18: `cairo_set_source_rgb` creates a source pattern, which in this case is a solid white paint.
|
||||
The second to fourth argument are red, green and blue color values respectively, and they are
|
||||
The second to fourth arguments are red, green and blue color values respectively, and they are
|
||||
of type float. The values are between zero (0.0) and one (1.0), with
|
||||
black being given by (0.0,0.0,0.0) and white by (1.0,1.0,1.0).
|
||||
- 19: `cairo_paint` copies everywhere in the source to destination.
|
||||
|
@ -120,13 +121,13 @@ The square is located at the center.
|
|||
- 28: Destroys the context. At the same time the source is destroyed.
|
||||
- 29: Destroys the surface.
|
||||
|
||||
To compile this, type the following.
|
||||
To compile this, change your current directory to `src/misc` and type the following.
|
||||
|
||||
$ gcc `pkg-config --cflags cairo` cairo.c `pkg-config --libs cairo`
|
||||
|
||||
![rectangle.png](../image/rectangle.png)
|
||||
|
||||
See the [Cairo's website](https://www.cairographics.org/) for more details.
|
||||
See the [Cairo's website](https://www.cairographics.org/) for further information.
|
||||
|
||||
## GtkDrawingArea
|
||||
|
||||
|
@ -181,12 +182,12 @@ The following is a very simple example.
|
|||
The function `main` is almost same as before.
|
||||
The two functions `app_activate` and `draw_function` are important in this example.
|
||||
|
||||
- 18: Creates a GtkDrawingArea instance; and
|
||||
- 21: Sets a drawing function of the widget.
|
||||
- 22: Creates a GtkDrawingArea instance.
|
||||
- 25: Sets a drawing function of the widget.
|
||||
GtkDrawingArea widget uses the function to draw the contents of itself whenever its necessary.
|
||||
For example, when a user drag a mouse pointer and resize a top-level window, GtkDrawingArea also changes the size.
|
||||
Then, the whole window needs to be redrawn.
|
||||
For the information of `gtk_drawing_area_set_draw_func`, see [Gtk API Reference, gtk\_drawing\_area\_set\_draw\_func](https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html).
|
||||
For the information of `gtk_drawing_area_set_draw_func`, see [Gtk API Reference -- gtk\_drawing\_area\_set\_draw\_func](https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html).
|
||||
|
||||
The drawing function has five parameters.
|
||||
|
||||
|
@ -201,15 +202,16 @@ The second parameter is a cairo context given by the widget.
|
|||
The destination surface of the context is connected to the contents of the widget.
|
||||
What you draw to this surface will appear in the widget on the screen.
|
||||
The third and fourth parameters are the size of the destination surface.
|
||||
Now, look at the program example again.
|
||||
Now, look at the program again.
|
||||
|
||||
- 3-13: The drawing function.
|
||||
- 3-17: The drawing function.
|
||||
- 7-8: Sets the source to be white and paint the destination white.
|
||||
- 9: Sets the line width to be 2.
|
||||
- 10: Sets the source to be black.
|
||||
- 11: Adds a rectangle to the mask.
|
||||
- 12: Draws the rectangle with black color to the destination.
|
||||
- 11-15: Adds a rectangle to the mask.
|
||||
- 16: Draws the rectangle with black color to the destination.
|
||||
|
||||
The program is [src/misc/da1.c](../src/misc/da1.c).
|
||||
Compile and run it, then a window with a black rectangle (square) appears.
|
||||
Try resizing the window.
|
||||
The square always appears at the center of the window because the drawing function is invoked each time the window is resized.
|
||||
|
|
421
gfm/sec24.md
|
@ -9,6 +9,7 @@ If you write a name of a color in TfeTextView and click on the `run` button, the
|
|||
![color](../image/color.png)
|
||||
|
||||
The following colors are available.
|
||||
(without new line charactor)
|
||||
|
||||
- white
|
||||
- black
|
||||
|
@ -30,8 +31,7 @@ In this section, we focus on how to bind the two objects.
|
|||
## Color.ui and color.gresource.xml
|
||||
|
||||
First, We need to make the ui file of the widgets.
|
||||
The image in the previous subsection gives us the structure of the widgets.
|
||||
Title bar, four buttons in the tool bar and two widgets textview and drawing area.
|
||||
Title bar, four buttons in the tool bar, textview and drawing area.
|
||||
The ui file is as follows.
|
||||
|
||||
~~~xml
|
||||
|
@ -117,16 +117,16 @@ The ui file is as follows.
|
|||
80 </interface>
|
||||
~~~
|
||||
|
||||
- 10-53: This part is the tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
|
||||
This is similar to the toolbar of tfe text editor in [Section 9](sec9.md).
|
||||
- 10-53: The horizontal box `boxh1` makes a tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
|
||||
This is similar to the `tfe` text editor in [Section 9](sec9.md).
|
||||
There are two differences.
|
||||
`Run` button replaces `New` button.
|
||||
A signal element is added to each button object.
|
||||
It has "name" attribute which is a signal name and "handler" attribute which is the name of its signal handler function.
|
||||
It has "name" attribute which is a signal name and "handler" attribute which is the name of its signal handler.
|
||||
Options "-WI, --export-dynamic" CFLAG is necessary when you compile the application.
|
||||
You can achieve this by adding "export_dynamic: true" argument to executable function in `meson.build`.
|
||||
You can achieve this by adding "export_dynamic: true" argument to the executable function in `meson.build`.
|
||||
And be careful that the handler must be defined without 'static' class.
|
||||
- 54-76: Puts GtkScrolledWindow and GtkDrawingArea into GtkBox.
|
||||
- 54-76: The horizontal box `boxh2` includes GtkScrolledWindow and GtkDrawingArea.
|
||||
GtkBox has "homogeneous property" with TRUE value, so the two children have the same width in the box.
|
||||
TfeTextView is a child of GtkScrolledWindow.
|
||||
|
||||
|
@ -142,121 +142,209 @@ Just substitute "color" for "tfe".
|
|||
6 </gresources>
|
||||
~~~
|
||||
|
||||
## Tfetextview.h, tfetextview.c and color.h
|
||||
## Drawing function and surface
|
||||
|
||||
First two files are the same as before.
|
||||
Color.h just includes tfetextview.h.
|
||||
The main point of this program is a drawing function.
|
||||
|
||||
~~~C
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 #include "../tfetextview/tfetextview.h"
|
||||
1 static void
|
||||
2 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
3 if (surface) {
|
||||
4 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
5 cairo_paint (cr);
|
||||
6 }
|
||||
7 }
|
||||
~~~
|
||||
|
||||
The `surface` variable in line 3 is a static variable.
|
||||
|
||||
~~~C
|
||||
static cairo_surface_t *surface = NULL;
|
||||
~~~
|
||||
|
||||
The drawing function just copies the `surface` to its own surface with the `cairo_paint` function.
|
||||
The surface (pointed by the static variable `surface`) is built by the `run` function.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 run (void) {
|
||||
3 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
4 GtkTextIter start_iter;
|
||||
5 GtkTextIter end_iter;
|
||||
6 char *contents;
|
||||
7 cairo_t *cr;
|
||||
8
|
||||
9 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
10 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
11 if (surface) {
|
||||
12 cr = cairo_create (surface);
|
||||
13 if (g_strcmp0 ("red", contents) == 0)
|
||||
14 cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
15 else if (g_strcmp0 ("green", contents) == 0)
|
||||
16 cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
17 else if (g_strcmp0 ("blue", contents) == 0)
|
||||
18 cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
19 else if (g_strcmp0 ("white", contents) == 0)
|
||||
20 cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
21 else if (g_strcmp0 ("black", contents) == 0)
|
||||
22 cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
23 else if (g_strcmp0 ("light", contents) == 0)
|
||||
24 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
|
||||
25 else if (g_strcmp0 ("dark", contents) == 0)
|
||||
26 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
27 else
|
||||
28 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
29 cairo_paint (cr);
|
||||
30 cairo_destroy (cr);
|
||||
31 }
|
||||
32 g_free (contents);
|
||||
33 }
|
||||
~~~
|
||||
|
||||
- 9-10: Gets the string in the GtkTextBuffer and inserts it to `contents`.
|
||||
- 11: If the variable `surface` points a surface instance, it is painted as follows.
|
||||
- 12- 30: The source is set based on the string `contents` and copied to the surface with `cairo_paint`.
|
||||
- 24,26: Alpha channel is used in "light" and "dark" procedure.
|
||||
|
||||
The drawing area just reflects the `surface`.
|
||||
But one problem is resizing.
|
||||
If a user resizes the main window, the drawing area is also resized.
|
||||
It makes size difference between the surface and the drawing area.
|
||||
So, the surface needs to be resized to fit the drawing area.
|
||||
|
||||
It is accomplished by connecting the "resize" signal on the drawing area to a handler.
|
||||
|
||||
~~~C
|
||||
g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
~~~
|
||||
|
||||
The handler is as follows.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
3 if (surface)
|
||||
4 cairo_surface_destroy (surface);
|
||||
5 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
6 run ();
|
||||
7 }
|
||||
~~~
|
||||
|
||||
If the variable `surface` sets a surface instance, it is destroyed.
|
||||
A new surface is created and its size fits the drawing area.
|
||||
The surface is assigned to the variable `surface`.
|
||||
The function `run` is called and the surface is colored.
|
||||
|
||||
The signal is emitted when:
|
||||
|
||||
- The drawing area is realized (it appears on the display).
|
||||
- It is changed (resized) while realized
|
||||
|
||||
So, the first surface is created when it is realized.
|
||||
|
||||
## Colorapplication.c
|
||||
|
||||
This is the main file.
|
||||
It deals with:
|
||||
|
||||
- Building widgets by GtkBuilder.
|
||||
- Setting a drawing function of GtkDrawingArea.
|
||||
And connecting a handler to "resize" signal on GtkDrawingArea.
|
||||
- Implementing each call back functions.
|
||||
- Builds widgets by GtkBuilder.
|
||||
- Sets a drawing function for GtkDrawingArea.
|
||||
And connects a handler to the "resize" signal on the GtkDrawingArea instance.
|
||||
- Implements each call back function.
|
||||
Particularly, `Run` signal handler is the point in this program.
|
||||
|
||||
The following is `colorapplication.c`.
|
||||
|
||||
~~~C
|
||||
1 #include "color.h"
|
||||
2
|
||||
3 static GtkWidget *win;
|
||||
4 static GtkWidget *tv;
|
||||
5 static GtkWidget *da;
|
||||
6
|
||||
7 static cairo_surface_t *surface = NULL;
|
||||
8
|
||||
9 static void
|
||||
10 run (void) {
|
||||
11 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
12 GtkTextIter start_iter;
|
||||
13 GtkTextIter end_iter;
|
||||
14 char *contents;
|
||||
15 cairo_t *cr;
|
||||
16
|
||||
17 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
18 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
19 if (surface) {
|
||||
20 cr = cairo_create (surface);
|
||||
21 if (g_strcmp0 ("red", contents) == 0)
|
||||
22 cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
23 else if (g_strcmp0 ("green", contents) == 0)
|
||||
24 cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
25 else if (g_strcmp0 ("blue", contents) == 0)
|
||||
26 cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
27 else if (g_strcmp0 ("white", contents) == 0)
|
||||
28 cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
29 else if (g_strcmp0 ("black", contents) == 0)
|
||||
30 cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
31 else if (g_strcmp0 ("light", contents) == 0)
|
||||
32 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
|
||||
33 else if (g_strcmp0 ("dark", contents) == 0)
|
||||
34 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
35 else
|
||||
36 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
37 cairo_paint (cr);
|
||||
38 cairo_destroy (cr);
|
||||
39 }
|
||||
40 g_free (contents);
|
||||
41 }
|
||||
42
|
||||
43 void
|
||||
44 run_cb (GtkWidget *btnr) {
|
||||
45 run ();
|
||||
46 gtk_widget_queue_draw (GTK_WIDGET (da));
|
||||
47 }
|
||||
48
|
||||
49 void
|
||||
50 open_cb (GtkWidget *btno) {
|
||||
51 tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (win));
|
||||
52 }
|
||||
53
|
||||
54 void
|
||||
55 save_cb (GtkWidget *btns) {
|
||||
56 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
57 }
|
||||
58
|
||||
59 void
|
||||
60 close_cb (GtkWidget *btnc) {
|
||||
61 if (surface)
|
||||
62 cairo_surface_destroy (surface);
|
||||
63 gtk_window_destroy (GTK_WINDOW (win));
|
||||
64 }
|
||||
65
|
||||
66 static void
|
||||
67 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
68 if (surface)
|
||||
69 cairo_surface_destroy (surface);
|
||||
70 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
71 run ();
|
||||
72 }
|
||||
73
|
||||
74 static void
|
||||
75 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
76 if (surface) {
|
||||
77 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
78 cairo_paint (cr);
|
||||
1 #include <gtk/gtk.h>
|
||||
2 #include "../tfetextview/tfetextview.h"
|
||||
3
|
||||
4 static GtkWidget *win;
|
||||
5 static GtkWidget *tv;
|
||||
6 static GtkWidget *da;
|
||||
7
|
||||
8 static cairo_surface_t *surface = NULL;
|
||||
9
|
||||
10 static void
|
||||
11 run (void) {
|
||||
12 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
13 GtkTextIter start_iter;
|
||||
14 GtkTextIter end_iter;
|
||||
15 char *contents;
|
||||
16 cairo_t *cr;
|
||||
17
|
||||
18 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
19 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
20 if (surface) {
|
||||
21 cr = cairo_create (surface);
|
||||
22 if (g_strcmp0 ("red", contents) == 0)
|
||||
23 cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
24 else if (g_strcmp0 ("green", contents) == 0)
|
||||
25 cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
26 else if (g_strcmp0 ("blue", contents) == 0)
|
||||
27 cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
28 else if (g_strcmp0 ("white", contents) == 0)
|
||||
29 cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
30 else if (g_strcmp0 ("black", contents) == 0)
|
||||
31 cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
32 else if (g_strcmp0 ("light", contents) == 0)
|
||||
33 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
|
||||
34 else if (g_strcmp0 ("dark", contents) == 0)
|
||||
35 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
36 else
|
||||
37 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
38 cairo_paint (cr);
|
||||
39 cairo_destroy (cr);
|
||||
40 }
|
||||
41 g_free (contents);
|
||||
42 }
|
||||
43
|
||||
44 void
|
||||
45 run_cb (GtkWidget *btnr) {
|
||||
46 run ();
|
||||
47 gtk_widget_queue_draw (GTK_WIDGET (da));
|
||||
48 }
|
||||
49
|
||||
50 void
|
||||
51 open_cb (GtkWidget *btno) {
|
||||
52 tfe_text_view_open (TFE_TEXT_VIEW (tv), GTK_WINDOW (win));
|
||||
53 }
|
||||
54
|
||||
55 void
|
||||
56 save_cb (GtkWidget *btns) {
|
||||
57 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
58 }
|
||||
59
|
||||
60 void
|
||||
61 close_cb (GtkWidget *btnc) {
|
||||
62 gtk_window_destroy (GTK_WINDOW (win));
|
||||
63 }
|
||||
64
|
||||
65 static void
|
||||
66 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
67 if (surface)
|
||||
68 cairo_surface_destroy (surface);
|
||||
69 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
70 run ();
|
||||
71 }
|
||||
72
|
||||
73 static void
|
||||
74 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
75 if (surface) {
|
||||
76 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
77 cairo_paint (cr);
|
||||
78 }
|
||||
79 }
|
||||
80 }
|
||||
81
|
||||
82 static void
|
||||
83 app_activate (GApplication *application) {
|
||||
84 gtk_widget_show (win);
|
||||
85 }
|
||||
86
|
||||
87 static void
|
||||
88 app_startup (GApplication *application) {
|
||||
89 GtkApplication *app = GTK_APPLICATION (application);
|
||||
90 GtkBuilder *build;
|
||||
80
|
||||
81 static void
|
||||
82 app_activate (GApplication *application) {
|
||||
83 gtk_window_present (GTK_WINDOW (win));
|
||||
84 }
|
||||
85
|
||||
86 static void
|
||||
87 app_startup (GApplication *application) {
|
||||
88 GtkApplication *app = GTK_APPLICATION (application);
|
||||
89 GtkBuilder *build;
|
||||
90 GdkDisplay *display;
|
||||
91
|
||||
92 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/color/color.ui");
|
||||
93 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
|
@ -267,67 +355,58 @@ The following is `colorapplication.c`.
|
|||
98 g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
99 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
|
||||
100
|
||||
101 GdkDisplay *display;
|
||||
102
|
||||
103 display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
104 GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
105 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
106 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
107 }
|
||||
108
|
||||
109 #define APPLICATION_ID "com.github.ToshioCP.color"
|
||||
110
|
||||
111 int
|
||||
112 main (int argc, char **argv) {
|
||||
113 GtkApplication *app;
|
||||
114 int stat;
|
||||
115
|
||||
116 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
117
|
||||
118 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
119 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
120
|
||||
121 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
122 g_object_unref (app);
|
||||
123 return stat;
|
||||
124 }
|
||||
101 display = gdk_display_get_default ();
|
||||
102 GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
103 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
104 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
105 }
|
||||
106
|
||||
107 static void
|
||||
108 app_shutdown (GApplication *application) {
|
||||
109 if (surface)
|
||||
110 cairo_surface_destroy (surface);
|
||||
111 }
|
||||
112
|
||||
113 #define APPLICATION_ID "com.github.ToshioCP.color"
|
||||
114
|
||||
115 int
|
||||
116 main (int argc, char **argv) {
|
||||
117 GtkApplication *app;
|
||||
118 int stat;
|
||||
119
|
||||
120 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
121
|
||||
122 g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
123 g_signal_connect (app, "shutdown", G_CALLBACK (app_shutdown), NULL);
|
||||
124 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
125
|
||||
126 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
127 g_object_unref (app);
|
||||
128 return stat;
|
||||
129 }
|
||||
130
|
||||
~~~
|
||||
|
||||
- 109-124: The function `main` is almost same as before but there are some differences.
|
||||
The application ID is "com.github.ToshioCP.color".
|
||||
`G_APPLICATION_FLAGS_NONE` is specified so no open signal handler is necessary.
|
||||
- 87-107: Startup handler.
|
||||
- 92-97: Builds widgets.
|
||||
The pointers of the top window, TfeTextView and GtkDrawingArea objects are stored to static variables `win`, `tv` and `da` respectively.
|
||||
This is because these objects are often used in handlers.
|
||||
They never be rewritten so they're thread safe.
|
||||
- 98: connects "resize" signal and the handler.
|
||||
- 99: sets the drawing function.
|
||||
- 82-85: Activate handler, which just shows the widgets.
|
||||
- 74-80: The drawing function.
|
||||
It just copies `surface` to destination.
|
||||
- 66-72: Resize handler.
|
||||
Re-creates the surface to fit its width and height for the drawing area and paints by calling the function `run`.
|
||||
- 59-64: Close handler.
|
||||
It destroys `surface` if it exists.
|
||||
Then it destroys the top-level window and quits the application.
|
||||
- 49-57: Open and save handler.
|
||||
They just call the corresponding functions of TfeTextView.
|
||||
- 43-47: Run handler.
|
||||
It calls run function to paint the surface.
|
||||
After that `gtk_widget_queue_draw` is called.
|
||||
This function adds the widget (GtkDrawingArea) to the queue to be redrawn.
|
||||
It is important to know that the window is redrawn whenever it is necessary.
|
||||
For example, when another window is moved and uncovers part of the widget, or when the window containing it is resized.
|
||||
But repainting `surface` is not automatically notified to gtk.
|
||||
Therefore, you need to call `gtk_widget_queue_draw` to redraw the widget.
|
||||
- 9-41: Run function paints the surface.
|
||||
First, it gets the contents of GtkTextBuffer.
|
||||
Then it compares it to "red", "green" and so on.
|
||||
If it matches the color, then the surface is painted the color.
|
||||
If it matches "light" or "dark", then the color of the surface is lightened or darkened respectively.
|
||||
Alpha channel is used.
|
||||
- 4-8: Win, tv, da and surface are defined as static variables.
|
||||
- 10-42: Run function.
|
||||
- 44-63: Handlers for button signals.
|
||||
- 65-71: Resize handler.
|
||||
- 73-79: Drawing function.
|
||||
- 81-84: Application activate handler.
|
||||
It just shows the main window.
|
||||
- 86-105: Application startup handler.
|
||||
- 92- 97: It builds widgets according to the ui resource.
|
||||
The static variables win, tv and da are assigned instances.
|
||||
- 98: Connects "resize" signal and a handler.
|
||||
- 99: Drawing function is set.
|
||||
- 101-104: CSS for textview padding is set.
|
||||
- 107-111: Application shutdown handler.
|
||||
If there exists a surface instance, it will be destroyed.
|
||||
- 116-129: A function `main`.
|
||||
It creates a new application instance.
|
||||
And connects three signals startup, shutdown and activate to their handlers.
|
||||
It runs the application.
|
||||
It releases the reference to the application and returns with `stat` value.
|
||||
|
||||
## Meson.build
|
||||
|
||||
|
@ -347,14 +426,9 @@ An argument "export_dynamic: true" is added to executable function.
|
|||
10 executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)
|
||||
~~~
|
||||
|
||||
## Compile and execute it
|
||||
## Build and try
|
||||
|
||||
First you need to export some variables (refer to [Section 2](sec2.md)) if you've installed GTK 4 from the source.
|
||||
If you've installed GTK 4 from the distribution packages, you don't need to do this.
|
||||
|
||||
$ . env.sh
|
||||
|
||||
Then type the following to compile it.
|
||||
Type the following to compile the program.
|
||||
|
||||
$ meson _build
|
||||
$ ninja -C _build
|
||||
|
@ -365,7 +439,8 @@ Type the following to execute it.
|
|||
$ _build/color
|
||||
|
||||
Type "red", "green", "blue", "white", black", "light" or "dark" in the TfeTextView.
|
||||
Then, click on `Run` button.
|
||||
No new line charactor is needed.
|
||||
Then, click on the `Run` button.
|
||||
Make sure the color of GtkDrawingArea changes.
|
||||
|
||||
In this program TfeTextView is used to change the color.
|
||||
|
|
372
gfm/sec25.md
|
@ -1,37 +1,38 @@
|
|||
Up: [Readme.md](../Readme.md), Prev: [Section 24](sec24.md), Next: [Section 26](sec26.md)
|
||||
Up: [README.md](../README.md), Prev: [Section 24](sec24.md), Next: [Section 26](sec26.md)
|
||||
|
||||
# Tiny turtle graphics interpreter
|
||||
|
||||
A program `turtle` is an example with the combination of TfeTextView and GtkDrawingArea objects.
|
||||
It is a very small interpreter but it provides a tool to draw fractal curves.
|
||||
The following diagram is a Koch curve, which is a famous example of fractal curves.
|
||||
It is a very small interpreter but you can draw fractal curves with it.
|
||||
The following diagram is a Koch curve, which is one of famous fractal curves.
|
||||
|
||||
![Koch curve](../src/turtle/image/turtle_koch.png)
|
||||
|
||||
The following is a snow-crystal-shaped curve.
|
||||
It is composed of six Koch curves.
|
||||
|
||||
![Snow](../image/turtle_snow.png)
|
||||
|
||||
This program uses flex and bison.
|
||||
Flex is a lexical analyzer.
|
||||
Bison is a parser generator.
|
||||
These two programs are similar to lex and yacc which are proprietary software developed in Bell Laboratory.
|
||||
However, flex and bison are open source software.
|
||||
I will write about how to use those software, but they are not topics about gtk.
|
||||
So, readers can skip that part of this sections.
|
||||
I will write about how to use those software, but they are not topics about GTK 4.
|
||||
So, readers can skip this section.
|
||||
|
||||
## How to use turtle
|
||||
|
||||
The documentation of turtle is [here](turtle_doc.md).
|
||||
The turtle document is [here](turtle_doc.md).
|
||||
I'll show you a simple example.
|
||||
|
||||
~~~
|
||||
fc (1,0,0) # Foreground color is red, rgb = (1,0,0).
|
||||
pd # Pen down.
|
||||
rp (4) { # Repeat four times.
|
||||
fd 100 # Go forward by 100 pixels.
|
||||
tr 90 # Turn right by 90 degrees.
|
||||
fd 100
|
||||
tr 90
|
||||
fd 100
|
||||
tr 90
|
||||
fd 100
|
||||
tr 90
|
||||
}
|
||||
~~~
|
||||
|
||||
1. Compile and install `turtle` (See the documentation above).
|
||||
|
@ -41,8 +42,8 @@ Then, run `turtle`.
|
|||
The side of the square is 100 pixels long.
|
||||
|
||||
In the same way, you can draw other curves.
|
||||
The documentation above shows some fractal curves such as tree, snow and square-koch.
|
||||
The source code in turtle language is located at [src/turtle/example](../src/turtle/example) directory.
|
||||
The turtle document includes some fractal curves such as tree, snow and square-koch.
|
||||
The source codes are located at [src/turtle/example](../src/turtle/example) directory.
|
||||
You can read these files into `turtle` editor by clicking on the `Open` button.
|
||||
|
||||
## Combination of TfeTextView and GtkDrawingArea objects
|
||||
|
@ -55,10 +56,9 @@ It is similar to `color` program in the previous section.
|
|||
3. The parser reads the program and generates tree-structured data.
|
||||
4. The interpriter reads the data and executes it step by step.
|
||||
And it draws shapes on a surface.
|
||||
The surface is different from the surface of the GtkDrawingArea widget.
|
||||
The surface isn't the one in the GtkDrawingArea widget.
|
||||
5. The widget is added to the queue.
|
||||
It will be redrawn with the drawing function.
|
||||
The function just copies the surface, which is drawn by the interpreter, into the surface of the GtkDrawingArea.
|
||||
It will be redrawn with the drawing function, which just copies the surface into the one in the GtkDrawingArea.
|
||||
|
||||
![Parser, interpreter and drawing function](../image/turtle.png)
|
||||
|
||||
|
@ -74,10 +74,10 @@ So the handler of "clicked" signal of the `Run` button prevents from reentering.
|
|||
5 GtkTextIter end_iter;
|
||||
6 char *contents;
|
||||
7 int stat;
|
||||
8 static gboolean busy = FALSE;
|
||||
8 static gboolean busy = FALSE; /* initialized only once */
|
||||
9
|
||||
10 /* yyparse() and run() are NOT thread safe. */
|
||||
11 /* The variable busy avoids reentry. */
|
||||
11 /* The variable busy avoids reentrance. */
|
||||
12 if (busy)
|
||||
13 return;
|
||||
14 busy = TRUE;
|
||||
|
@ -98,16 +98,18 @@ So the handler of "clicked" signal of the `Run` button prevents from reentering.
|
|||
29
|
||||
30 static void
|
||||
31 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
32 if (surface)
|
||||
33 cairo_surface_destroy (surface);
|
||||
34 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
35 }
|
||||
32
|
||||
33 if (surface)
|
||||
34 cairo_surface_destroy (surface);
|
||||
35 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
36 run_cb (NULL); // NULL is a fake (run button).
|
||||
37 }
|
||||
~~~
|
||||
|
||||
- 8-13: The static value `busy` holds a status of the interpreter.
|
||||
If it is `TRUE`, the interpreter is running and it is not possible to call the interpreter again because it's not a re-entrant program.
|
||||
If it is `FALSE`, it is safe to call the interpreter.
|
||||
- 14: Now it is about to call the interpreter so it changes `busy` to TRUE.
|
||||
- 14: Changes `busy` to TRUE to avoid reentrance.
|
||||
- 15-16: Gets the contents of `tb`.
|
||||
- 17: The variable `surface` is a static variable.
|
||||
It points to a `cairo_surface_t` instance.
|
||||
|
@ -116,17 +118,17 @@ Therefore, `surface` isn't NULL usually.
|
|||
But if it is NULL, the interpreter won't be called.
|
||||
- 18: Initializes lexical analyzer.
|
||||
- 19: Calls parser.
|
||||
Parser analyzes the program codes syntactically and generate a tree structured data.
|
||||
Parser analyzes the program codes syntactically and generates a tree structured data.
|
||||
- 20-22: If the parser successfully parsed, it calls `run` (runtime routine).
|
||||
- 23: finalizes the lexical analyzer.
|
||||
- 25: frees `contents`.
|
||||
- 26: Adds the drawing area widget to the queue to draw.
|
||||
- 27: The interpreter program has finished so `busy` is now changed to FALSE.
|
||||
- 29-34: A handler of "resized" signal.
|
||||
If `surface` isn't NULL, it destroys the old surface.
|
||||
Then it creates a new surface.
|
||||
- 30-37: A "resized" signal handler.
|
||||
If the `surface` isn't NULL, it is destroyed.
|
||||
A new surface is created.
|
||||
Its size is the same as the surface of the GtkDrawingArea instance.
|
||||
|
||||
Run\_cb is called to redraw the shape on the drawing area.
|
||||
|
||||
Other part of `turtleapplication.c` is almost same as the codes of `colorapplication.c` in the previous section.
|
||||
The codes of `turtleapplication.c` is in the [turtle directory](../src/turtle).
|
||||
|
@ -215,7 +217,7 @@ The source files are:
|
|||
|
||||
- flex source file => `turtle.lex`
|
||||
- bison source file => `turtle.y`
|
||||
- C header file => `turtle.h`, `turtle_lex.h`
|
||||
- C header file => `turtle_lex.h`
|
||||
- C source file => `turtleapplication.c`
|
||||
- other files => `turtle.ui`, `turtle.gresources.xml` and `meson.build`
|
||||
|
||||
|
@ -225,12 +227,13 @@ The compilation process is a bit complicated.
|
|||
It also generates `resources.h`.
|
||||
2. bison compiles `turtle.y` to `turtle_parser.c` and generates `turtle_parser.h`
|
||||
3. flex compiles `turtle.lex` to `turtle_lex.c`.
|
||||
4. gcc compiles `application.c`, `resources.c`, `turtle_parser.c` and `turtle_lex.c` with `turtle.h`, `turtle_lex.h`, `resources.h` and `turtle_parser.h`.
|
||||
4. gcc compiles `application.c`, `resources.c`, `turtle_parser.c` and `turtle_lex.c` with `turtle_lex.h`, `resources.h` and `turtle_parser.h`.
|
||||
It generates an executable file `turtle`.
|
||||
|
||||
![compile process](../image/turtle_compile_process.png)
|
||||
|
||||
Meson controls the process and the instruction is described in `meson.build`.
|
||||
Meson controls the process.
|
||||
The instruction is described in `meson.build`.
|
||||
|
||||
~~~meson
|
||||
1 project('turtle', 'c')
|
||||
|
@ -261,15 +264,13 @@ This program uses trigonometric functions.
|
|||
They are defined in the math library, but the library is optional.
|
||||
So, it is necessary to include it by `#include <math.h>` and also link the library with the linker.
|
||||
- 6: Gets gtk4 library.
|
||||
- 8: Gets gnome module.
|
||||
Module is a system provided by meson.
|
||||
See [Meson build system website, GNUME module](https://mesonbuild.com/Gnome-module.html#gnome-module) for further information.
|
||||
- 8: Gets gnome module.See [Meson build system website -- GNUME module](https://mesonbuild.com/Gnome-module.html#gnome-module) for further information.
|
||||
- 9: Compiles ui file to C source file according to the XML file `turtle.gresource.xml`.
|
||||
- 11: Gets flex.
|
||||
- 12: Gets bison.
|
||||
- 13: Compiles `turtle.y` to `turtle_parser.c` and `turtle_parser.h` by bison.
|
||||
The function `custom_target` creates a custom top level target.
|
||||
See [Meson build system website, custom target](https://mesonbuild.com/Reference-manual.html#custom_target) for further information.
|
||||
See [Meson build system website -- custom target](https://mesonbuild.com/Reference-manual.html#custom_target) for further information.
|
||||
- 14: Compiles `turtle.lex` to `turtle_lex.c` by flex.
|
||||
- 16: Specifies C source files.
|
||||
- 18: Compiles C source files including generated files by glib-compile-resources, bison and flex.
|
||||
|
@ -309,79 +310,81 @@ Turtle.lex isn't a big program.
|
|||
1 %top{
|
||||
2 #include <string.h>
|
||||
3 #include <stdlib.h>
|
||||
4 #include "turtle.h"
|
||||
5
|
||||
6 static int nline = 1;
|
||||
7 static int ncolumn = 1;
|
||||
8 static void get_location (char *text);
|
||||
9
|
||||
10 /* Dinamically allocated memories are added to the single list. They will be freed in the finalize function. */
|
||||
11 extern GSList *list;
|
||||
12 }
|
||||
13
|
||||
14 %option noyywrap
|
||||
15
|
||||
16 REAL_NUMBER (0|[1-9][0-9]*)(\.[0-9]+)?
|
||||
17 IDENTIFIER [a-zA-Z][a-zA-Z0-9]*
|
||||
18 %%
|
||||
19 /* rules */
|
||||
20 #.* ; /* comment. Be careful. Dot symbol (.) matches any character but new line. */
|
||||
21 [ ] ncolumn++;
|
||||
22 \t ncolumn += 8; /* assume that tab is 8 spaces. */
|
||||
23 \n nline++; ncolumn = 1;
|
||||
24 /* reserved keywords */
|
||||
25 pu get_location (yytext); return PU; /* pen up */
|
||||
26 pd get_location (yytext); return PD; /* pen down */
|
||||
27 pw get_location (yytext); return PW; /* pen width = line width */
|
||||
28 fd get_location (yytext); return FD; /* forward */
|
||||
29 tr get_location (yytext); return TR; /* turn right */
|
||||
30 bc get_location (yytext); return BC; /* background color */
|
||||
31 fc get_location (yytext); return FC; /* foreground color */
|
||||
32 dp get_location (yytext); return DP; /* define procedure */
|
||||
33 if get_location (yytext); return IF; /* if statement */
|
||||
34 rt get_location (yytext); return RT; /* return statement */
|
||||
35 rs get_location (yytext); return RS; /* reset the status */
|
||||
36 /* constant */
|
||||
37 {REAL_NUMBER} get_location (yytext); yylval.NUM = atof (yytext); return NUM;
|
||||
38 /* identifier */
|
||||
39 {IDENTIFIER} { get_location (yytext); yylval.ID = g_strdup(yytext);
|
||||
40 list = g_slist_prepend (list, yylval.ID);
|
||||
41 return ID;
|
||||
42 }
|
||||
43 "=" get_location (yytext); return '=';
|
||||
44 ">" get_location (yytext); return '>';
|
||||
45 "<" get_location (yytext); return '<';
|
||||
46 "+" get_location (yytext); return '+';
|
||||
47 "-" get_location (yytext); return '-';
|
||||
48 "*" get_location (yytext); return '*';
|
||||
49 "/" get_location (yytext); return '/';
|
||||
50 "(" get_location (yytext); return '(';
|
||||
51 ")" get_location (yytext); return ')';
|
||||
52 "{" get_location (yytext); return '{';
|
||||
53 "}" get_location (yytext); return '}';
|
||||
54 "," get_location (yytext); return ',';
|
||||
55 . ncolumn++; return YYUNDEF;
|
||||
56 %%
|
||||
57
|
||||
58 static void
|
||||
59 get_location (char *text) {
|
||||
60 yylloc.first_line = yylloc.last_line = nline;
|
||||
61 yylloc.first_column = ncolumn;
|
||||
62 yylloc.last_column = (ncolumn += strlen(text)) - 1;
|
||||
63 }
|
||||
64
|
||||
65 static YY_BUFFER_STATE state;
|
||||
66
|
||||
67 void
|
||||
68 init_flex (const char *text) {
|
||||
69 state = yy_scan_string (text);
|
||||
70 }
|
||||
71
|
||||
72 void
|
||||
73 finalize_flex (void) {
|
||||
74 yy_delete_buffer (state);
|
||||
75 }
|
||||
76
|
||||
4 #include <glib.h>
|
||||
5 #include "turtle_parser.h"
|
||||
6
|
||||
7 static int nline = 1;
|
||||
8 static int ncolumn = 1;
|
||||
9 static void get_location (char *text);
|
||||
10
|
||||
11 /* Dinamically allocated memories are added to the single list. They will be freed in the finalize function. */
|
||||
12 extern GSList *list;
|
||||
13 }
|
||||
14
|
||||
15 %option noyywrap
|
||||
16
|
||||
17 REAL_NUMBER (0|[1-9][0-9]*)(\.[0-9]+)?
|
||||
18 IDENTIFIER [a-zA-Z][a-zA-Z0-9]*
|
||||
19 %%
|
||||
20 /* rules */
|
||||
21 #.* ; /* comment. Be careful. Dot symbol (.) matches any character but new line. */
|
||||
22 [ ] ncolumn++;
|
||||
23 \t ncolumn += 8; /* assume that tab is 8 spaces. */
|
||||
24 \n nline++; ncolumn = 1;
|
||||
25 /* reserved keywords */
|
||||
26 pu get_location (yytext); return PU; /* pen up */
|
||||
27 pd get_location (yytext); return PD; /* pen down */
|
||||
28 pw get_location (yytext); return PW; /* pen width = line width */
|
||||
29 fd get_location (yytext); return FD; /* forward */
|
||||
30 tr get_location (yytext); return TR; /* turn right */
|
||||
31 tl get_location (yytext); return TL; /* turn left ver 0.5 */
|
||||
32 bc get_location (yytext); return BC; /* background color */
|
||||
33 fc get_location (yytext); return FC; /* foreground color */
|
||||
34 dp get_location (yytext); return DP; /* define procedure */
|
||||
35 if get_location (yytext); return IF; /* if statement */
|
||||
36 rt get_location (yytext); return RT; /* return statement */
|
||||
37 rs get_location (yytext); return RS; /* reset the status */
|
||||
38 rp get_location (yytext); return RP; /* repeat ver 0.5 */
|
||||
39 /* constant */
|
||||
40 {REAL_NUMBER} get_location (yytext); yylval.NUM = atof (yytext); return NUM;
|
||||
41 /* identifier */
|
||||
42 {IDENTIFIER} { get_location (yytext); yylval.ID = g_strdup(yytext);
|
||||
43 list = g_slist_prepend (list, yylval.ID);
|
||||
44 return ID;
|
||||
45 }
|
||||
46 "=" get_location (yytext); return '=';
|
||||
47 ">" get_location (yytext); return '>';
|
||||
48 "<" get_location (yytext); return '<';
|
||||
49 "+" get_location (yytext); return '+';
|
||||
50 "-" get_location (yytext); return '-';
|
||||
51 "*" get_location (yytext); return '*';
|
||||
52 "/" get_location (yytext); return '/';
|
||||
53 "(" get_location (yytext); return '(';
|
||||
54 ")" get_location (yytext); return ')';
|
||||
55 "{" get_location (yytext); return '{';
|
||||
56 "}" get_location (yytext); return '}';
|
||||
57 "," get_location (yytext); return ',';
|
||||
58 . ncolumn++; return YYUNDEF;
|
||||
59 %%
|
||||
60
|
||||
61 static void
|
||||
62 get_location (char *text) {
|
||||
63 yylloc.first_line = yylloc.last_line = nline;
|
||||
64 yylloc.first_column = ncolumn;
|
||||
65 yylloc.last_column = (ncolumn += strlen(text)) - 1;
|
||||
66 }
|
||||
67
|
||||
68 static YY_BUFFER_STATE state;
|
||||
69
|
||||
70 void
|
||||
71 init_flex (const char *text) {
|
||||
72 state = yy_scan_string (text);
|
||||
73 }
|
||||
74
|
||||
75 void
|
||||
76 finalize_flex (void) {
|
||||
77 yy_delete_buffer (state);
|
||||
78 }
|
||||
~~~
|
||||
|
||||
The file consists of three sections which are separated by "%%" (line 18 and 56).
|
||||
|
@ -391,17 +394,17 @@ They are definitions, rules and user code sections.
|
|||
|
||||
- 1-12: Lines between "%top{" and "}" are C source codes.
|
||||
They will be copied to the top of the generated C source file.
|
||||
- 2-3: The function `strlen`, in line 62, is defined in `string.h`
|
||||
The function `atof`, in line 37, is defined in `stdlib.h`.
|
||||
- 6-8: The current input position is pointed by `nline` and `ncolumn`.
|
||||
The function `get_location` (line 58-63) sets `yylloc`to point the start and end point of `yytext` in the buffer.
|
||||
- 2-3: The function `strlen`, in line 65, is defined in `string.h`
|
||||
The function `atof`, in line 40, is defined in `stdlib.h`.
|
||||
- 7-9: The current input position is pointed by `nline` and `ncolumn`.
|
||||
The function `get_location` (line 61-66) sets `yylloc`to point the start and end point of `yytext` in the buffer.
|
||||
This function is declared here so that it can be called before the function is defined.
|
||||
- 11: GSlist is used to keep allocated memories.
|
||||
- 14: This option (`%option noyywrap`) must be specified when you have only single source file to the scanner. Refer to "9 The Generated Scanner" in the flex documentation in your distribution for further information.
|
||||
- 12: GSlist is used to keep allocated memories.
|
||||
- 15: This option (`%option noyywrap`) must be specified when you have only single source file to the scanner. Refer to "9 The Generated Scanner" in the flex documentation in your distribution for further information.
|
||||
(The documentation is not on the internet.)
|
||||
- 16-17: `REAL_NUMBER` and `IDENTIFIER` are names.
|
||||
- 17-18: `REAL_NUMBER` and `IDENTIFIER` are names.
|
||||
A name begins with a letter or an underscore followed by zero or more letters, digits, underscores (`_`) or dashes (`-`).
|
||||
They are followed by regular expressions which are their definition.
|
||||
They are followed by regular expressions which are their definitions.
|
||||
They will be used in rules section and will expand to the definition.
|
||||
You can leave out such definitions here and use regular expressions in rules section directly.
|
||||
|
||||
|
@ -413,64 +416,66 @@ The patterns are regular expressions or names surrounded by braces.
|
|||
The names must be defined in the definitions section.
|
||||
The definition of the regular expression is written in the flex documentation.
|
||||
|
||||
For example, line 37 is a rule.
|
||||
For example, line 40 is a rule.
|
||||
|
||||
- `{REAL_NUMBER}` is a pattern
|
||||
- `get_location (yytext); yylval.NUM = atof (yytext); return NUM;` is an action.
|
||||
|
||||
`{REAL_NUMBER}` is defined in the 16th line, so it expands to `(0|[1-9][0-9]*)(\.[0-9]+)?`.
|
||||
`{REAL_NUMBER}` is defined in the line 17, so it expands to `(0|[1-9][0-9]*)(\.[0-9]+)?`.
|
||||
This regular expression matches numbers like `0`, `12` and `1.5`.
|
||||
If the input is a number, it matches the pattern in line 37.
|
||||
If an input is a number, it matches the pattern in line 40.
|
||||
Then the matched text is assigned to `yytext` and corresponding action is executed.
|
||||
A function `get_location` changes the location variables.
|
||||
A function `get_location` changes the location variables to the position at the text.
|
||||
It assigns `atof (yytext)`, which is double sized number converted from `yytext`, to `yylval.NUM` and return `NUM`.
|
||||
`NUM` is an integer defined by `turtle.y`.
|
||||
`NUM` is a token kind and it represents integer.
|
||||
It is defined in `turtle.y`.
|
||||
|
||||
The scanner generated by flex and C compiler has `yylex` function.
|
||||
The scanner generated by flex has `yylex` function.
|
||||
If `yylex` is called and the input is "123.4", then it works as follows.
|
||||
|
||||
1. A string "123.4" matches `{REAL_NUMBER}`.
|
||||
2. Update the location variable `ncolumn` and `yylloc`with `get_location`.
|
||||
3. `atof` converts the string "123.4" to double type number 123.4.
|
||||
3. The function `atof` converts the string "123.4" to double type number 123.4.
|
||||
4. It is assigned to `yylval.NUM`.
|
||||
5. `yylex` returns `NUM` to the caller.
|
||||
|
||||
Then the caller knows the input is `NUM` (number), and its value is 123.4.
|
||||
Then the caller knows the input is a number (`NUM`), and its value is 123.4.
|
||||
|
||||
- 19-55: Rules section.
|
||||
- 20: The symbol `.` (dot) matches any character except newline.
|
||||
- 20-58: Rules section.
|
||||
- 21: The symbol `.` (dot) matches any character except newline.
|
||||
Therefore, a comment begins `#` followed by any characters except newline.
|
||||
No action happens.
|
||||
- 21: White space just increases a variable `ncolumn` by one.
|
||||
- 22: Tab is assumed to be equal to eight spaces.
|
||||
- 23: New line increases a variable `nline` by one and resets `ncolumn`.
|
||||
- 25-35: Keywords just updates the location variables `ncolumn` and `yylloc`, and return the codes of the keywords.
|
||||
- 37: Real number constant.
|
||||
- 38: `IDENTIFIER` is defined in line 17.
|
||||
- 22: White space just increases the variable `ncolumn` by one.
|
||||
- 23: Tab is assumed to be equal to eight spaces.
|
||||
- 24: New line increases a variable `nline` by one and resets `ncolumn`.
|
||||
- 26-38: Keywords just updates the location variables `ncolumn` and `yylloc`, and return the token kinds of the keywords.
|
||||
- 40: Real number constant.
|
||||
- 42: `IDENTIFIER` is defined in line 18.
|
||||
The location variables are updated and the name of the identifier is assigned to `yylval.ID`.
|
||||
The memory of the name is allocated by the function `g_strdup`.
|
||||
The memory is registered to the list (GSlist type list).
|
||||
The memory will be freed after the runtime routine finishes.
|
||||
Returns `ID`.
|
||||
- 43-54: Symbols just update the location variable and return the codes.
|
||||
The code is the same as the symbol itself.
|
||||
- 55: If the input doesn't match above patterns, then it is error.
|
||||
Returns `YYUNDEF`.
|
||||
A token kind `ID` is returned.
|
||||
- 46-56: Symbols just update the location variable and return the token kinds.
|
||||
The token kind is the same as the symbol itself.
|
||||
- 58: If the input doesn't match the patterns, then it is an error.
|
||||
A special token kind `YYUNDEF` is returned.
|
||||
|
||||
### User code section
|
||||
|
||||
This section is just copied to C source file.
|
||||
|
||||
- 58-63: A function `get_location`.
|
||||
- 61-66: A function `get_location`.
|
||||
The location of the input is recorded to `nline` and `ncolumn`.
|
||||
A variable `yylloc` is referred by the parser.
|
||||
It is a C structure and has four members, `first_line`, `first_column`, `last_line` and `last_column`.
|
||||
They point the start and end of the current input text.
|
||||
- 65: `YY_BUFFER_STATE` is a pointer points the input buffer.
|
||||
- 67-70: `init_flex` is called by `run_cb` signal handler, which is called when `Run` button is clicked on.
|
||||
`run_cb` calls `init_flex` with one argument which is the copy of the content of GtkTextBuffer.
|
||||
`yy_scan_string` sets the input buffer to read from the text.
|
||||
- 72-75: `finalize_flex` is called after runtime routine finishes.
|
||||
- 68: `YY_BUFFER_STATE` is a pointer points the input buffer.
|
||||
- 70-73: A function `init_flex` is called by `run_cb` which is a "clicked" signal handler on the `Run` button.
|
||||
It has one string type parameter.
|
||||
The caller assigns it with the content of the GtkTextBuffer instance.
|
||||
A function `yy_scan_string` sets the input buffer for the scanner.
|
||||
- 75-78: A function `finalize_flex` is called after runtime routine finishes.
|
||||
It deletes the input buffer.
|
||||
|
||||
## Turtle.y
|
||||
|
@ -480,8 +485,8 @@ So I will explain the key points and leave out other less important parts.
|
|||
|
||||
### What does bison do?
|
||||
|
||||
Bison creates C source file from bison source file.
|
||||
Bison source file is a text file.
|
||||
Bison creates C source file of a parser from a bison source file.
|
||||
The bison source file is a text file.
|
||||
A parser analyzes a program source code according to its grammar.
|
||||
Suppose here is a turtle source file.
|
||||
|
||||
|
@ -522,7 +527,7 @@ So, the parser gets items in the following table whenever it calls `yylex`.
|
|||
|
||||
Bison source code specifies the grammar rules of turtle language.
|
||||
For example, `fc (1,0,0)` is called primary procedure.
|
||||
A procedure is like a void type function in C source code.
|
||||
A procedure is like a void type C function.
|
||||
It doesn't return any values.
|
||||
Programmers can define their own procedures.
|
||||
On the other hand, `fc` is a built-in procedure.
|
||||
|
@ -540,7 +545,8 @@ This means:
|
|||
- expression is ID or NUM.
|
||||
|
||||
The description above is called BNF (Backus-Naur form).
|
||||
More precisely, it is similar to BNF.
|
||||
Precisely speaking, it is not exactly the same as BNF.
|
||||
But the difference is small.
|
||||
|
||||
The first line is:
|
||||
|
||||
|
@ -550,7 +556,7 @@ FC '(' NUM ',' NUM ',' NUM ')';
|
|||
|
||||
The parser analyzes the turtle source code and if the input matches the definition above, the parser recognizes it as a primary procedure.
|
||||
|
||||
The grammar of turtle is described in the [document](turtle_doc.md).
|
||||
The grammar of turtle is described in the [Turtle manual](https://toshiocp.github.io/Gtk4-tutorial/turtle_doc.html).
|
||||
The following is an extract from the document.
|
||||
|
||||
~~~
|
||||
|
@ -570,12 +576,14 @@ primary_procedure:
|
|||
| PW expression
|
||||
| FD expression
|
||||
| TR expression
|
||||
| TL expression
|
||||
| BC '(' expression ',' expression ',' expression ')'
|
||||
| FC '(' expression ',' expression ',' expression ')'
|
||||
| ID '=' expression
|
||||
| IF '(' expression ')' '{' primary_procedure_list '}'
|
||||
| RT
|
||||
| RS
|
||||
| RP '(' expression ')' '{' primary_procedure_list '}'
|
||||
| ID '(' ')'
|
||||
| ID '(' argument_list ')'
|
||||
;
|
||||
|
@ -622,12 +630,12 @@ The grammar rule defines `program` first.
|
|||
The definition is recursive.
|
||||
|
||||
- `statement` is program.
|
||||
- `statement statement` is `program statemet`.
|
||||
- `statement statement` is `program statement`.
|
||||
Therefore, it is program.
|
||||
- `statement statement statement` is `program statemet`.
|
||||
- `statement statement statement` is `program statement`.
|
||||
Therefore, it is program.
|
||||
|
||||
You can find that a list of statements is program like this.
|
||||
You can find that a sequence of statements is program like this.
|
||||
|
||||
`program` and `statement` aren't tokens.
|
||||
They don't appear in the input.
|
||||
|
@ -723,7 +731,17 @@ The following is an extract from `turtle.y`.
|
|||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
#include <math.h>
|
||||
#include "turtle.h"
|
||||
#include <glib.h>
|
||||
#include <cairo.h>
|
||||
#include "turtle_parser.h"
|
||||
|
||||
/* The following line defines 'debug' so that debug information is printed out during the run time. */
|
||||
/* However it makes the program slow. */
|
||||
/* If you want to debug on, uncomment the line. */
|
||||
|
||||
/* #define debug 1 */
|
||||
|
||||
extern cairo_surface_t *surface;
|
||||
|
||||
/* error reporting */
|
||||
static void yyerror (char const *s) { /* for syntax error */
|
||||
|
@ -768,7 +786,7 @@ The header file is read by the scanner C source file and other files.
|
|||
}
|
||||
~~~
|
||||
|
||||
- `yylex` is shared by parser implementation file and scanner file.
|
||||
- `yylex` is shared by the parser implementation file and scanner file.
|
||||
- `yyparse` and `run` is called by `run_cb` in `turtleapplication.c`.
|
||||
- `node_t` is the type of the semantic value of nterms.
|
||||
The header file defines `YYSTYPE`, which is the semantic value type, with all the token and nterm value types.
|
||||
|
@ -826,12 +844,14 @@ It also specifies some directives.
|
|||
%token PW
|
||||
%token FD
|
||||
%token TR
|
||||
%token TL
|
||||
%token BC
|
||||
%token FC
|
||||
%token DP
|
||||
%token IF
|
||||
%token RT
|
||||
%token RS
|
||||
%token RP
|
||||
/* constant */
|
||||
%token <double> NUM
|
||||
/* identirier */
|
||||
|
@ -950,8 +970,9 @@ Be careful.
|
|||
The operator `=` above is an assignment.
|
||||
Assignment is not expression in turtle language.
|
||||
It is primary_procedure.
|
||||
But if `=` appears in an expression, it is a logical operater, not an assignment.
|
||||
But if `=` appears in an expression, it is a logical operator, not an assignment.
|
||||
The logical equal '`=`' usually used in the conditional expression, for example, in `if` statement.
|
||||
(Turtle language uses '=' instead of '==' in C language).
|
||||
|
||||
### Grammar rules
|
||||
|
||||
|
@ -984,22 +1005,22 @@ expression:
|
|||
;
|
||||
~~~
|
||||
|
||||
- `program` is `statement`.
|
||||
- The first two lines tell that `program` is `statement`.
|
||||
- Whenever `statement` is reduced to `program`, an action `node_top=$$=$1;` is executed.
|
||||
- `node_top` is a static variable.
|
||||
It points the top node of the tree.
|
||||
- `$$` is a semantic value of the result, which is `program` in the second line of the example above.
|
||||
The semantic value of `program` is a pointer to `node_t` type structure.
|
||||
It was defined in the declaration section.
|
||||
- `$1` is a semantic value of the first component, which is `statement`.
|
||||
The semantic value of `statement` is also a pointer to `node_t`.
|
||||
- `statement` is `primary_procedure`.
|
||||
- A symbol `$$` is a semantic value of the result.
|
||||
For example, `$$` in line 2 is the semantic value of `program`.
|
||||
It is a pointer to a `node_t` type structure.
|
||||
- `$1` is a semantic value of the first component.
|
||||
For example, `$1` in line 2 is the semantic value of `statement`.
|
||||
It is also a pointer to `node_t`.
|
||||
- The next rule is that `statement` is `primary_procedure`.
|
||||
There's no action specified.
|
||||
Then, the default action is executed.
|
||||
It is ` $$ = $1`.
|
||||
- `primary_procedure` is `FD` followed by expression.
|
||||
Then, the default action `$$ = $1` is executed.
|
||||
- The next rule is that `primary_procedure` is `FD` followed by expression.
|
||||
The action calls `tree1` and assigns its return value to `$$`.
|
||||
`tree1` makes a tree node.
|
||||
The function `tree1` makes a tree node.
|
||||
The tree node has type and union of three pointers to children nodes, string or double.
|
||||
~~~
|
||||
node --+-- type
|
||||
|
@ -1009,7 +1030,7 @@ node --+-- type
|
|||
+---double value
|
||||
~~~
|
||||
- `tree1` assigns the four arguments to type, child1, child2 and child3 members.
|
||||
- `expression` is `NUM`.
|
||||
- The last rule is that `expression` is `NUM`.
|
||||
- `tree2` makes a tree node. The paremeters of `tree2` are a type and a semantic value.
|
||||
|
||||
Suppose the parser reads the following program.
|
||||
|
@ -1062,6 +1083,7 @@ primary_procedure:
|
|||
| PW expression { $$ = tree1 (N_PW, $2, NULL, NULL); }
|
||||
| FD expression { $$ = tree1 (N_FD, $2, NULL, NULL); }
|
||||
| TR expression { $$ = tree1 (N_TR, $2, NULL, NULL); }
|
||||
| TL expression { $$ = tree1 (N_TL, $2, NULL, NULL); } /* ver 0.5 */
|
||||
| BC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_BC, $3, $5, $7); }
|
||||
| FC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_FC, $3, $5, $7); }
|
||||
/* assignment */
|
||||
|
@ -1070,6 +1092,7 @@ primary_procedure:
|
|||
| IF '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_IF, $3, $6, NULL); }
|
||||
| RT { $$ = tree1 (N_RT, NULL, NULL, NULL); }
|
||||
| RS { $$ = tree1 (N_RS, NULL, NULL, NULL); }
|
||||
| RP '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_RP, $3, $6, NULL); }
|
||||
/* user defined procedure call */
|
||||
| ID '(' ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), NULL, NULL); }
|
||||
| ID '(' argument_list ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), $3, NULL); }
|
||||
|
@ -1219,7 +1242,7 @@ init_table (void) {
|
|||
~~~
|
||||
|
||||
`init_table` initializes the table.
|
||||
This must be called before any registrations.
|
||||
This must be called before registrations.
|
||||
|
||||
There are five functions to access the table,
|
||||
|
||||
|
@ -1347,8 +1370,8 @@ The runtime routine stores the name `drawline` and the node of the procedure to
|
|||
- The second line calls the procedure.
|
||||
First, it looks for the procedure in the symbol table and gets its node.
|
||||
Then it searches the node for the parameters and gets `angle` and `distance`.
|
||||
- It pushes ("distance", 100.0) to the stack.
|
||||
- It pushes ("angle", 90.0) to the stack.
|
||||
- It pushes ("distance", 100.0) to the stack.
|
||||
- It pushes (NULL, 2.0) to the stack.
|
||||
The number 2.0 is the number of parameters (or arguments).
|
||||
It is used when the procedure returns.
|
||||
|
@ -1356,8 +1379,11 @@ It is used when the procedure returns.
|
|||
The following diagram shows the structure of the stack.
|
||||
First, `procedure 1` is called.
|
||||
The procedure has two parameters.
|
||||
In the `procedure 1`, another procedure `procedure 2`, which has one parameter, is called.
|
||||
And in the `procedure 2`, `procedure 3`, which has three parameters, is called.
|
||||
In the `procedure 1`, another procedure `procedure 2` is called.
|
||||
It has one parameter.
|
||||
In the `procedure 2`, another procedure `procedure 3` is called.
|
||||
It has three parameters.
|
||||
These three procedures are nested.
|
||||
|
||||
Programs push data to a stack from a low address memory to a high address memory.
|
||||
In the following diagram, the lowest address is at the top and the highest address is at the bottom.
|
||||
|
@ -1948,6 +1974,6 @@ However, the following information is very useful (but old).
|
|||
- Source code of a language, for example, ruby.
|
||||
|
||||
Lately, lots of source codes are in the internet.
|
||||
Maybe reading source codes are the most useful for programmers.
|
||||
Maybe reading source codes is the most useful for programmers.
|
||||
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 24](sec24.md), Next: [Section 26](sec26.md)
|
||||
Up: [README.md](../README.md), Prev: [Section 24](sec24.md), Next: [Section 26](sec26.md)
|
||||
|
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 28 KiB |
BIN
image/turtle_snow.png
Normal file
After Width: | Height: | Size: 83 KiB |
|
@ -1,3 +0,0 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
#include "../tfetextview/tfetextview.h"
|
|
@ -1,4 +1,5 @@
|
|||
#include "color.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include "../tfetextview/tfetextview.h"
|
||||
|
||||
static GtkWidget *win;
|
||||
static GtkWidget *tv;
|
||||
|
@ -58,8 +59,6 @@ save_cb (GtkWidget *btns) {
|
|||
|
||||
void
|
||||
close_cb (GtkWidget *btnc) {
|
||||
if (surface)
|
||||
cairo_surface_destroy (surface);
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
|
@ -81,13 +80,14 @@ draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpo
|
|||
|
||||
static void
|
||||
app_activate (GApplication *application) {
|
||||
gtk_widget_show (win);
|
||||
gtk_window_present (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
app_startup (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
GtkBuilder *build;
|
||||
GdkDisplay *display;
|
||||
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/color/color.ui");
|
||||
win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
|
@ -98,14 +98,18 @@ app_startup (GApplication *application) {
|
|||
g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
|
||||
|
||||
GdkDisplay *display;
|
||||
|
||||
display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
display = gdk_display_get_default ();
|
||||
GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
}
|
||||
|
||||
static void
|
||||
app_shutdown (GApplication *application) {
|
||||
if (surface)
|
||||
cairo_surface_destroy (surface);
|
||||
}
|
||||
|
||||
#define APPLICATION_ID "com.github.ToshioCP.color"
|
||||
|
||||
int
|
||||
|
@ -113,9 +117,10 @@ main (int argc, char **argv) {
|
|||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "shutdown", G_CALLBACK (app_shutdown), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
|
|
|
@ -7,17 +7,17 @@ This is called custom drawing.
|
|||
GtkDrawingArea provides a cairo drawing context so users can draw images by using cairo functions.
|
||||
In this section, I will explain:
|
||||
|
||||
1. Cairo, but only briefly; and
|
||||
1. Cairo, but only briefly
|
||||
2. GtkDrawingArea, with a very simple example.
|
||||
|
||||
## Cairo
|
||||
|
||||
Cairo is a set of two dimensional graphical drawing functions (or graphics library).
|
||||
There is a lot of documentation on [Cairo's website](https://www.cairographics.org/).
|
||||
If you aren't familiar with Cairo, it is worth reading their [tutorial](https://www.cairographics.org/tutorial/).
|
||||
There are a lot of documents on [Cairo's website](https://www.cairographics.org/).
|
||||
If you aren't familiar with Cairo, it is worth reading the [tutorial](https://www.cairographics.org/tutorial/).
|
||||
|
||||
The following is a gentle introduction to the Cairo library and how to use it.
|
||||
Firstly, in order to use Cairo you need to know about surfaces, sources, masks, destinations, cairo context and transformations.
|
||||
The following is an introduction to the Cairo library and how to use it.
|
||||
First, you need to know about surfaces, sources, masks, destinations, cairo context and transformations.
|
||||
|
||||
- A surface represents an image.
|
||||
It is like a canvas.
|
||||
|
@ -48,6 +48,7 @@ This will be the destination.
|
|||
6. Save the destination surface to a file if necessary.
|
||||
|
||||
Here's a simple example program that draws a small square and saves it as a png file.
|
||||
The path of the file is `src/misc/cairo.c`.
|
||||
|
||||
@@@include
|
||||
misc/cairo.c
|
||||
|
@ -66,7 +67,7 @@ Width and height are in pixels and given as integers.
|
|||
- 14: Creates cairo context.
|
||||
The surface given as an argument will be the destination of the context.
|
||||
- 18: `cairo_set_source_rgb` creates a source pattern, which in this case is a solid white paint.
|
||||
The second to fourth argument are red, green and blue color values respectively, and they are
|
||||
The second to fourth arguments are red, green and blue color values respectively, and they are
|
||||
of type float. The values are between zero (0.0) and one (1.0), with
|
||||
black being given by (0.0,0.0,0.0) and white by (1.0,1.0,1.0).
|
||||
- 19: `cairo_paint` copies everywhere in the source to destination.
|
||||
|
@ -83,13 +84,13 @@ The square is located at the center.
|
|||
- 28: Destroys the context. At the same time the source is destroyed.
|
||||
- 29: Destroys the surface.
|
||||
|
||||
To compile this, type the following.
|
||||
To compile this, change your current directory to `src/misc` and type the following.
|
||||
|
||||
$ gcc `pkg-config --cflags cairo` cairo.c `pkg-config --libs cairo`
|
||||
|
||||
![rectangle.png](../image/rectangle.png)
|
||||
|
||||
See the [Cairo's website](https://www.cairographics.org/) for more details.
|
||||
See the [Cairo's website](https://www.cairographics.org/) for further information.
|
||||
|
||||
## GtkDrawingArea
|
||||
|
||||
|
@ -102,12 +103,12 @@ misc/da1.c
|
|||
The function `main` is almost same as before.
|
||||
The two functions `app_activate` and `draw_function` are important in this example.
|
||||
|
||||
- 18: Creates a GtkDrawingArea instance; and
|
||||
- 21: Sets a drawing function of the widget.
|
||||
- 22: Creates a GtkDrawingArea instance.
|
||||
- 25: Sets a drawing function of the widget.
|
||||
GtkDrawingArea widget uses the function to draw the contents of itself whenever its necessary.
|
||||
For example, when a user drag a mouse pointer and resize a top-level window, GtkDrawingArea also changes the size.
|
||||
Then, the whole window needs to be redrawn.
|
||||
For the information of `gtk_drawing_area_set_draw_func`, see [Gtk API Reference, gtk\_drawing\_area\_set\_draw\_func](https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html).
|
||||
For the information of `gtk_drawing_area_set_draw_func`, see [Gtk API Reference -- gtk\_drawing\_area\_set\_draw\_func](https://docs.gtk.org/gtk4/method.DrawingArea.set_draw_func.html).
|
||||
|
||||
The drawing function has five parameters.
|
||||
|
||||
|
@ -122,15 +123,16 @@ The second parameter is a cairo context given by the widget.
|
|||
The destination surface of the context is connected to the contents of the widget.
|
||||
What you draw to this surface will appear in the widget on the screen.
|
||||
The third and fourth parameters are the size of the destination surface.
|
||||
Now, look at the program example again.
|
||||
Now, look at the program again.
|
||||
|
||||
- 3-13: The drawing function.
|
||||
- 3-17: The drawing function.
|
||||
- 7-8: Sets the source to be white and paint the destination white.
|
||||
- 9: Sets the line width to be 2.
|
||||
- 10: Sets the source to be black.
|
||||
- 11: Adds a rectangle to the mask.
|
||||
- 12: Draws the rectangle with black color to the destination.
|
||||
- 11-15: Adds a rectangle to the mask.
|
||||
- 16: Draws the rectangle with black color to the destination.
|
||||
|
||||
The program is [src/misc/da1.c](misc/da1.c).
|
||||
Compile and run it, then a window with a black rectangle (square) appears.
|
||||
Try resizing the window.
|
||||
The square always appears at the center of the window because the drawing function is invoked each time the window is resized.
|
||||
|
|
144
src/sec24.src.md
|
@ -7,6 +7,7 @@ If you write a name of a color in TfeTextView and click on the `run` button, the
|
|||
![color](../image/color.png){width=7.0cm height=5.13cm}
|
||||
|
||||
The following colors are available.
|
||||
(without new line charactor)
|
||||
|
||||
- white
|
||||
- black
|
||||
|
@ -28,24 +29,23 @@ In this section, we focus on how to bind the two objects.
|
|||
## Color.ui and color.gresource.xml
|
||||
|
||||
First, We need to make the ui file of the widgets.
|
||||
The image in the previous subsection gives us the structure of the widgets.
|
||||
Title bar, four buttons in the tool bar and two widgets textview and drawing area.
|
||||
Title bar, four buttons in the tool bar, textview and drawing area.
|
||||
The ui file is as follows.
|
||||
|
||||
@@@include
|
||||
color/color.ui
|
||||
@@@
|
||||
|
||||
- 10-53: This part is the tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
|
||||
This is similar to the toolbar of tfe text editor in [Section 9](sec9.src.md).
|
||||
- 10-53: The horizontal box `boxh1` makes a tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
|
||||
This is similar to the `tfe` text editor in [Section 9](sec9.src.md).
|
||||
There are two differences.
|
||||
`Run` button replaces `New` button.
|
||||
A signal element is added to each button object.
|
||||
It has "name" attribute which is a signal name and "handler" attribute which is the name of its signal handler function.
|
||||
It has "name" attribute which is a signal name and "handler" attribute which is the name of its signal handler.
|
||||
Options "-WI, --export-dynamic" CFLAG is necessary when you compile the application.
|
||||
You can achieve this by adding "export_dynamic: true" argument to executable function in `meson.build`.
|
||||
You can achieve this by adding "export_dynamic: true" argument to the executable function in `meson.build`.
|
||||
And be careful that the handler must be defined without 'static' class.
|
||||
- 54-76: Puts GtkScrolledWindow and GtkDrawingArea into GtkBox.
|
||||
- 54-76: The horizontal box `boxh2` includes GtkScrolledWindow and GtkDrawingArea.
|
||||
GtkBox has "homogeneous property" with TRUE value, so the two children have the same width in the box.
|
||||
TfeTextView is a child of GtkScrolledWindow.
|
||||
|
||||
|
@ -56,24 +56,70 @@ Just substitute "color" for "tfe".
|
|||
color/color.gresource.xml
|
||||
@@@
|
||||
|
||||
## Tfetextview.h, tfetextview.c and color.h
|
||||
## Drawing function and surface
|
||||
|
||||
First two files are the same as before.
|
||||
Color.h just includes tfetextview.h.
|
||||
The main point of this program is a drawing function.
|
||||
|
||||
@@@include
|
||||
color/color.h
|
||||
color/colorapplication.c draw_func
|
||||
@@@
|
||||
|
||||
The `surface` variable in line 3 is a static variable.
|
||||
|
||||
~~~C
|
||||
static cairo_surface_t *surface = NULL;
|
||||
~~~
|
||||
|
||||
The drawing function just copies the `surface` to its own surface with the `cairo_paint` function.
|
||||
The surface (pointed by the static variable `surface`) is built by the `run` function.
|
||||
|
||||
@@@include
|
||||
color/colorapplication.c run
|
||||
@@@
|
||||
|
||||
- 9-10: Gets the string in the GtkTextBuffer and inserts it to `contents`.
|
||||
- 11: If the variable `surface` points a surface instance, it is painted as follows.
|
||||
- 12- 30: The source is set based on the string `contents` and copied to the surface with `cairo_paint`.
|
||||
- 24,26: Alpha channel is used in "light" and "dark" procedure.
|
||||
|
||||
The drawing area just reflects the `surface`.
|
||||
But one problem is resizing.
|
||||
If a user resizes the main window, the drawing area is also resized.
|
||||
It makes size difference between the surface and the drawing area.
|
||||
So, the surface needs to be resized to fit the drawing area.
|
||||
|
||||
It is accomplished by connecting the "resize" signal on the drawing area to a handler.
|
||||
|
||||
~~~C
|
||||
g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
~~~
|
||||
|
||||
The handler is as follows.
|
||||
|
||||
@@@include
|
||||
color/colorapplication.c resize_cb
|
||||
@@@
|
||||
|
||||
If the variable `surface` sets a surface instance, it is destroyed.
|
||||
A new surface is created and its size fits the drawing area.
|
||||
The surface is assigned to the variable `surface`.
|
||||
The function `run` is called and the surface is colored.
|
||||
|
||||
The signal is emitted when:
|
||||
|
||||
- The drawing area is realized (it appears on the display).
|
||||
- It is changed (resized) while realized
|
||||
|
||||
So, the first surface is created when it is realized.
|
||||
|
||||
## Colorapplication.c
|
||||
|
||||
This is the main file.
|
||||
It deals with:
|
||||
|
||||
- Building widgets by GtkBuilder.
|
||||
- Setting a drawing function of GtkDrawingArea.
|
||||
And connecting a handler to "resize" signal on GtkDrawingArea.
|
||||
- Implementing each call back functions.
|
||||
- Builds widgets by GtkBuilder.
|
||||
- Sets a drawing function for GtkDrawingArea.
|
||||
And connects a handler to the "resize" signal on the GtkDrawingArea instance.
|
||||
- Implements each call back function.
|
||||
Particularly, `Run` signal handler is the point in this program.
|
||||
|
||||
The following is `colorapplication.c`.
|
||||
|
@ -82,40 +128,26 @@ The following is `colorapplication.c`.
|
|||
color/colorapplication.c
|
||||
@@@
|
||||
|
||||
- 109-124: The function `main` is almost same as before but there are some differences.
|
||||
The application ID is "com.github.ToshioCP.color".
|
||||
`G_APPLICATION_FLAGS_NONE` is specified so no open signal handler is necessary.
|
||||
- 87-107: Startup handler.
|
||||
- 92-97: Builds widgets.
|
||||
The pointers of the top window, TfeTextView and GtkDrawingArea objects are stored to static variables `win`, `tv` and `da` respectively.
|
||||
This is because these objects are often used in handlers.
|
||||
They never be rewritten so they're thread safe.
|
||||
- 98: connects "resize" signal and the handler.
|
||||
- 99: sets the drawing function.
|
||||
- 82-85: Activate handler, which just shows the widgets.
|
||||
- 74-80: The drawing function.
|
||||
It just copies `surface` to destination.
|
||||
- 66-72: Resize handler.
|
||||
Re-creates the surface to fit its width and height for the drawing area and paints by calling the function `run`.
|
||||
- 59-64: Close handler.
|
||||
It destroys `surface` if it exists.
|
||||
Then it destroys the top-level window and quits the application.
|
||||
- 49-57: Open and save handler.
|
||||
They just call the corresponding functions of TfeTextView.
|
||||
- 43-47: Run handler.
|
||||
It calls run function to paint the surface.
|
||||
After that `gtk_widget_queue_draw` is called.
|
||||
This function adds the widget (GtkDrawingArea) to the queue to be redrawn.
|
||||
It is important to know that the window is redrawn whenever it is necessary.
|
||||
For example, when another window is moved and uncovers part of the widget, or when the window containing it is resized.
|
||||
But repainting `surface` is not automatically notified to gtk.
|
||||
Therefore, you need to call `gtk_widget_queue_draw` to redraw the widget.
|
||||
- 9-41: Run function paints the surface.
|
||||
First, it gets the contents of GtkTextBuffer.
|
||||
Then it compares it to "red", "green" and so on.
|
||||
If it matches the color, then the surface is painted the color.
|
||||
If it matches "light" or "dark", then the color of the surface is lightened or darkened respectively.
|
||||
Alpha channel is used.
|
||||
- 4-8: Win, tv, da and surface are defined as static variables.
|
||||
- 10-42: Run function.
|
||||
- 44-63: Handlers for button signals.
|
||||
- 65-71: Resize handler.
|
||||
- 73-79: Drawing function.
|
||||
- 81-84: Application activate handler.
|
||||
It just shows the main window.
|
||||
- 86-105: Application startup handler.
|
||||
- 92- 97: It builds widgets according to the ui resource.
|
||||
The static variables win, tv and da are assigned instances.
|
||||
- 98: Connects "resize" signal and a handler.
|
||||
- 99: Drawing function is set.
|
||||
- 101-104: CSS for textview padding is set.
|
||||
- 107-111: Application shutdown handler.
|
||||
If there exists a surface instance, it will be destroyed.
|
||||
- 116-129: A function `main`.
|
||||
It creates a new application instance.
|
||||
And connects three signals startup, shutdown and activate to their handlers.
|
||||
It runs the application.
|
||||
It releases the reference to the application and returns with `stat` value.
|
||||
|
||||
## Meson.build
|
||||
|
||||
|
@ -126,14 +158,9 @@ An argument "export_dynamic: true" is added to executable function.
|
|||
color/meson.build
|
||||
@@@
|
||||
|
||||
## Compile and execute it
|
||||
## Build and try
|
||||
|
||||
First you need to export some variables (refer to [Section 2](sec2.src.md)) if you've installed GTK 4 from the source.
|
||||
If you've installed GTK 4 from the distribution packages, you don't need to do this.
|
||||
|
||||
$ . env.sh
|
||||
|
||||
Then type the following to compile it.
|
||||
Type the following to compile the program.
|
||||
|
||||
$ meson _build
|
||||
$ ninja -C _build
|
||||
|
@ -144,7 +171,8 @@ Type the following to execute it.
|
|||
$ _build/color
|
||||
|
||||
Type "red", "green", "blue", "white", black", "light" or "dark" in the TfeTextView.
|
||||
Then, click on `Run` button.
|
||||
No new line charactor is needed.
|
||||
Then, click on the `Run` button.
|
||||
Make sure the color of GtkDrawingArea changes.
|
||||
|
||||
In this program TfeTextView is used to change the color.
|
||||
|
|
210
src/sec25.src.md
|
@ -1,41 +1,42 @@
|
|||
# Tiny turtle graphics interpreter
|
||||
|
||||
A program `turtle` is an example with the combination of TfeTextView and GtkDrawingArea objects.
|
||||
It is a very small interpreter but it provides a tool to draw fractal curves.
|
||||
The following diagram is a Koch curve, which is a famous example of fractal curves.
|
||||
It is a very small interpreter but you can draw fractal curves with it.
|
||||
The following diagram is a Koch curve, which is one of famous fractal curves.
|
||||
|
||||
![Koch curve](turtle/image/turtle_koch.png){width=8cm height=5.11cm}
|
||||
|
||||
The following is a snow-crystal-shaped curve.
|
||||
It is composed of six Koch curves.
|
||||
|
||||
![Snow](../image/turtle_snow.png){width=8cm height=5.11cm}
|
||||
|
||||
This program uses flex and bison.
|
||||
Flex is a lexical analyzer.
|
||||
Bison is a parser generator.
|
||||
These two programs are similar to lex and yacc which are proprietary software developed in Bell Laboratory.
|
||||
However, flex and bison are open source software.
|
||||
I will write about how to use those software, but they are not topics about gtk.
|
||||
So, readers can skip that part of this sections.
|
||||
I will write about how to use those software, but they are not topics about GTK 4.
|
||||
So, readers can skip this section.
|
||||
|
||||
## How to use turtle
|
||||
|
||||
@@@if gfm
|
||||
The documentation of turtle is [here](turtle/turtle_doc.src.md).
|
||||
The turtle document is [here](turtle/turtle_doc.src.md).
|
||||
@@@elif html
|
||||
The documentation of turtle is [here](turtle/turtle_doc.src.md).
|
||||
The turtle document is [here](https://toshiocp.github.io/Gtk4-tutorial/turtle_doc.html).
|
||||
@@@elif latex
|
||||
The documentation of turtle is in the appendix.
|
||||
The turtle document is in the appendix.
|
||||
@@@end
|
||||
I'll show you a simple example.
|
||||
|
||||
~~~
|
||||
fc (1,0,0) # Foreground color is red, rgb = (1,0,0).
|
||||
pd # Pen down.
|
||||
rp (4) { # Repeat four times.
|
||||
fd 100 # Go forward by 100 pixels.
|
||||
tr 90 # Turn right by 90 degrees.
|
||||
fd 100
|
||||
tr 90
|
||||
fd 100
|
||||
tr 90
|
||||
fd 100
|
||||
tr 90
|
||||
}
|
||||
~~~
|
||||
|
||||
1. Compile and install `turtle` (See the documentation above).
|
||||
|
@ -45,8 +46,8 @@ Then, run `turtle`.
|
|||
The side of the square is 100 pixels long.
|
||||
|
||||
In the same way, you can draw other curves.
|
||||
The documentation above shows some fractal curves such as tree, snow and square-koch.
|
||||
The source code in turtle language is located at [src/turtle/example](turtle/example) directory.
|
||||
The turtle document includes some fractal curves such as tree, snow and square-koch.
|
||||
The source codes are located at [src/turtle/example](turtle/example) directory.
|
||||
You can read these files into `turtle` editor by clicking on the `Open` button.
|
||||
|
||||
## Combination of TfeTextView and GtkDrawingArea objects
|
||||
|
@ -59,10 +60,9 @@ It is similar to `color` program in the previous section.
|
|||
3. The parser reads the program and generates tree-structured data.
|
||||
4. The interpriter reads the data and executes it step by step.
|
||||
And it draws shapes on a surface.
|
||||
The surface is different from the surface of the GtkDrawingArea widget.
|
||||
The surface isn't the one in the GtkDrawingArea widget.
|
||||
5. The widget is added to the queue.
|
||||
It will be redrawn with the drawing function.
|
||||
The function just copies the surface, which is drawn by the interpreter, into the surface of the GtkDrawingArea.
|
||||
It will be redrawn with the drawing function, which just copies the surface into the one in the GtkDrawingArea.
|
||||
|
||||
![Parser, interpreter and drawing function](../image/turtle.png)
|
||||
|
||||
|
@ -77,7 +77,7 @@ turtle/turtleapplication.c run_cb resize_cb
|
|||
- 8-13: The static value `busy` holds a status of the interpreter.
|
||||
If it is `TRUE`, the interpreter is running and it is not possible to call the interpreter again because it's not a re-entrant program.
|
||||
If it is `FALSE`, it is safe to call the interpreter.
|
||||
- 14: Now it is about to call the interpreter so it changes `busy` to TRUE.
|
||||
- 14: Changes `busy` to TRUE to avoid reentrance.
|
||||
- 15-16: Gets the contents of `tb`.
|
||||
- 17: The variable `surface` is a static variable.
|
||||
It points to a `cairo_surface_t` instance.
|
||||
|
@ -86,17 +86,17 @@ Therefore, `surface` isn't NULL usually.
|
|||
But if it is NULL, the interpreter won't be called.
|
||||
- 18: Initializes lexical analyzer.
|
||||
- 19: Calls parser.
|
||||
Parser analyzes the program codes syntactically and generate a tree structured data.
|
||||
Parser analyzes the program codes syntactically and generates a tree structured data.
|
||||
- 20-22: If the parser successfully parsed, it calls `run` (runtime routine).
|
||||
- 23: finalizes the lexical analyzer.
|
||||
- 25: frees `contents`.
|
||||
- 26: Adds the drawing area widget to the queue to draw.
|
||||
- 27: The interpreter program has finished so `busy` is now changed to FALSE.
|
||||
- 29-34: A handler of "resized" signal.
|
||||
If `surface` isn't NULL, it destroys the old surface.
|
||||
Then it creates a new surface.
|
||||
- 30-37: A "resized" signal handler.
|
||||
If the `surface` isn't NULL, it is destroyed.
|
||||
A new surface is created.
|
||||
Its size is the same as the surface of the GtkDrawingArea instance.
|
||||
|
||||
Run\_cb is called to redraw the shape on the drawing area.
|
||||
|
||||
Other part of `turtleapplication.c` is almost same as the codes of `colorapplication.c` in the previous section.
|
||||
The codes of `turtleapplication.c` is in the [turtle directory](turtle).
|
||||
|
@ -185,7 +185,7 @@ The source files are:
|
|||
|
||||
- flex source file => `turtle.lex`
|
||||
- bison source file => `turtle.y`
|
||||
- C header file => `turtle.h`, `turtle_lex.h`
|
||||
- C header file => `turtle_lex.h`
|
||||
- C source file => `turtleapplication.c`
|
||||
- other files => `turtle.ui`, `turtle.gresources.xml` and `meson.build`
|
||||
|
||||
|
@ -195,12 +195,13 @@ The compilation process is a bit complicated.
|
|||
It also generates `resources.h`.
|
||||
2. bison compiles `turtle.y` to `turtle_parser.c` and generates `turtle_parser.h`
|
||||
3. flex compiles `turtle.lex` to `turtle_lex.c`.
|
||||
4. gcc compiles `application.c`, `resources.c`, `turtle_parser.c` and `turtle_lex.c` with `turtle.h`, `turtle_lex.h`, `resources.h` and `turtle_parser.h`.
|
||||
4. gcc compiles `application.c`, `resources.c`, `turtle_parser.c` and `turtle_lex.c` with `turtle_lex.h`, `resources.h` and `turtle_parser.h`.
|
||||
It generates an executable file `turtle`.
|
||||
|
||||
![compile process](../image/turtle_compile_process.png){width=12cm height=9cm}
|
||||
|
||||
Meson controls the process and the instruction is described in `meson.build`.
|
||||
Meson controls the process.
|
||||
The instruction is described in `meson.build`.
|
||||
|
||||
@@@include
|
||||
turtle/meson.build
|
||||
|
@ -213,15 +214,13 @@ This program uses trigonometric functions.
|
|||
They are defined in the math library, but the library is optional.
|
||||
So, it is necessary to include it by `#include <math.h>` and also link the library with the linker.
|
||||
- 6: Gets gtk4 library.
|
||||
- 8: Gets gnome module.
|
||||
Module is a system provided by meson.
|
||||
See [Meson build system website, GNUME module](https://mesonbuild.com/Gnome-module.html#gnome-module) for further information.
|
||||
- 8: Gets gnome module.See [Meson build system website -- GNUME module](https://mesonbuild.com/Gnome-module.html#gnome-module) for further information.
|
||||
- 9: Compiles ui file to C source file according to the XML file `turtle.gresource.xml`.
|
||||
- 11: Gets flex.
|
||||
- 12: Gets bison.
|
||||
- 13: Compiles `turtle.y` to `turtle_parser.c` and `turtle_parser.h` by bison.
|
||||
The function `custom_target` creates a custom top level target.
|
||||
See [Meson build system website, custom target](https://mesonbuild.com/Reference-manual.html#custom_target) for further information.
|
||||
See [Meson build system website -- custom target](https://mesonbuild.com/Reference-manual.html#custom_target) for further information.
|
||||
- 14: Compiles `turtle.lex` to `turtle_lex.c` by flex.
|
||||
- 16: Specifies C source files.
|
||||
- 18: Compiles C source files including generated files by glib-compile-resources, bison and flex.
|
||||
|
@ -268,17 +267,17 @@ They are definitions, rules and user code sections.
|
|||
|
||||
- 1-12: Lines between "%top{" and "}" are C source codes.
|
||||
They will be copied to the top of the generated C source file.
|
||||
- 2-3: The function `strlen`, in line 62, is defined in `string.h`
|
||||
The function `atof`, in line 37, is defined in `stdlib.h`.
|
||||
- 6-8: The current input position is pointed by `nline` and `ncolumn`.
|
||||
The function `get_location` (line 58-63) sets `yylloc`to point the start and end point of `yytext` in the buffer.
|
||||
- 2-3: The function `strlen`, in line 65, is defined in `string.h`
|
||||
The function `atof`, in line 40, is defined in `stdlib.h`.
|
||||
- 7-9: The current input position is pointed by `nline` and `ncolumn`.
|
||||
The function `get_location` (line 61-66) sets `yylloc`to point the start and end point of `yytext` in the buffer.
|
||||
This function is declared here so that it can be called before the function is defined.
|
||||
- 11: GSlist is used to keep allocated memories.
|
||||
- 14: This option (`%option noyywrap`) must be specified when you have only single source file to the scanner. Refer to "9 The Generated Scanner" in the flex documentation in your distribution for further information.
|
||||
- 12: GSlist is used to keep allocated memories.
|
||||
- 15: This option (`%option noyywrap`) must be specified when you have only single source file to the scanner. Refer to "9 The Generated Scanner" in the flex documentation in your distribution for further information.
|
||||
(The documentation is not on the internet.)
|
||||
- 16-17: `REAL_NUMBER` and `IDENTIFIER` are names.
|
||||
- 17-18: `REAL_NUMBER` and `IDENTIFIER` are names.
|
||||
A name begins with a letter or an underscore followed by zero or more letters, digits, underscores (`_`) or dashes (`-`).
|
||||
They are followed by regular expressions which are their definition.
|
||||
They are followed by regular expressions which are their definitions.
|
||||
They will be used in rules section and will expand to the definition.
|
||||
You can leave out such definitions here and use regular expressions in rules section directly.
|
||||
|
||||
|
@ -290,64 +289,66 @@ The patterns are regular expressions or names surrounded by braces.
|
|||
The names must be defined in the definitions section.
|
||||
The definition of the regular expression is written in the flex documentation.
|
||||
|
||||
For example, line 37 is a rule.
|
||||
For example, line 40 is a rule.
|
||||
|
||||
- `{REAL_NUMBER}` is a pattern
|
||||
- `get_location (yytext); yylval.NUM = atof (yytext); return NUM;` is an action.
|
||||
|
||||
`{REAL_NUMBER}` is defined in the 16th line, so it expands to `(0|[1-9][0-9]*)(\.[0-9]+)?`.
|
||||
`{REAL_NUMBER}` is defined in the line 17, so it expands to `(0|[1-9][0-9]*)(\.[0-9]+)?`.
|
||||
This regular expression matches numbers like `0`, `12` and `1.5`.
|
||||
If the input is a number, it matches the pattern in line 37.
|
||||
If an input is a number, it matches the pattern in line 40.
|
||||
Then the matched text is assigned to `yytext` and corresponding action is executed.
|
||||
A function `get_location` changes the location variables.
|
||||
A function `get_location` changes the location variables to the position at the text.
|
||||
It assigns `atof (yytext)`, which is double sized number converted from `yytext`, to `yylval.NUM` and return `NUM`.
|
||||
`NUM` is an integer defined by `turtle.y`.
|
||||
`NUM` is a token kind and it represents integer.
|
||||
It is defined in `turtle.y`.
|
||||
|
||||
The scanner generated by flex and C compiler has `yylex` function.
|
||||
The scanner generated by flex has `yylex` function.
|
||||
If `yylex` is called and the input is "123.4", then it works as follows.
|
||||
|
||||
1. A string "123.4" matches `{REAL_NUMBER}`.
|
||||
2. Update the location variable `ncolumn` and `yylloc`with `get_location`.
|
||||
3. `atof` converts the string "123.4" to double type number 123.4.
|
||||
3. The function `atof` converts the string "123.4" to double type number 123.4.
|
||||
4. It is assigned to `yylval.NUM`.
|
||||
5. `yylex` returns `NUM` to the caller.
|
||||
|
||||
Then the caller knows the input is `NUM` (number), and its value is 123.4.
|
||||
Then the caller knows the input is a number (`NUM`), and its value is 123.4.
|
||||
|
||||
- 19-55: Rules section.
|
||||
- 20: The symbol `.` (dot) matches any character except newline.
|
||||
- 20-58: Rules section.
|
||||
- 21: The symbol `.` (dot) matches any character except newline.
|
||||
Therefore, a comment begins `#` followed by any characters except newline.
|
||||
No action happens.
|
||||
- 21: White space just increases a variable `ncolumn` by one.
|
||||
- 22: Tab is assumed to be equal to eight spaces.
|
||||
- 23: New line increases a variable `nline` by one and resets `ncolumn`.
|
||||
- 25-35: Keywords just updates the location variables `ncolumn` and `yylloc`, and return the codes of the keywords.
|
||||
- 37: Real number constant.
|
||||
- 38: `IDENTIFIER` is defined in line 17.
|
||||
- 22: White space just increases the variable `ncolumn` by one.
|
||||
- 23: Tab is assumed to be equal to eight spaces.
|
||||
- 24: New line increases a variable `nline` by one and resets `ncolumn`.
|
||||
- 26-38: Keywords just updates the location variables `ncolumn` and `yylloc`, and return the token kinds of the keywords.
|
||||
- 40: Real number constant.
|
||||
- 42: `IDENTIFIER` is defined in line 18.
|
||||
The location variables are updated and the name of the identifier is assigned to `yylval.ID`.
|
||||
The memory of the name is allocated by the function `g_strdup`.
|
||||
The memory is registered to the list (GSlist type list).
|
||||
The memory will be freed after the runtime routine finishes.
|
||||
Returns `ID`.
|
||||
- 43-54: Symbols just update the location variable and return the codes.
|
||||
The code is the same as the symbol itself.
|
||||
- 55: If the input doesn't match above patterns, then it is error.
|
||||
Returns `YYUNDEF`.
|
||||
A token kind `ID` is returned.
|
||||
- 46-56: Symbols just update the location variable and return the token kinds.
|
||||
The token kind is the same as the symbol itself.
|
||||
- 58: If the input doesn't match the patterns, then it is an error.
|
||||
A special token kind `YYUNDEF` is returned.
|
||||
|
||||
### User code section
|
||||
|
||||
This section is just copied to C source file.
|
||||
|
||||
- 58-63: A function `get_location`.
|
||||
- 61-66: A function `get_location`.
|
||||
The location of the input is recorded to `nline` and `ncolumn`.
|
||||
A variable `yylloc` is referred by the parser.
|
||||
It is a C structure and has four members, `first_line`, `first_column`, `last_line` and `last_column`.
|
||||
They point the start and end of the current input text.
|
||||
- 65: `YY_BUFFER_STATE` is a pointer points the input buffer.
|
||||
- 67-70: `init_flex` is called by `run_cb` signal handler, which is called when `Run` button is clicked on.
|
||||
`run_cb` calls `init_flex` with one argument which is the copy of the content of GtkTextBuffer.
|
||||
`yy_scan_string` sets the input buffer to read from the text.
|
||||
- 72-75: `finalize_flex` is called after runtime routine finishes.
|
||||
- 68: `YY_BUFFER_STATE` is a pointer points the input buffer.
|
||||
- 70-73: A function `init_flex` is called by `run_cb` which is a "clicked" signal handler on the `Run` button.
|
||||
It has one string type parameter.
|
||||
The caller assigns it with the content of the GtkTextBuffer instance.
|
||||
A function `yy_scan_string` sets the input buffer for the scanner.
|
||||
- 75-78: A function `finalize_flex` is called after runtime routine finishes.
|
||||
It deletes the input buffer.
|
||||
|
||||
## Turtle.y
|
||||
|
@ -357,8 +358,8 @@ So I will explain the key points and leave out other less important parts.
|
|||
|
||||
### What does bison do?
|
||||
|
||||
Bison creates C source file from bison source file.
|
||||
Bison source file is a text file.
|
||||
Bison creates C source file of a parser from a bison source file.
|
||||
The bison source file is a text file.
|
||||
A parser analyzes a program source code according to its grammar.
|
||||
Suppose here is a turtle source file.
|
||||
|
||||
|
@ -399,7 +400,7 @@ So, the parser gets items in the following table whenever it calls `yylex`.
|
|||
|
||||
Bison source code specifies the grammar rules of turtle language.
|
||||
For example, `fc (1,0,0)` is called primary procedure.
|
||||
A procedure is like a void type function in C source code.
|
||||
A procedure is like a void type C function.
|
||||
It doesn't return any values.
|
||||
Programmers can define their own procedures.
|
||||
On the other hand, `fc` is a built-in procedure.
|
||||
|
@ -417,7 +418,8 @@ This means:
|
|||
- expression is ID or NUM.
|
||||
|
||||
The description above is called BNF (Backus-Naur form).
|
||||
More precisely, it is similar to BNF.
|
||||
Precisely speaking, it is not exactly the same as BNF.
|
||||
But the difference is small.
|
||||
|
||||
The first line is:
|
||||
|
||||
|
@ -427,7 +429,7 @@ FC '(' NUM ',' NUM ',' NUM ')';
|
|||
|
||||
The parser analyzes the turtle source code and if the input matches the definition above, the parser recognizes it as a primary procedure.
|
||||
|
||||
The grammar of turtle is described in the [document](turtle/turtle_doc.src.md).
|
||||
The grammar of turtle is described in the [Turtle manual](https://toshiocp.github.io/Gtk4-tutorial/turtle_doc.html).
|
||||
The following is an extract from the document.
|
||||
|
||||
~~~
|
||||
|
@ -447,12 +449,14 @@ primary_procedure:
|
|||
| PW expression
|
||||
| FD expression
|
||||
| TR expression
|
||||
| TL expression
|
||||
| BC '(' expression ',' expression ',' expression ')'
|
||||
| FC '(' expression ',' expression ',' expression ')'
|
||||
| ID '=' expression
|
||||
| IF '(' expression ')' '{' primary_procedure_list '}'
|
||||
| RT
|
||||
| RS
|
||||
| RP '(' expression ')' '{' primary_procedure_list '}'
|
||||
| ID '(' ')'
|
||||
| ID '(' argument_list ')'
|
||||
;
|
||||
|
@ -499,12 +503,12 @@ The grammar rule defines `program` first.
|
|||
The definition is recursive.
|
||||
|
||||
- `statement` is program.
|
||||
- `statement statement` is `program statemet`.
|
||||
- `statement statement` is `program statement`.
|
||||
Therefore, it is program.
|
||||
- `statement statement statement` is `program statemet`.
|
||||
- `statement statement statement` is `program statement`.
|
||||
Therefore, it is program.
|
||||
|
||||
You can find that a list of statements is program like this.
|
||||
You can find that a sequence of statements is program like this.
|
||||
|
||||
`program` and `statement` aren't tokens.
|
||||
They don't appear in the input.
|
||||
|
@ -606,7 +610,17 @@ The following is an extract from `turtle.y`.
|
|||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
#include <math.h>
|
||||
#include "turtle.h"
|
||||
#include <glib.h>
|
||||
#include <cairo.h>
|
||||
#include "turtle_parser.h"
|
||||
|
||||
/* The following line defines 'debug' so that debug information is printed out during the run time. */
|
||||
/* However it makes the program slow. */
|
||||
/* If you want to debug on, uncomment the line. */
|
||||
|
||||
/* #define debug 1 */
|
||||
|
||||
extern cairo_surface_t *surface;
|
||||
|
||||
/* error reporting */
|
||||
static void yyerror (char const *s) { /* for syntax error */
|
||||
|
@ -657,7 +671,7 @@ The header file is read by the scanner C source file and other files.
|
|||
}
|
||||
~~~
|
||||
|
||||
- `yylex` is shared by parser implementation file and scanner file.
|
||||
- `yylex` is shared by the parser implementation file and scanner file.
|
||||
- `yyparse` and `run` is called by `run_cb` in `turtleapplication.c`.
|
||||
- `node_t` is the type of the semantic value of nterms.
|
||||
The header file defines `YYSTYPE`, which is the semantic value type, with all the token and nterm value types.
|
||||
|
@ -715,12 +729,14 @@ It also specifies some directives.
|
|||
%token PW
|
||||
%token FD
|
||||
%token TR
|
||||
%token TL
|
||||
%token BC
|
||||
%token FC
|
||||
%token DP
|
||||
%token IF
|
||||
%token RT
|
||||
%token RS
|
||||
%token RP
|
||||
/* constant */
|
||||
%token <double> NUM
|
||||
/* identirier */
|
||||
|
@ -839,8 +855,9 @@ Be careful.
|
|||
The operator `=` above is an assignment.
|
||||
Assignment is not expression in turtle language.
|
||||
It is primary_procedure.
|
||||
But if `=` appears in an expression, it is a logical operater, not an assignment.
|
||||
But if `=` appears in an expression, it is a logical operator, not an assignment.
|
||||
The logical equal '`=`' usually used in the conditional expression, for example, in `if` statement.
|
||||
(Turtle language uses '=' instead of '==' in C language).
|
||||
|
||||
### Grammar rules
|
||||
|
||||
|
@ -873,22 +890,22 @@ expression:
|
|||
;
|
||||
~~~
|
||||
|
||||
- `program` is `statement`.
|
||||
- The first two lines tell that `program` is `statement`.
|
||||
- Whenever `statement` is reduced to `program`, an action `node_top=$$=$1;` is executed.
|
||||
- `node_top` is a static variable.
|
||||
It points the top node of the tree.
|
||||
- `$$` is a semantic value of the result, which is `program` in the second line of the example above.
|
||||
The semantic value of `program` is a pointer to `node_t` type structure.
|
||||
It was defined in the declaration section.
|
||||
- `$1` is a semantic value of the first component, which is `statement`.
|
||||
The semantic value of `statement` is also a pointer to `node_t`.
|
||||
- `statement` is `primary_procedure`.
|
||||
- A symbol `$$` is a semantic value of the result.
|
||||
For example, `$$` in line 2 is the semantic value of `program`.
|
||||
It is a pointer to a `node_t` type structure.
|
||||
- `$1` is a semantic value of the first component.
|
||||
For example, `$1` in line 2 is the semantic value of `statement`.
|
||||
It is also a pointer to `node_t`.
|
||||
- The next rule is that `statement` is `primary_procedure`.
|
||||
There's no action specified.
|
||||
Then, the default action is executed.
|
||||
It is ` $$ = $1`.
|
||||
- `primary_procedure` is `FD` followed by expression.
|
||||
Then, the default action `$$ = $1` is executed.
|
||||
- The next rule is that `primary_procedure` is `FD` followed by expression.
|
||||
The action calls `tree1` and assigns its return value to `$$`.
|
||||
`tree1` makes a tree node.
|
||||
The function `tree1` makes a tree node.
|
||||
The tree node has type and union of three pointers to children nodes, string or double.
|
||||
~~~
|
||||
node --+-- type
|
||||
|
@ -898,7 +915,7 @@ node --+-- type
|
|||
+---double value
|
||||
~~~
|
||||
- `tree1` assigns the four arguments to type, child1, child2 and child3 members.
|
||||
- `expression` is `NUM`.
|
||||
- The last rule is that `expression` is `NUM`.
|
||||
- `tree2` makes a tree node. The paremeters of `tree2` are a type and a semantic value.
|
||||
|
||||
Suppose the parser reads the following program.
|
||||
|
@ -957,6 +974,7 @@ primary_procedure:
|
|||
| PW expression { $$ = tree1 (N_PW, $2, NULL, NULL); }
|
||||
| FD expression { $$ = tree1 (N_FD, $2, NULL, NULL); }
|
||||
| TR expression { $$ = tree1 (N_TR, $2, NULL, NULL); }
|
||||
| TL expression { $$ = tree1 (N_TL, $2, NULL, NULL); } /* ver 0.5 */
|
||||
| BC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_BC, $3, $5, $7); }
|
||||
| FC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_FC, $3, $5, $7); }
|
||||
/* assignment */
|
||||
|
@ -965,6 +983,7 @@ primary_procedure:
|
|||
| IF '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_IF, $3, $6, NULL); }
|
||||
| RT { $$ = tree1 (N_RT, NULL, NULL, NULL); }
|
||||
| RS { $$ = tree1 (N_RS, NULL, NULL, NULL); }
|
||||
| RP '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_RP, $3, $6, NULL); }
|
||||
/* user defined procedure call */
|
||||
| ID '(' ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), NULL, NULL); }
|
||||
| ID '(' argument_list ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), $3, NULL); }
|
||||
|
@ -1114,7 +1133,7 @@ init_table (void) {
|
|||
~~~
|
||||
|
||||
`init_table` initializes the table.
|
||||
This must be called before any registrations.
|
||||
This must be called before registrations.
|
||||
|
||||
There are five functions to access the table,
|
||||
|
||||
|
@ -1242,8 +1261,8 @@ The runtime routine stores the name `drawline` and the node of the procedure to
|
|||
- The second line calls the procedure.
|
||||
First, it looks for the procedure in the symbol table and gets its node.
|
||||
Then it searches the node for the parameters and gets `angle` and `distance`.
|
||||
- It pushes ("distance", 100.0) to the stack.
|
||||
- It pushes ("angle", 90.0) to the stack.
|
||||
- It pushes ("distance", 100.0) to the stack.
|
||||
- It pushes (NULL, 2.0) to the stack.
|
||||
The number 2.0 is the number of parameters (or arguments).
|
||||
It is used when the procedure returns.
|
||||
|
@ -1251,8 +1270,11 @@ It is used when the procedure returns.
|
|||
The following diagram shows the structure of the stack.
|
||||
First, `procedure 1` is called.
|
||||
The procedure has two parameters.
|
||||
In the `procedure 1`, another procedure `procedure 2`, which has one parameter, is called.
|
||||
And in the `procedure 2`, `procedure 3`, which has three parameters, is called.
|
||||
In the `procedure 1`, another procedure `procedure 2` is called.
|
||||
It has one parameter.
|
||||
In the `procedure 2`, another procedure `procedure 3` is called.
|
||||
It has three parameters.
|
||||
These three procedures are nested.
|
||||
|
||||
Programs push data to a stack from a low address memory to a high address memory.
|
||||
In the following diagram, the lowest address is at the top and the highest address is at the bottom.
|
||||
|
@ -1843,4 +1865,4 @@ However, the following information is very useful (but old).
|
|||
- Source code of a language, for example, ruby.
|
||||
|
||||
Lately, lots of source codes are in the internet.
|
||||
Maybe reading source codes are the most useful for programmers.
|
||||
Maybe reading source codes is the most useful for programmers.
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
dp sq (side) {
|
||||
fd side
|
||||
tr 90
|
||||
fd side
|
||||
tr 90
|
||||
fd side
|
||||
tr 90
|
||||
rp (4) {
|
||||
fd side
|
||||
tr 90
|
||||
}
|
||||
}
|
||||
|
||||
sq (100)
|
BIN
src/turtle/image/turtle_snow.png
Normal file
After Width: | Height: | Size: 83 KiB |
|
@ -1,13 +0,0 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
#include "../tfetextview/tfetextview.h"
|
||||
#include "turtle_lex.h"
|
||||
#include "turtle_parser.h"
|
||||
|
||||
/* The following line defines 'debug' so that debug information is printed during the run time. */
|
||||
/* However it makes the program slow. */
|
||||
/* If you don't want to see such information, remove the line. */
|
||||
/*#define debug 1*/
|
||||
|
||||
extern cairo_surface_t *surface;
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
%top{
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "turtle.h"
|
||||
#include <glib.h>
|
||||
#include "turtle_parser.h"
|
||||
|
||||
static int nline = 1;
|
||||
static int ncolumn = 1;
|
||||
|
@ -27,12 +28,14 @@ pd get_location (yytext); return PD; /* pen down */
|
|||
pw get_location (yytext); return PW; /* pen width = line width */
|
||||
fd get_location (yytext); return FD; /* forward */
|
||||
tr get_location (yytext); return TR; /* turn right */
|
||||
tl get_location (yytext); return TL; /* turn left ver 0.5 */
|
||||
bc get_location (yytext); return BC; /* background color */
|
||||
fc get_location (yytext); return FC; /* foreground color */
|
||||
dp get_location (yytext); return DP; /* define procedure */
|
||||
if get_location (yytext); return IF; /* if statement */
|
||||
rt get_location (yytext); return RT; /* return statement */
|
||||
rs get_location (yytext); return RS; /* reset the status */
|
||||
rp get_location (yytext); return RP; /* repeat ver 0.5 */
|
||||
/* constant */
|
||||
{REAL_NUMBER} get_location (yytext); yylval.NUM = atof (yytext); return NUM;
|
||||
/* identifier */
|
||||
|
@ -73,4 +76,3 @@ void
|
|||
finalize_flex (void) {
|
||||
yy_delete_buffer (state);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,17 @@
|
|||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
#include <math.h>
|
||||
#include "turtle.h"
|
||||
#include <glib.h>
|
||||
#include <cairo.h>
|
||||
#include "turtle_parser.h"
|
||||
|
||||
/* The following line defines 'debug' so that debug information is printed out during the run time. */
|
||||
/* However it makes the program slow. */
|
||||
/* If you want to debug on, uncomment the line. */
|
||||
|
||||
/* #define debug 1 */
|
||||
|
||||
extern cairo_surface_t *surface;
|
||||
|
||||
/* error reporting */
|
||||
static void yyerror (char const *s) { /* for syntax error */
|
||||
|
@ -25,6 +35,7 @@
|
|||
N_PW,
|
||||
N_FD,
|
||||
N_TR,
|
||||
N_TL, /* Turn Left version 0.5 */
|
||||
N_BC,
|
||||
N_FC,
|
||||
N_DP,
|
||||
|
@ -32,6 +43,7 @@
|
|||
N_IF,
|
||||
N_RT,
|
||||
N_RS,
|
||||
N_RP, /* Repeat version 0.5 */
|
||||
N_NUM,
|
||||
N_ID,
|
||||
N_program,
|
||||
|
@ -59,6 +71,7 @@
|
|||
"N_PW",
|
||||
"N_FD",
|
||||
"N_TR",
|
||||
"N_TL", /* ver o.5 */
|
||||
"N_BC",
|
||||
"N_FC",
|
||||
"N_DP",
|
||||
|
@ -66,6 +79,7 @@
|
|||
"N_IF",
|
||||
"N_RT",
|
||||
"N_RS",
|
||||
"N_RP", /* ver 0.5 */
|
||||
"N_NUM",
|
||||
"N_ID",
|
||||
"N_program",
|
||||
|
@ -132,12 +146,14 @@
|
|||
%token PW
|
||||
%token FD
|
||||
%token TR
|
||||
%token TL /* ver 0.5 */
|
||||
%token BC
|
||||
%token FC
|
||||
%token DP
|
||||
%token IF
|
||||
%token RT
|
||||
%token RS
|
||||
%token RP /* ver 0.5 */
|
||||
/* constant */
|
||||
%token <double> NUM
|
||||
/* identirier */
|
||||
|
@ -180,6 +196,7 @@ primary_procedure:
|
|||
| PW expression { $$ = tree1 (N_PW, $2, NULL, NULL); }
|
||||
| FD expression { $$ = tree1 (N_FD, $2, NULL, NULL); }
|
||||
| TR expression { $$ = tree1 (N_TR, $2, NULL, NULL); }
|
||||
| TL expression { $$ = tree1 (N_TL, $2, NULL, NULL); } /* ver 0.5 */
|
||||
| BC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_BC, $3, $5, $7); }
|
||||
| FC '(' expression ',' expression ',' expression ')' { $$ = tree1 (N_FC, $3, $5, $7); }
|
||||
/* assignment */
|
||||
|
@ -188,6 +205,7 @@ primary_procedure:
|
|||
| IF '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_IF, $3, $6, NULL); }
|
||||
| RT { $$ = tree1 (N_RT, NULL, NULL, NULL); }
|
||||
| RS { $$ = tree1 (N_RS, NULL, NULL, NULL); }
|
||||
| RP '(' expression ')' '{' primary_procedure_list '}' { $$ = tree1 (N_RP, $3, $6, NULL); }
|
||||
/* user defined procedure call */
|
||||
| ID '(' ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), NULL, NULL); }
|
||||
| ID '(' argument_list ')' { $$ = tree1 (N_procedure_call, tree3 (N_ID, $1), $3, NULL); }
|
||||
|
@ -614,6 +632,7 @@ execute (node_t *node) {
|
|||
double d, x, y;
|
||||
char *name;
|
||||
int n, i;
|
||||
int counter; /* ver 0.5, for repeat procedure */
|
||||
|
||||
if (node == NULL)
|
||||
runtime_error ("Node is NULL.\n");
|
||||
|
@ -677,6 +696,11 @@ g_print ("fd: New Y coordinate is %f.\n", cur_y);
|
|||
for (; angle < 0; angle += 360.0);
|
||||
for (; angle>360; angle -= 360.0);
|
||||
break;
|
||||
case N_TL: /* ver 0.5 */
|
||||
angle += eval (child1(node));
|
||||
for (; angle < 0; angle += 360.0);
|
||||
for (; angle>360; angle -= 360.0);
|
||||
break;
|
||||
case N_BC:
|
||||
bc.red = eval (child1(node));
|
||||
bc.green = eval (child2(node));
|
||||
|
@ -722,6 +746,15 @@ g_print ("fc: Foreground color is (%f, %f, %f).\n", fc.red, fc.green, fc.blue);
|
|||
fc.red = 0.0; fc.green = 0.0; fc.blue = 0.0;
|
||||
/* To change background color, use bc. */
|
||||
break;
|
||||
case N_RP: /* ver 0.5 */
|
||||
counter = (int) eval (child1(node));
|
||||
if (counter < 0)
|
||||
runtime_error ("Repeat number %d is negative.\n", counter);
|
||||
if (counter > 100)
|
||||
runtime_error ("Repeat number %d is too big.\n", counter);
|
||||
for (i=0; i<counter; ++i)
|
||||
execute (child2(node));
|
||||
break;
|
||||
case N_procedure_call:
|
||||
name = name(child1(node));
|
||||
node_t *proc = proc_lookup (name);
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#include "turtle.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include "../tfetextview/tfetextview.h"
|
||||
#include "turtle_lex.h"
|
||||
#include "turtle_parser.h"
|
||||
|
||||
static GtkWidget *win;
|
||||
static GtkWidget *tv;
|
||||
|
@ -13,10 +16,10 @@ run_cb (GtkWidget *btnr) {
|
|||
GtkTextIter end_iter;
|
||||
char *contents;
|
||||
int stat;
|
||||
static gboolean busy = FALSE;
|
||||
static gboolean busy = FALSE; /* initialized only once */
|
||||
|
||||
/* yyparse() and run() are NOT thread safe. */
|
||||
/* The variable busy avoids reentry. */
|
||||
/* The variable busy avoids reentrance. */
|
||||
if (busy)
|
||||
return;
|
||||
busy = TRUE;
|
||||
|
@ -79,9 +82,11 @@ show_filename (TfeTextView *tv) {
|
|||
|
||||
static void
|
||||
resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
|
||||
if (surface)
|
||||
cairo_surface_destroy (surface);
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
run_cb (NULL); // NULL is a fake (run button).
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -128,7 +133,7 @@ main (int argc, char **argv) {
|
|||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
|
||||
app = gtk_application_new (APPLICATION_ID, G_APPLICATION_DEFAULT_FLAGS);
|
||||
|
||||
g_signal_connect (app, "startup", G_CALLBACK (app_startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
|
||||
|
@ -137,4 +142,3 @@ main (int argc, char **argv) {
|
|||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
||||
|
||||
|
|
1
src/turtle/version.txt
Normal file
|
@ -0,0 +1 @@
|
|||
0.5
|