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