mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-12 20:03:28 +01:00
Update section 29-33.
This commit is contained in:
parent
bda0f28ad3
commit
3ada90257e
26 changed files with 1323 additions and 1604 deletions
|
@ -10,7 +10,8 @@ The table of contents is at the end of this abstract.
|
|||
|
||||
- Section 3 to 23 describes the basics, with the example of a simple editor `tfe` (Text File Editor).
|
||||
- Section 24 to 27 describes GtkDrawingArea.
|
||||
- Section 28 to 32 describes the list model and the list view (GtkListView, GtkGridView and GtkColumnView).
|
||||
- Section 28 describes Drag and Drop.
|
||||
- Section 29 to 33 describes the list model and the list view (GtkListView, GtkGridView and GtkColumnView).
|
||||
It also describes GtkExpression.
|
||||
|
||||
The latest version of the tutorial is located at [GTK4-tutorial GitHub repository](https://github.com/ToshioCP/Gtk4-tutorial).
|
||||
|
|
|
@ -111,7 +111,8 @@ basics. The table of contents is at the end of this abstract.</p>
|
|||
<li>Section 3 to 23 describes the basics, with the example of a simple
|
||||
editor <code>tfe</code> (Text File Editor).</li>
|
||||
<li>Section 24 to 27 describes GtkDrawingArea.</li>
|
||||
<li>Section 28 to 32 describes the list model and the list view
|
||||
<li>Section 28 describes Drag and Drop.</li>
|
||||
<li>Section 29 to 33 describes the list model and the list view
|
||||
(GtkListView, GtkGridView and GtkColumnView). It also describes
|
||||
GtkExpression.</li>
|
||||
</ul>
|
||||
|
|
|
@ -120,16 +120,17 @@ Reference – List Widget Overview</a>.</p>
|
|||
GtkTreeView which are took over from GTK 3. There’s an article in <a
|
||||
href="https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/">Gtk
|
||||
Development blog</a> about list widgets by Matthias Clasen. He described
|
||||
why GtkListView are developed to replace GtkListBox and GtkTreeView.</p>
|
||||
why GtkListView are developed to replace GtkTreeView. GtkTreeView is
|
||||
deprecated since version 4.10.</p>
|
||||
<p>GtkListView, GtkGridView, GtkColumnView and related objects are
|
||||
described in Section 26 to 29.</p>
|
||||
described in Section 29 to 33.</p>
|
||||
<h2 id="outline">Outline</h2>
|
||||
<p>A list is a sequential data structure. For example, an ordered string
|
||||
sequence “one”, “two”, “three”, “four” is a list. Each element is called
|
||||
item. A list is like an array, but in many cases it is implemented with
|
||||
pointers which point to the next items of the list. And it has a start
|
||||
point. So, each item can be referred by the index of the item (first
|
||||
item, second item, …, nth item, …). There are two cases. One is the
|
||||
item, second item, …, nth item, …). There are two cases. The one is the
|
||||
index starts from one (one-based) and the other is from zero
|
||||
(zero-based).</p>
|
||||
<p>Gio provides GListModel interface. It is a zero-based list and its
|
||||
|
@ -138,12 +139,12 @@ implement the same interface. An object implements GListModel is not a
|
|||
widget. So, the list is not displayed on the screen directly. There’s
|
||||
another object GtkListView which is a widget to display the list. The
|
||||
items in the list need to be connected to the items in GtkListView.
|
||||
GtkListItemFactory instance maps items in the list to GListView.</p>
|
||||
GtkListItemFactory instance maps items in the list to GtkListView.</p>
|
||||
<figure>
|
||||
<img src="image/list.png" alt="List" />
|
||||
<figcaption aria-hidden="true">List</figcaption>
|
||||
</figure>
|
||||
<h2 id="glistmodel">GListModel</h2>
|
||||
<h2 id="glistmodel-and-gtkstringlist">GListModel and GtkStringList</h2>
|
||||
<p>If you want to make a list of strings with GListModel, for example,
|
||||
“one”, “two”, “three”, “four”, note that strings can’t be items of the
|
||||
list. Because GListModel is a list of GObject objects and strings aren’t
|
||||
|
@ -356,7 +357,7 @@ instantiated.</p>
|
|||
</blockquote>
|
||||
<p>Therefore, GtkListItem instance is used as the <code>this</code>
|
||||
object of the lookup tag when it is evaluated. <code>this</code> object
|
||||
will be explained in section 30.</p>
|
||||
will be explained in section 31.</p>
|
||||
<p>The C source code is as follows. Its name is <code>list2.c</code> and
|
||||
located under src/misc directory.</p>
|
||||
<div class="sourceCode" id="cb7"><pre
|
||||
|
@ -431,7 +432,7 @@ are information of files under a certain directory. It uses
|
|||
<code>g_file_enumerate_children_async()</code> to get the GFileInfo
|
||||
objects. The list model is created by
|
||||
<code>gtk_directory_list_new</code> function.</p>
|
||||
<div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>GtkDirectoryList <span class="op">*</span>gtk_directory_list_new <span class="op">(</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>attributes<span class="op">,</span> GFile <span class="op">*</span>file<span class="op">);</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb8"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>GtkDirectoryList <span class="op">*</span>gtk_directory_list_new <span class="op">(</span><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>attributes<span class="op">,</span> GFile <span class="op">*</span>file<span class="op">);</span></span></code></pre></div>
|
||||
<p><code>attributes</code> is a comma separated list of file attributes.
|
||||
File attributes are key-value pairs. A key consists of a namespace and a
|
||||
name. For example, “standard::name” key is the name of a file.
|
||||
|
@ -477,7 +478,7 @@ seconds since the UNIX epoch</td>
|
|||
<p>The current directory is “.”. The following program makes
|
||||
GtkDirectoryList <code>dl</code> and its contents are GFileInfo objects
|
||||
under the current directory.</p>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>GFile <span class="op">*</span>file <span class="op">=</span> g_file_new_for_path <span class="op">(</span><span class="st">"."</span><span class="op">);</span></span>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>GFile <span class="op">*</span>file <span class="op">=</span> g_file_new_for_path <span class="op">(</span><span class="st">"."</span><span class="op">);</span></span>
|
||||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>GtkDirectoryList <span class="op">*</span>dl <span class="op">=</span> gtk_directory_list_new <span class="op">(</span><span class="st">"standard::name"</span><span class="op">,</span> file<span class="op">);</span></span>
|
||||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>g_object_unref <span class="op">(</span>file<span class="op">);</span></span></code></pre></div>
|
||||
<p>It is not so difficult to make file listing program by changing
|
||||
|
@ -486,7 +487,7 @@ GInfoFile doesn’t have properties. Lookup tag look for a property, so it
|
|||
is useless for looking for a filename from a GFileInfo object. Instead,
|
||||
closure tag is appropriate in this case. Closure tag specifies a
|
||||
function and the type of the return value of the function.</p>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span></span>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span> <span class="op">*</span></span>
|
||||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>get_file_name <span class="op">(</span>GtkListItem <span class="op">*</span>item<span class="op">,</span> GFileInfo <span class="op">*</span>info<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> G_IS_FILE_INFO <span class="op">(</span>info<span class="op">)</span> <span class="op">?</span> g_strdup <span class="op">(</span>g_file_info_get_name <span class="op">(</span>info<span class="op">))</span> <span class="op">:</span> NULL<span class="op">;</span></span>
|
||||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
|
||||
|
@ -526,7 +527,7 @@ the function.
|
|||
the value of the item property of the GtkListItem. This will be the
|
||||
second argument of the function. The first parameter is always the
|
||||
GListItem instance, which is a ‘this’ object. The ‘this’ object is
|
||||
explained in section 28.</li>
|
||||
explained in section 31.</li>
|
||||
<li><code>gtk_file_name</code> function is the callback function for the
|
||||
closure tag. It first checks the <code>info</code> parameter. Because it
|
||||
can be NULL when GListItem <code>item</code> is unbounded. If it’s
|
||||
|
|
|
@ -173,8 +173,7 @@ registered to IANA media types. Such “x-” subtype is not a standard mime
|
|||
type.) Content type is also used by desktop systems.</li>
|
||||
</ul>
|
||||
<p>GtkGridView uses the same GtkSingleSelection instance
|
||||
(<code>singleselection</code>). So, its model property is set with
|
||||
it.</p>
|
||||
(<code>singleselection</code>). So, its model property is set to it.</p>
|
||||
<h2 id="ui-file-of-the-window">Ui file of the window</h2>
|
||||
<p>The window is built with the following ui file. (See the screenshot
|
||||
at the beginning of this section).</p>
|
||||
|
@ -291,7 +290,7 @@ GtkListView or GtkGridView.</li>
|
|||
</ul>
|
||||
<p>The action <code>view</code> is created, connected to the “activate”
|
||||
signal handler and inserted to the window (action map) as follows.</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>act_view <span class="op">=</span> g_simple_action_new_stateful <span class="op">(</span><span class="st">"view"</span><span class="op">,</span> g_variant_type_new<span class="op">(</span><span class="st">"s"</span><span class="op">),</span> g_variant_new_string <span class="op">(</span><span class="st">"list"</span><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>act_view <span class="op">=</span> g_simple_action_new_stateful <span class="op">(</span><span class="st">"view"</span><span class="op">,</span> g_variant_type_new<span class="op">(</span><span class="st">"s"</span><span class="op">),</span> g_variant_new_string <span class="op">(</span><span class="st">"list"</span><span class="op">));</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>g_signal_connect <span class="op">(</span>act_view<span class="op">,</span> <span class="st">"activate"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>view_activated<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>g_action_map_add_action <span class="op">(</span>G_ACTION_MAP <span class="op">(</span>win<span class="op">),</span> G_ACTION <span class="op">(</span>act_view<span class="op">));</span></span></code></pre></div>
|
||||
<p>The signal handler <code>view_activated</code> will be explained
|
||||
|
@ -464,7 +463,7 @@ pressed. You can do anything you like by connecting the “activate”
|
|||
signal to the handler.</p>
|
||||
<p>The example <code>list4</code> launches <code>tfe</code> text file
|
||||
editor if the item of the list is a text file.</p>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<div class="sourceCode" id="cb10"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>list_activate <span class="op">(</span>GtkListView <span class="op">*</span>list<span class="op">,</span> <span class="dt">int</span> position<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> GFileInfo <span class="op">*</span>info <span class="op">=</span> G_FILE_INFO <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>gtk_list_view_get_model <span class="op">(</span>list<span class="op">)),</span> position<span class="op">));</span></span>
|
||||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> launch_tfe_with_file <span class="op">(</span>info<span class="op">);</span></span>
|
||||
|
@ -558,12 +557,12 @@ list and items.</li>
|
|||
<code>g_app_info_launch_default_for_uri</code> is convenient. The
|
||||
function automatically determines the default application from the file
|
||||
and launches it. For example, if the file is text, then it launches
|
||||
gedit with the file. Such feature comes from desktop.</p>
|
||||
GNOME text editor with the file. Such feature comes from desktop.</p>
|
||||
<h2 id="compilation-and-execution">Compilation and execution</h2>
|
||||
<p>The source files are located in src/list4 directory. To compile and
|
||||
execute list4, type as follows.</p>
|
||||
<pre><code>$ cd list4 # or cd src/list4. It depends your current directory.
|
||||
$ meson _build
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/list4</code></pre>
|
||||
<p>Then a file list appears as a list style. Click on a button on the
|
||||
|
|
748
docs/sec31.html
748
docs/sec31.html
|
@ -191,13 +191,13 @@ value of the expression. The type of the value is int.</li>
|
|||
</tr>
|
||||
<tr class="even">
|
||||
<td style="text-align: left;">G_TYPE_POINTER</td>
|
||||
<td style="text-align: left;"></td>
|
||||
<td style="text-align: left;">void *</td>
|
||||
<td style="text-align: left;">gpointer</td>
|
||||
<td style="text-align: left;"></td>
|
||||
<td style="text-align: left;">general pointer</td>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td style="text-align: left;">G_TYPE_STRING</td>
|
||||
<td style="text-align: left;"></td>
|
||||
<td style="text-align: left;">char *</td>
|
||||
<td style="text-align: left;">gchararray</td>
|
||||
<td style="text-align: left;">null-terminated Cstring</td>
|
||||
</tr>
|
||||
|
@ -250,7 +250,7 @@ instance to another expression.</p>
|
|||
<p>A property expression (GtkPropertyExpression) looks up a property in
|
||||
a GObject instance. For example, a property expression that refers
|
||||
“label” property in a GtkLabel object is created like this.</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>expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> another_expression<span class="op">,</span> <span class="st">"label"</span><span class="op">);</span></span></code></pre></div>
|
||||
<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>expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> another_expression<span class="op">,</span> <span class="st">"label"</span><span class="op">);</span></span></code></pre></div>
|
||||
<p>The second parameter <code>another_expression</code> is one of:</p>
|
||||
<ul>
|
||||
<li>An expression that gives a GtkLabel instance when it is
|
||||
|
@ -259,14 +259,14 @@ evaluated.</li>
|
|||
is evaluated. The instance is called <code>this</code> object.</li>
|
||||
</ul>
|
||||
<p>For example,</p>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>label <span class="op">=</span> gtk_label_new <span class="op">(</span><span class="st">"Hello"</span><span class="op">);</span></span>
|
||||
<div class="sourceCode" id="cb5"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>label <span class="op">=</span> gtk_label_new <span class="op">(</span><span class="st">"Hello"</span><span class="op">);</span></span>
|
||||
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>another_expression <span class="op">=</span> gtk_constant_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> label<span class="op">);</span></span>
|
||||
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_LABEL<span class="op">,</span> another_expression<span class="op">,</span> <span class="st">"label"</span><span class="op">);</span></span></code></pre></div>
|
||||
<p>If <code>expression</code> is evaluated, the second parameter
|
||||
<code>another_expression</code> is evaluated in advance. The value of
|
||||
<code>another_expression</code> is the <code>label</code> (GtkLabel
|
||||
instance). Then, <code>expression</code> looks up “label” property of
|
||||
the label and the evaluation results “Hello”.</p>
|
||||
the label and the evaluation results in “Hello”.</p>
|
||||
<p>In the example above, the second argument of
|
||||
<code>gtk_property_expression_new</code> is another expression. But the
|
||||
second argument can be NULL. If it is NULL, <code>this</code> instance
|
||||
|
@ -291,7 +291,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb6-14"><a href="#cb6-14"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="op">&</span>value<span class="op">))</span></span>
|
||||
<span id="cb6-15"><a href="#cb6-15"></a> g_print <span class="op">(</span><span class="st">"The value is %s.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> g_value_get_string <span class="op">(&</span>value<span class="op">));</span></span>
|
||||
<span id="cb6-16"><a href="#cb6-16"></a> <span class="cf">else</span></span>
|
||||
<span id="cb6-17"><a href="#cb6-17"></a> g_print <span class="op">(</span><span class="st">"The constant expression wasn't evaluated correctly.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb6-17"><a href="#cb6-17"></a> g_print <span class="op">(</span><span class="st">"The property expression wasn't evaluated correctly.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb6-18"><a href="#cb6-18"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
|
||||
<span id="cb6-19"><a href="#cb6-19"></a> g_value_unset <span class="op">(&</span>value<span class="op">);</span></span>
|
||||
<span id="cb6-20"><a href="#cb6-20"></a></span>
|
||||
|
@ -311,8 +311,8 @@ the expression with a ‘this’ instance <code>label</code>. The result is
|
|||
stored in the GValue <code>value</code>. The function
|
||||
<code>g_value_get_string</code> gets a string from the GValue. But the
|
||||
string is owned by the GValue so you must not free the string.</li>
|
||||
<li>18-19: Release the expression and unset the GValue. At the same time
|
||||
the string in the GValue is freed.</li>
|
||||
<li>18-19: Releases the expression and unset the GValue. At the same
|
||||
time the string in the GValue is freed.</li>
|
||||
</ul>
|
||||
<p>If the second argument of <code>gtk_property_expression_new</code>
|
||||
isn’t NULL, it is another expression. The expression is owned by a newly
|
||||
|
@ -334,79 +334,44 @@ respectively. When you program in C language, GtkCClosureExpression and
|
|||
GCClosure are appropriate.</p>
|
||||
<p>A closure expression is created with
|
||||
<code>gtk_cclosure_expression_new</code> function.</p>
|
||||
<div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>GtkExpression <span class="op">*</span></span>
|
||||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>gtk_cclosure_expression_new <span class="op">(</span>GType value_type<span class="op">,</span></span>
|
||||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> GClosureMarshal marshal<span class="op">,</span></span>
|
||||
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> guint n_params<span class="op">,</span></span>
|
||||
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> GtkExpression <span class="op">**</span>params<span class="op">,</span></span>
|
||||
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> GCallback callback_func<span class="op">,</span></span>
|
||||
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">,</span></span>
|
||||
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> GClosureNotify user_destroy<span class="op">);</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li><code>value_type</code> is the type of the value when it is
|
||||
evaluated.</li>
|
||||
<li><code>marshal</code> is a marshaller. You can assign NULL. If it is
|
||||
NULL, then <code>g_cclosure_marshal_generic ()</code> is used as a
|
||||
marshaller. It is a generic marshaller function implemented via
|
||||
libffi.</li>
|
||||
<li><code>n_params</code> is the number of parameters.</li>
|
||||
<li><code>params</code> points expressions for each parameter of the
|
||||
call back function.</li>
|
||||
<li><code>callback_func</code> is a callback function. It is given
|
||||
arguments <code>this</code> and parameters above. So, if
|
||||
<code>n_params</code> is 3, the number of arguments of the function is
|
||||
4. (<code>this</code> and <code>params</code>. See below.)</li>
|
||||
<li><code>user_data</code> is user data. You can add it for the closure.
|
||||
It is like <code>user_data</code> in <code>g_signal_connect</code>. If
|
||||
it is not necessary, assign NULL.</li>
|
||||
<li><code>user_destroy</code> is a destroy notify for
|
||||
<code>user_data</code>. It is called to destroy <code>user_data</code>
|
||||
when it is no longer needed. If NULL is assigned to
|
||||
<code>user_data</code>, assign NULL to <code>user_destroy</code>,
|
||||
too.</li>
|
||||
</ul>
|
||||
<p>Call back functions have the following format.</p>
|
||||
<pre><code>C-type
|
||||
callback (this, param1, param2, ...)</code></pre>
|
||||
<p>For example,</p>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span></span>
|
||||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>callback <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">int</span> x<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>s<span class="op">)</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb7"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span></span>
|
||||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>callback <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">int</span> x<span class="op">,</span> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>s<span class="op">)</span></span></code></pre></div>
|
||||
<p>The following is <code>exp_closure_simple.c</code> in
|
||||
<code>src/expression</code>.</p>
|
||||
<div class="sourceCode" id="cb10"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb10-2"><a href="#cb10-2"></a></span>
|
||||
<span id="cb10-3"><a href="#cb10-3"></a><span class="dt">static</span> <span class="dt">int</span></span>
|
||||
<span id="cb10-4"><a href="#cb10-4"></a>calc <span class="op">(</span>GtkLabel <span class="op">*</span>label<span class="op">)</span> <span class="op">{</span> <span class="co">/* this object */</span></span>
|
||||
<span id="cb10-5"><a href="#cb10-5"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> s<span class="op">;</span></span>
|
||||
<span id="cb10-6"><a href="#cb10-6"></a> <span class="dt">int</span> i<span class="op">,</span> j<span class="op">;</span></span>
|
||||
<span id="cb10-7"><a href="#cb10-7"></a></span>
|
||||
<span id="cb10-8"><a href="#cb10-8"></a> s <span class="op">=</span> gtk_label_get_text <span class="op">(</span>label<span class="op">);</span> <span class="co">/* s is owned by the label. */</span></span>
|
||||
<span id="cb10-9"><a href="#cb10-9"></a> sscanf <span class="op">(</span>s<span class="op">,</span> <span class="st">"%d+%d"</span><span class="op">,</span> <span class="op">&</span>i<span class="op">,</span> <span class="op">&</span>j<span class="op">);</span></span>
|
||||
<span id="cb10-10"><a href="#cb10-10"></a> <span class="cf">return</span> i<span class="op">+</span>j<span class="op">;</span></span>
|
||||
<span id="cb10-11"><a href="#cb10-11"></a><span class="op">}</span></span>
|
||||
<span id="cb10-12"><a href="#cb10-12"></a></span>
|
||||
<span id="cb10-13"><a href="#cb10-13"></a><span class="dt">int</span></span>
|
||||
<span id="cb10-14"><a href="#cb10-14"></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="cb10-15"><a href="#cb10-15"></a> GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
|
||||
<span id="cb10-16"><a href="#cb10-16"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
|
||||
<span id="cb10-17"><a href="#cb10-17"></a> GtkLabel <span class="op">*</span>label<span class="op">;</span></span>
|
||||
<span id="cb10-18"><a href="#cb10-18"></a></span>
|
||||
<span id="cb10-19"><a href="#cb10-19"></a> gtk_init <span class="op">();</span></span>
|
||||
<span id="cb10-20"><a href="#cb10-20"></a> label <span class="op">=</span> GTK_LABEL <span class="op">(</span>gtk_label_new <span class="op">(</span><span class="st">"123+456"</span><span class="op">));</span></span>
|
||||
<span id="cb10-21"><a href="#cb10-21"></a> g_object_ref_sink <span class="op">(</span>label<span class="op">);</span></span>
|
||||
<span id="cb10-22"><a href="#cb10-22"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> NULL<span class="op">,</span></span>
|
||||
<span id="cb10-23"><a href="#cb10-23"></a> G_CALLBACK <span class="op">(</span>calc<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb10-24"><a href="#cb10-24"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="op">&</span>value<span class="op">))</span> <span class="co">/* 'this' object is the label. */</span></span>
|
||||
<span id="cb10-25"><a href="#cb10-25"></a> g_print <span class="op">(</span><span class="st">"%d</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> g_value_get_int <span class="op">(&</span>value<span class="op">));</span></span>
|
||||
<span id="cb10-26"><a href="#cb10-26"></a> <span class="cf">else</span></span>
|
||||
<span id="cb10-27"><a href="#cb10-27"></a> g_print <span class="op">(</span><span class="st">"The closure expression wasn't evaluated correctly.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb10-28"><a href="#cb10-28"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
|
||||
<span id="cb10-29"><a href="#cb10-29"></a> g_value_unset <span class="op">(&</span>value<span class="op">);</span></span>
|
||||
<span id="cb10-30"><a href="#cb10-30"></a> g_object_unref <span class="op">(</span>label<span class="op">);</span></span>
|
||||
<span id="cb10-31"><a href="#cb10-31"></a> </span>
|
||||
<span id="cb10-32"><a href="#cb10-32"></a> <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
|
||||
<span id="cb10-33"><a href="#cb10-33"></a><span class="op">}</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb8"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb8-2"><a href="#cb8-2"></a></span>
|
||||
<span id="cb8-3"><a href="#cb8-3"></a><span class="dt">static</span> <span class="dt">int</span></span>
|
||||
<span id="cb8-4"><a href="#cb8-4"></a>calc <span class="op">(</span>GtkLabel <span class="op">*</span>label<span class="op">)</span> <span class="op">{</span> <span class="co">/* this object */</span></span>
|
||||
<span id="cb8-5"><a href="#cb8-5"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span> s<span class="op">;</span></span>
|
||||
<span id="cb8-6"><a href="#cb8-6"></a> <span class="dt">int</span> i<span class="op">,</span> j<span class="op">;</span></span>
|
||||
<span id="cb8-7"><a href="#cb8-7"></a></span>
|
||||
<span id="cb8-8"><a href="#cb8-8"></a> s <span class="op">=</span> gtk_label_get_text <span class="op">(</span>label<span class="op">);</span> <span class="co">/* s is owned by the label. */</span></span>
|
||||
<span id="cb8-9"><a href="#cb8-9"></a> sscanf <span class="op">(</span>s<span class="op">,</span> <span class="st">"%d+%d"</span><span class="op">,</span> <span class="op">&</span>i<span class="op">,</span> <span class="op">&</span>j<span class="op">);</span></span>
|
||||
<span id="cb8-10"><a href="#cb8-10"></a> <span class="cf">return</span> i<span class="op">+</span>j<span class="op">;</span></span>
|
||||
<span id="cb8-11"><a href="#cb8-11"></a><span class="op">}</span></span>
|
||||
<span id="cb8-12"><a href="#cb8-12"></a></span>
|
||||
<span id="cb8-13"><a href="#cb8-13"></a><span class="dt">int</span></span>
|
||||
<span id="cb8-14"><a href="#cb8-14"></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-15"><a href="#cb8-15"></a> GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
|
||||
<span id="cb8-16"><a href="#cb8-16"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
|
||||
<span id="cb8-17"><a href="#cb8-17"></a> GtkLabel <span class="op">*</span>label<span class="op">;</span></span>
|
||||
<span id="cb8-18"><a href="#cb8-18"></a></span>
|
||||
<span id="cb8-19"><a href="#cb8-19"></a> gtk_init <span class="op">();</span></span>
|
||||
<span id="cb8-20"><a href="#cb8-20"></a> label <span class="op">=</span> GTK_LABEL <span class="op">(</span>gtk_label_new <span class="op">(</span><span class="st">"123+456"</span><span class="op">));</span></span>
|
||||
<span id="cb8-21"><a href="#cb8-21"></a> g_object_ref_sink <span class="op">(</span>label<span class="op">);</span></span>
|
||||
<span id="cb8-22"><a href="#cb8-22"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> NULL<span class="op">,</span></span>
|
||||
<span id="cb8-23"><a href="#cb8-23"></a> G_CALLBACK <span class="op">(</span>calc<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-24"><a href="#cb8-24"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_evaluate <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="op">&</span>value<span class="op">))</span> <span class="co">/* 'this' object is the label. */</span></span>
|
||||
<span id="cb8-25"><a href="#cb8-25"></a> g_print <span class="op">(</span><span class="st">"%d</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> g_value_get_int <span class="op">(&</span>value<span class="op">));</span></span>
|
||||
<span id="cb8-26"><a href="#cb8-26"></a> <span class="cf">else</span></span>
|
||||
<span id="cb8-27"><a href="#cb8-27"></a> g_print <span class="op">(</span><span class="st">"The closure expression wasn't evaluated correctly.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb8-28"><a href="#cb8-28"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
|
||||
<span id="cb8-29"><a href="#cb8-29"></a> g_value_unset <span class="op">(&</span>value<span class="op">);</span></span>
|
||||
<span id="cb8-30"><a href="#cb8-30"></a> g_object_unref <span class="op">(</span>label<span class="op">);</span></span>
|
||||
<span id="cb8-31"><a href="#cb8-31"></a> </span>
|
||||
<span id="cb8-32"><a href="#cb8-32"></a> <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
|
||||
<span id="cb8-33"><a href="#cb8-33"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>3-11: A call back function. The parameter is only one and it is a
|
||||
‘this’ object. It is a GtkLabel and its label is assumed to be
|
||||
|
@ -419,16 +384,17 @@ argument of <code>gtk_cclosure_expression_new</code> is
|
|||
<code>G_TYPE_POINTER</code>. There is a sample program
|
||||
<code>exp_closure_with_error_report</code> in
|
||||
<code>src/expression</code> directory.</li>
|
||||
<li>19: gtk_init initializes GTK. It is necessary for GtkLabel.</li>
|
||||
<li>19: The function `gtk_init`` initializes GTK. It is necessary for
|
||||
GtkLabel.</li>
|
||||
<li>20: A GtkLabel instance is created with “123+456”.</li>
|
||||
<li>21: The instance has floating reference. It is changed to an
|
||||
ordinary reference count.</li>
|
||||
<li>22-23: Create a closure expression. Its return value type is
|
||||
<li>22-23: Creates a closure expression. Its return value type is
|
||||
<code>G_TYPE_INT</code> and no parameters or ‘this’ object.</li>
|
||||
<li>24: Evaluates the expression with the label as a ‘this’ object.</li>
|
||||
<li>25: If the evaluation successes, show the sum of “123+456”. It’s
|
||||
579.</li>
|
||||
<li>27: If it fails, show an error message.</li>
|
||||
<li>25: If the evaluation successes, the sum of “123+456”, which is 579,
|
||||
is shown.</li>
|
||||
<li>27: If it fails, an error message appears.</li>
|
||||
<li>28-30: Releases the expression and the label. Unsets the value.</li>
|
||||
</ul>
|
||||
<p>Closure expression is flexible than other type of expression because
|
||||
|
@ -436,18 +402,19 @@ you can specify your own callback function.</p>
|
|||
<h2 id="gtkexpressionwatch">GtkExpressionWatch</h2>
|
||||
<p>GtkExpressionWatch is a structure, not an object. It represents a
|
||||
watched GtkExpression. Two functions create GtkExpressionWatch
|
||||
structure.</p>
|
||||
structure. They are <code>gtk_expression_bind</code> and
|
||||
<code>gtk_expression_watch</code>.</p>
|
||||
<h3 id="gtk_expression_bind-function">gtk_expression_bind function</h3>
|
||||
<p>This function binds the target object’s property to the expression.
|
||||
If the value of the expression changes, the property reflects the value
|
||||
immediately.</p>
|
||||
<div class="sourceCode" id="cb11"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>GtkExpressionWatch<span class="op">*</span></span>
|
||||
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_bind <span class="op">(</span></span>
|
||||
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span>
|
||||
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> target<span class="op">,</span></span>
|
||||
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> property<span class="op">,</span></span>
|
||||
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_</span>
|
||||
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb9"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>GtkExpressionWatch<span class="op">*</span></span>
|
||||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_bind <span class="op">(</span></span>
|
||||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span>
|
||||
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> target<span class="op">,</span></span>
|
||||
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">const</span> <span class="dt">char</span><span class="op">*</span> property<span class="op">,</span></span>
|
||||
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_</span>
|
||||
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
|
||||
<p>This function takes the ownership of the expression. So, if you want
|
||||
to own the expression, call <code>gtk_expression_ref ()</code> to
|
||||
increase the reference count of the expression. And you should unref it
|
||||
|
@ -463,41 +430,41 @@ about releasing the expression.</p>
|
|||
the scale value increases and the number on the label also increases. In
|
||||
the same way, if you move it to the left, the number on the label
|
||||
decreases. The label is bound to the scale value via an adjustment.</p>
|
||||
<div class="sourceCode" id="cb12"><pre
|
||||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb12-1"><a href="#cb12-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="cb12-2"><a href="#cb12-2"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb12-3"><a href="#cb12-3"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkApplicationWindow'</span><span class="ot"> id=</span><span class="st">'win'</span>></span>
|
||||
<span id="cb12-4"><a href="#cb12-4"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'default-width'</span>>600</<span class="kw">property</span>></span>
|
||||
<span id="cb12-5"><a href="#cb12-5"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb12-6"><a href="#cb12-6"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkBox'</span>></span>
|
||||
<span id="cb12-7"><a href="#cb12-7"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'orientation'</span>>GTK_ORIENTATION_VERTICAL</<span class="kw">property</span>></span>
|
||||
<span id="cb12-8"><a href="#cb12-8"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb12-9"><a href="#cb12-9"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkLabel'</span><span class="ot"> id=</span><span class="st">'label'</span>></span>
|
||||
<span id="cb12-10"><a href="#cb12-10"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>10</<span class="kw">property</span>></span>
|
||||
<span id="cb12-11"><a href="#cb12-11"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb12-12"><a href="#cb12-12"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb12-13"><a href="#cb12-13"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb12-14"><a href="#cb12-14"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkScale'</span>></span>
|
||||
<span id="cb12-15"><a href="#cb12-15"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'adjustment'</span>></span>
|
||||
<span id="cb12-16"><a href="#cb12-16"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkAdjustment'</span><span class="ot"> id=</span><span class="st">'adjustment'</span>></span>
|
||||
<span id="cb12-17"><a href="#cb12-17"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'upper'</span>>20.0</<span class="kw">property</span>></span>
|
||||
<span id="cb12-18"><a href="#cb12-18"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'lower'</span>>0.0</<span class="kw">property</span>></span>
|
||||
<span id="cb12-19"><a href="#cb12-19"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'value'</span>>10.0</<span class="kw">property</span>></span>
|
||||
<span id="cb12-20"><a href="#cb12-20"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'step-increment'</span>>1.0</<span class="kw">property</span>></span>
|
||||
<span id="cb12-21"><a href="#cb12-21"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'page-increment'</span>>5.0</<span class="kw">property</span>></span>
|
||||
<span id="cb12-22"><a href="#cb12-22"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'page-size'</span>>0.0</<span class="kw">property</span>></span>
|
||||
<span id="cb12-23"><a href="#cb12-23"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb12-24"><a href="#cb12-24"></a> </<span class="kw">property</span>></span>
|
||||
<span id="cb12-25"><a href="#cb12-25"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'digits'</span>>0</<span class="kw">property</span>></span>
|
||||
<span id="cb12-26"><a href="#cb12-26"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'draw-value'</span>>true</<span class="kw">property</span>></span>
|
||||
<span id="cb12-27"><a href="#cb12-27"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'has-origin'</span>>true</<span class="kw">property</span>></span>
|
||||
<span id="cb12-28"><a href="#cb12-28"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'round-digits'</span>>0</<span class="kw">property</span>></span>
|
||||
<span id="cb12-29"><a href="#cb12-29"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb12-30"><a href="#cb12-30"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb12-31"><a href="#cb12-31"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb12-32"><a href="#cb12-32"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb12-33"><a href="#cb12-33"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb12-34"><a href="#cb12-34"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb10"><pre
|
||||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb10-1"><a href="#cb10-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="cb10-2"><a href="#cb10-2"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb10-3"><a href="#cb10-3"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkApplicationWindow'</span><span class="ot"> id=</span><span class="st">'win'</span>></span>
|
||||
<span id="cb10-4"><a href="#cb10-4"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'default-width'</span>>600</<span class="kw">property</span>></span>
|
||||
<span id="cb10-5"><a href="#cb10-5"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb10-6"><a href="#cb10-6"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkBox'</span>></span>
|
||||
<span id="cb10-7"><a href="#cb10-7"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'orientation'</span>>GTK_ORIENTATION_VERTICAL</<span class="kw">property</span>></span>
|
||||
<span id="cb10-8"><a href="#cb10-8"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb10-9"><a href="#cb10-9"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkLabel'</span><span class="ot"> id=</span><span class="st">'label'</span>></span>
|
||||
<span id="cb10-10"><a href="#cb10-10"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>10</<span class="kw">property</span>></span>
|
||||
<span id="cb10-11"><a href="#cb10-11"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb10-12"><a href="#cb10-12"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb10-13"><a href="#cb10-13"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb10-14"><a href="#cb10-14"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkScale'</span>></span>
|
||||
<span id="cb10-15"><a href="#cb10-15"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'adjustment'</span>></span>
|
||||
<span id="cb10-16"><a href="#cb10-16"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">'GtkAdjustment'</span><span class="ot"> id=</span><span class="st">'adjustment'</span>></span>
|
||||
<span id="cb10-17"><a href="#cb10-17"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'upper'</span>>20.0</<span class="kw">property</span>></span>
|
||||
<span id="cb10-18"><a href="#cb10-18"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'lower'</span>>0.0</<span class="kw">property</span>></span>
|
||||
<span id="cb10-19"><a href="#cb10-19"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'value'</span>>10.0</<span class="kw">property</span>></span>
|
||||
<span id="cb10-20"><a href="#cb10-20"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'step-increment'</span>>1.0</<span class="kw">property</span>></span>
|
||||
<span id="cb10-21"><a href="#cb10-21"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'page-increment'</span>>5.0</<span class="kw">property</span>></span>
|
||||
<span id="cb10-22"><a href="#cb10-22"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'page-size'</span>>0.0</<span class="kw">property</span>></span>
|
||||
<span id="cb10-23"><a href="#cb10-23"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb10-24"><a href="#cb10-24"></a> </<span class="kw">property</span>></span>
|
||||
<span id="cb10-25"><a href="#cb10-25"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'digits'</span>>0</<span class="kw">property</span>></span>
|
||||
<span id="cb10-26"><a href="#cb10-26"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'draw-value'</span>>true</<span class="kw">property</span>></span>
|
||||
<span id="cb10-27"><a href="#cb10-27"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'has-origin'</span>>true</<span class="kw">property</span>></span>
|
||||
<span id="cb10-28"><a href="#cb10-28"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">'round-digits'</span>>0</<span class="kw">property</span>></span>
|
||||
<span id="cb10-29"><a href="#cb10-29"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb10-30"><a href="#cb10-30"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb10-31"><a href="#cb10-31"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb10-32"><a href="#cb10-32"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb10-33"><a href="#cb10-33"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb10-34"><a href="#cb10-34"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<p>The ui file describes the following parent-child relationship.</p>
|
||||
<pre><code>GtkApplicationWindow (win) -- GtkBox -+- GtkLabel (label)
|
||||
+- GtkScale</code></pre>
|
||||
|
@ -523,73 +490,73 @@ orange bar appears between the origin and the current point.</li>
|
|||
changes. For example, if it is zero, the slider moves to an integer
|
||||
point.</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb14"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb14-2"><a href="#cb14-2"></a></span>
|
||||
<span id="cb14-3"><a href="#cb14-3"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span>
|
||||
<span id="cb14-4"><a href="#cb14-4"></a></span>
|
||||
<span id="cb14-5"><a href="#cb14-5"></a><span class="dt">static</span> <span class="dt">int</span></span>
|
||||
<span id="cb14-6"><a href="#cb14-6"></a>f2i <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">double</span> d<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb14-7"><a href="#cb14-7"></a> <span class="cf">return</span> <span class="op">(</span><span class="dt">int</span><span class="op">)</span> d<span class="op">;</span></span>
|
||||
<span id="cb14-8"><a href="#cb14-8"></a><span class="op">}</span></span>
|
||||
<span id="cb14-9"><a href="#cb14-9"></a></span>
|
||||
<span id="cb14-10"><a href="#cb14-10"></a><span class="dt">static</span> <span class="dt">int</span></span>
|
||||
<span id="cb14-11"><a href="#cb14-11"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb14-12"><a href="#cb14-12"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span>
|
||||
<span id="cb14-13"><a href="#cb14-13"></a> <span class="cf">return</span> false<span class="op">;</span></span>
|
||||
<span id="cb14-14"><a href="#cb14-14"></a><span class="op">}</span></span>
|
||||
<span id="cb14-15"><a href="#cb14-15"></a></span>
|
||||
<span id="cb14-16"><a href="#cb14-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb14-17"><a href="#cb14-17"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb14-18"><a href="#cb14-18"></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="cb14-19"><a href="#cb14-19"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb14-20"><a href="#cb14-20"></a><span class="op">}</span></span>
|
||||
<span id="cb14-21"><a href="#cb14-21"></a></span>
|
||||
<span id="cb14-22"><a href="#cb14-22"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb14-23"><a href="#cb14-23"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb14-24"><a href="#cb14-24"></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="cb14-25"><a href="#cb14-25"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||||
<span id="cb14-26"><a href="#cb14-26"></a> GtkWidget <span class="op">*</span>win<span class="op">,</span> <span class="op">*</span>label<span class="op">;</span></span>
|
||||
<span id="cb14-27"><a href="#cb14-27"></a> GtkAdjustment <span class="op">*</span>adjustment<span class="op">;</span></span>
|
||||
<span id="cb14-28"><a href="#cb14-28"></a> GtkExpression <span class="op">*</span>expression<span class="op">,</span> <span class="op">*</span>params<span class="op">[</span><span class="dv">1</span><span class="op">];</span></span>
|
||||
<span id="cb14-29"><a href="#cb14-29"></a></span>
|
||||
<span id="cb14-30"><a href="#cb14-30"></a> <span class="co">/* Builds a window with exp.ui resource */</span></span>
|
||||
<span id="cb14-31"><a href="#cb14-31"></a> build <span class="op">=</span> gtk_builder_new_from_file <span class="op">(</span><span class="st">"exp_bind.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb14-32"><a href="#cb14-32"></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="cb14-33"><a href="#cb14-33"></a> label <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">"label"</span><span class="op">));</span></span>
|
||||
<span id="cb14-34"><a href="#cb14-34"></a> <span class="co">// scale = GTK_WIDGET (gtk_builder_get_object (build, "scale"));</span></span>
|
||||
<span id="cb14-35"><a href="#cb14-35"></a> adjustment <span class="op">=</span> GTK_ADJUSTMENT <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"adjustment"</span><span class="op">));</span></span>
|
||||
<span id="cb14-36"><a href="#cb14-36"></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="cb14-37"><a href="#cb14-37"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">"close-request"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb14-38"><a href="#cb14-38"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
|
||||
<span id="cb14-39"><a href="#cb14-39"></a></span>
|
||||
<span id="cb14-40"><a href="#cb14-40"></a> <span class="co">/* GtkExpressionWatch */</span></span>
|
||||
<span id="cb14-41"><a href="#cb14-41"></a> params<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_ADJUSTMENT<span class="op">,</span> NULL<span class="op">,</span> <span class="st">"value"</span><span class="op">);</span></span>
|
||||
<span id="cb14-42"><a href="#cb14-42"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> params<span class="op">,</span> G_CALLBACK <span class="op">(</span>f2i<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb14-43"><a href="#cb14-43"></a> watch <span class="op">=</span> gtk_expression_bind <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="st">"label"</span><span class="op">,</span> adjustment<span class="op">);</span> <span class="co">/* watch takes the ownership of the expression. */</span></span>
|
||||
<span id="cb14-44"><a href="#cb14-44"></a><span class="op">}</span></span>
|
||||
<span id="cb14-45"><a href="#cb14-45"></a></span>
|
||||
<span id="cb14-46"><a href="#cb14-46"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.exp_watch"</span></span>
|
||||
<span id="cb14-47"><a href="#cb14-47"></a></span>
|
||||
<span id="cb14-48"><a href="#cb14-48"></a><span class="dt">int</span></span>
|
||||
<span id="cb14-49"><a href="#cb14-49"></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="cb14-50"><a href="#cb14-50"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb14-51"><a href="#cb14-51"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb14-52"><a href="#cb14-52"></a></span>
|
||||
<span id="cb14-53"><a href="#cb14-53"></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="cb14-54"><a href="#cb14-54"></a></span>
|
||||
<span id="cb14-55"><a href="#cb14-55"></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="cb14-56"><a href="#cb14-56"></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="cb14-57"><a href="#cb14-57"></a></span>
|
||||
<span id="cb14-58"><a href="#cb14-58"></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="cb14-59"><a href="#cb14-59"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb14-60"><a href="#cb14-60"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb14-61"><a href="#cb14-61"></a><span class="op">}</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb12"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb12-1"><a href="#cb12-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb12-2"><a href="#cb12-2"></a></span>
|
||||
<span id="cb12-3"><a href="#cb12-3"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span>
|
||||
<span id="cb12-4"><a href="#cb12-4"></a></span>
|
||||
<span id="cb12-5"><a href="#cb12-5"></a><span class="dt">static</span> <span class="dt">int</span></span>
|
||||
<span id="cb12-6"><a href="#cb12-6"></a>f2i <span class="op">(</span>GObject <span class="op">*</span>object<span class="op">,</span> <span class="dt">double</span> d<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb12-7"><a href="#cb12-7"></a> <span class="cf">return</span> <span class="op">(</span><span class="dt">int</span><span class="op">)</span> d<span class="op">;</span></span>
|
||||
<span id="cb12-8"><a href="#cb12-8"></a><span class="op">}</span></span>
|
||||
<span id="cb12-9"><a href="#cb12-9"></a></span>
|
||||
<span id="cb12-10"><a href="#cb12-10"></a><span class="dt">static</span> <span class="dt">int</span></span>
|
||||
<span id="cb12-11"><a href="#cb12-11"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb12-12"><a href="#cb12-12"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span>
|
||||
<span id="cb12-13"><a href="#cb12-13"></a> <span class="cf">return</span> false<span class="op">;</span></span>
|
||||
<span id="cb12-14"><a href="#cb12-14"></a><span class="op">}</span></span>
|
||||
<span id="cb12-15"><a href="#cb12-15"></a></span>
|
||||
<span id="cb12-16"><a href="#cb12-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb12-17"><a href="#cb12-17"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb12-18"><a href="#cb12-18"></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="cb12-19"><a href="#cb12-19"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb12-20"><a href="#cb12-20"></a><span class="op">}</span></span>
|
||||
<span id="cb12-21"><a href="#cb12-21"></a></span>
|
||||
<span id="cb12-22"><a href="#cb12-22"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb12-23"><a href="#cb12-23"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb12-24"><a href="#cb12-24"></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="cb12-25"><a href="#cb12-25"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||||
<span id="cb12-26"><a href="#cb12-26"></a> GtkWidget <span class="op">*</span>win<span class="op">,</span> <span class="op">*</span>label<span class="op">;</span></span>
|
||||
<span id="cb12-27"><a href="#cb12-27"></a> GtkAdjustment <span class="op">*</span>adjustment<span class="op">;</span></span>
|
||||
<span id="cb12-28"><a href="#cb12-28"></a> GtkExpression <span class="op">*</span>expression<span class="op">,</span> <span class="op">*</span>params<span class="op">[</span><span class="dv">1</span><span class="op">];</span></span>
|
||||
<span id="cb12-29"><a href="#cb12-29"></a></span>
|
||||
<span id="cb12-30"><a href="#cb12-30"></a> <span class="co">/* Builds a window with exp.ui resource */</span></span>
|
||||
<span id="cb12-31"><a href="#cb12-31"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/exp/exp_bind.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb12-32"><a href="#cb12-32"></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="cb12-33"><a href="#cb12-33"></a> label <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">"label"</span><span class="op">));</span></span>
|
||||
<span id="cb12-34"><a href="#cb12-34"></a> <span class="co">// scale = GTK_WIDGET (gtk_builder_get_object (build, "scale"));</span></span>
|
||||
<span id="cb12-35"><a href="#cb12-35"></a> adjustment <span class="op">=</span> GTK_ADJUSTMENT <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"adjustment"</span><span class="op">));</span></span>
|
||||
<span id="cb12-36"><a href="#cb12-36"></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="cb12-37"><a href="#cb12-37"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">"close-request"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb12-38"><a href="#cb12-38"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
|
||||
<span id="cb12-39"><a href="#cb12-39"></a></span>
|
||||
<span id="cb12-40"><a href="#cb12-40"></a> <span class="co">/* GtkExpressionWatch */</span></span>
|
||||
<span id="cb12-41"><a href="#cb12-41"></a> params<span class="op">[</span><span class="dv">0</span><span class="op">]</span> <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_ADJUSTMENT<span class="op">,</span> NULL<span class="op">,</span> <span class="st">"value"</span><span class="op">);</span></span>
|
||||
<span id="cb12-42"><a href="#cb12-42"></a> expression <span class="op">=</span> gtk_cclosure_expression_new <span class="op">(</span>G_TYPE_INT<span class="op">,</span> NULL<span class="op">,</span> <span class="dv">1</span><span class="op">,</span> params<span class="op">,</span> G_CALLBACK <span class="op">(</span>f2i<span class="op">),</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb12-43"><a href="#cb12-43"></a> watch <span class="op">=</span> gtk_expression_bind <span class="op">(</span>expression<span class="op">,</span> label<span class="op">,</span> <span class="st">"label"</span><span class="op">,</span> adjustment<span class="op">);</span> <span class="co">/* watch takes the ownership of the expression. */</span></span>
|
||||
<span id="cb12-44"><a href="#cb12-44"></a><span class="op">}</span></span>
|
||||
<span id="cb12-45"><a href="#cb12-45"></a></span>
|
||||
<span id="cb12-46"><a href="#cb12-46"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.exp_watch"</span></span>
|
||||
<span id="cb12-47"><a href="#cb12-47"></a></span>
|
||||
<span id="cb12-48"><a href="#cb12-48"></a><span class="dt">int</span></span>
|
||||
<span id="cb12-49"><a href="#cb12-49"></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="cb12-50"><a href="#cb12-50"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb12-51"><a href="#cb12-51"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb12-52"><a href="#cb12-52"></a></span>
|
||||
<span id="cb12-53"><a href="#cb12-53"></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="cb12-54"><a href="#cb12-54"></a></span>
|
||||
<span id="cb12-55"><a href="#cb12-55"></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="cb12-56"><a href="#cb12-56"></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="cb12-57"><a href="#cb12-57"></a></span>
|
||||
<span id="cb12-58"><a href="#cb12-58"></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="cb12-59"><a href="#cb12-59"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb12-60"><a href="#cb12-60"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb12-61"><a href="#cb12-61"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The point of the program is:</p>
|
||||
<ul>
|
||||
<li>41-42: Two expressions are defined. One is a property expression and
|
||||
the other is a closure expression. The property expression look up the
|
||||
“value”property of the adjustment instance. The closure expression just
|
||||
the other is a closure expression. The property expression looks up the
|
||||
“value” property of the adjustment instance. The closure expression just
|
||||
converts the double into an integer.</li>
|
||||
<li>43: <code>gtk_expression_bind</code> binds the label property of the
|
||||
GtkLabel instance to the integer returned by the closure expression. It
|
||||
|
@ -603,24 +570,23 @@ is destroyed.</li>
|
|||
<code>close_request_cb</code>. This signal is emitted when the close
|
||||
button is clicked. The handler is called just before the window closes.
|
||||
It is the right moment to make the GtkExpressionWatch unwatched.</li>
|
||||
<li>10-14: “close-request” signal handler.
|
||||
<li>10-14: “close-request” signal handler. The function
|
||||
<code>gtk_expression_watch_unwatch (watch)</code> makes the watch stop
|
||||
watching the expression. It releases the expression and calls
|
||||
<code>gtk_expression_watch_unref (watch)</code> in it.</li>
|
||||
watching the expression. It also releases the expression.</li>
|
||||
</ul>
|
||||
<p>If you want to bind a property to an expression,
|
||||
<code>gtk_expression_bind</code> is the best choice. You can do it with
|
||||
<code>gtk_expression_watch</code> function, but it is less suitable.</p>
|
||||
<h3 id="gtk_expression_watch-function">gtk_expression_watch
|
||||
function</h3>
|
||||
<div class="sourceCode" id="cb15"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>GtkExpressionWatch<span class="op">*</span></span>
|
||||
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_watch <span class="op">(</span></span>
|
||||
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span>
|
||||
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_<span class="op">,</span></span>
|
||||
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a> GtkExpressionNotify notify<span class="op">,</span></span>
|
||||
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">,</span></span>
|
||||
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a> GDestroyNotify user_destroy</span>
|
||||
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb13"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>GtkExpressionWatch<span class="op">*</span></span>
|
||||
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>gtk_expression_watch <span class="op">(</span></span>
|
||||
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a> GtkExpression<span class="op">*</span> self<span class="op">,</span></span>
|
||||
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a> GObject<span class="op">*</span> this_<span class="op">,</span></span>
|
||||
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a> GtkExpressionNotify notify<span class="op">,</span></span>
|
||||
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a> gpointer user_data<span class="op">,</span></span>
|
||||
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a> GDestroyNotify user_destroy</span>
|
||||
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
|
||||
<p>The function doesn’t take the ownership of the expression. It differs
|
||||
from <code>gtk_expression_bind</code>. So, you need to release the
|
||||
expression when it is useless. It creates a GtkExpressionWatch
|
||||
|
@ -630,10 +596,10 @@ to give it to the callback. The last parameter is a function to destroy
|
|||
the <code>user_data</code> when the watch is unwatched. Put NULL if you
|
||||
don’t need them.</p>
|
||||
<p>Notify callback has the following format.</p>
|
||||
<div class="sourceCode" id="cb16"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||||
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>notify <span class="op">(</span></span>
|
||||
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> gpointer user_data</span>
|
||||
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb14"><pre class="sourceCode C"><code class="sourceCode c"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
|
||||
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>notify <span class="op">(</span></span>
|
||||
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> gpointer user_data</span>
|
||||
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span></code></pre></div>
|
||||
<p>This function is used to do something when the value of the
|
||||
expression changes. But if you want to bind a property to the value, use
|
||||
<code>gtk_expression_bind</code> instead.</p>
|
||||
|
@ -646,63 +612,63 @@ window to the standard output.</p>
|
|||
</figure>
|
||||
<p>When you resize the window, the width is displayed in the
|
||||
terminal.</p>
|
||||
<div class="sourceCode" id="cb17"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb17-1"><a href="#cb17-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb17-2"><a href="#cb17-2"></a></span>
|
||||
<span id="cb17-3"><a href="#cb17-3"></a>GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
|
||||
<span id="cb17-4"><a href="#cb17-4"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span>
|
||||
<span id="cb17-5"><a href="#cb17-5"></a></span>
|
||||
<span id="cb17-6"><a href="#cb17-6"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb17-7"><a href="#cb17-7"></a>notify <span class="op">(</span>gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb17-8"><a href="#cb17-8"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
|
||||
<span id="cb17-9"><a href="#cb17-9"></a></span>
|
||||
<span id="cb17-10"><a href="#cb17-10"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_watch_evaluate <span class="op">(</span>watch<span class="op">,</span> <span class="op">&</span>value<span class="op">))</span></span>
|
||||
<span id="cb17-11"><a href="#cb17-11"></a> g_print <span class="op">(</span><span class="st">"width = %d</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> g_value_get_int <span class="op">(&</span>value<span class="op">));</span></span>
|
||||
<span id="cb17-12"><a href="#cb17-12"></a> <span class="cf">else</span></span>
|
||||
<span id="cb17-13"><a href="#cb17-13"></a> g_print <span class="op">(</span><span class="st">"evaluation failed.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb17-14"><a href="#cb17-14"></a><span class="op">}</span></span>
|
||||
<span id="cb17-15"><a href="#cb17-15"></a></span>
|
||||
<span id="cb17-16"><a href="#cb17-16"></a><span class="dt">static</span> <span class="dt">int</span></span>
|
||||
<span id="cb17-17"><a href="#cb17-17"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb17-18"><a href="#cb17-18"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span>
|
||||
<span id="cb17-19"><a href="#cb17-19"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
|
||||
<span id="cb17-20"><a href="#cb17-20"></a> <span class="cf">return</span> false<span class="op">;</span></span>
|
||||
<span id="cb17-21"><a href="#cb17-21"></a><span class="op">}</span></span>
|
||||
<span id="cb17-22"><a href="#cb17-22"></a></span>
|
||||
<span id="cb17-23"><a href="#cb17-23"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb17-24"><a href="#cb17-24"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb17-25"><a href="#cb17-25"></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="cb17-26"><a href="#cb17-26"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb17-27"><a href="#cb17-27"></a><span class="op">}</span></span>
|
||||
<span id="cb17-28"><a href="#cb17-28"></a></span>
|
||||
<span id="cb17-29"><a href="#cb17-29"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb17-30"><a href="#cb17-30"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb17-31"><a href="#cb17-31"></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="cb17-32"><a href="#cb17-32"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb17-33"><a href="#cb17-33"></a></span>
|
||||
<span id="cb17-34"><a href="#cb17-34"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_application_window_new <span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb17-35"><a href="#cb17-35"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">"close-request"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb17-36"><a href="#cb17-36"></a></span>
|
||||
<span id="cb17-37"><a href="#cb17-37"></a> expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_WINDOW<span class="op">,</span> NULL<span class="op">,</span> <span class="st">"default-width"</span><span class="op">);</span></span>
|
||||
<span id="cb17-38"><a href="#cb17-38"></a> watch <span class="op">=</span> gtk_expression_watch <span class="op">(</span>expression<span class="op">,</span> win<span class="op">,</span> notify<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb17-39"><a href="#cb17-39"></a><span class="op">}</span></span>
|
||||
<span id="cb17-40"><a href="#cb17-40"></a></span>
|
||||
<span id="cb17-41"><a href="#cb17-41"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.exp_watch"</span></span>
|
||||
<span id="cb17-42"><a href="#cb17-42"></a></span>
|
||||
<span id="cb17-43"><a href="#cb17-43"></a><span class="dt">int</span></span>
|
||||
<span id="cb17-44"><a href="#cb17-44"></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="cb17-45"><a href="#cb17-45"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb17-46"><a href="#cb17-46"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb17-47"><a href="#cb17-47"></a></span>
|
||||
<span id="cb17-48"><a href="#cb17-48"></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="cb17-49"><a href="#cb17-49"></a></span>
|
||||
<span id="cb17-50"><a href="#cb17-50"></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="cb17-51"><a href="#cb17-51"></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="cb17-52"><a href="#cb17-52"></a></span>
|
||||
<span id="cb17-53"><a href="#cb17-53"></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="cb17-54"><a href="#cb17-54"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb17-55"><a href="#cb17-55"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb17-56"><a href="#cb17-56"></a><span class="op">}</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb15"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb15-1"><a href="#cb15-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb15-2"><a href="#cb15-2"></a></span>
|
||||
<span id="cb15-3"><a href="#cb15-3"></a>GtkExpression <span class="op">*</span>expression<span class="op">;</span></span>
|
||||
<span id="cb15-4"><a href="#cb15-4"></a>GtkExpressionWatch <span class="op">*</span>watch<span class="op">;</span></span>
|
||||
<span id="cb15-5"><a href="#cb15-5"></a></span>
|
||||
<span id="cb15-6"><a href="#cb15-6"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb15-7"><a href="#cb15-7"></a>notify <span class="op">(</span>gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb15-8"><a href="#cb15-8"></a> GValue value <span class="op">=</span> G_VALUE_INIT<span class="op">;</span></span>
|
||||
<span id="cb15-9"><a href="#cb15-9"></a></span>
|
||||
<span id="cb15-10"><a href="#cb15-10"></a> <span class="cf">if</span> <span class="op">(</span>gtk_expression_watch_evaluate <span class="op">(</span>watch<span class="op">,</span> <span class="op">&</span>value<span class="op">))</span></span>
|
||||
<span id="cb15-11"><a href="#cb15-11"></a> g_print <span class="op">(</span><span class="st">"width = %d</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> g_value_get_int <span class="op">(&</span>value<span class="op">));</span></span>
|
||||
<span id="cb15-12"><a href="#cb15-12"></a> <span class="cf">else</span></span>
|
||||
<span id="cb15-13"><a href="#cb15-13"></a> g_print <span class="op">(</span><span class="st">"evaluation failed.</span><span class="sc">\n</span><span class="st">"</span><span class="op">);</span></span>
|
||||
<span id="cb15-14"><a href="#cb15-14"></a><span class="op">}</span></span>
|
||||
<span id="cb15-15"><a href="#cb15-15"></a></span>
|
||||
<span id="cb15-16"><a href="#cb15-16"></a><span class="dt">static</span> <span class="dt">int</span></span>
|
||||
<span id="cb15-17"><a href="#cb15-17"></a>close_request_cb <span class="op">(</span>GtkWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb15-18"><a href="#cb15-18"></a> gtk_expression_watch_unwatch <span class="op">(</span>watch<span class="op">);</span></span>
|
||||
<span id="cb15-19"><a href="#cb15-19"></a> gtk_expression_unref <span class="op">(</span>expression<span class="op">);</span></span>
|
||||
<span id="cb15-20"><a href="#cb15-20"></a> <span class="cf">return</span> false<span class="op">;</span></span>
|
||||
<span id="cb15-21"><a href="#cb15-21"></a><span class="op">}</span></span>
|
||||
<span id="cb15-22"><a href="#cb15-22"></a></span>
|
||||
<span id="cb15-23"><a href="#cb15-23"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb15-24"><a href="#cb15-24"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb15-25"><a href="#cb15-25"></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="cb15-26"><a href="#cb15-26"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb15-27"><a href="#cb15-27"></a><span class="op">}</span></span>
|
||||
<span id="cb15-28"><a href="#cb15-28"></a></span>
|
||||
<span id="cb15-29"><a href="#cb15-29"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb15-30"><a href="#cb15-30"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb15-31"><a href="#cb15-31"></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="cb15-32"><a href="#cb15-32"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb15-33"><a href="#cb15-33"></a></span>
|
||||
<span id="cb15-34"><a href="#cb15-34"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_application_window_new <span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb15-35"><a href="#cb15-35"></a> g_signal_connect <span class="op">(</span>win<span class="op">,</span> <span class="st">"close-request"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>close_request_cb<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb15-36"><a href="#cb15-36"></a></span>
|
||||
<span id="cb15-37"><a href="#cb15-37"></a> expression <span class="op">=</span> gtk_property_expression_new <span class="op">(</span>GTK_TYPE_WINDOW<span class="op">,</span> NULL<span class="op">,</span> <span class="st">"default-width"</span><span class="op">);</span></span>
|
||||
<span id="cb15-38"><a href="#cb15-38"></a> watch <span class="op">=</span> gtk_expression_watch <span class="op">(</span>expression<span class="op">,</span> win<span class="op">,</span> notify<span class="op">,</span> NULL<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb15-39"><a href="#cb15-39"></a><span class="op">}</span></span>
|
||||
<span id="cb15-40"><a href="#cb15-40"></a></span>
|
||||
<span id="cb15-41"><a href="#cb15-41"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.exp_watch"</span></span>
|
||||
<span id="cb15-42"><a href="#cb15-42"></a></span>
|
||||
<span id="cb15-43"><a href="#cb15-43"></a><span class="dt">int</span></span>
|
||||
<span id="cb15-44"><a href="#cb15-44"></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="cb15-45"><a href="#cb15-45"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb15-46"><a href="#cb15-46"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb15-47"><a href="#cb15-47"></a></span>
|
||||
<span id="cb15-48"><a href="#cb15-48"></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="cb15-49"><a href="#cb15-49"></a></span>
|
||||
<span id="cb15-50"><a href="#cb15-50"></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="cb15-51"><a href="#cb15-51"></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="cb15-52"><a href="#cb15-52"></a></span>
|
||||
<span id="cb15-53"><a href="#cb15-53"></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="cb15-54"><a href="#cb15-54"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb15-55"><a href="#cb15-55"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb15-56"><a href="#cb15-56"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>37: A property expression looks up the “default-width” property of
|
||||
the window.</li>
|
||||
|
@ -738,37 +704,36 @@ expressions.</li>
|
|||
content of an object tag. Name attribute specifies the property name of
|
||||
the object. The content is an expression.</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb18"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">constant</span><span class="ot"> type=</span><span class="st">"gchararray"</span>>Hello world</<span class="kw">constant</span>></span>
|
||||
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"label"</span><span class="ot"> type=</span><span class="st">"GtkLabel"</span>>label</<span class="kw">lookup</span>></span>
|
||||
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a><<span class="kw">closure</span><span class="ot"> type=</span><span class="st">"gint"</span><span class="ot"> function=</span><span class="st">"callback_function"</span>></<span class="kw">closure</span>></span>
|
||||
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a><<span class="kw">bind</span><span class="ot"> name=</span><span class="st">"label"</span>></span>
|
||||
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"default-width"</span>>win</<span class="kw">lookup</span>></span>
|
||||
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a></<span class="kw">bind</span>></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb16"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">constant</span><span class="ot"> type=</span><span class="st">"gchararray"</span>>Hello world</<span class="kw">constant</span>></span>
|
||||
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"label"</span><span class="ot"> type=</span><span class="st">"GtkLabel"</span>>label</<span class="kw">lookup</span>></span>
|
||||
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><<span class="kw">closure</span><span class="ot"> type=</span><span class="st">"gint"</span><span class="ot"> function=</span><span class="st">"callback_function"</span>></<span class="kw">closure</span>></span>
|
||||
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a><<span class="kw">bind</span><span class="ot"> name=</span><span class="st">"label"</span>></span>
|
||||
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"default-width"</span>>win</<span class="kw">lookup</span>></span>
|
||||
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a></<span class="kw">bind</span>></span></code></pre></div>
|
||||
<p>These tags are usually used for GtkBuilderListItemFactory.</p>
|
||||
<div class="sourceCode" id="cb19"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> <<span class="kw">template</span><span class="ot"> class=</span><span class="st">"GtkListItem"</span>></span>
|
||||
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"child"</span>></span>
|
||||
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||||
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">binding</span><span class="ot"> name=</span><span class="st">"label"</span>></span>
|
||||
<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"name"</span><span class="ot"> type=</span><span class="st">"string"</span>></span>
|
||||
<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"item"</span>>GtkListItem</<span class="kw">lookup</span>></span>
|
||||
<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a> </<span class="kw">lookup</span>></span>
|
||||
<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a> </<span class="kw">binding</span>></span>
|
||||
<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a> </<span class="kw">property</span>></span>
|
||||
<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a> </<span class="kw">template</span>></span>
|
||||
<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb17"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a> <<span class="kw">template</span><span class="ot"> class=</span><span class="st">"GtkListItem"</span>></span>
|
||||
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"child"</span>></span>
|
||||
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||||
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">binding</span><span class="ot"> name=</span><span class="st">"label"</span>></span>
|
||||
<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"string"</span><span class="ot"> type=</span><span class="st">"GtkStringObject"</span>></span>
|
||||
<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"item"</span>>GtkListItem</<span class="kw">lookup</span>></span>
|
||||
<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a> </<span class="kw">lookup</span>></span>
|
||||
<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a> </<span class="kw">binding</span>></span>
|
||||
<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a> </<span class="kw">property</span>></span>
|
||||
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a> </<span class="kw">template</span>></span>
|
||||
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<p>GtkBuilderListItemFactory uses GtkBuilder to extends the GtkListItem
|
||||
with the XML data.</p>
|
||||
<p>In the xml file above, “GtkListItem” is an instance of the
|
||||
GtkListItem template. It is the ‘this’ object given to the expressions.
|
||||
(The information is in the <a href="https://blog.gtk.org/2020/09/">GTK
|
||||
Development Blog</a>).</p>
|
||||
<p>GtkBuilderListItemFactory uses GtkBuilder to build the XML data. It
|
||||
sets the current object of the GtkBuilder to the GtkListItem
|
||||
instance.</p>
|
||||
<p>GtkBuilder calls <code>gtk_expression_bind</code> function in the
|
||||
binding tag analysis. The function sets the ‘this’ object like this:</p>
|
||||
<p>GtkBuilder calls <code>gtk_expression_bind</code> function when it
|
||||
finds a binding tag. The function sets the ‘this’ object like this:</p>
|
||||
<ol type="1">
|
||||
<li>If the binding tag has object attribute, the object will be the
|
||||
‘this’ object.</li>
|
||||
|
@ -794,41 +759,41 @@ constant tags are not used so often.</p>
|
|||
window. If you type characters in the entry, the same characters appear
|
||||
on the label.</p>
|
||||
<p>The ui file is as follows.</p>
|
||||
<div class="sourceCode" id="cb20"><pre
|
||||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb20-1"><a href="#cb20-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="cb20-2"><a href="#cb20-2"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb20-3"><a href="#cb20-3"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkApplicationWindow"</span><span class="ot"> id=</span><span class="st">"win"</span>></span>
|
||||
<span id="cb20-4"><a href="#cb20-4"></a> <<span class="kw">binding</span><span class="ot"> name=</span><span class="st">"title"</span>></span>
|
||||
<span id="cb20-5"><a href="#cb20-5"></a> <<span class="kw">closure</span><span class="ot"> type=</span><span class="st">"gchararray"</span><span class="ot"> function=</span><span class="st">"set_title"</span>></span>
|
||||
<span id="cb20-6"><a href="#cb20-6"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"default-width"</span><span class="ot"> type=</span><span class="st">"GtkWindow"</span>></<span class="kw">lookup</span>></span>
|
||||
<span id="cb20-7"><a href="#cb20-7"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"default-height"</span><span class="ot"> type=</span><span class="st">"GtkWindow"</span>></<span class="kw">lookup</span>></span>
|
||||
<span id="cb20-8"><a href="#cb20-8"></a> </<span class="kw">closure</span>></span>
|
||||
<span id="cb20-9"><a href="#cb20-9"></a> </<span class="kw">binding</span>></span>
|
||||
<span id="cb20-10"><a href="#cb20-10"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-width"</span>>600</<span class="kw">property</span>></span>
|
||||
<span id="cb20-11"><a href="#cb20-11"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-height"</span>>400</<span class="kw">property</span>></span>
|
||||
<span id="cb20-12"><a href="#cb20-12"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb20-13"><a href="#cb20-13"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span>></span>
|
||||
<span id="cb20-14"><a href="#cb20-14"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_VERTICAL</<span class="kw">property</span>></span>
|
||||
<span id="cb20-15"><a href="#cb20-15"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb20-16"><a href="#cb20-16"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||||
<span id="cb20-17"><a href="#cb20-17"></a> <<span class="kw">binding</span><span class="ot"> name=</span><span class="st">"label"</span>></span>
|
||||
<span id="cb20-18"><a href="#cb20-18"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"text"</span>></span>
|
||||
<span id="cb20-19"><a href="#cb20-19"></a> buffer</span>
|
||||
<span id="cb20-20"><a href="#cb20-20"></a> </<span class="kw">lookup</span>></span>
|
||||
<span id="cb20-21"><a href="#cb20-21"></a> </<span class="kw">binding</span>></span>
|
||||
<span id="cb20-22"><a href="#cb20-22"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb20-23"><a href="#cb20-23"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb20-24"><a href="#cb20-24"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb20-25"><a href="#cb20-25"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkEntry"</span>></span>
|
||||
<span id="cb20-26"><a href="#cb20-26"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"buffer"</span>></span>
|
||||
<span id="cb20-27"><a href="#cb20-27"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkEntryBuffer"</span><span class="ot"> id=</span><span class="st">"buffer"</span>></<span class="kw">object</span>></span>
|
||||
<span id="cb20-28"><a href="#cb20-28"></a> </<span class="kw">property</span>></span>
|
||||
<span id="cb20-29"><a href="#cb20-29"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb20-30"><a href="#cb20-30"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb20-31"><a href="#cb20-31"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb20-32"><a href="#cb20-32"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb20-33"><a href="#cb20-33"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb20-34"><a href="#cb20-34"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb18"><pre
|
||||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb18-1"><a href="#cb18-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="cb18-2"><a href="#cb18-2"></a><<span class="kw">interface</span>></span>
|
||||
<span id="cb18-3"><a href="#cb18-3"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkApplicationWindow"</span><span class="ot"> id=</span><span class="st">"win"</span>></span>
|
||||
<span id="cb18-4"><a href="#cb18-4"></a> <<span class="kw">binding</span><span class="ot"> name=</span><span class="st">"title"</span>></span>
|
||||
<span id="cb18-5"><a href="#cb18-5"></a> <<span class="kw">closure</span><span class="ot"> type=</span><span class="st">"gchararray"</span><span class="ot"> function=</span><span class="st">"set_title"</span>></span>
|
||||
<span id="cb18-6"><a href="#cb18-6"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"default-width"</span><span class="ot"> type=</span><span class="st">"GtkWindow"</span>></<span class="kw">lookup</span>></span>
|
||||
<span id="cb18-7"><a href="#cb18-7"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"default-height"</span><span class="ot"> type=</span><span class="st">"GtkWindow"</span>></<span class="kw">lookup</span>></span>
|
||||
<span id="cb18-8"><a href="#cb18-8"></a> </<span class="kw">closure</span>></span>
|
||||
<span id="cb18-9"><a href="#cb18-9"></a> </<span class="kw">binding</span>></span>
|
||||
<span id="cb18-10"><a href="#cb18-10"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-width"</span>>600</<span class="kw">property</span>></span>
|
||||
<span id="cb18-11"><a href="#cb18-11"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-height"</span>>400</<span class="kw">property</span>></span>
|
||||
<span id="cb18-12"><a href="#cb18-12"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb18-13"><a href="#cb18-13"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span>></span>
|
||||
<span id="cb18-14"><a href="#cb18-14"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_VERTICAL</<span class="kw">property</span>></span>
|
||||
<span id="cb18-15"><a href="#cb18-15"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb18-16"><a href="#cb18-16"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||||
<span id="cb18-17"><a href="#cb18-17"></a> <<span class="kw">binding</span><span class="ot"> name=</span><span class="st">"label"</span>></span>
|
||||
<span id="cb18-18"><a href="#cb18-18"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"text"</span>></span>
|
||||
<span id="cb18-19"><a href="#cb18-19"></a> buffer</span>
|
||||
<span id="cb18-20"><a href="#cb18-20"></a> </<span class="kw">lookup</span>></span>
|
||||
<span id="cb18-21"><a href="#cb18-21"></a> </<span class="kw">binding</span>></span>
|
||||
<span id="cb18-22"><a href="#cb18-22"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb18-23"><a href="#cb18-23"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb18-24"><a href="#cb18-24"></a> <<span class="kw">child</span>></span>
|
||||
<span id="cb18-25"><a href="#cb18-25"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkEntry"</span>></span>
|
||||
<span id="cb18-26"><a href="#cb18-26"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"buffer"</span>></span>
|
||||
<span id="cb18-27"><a href="#cb18-27"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkEntryBuffer"</span><span class="ot"> id=</span><span class="st">"buffer"</span>></<span class="kw">object</span>></span>
|
||||
<span id="cb18-28"><a href="#cb18-28"></a> </<span class="kw">property</span>></span>
|
||||
<span id="cb18-29"><a href="#cb18-29"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb18-30"><a href="#cb18-30"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb18-31"><a href="#cb18-31"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb18-32"><a href="#cb18-32"></a> </<span class="kw">child</span>></span>
|
||||
<span id="cb18-33"><a href="#cb18-33"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb18-34"><a href="#cb18-34"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||||
<ul>
|
||||
<li>4-9: The title property of the main window is bound to a closure
|
||||
expression. Its callback function <code>set_title</code> is defined in
|
||||
|
@ -844,48 +809,48 @@ defined in line 25. If a user types characters in the entry, the same
|
|||
characters appear on the label.</li>
|
||||
</ul>
|
||||
<p>The C source file is as follows.</p>
|
||||
<div class="sourceCode" id="cb21"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb21-1"><a href="#cb21-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb21-2"><a href="#cb21-2"></a></span>
|
||||
<span id="cb21-3"><a href="#cb21-3"></a><span class="dt">char</span> <span class="op">*</span></span>
|
||||
<span id="cb21-4"><a href="#cb21-4"></a>set_title <span class="op">(</span>GtkWidget <span class="op">*</span>win<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 class="op">{</span></span>
|
||||
<span id="cb21-5"><a href="#cb21-5"></a> <span class="cf">return</span> g_strdup_printf <span class="op">(</span><span class="st">"%d x %d"</span><span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
|
||||
<span id="cb21-6"><a href="#cb21-6"></a><span class="op">}</span></span>
|
||||
<span id="cb21-7"><a href="#cb21-7"></a></span>
|
||||
<span id="cb21-8"><a href="#cb21-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb21-9"><a href="#cb21-9"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb21-10"><a href="#cb21-10"></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="cb21-11"><a href="#cb21-11"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb21-12"><a href="#cb21-12"></a><span class="op">}</span></span>
|
||||
<span id="cb21-13"><a href="#cb21-13"></a></span>
|
||||
<span id="cb21-14"><a href="#cb21-14"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb21-15"><a href="#cb21-15"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb21-16"><a href="#cb21-16"></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="cb21-17"><a href="#cb21-17"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||||
<span id="cb21-18"><a href="#cb21-18"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb21-19"><a href="#cb21-19"></a></span>
|
||||
<span id="cb21-20"><a href="#cb21-20"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/exp/exp.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb21-21"><a href="#cb21-21"></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="cb21-22"><a href="#cb21-22"></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="cb21-23"><a href="#cb21-23"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
|
||||
<span id="cb21-24"><a href="#cb21-24"></a><span class="op">}</span></span>
|
||||
<span id="cb21-25"><a href="#cb21-25"></a></span>
|
||||
<span id="cb21-26"><a href="#cb21-26"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.exp"</span></span>
|
||||
<span id="cb21-27"><a href="#cb21-27"></a></span>
|
||||
<span id="cb21-28"><a href="#cb21-28"></a><span class="dt">int</span></span>
|
||||
<span id="cb21-29"><a href="#cb21-29"></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="cb21-30"><a href="#cb21-30"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb21-31"><a href="#cb21-31"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb21-32"><a href="#cb21-32"></a></span>
|
||||
<span id="cb21-33"><a href="#cb21-33"></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="cb21-34"><a href="#cb21-34"></a></span>
|
||||
<span id="cb21-35"><a href="#cb21-35"></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="cb21-36"><a href="#cb21-36"></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="cb21-37"><a href="#cb21-37"></a></span>
|
||||
<span id="cb21-38"><a href="#cb21-38"></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="cb21-39"><a href="#cb21-39"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb21-40"><a href="#cb21-40"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb21-41"><a href="#cb21-41"></a><span class="op">}</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb19"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb19-1"><a href="#cb19-1"></a><span class="pp">#include </span><span class="im"><gtk/gtk.h></span></span>
|
||||
<span id="cb19-2"><a href="#cb19-2"></a></span>
|
||||
<span id="cb19-3"><a href="#cb19-3"></a><span class="dt">char</span> <span class="op">*</span></span>
|
||||
<span id="cb19-4"><a href="#cb19-4"></a>set_title <span class="op">(</span>GtkWidget <span class="op">*</span>win<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 class="op">{</span></span>
|
||||
<span id="cb19-5"><a href="#cb19-5"></a> <span class="cf">return</span> g_strdup_printf <span class="op">(</span><span class="st">"%d x %d"</span><span class="op">,</span> width<span class="op">,</span> height<span class="op">);</span></span>
|
||||
<span id="cb19-6"><a href="#cb19-6"></a><span class="op">}</span></span>
|
||||
<span id="cb19-7"><a href="#cb19-7"></a></span>
|
||||
<span id="cb19-8"><a href="#cb19-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb19-9"><a href="#cb19-9"></a>app_activate <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb19-10"><a href="#cb19-10"></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="cb19-11"><a href="#cb19-11"></a> gtk_window_present <span class="op">(</span>gtk_application_get_active_window<span class="op">(</span>app<span class="op">));</span></span>
|
||||
<span id="cb19-12"><a href="#cb19-12"></a><span class="op">}</span></span>
|
||||
<span id="cb19-13"><a href="#cb19-13"></a></span>
|
||||
<span id="cb19-14"><a href="#cb19-14"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb19-15"><a href="#cb19-15"></a>app_startup <span class="op">(</span>GApplication <span class="op">*</span>application<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb19-16"><a href="#cb19-16"></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="cb19-17"><a href="#cb19-17"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||||
<span id="cb19-18"><a href="#cb19-18"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
|
||||
<span id="cb19-19"><a href="#cb19-19"></a></span>
|
||||
<span id="cb19-20"><a href="#cb19-20"></a> build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/exp/exp.ui"</span><span class="op">);</span></span>
|
||||
<span id="cb19-21"><a href="#cb19-21"></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="cb19-22"><a href="#cb19-22"></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="cb19-23"><a href="#cb19-23"></a> g_object_unref <span class="op">(</span>build<span class="op">);</span></span>
|
||||
<span id="cb19-24"><a href="#cb19-24"></a><span class="op">}</span></span>
|
||||
<span id="cb19-25"><a href="#cb19-25"></a></span>
|
||||
<span id="cb19-26"><a href="#cb19-26"></a><span class="pp">#define APPLICATION_ID "com.github.ToshioCP.exp"</span></span>
|
||||
<span id="cb19-27"><a href="#cb19-27"></a></span>
|
||||
<span id="cb19-28"><a href="#cb19-28"></a><span class="dt">int</span></span>
|
||||
<span id="cb19-29"><a href="#cb19-29"></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="cb19-30"><a href="#cb19-30"></a> GtkApplication <span class="op">*</span>app<span class="op">;</span></span>
|
||||
<span id="cb19-31"><a href="#cb19-31"></a> <span class="dt">int</span> stat<span class="op">;</span></span>
|
||||
<span id="cb19-32"><a href="#cb19-32"></a></span>
|
||||
<span id="cb19-33"><a href="#cb19-33"></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="cb19-34"><a href="#cb19-34"></a></span>
|
||||
<span id="cb19-35"><a href="#cb19-35"></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="cb19-36"><a href="#cb19-36"></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="cb19-37"><a href="#cb19-37"></a></span>
|
||||
<span id="cb19-38"><a href="#cb19-38"></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="cb19-39"><a href="#cb19-39"></a> g_object_unref <span class="op">(</span>app<span class="op">);</span></span>
|
||||
<span id="cb19-40"><a href="#cb19-40"></a> <span class="cf">return</span> stat<span class="op">;</span></span>
|
||||
<span id="cb19-41"><a href="#cb19-41"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>4-6: The callback function. It returns a string (w)x(h), where the w
|
||||
and h are the width and height of the window. String duplication is
|
||||
|
@ -893,18 +858,18 @@ necessary.</li>
|
|||
</ul>
|
||||
<p>The C source file is very simple because almost everything is done in
|
||||
the ui file.</p>
|
||||
<h3 id="conversion-between-gvalues">Conversion between GValues</h3>
|
||||
<h2 id="conversion-between-gvalues">Conversion between GValues</h2>
|
||||
<p>If you bind different type properties, type conversion is
|
||||
automatically done. Suppose a label property (string) is bound to
|
||||
default-width property (int).</p>
|
||||
<div class="sourceCode" id="cb22"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||||
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a> <<span class="kw">binding</span><span class="ot"> name=</span><span class="st">"label"</span>></span>
|
||||
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"default-width"</span>></span>
|
||||
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a> win</span>
|
||||
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true" tabindex="-1"></a> </<span class="kw">lookup</span>></span>
|
||||
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true" tabindex="-1"></a> </<span class="kw">binding</span>></span>
|
||||
<span id="cb22-7"><a href="#cb22-7" aria-hidden="true" tabindex="-1"></a></<span class="kw">object</span>></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb20"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||||
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a> <<span class="kw">binding</span><span class="ot"> name=</span><span class="st">"label"</span>></span>
|
||||
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">lookup</span><span class="ot"> name=</span><span class="st">"default-width"</span>></span>
|
||||
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> win</span>
|
||||
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a> </<span class="kw">lookup</span>></span>
|
||||
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a> </<span class="kw">binding</span>></span>
|
||||
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a></<span class="kw">object</span>></span></code></pre></div>
|
||||
<p>The expression created by the lookup tag returns a int type GValue.
|
||||
On the other hand “label” property holds a string type GValue. When a
|
||||
GValue is copied to another GValue, the type is automatically converted
|
||||
|
@ -912,6 +877,37 @@ if possible. If the current width is 100, an int <code>100</code> is
|
|||
converted to a string <code>"100"</code>.</p>
|
||||
<p>If you use <code>g_object_get</code> and <code>g_object_set</code> to
|
||||
copy properties, the value is automatically converted.</p>
|
||||
<h2 id="meson.build">Meson.build</h2>
|
||||
<p>The source files are in <code>src/expression</code> directory. You
|
||||
can build all the files at once.</p>
|
||||
<pre><code>$ cd src/expression
|
||||
$ meson setup _build
|
||||
$ ninja -C _build</code></pre>
|
||||
<p>For example, if you want to run “exp”, which is the executable file
|
||||
from “exp.c”, type <code>_build/exp</code>. You can run other programs
|
||||
as well.</p>
|
||||
<p>The file <code>meson.build</code> is as follows.</p>
|
||||
<div class="sourceCode" id="cb22"><pre
|
||||
class="sourceCode numberSource numberLines"><code class="sourceCode"><span id="cb22-1"><a href="#cb22-1"></a>project('exp', 'c')</span>
|
||||
<span id="cb22-2"><a href="#cb22-2"></a></span>
|
||||
<span id="cb22-3"><a href="#cb22-3"></a>gtkdep = dependency('gtk4')</span>
|
||||
<span id="cb22-4"><a href="#cb22-4"></a></span>
|
||||
<span id="cb22-5"><a href="#cb22-5"></a>gnome=import('gnome')</span>
|
||||
<span id="cb22-6"><a href="#cb22-6"></a>resources = gnome.compile_resources('resources','exp.gresource.xml')</span>
|
||||
<span id="cb22-7"><a href="#cb22-7"></a></span>
|
||||
<span id="cb22-8"><a href="#cb22-8"></a>sourcefiles=files('exp.c')</span>
|
||||
<span id="cb22-9"><a href="#cb22-9"></a></span>
|
||||
<span id="cb22-10"><a href="#cb22-10"></a>executable('exp', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-11"><a href="#cb22-11"></a>executable('exp_constant', 'exp_constant.c', dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-12"><a href="#cb22-12"></a>executable('exp_constant_simple', 'exp_constant_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-13"><a href="#cb22-13"></a>executable('exp_property_simple', 'exp_property_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-14"><a href="#cb22-14"></a>executable('closure', 'closure.c', dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-15"><a href="#cb22-15"></a>executable('closure_each', 'closure_each.c', dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-16"><a href="#cb22-16"></a>executable('exp_closure_simple', 'exp_closure_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-17"><a href="#cb22-17"></a>executable('exp_closure_with_error_report', 'exp_closure_with_error_report.c', dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-18"><a href="#cb22-18"></a>executable('exp_bind', 'exp_bind.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-19"><a href="#cb22-19"></a>executable('exp_watch', 'exp_watch.c', dependencies: gtkdep, export_dynamic: true, install: false)</span>
|
||||
<span id="cb22-20"><a href="#cb22-20"></a>executable('exp_test', 'exp_test.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)</span></code></pre></div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
|
|
|
@ -328,10 +328,9 @@ header of the column.</li>
|
|||
as much as possible. (See the image above).</li>
|
||||
<li>33- 69: Sets the “factory” property to GtkBuilderListItemFactory.
|
||||
The factory has “bytes” property which holds a ui string to define a
|
||||
template to build GtkListItem composite widget. The CDATA section (line
|
||||
36-66) is the ui string to put into the “bytes” property. The contents
|
||||
are the same as the ui file <code>factory_list.ui</code> in the section
|
||||
27.</li>
|
||||
template to extend GtkListItem class. The CDATA section (line 36-66) is
|
||||
the ui string to put into the “bytes” property. The contents are the
|
||||
same as the ui file <code>factory_list.ui</code> in the section 30.</li>
|
||||
<li>70-77: Sets the “sorter” property to GtkStringSorter object. This
|
||||
object provides a sorter that compares strings. It has “expression”
|
||||
property. A closure tag with a string type function
|
||||
|
@ -542,7 +541,8 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<h2 id="compilation-and-execution.">Compilation and execution.</h2>
|
||||
<p>All the source files are in <code>src/column</code> directory. Change
|
||||
your current directory to the directory and type the following.</p>
|
||||
<pre><code>$ meson _build
|
||||
<pre><code>$ cd src/colomn
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/column</code></pre>
|
||||
<p>Then, a window appears.</p>
|
||||
|
|
393
docs/sec33.html
393
docs/sec33.html
|
@ -116,25 +116,14 @@ and GtkBulderListItemFactory</h2>
|
|||
the contents of a list. Its binding direction is always from an item of
|
||||
a list to a child of GtkListItem.</p>
|
||||
<p>When it comes to dynamic connection, it’s not enough. For example,
|
||||
you want to edit the contents of a list. You set a child of GtkListItem
|
||||
to a GtkText instance so a user can edit a text with it. You need to
|
||||
bind an item in the list with the buffer of the GtkText. The direction
|
||||
is opposite from the one with GtkBuilderListItemFactory. It is from the
|
||||
GtkText instance to the item in the list. You can implement this with
|
||||
GtkSignalListItemFactory, which is more flexible than
|
||||
suppose you want to edit the contents of a list. You set a child of
|
||||
GtkListItem to a GtkText instance so a user can edit a text with it. You
|
||||
need to bind an item in the list with the buffer of the GtkText. The
|
||||
direction is opposite from the one with GtkBuilderListItemFactory. It is
|
||||
from the GtkText instance to the item in the list. You can implement
|
||||
this with GtkSignalListItemFactory, which is more flexible than
|
||||
GtkBuilderListItemFactory.</p>
|
||||
<p>Two things are shown in this section.</p>
|
||||
<ul>
|
||||
<li>Binding from a child of a GtkListItem instance to an item of a
|
||||
list.</li>
|
||||
<li>Access a child of GtkListItem dynamically. This direction is the
|
||||
same as the one with GtkBulderListItemFactory. But
|
||||
GtkBulderListItemFactory uses GtkExpression from the item property of
|
||||
the GtkListItem. So, it updates its child widget only when the item
|
||||
property changes. In this example the child reflects the change in the
|
||||
same item in the list dynamically.</li>
|
||||
</ul>
|
||||
<p>This section shows just a part of the source file
|
||||
<p>This section shows just some parts of the source file
|
||||
<code>listeditor.c</code>. If you want to see the whole codes, see
|
||||
<code>src/listeditor</code> directory of the <a
|
||||
href="https://github.com/ToshioCP/Gtk4-tutorial">Gtk4 tutorial
|
||||
|
@ -143,7 +132,7 @@ repository</a>.</p>
|
|||
<p>The sample program is a list editor and data of the list are strings.
|
||||
It’s the same as a line editor. It reads a text file line by line. Each
|
||||
line is an item of the list. The list is displayed with GtkColumnView.
|
||||
There are two columns. The one is a button, which makes the line be a
|
||||
There are two columns. The one is a button, which shows if the line is a
|
||||
current line. If the line is the current line, the button is colored
|
||||
with red. The other is a string which is the contents of the
|
||||
corresponding item of the list.</p>
|
||||
|
@ -159,18 +148,19 @@ href="https://github.com/ToshioCP/Gtk4-tutorial">repository</a>.</li>
|
|||
<li>Change your current directory to <code>src/listeditor</code>.</li>
|
||||
<li>Type the following on your commandline.</li>
|
||||
</ul>
|
||||
<pre><code>$ meson _build
|
||||
<pre><code>$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/listeditor</code></pre>
|
||||
<ul>
|
||||
<li>Append button: appends a line after the current line, or at the last
|
||||
line if no current line exists.</li>
|
||||
<li>Insert button: inserts a line before the current line.</li>
|
||||
<li>Insert button: inserts a line before the current line, or at the top
|
||||
line if no current line exists.</li>
|
||||
<li>Remove button: removes a current line.</li>
|
||||
<li>Read button: reads a file.</li>
|
||||
<li>Write button: writes the contents to a file.</li>
|
||||
<li>close button: close the contents.</li>
|
||||
<li>quit button: quit the application.</li>
|
||||
<li>close button: closes the contents.</li>
|
||||
<li>quit button: quits the application.</li>
|
||||
<li>Button on the select column: makes the line current.</li>
|
||||
<li>String column: GtkText. You can edit a string in the field.</li>
|
||||
</ul>
|
||||
|
@ -180,7 +170,7 @@ bar. The file name is shown at the right of the write button.</p>
|
|||
GtkText instance and an item in the list</h2>
|
||||
<p>The second column (GtkColumnViewColumn) sets its factory property to
|
||||
GtkSignalListItemFactory. It uses three signals setup, bind and unbind.
|
||||
The following is their sgnal handlers.</p>
|
||||
The following shows the signal handlers.</p>
|
||||
<div class="sourceCode" id="cb2"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb2-2"><a href="#cb2-2"></a>setup2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
|
@ -193,7 +183,7 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb2-9"><a href="#cb2-9"></a>bind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb2-10"><a href="#cb2-10"></a> GtkWidget <span class="op">*</span>text <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
|
||||
<span id="cb2-11"><a href="#cb2-11"></a> GtkEntryBuffer <span class="op">*</span>buffer <span class="op">=</span> gtk_text_get_buffer <span class="op">(</span>GTK_TEXT <span class="op">(</span>text<span class="op">));</span></span>
|
||||
<span id="cb2-12"><a href="#cb2-12"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb2-12"><a href="#cb2-12"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item<span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb2-13"><a href="#cb2-13"></a> GBinding <span class="op">*</span>bind<span class="op">;</span></span>
|
||||
<span id="cb2-14"><a href="#cb2-14"></a></span>
|
||||
<span id="cb2-15"><a href="#cb2-15"></a> gtk_editable_set_text <span class="op">(</span>GTK_EDITABLE <span class="op">(</span>text<span class="op">),</span> le_data_look_string <span class="op">(</span>data<span class="op">));</span></span>
|
||||
|
@ -207,9 +197,10 @@ class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span i
|
|||
<span id="cb2-23"><a href="#cb2-23"></a>unbind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb2-24"><a href="#cb2-24"></a> GBinding <span class="op">*</span>bind <span class="op">=</span> G_BINDING <span class="op">(</span>g_object_get_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">"bind"</span><span class="op">));</span></span>
|
||||
<span id="cb2-25"><a href="#cb2-25"></a></span>
|
||||
<span id="cb2-26"><a href="#cb2-26"></a> g_binding_unbind<span class="op">(</span>bind<span class="op">);</span></span>
|
||||
<span id="cb2-27"><a href="#cb2-27"></a> g_object_set_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">"bind"</span><span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb2-28"><a href="#cb2-28"></a><span class="op">}</span></span></code></pre></div>
|
||||
<span id="cb2-26"><a href="#cb2-26"></a> <span class="cf">if</span> <span class="op">(</span>bind<span class="op">)</span></span>
|
||||
<span id="cb2-27"><a href="#cb2-27"></a> g_binding_unbind<span class="op">(</span>bind<span class="op">);</span></span>
|
||||
<span id="cb2-28"><a href="#cb2-28"></a> g_object_set_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">"bind"</span><span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb2-29"><a href="#cb2-29"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>1-6: <code>setup2_cb</code> is a setup signal handler on the
|
||||
GtkSignalListItemFactory. This factory is inserted to the factory
|
||||
|
@ -221,22 +212,18 @@ is destroyed. So, teardown signal handler isn’t necessary.</li>
|
|||
when the <code>listitem</code> is bound to an item in the list. The list
|
||||
items are LeData instances. LeData is defined in the file
|
||||
<code>listeditor.c</code> (the C source file of the list editor). It is
|
||||
a child class of GObject and has two data. The one is
|
||||
<code>listitem</code> which points a first column GtkListItem instance
|
||||
when they are connected. Be careful that the GtkListItem instance is
|
||||
<em>not</em> the <code>listitem</code> in this handler. If no
|
||||
GtkListItem is connected, it is NULL. The other is <code>string</code>
|
||||
which is a content of the line.
|
||||
a child class of GObject and has string data which is the content of the
|
||||
line.
|
||||
<ul>
|
||||
<li>10-11: <code>text</code> is a child of the <code>listitem</code> and
|
||||
it is a GtkText instance. And <code>buffer</code> is a GtkTextBuffer
|
||||
it is a GtkText instance. And <code>buffer</code> is a GtkEntryBuffer
|
||||
instance of the <code>text</code>.</li>
|
||||
<li>12: The LeData instance <code>data</code> is an item pointed by the
|
||||
<code>listitem</code>.</li>
|
||||
<li>15-16: Sets the text of <code>text</code> to
|
||||
<code>le_data_look_string (data)</code>. le_data_look_string returns the
|
||||
string of the <code>data</code> and the ownership of the string is still
|
||||
taken by the <code>data</code>. So, the caller don’t need to free the
|
||||
taken by the <code>data</code>. So, the caller doesn’t need to free the
|
||||
string.</li>
|
||||
<li>18: <code>g_object_bind_property</code> binds a property and another
|
||||
object property. This line binds the “text” property of the
|
||||
|
@ -254,16 +241,22 @@ value. This line sets the association from “bind” to <code>bind</code>
|
|||
instance. It makes possible for the “unbind” handler to get the
|
||||
<code>bind</code> instance.</li>
|
||||
</ul></li>
|
||||
<li>22-28: <code>unbind2_cb</code> is a unbind signal handler.
|
||||
<li>22-29: <code>unbind2_cb</code> is a unbind signal handler.
|
||||
<ul>
|
||||
<li>24: Retrieves the <code>bind</code> instance from the table in the
|
||||
<code>listitem</code> instance.</li>
|
||||
<li>26: Unbind the binding.</li>
|
||||
<li>27: Removes the value corresponds to the “bind” key.</li>
|
||||
<li>26-27: Unbind the binding.</li>
|
||||
<li>28: Removes the value corresponds to the “bind” key.</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
<p>This technique is not so complicated. You can use it when you make a
|
||||
cell editable application.</p>
|
||||
<p>If it is impossible to use <code>g_object_bind_property</code>, use a
|
||||
notify signal on the GtkEntryBuffer instance. You can use “deleted-text”
|
||||
and “inserted-text” signal instead. The handler of the signals above
|
||||
copies the text in the GtkEntryBuffer instance to the LeData string.
|
||||
Connect the notify signal handler in <code>bind2_cb</code> and
|
||||
disconnect it in <code>unbind2_cb</code>.</p>
|
||||
<h2 id="change-the-cell-of-gtkcolumnview-dynamically">Change the cell of
|
||||
GtkColumnView dynamically</h2>
|
||||
<p>Next topic is to change the GtkColumnView (or GtkListView) cells
|
||||
|
@ -289,164 +282,148 @@ GtkSingleSelection selects a line on the display. The current line
|
|||
doesn’t need to be on the display. It is possible to be on the line out
|
||||
of the Window (GtkScrolledWindow). Actually, the program doesn’t use
|
||||
GtkSingleSelection.</p>
|
||||
<p>It is necessary to know the corresponding GtkListItem instance from
|
||||
the item in the list. It is the opposite direction from
|
||||
<code>gtk_list_item_get_item</code> function. To accomplish this, we set
|
||||
a <code>listitem</code> element of LeData to point the corresponding
|
||||
GtkListItem instance. Therefore, items (LeData) in the list always know
|
||||
the GtkListItem. If there’s no GtkListItem bound to the item, NULL is
|
||||
assigned.</p>
|
||||
<p>The LeWindow instance has two instance variables for recording the
|
||||
current line.</p>
|
||||
<ul>
|
||||
<li><code>win->position</code>: An int type variable. It is the
|
||||
position of the current line. It is zero-based. If no current line
|
||||
exists, it is -1.</li>
|
||||
<li><code>win->current_button</code>: A variable points the button,
|
||||
located at the first column, on the current line. If no current line
|
||||
exists, it is NULL.</li>
|
||||
</ul>
|
||||
<p>If the current line moves, the following two functions are called.
|
||||
They updates the two varables.</p>
|
||||
<div class="sourceCode" id="cb3"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="dt">void</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a>select_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>gtk_widget_get_ancestor <span class="op">(</span>GTK_WIDGET <span class="op">(</span>btn<span class="op">),</span> LE_TYPE_WINDOW<span class="op">));</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>update_current_position <span class="op">(</span>LeWindow <span class="op">*</span>win<span class="op">,</span> <span class="dt">int</span> new<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a></span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a> update_current <span class="op">(</span>win<span class="op">,</span> gtk_list_item_get_position <span class="op">(</span>listitem<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>
|
||||
<span id="cb3-8"><a href="#cb3-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-9"><a href="#cb3-9"></a>setup1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-10"><a href="#cb3-10"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_button_new <span class="op">();</span></span>
|
||||
<span id="cb3-11"><a href="#cb3-11"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> button<span class="op">);</span></span>
|
||||
<span id="cb3-12"><a href="#cb3-12"></a> gtk_widget_set_focusable <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> FALSE<span class="op">);</span></span>
|
||||
<span id="cb3-13"><a href="#cb3-13"></a> g_signal_connect <span class="op">(</span>button<span class="op">,</span> <span class="st">"clicked"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>select_cb<span class="op">),</span> listitem<span class="op">);</span></span>
|
||||
<span id="cb3-14"><a href="#cb3-14"></a><span class="op">}</span></span>
|
||||
<span id="cb3-15"><a href="#cb3-15"></a></span>
|
||||
<span id="cb3-16"><a href="#cb3-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-17"><a href="#cb3-17"></a>bind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-18"><a href="#cb3-18"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb3-19"><a href="#cb3-19"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
|
||||
<span id="cb3-20"><a href="#cb3-20"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span>
|
||||
<span id="cb3-21"><a href="#cb3-21"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">"current"</span><span class="op">,</span> NULL<span class="op">};</span></span>
|
||||
<span id="cb3-22"><a href="#cb3-22"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb3-23"><a href="#cb3-23"></a></span>
|
||||
<span id="cb3-24"><a href="#cb3-24"></a> <span class="cf">if</span> <span class="op">(</span>data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-25"><a href="#cb3-25"></a> le_data_set_listitem <span class="op">(</span>data<span class="op">,</span> listitem<span class="op">);</span></span>
|
||||
<span id="cb3-26"><a href="#cb3-26"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">==</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">))</span></span>
|
||||
<span id="cb3-27"><a href="#cb3-27"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> current<span class="op">);</span></span>
|
||||
<span id="cb3-28"><a href="#cb3-28"></a> <span class="cf">else</span></span>
|
||||
<span id="cb3-29"><a href="#cb3-29"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> non_current<span class="op">);</span></span>
|
||||
<span id="cb3-30"><a href="#cb3-30"></a> <span class="op">}</span></span>
|
||||
<span id="cb3-31"><a href="#cb3-31"></a><span class="op">}</span></span>
|
||||
<span id="cb3-32"><a href="#cb3-32"></a></span>
|
||||
<span id="cb3-33"><a href="#cb3-33"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-34"><a href="#cb3-34"></a>unbind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-35"><a href="#cb3-35"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb3-36"><a href="#cb3-36"></a> <span class="cf">if</span> <span class="op">(</span>data<span class="op">)</span></span>
|
||||
<span id="cb3-37"><a href="#cb3-37"></a> le_data_set_listitem <span class="op">(</span>data<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb3-38"><a href="#cb3-38"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>8-14: <code>setup1_cb</code> is a setup signal handler on the
|
||||
GtkSignalListItemFactory. This factory is inserted to the factory
|
||||
property of the first GtkColumnViewColumn. It sets the child of
|
||||
<code>listitem</code> to a GtkButton instance. The “clicked” signal on
|
||||
the button is connected to the handler <code>select_cb</code>. When the
|
||||
listitem is destroyed, the child (GtkButton) is also destroyed. At the
|
||||
same time, the connection of the signal and the handler is also
|
||||
destroyed. So, you don’t need teardown signal handler.</li>
|
||||
<li>1-6: <code>select_cb</code> is a “clicked” signal handler. LeWindow
|
||||
is defined in <code>listeditor.c</code>. It’s a child class of
|
||||
GtkApplicationWindow. The handler just calls the
|
||||
<code>update_current</code> function. The function will be explained
|
||||
later.</li>
|
||||
<li>16-31: <code>bind1_cb</code> is a bind signal handler. It sets the
|
||||
“listitem” element of the item (LeData) to point the
|
||||
<code>listitem</code> (GtkListItem instance). It makes the item possible
|
||||
to find the corresponding GtkListItem instance. If the item is the
|
||||
current line, the CSS class of the button includes “current” class.
|
||||
Otherwise it has no CSS class. This is necessary because the button may
|
||||
be recycled and it has had former CSS class. The class need to be
|
||||
updated.</li>
|
||||
<li>33-38: <code>unbind1_cb</code> is an unbind signal handler. It
|
||||
removes the <code>listitem</code> instance from the “listitem” element
|
||||
of the item. The element becomes NULL, which tells no GtkListItem is
|
||||
bound. When referring GtkListItem, it needs to check the “listitem”
|
||||
element whether it points a GtkListItem or not (NULL). Otherwise bad
|
||||
things will happen.</li>
|
||||
</ul>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a> win<span class="op">-></span>position <span class="op">=</span> new<span class="op">;</span></span>
|
||||
<span id="cb3-6"><a href="#cb3-6"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">>=</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb3-7"><a href="#cb3-7"></a> s <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">"%d"</span><span class="op">,</span> win<span class="op">-></span>position<span class="op">);</span></span>
|
||||
<span id="cb3-8"><a href="#cb3-8"></a> <span class="cf">else</span></span>
|
||||
<span id="cb3-9"><a href="#cb3-9"></a> s <span class="op">=</span> <span class="st">""</span><span class="op">;</span></span>
|
||||
<span id="cb3-10"><a href="#cb3-10"></a> gtk_label_set_text <span class="op">(</span>GTK_LABEL <span class="op">(</span>win<span class="op">-></span>position_label<span class="op">),</span> s<span class="op">);</span></span>
|
||||
<span id="cb3-11"><a href="#cb3-11"></a> <span class="cf">if</span> <span class="op">(*</span>s<span class="op">)</span> <span class="co">// s isn't an empty string</span></span>
|
||||
<span id="cb3-12"><a href="#cb3-12"></a> g_free <span class="op">(</span>s<span class="op">);</span></span>
|
||||
<span id="cb3-13"><a href="#cb3-13"></a><span class="op">}</span></span>
|
||||
<span id="cb3-14"><a href="#cb3-14"></a></span>
|
||||
<span id="cb3-15"><a href="#cb3-15"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-16"><a href="#cb3-16"></a>update_current_button <span class="op">(</span>LeWindow <span class="op">*</span>win<span class="op">,</span> GtkButton <span class="op">*</span>new_button<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-17"><a href="#cb3-17"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span>
|
||||
<span id="cb3-18"><a href="#cb3-18"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">"current"</span><span class="op">,</span> NULL<span class="op">};</span></span>
|
||||
<span id="cb3-19"><a href="#cb3-19"></a></span>
|
||||
<span id="cb3-20"><a href="#cb3-20"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>current_button<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-21"><a href="#cb3-21"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">-></span>current_button<span class="op">),</span> non_current<span class="op">);</span></span>
|
||||
<span id="cb3-22"><a href="#cb3-22"></a> g_object_unref <span class="op">(</span>win<span class="op">-></span>current_button<span class="op">);</span></span>
|
||||
<span id="cb3-23"><a href="#cb3-23"></a> <span class="op">}</span></span>
|
||||
<span id="cb3-24"><a href="#cb3-24"></a> win<span class="op">-></span>current_button <span class="op">=</span> new_button<span class="op">;</span></span>
|
||||
<span id="cb3-25"><a href="#cb3-25"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>current_button<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-26"><a href="#cb3-26"></a> g_object_ref <span class="op">(</span>win<span class="op">-></span>current_button<span class="op">);</span></span>
|
||||
<span id="cb3-27"><a href="#cb3-27"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>win<span class="op">-></span>current_button<span class="op">),</span> current<span class="op">);</span></span>
|
||||
<span id="cb3-28"><a href="#cb3-28"></a> <span class="op">}</span></span>
|
||||
<span id="cb3-29"><a href="#cb3-29"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The varable <code>win->position_label</code> points a GtkLabel
|
||||
instance. The label shows the current line position.</p>
|
||||
<p>The current button has CSS “current” class. The button is colored red
|
||||
through the CSS “button.current {background: red;}”.</p>
|
||||
<p>The order of the call for these two functions is important. The first
|
||||
function, which updates the position, is usually called first. After
|
||||
that, a new line is appended or inserted. Then, the second function is
|
||||
called.</p>
|
||||
<p>The following functions call the two functions above. Be careful
|
||||
about the order of the call.</p>
|
||||
<div class="sourceCode" id="cb4"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a>update_current <span class="op">(</span>LeWindow <span class="op">*</span>win<span class="op">,</span> <span class="dt">int</span> new<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a> LeData <span class="op">*</span>data<span class="op">;</span></span>
|
||||
<span id="cb4-5"><a href="#cb4-5"></a> GtkListItem <span class="op">*</span>listitem<span class="op">;</span></span>
|
||||
<span id="cb4-6"><a href="#cb4-6"></a> GtkButton <span class="op">*</span>button<span class="op">;</span></span>
|
||||
<span id="cb4-7"><a href="#cb4-7"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span>
|
||||
<span id="cb4-8"><a href="#cb4-8"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">"current"</span><span class="op">,</span> NULL<span class="op">};</span></span>
|
||||
<span id="cb4-9"><a href="#cb4-9"></a></span>
|
||||
<span id="cb4-10"><a href="#cb4-10"></a> <span class="cf">if</span> <span class="op">(</span>new <span class="op">>=</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb4-11"><a href="#cb4-11"></a> s <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">"%d"</span><span class="op">,</span> new<span class="op">);</span></span>
|
||||
<span id="cb4-12"><a href="#cb4-12"></a> <span class="cf">else</span></span>
|
||||
<span id="cb4-13"><a href="#cb4-13"></a> s <span class="op">=</span> <span class="st">""</span><span class="op">;</span></span>
|
||||
<span id="cb4-14"><a href="#cb4-14"></a> gtk_label_set_text <span class="op">(</span>GTK_LABEL <span class="op">(</span>win<span class="op">-></span>position_label<span class="op">),</span> s<span class="op">);</span></span>
|
||||
<span id="cb4-15"><a href="#cb4-15"></a> <span class="cf">if</span> <span class="op">(*</span>s<span class="op">)</span> <span class="co">// s isn't an empty string</span></span>
|
||||
<span id="cb4-16"><a href="#cb4-16"></a> g_free <span class="op">(</span>s<span class="op">);</span></span>
|
||||
<span id="cb4-17"><a href="#cb4-17"></a></span>
|
||||
<span id="cb4-18"><a href="#cb4-18"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">>=</span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-19"><a href="#cb4-19"></a> data <span class="op">=</span> LE_DATA <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">),</span> win<span class="op">-></span>position<span class="op">));</span></span>
|
||||
<span id="cb4-20"><a href="#cb4-20"></a> <span class="cf">if</span> <span class="op">((</span>listitem <span class="op">=</span> le_data_get_listitem <span class="op">(</span>data<span class="op">))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-21"><a href="#cb4-21"></a> button <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb4-22"><a href="#cb4-22"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> non_current<span class="op">);</span></span>
|
||||
<span id="cb4-23"><a href="#cb4-23"></a> g_object_unref <span class="op">(</span>listitem<span class="op">);</span></span>
|
||||
<span id="cb4-24"><a href="#cb4-24"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-25"><a href="#cb4-25"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
|
||||
<span id="cb4-26"><a href="#cb4-26"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-27"><a href="#cb4-27"></a> win<span class="op">-></span>position <span class="op">=</span> new<span class="op">;</span></span>
|
||||
<span id="cb4-28"><a href="#cb4-28"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">>=</span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-29"><a href="#cb4-29"></a> data <span class="op">=</span> LE_DATA <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">),</span> win<span class="op">-></span>position<span class="op">));</span></span>
|
||||
<span id="cb4-30"><a href="#cb4-30"></a> <span class="cf">if</span> <span class="op">((</span>listitem <span class="op">=</span> le_data_get_listitem <span class="op">(</span>data<span class="op">))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-31"><a href="#cb4-31"></a> button <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb4-32"><a href="#cb4-32"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> current<span class="op">);</span></span>
|
||||
<span id="cb4-33"><a href="#cb4-33"></a> g_object_unref <span class="op">(</span>listitem<span class="op">);</span></span>
|
||||
<span id="cb4-34"><a href="#cb4-34"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-35"><a href="#cb4-35"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
|
||||
<span id="cb4-36"><a href="#cb4-36"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-37"><a href="#cb4-37"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The function <code>update_current</code> does several things.</p>
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="dt">void</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a>select_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>gtk_widget_get_ancestor <span class="op">(</span>GTK_WIDGET <span class="op">(</span>btn<span class="op">),</span> LE_TYPE_WINDOW<span class="op">));</span></span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a></span>
|
||||
<span id="cb4-5"><a href="#cb4-5"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb4-6"><a href="#cb4-6"></a> update_current_button <span class="op">(</span>win<span class="op">,</span> btn<span class="op">);</span></span>
|
||||
<span id="cb4-7"><a href="#cb4-7"></a><span class="op">}</span></span>
|
||||
<span id="cb4-8"><a href="#cb4-8"></a></span>
|
||||
<span id="cb4-9"><a href="#cb4-9"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-10"><a href="#cb4-10"></a>setup1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-11"><a href="#cb4-11"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_button_new <span class="op">();</span></span>
|
||||
<span id="cb4-12"><a href="#cb4-12"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> button<span class="op">);</span></span>
|
||||
<span id="cb4-13"><a href="#cb4-13"></a> gtk_widget_set_focusable <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> FALSE<span class="op">);</span></span>
|
||||
<span id="cb4-14"><a href="#cb4-14"></a> g_signal_connect <span class="op">(</span>button<span class="op">,</span> <span class="st">"clicked"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>select_cb<span class="op">),</span> listitem<span class="op">);</span></span>
|
||||
<span id="cb4-15"><a href="#cb4-15"></a><span class="op">}</span></span>
|
||||
<span id="cb4-16"><a href="#cb4-16"></a></span>
|
||||
<span id="cb4-17"><a href="#cb4-17"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-18"><a href="#cb4-18"></a>bind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-19"><a href="#cb4-19"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb4-20"><a href="#cb4-20"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
|
||||
<span id="cb4-21"><a href="#cb4-21"></a></span>
|
||||
<span id="cb4-22"><a href="#cb4-22"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">==</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">))</span></span>
|
||||
<span id="cb4-23"><a href="#cb4-23"></a> update_current_button <span class="op">(</span>win<span class="op">,</span> GTK_BUTTON <span class="op">(</span>button<span class="op">));</span></span>
|
||||
<span id="cb4-24"><a href="#cb4-24"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>It has two parameters. The first one is <code>win</code>, which is
|
||||
an instance of LeWindow class. It has some elements.
|
||||
<ul>
|
||||
<li>win->position: an Integer. it is the current position. If no
|
||||
current line exists, it is -1.</li>
|
||||
<li>win->position_label: GtkLabel. It shows the current
|
||||
position.</li>
|
||||
</ul></li>
|
||||
<li>The second parameter is <code>new</code>, which is the new current
|
||||
position. At the beginning of the function, win->position points the
|
||||
old position.</li>
|
||||
<li>10-16: Update the text of GtkLabel.</li>
|
||||
<li>18-26: If the old position (win->position) is not negative, the
|
||||
current line exists. It gets a GtkListItem instance via the item
|
||||
(LeData) of the list. And it gets the GtkButton instance which is the
|
||||
child of the GtkListItem. It clears the “css-classes” property of the
|
||||
<li>1-7: <code>select_cb</code> is a “clicked” signal handler. The
|
||||
handler just calls the two functions and update the position and
|
||||
button.</li>
|
||||
<li>27: Updates win->position.</li>
|
||||
<li>28-36: If the new position is not negative (It’s possible to be
|
||||
negative when the current line has been removed), the current line
|
||||
exists. It sets the “css-classes” property of the button to
|
||||
<code>{"current", NULL}</code>. It is a NULL-terminated array of
|
||||
strings. Each string is a CSS class. Now the button has “current” style
|
||||
class.</li>
|
||||
<li>9-15: <code>setup1_cb</code> is a setup signal handler on the
|
||||
GtkSignalListItemFactory. It sets the child of <code>listitem</code> to
|
||||
a GtkButton instance. The “clicked” signal on the button is connected to
|
||||
the handler <code>select_cb</code>. When the listitem is destroyed, the
|
||||
child (GtkButton) is also destroyed. At the same time, the connection of
|
||||
the signal and the handler is also destroyed. So, you don’t need
|
||||
teardown signal handler.</li>
|
||||
<li>17-24: <code>bind1_cb</code> is a bind signal handler. Usually, the
|
||||
position moves before this handler is called. If the item is on the
|
||||
current line, the button is updated. No unbind handler is
|
||||
necessary.</li>
|
||||
</ul>
|
||||
<p>The color of buttons are determined by the “background” CSS style.
|
||||
The following CSS is applied to the default GdkDisplay in advance (in
|
||||
the startup handler of the application).</p>
|
||||
<p>When a line is added, the current position is updated in advance.</p>
|
||||
<div class="sourceCode" id="cb5"><pre
|
||||
class="sourceCode css"><code class="sourceCode css"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>columnview listview row button<span class="fu">.current</span> {<span class="kw">background</span>: <span class="cn">red</span><span class="op">;</span>}</span></code></pre></div>
|
||||
<p>The selectors “columnview listview row” is needed before “button”
|
||||
selector. Otherwise the buttons in the GtkColumnview won’t be found. The
|
||||
button selector has “current” class. So, the only “current” class button
|
||||
is colored with red. Other buttons are not colored, which means they are
|
||||
white.</p>
|
||||
<h2
|
||||
id="gtk_widget_dispose_template-function">Gtk_widget_dispose_template
|
||||
function</h2>
|
||||
<p>The function <code>gtk_widget_dispose_template</code> clears the
|
||||
template children for the given widget. This is the opposite of
|
||||
<code>gtk_widget_init_template()</code>. It is a new function of GTK 4.8
|
||||
version. If your GTK version is lower than 4.8, you need to modify the
|
||||
program.</p>
|
||||
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>app_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> LeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-3"><a href="#cb5-3"></a> LeData <span class="op">*</span>data <span class="op">=</span> le_data_new_with_data <span class="op">(</span><span class="st">""</span><span class="op">);</span></span>
|
||||
<span id="cb5-4"><a href="#cb5-4"></a></span>
|
||||
<span id="cb5-5"><a href="#cb5-5"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">>=</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-6"><a href="#cb5-6"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> win<span class="op">-></span>position <span class="op">+</span> <span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb5-7"><a href="#cb5-7"></a> g_list_store_insert <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">,</span> win<span class="op">-></span>position<span class="op">,</span> data<span class="op">);</span></span>
|
||||
<span id="cb5-8"><a href="#cb5-8"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
|
||||
<span id="cb5-9"><a href="#cb5-9"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> g_list_model_get_n_items <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">)));</span></span>
|
||||
<span id="cb5-10"><a href="#cb5-10"></a> g_list_store_append <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">,</span> data<span class="op">);</span></span>
|
||||
<span id="cb5-11"><a href="#cb5-11"></a> <span class="op">}</span></span>
|
||||
<span id="cb5-12"><a href="#cb5-12"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
|
||||
<span id="cb5-13"><a href="#cb5-13"></a><span class="op">}</span></span>
|
||||
<span id="cb5-14"><a href="#cb5-14"></a></span>
|
||||
<span id="cb5-15"><a href="#cb5-15"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb5-16"><a href="#cb5-16"></a>ins_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> LeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb5-17"><a href="#cb5-17"></a> LeData <span class="op">*</span>data <span class="op">=</span> le_data_new_with_data <span class="op">(</span><span class="st">""</span><span class="op">);</span></span>
|
||||
<span id="cb5-18"><a href="#cb5-18"></a></span>
|
||||
<span id="cb5-19"><a href="#cb5-19"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">>=</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb5-20"><a href="#cb5-20"></a> g_list_store_insert <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">,</span> win<span class="op">-></span>position<span class="op">,</span> data<span class="op">);</span></span>
|
||||
<span id="cb5-21"><a href="#cb5-21"></a> <span class="cf">else</span> <span class="op">{</span></span>
|
||||
<span id="cb5-22"><a href="#cb5-22"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb5-23"><a href="#cb5-23"></a> g_list_store_insert <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">,</span> <span class="dv">0</span><span class="op">,</span> data<span class="op">);</span></span>
|
||||
<span id="cb5-24"><a href="#cb5-24"></a> <span class="op">}</span></span>
|
||||
<span id="cb5-25"><a href="#cb5-25"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
|
||||
<span id="cb5-26"><a href="#cb5-26"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>When a line is removed, the current position becomes -1 and no button
|
||||
is current.</p>
|
||||
<div class="sourceCode" id="cb6"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb6-2"><a href="#cb6-2"></a>rm_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> LeWindow <span class="op">*</span>win<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb6-3"><a href="#cb6-3"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">>=</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb6-4"><a href="#cb6-4"></a> g_list_store_remove <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">,</span> win<span class="op">-></span>position<span class="op">);</span></span>
|
||||
<span id="cb6-5"><a href="#cb6-5"></a> update_current_position <span class="op">(</span>win<span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span>
|
||||
<span id="cb6-6"><a href="#cb6-6"></a> update_current_button <span class="op">(</span>win<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb6-7"><a href="#cb6-7"></a> <span class="op">}</span></span>
|
||||
<span id="cb6-8"><a href="#cb6-8"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The color of buttons are determined by the “background” CSS style.
|
||||
The following CSS node is a bit complicated. CSS node
|
||||
<code>column view</code> has <code>listview</code> child node. It covers
|
||||
the rows in the GtkColumnView. The <code>listview</code> node is the
|
||||
same as the one for GtkListView. It has <code>row</code> child node,
|
||||
which is for each child widget. Therefore, the following node
|
||||
corresponds buttons on the GtkColumnView widget. In addition, it is
|
||||
applied to the “current” class.</p>
|
||||
<div class="sourceCode" id="cb7"><pre
|
||||
class="sourceCode css"><code class="sourceCode css"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>columnview listview row button<span class="fu">.current</span> {<span class="kw">background</span>: <span class="cn">red</span><span class="op">;</span>}</span></code></pre></div>
|
||||
<h2 id="a-waring-from-gtktext">A waring from GtkText</h2>
|
||||
<p>If your program has the following two, a warning message can be
|
||||
issued.</p>
|
||||
|
@ -462,24 +439,24 @@ probably comes from focus and scroll.</p>
|
|||
window. When scroll begins, the “value-changed” signal on the vertical
|
||||
adjustment of the scrolled window is emitted.</p>
|
||||
<p>The following is extracted from the ui file and C source file.</p>
|
||||
<div class="sourceCode" id="cb7"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>... ... ...</span>
|
||||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkScrolledWindow"</span>></span>
|
||||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vadjustment"</span>></span>
|
||||
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkAdjustment"</span>></span>
|
||||
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <<span class="kw">signal</span><span class="ot"> name=</span><span class="st">"value-changed"</span><span class="ot"> handler=</span><span class="st">"adjustment_value_changed_cb"</span><span class="ot"> swapped=</span><span class="st">"no"</span><span class="ot"> object=</span><span class="st">"LeWindow"</span>/></span>
|
||||
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> </<span class="kw">property</span>></span>
|
||||
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>... ... ... </span></code></pre></div>
|
||||
<div class="sourceCode" id="cb8"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-2"><a href="#cb8-2"></a>adjustment_value_changed_cb <span class="op">(</span>GtkAdjustment <span class="op">*</span>adjustment<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-3"><a href="#cb8-3"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb8-4"><a href="#cb8-4"></a></span>
|
||||
<span id="cb8-5"><a href="#cb8-5"></a> gtk_window_set_focus <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-6"><a href="#cb8-6"></a><span class="op">}</span></span></code></pre></div>
|
||||
<div class="sourceCode" id="cb9"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>... ... ...</span>
|
||||
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkScrolledWindow"</span>></span>
|
||||
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vadjustment"</span>></span>
|
||||
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkAdjustment"</span>></span>
|
||||
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a> <<span class="kw">signal</span><span class="ot"> name=</span><span class="st">"value-changed"</span><span class="ot"> handler=</span><span class="st">"adjustment_value_changed_cb"</span><span class="ot"> swapped=</span><span class="st">"no"</span><span class="ot"> object=</span><span class="st">"LeWindow"</span>/></span>
|
||||
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a> </<span class="kw">property</span>></span>
|
||||
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a>... ... ... </span></code></pre></div>
|
||||
<div class="sourceCode" id="cb10"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb10-2"><a href="#cb10-2"></a>adjustment_value_changed_cb <span class="op">(</span>GtkAdjustment <span class="op">*</span>adjustment<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb10-3"><a href="#cb10-3"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb10-4"><a href="#cb10-4"></a></span>
|
||||
<span id="cb10-5"><a href="#cb10-5"></a> gtk_window_set_focus <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb10-6"><a href="#cb10-6"></a><span class="op">}</span></span></code></pre></div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
|
|
486
docs/sec34.html
486
docs/sec34.html
|
@ -1,486 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
|
||||
<title>GTK 4 tutorial</title>
|
||||
<style>
|
||||
code{white-space: pre-wrap;}
|
||||
span.smallcaps{font-variant: small-caps;}
|
||||
span.underline{text-decoration: underline;}
|
||||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
||||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||||
ul.task-list{list-style: none;}
|
||||
pre{overflow: visible;}
|
||||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||||
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
||||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||||
div.sourceCode { margin: 1em 0; }
|
||||
pre.sourceCode { margin: 0; }
|
||||
@media screen {
|
||||
div.sourceCode { overflow: auto; }
|
||||
}
|
||||
@media print {
|
||||
pre > code.sourceCode { white-space: pre-wrap; }
|
||||
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
||||
}
|
||||
pre.numberSource code
|
||||
{ counter-reset: source-line 0; }
|
||||
pre.numberSource code > span
|
||||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||||
pre.numberSource code > span > a:first-child::after
|
||||
{ content: counter(source-line);
|
||||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||||
border: none; display: inline-block;
|
||||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||||
-khtml-user-select: none; -moz-user-select: none;
|
||||
-ms-user-select: none; user-select: none;
|
||||
padding: 0 4px; width: 4em;
|
||||
color: #aaaaaa;
|
||||
}
|
||||
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
||||
div.sourceCode
|
||||
{ }
|
||||
@media screen {
|
||||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||||
}
|
||||
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
||||
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
||||
code span.at { color: #7d9029; } /* Attribute */
|
||||
code span.bn { color: #40a070; } /* BaseN */
|
||||
code span.bu { } /* BuiltIn */
|
||||
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
||||
code span.ch { color: #4070a0; } /* Char */
|
||||
code span.cn { color: #880000; } /* Constant */
|
||||
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
||||
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
||||
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
||||
code span.dt { color: #902000; } /* DataType */
|
||||
code span.dv { color: #40a070; } /* DecVal */
|
||||
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
||||
code span.ex { } /* Extension */
|
||||
code span.fl { color: #40a070; } /* Float */
|
||||
code span.fu { color: #06287e; } /* Function */
|
||||
code span.im { } /* Import */
|
||||
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
||||
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
||||
code span.op { color: #666666; } /* Operator */
|
||||
code span.ot { color: #007020; } /* Other */
|
||||
code span.pp { color: #bc7a00; } /* Preprocessor */
|
||||
code span.sc { color: #4070a0; } /* SpecialChar */
|
||||
code span.ss { color: #bb6688; } /* SpecialString */
|
||||
code span.st { color: #4070a0; } /* String */
|
||||
code span.va { color: #19177c; } /* Variable */
|
||||
code span.vs { color: #4070a0; } /* VerbatimString */
|
||||
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
||||
div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
|
||||
pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
|
||||
table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
|
||||
th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
|
||||
td {padding: 2px 6px; border: 1px solid;}
|
||||
img {display: block; margin-left: auto; margin-right: auto;}
|
||||
figcaption {text-align: center;}
|
||||
</style>
|
||||
</head>
|
||||
<body style="padding-top: 70px;">
|
||||
<div class="container">
|
||||
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
|
||||
<div class="container-fluid">
|
||||
<span class="navbar-brand">Gtk4 tutorial</span>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.html">Home</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="sec33.html">Prev: section33</a>
|
||||
</li>
|
||||
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<h1 id="gtksignallistitemfactory">GtkSignalListItemFactory</h1>
|
||||
<h2
|
||||
id="gtksignallistitemfactory-and-gtkbulderlistitemfactory">GtkSignalListItemFactory
|
||||
and GtkBulderListItemFactory</h2>
|
||||
<p>GtkBuilderlistItemFactory is convenient when GtkListView just shows
|
||||
the contents of a list. Its binding direction is always from an item of
|
||||
a list to a child of GtkListItem.</p>
|
||||
<p>When it comes to dynamic connection, it’s not enough. For example,
|
||||
you want to edit the contents of a list. You set a child of GtkListItem
|
||||
to a GtkText instance so a user can edit a text with it. You need to
|
||||
bind an item in the list with the buffer of the GtkText. The direction
|
||||
is opposite from the one with GtkBuilderListItemFactory. It is from the
|
||||
GtkText instance to the item in the list. You can implement this with
|
||||
GtkSignalListItemFactory, which is more flexible than
|
||||
GtkBuilderListItemFactory.</p>
|
||||
<p>Two things are shown in this section.</p>
|
||||
<ul>
|
||||
<li>Binding from a child of a GtkListItem instance to an item of a
|
||||
list.</li>
|
||||
<li>Access a child of GtkListItem dynamically. This direction is the
|
||||
same as the one with GtkBulderListItemFactory. But
|
||||
GtkBulderListItemFactory uses GtkExpression from the item property of
|
||||
the GtkListItem. So, it updates its child widget only when the item
|
||||
property changes. In this example the child reflects the change in the
|
||||
same item in the list dynamically.</li>
|
||||
</ul>
|
||||
<p>This section shows just a part of the source file
|
||||
<code>listeditor.c</code>. If you want to see the whole codes, see
|
||||
<code>src/listeditor</code> directory of the <a
|
||||
href="https://github.com/ToshioCP/Gtk4-tutorial">Gtk4 tutorial
|
||||
repository</a>.</p>
|
||||
<h2 id="a-list-editor">A list editor</h2>
|
||||
<p>The sample program is a list editor and data of the list are strings.
|
||||
It’s the same as a line editor. It reads a text file line by line. Each
|
||||
line is an item of the list. The list is displayed with GtkColumnView.
|
||||
There are two columns. The one is a button, which makes the line be a
|
||||
current line. If the line is the current line, the button is colored
|
||||
with red. The other is a string which is the contents of the
|
||||
corresponding item of the list.</p>
|
||||
<figure>
|
||||
<img src="image/listeditor.png" alt="List editor" />
|
||||
<figcaption aria-hidden="true">List editor</figcaption>
|
||||
</figure>
|
||||
<p>The source files are located at <code>src/listeditor</code>
|
||||
directory. You can compile end execute it as follows.</p>
|
||||
<ul>
|
||||
<li>Download the program from the <a
|
||||
href="https://github.com/ToshioCP/Gtk4-tutorial">repository</a>.</li>
|
||||
<li>Change your current directory to <code>src/listeditor</code>.</li>
|
||||
<li>Type the following on your commandline.</li>
|
||||
</ul>
|
||||
<pre><code>$ meson _build
|
||||
$ ninja -C _build
|
||||
$ _build/listeditor</code></pre>
|
||||
<ul>
|
||||
<li>Append button: appends a line after the current line, or at the last
|
||||
line if no current line exists.</li>
|
||||
<li>Insert button: inserts a line before the current line.</li>
|
||||
<li>Remove button: removes a current line.</li>
|
||||
<li>Read button: reads a file.</li>
|
||||
<li>Write button: writes the contents to a file.</li>
|
||||
<li>close button: close the contents.</li>
|
||||
<li>quit button: quit the application.</li>
|
||||
<li>Button on the select column: makes the line current.</li>
|
||||
<li>String column: GtkText. You can edit a string in the field.</li>
|
||||
</ul>
|
||||
<p>The current line number (zero-based) is shown at the left of the tool
|
||||
bar. The file name is shown at the right of the write button.</p>
|
||||
<h2 id="connect-a-gtktext-instance-and-an-item-in-the-list">Connect a
|
||||
GtkText instance and an item in the list</h2>
|
||||
<p>The second column (GtkColumnViewColumn) sets its factory property to
|
||||
GtkSignalListItemFactory. It uses three signals setup, bind and unbind.
|
||||
The following is their sgnal handlers.</p>
|
||||
<div class="sourceCode" id="cb2"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb2-2"><a href="#cb2-2"></a>setup2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb2-3"><a href="#cb2-3"></a> GtkWidget <span class="op">*</span>text <span class="op">=</span> gtk_text_new <span class="op">();</span></span>
|
||||
<span id="cb2-4"><a href="#cb2-4"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> GTK_WIDGET <span class="op">(</span>text<span class="op">));</span></span>
|
||||
<span id="cb2-5"><a href="#cb2-5"></a> gtk_editable_set_alignment <span class="op">(</span>GTK_EDITABLE <span class="op">(</span>text<span class="op">),</span> <span class="fl">0.0</span><span class="op">);</span></span>
|
||||
<span id="cb2-6"><a href="#cb2-6"></a><span class="op">}</span></span>
|
||||
<span id="cb2-7"><a href="#cb2-7"></a></span>
|
||||
<span id="cb2-8"><a href="#cb2-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb2-9"><a href="#cb2-9"></a>bind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb2-10"><a href="#cb2-10"></a> GtkWidget <span class="op">*</span>text <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
|
||||
<span id="cb2-11"><a href="#cb2-11"></a> GtkEntryBuffer <span class="op">*</span>buffer <span class="op">=</span> gtk_text_get_buffer <span class="op">(</span>GTK_TEXT <span class="op">(</span>text<span class="op">));</span></span>
|
||||
<span id="cb2-12"><a href="#cb2-12"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb2-13"><a href="#cb2-13"></a> GBinding <span class="op">*</span>bind<span class="op">;</span></span>
|
||||
<span id="cb2-14"><a href="#cb2-14"></a></span>
|
||||
<span id="cb2-15"><a href="#cb2-15"></a> gtk_editable_set_text <span class="op">(</span>GTK_EDITABLE <span class="op">(</span>text<span class="op">),</span> le_data_look_string <span class="op">(</span>data<span class="op">));</span></span>
|
||||
<span id="cb2-16"><a href="#cb2-16"></a> gtk_editable_set_position <span class="op">(</span>GTK_EDITABLE <span class="op">(</span>text<span class="op">),</span> <span class="dv">0</span><span class="op">);</span></span>
|
||||
<span id="cb2-17"><a href="#cb2-17"></a></span>
|
||||
<span id="cb2-18"><a href="#cb2-18"></a> bind <span class="op">=</span> g_object_bind_property <span class="op">(</span>buffer<span class="op">,</span> <span class="st">"text"</span><span class="op">,</span> data<span class="op">,</span> <span class="st">"string"</span><span class="op">,</span> G_BINDING_DEFAULT<span class="op">);</span></span>
|
||||
<span id="cb2-19"><a href="#cb2-19"></a> g_object_set_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">"bind"</span><span class="op">,</span> bind<span class="op">);</span></span>
|
||||
<span id="cb2-20"><a href="#cb2-20"></a><span class="op">}</span></span>
|
||||
<span id="cb2-21"><a href="#cb2-21"></a></span>
|
||||
<span id="cb2-22"><a href="#cb2-22"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb2-23"><a href="#cb2-23"></a>unbind2_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb2-24"><a href="#cb2-24"></a> GBinding <span class="op">*</span>bind <span class="op">=</span> G_BINDING <span class="op">(</span>g_object_get_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">"bind"</span><span class="op">));</span></span>
|
||||
<span id="cb2-25"><a href="#cb2-25"></a></span>
|
||||
<span id="cb2-26"><a href="#cb2-26"></a> g_binding_unbind<span class="op">(</span>bind<span class="op">);</span></span>
|
||||
<span id="cb2-27"><a href="#cb2-27"></a> g_object_set_data <span class="op">(</span>G_OBJECT <span class="op">(</span>listitem<span class="op">),</span> <span class="st">"bind"</span><span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb2-28"><a href="#cb2-28"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>1-6: <code>setup2_cb</code> is a setup signal handler on the
|
||||
GtkSignalListItemFactory. This factory is inserted to the factory
|
||||
property of the second GtkColumnViewColumn. The handler just creates a
|
||||
GtkText instance and sets the child of <code>listitem</code> to it. The
|
||||
instance will be destroyed automatically when the <code>listitem</code>
|
||||
is destroyed. So, teardown signal handler isn’t necessary.</li>
|
||||
<li>8-20: <code>bind2_cb</code> is a bind signal handler. It is called
|
||||
when the <code>listitem</code> is bound to an item in the list. The list
|
||||
items are LeData instances. LeData is defined in the file
|
||||
<code>listeditor.c</code> (the C source file of the list editor). It is
|
||||
a child class of GObject and has two data. The one is
|
||||
<code>listitem</code> which points a first column GtkListItem instance
|
||||
when they are connected. Be careful that the GtkListItem instance is
|
||||
<em>not</em> the <code>listitem</code> in this handler. If no
|
||||
GtkListItem is connected, it is NULL. The other is <code>string</code>
|
||||
which is a content of the line.
|
||||
<ul>
|
||||
<li>10-11: <code>text</code> is a child of the <code>listitem</code> and
|
||||
it is a GtkText instance. And <code>buffer</code> is a GtkTextBuffer
|
||||
instance of the <code>text</code>.</li>
|
||||
<li>12: The LeData instance <code>data</code> is an item pointed by the
|
||||
<code>listitem</code>.</li>
|
||||
<li>15-16: Sets the text of <code>text</code> to
|
||||
<code>le_data_look_string (data)</code>. le_data_look_string returns the
|
||||
string of the <code>data</code> and the ownership of the string is still
|
||||
taken by the <code>data</code>. So, the caller don’t need to free the
|
||||
string.</li>
|
||||
<li>18: <code>g_object_bind_property</code> binds a property and another
|
||||
object property. This line binds the “text” property of the
|
||||
<code>buffer</code> (source) and the “string” property of the
|
||||
<code>data</code> (destination). It is a uni-directional binding
|
||||
(<code>G_BINDING_DEFAULT</code>). When a user changes the GtkText text,
|
||||
the same string is immediately put into the <code>data</code>. The
|
||||
function returns a GBinding instance. This binding is different from
|
||||
bindings of GtkExpression. This binding needs the existence of the two
|
||||
properties.</li>
|
||||
<li>19: GObjec has a table. The key is a string (or GQuark) and the
|
||||
value is a gpointer (pointer to any type). The function
|
||||
<code>g_object_set_data</code> sets the association from the key to the
|
||||
value. This line sets the association from “bind” to <code>bind</code>
|
||||
instance. It makes possible for the “unbind” handler to get the
|
||||
<code>bind</code> instance.</li>
|
||||
</ul></li>
|
||||
<li>22-28: <code>unbind2_cb</code> is a unbind signal handler.
|
||||
<ul>
|
||||
<li>24: Retrieves the <code>bind</code> instance from the table in the
|
||||
<code>listitem</code> instance.</li>
|
||||
<li>26: Unbind the binding.</li>
|
||||
<li>27: Removes the value corresponds to the “bind” key.</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
<p>This technique is not so complicated. You can use it when you make a
|
||||
cell editable application.</p>
|
||||
<h2 id="change-the-cell-of-gtkcolumnview-dynamically">Change the cell of
|
||||
GtkColumnView dynamically</h2>
|
||||
<p>Next topic is to change the GtkColumnView (or GtkListView) cells
|
||||
dynamically. The example changes the color of the buttons, which are
|
||||
children of GtkListItem instances, as the current line position
|
||||
moves.</p>
|
||||
<p>The line editor has the current position of the list.</p>
|
||||
<ul>
|
||||
<li>At first, no line is current.</li>
|
||||
<li>When a line is appended or inserted, the line is current.</li>
|
||||
<li>When the current line is deleted, no line will be current.</li>
|
||||
<li>When a button in the first column of GtkColumnView is clicked, the
|
||||
line will be current.</li>
|
||||
<li>It is necessary to set the line status (whether current or not) when
|
||||
a GtkListItem is bound to an item in the list. It is because GtkListItem
|
||||
is recycled. A GtkListItem was possibly current line before but not
|
||||
current after recycled. The opposite can also be happen.</li>
|
||||
</ul>
|
||||
<p>The button of the current line is colored with red and otherwise
|
||||
white.</p>
|
||||
<p>The current line has no relationship to GtkSingleSelection object.
|
||||
GtkSingleSelection selects a line on the display. The current line
|
||||
doesn’t need to be on the display. It is possible to be on the line out
|
||||
of the Window (GtkScrolledWindow). Actually, the program doesn’t use
|
||||
GtkSingleSelection.</p>
|
||||
<p>It is necessary to know the corresponding GtkListItem instance from
|
||||
the item in the list. It is the opposite direction from
|
||||
<code>gtk_list_item_get_item</code> function. To accomplish this, we set
|
||||
a <code>listitem</code> element of LeData to point the corresponding
|
||||
GtkListItem instance. Therefore, items (LeData) in the list always know
|
||||
the GtkListItem. If there’s no GtkListItem bound to the item, NULL is
|
||||
assigned.</p>
|
||||
<div class="sourceCode" id="cb3"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="dt">void</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2"></a>select_cb <span class="op">(</span>GtkButton <span class="op">*</span>btn<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-3"><a href="#cb3-3"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>gtk_widget_get_ancestor <span class="op">(</span>GTK_WIDGET <span class="op">(</span>btn<span class="op">),</span> LE_TYPE_WINDOW<span class="op">));</span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4"></a></span>
|
||||
<span id="cb3-5"><a href="#cb3-5"></a> update_current <span class="op">(</span>win<span class="op">,</span> gtk_list_item_get_position <span class="op">(</span>listitem<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>
|
||||
<span id="cb3-8"><a href="#cb3-8"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-9"><a href="#cb3-9"></a>setup1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-10"><a href="#cb3-10"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_button_new <span class="op">();</span></span>
|
||||
<span id="cb3-11"><a href="#cb3-11"></a> gtk_list_item_set_child <span class="op">(</span>listitem<span class="op">,</span> button<span class="op">);</span></span>
|
||||
<span id="cb3-12"><a href="#cb3-12"></a> gtk_widget_set_focusable <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> FALSE<span class="op">);</span></span>
|
||||
<span id="cb3-13"><a href="#cb3-13"></a> g_signal_connect <span class="op">(</span>button<span class="op">,</span> <span class="st">"clicked"</span><span class="op">,</span> G_CALLBACK <span class="op">(</span>select_cb<span class="op">),</span> listitem<span class="op">);</span></span>
|
||||
<span id="cb3-14"><a href="#cb3-14"></a><span class="op">}</span></span>
|
||||
<span id="cb3-15"><a href="#cb3-15"></a></span>
|
||||
<span id="cb3-16"><a href="#cb3-16"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-17"><a href="#cb3-17"></a>bind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-18"><a href="#cb3-18"></a> LeWindow <span class="op">*</span>win <span class="op">=</span> LE_WINDOW <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb3-19"><a href="#cb3-19"></a> GtkWidget <span class="op">*</span>button <span class="op">=</span> gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">);</span></span>
|
||||
<span id="cb3-20"><a href="#cb3-20"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span>
|
||||
<span id="cb3-21"><a href="#cb3-21"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">"current"</span><span class="op">,</span> NULL<span class="op">};</span></span>
|
||||
<span id="cb3-22"><a href="#cb3-22"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb3-23"><a href="#cb3-23"></a></span>
|
||||
<span id="cb3-24"><a href="#cb3-24"></a> <span class="cf">if</span> <span class="op">(</span>data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-25"><a href="#cb3-25"></a> le_data_set_listitem <span class="op">(</span>data<span class="op">,</span> listitem<span class="op">);</span></span>
|
||||
<span id="cb3-26"><a href="#cb3-26"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">==</span> gtk_list_item_get_position <span class="op">(</span>listitem<span class="op">))</span></span>
|
||||
<span id="cb3-27"><a href="#cb3-27"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> current<span class="op">);</span></span>
|
||||
<span id="cb3-28"><a href="#cb3-28"></a> <span class="cf">else</span></span>
|
||||
<span id="cb3-29"><a href="#cb3-29"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> non_current<span class="op">);</span></span>
|
||||
<span id="cb3-30"><a href="#cb3-30"></a> <span class="op">}</span></span>
|
||||
<span id="cb3-31"><a href="#cb3-31"></a><span class="op">}</span></span>
|
||||
<span id="cb3-32"><a href="#cb3-32"></a></span>
|
||||
<span id="cb3-33"><a href="#cb3-33"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb3-34"><a href="#cb3-34"></a>unbind1_cb <span class="op">(</span>GtkListItemFactory <span class="op">*</span>factory<span class="op">,</span> GtkListItem <span class="op">*</span>listitem<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb3-35"><a href="#cb3-35"></a> LeData <span class="op">*</span>data <span class="op">=</span> LE_DATA <span class="op">(</span>gtk_list_item_get_item <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb3-36"><a href="#cb3-36"></a> <span class="cf">if</span> <span class="op">(</span>data<span class="op">)</span></span>
|
||||
<span id="cb3-37"><a href="#cb3-37"></a> le_data_set_listitem <span class="op">(</span>data<span class="op">,</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb3-38"><a href="#cb3-38"></a><span class="op">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>8-14: <code>setup1_cb</code> is a setup signal handler on the
|
||||
GtkSignalListItemFactory. This factory is inserted to the factory
|
||||
property of the first GtkColumnViewColumn. It sets the child of
|
||||
<code>listitem</code> to a GtkButton instance. The “clicked” signal on
|
||||
the button is connected to the handler <code>select_cb</code>. When the
|
||||
listitem is destroyed, the child (GtkButton) is also destroyed. At the
|
||||
same time, the connection of the signal and the handler is also
|
||||
destroyed. So, you don’t need teardown signal handler.</li>
|
||||
<li>1-6: <code>select_cb</code> is a “clicked” signal handler. LeWindow
|
||||
is defined in <code>listeditor.c</code>. It’s a child class of
|
||||
GtkApplicationWindow. The handler just calls the
|
||||
<code>update_current</code> function. The function will be explained
|
||||
later.</li>
|
||||
<li>16-31: <code>bind1_cb</code> is a bind signal handler. It sets the
|
||||
“listitem” element of the item (LeData) to point the
|
||||
<code>listitem</code> (GtkListItem instance). It makes the item possible
|
||||
to find the corresponding GtkListItem instance. If the item is the
|
||||
current line, the CSS class of the button includes “current” class.
|
||||
Otherwise it has no CSS class. This is necessary because the button may
|
||||
be recycled and it has had former CSS class. The class need to be
|
||||
updated.</li>
|
||||
<li>33-38: <code>unbind1_cb</code> is an unbind signal handler. It
|
||||
removes the <code>listitem</code> instance from the “listitem” element
|
||||
of the item. The element becomes NULL, which tells no GtkListItem is
|
||||
bound. When referring GtkListItem, it needs to check the “listitem”
|
||||
element whether it points a GtkListItem or not (NULL). Otherwise bad
|
||||
things will happen.</li>
|
||||
</ul>
|
||||
<div class="sourceCode" id="cb4"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb4-2"><a href="#cb4-2"></a>update_current <span class="op">(</span>LeWindow <span class="op">*</span>win<span class="op">,</span> <span class="dt">int</span> new<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-3"><a href="#cb4-3"></a> <span class="dt">char</span> <span class="op">*</span>s<span class="op">;</span></span>
|
||||
<span id="cb4-4"><a href="#cb4-4"></a> LeData <span class="op">*</span>data<span class="op">;</span></span>
|
||||
<span id="cb4-5"><a href="#cb4-5"></a> GtkListItem <span class="op">*</span>listitem<span class="op">;</span></span>
|
||||
<span id="cb4-6"><a href="#cb4-6"></a> GtkButton <span class="op">*</span>button<span class="op">;</span></span>
|
||||
<span id="cb4-7"><a href="#cb4-7"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>non_current<span class="op">[</span><span class="dv">1</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span>NULL<span class="op">};</span></span>
|
||||
<span id="cb4-8"><a href="#cb4-8"></a> <span class="dt">const</span> <span class="dt">char</span> <span class="op">*</span>current<span class="op">[</span><span class="dv">2</span><span class="op">]</span> <span class="op">=</span> <span class="op">{</span><span class="st">"current"</span><span class="op">,</span> NULL<span class="op">};</span></span>
|
||||
<span id="cb4-9"><a href="#cb4-9"></a></span>
|
||||
<span id="cb4-10"><a href="#cb4-10"></a> <span class="cf">if</span> <span class="op">(</span>new <span class="op">>=</span> <span class="dv">0</span><span class="op">)</span></span>
|
||||
<span id="cb4-11"><a href="#cb4-11"></a> s <span class="op">=</span> g_strdup_printf <span class="op">(</span><span class="st">"%d"</span><span class="op">,</span> new<span class="op">);</span></span>
|
||||
<span id="cb4-12"><a href="#cb4-12"></a> <span class="cf">else</span></span>
|
||||
<span id="cb4-13"><a href="#cb4-13"></a> s <span class="op">=</span> <span class="st">""</span><span class="op">;</span></span>
|
||||
<span id="cb4-14"><a href="#cb4-14"></a> gtk_label_set_text <span class="op">(</span>GTK_LABEL <span class="op">(</span>win<span class="op">-></span>position_label<span class="op">),</span> s<span class="op">);</span></span>
|
||||
<span id="cb4-15"><a href="#cb4-15"></a> <span class="cf">if</span> <span class="op">(*</span>s<span class="op">)</span> <span class="co">// s isn't an empty string</span></span>
|
||||
<span id="cb4-16"><a href="#cb4-16"></a> g_free <span class="op">(</span>s<span class="op">);</span></span>
|
||||
<span id="cb4-17"><a href="#cb4-17"></a></span>
|
||||
<span id="cb4-18"><a href="#cb4-18"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">>=</span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-19"><a href="#cb4-19"></a> data <span class="op">=</span> LE_DATA <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">),</span> win<span class="op">-></span>position<span class="op">));</span></span>
|
||||
<span id="cb4-20"><a href="#cb4-20"></a> <span class="cf">if</span> <span class="op">((</span>listitem <span class="op">=</span> le_data_get_listitem <span class="op">(</span>data<span class="op">))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-21"><a href="#cb4-21"></a> button <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb4-22"><a href="#cb4-22"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> non_current<span class="op">);</span></span>
|
||||
<span id="cb4-23"><a href="#cb4-23"></a> g_object_unref <span class="op">(</span>listitem<span class="op">);</span></span>
|
||||
<span id="cb4-24"><a href="#cb4-24"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-25"><a href="#cb4-25"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
|
||||
<span id="cb4-26"><a href="#cb4-26"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-27"><a href="#cb4-27"></a> win<span class="op">-></span>position <span class="op">=</span> new<span class="op">;</span></span>
|
||||
<span id="cb4-28"><a href="#cb4-28"></a> <span class="cf">if</span> <span class="op">(</span>win<span class="op">-></span>position <span class="op">>=</span><span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-29"><a href="#cb4-29"></a> data <span class="op">=</span> LE_DATA <span class="op">(</span>g_list_model_get_item <span class="op">(</span>G_LIST_MODEL <span class="op">(</span>win<span class="op">-></span>liststore<span class="op">),</span> win<span class="op">-></span>position<span class="op">));</span></span>
|
||||
<span id="cb4-30"><a href="#cb4-30"></a> <span class="cf">if</span> <span class="op">((</span>listitem <span class="op">=</span> le_data_get_listitem <span class="op">(</span>data<span class="op">))</span> <span class="op">!=</span> NULL<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb4-31"><a href="#cb4-31"></a> button <span class="op">=</span> GTK_BUTTON <span class="op">(</span>gtk_list_item_get_child <span class="op">(</span>listitem<span class="op">));</span></span>
|
||||
<span id="cb4-32"><a href="#cb4-32"></a> gtk_widget_set_css_classes <span class="op">(</span>GTK_WIDGET <span class="op">(</span>button<span class="op">),</span> current<span class="op">);</span></span>
|
||||
<span id="cb4-33"><a href="#cb4-33"></a> g_object_unref <span class="op">(</span>listitem<span class="op">);</span></span>
|
||||
<span id="cb4-34"><a href="#cb4-34"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-35"><a href="#cb4-35"></a> g_object_unref <span class="op">(</span>data<span class="op">);</span></span>
|
||||
<span id="cb4-36"><a href="#cb4-36"></a> <span class="op">}</span></span>
|
||||
<span id="cb4-37"><a href="#cb4-37"></a><span class="op">}</span></span></code></pre></div>
|
||||
<p>The function <code>update_current</code> does several things.</p>
|
||||
<ul>
|
||||
<li>It has two parameters. The first one is <code>win</code>, which is
|
||||
an instance of LeWindow class. It has some elements.
|
||||
<ul>
|
||||
<li>win->position: an Integer. it is the current position. If no
|
||||
current line exists, it is -1.</li>
|
||||
<li>win->position_label: GtkLabel. It shows the current
|
||||
position.</li>
|
||||
</ul></li>
|
||||
<li>The second parameter is <code>new</code>, which is the new current
|
||||
position. At the beginning of the function, win->position points the
|
||||
old position.</li>
|
||||
<li>10-16: Update the text of GtkLabel.</li>
|
||||
<li>18-26: If the old position (win->position) is not negative, the
|
||||
current line exists. It gets a GtkListItem instance via the item
|
||||
(LeData) of the list. And it gets the GtkButton instance which is the
|
||||
child of the GtkListItem. It clears the “css-classes” property of the
|
||||
button.</li>
|
||||
<li>27: Updates win->position.</li>
|
||||
<li>28-36: If the new position is not negative (It’s possible to be
|
||||
negative when the current line has been removed), the current line
|
||||
exists. It sets the “css-classes” property of the button to
|
||||
<code>{"current", NULL}</code>. It is a NULL-terminated array of
|
||||
strings. Each string is a CSS class. Now the button has “current” style
|
||||
class.</li>
|
||||
</ul>
|
||||
<p>The color of buttons are determined by the “background” CSS style.
|
||||
The following CSS is applied to the default GdkDisplay in advance (in
|
||||
the startup handler of the application).</p>
|
||||
<div class="sourceCode" id="cb5"><pre
|
||||
class="sourceCode css"><code class="sourceCode css"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>columnview listview row button<span class="fu">.current</span> {<span class="kw">background</span>: <span class="cn">red</span><span class="op">;</span>}</span></code></pre></div>
|
||||
<p>The selectors “columnview listview row” is needed before “button”
|
||||
selector. Otherwise the buttons in the GtkColumnview won’t be found. The
|
||||
button selector has “current” class. So, the only “current” class button
|
||||
is colored with red. Other buttons are not colored, which means they are
|
||||
white.</p>
|
||||
<h2
|
||||
id="gtk_widget_dispose_template-function">Gtk_widget_dispose_template
|
||||
function</h2>
|
||||
<p>The function <code>gtk_widget_dispose_template</code> clears the
|
||||
template children for the given widget. This is the opposite of
|
||||
<code>gtk_widget_init_template()</code>. It is a new function of GTK 4.8
|
||||
version. If your GTK version is lower than 4.8, you need to modify the
|
||||
program.</p>
|
||||
<h2 id="a-waring-from-gtktext">A waring from GtkText</h2>
|
||||
<p>If your program has the following two, a warning message can be
|
||||
issued.</p>
|
||||
<ul>
|
||||
<li>The list has many items and it needs to be scrolled.</li>
|
||||
<li>A GtkText instance is the focus widget.</li>
|
||||
</ul>
|
||||
<pre><code>GtkText - unexpected blinking selection. Removing</code></pre>
|
||||
<p>I don’t have an exact idea why this happens. But if GtkText
|
||||
“focusable” property is FALSE, the warning doesn’t happen. So it
|
||||
probably comes from focus and scroll.</p>
|
||||
<p>You can avoid this by unsetting any focus widget under the main
|
||||
window. When scroll begins, the “value-changed” signal on the vertical
|
||||
adjustment of the scrolled window is emitted.</p>
|
||||
<p>The following is extracted from the ui file and C source file.</p>
|
||||
<div class="sourceCode" id="cb7"><pre
|
||||
class="sourceCode xml"><code class="sourceCode xml"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>... ... ...</span>
|
||||
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkScrolledWindow"</span>></span>
|
||||
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||||
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vadjustment"</span>></span>
|
||||
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkAdjustment"</span>></span>
|
||||
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a> <<span class="kw">signal</span><span class="ot"> name=</span><span class="st">"value-changed"</span><span class="ot"> handler=</span><span class="st">"adjustment_value_changed_cb"</span><span class="ot"> swapped=</span><span class="st">"no"</span><span class="ot"> object=</span><span class="st">"LeWindow"</span>/></span>
|
||||
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a> </<span class="kw">object</span>></span>
|
||||
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a> </<span class="kw">property</span>></span>
|
||||
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>... ... ... </span></code></pre></div>
|
||||
<div class="sourceCode" id="cb8"><pre
|
||||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||||
<span id="cb8-2"><a href="#cb8-2"></a>adjustment_value_changed_cb <span class="op">(</span>GtkAdjustment <span class="op">*</span>adjustment<span class="op">,</span> gpointer user_data<span class="op">)</span> <span class="op">{</span></span>
|
||||
<span id="cb8-3"><a href="#cb8-3"></a> GtkWidget <span class="op">*</span>win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>user_data<span class="op">);</span></span>
|
||||
<span id="cb8-4"><a href="#cb8-4"></a></span>
|
||||
<span id="cb8-5"><a href="#cb8-5"></a> gtk_window_set_focus <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> NULL<span class="op">);</span></span>
|
||||
<span id="cb8-6"><a href="#cb8-6"></a><span class="op">}</span></span></code></pre></div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
||||
</body>
|
||||
</html>
|
18
gfm/sec29.md
18
gfm/sec29.md
|
@ -8,9 +8,10 @@ The new feature is described in [Gtk API Reference -- List Widget Overview](http
|
|||
GTK 4 has other means to implement lists.
|
||||
They are GtkListBox and GtkTreeView which are took over from GTK 3.
|
||||
There's an article in [Gtk Development blog](https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/) about list widgets by Matthias Clasen.
|
||||
He described why GtkListView are developed to replace GtkListBox and GtkTreeView.
|
||||
He described why GtkListView are developed to replace GtkTreeView.
|
||||
GtkTreeView is deprecated since version 4.10.
|
||||
|
||||
GtkListView, GtkGridView, GtkColumnView and related objects are described in Section 26 to 29.
|
||||
GtkListView, GtkGridView, GtkColumnView and related objects are described in Section 29 to 33.
|
||||
|
||||
## Outline
|
||||
|
||||
|
@ -21,7 +22,7 @@ A list is like an array, but in many cases it is implemented with pointers which
|
|||
And it has a start point.
|
||||
So, each item can be referred by the index of the item (first item, second item, ..., nth item, ...).
|
||||
There are two cases.
|
||||
One is the index starts from one (one-based) and the other is from zero (zero-based).
|
||||
The one is the index starts from one (one-based) and the other is from zero (zero-based).
|
||||
|
||||
Gio provides GListModel interface.
|
||||
It is a zero-based list and its items are the same type of GObject descendants, or objects that implement the same interface.
|
||||
|
@ -29,11 +30,11 @@ An object implements GListModel is not a widget.
|
|||
So, the list is not displayed on the screen directly.
|
||||
There's another object GtkListView which is a widget to display the list.
|
||||
The items in the list need to be connected to the items in GtkListView.
|
||||
GtkListItemFactory instance maps items in the list to GListView.
|
||||
GtkListItemFactory instance maps items in the list to GtkListView.
|
||||
|
||||
![List](../image/list.png)
|
||||
|
||||
## GListModel
|
||||
## GListModel and GtkStringList
|
||||
|
||||
If you want to make a list of strings with GListModel, for example, "one", "two", "three", "four", note that strings can't be items of the list.
|
||||
Because GListModel is a list of GObject objects and strings aren't GObject objects.
|
||||
|
@ -253,7 +254,7 @@ There is an explanation in the [GTK Development Blog](https://blog.gtk.org/2020/
|
|||
> Remember that the classname (GtkListItem) in a ui template is used as the “this” pointer referring to the object that is being instantiated.
|
||||
|
||||
Therefore, GtkListItem instance is used as the `this` object of the lookup tag when it is evaluated.
|
||||
`this` object will be explained in [section 30](../src/sec30).
|
||||
`this` object will be explained in [section 31](../src/sec31).
|
||||
|
||||
The C source code is as follows.
|
||||
Its name is `list2.c` and located under [src/misc](../src/misc) directory.
|
||||
|
@ -370,7 +371,7 @@ Instead, closure tag is appropriate in this case.
|
|||
Closure tag specifies a function and the type of the return value of the function.
|
||||
|
||||
~~~C
|
||||
const char *
|
||||
char *
|
||||
get_file_name (GtkListItem *item, GFileInfo *info) {
|
||||
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
|
||||
}
|
||||
|
@ -406,7 +407,7 @@ The contents of closure tag (it is between \<closure...\> and\</closure\>) is pa
|
|||
`<lookup name="item">GtkListItem</lookup>` gives the value of the item property of the GtkListItem.
|
||||
This will be the second argument of the function.
|
||||
The first parameter is always the GListItem instance, which is a 'this' object.
|
||||
The 'this' object is explained in section 28.
|
||||
The 'this' object is explained in section 31.
|
||||
- `gtk_file_name` function is the callback function for the closure tag.
|
||||
It first checks the `info` parameter.
|
||||
Because it can be NULL when GListItem `item` is unbounded.
|
||||
|
@ -531,5 +532,4 @@ $ ./a.out
|
|||
|
||||
![screenshot list3](../image/list3.png)
|
||||
|
||||
|
||||
Up: [README.md](../README.md), Prev: [Section 28](sec28.md), Next: [Section 30](sec30.md)
|
||||
|
|
|
@ -64,7 +64,7 @@ Such "x-" subtype is not a standard mime type.)
|
|||
Content type is also used by desktop systems.
|
||||
|
||||
GtkGridView uses the same GtkSingleSelection instance (`singleselection`).
|
||||
So, its model property is set with it.
|
||||
So, its model property is set to it.
|
||||
|
||||
## Ui file of the window
|
||||
|
||||
|
@ -467,7 +467,7 @@ The last parameter is the pointer to the pointer to a GError.
|
|||
|
||||
If your distribution supports GTK 4, using `g_app_info_launch_default_for_uri` is convenient.
|
||||
The function automatically determines the default application from the file and launches it.
|
||||
For example, if the file is text, then it launches gedit with the file.
|
||||
For example, if the file is text, then it launches GNOME text editor with the file.
|
||||
Such feature comes from desktop.
|
||||
|
||||
## Compilation and execution
|
||||
|
@ -477,7 +477,7 @@ To compile and execute list4, type as follows.
|
|||
|
||||
~~~
|
||||
$ cd list4 # or cd src/list4. It depends your current directory.
|
||||
$ meson _build
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/list4
|
||||
~~~
|
||||
|
|
90
gfm/sec31.md
90
gfm/sec31.md
|
@ -58,8 +58,8 @@ The type of the value is int.
|
|||
|G\_TYPE\_INT |int |gint | |
|
||||
|G\_TYPE\_FLOAT |float |gfloat | |
|
||||
|G\_TYPE\_DOUBLE |double|gdouble | |
|
||||
|G\_TYPE\_POINTER | |gpointer | |
|
||||
|G\_TYPE\_STRING | |gchararray|null-terminated Cstring|
|
||||
|G\_TYPE\_POINTER |void *|gpointer |general pointer |
|
||||
|G\_TYPE\_STRING |char *|gchararray|null-terminated Cstring|
|
||||
|G\_TYPE\_OBJECT | |GObject | |
|
||||
|GTK\_TYPE\_WINDOW| |GtkWindow | |
|
||||
|
||||
|
@ -119,7 +119,7 @@ expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "l
|
|||
|
||||
If `expression` is evaluated, the second parameter `another_expression` is evaluated in advance.
|
||||
The value of `another_expression` is the `label` (GtkLabel instance).
|
||||
Then, `expression` looks up "label" property of the label and the evaluation results "Hello".
|
||||
Then, `expression` looks up "label" property of the label and the evaluation results in "Hello".
|
||||
|
||||
In the example above, the second argument of `gtk_property_expression_new` is another expression.
|
||||
But the second argument can be NULL.
|
||||
|
@ -145,7 +145,7 @@ There's a simple program `exp_property_simple.c` in `src/expression` directory.
|
|||
14 if (gtk_expression_evaluate (expression, label, &value))
|
||||
15 g_print ("The value is %s.\n", g_value_get_string (&value));
|
||||
16 else
|
||||
17 g_print ("The constant expression wasn't evaluated correctly.\n");
|
||||
17 g_print ("The property expression wasn't evaluated correctly.\n");
|
||||
18 gtk_expression_unref (expression);
|
||||
19 g_value_unset (&value);
|
||||
20
|
||||
|
@ -164,7 +164,7 @@ The expression just knows how to take the property from a future-given GtkLabel
|
|||
The result is stored in the GValue `value`.
|
||||
The function `g_value_get_string` gets a string from the GValue.
|
||||
But the string is owned by the GValue so you must not free the string.
|
||||
- 18-19: Release the expression and unset the GValue.
|
||||
- 18-19: Releases the expression and unset the GValue.
|
||||
At the same time the string in the GValue is freed.
|
||||
|
||||
If the second argument of `gtk_property_expression_new` isn't NULL, it is another expression.
|
||||
|
@ -195,6 +195,18 @@ gtk_cclosure_expression_new (GType value_type,
|
|||
gpointer user_data,
|
||||
GClosureNotify user_destroy);
|
||||
~~~
|
||||
@else
|
||||
~~~{.C}
|
||||
GtkExpression *
|
||||
gtk_cclosure_expression_new (GType value_type,
|
||||
GClosureMarshal marshal,
|
||||
guint n_params,
|
||||
GtkExpression **params,
|
||||
GCallback callback_func,
|
||||
gpointer user_data,
|
||||
GClosureNotify user_destroy);
|
||||
~~~
|
||||
@end
|
||||
|
||||
- `value_type` is the type of the value when it is evaluated.
|
||||
- `marshal` is a marshaller.
|
||||
|
@ -224,6 +236,7 @@ callback (this, param1, param2, ...)
|
|||
|
||||
For example,
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
int
|
||||
callback (GObject *object, int x, const char *s)
|
||||
|
@ -276,13 +289,13 @@ If you want to return error report, change the return value type to be a pointer
|
|||
One for error and the other for the sum.
|
||||
The first argument of `gtk_cclosure_expression_new` is `G_TYPE_POINTER`.
|
||||
There is a sample program `exp_closure_with_error_report` in `src/expression` directory.
|
||||
- 19: gtk\_init initializes GTK. It is necessary for GtkLabel.
|
||||
- 19: The function `gtk_init`` initializes GTK. It is necessary for GtkLabel.
|
||||
- 20: A GtkLabel instance is created with "123+456".
|
||||
- 21: The instance has floating reference. It is changed to an ordinary reference count.
|
||||
- 22-23: Create a closure expression. Its return value type is `G_TYPE_INT` and no parameters or 'this' object.
|
||||
- 22-23: Creates a closure expression. Its return value type is `G_TYPE_INT` and no parameters or 'this' object.
|
||||
- 24: Evaluates the expression with the label as a 'this' object.
|
||||
- 25: If the evaluation successes, show the sum of "123+456". It's 579.
|
||||
- 27: If it fails, show an error message.
|
||||
- 25: If the evaluation successes, the sum of "123+456", which is 579, is shown.
|
||||
- 27: If it fails, an error message appears.
|
||||
- 28-30: Releases the expression and the label. Unsets the value.
|
||||
|
||||
Closure expression is flexible than other type of expression because you can specify your own callback function.
|
||||
|
@ -292,6 +305,7 @@ Closure expression is flexible than other type of expression because you can spe
|
|||
GtkExpressionWatch is a structure, not an object.
|
||||
It represents a watched GtkExpression.
|
||||
Two functions create GtkExpressionWatch structure.
|
||||
They are `gtk_expression_bind` and `gtk_expression_watch`.
|
||||
|
||||
### gtk\_expression\_bind function
|
||||
|
||||
|
@ -411,7 +425,7 @@ For example, if it is zero, the slider moves to an integer point.
|
|||
28 GtkExpression *expression, *params[1];
|
||||
29
|
||||
30 /* Builds a window with exp.ui resource */
|
||||
31 build = gtk_builder_new_from_file ("exp_bind.ui");
|
||||
31 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/exp/exp_bind.ui");
|
||||
32 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
33 label = GTK_WIDGET (gtk_builder_get_object (build, "label"));
|
||||
34 // scale = GTK_WIDGET (gtk_builder_get_object (build, "scale"));
|
||||
|
@ -448,7 +462,7 @@ The point of the program is:
|
|||
|
||||
- 41-42: Two expressions are defined.
|
||||
One is a property expression and the other is a closure expression.
|
||||
The property expression look up the "value"property of the adjustment instance.
|
||||
The property expression looks up the "value" property of the adjustment instance.
|
||||
The closure expression just converts the double into an integer.
|
||||
- 43: `gtk_expression_bind` binds the label property of the GtkLabel instance to the integer returned by the closure expression.
|
||||
It creates a GtkExpressionWatch structure.
|
||||
|
@ -462,8 +476,8 @@ This signal is emitted when the close button is clicked.
|
|||
The handler is called just before the window closes.
|
||||
It is the right moment to make the GtkExpressionWatch unwatched.
|
||||
- 10-14: "close-request" signal handler.
|
||||
`gtk_expression_watch_unwatch (watch)` makes the watch stop watching the expression.
|
||||
It releases the expression and calls `gtk_expression_watch_unref (watch)` in it.
|
||||
The function `gtk_expression_watch_unwatch (watch)` makes the watch stop watching the expression.
|
||||
It also releases the expression.
|
||||
|
||||
If you want to bind a property to an expression, `gtk_expression_bind` is the best choice.
|
||||
You can do it with `gtk_expression_watch` function, but it is less suitable.
|
||||
|
@ -619,7 +633,7 @@ These tags are usually used for GtkBuilderListItemFactory.
|
|||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<binding name="label">
|
||||
<lookup name="name" type="string">
|
||||
<lookup name="string" type="GtkStringObject">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
|
@ -629,14 +643,13 @@ These tags are usually used for GtkBuilderListItemFactory.
|
|||
</interface>
|
||||
~~~
|
||||
|
||||
GtkBuilderListItemFactory uses GtkBuilder to extends the GtkListItem with the XML data.
|
||||
|
||||
In the xml file above, "GtkListItem" is an instance of the GtkListItem template.
|
||||
It is the 'this' object given to the expressions.
|
||||
(The information is in the [GTK Development Blog](https://blog.gtk.org/2020/09/)).
|
||||
|
||||
GtkBuilderListItemFactory uses GtkBuilder to build the XML data.
|
||||
It sets the current object of the GtkBuilder to the GtkListItem instance.
|
||||
|
||||
GtkBuilder calls `gtk_expression_bind` function in the binding tag analysis.
|
||||
GtkBuilder calls `gtk_expression_bind` function when it finds a binding tag.
|
||||
The function sets the 'this' object like this:
|
||||
|
||||
1. If the binding tag has object attribute, the object will be the 'this' object.
|
||||
|
@ -760,7 +773,7 @@ String duplication is necessary.
|
|||
|
||||
The C source file is very simple because almost everything is done in the ui file.
|
||||
|
||||
### Conversion between GValues
|
||||
## Conversion between GValues
|
||||
|
||||
If you bind different type properties, type conversion is automatically done.
|
||||
Suppose a label property (string) is bound to default-width property (int).
|
||||
|
@ -782,4 +795,43 @@ If the current width is 100, an int `100` is converted to a string `"100"`.
|
|||
|
||||
If you use `g_object_get` and `g_object_set` to copy properties, the value is automatically converted.
|
||||
|
||||
## Meson.build
|
||||
|
||||
The source files are in `src/expression` directory.
|
||||
You can build all the files at once.
|
||||
|
||||
~~~
|
||||
$ cd src/expression
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
~~~
|
||||
|
||||
For example, if you want to run "exp", which is the executable file from "exp.c", type `_build/exp`.
|
||||
You can run other programs as well.
|
||||
|
||||
The file `meson.build` is as follows.
|
||||
|
||||
~~~meson
|
||||
1 project('exp', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','exp.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('exp.c')
|
||||
9
|
||||
10 executable('exp', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
11 executable('exp_constant', 'exp_constant.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
12 executable('exp_constant_simple', 'exp_constant_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
13 executable('exp_property_simple', 'exp_property_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
14 executable('closure', 'closure.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
15 executable('closure_each', 'closure_each.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
16 executable('exp_closure_simple', 'exp_closure_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
17 executable('exp_closure_with_error_report', 'exp_closure_with_error_report.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
18 executable('exp_bind', 'exp_bind.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
19 executable('exp_watch', 'exp_watch.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
20 executable('exp_test', 'exp_test.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
~~~
|
||||
|
||||
Up: [README.md](../README.md), Prev: [Section 30](sec30.md), Next: [Section 32](sec32.md)
|
||||
|
|
|
@ -218,9 +218,9 @@ This is the title on the header of the column.
|
|||
- 32: Sets the "expand" property to TRUE to allow the column to expand as much as possible.
|
||||
(See the image above).
|
||||
- 33- 69: Sets the "factory" property to GtkBuilderListItemFactory.
|
||||
The factory has "bytes" property which holds a ui string to define a template to build GtkListItem composite widget.
|
||||
The factory has "bytes" property which holds a ui string to define a template to extend GtkListItem class.
|
||||
The CDATA section (line 36-66) is the ui string to put into the "bytes" property.
|
||||
The contents are the same as the ui file `factory_list.ui` in the section 27.
|
||||
The contents are the same as the ui file `factory_list.ui` in the section 30.
|
||||
- 70-77: Sets the "sorter" property to GtkStringSorter object.
|
||||
This object provides a sorter that compares strings.
|
||||
It has "expression" property.
|
||||
|
@ -456,7 +456,8 @@ All the source files are in [`src/column`](../src/column) directory.
|
|||
Change your current directory to the directory and type the following.
|
||||
|
||||
~~~
|
||||
$ meson _build
|
||||
$ cd src/colomn
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/column
|
||||
~~~
|
||||
|
|
301
gfm/sec33.md
301
gfm/sec33.md
|
@ -8,23 +8,14 @@ GtkBuilderlistItemFactory is convenient when GtkListView just shows the contents
|
|||
Its binding direction is always from an item of a list to a child of GtkListItem.
|
||||
|
||||
When it comes to dynamic connection, it's not enough.
|
||||
For example, you want to edit the contents of a list.
|
||||
For example, suppose you want to edit the contents of a list.
|
||||
You set a child of GtkListItem to a GtkText instance so a user can edit a text with it.
|
||||
You need to bind an item in the list with the buffer of the GtkText.
|
||||
The direction is opposite from the one with GtkBuilderListItemFactory.
|
||||
It is from the GtkText instance to the item in the list.
|
||||
You can implement this with GtkSignalListItemFactory, which is more flexible than GtkBuilderListItemFactory.
|
||||
|
||||
Two things are shown in this section.
|
||||
|
||||
- Binding from a child of a GtkListItem instance to an item of a list.
|
||||
- Access a child of GtkListItem dynamically.
|
||||
This direction is the same as the one with GtkBulderListItemFactory.
|
||||
But GtkBulderListItemFactory uses GtkExpression from the item property of the GtkListItem.
|
||||
So, it updates its child widget only when the item property changes.
|
||||
In this example the child reflects the change in the same item in the list dynamically.
|
||||
|
||||
This section shows just a part of the source file `listeditor.c`.
|
||||
This section shows just some parts of the source file `listeditor.c`.
|
||||
If you want to see the whole codes, see `src/listeditor` directory of the [Gtk4 tutorial repository](https://github.com/ToshioCP/Gtk4-tutorial).
|
||||
|
||||
## A list editor
|
||||
|
@ -35,7 +26,7 @@ It reads a text file line by line.
|
|||
Each line is an item of the list.
|
||||
The list is displayed with GtkColumnView.
|
||||
There are two columns.
|
||||
The one is a button, which makes the line be a current line.
|
||||
The one is a button, which shows if the line is a current line.
|
||||
If the line is the current line, the button is colored with red.
|
||||
The other is a string which is the contents of the corresponding item of the list.
|
||||
|
||||
|
@ -49,18 +40,18 @@ You can compile end execute it as follows.
|
|||
- Type the following on your commandline.
|
||||
|
||||
~~~
|
||||
$ meson _build
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/listeditor
|
||||
~~~
|
||||
|
||||
- Append button: appends a line after the current line, or at the last line if no current line exists.
|
||||
- Insert button: inserts a line before the current line.
|
||||
- Insert button: inserts a line before the current line, or at the top line if no current line exists.
|
||||
- Remove button: removes a current line.
|
||||
- Read button: reads a file.
|
||||
- Write button: writes the contents to a file.
|
||||
- close button: close the contents.
|
||||
- quit button: quit the application.
|
||||
- close button: closes the contents.
|
||||
- quit button: quits the application.
|
||||
- Button on the select column: makes the line current.
|
||||
- String column: GtkText. You can edit a string in the field.
|
||||
|
||||
|
@ -71,7 +62,7 @@ The file name is shown at the right of the write button.
|
|||
|
||||
The second column (GtkColumnViewColumn) sets its factory property to GtkSignalListItemFactory.
|
||||
It uses three signals setup, bind and unbind.
|
||||
The following is their sgnal handlers.
|
||||
The following shows the signal handlers.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
|
@ -85,7 +76,7 @@ The following is their sgnal handlers.
|
|||
9 bind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
|
||||
10 GtkWidget *text = gtk_list_item_get_child (listitem);
|
||||
11 GtkEntryBuffer *buffer = gtk_text_get_buffer (GTK_TEXT (text));
|
||||
12 LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
|
||||
12 LeData *data = LE_DATA (gtk_list_item_get_item(listitem));
|
||||
13 GBinding *bind;
|
||||
14
|
||||
15 gtk_editable_set_text (GTK_EDITABLE (text), le_data_look_string (data));
|
||||
|
@ -99,9 +90,10 @@ The following is their sgnal handlers.
|
|||
23 unbind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
|
||||
24 GBinding *bind = G_BINDING (g_object_get_data (G_OBJECT (listitem), "bind"));
|
||||
25
|
||||
26 g_binding_unbind(bind);
|
||||
27 g_object_set_data (G_OBJECT (listitem), "bind", NULL);
|
||||
28 }
|
||||
26 if (bind)
|
||||
27 g_binding_unbind(bind);
|
||||
28 g_object_set_data (G_OBJECT (listitem), "bind", NULL);
|
||||
29 }
|
||||
~~~
|
||||
|
||||
- 1-6: `setup2_cb` is a setup signal handler on the GtkSignalListItemFactory.
|
||||
|
@ -113,17 +105,13 @@ So, teardown signal handler isn't necessary.
|
|||
It is called when the `listitem` is bound to an item in the list.
|
||||
The list items are LeData instances.
|
||||
LeData is defined in the file `listeditor.c` (the C source file of the list editor).
|
||||
It is a child class of GObject and has two data.
|
||||
The one is `listitem` which points a first column GtkListItem instance when they are connected.
|
||||
Be careful that the GtkListItem instance is *not* the `listitem` in this handler.
|
||||
If no GtkListItem is connected, it is NULL.
|
||||
The other is `string` which is a content of the line.
|
||||
It is a child class of GObject and has string data which is the content of the line.
|
||||
- 10-11: `text` is a child of the `listitem` and it is a GtkText instance.
|
||||
And `buffer` is a GtkTextBuffer instance of the `text`.
|
||||
And `buffer` is a GtkEntryBuffer instance of the `text`.
|
||||
- 12: The LeData instance `data` is an item pointed by the `listitem`.
|
||||
- 15-16: Sets the text of `text` to `le_data_look_string (data)`.
|
||||
le\_data\_look\_string returns the string of the `data` and the ownership of the string is still taken by the `data`.
|
||||
So, the caller don't need to free the string.
|
||||
So, the caller doesn't need to free the string.
|
||||
- 18: `g_object_bind_property` binds a property and another object property.
|
||||
This line binds the "text" property of the `buffer` (source) and the "string" property of the `data` (destination).
|
||||
It is a uni-directional binding (`G_BINDING_DEFAULT`).
|
||||
|
@ -136,14 +124,19 @@ The key is a string (or GQuark) and the value is a gpointer (pointer to any type
|
|||
The function `g_object_set_data` sets the association from the key to the value.
|
||||
This line sets the association from "bind" to `bind` instance.
|
||||
It makes possible for the "unbind" handler to get the `bind` instance.
|
||||
- 22-28: `unbind2_cb` is a unbind signal handler.
|
||||
- 22-29: `unbind2_cb` is a unbind signal handler.
|
||||
- 24: Retrieves the `bind` instance from the table in the `listitem` instance.
|
||||
- 26: Unbind the binding.
|
||||
- 27: Removes the value corresponds to the "bind" key.
|
||||
- 26-27: Unbind the binding.
|
||||
- 28: Removes the value corresponds to the "bind" key.
|
||||
|
||||
This technique is not so complicated.
|
||||
You can use it when you make a cell editable application.
|
||||
|
||||
If it is impossible to use `g_object_bind_property`, use a notify signal on the GtkEntryBuffer instance.
|
||||
You can use "deleted-text" and "inserted-text" signal instead.
|
||||
The handler of the signals above copies the text in the GtkEntryBuffer instance to the LeData string.
|
||||
Connect the notify signal handler in `bind2_cb` and disconnect it in `unbind2_cb`.
|
||||
|
||||
## Change the cell of GtkColumnView dynamically
|
||||
|
||||
Next topic is to change the GtkColumnView (or GtkListView) cells dynamically.
|
||||
|
@ -168,159 +161,157 @@ The current line doesn't need to be on the display.
|
|||
It is possible to be on the line out of the Window (GtkScrolledWindow).
|
||||
Actually, the program doesn't use GtkSingleSelection.
|
||||
|
||||
It is necessary to know the corresponding GtkListItem instance from the item in the list.
|
||||
It is the opposite direction from `gtk_list_item_get_item` function.
|
||||
To accomplish this, we set a `listitem` element of LeData to point the corresponding GtkListItem instance.
|
||||
Therefore, items (LeData) in the list always know the GtkListItem.
|
||||
If there's no GtkListItem bound to the item, NULL is assigned.
|
||||
The LeWindow instance has two instance variables for recording the current line.
|
||||
|
||||
- `win->position`: An int type variable. It is the position of the current line. It is zero-based. If no current line exists, it is -1.
|
||||
- `win->current_button`: A variable points the button, located at the first column, on the current line. If no current line exists, it is NULL.
|
||||
|
||||
If the current line moves, the following two functions are called.
|
||||
They updates the two varables.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 update_current_position (LeWindow *win, int new) {
|
||||
3 char *s;
|
||||
4
|
||||
5 win->position = new;
|
||||
6 if (win->position >= 0)
|
||||
7 s = g_strdup_printf ("%d", win->position);
|
||||
8 else
|
||||
9 s = "";
|
||||
10 gtk_label_set_text (GTK_LABEL (win->position_label), s);
|
||||
11 if (*s) // s isn't an empty string
|
||||
12 g_free (s);
|
||||
13 }
|
||||
14
|
||||
15 static void
|
||||
16 update_current_button (LeWindow *win, GtkButton *new_button) {
|
||||
17 const char *non_current[1] = {NULL};
|
||||
18 const char *current[2] = {"current", NULL};
|
||||
19
|
||||
20 if (win->current_button) {
|
||||
21 gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), non_current);
|
||||
22 g_object_unref (win->current_button);
|
||||
23 }
|
||||
24 win->current_button = new_button;
|
||||
25 if (win->current_button) {
|
||||
26 g_object_ref (win->current_button);
|
||||
27 gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), current);
|
||||
28 }
|
||||
29 }
|
||||
~~~
|
||||
|
||||
The varable `win->position_label` points a GtkLabel instance.
|
||||
The label shows the current line position.
|
||||
|
||||
The current button has CSS "current" class.
|
||||
The button is colored red through the CSS "button.current {background: red;}".
|
||||
|
||||
The order of the call for these two functions is important.
|
||||
The first function, which updates the position, is usually called first.
|
||||
After that, a new line is appended or inserted.
|
||||
Then, the second function is called.
|
||||
|
||||
The following functions call the two functions above.
|
||||
Be careful about the order of the call.
|
||||
|
||||
~~~C
|
||||
1 void
|
||||
2 select_cb (GtkButton *btn, GtkListItem *listitem) {
|
||||
3 LeWindow *win = LE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (btn), LE_TYPE_WINDOW));
|
||||
4
|
||||
5 update_current (win, gtk_list_item_get_position (listitem));
|
||||
6 }
|
||||
7
|
||||
8 static void
|
||||
9 setup1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
|
||||
10 GtkWidget *button = gtk_button_new ();
|
||||
11 gtk_list_item_set_child (listitem, button);
|
||||
12 gtk_widget_set_focusable (GTK_WIDGET (button), FALSE);
|
||||
13 g_signal_connect (button, "clicked", G_CALLBACK (select_cb), listitem);
|
||||
14 }
|
||||
15
|
||||
16 static void
|
||||
17 bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) {
|
||||
18 LeWindow *win = LE_WINDOW (user_data);
|
||||
19 GtkWidget *button = gtk_list_item_get_child (listitem);
|
||||
20 const char *non_current[1] = {NULL};
|
||||
21 const char *current[2] = {"current", NULL};
|
||||
22 LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
|
||||
23
|
||||
24 if (data) {
|
||||
25 le_data_set_listitem (data, listitem);
|
||||
26 if (win->position == gtk_list_item_get_position (listitem))
|
||||
27 gtk_widget_set_css_classes (GTK_WIDGET (button), current);
|
||||
28 else
|
||||
29 gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
|
||||
30 }
|
||||
31 }
|
||||
32
|
||||
33 static void
|
||||
34 unbind1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
|
||||
35 LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
|
||||
36 if (data)
|
||||
37 le_data_set_listitem (data, NULL);
|
||||
38 }
|
||||
5 update_current_position (win, gtk_list_item_get_position (listitem));
|
||||
6 update_current_button (win, btn);
|
||||
7 }
|
||||
8
|
||||
9 static void
|
||||
10 setup1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
|
||||
11 GtkWidget *button = gtk_button_new ();
|
||||
12 gtk_list_item_set_child (listitem, button);
|
||||
13 gtk_widget_set_focusable (GTK_WIDGET (button), FALSE);
|
||||
14 g_signal_connect (button, "clicked", G_CALLBACK (select_cb), listitem);
|
||||
15 }
|
||||
16
|
||||
17 static void
|
||||
18 bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) {
|
||||
19 LeWindow *win = LE_WINDOW (user_data);
|
||||
20 GtkWidget *button = gtk_list_item_get_child (listitem);
|
||||
21
|
||||
22 if (win->position == gtk_list_item_get_position (listitem))
|
||||
23 update_current_button (win, GTK_BUTTON (button));
|
||||
24 }
|
||||
~~~
|
||||
|
||||
- 8-14: `setup1_cb` is a setup signal handler on the GtkSignalListItemFactory.
|
||||
This factory is inserted to the factory property of the first GtkColumnViewColumn.
|
||||
- 1-7: `select_cb` is a "clicked" signal handler.
|
||||
The handler just calls the two functions and update the position and button.
|
||||
- 9-15: `setup1_cb` is a setup signal handler on the GtkSignalListItemFactory.
|
||||
It sets the child of `listitem` to a GtkButton instance.
|
||||
The "clicked" signal on the button is connected to the handler `select_cb`.
|
||||
When the listitem is destroyed, the child (GtkButton) is also destroyed.
|
||||
At the same time, the connection of the signal and the handler is also destroyed.
|
||||
So, you don't need teardown signal handler.
|
||||
- 1-6: `select_cb` is a "clicked" signal handler.
|
||||
LeWindow is defined in `listeditor.c`.
|
||||
It's a child class of GtkApplicationWindow.
|
||||
The handler just calls the `update_current` function.
|
||||
The function will be explained later.
|
||||
- 16-31: `bind1_cb` is a bind signal handler.
|
||||
It sets the "listitem" element of the item (LeData) to point the `listitem` (GtkListItem instance).
|
||||
It makes the item possible to find the corresponding GtkListItem instance.
|
||||
If the item is the current line, the CSS class of the button includes "current" class.
|
||||
Otherwise it has no CSS class.
|
||||
This is necessary because the button may be recycled and it has had former CSS class.
|
||||
The class need to be updated.
|
||||
- 33-38: `unbind1_cb` is an unbind signal handler.
|
||||
It removes the `listitem` instance from the "listitem" element of the item.
|
||||
The element becomes NULL, which tells no GtkListItem is bound.
|
||||
When referring GtkListItem, it needs to check the "listitem" element whether it points a GtkListItem or not (NULL).
|
||||
Otherwise bad things will happen.
|
||||
- 17-24: `bind1_cb` is a bind signal handler.
|
||||
Usually, the position moves before this handler is called.
|
||||
If the item is on the current line, the button is updated.
|
||||
No unbind handler is necessary.
|
||||
|
||||
When a line is added, the current position is updated in advance.
|
||||
|
||||
~~~C
|
||||
1 static void
|
||||
2 update_current (LeWindow *win, int new) {
|
||||
3 char *s;
|
||||
4 LeData *data;
|
||||
5 GtkListItem *listitem;
|
||||
6 GtkButton *button;
|
||||
7 const char *non_current[1] = {NULL};
|
||||
8 const char *current[2] = {"current", NULL};
|
||||
9
|
||||
10 if (new >= 0)
|
||||
11 s = g_strdup_printf ("%d", new);
|
||||
12 else
|
||||
13 s = "";
|
||||
14 gtk_label_set_text (GTK_LABEL (win->position_label), s);
|
||||
15 if (*s) // s isn't an empty string
|
||||
16 g_free (s);
|
||||
17
|
||||
18 if (win->position >=0) {
|
||||
19 data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position));
|
||||
20 if ((listitem = le_data_get_listitem (data)) != NULL) {
|
||||
21 button = GTK_BUTTON (gtk_list_item_get_child (listitem));
|
||||
22 gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
|
||||
23 g_object_unref (listitem);
|
||||
2 app_cb (GtkButton *btn, LeWindow *win) {
|
||||
3 LeData *data = le_data_new_with_data ("");
|
||||
4
|
||||
5 if (win->position >= 0) {
|
||||
6 update_current_position (win, win->position + 1);
|
||||
7 g_list_store_insert (win->liststore, win->position, data);
|
||||
8 } else {
|
||||
9 update_current_position (win, g_list_model_get_n_items (G_LIST_MODEL (win->liststore)));
|
||||
10 g_list_store_append (win->liststore, data);
|
||||
11 }
|
||||
12 g_object_unref (data);
|
||||
13 }
|
||||
14
|
||||
15 static void
|
||||
16 ins_cb (GtkButton *btn, LeWindow *win) {
|
||||
17 LeData *data = le_data_new_with_data ("");
|
||||
18
|
||||
19 if (win->position >= 0)
|
||||
20 g_list_store_insert (win->liststore, win->position, data);
|
||||
21 else {
|
||||
22 update_current_position (win, 0);
|
||||
23 g_list_store_insert (win->liststore, 0, data);
|
||||
24 }
|
||||
25 g_object_unref (data);
|
||||
26 }
|
||||
27 win->position = new;
|
||||
28 if (win->position >=0) {
|
||||
29 data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position));
|
||||
30 if ((listitem = le_data_get_listitem (data)) != NULL) {
|
||||
31 button = GTK_BUTTON (gtk_list_item_get_child (listitem));
|
||||
32 gtk_widget_set_css_classes (GTK_WIDGET (button), current);
|
||||
33 g_object_unref (listitem);
|
||||
34 }
|
||||
35 g_object_unref (data);
|
||||
36 }
|
||||
37 }
|
||||
~~~
|
||||
|
||||
The function `update_current` does several things.
|
||||
When a line is removed, the current position becomes -1 and no button is current.
|
||||
|
||||
- It has two parameters.
|
||||
The first one is `win`, which is an instance of LeWindow class.
|
||||
It has some elements.
|
||||
- win->position: an Integer. it is the current position. If no current line exists, it is -1.
|
||||
- win->position_label: GtkLabel. It shows the current position.
|
||||
- The second parameter is `new`, which is the new current position.
|
||||
At the beginning of the function, win->position points the old position.
|
||||
- 10-16: Update the text of GtkLabel.
|
||||
- 18-26: If the old position (win->position) is not negative, the current line exists.
|
||||
It gets a GtkListItem instance via the item (LeData) of the list.
|
||||
And it gets the GtkButton instance which is the child of the GtkListItem.
|
||||
It clears the "css-classes" property of the button.
|
||||
- 27: Updates win->position.
|
||||
- 28-36: If the new position is not negative (It's possible to be negative when the current line has been removed), the current line exists.
|
||||
It sets the "css-classes" property of the button to `{"current", NULL}`.
|
||||
It is a NULL-terminated array of strings.
|
||||
Each string is a CSS class.
|
||||
Now the button has "current" style class.
|
||||
~~~C
|
||||
1 static void
|
||||
2 rm_cb (GtkButton *btn, LeWindow *win) {
|
||||
3 if (win->position >= 0) {
|
||||
4 g_list_store_remove (win->liststore, win->position);
|
||||
5 update_current_position (win, -1);
|
||||
6 update_current_button (win, NULL);
|
||||
7 }
|
||||
8 }
|
||||
~~~
|
||||
|
||||
The color of buttons are determined by the "background" CSS style.
|
||||
The following CSS is applied to the default GdkDisplay in advance (in the startup handler of the application).
|
||||
The following CSS node is a bit complicated.
|
||||
CSS node `column view` has `listview` child node.
|
||||
It covers the rows in the GtkColumnView.
|
||||
The `listview` node is the same as the one for GtkListView.
|
||||
It has `row` child node, which is for each child widget.
|
||||
Therefore, the following node corresponds buttons on the GtkColumnView widget.
|
||||
In addition, it is applied to the "current" class.
|
||||
|
||||
~~~css
|
||||
columnview listview row button.current {background: red;}
|
||||
~~~
|
||||
|
||||
The selectors "columnview listview row" is needed before "button" selector.
|
||||
Otherwise the buttons in the GtkColumnview won't be found.
|
||||
The button selector has "current" class.
|
||||
So, the only "current" class button is colored with red.
|
||||
Other buttons are not colored, which means they are white.
|
||||
|
||||
## Gtk\_widget\_dispose\_template function
|
||||
|
||||
The function `gtk_widget_dispose_template` clears the template children for the given widget.
|
||||
This is the opposite of `gtk_widget_init_template()`.
|
||||
It is a new function of GTK 4.8 version.
|
||||
If your GTK version is lower than 4.8, you need to modify the program.
|
||||
|
||||
## A waring from GtkText
|
||||
|
||||
If your program has the following two, a warning message can be issued.
|
||||
|
|
|
@ -6,7 +6,8 @@ The table of contents is at the end of this abstract.
|
|||
|
||||
- Section 3 to 23 describes the basics, with the example of a simple editor `tfe` (Text File Editor).
|
||||
- Section 24 to 27 describes GtkDrawingArea.
|
||||
- Section 28 to 32 describes the list model and the list view (GtkListView, GtkGridView and GtkColumnView).
|
||||
- Section 28 describes Drag and Drop.
|
||||
- Section 29 to 33 describes the list model and the list view (GtkListView, GtkGridView and GtkColumnView).
|
||||
It also describes GtkExpression.
|
||||
|
||||
The latest version of the tutorial is located at [GTK4-tutorial GitHub repository](https://github.com/ToshioCP/Gtk4-tutorial).
|
||||
|
|
|
@ -2,5 +2,7 @@
|
|||
<gresources>
|
||||
<gresource prefix="/com/github/ToshioCP/exp">
|
||||
<file>exp.ui</file>
|
||||
<file>exp_bind.ui</file>
|
||||
<file>exp_test.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
|
|
@ -28,7 +28,7 @@ app_startup (GApplication *application) {
|
|||
GtkExpression *expression, *params[1];
|
||||
|
||||
/* Builds a window with exp.ui resource */
|
||||
build = gtk_builder_new_from_file ("exp_bind.ui");
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/exp/exp_bind.ui");
|
||||
win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
label = GTK_WIDGET (gtk_builder_get_object (build, "label"));
|
||||
// scale = GTK_WIDGET (gtk_builder_get_object (build, "scale"));
|
||||
|
|
|
@ -14,7 +14,7 @@ main (int argc, char **argv) {
|
|||
if (gtk_expression_evaluate (expression, label, &value))
|
||||
g_print ("The value is %s.\n", g_value_get_string (&value));
|
||||
else
|
||||
g_print ("The constant expression wasn't evaluated correctly.\n");
|
||||
g_print ("The property expression wasn't evaluated correctly.\n");
|
||||
gtk_expression_unref (expression);
|
||||
g_value_unset (&value);
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ app_startup (GApplication *application) {
|
|||
GtkBuilder *build;
|
||||
GtkWidget *win;
|
||||
|
||||
build = gtk_builder_new_from_file ("exp_test.ui");
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/exp/exp_test.ui");
|
||||
win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
g_object_unref (build);
|
||||
|
|
|
@ -15,6 +15,6 @@ executable('closure', 'closure.c', dependencies: gtkdep, export_dynamic: true, i
|
|||
executable('closure_each', 'closure_each.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
executable('exp_closure_simple', 'exp_closure_simple.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
executable('exp_closure_with_error_report', 'exp_closure_with_error_report.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
executable('exp_bind', 'exp_bind.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
executable('exp_bind', 'exp_bind.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
executable('exp_watch', 'exp_watch.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
executable('exp_test', 'exp_test.c', dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
executable('exp_test', 'exp_test.c', resources, dependencies: gtkdep, export_dynamic: true, install: false)
|
||||
|
|
|
@ -13,7 +13,6 @@ static GParamSpec *ledata_properties[N_PROPERTIES] = {NULL, };
|
|||
|
||||
typedef struct _LeData {
|
||||
GObject parent;
|
||||
GtkListItem *listitem;
|
||||
char *string;
|
||||
} LeData;
|
||||
|
||||
|
@ -41,19 +40,9 @@ le_data_get_property (GObject *object, guint property_id, GValue *value, GParamS
|
|||
|
||||
static void
|
||||
le_data_init (LeData *self) {
|
||||
self->listitem = NULL;
|
||||
self->string = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
le_data_dispose (GObject *object) {
|
||||
LeData *self = LE_DATA (object);
|
||||
|
||||
if (self->listitem)
|
||||
g_clear_object (&self->listitem);
|
||||
G_OBJECT_CLASS (le_data_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
le_data_finalize (GObject *object) {
|
||||
LeData *self = LE_DATA (object);
|
||||
|
@ -67,7 +56,6 @@ static void
|
|||
le_data_class_init (LeDataClass *class) {
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
||||
gobject_class->finalize = le_data_dispose;
|
||||
gobject_class->finalize = le_data_finalize;
|
||||
gobject_class->set_property = le_data_set_property;
|
||||
gobject_class->get_property = le_data_get_property;
|
||||
|
@ -75,14 +63,16 @@ le_data_class_init (LeDataClass *class) {
|
|||
g_object_class_install_properties (gobject_class,N_PROPERTIES, ledata_properties);
|
||||
}
|
||||
|
||||
/* setter and getter */
|
||||
void
|
||||
le_data_set_listitem (LeData *self, GtkListItem *listitem) {
|
||||
g_return_if_fail (GTK_IS_LIST_ITEM (listitem) || listitem == NULL);
|
||||
/* getter and setter */
|
||||
|
||||
if (self->listitem)
|
||||
g_object_unref (self->listitem);
|
||||
self->listitem = listitem ? g_object_ref (listitem) : NULL;
|
||||
char *
|
||||
le_data_get_string (LeData *self) {
|
||||
return g_strdup (self->string);
|
||||
}
|
||||
|
||||
const char *
|
||||
le_data_look_string (LeData *self) {
|
||||
return self->string;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -99,35 +89,9 @@ le_data_take_string (LeData *self, char *string) {
|
|||
self->string = string;
|
||||
}
|
||||
|
||||
GtkListItem *
|
||||
le_data_get_listitem (LeData *self) {
|
||||
return self->listitem ? g_object_ref (self->listitem) : NULL;
|
||||
}
|
||||
|
||||
GtkListItem *
|
||||
le_data_look_listitem (LeData *self) {
|
||||
return self->listitem ? self->listitem : NULL;
|
||||
}
|
||||
|
||||
char *
|
||||
le_data_get_string (LeData *self) {
|
||||
return g_strdup (self->string);
|
||||
}
|
||||
|
||||
const char *
|
||||
le_data_look_string (LeData *self) {
|
||||
return self->string;
|
||||
}
|
||||
|
||||
LeData *
|
||||
le_data_new_with_data (GtkListItem *listitem, const char *string) {
|
||||
g_return_val_if_fail (GTK_IS_LIST_ITEM (listitem) || listitem == NULL, NULL);
|
||||
LeData *data;
|
||||
|
||||
data = LE_DATA (g_object_new (LE_TYPE_DATA, NULL));
|
||||
data->listitem = listitem ? g_object_ref (listitem) : NULL;
|
||||
data->string = g_strdup (string);
|
||||
return data;
|
||||
le_data_new_with_data (const char *string) {
|
||||
return LE_DATA (g_object_new (LE_TYPE_DATA, "string", string, NULL));
|
||||
}
|
||||
|
||||
LeData *
|
||||
|
@ -141,151 +105,149 @@ G_DECLARE_FINAL_TYPE (LeWindow, le_window, LE, WINDOW, GtkApplicationWindow)
|
|||
typedef struct _LeWindow {
|
||||
GtkApplicationWindow parent;
|
||||
int position; /* current position */
|
||||
GtkButton *current_button;
|
||||
GFile *file;
|
||||
GtkWidget *position_label;
|
||||
GtkWidget *filename;
|
||||
GtkWidget *columnview;
|
||||
GtkNoSelection *noselection;
|
||||
GListStore *liststore;
|
||||
} LeWindow;
|
||||
G_DEFINE_TYPE (LeWindow, le_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||
G_DEFINE_FINAL_TYPE (LeWindow, le_window, GTK_TYPE_APPLICATION_WINDOW)
|
||||
|
||||
static void
|
||||
update_current (LeWindow *win, int new) {
|
||||
update_current_position (LeWindow *win, int new) {
|
||||
char *s;
|
||||
LeData *data;
|
||||
GtkListItem *listitem;
|
||||
GtkButton *button;
|
||||
const char *non_current[1] = {NULL};
|
||||
const char *current[2] = {"current", NULL};
|
||||
|
||||
if (new >= 0)
|
||||
s = g_strdup_printf ("%d", new);
|
||||
win->position = new;
|
||||
if (win->position >= 0)
|
||||
s = g_strdup_printf ("%d", win->position);
|
||||
else
|
||||
s = "";
|
||||
gtk_label_set_text (GTK_LABEL (win->position_label), s);
|
||||
if (*s) // s isn't an empty string
|
||||
g_free (s);
|
||||
}
|
||||
|
||||
if (win->position >=0) {
|
||||
data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position));
|
||||
if ((listitem = le_data_get_listitem (data)) != NULL) {
|
||||
button = GTK_BUTTON (gtk_list_item_get_child (listitem));
|
||||
gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
|
||||
g_object_unref (listitem);
|
||||
static void
|
||||
update_current_button (LeWindow *win, GtkButton *new_button) {
|
||||
const char *non_current[1] = {NULL};
|
||||
const char *current[2] = {"current", NULL};
|
||||
|
||||
if (win->current_button) {
|
||||
gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), non_current);
|
||||
g_object_unref (win->current_button);
|
||||
}
|
||||
g_object_unref (data);
|
||||
}
|
||||
win->position = new;
|
||||
if (win->position >=0) {
|
||||
data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), win->position));
|
||||
if ((listitem = le_data_get_listitem (data)) != NULL) {
|
||||
button = GTK_BUTTON (gtk_list_item_get_child (listitem));
|
||||
gtk_widget_set_css_classes (GTK_WIDGET (button), current);
|
||||
g_object_unref (listitem);
|
||||
}
|
||||
g_object_unref (data);
|
||||
win->current_button = new_button;
|
||||
if (win->current_button) {
|
||||
g_object_ref (win->current_button);
|
||||
gtk_widget_set_css_classes (GTK_WIDGET (win->current_button), current);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----- Button "clicled" signal handlers ----- */
|
||||
static void
|
||||
app_cb (GtkButton *btn, LeWindow *win) {
|
||||
LeData *data;
|
||||
LeData *data = le_data_new_with_data ("");
|
||||
|
||||
data = le_data_new_with_data (NULL, "");
|
||||
if (win->position >= 0) {
|
||||
g_list_store_insert (win->liststore, win->position + 1, data);
|
||||
update_current (win, win->position + 1);
|
||||
update_current_position (win, win->position + 1);
|
||||
g_list_store_insert (win->liststore, win->position, data);
|
||||
} else {
|
||||
update_current_position (win, g_list_model_get_n_items (G_LIST_MODEL (win->liststore)));
|
||||
g_list_store_append (win->liststore, data);
|
||||
update_current (win, g_list_model_get_n_items (G_LIST_MODEL (win->liststore)) - 1);
|
||||
}
|
||||
g_object_unref (data);
|
||||
}
|
||||
|
||||
static void
|
||||
ins_cb (GtkButton *btn, LeWindow *win) {
|
||||
LeData *data;
|
||||
LeData *data = le_data_new_with_data ("");
|
||||
|
||||
data = le_data_new_with_data (NULL, "");
|
||||
if (win->position >= 0) {
|
||||
if (win->position >= 0)
|
||||
g_list_store_insert (win->liststore, win->position, data);
|
||||
win->position += 1;
|
||||
update_current (win, win->position - 1);
|
||||
else {
|
||||
update_current_position (win, 0);
|
||||
g_list_store_insert (win->liststore, 0, data);
|
||||
}
|
||||
g_object_unref (data);
|
||||
}
|
||||
|
||||
static void
|
||||
rm_cb (GtkButton *btn, LeWindow *win) {
|
||||
int position;
|
||||
|
||||
if (win->position >= 0) {
|
||||
position = win->position;
|
||||
win->position = -1;
|
||||
g_list_store_remove (win->liststore, position);
|
||||
update_current (win, -1);
|
||||
g_list_store_remove (win->liststore, win->position);
|
||||
update_current_position (win, -1);
|
||||
update_current_button (win, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
open_dialog_response(GtkWidget *dialog, gint response, LeWindow *win) {
|
||||
open_dialog_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) {
|
||||
GtkFileDialog *dialog = GTK_FILE_DIALOG (source_object);
|
||||
LeWindow *win = LE_WINDOW (user_data);
|
||||
GFile *file;
|
||||
char *contents;
|
||||
GListStore *liststore;
|
||||
GListStore *liststore_old;
|
||||
LeData *data;
|
||||
char *s;
|
||||
gsize length;
|
||||
GFileInputStream *stream;
|
||||
GDataInputStream *dstream;
|
||||
GError *err = NULL;
|
||||
LeData *data;
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT
|
||||
&& G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)))
|
||||
&& g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) {
|
||||
if (! (stream = g_file_read (file, NULL, &err))) {
|
||||
if ((file = gtk_file_dialog_open_finish (dialog, res, &err)) == NULL) {
|
||||
g_warning ("%s\n", err->message);
|
||||
g_error_free (err);
|
||||
return;
|
||||
}
|
||||
if ((stream = g_file_read (file, NULL, &err)) == NULL) {
|
||||
g_warning ("%s\n", err->message);
|
||||
g_error_free (err);
|
||||
return;
|
||||
}
|
||||
dstream = g_data_input_stream_new (G_INPUT_STREAM (stream));
|
||||
g_object_unref (stream);
|
||||
while ((contents = g_data_input_stream_read_line_utf8 (dstream, &length, NULL, &err)) != NULL) {
|
||||
data = le_data_new_with_data (NULL, contents);
|
||||
liststore = g_list_store_new (LE_TYPE_DATA);
|
||||
while ((contents = g_data_input_stream_read_line_utf8 (dstream, NULL, NULL, &err)) != NULL) {
|
||||
data = le_data_new_with_data (contents);
|
||||
g_list_store_append (liststore, data);
|
||||
g_free (contents);
|
||||
g_list_store_append (win->liststore, data);
|
||||
g_object_unref (data);
|
||||
}
|
||||
if (err) {
|
||||
g_warning ("%s\n", err->message);
|
||||
if (g_list_model_get_n_items(G_LIST_MODEL (win->liststore)) > 0)
|
||||
g_list_store_remove_all (win->liststore);
|
||||
return;
|
||||
} else if (! g_input_stream_close (G_INPUT_STREAM (dstream), NULL, &err)) { /* EOF */
|
||||
g_warning ("%s\n", err->message);
|
||||
g_error_free (err);
|
||||
g_object_unref (liststore);
|
||||
return;
|
||||
}
|
||||
win->file = file; /* win->file is NULL (has already checked) and it take the ownership of 'file' */
|
||||
if (! g_input_stream_close (G_INPUT_STREAM (dstream), NULL, &err)) {
|
||||
g_warning ("%s\n", err->message);
|
||||
g_error_free (err);
|
||||
g_object_unref (liststore);
|
||||
return;
|
||||
}
|
||||
/* Now the file has successfully read. */
|
||||
if (win->file)
|
||||
g_object_unref (file);
|
||||
win->file = file; /* The ownership of the GFile moves to the window. */
|
||||
s = g_file_get_basename (file);
|
||||
gtk_label_set_text (GTK_LABEL (win->filename), s);
|
||||
g_free (s);
|
||||
update_current (win, -1);
|
||||
}
|
||||
gtk_window_destroy (GTK_WINDOW (dialog));
|
||||
liststore_old = win->liststore;
|
||||
gtk_no_selection_set_model (win->noselection, G_LIST_MODEL (liststore));
|
||||
win->liststore = liststore; /* The ownership of the stringlist moves to the window. */
|
||||
g_object_unref (liststore_old);
|
||||
update_current_position (win, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
read_cb (GtkButton *btn, LeWindow *win) {
|
||||
GtkWidget *dialog;
|
||||
GtkFileDialog *dialog;
|
||||
|
||||
if (win->file || g_list_model_get_n_items (G_LIST_MODEL (win->liststore)) > 0)
|
||||
return;
|
||||
dialog = gtk_file_chooser_dialog_new ("Open file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_OPEN,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Open", GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), win);
|
||||
gtk_window_present (GTK_WINDOW (dialog));
|
||||
dialog = gtk_file_dialog_new ();
|
||||
gtk_file_dialog_open (dialog, GTK_WINDOW (win), NULL, open_dialog_cb, win);
|
||||
g_object_unref (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -293,8 +255,9 @@ write_data (LeWindow *win) {
|
|||
GFileOutputStream *ostream;
|
||||
gssize size;
|
||||
gsize length;
|
||||
LeData *data;
|
||||
int i, n_items;
|
||||
LeData *data;
|
||||
const char *s;
|
||||
GError *err = NULL;
|
||||
|
||||
if (! (ostream = g_file_replace (win->file, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &err))) {
|
||||
|
@ -305,18 +268,19 @@ write_data (LeWindow *win) {
|
|||
n_items = g_list_model_get_n_items (G_LIST_MODEL (win->liststore));
|
||||
for (i=0; i<n_items; ++i) {
|
||||
data = LE_DATA (g_list_model_get_item (G_LIST_MODEL (win->liststore), i));
|
||||
length = (gsize) strlen (le_data_look_string (data));
|
||||
size = g_output_stream_write (G_OUTPUT_STREAM (ostream), le_data_look_string (data), length, NULL, &err);
|
||||
s = le_data_look_string (data);
|
||||
length = (gsize) strlen (s);
|
||||
size = g_output_stream_write (G_OUTPUT_STREAM (ostream), s, length, NULL, &err);
|
||||
g_object_unref (data);
|
||||
if (size < 0) {
|
||||
g_warning ("%s\n", err->message);
|
||||
g_error_free (err);
|
||||
g_clear_error (&err);
|
||||
break;
|
||||
}
|
||||
size = g_output_stream_write (G_OUTPUT_STREAM (ostream), "\n", 1, NULL, &err);
|
||||
if (size < 0) {
|
||||
g_warning ("%s\n", err->message);
|
||||
g_error_free (err);
|
||||
g_clear_error (&err);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -327,36 +291,34 @@ write_data (LeWindow *win) {
|
|||
}
|
||||
|
||||
static void
|
||||
saveas_dialog_response (GtkWidget *dialog, gint response, LeWindow *win) {
|
||||
saveas_dialog_cb (GObject* source_object, GAsyncResult* res, gpointer user_data) {
|
||||
GtkFileDialog *dialog = GTK_FILE_DIALOG (source_object);
|
||||
LeWindow *win = LE_WINDOW (user_data);
|
||||
GFile *file;
|
||||
GError *err = NULL;
|
||||
char *s;
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||
if (G_IS_FILE (file)) {
|
||||
if ((file = gtk_file_dialog_save_finish (dialog, res, &err)) == NULL) {
|
||||
g_warning ("%s\n", err->message);
|
||||
g_error_free (err);
|
||||
return;
|
||||
}
|
||||
if (win->file)
|
||||
g_object_unref (win->file);
|
||||
win->file = file; /* the ownership is taken by win */
|
||||
s = g_file_get_basename (file);
|
||||
gtk_label_set_text (GTK_LABEL (win->filename), s);
|
||||
g_free (s);
|
||||
write_data (win);
|
||||
}
|
||||
else {
|
||||
g_warning ("gtk_file_chooser_get_file returns non GFile.\n");
|
||||
}
|
||||
}
|
||||
gtk_window_destroy (GTK_WINDOW (dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
show_saveas_dialog (LeWindow *win) {
|
||||
GtkWidget *dialog;
|
||||
GtkFileDialog *dialog;
|
||||
|
||||
dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
"Cancel", GTK_RESPONSE_CANCEL,
|
||||
"Save", GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), win);
|
||||
gtk_widget_show (dialog);
|
||||
dialog = gtk_file_dialog_new ();
|
||||
gtk_file_dialog_save (dialog, GTK_WINDOW (win), NULL, saveas_dialog_cb, win);
|
||||
g_object_unref (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -371,14 +333,15 @@ write_cb (GtkButton *btn, LeWindow *win) {
|
|||
|
||||
static void
|
||||
close_cb (GtkButton *btn, LeWindow *win) {
|
||||
if (g_list_model_get_n_items (G_LIST_MODEL (win->liststore)) > 0)
|
||||
guint n_items;
|
||||
|
||||
if ((n_items = g_list_model_get_n_items (G_LIST_MODEL (win->liststore))) > 0)
|
||||
g_list_store_remove_all (win->liststore);
|
||||
if (win->file) {
|
||||
g_clear_object (&win->file);
|
||||
gtk_label_set_text (GTK_LABEL (win->filename), "");
|
||||
}
|
||||
win->position = -1;
|
||||
gtk_label_set_text (GTK_LABEL (win->position_label), "");
|
||||
update_current_position (win, -1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -391,7 +354,8 @@ void
|
|||
select_cb (GtkButton *btn, GtkListItem *listitem) {
|
||||
LeWindow *win = LE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (btn), LE_TYPE_WINDOW));
|
||||
|
||||
update_current (win, gtk_list_item_get_position (listitem));
|
||||
update_current_position (win, gtk_list_item_get_position (listitem));
|
||||
update_current_button (win, btn);
|
||||
}
|
||||
|
||||
/* ----- Handlers on GtkSignalListItemFacory ----- */
|
||||
|
@ -407,24 +371,9 @@ static void
|
|||
bind1_cb (GtkListItemFactory *factory, GtkListItem *listitem, gpointer user_data) {
|
||||
LeWindow *win = LE_WINDOW (user_data);
|
||||
GtkWidget *button = gtk_list_item_get_child (listitem);
|
||||
const char *non_current[1] = {NULL};
|
||||
const char *current[2] = {"current", NULL};
|
||||
LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
|
||||
|
||||
if (data) {
|
||||
le_data_set_listitem (data, listitem);
|
||||
if (win->position == gtk_list_item_get_position (listitem))
|
||||
gtk_widget_set_css_classes (GTK_WIDGET (button), current);
|
||||
else
|
||||
gtk_widget_set_css_classes (GTK_WIDGET (button), non_current);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
unbind1_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
|
||||
LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
|
||||
if (data)
|
||||
le_data_set_listitem (data, NULL);
|
||||
update_current_button (win, GTK_BUTTON (button));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -438,7 +387,7 @@ static void
|
|||
bind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
|
||||
GtkWidget *text = gtk_list_item_get_child (listitem);
|
||||
GtkEntryBuffer *buffer = gtk_text_get_buffer (GTK_TEXT (text));
|
||||
LeData *data = LE_DATA (gtk_list_item_get_item (listitem));
|
||||
LeData *data = LE_DATA (gtk_list_item_get_item(listitem));
|
||||
GBinding *bind;
|
||||
|
||||
gtk_editable_set_text (GTK_EDITABLE (text), le_data_look_string (data));
|
||||
|
@ -452,6 +401,7 @@ static void
|
|||
unbind2_cb (GtkListItemFactory *factory, GtkListItem *listitem) {
|
||||
GBinding *bind = G_BINDING (g_object_get_data (G_OBJECT (listitem), "bind"));
|
||||
|
||||
if (bind)
|
||||
g_binding_unbind(bind);
|
||||
g_object_set_data (G_OBJECT (listitem), "bind", NULL);
|
||||
}
|
||||
|
@ -463,24 +413,29 @@ adjustment_value_changed_cb (GtkAdjustment *adjustment, gpointer user_data) {
|
|||
gtk_window_set_focus (GTK_WINDOW (win), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
le_window_init (LeWindow *win) {
|
||||
gtk_widget_init_template (GTK_WIDGET (win));
|
||||
|
||||
win->position = -1;
|
||||
win->file =NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
le_window_dispose (GObject *object) {
|
||||
LeWindow *win = LE_WINDOW (object);
|
||||
|
||||
if (win->current_button)
|
||||
g_clear_object (&win->current_button);
|
||||
if (win->file)
|
||||
g_clear_object (&win->file);
|
||||
/* this function is available since GTK 4.8 */
|
||||
gtk_widget_dispose_template (GTK_WIDGET (win), LE_TYPE_WINDOW);
|
||||
/* chain to the parent */
|
||||
G_OBJECT_CLASS (le_window_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
le_window_init (LeWindow *win) {
|
||||
gtk_widget_init_template (GTK_WIDGET (win));
|
||||
|
||||
win->position = -1;
|
||||
win->current_button = NULL;
|
||||
win->file =NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
le_window_class_init (LeWindowClass *class) {
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||
|
@ -491,6 +446,7 @@ le_window_class_init (LeWindowClass *class) {
|
|||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, position_label);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, filename);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, columnview);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, noselection);
|
||||
gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), LeWindow, liststore);
|
||||
/* The followint macros are available since GTK 4.8 */
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), app_cb);
|
||||
|
@ -502,7 +458,6 @@ le_window_class_init (LeWindowClass *class) {
|
|||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), quit_cb);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup1_cb);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind1_cb);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), unbind1_cb);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), setup2_cb);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), bind2_cb);
|
||||
gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), unbind2_cb);
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
<interface>
|
||||
<template class="LeWindow" parent="GtkApplicationWindow">
|
||||
<property name="title">list editor</property>
|
||||
<property name="default-width">600</property>
|
||||
<property name="default-height">400</property>
|
||||
<property name="default-width">1000</property>
|
||||
<property name="default-height">600</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
|
@ -95,7 +95,7 @@
|
|||
<property name="vexpand">TRUE</property>
|
||||
<property name="focusable">FALSE</property>
|
||||
<property name="model">
|
||||
<object class="GtkNoSelection">
|
||||
<object class="GtkNoSelection" id = "noselection">
|
||||
<property name="model">
|
||||
<object class="GListStore" id="liststore">
|
||||
<property name="item-type">LeData</property>
|
||||
|
@ -110,7 +110,6 @@
|
|||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup1_cb"></signal>
|
||||
<signal name="bind" handler="bind1_cb" swapped="no" object="LeWindow"></signal>
|
||||
<signal name="unbind" handler="unbind1_cb"></signal>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
|
@ -118,6 +117,7 @@
|
|||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title">String</property>
|
||||
<property name="expand">TRUE</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup2_cb"></signal>
|
||||
|
|
|
@ -6,9 +6,10 @@ The new feature is described in [Gtk API Reference -- List Widget Overview](http
|
|||
GTK 4 has other means to implement lists.
|
||||
They are GtkListBox and GtkTreeView which are took over from GTK 3.
|
||||
There's an article in [Gtk Development blog](https://blog.gtk.org/2020/06/07/scalable-lists-in-gtk-4/) about list widgets by Matthias Clasen.
|
||||
He described why GtkListView are developed to replace GtkListBox and GtkTreeView.
|
||||
He described why GtkListView are developed to replace GtkTreeView.
|
||||
GtkTreeView is deprecated since version 4.10.
|
||||
|
||||
GtkListView, GtkGridView, GtkColumnView and related objects are described in Section 26 to 29.
|
||||
GtkListView, GtkGridView, GtkColumnView and related objects are described in Section 29 to 33.
|
||||
|
||||
## Outline
|
||||
|
||||
|
@ -19,7 +20,7 @@ A list is like an array, but in many cases it is implemented with pointers which
|
|||
And it has a start point.
|
||||
So, each item can be referred by the index of the item (first item, second item, ..., nth item, ...).
|
||||
There are two cases.
|
||||
One is the index starts from one (one-based) and the other is from zero (zero-based).
|
||||
The one is the index starts from one (one-based) and the other is from zero (zero-based).
|
||||
|
||||
Gio provides GListModel interface.
|
||||
It is a zero-based list and its items are the same type of GObject descendants, or objects that implement the same interface.
|
||||
|
@ -27,11 +28,11 @@ An object implements GListModel is not a widget.
|
|||
So, the list is not displayed on the screen directly.
|
||||
There's another object GtkListView which is a widget to display the list.
|
||||
The items in the list need to be connected to the items in GtkListView.
|
||||
GtkListItemFactory instance maps items in the list to GListView.
|
||||
GtkListItemFactory instance maps items in the list to GtkListView.
|
||||
|
||||
![List](../image/list.png){width=10cm height=7.5cm}
|
||||
|
||||
## GListModel
|
||||
## GListModel and GtkStringList
|
||||
|
||||
If you want to make a list of strings with GListModel, for example, "one", "two", "three", "four", note that strings can't be items of the list.
|
||||
Because GListModel is a list of GObject objects and strings aren't GObject objects.
|
||||
|
@ -172,6 +173,7 @@ If you feel some difficulty, read this section again, especially GtkSignalListIt
|
|||
GtkBuilderListItemFactory is another GtkListItemFactory.
|
||||
Its behavior is defined with ui file.
|
||||
|
||||
@@@if gfm
|
||||
~~~xml
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
|
@ -187,6 +189,23 @@ Its behavior is defined with ui file.
|
|||
</template>
|
||||
</interface>
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.xml}
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<binding name="label">
|
||||
<lookup name="string" type="GtkStringObject">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
Template tag is used to define GtkListItem.
|
||||
And its child property is GtkLabel object.
|
||||
|
@ -209,7 +228,7 @@ There is an explanation in the [GTK Development Blog](https://blog.gtk.org/2020/
|
|||
> Remember that the classname (GtkListItem) in a ui template is used as the “this” pointer referring to the object that is being instantiated.
|
||||
|
||||
Therefore, GtkListItem instance is used as the `this` object of the lookup tag when it is evaluated.
|
||||
`this` object will be explained in [section 30](sec30).
|
||||
`this` object will be explained in [section 31](sec31).
|
||||
|
||||
The C source code is as follows.
|
||||
Its name is `list2.c` and located under [src/misc](misc) directory.
|
||||
|
@ -229,9 +248,15 @@ GtkDirectoryList is a list model containing GFileInfo objects which are informat
|
|||
It uses `g_file_enumerate_children_async()` to get the GFileInfo objects.
|
||||
The list model is created by `gtk_directory_list_new` function.
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
GtkDirectoryList *gtk_directory_list_new (const char *attributes, GFile *file);
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
GtkDirectoryList *gtk_directory_list_new (const char *attributes, GFile *file);
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
`attributes` is a comma separated list of file attributes.
|
||||
File attributes are key-value pairs.
|
||||
|
@ -252,11 +277,19 @@ The following table shows some example.
|
|||
The current directory is ".".
|
||||
The following program makes GtkDirectoryList `dl` and its contents are GFileInfo objects under the current directory.
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
GFile *file = g_file_new_for_path (".");
|
||||
GtkDirectoryList *dl = gtk_directory_list_new ("standard::name", file);
|
||||
g_object_unref (file);
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
GFile *file = g_file_new_for_path (".");
|
||||
GtkDirectoryList *dl = gtk_directory_list_new ("standard::name", file);
|
||||
g_object_unref (file);
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
It is not so difficult to make file listing program by changing `list2.c` in the previous subsection.
|
||||
One problem is that GInfoFile doesn't have properties.
|
||||
|
@ -264,8 +297,9 @@ Lookup tag look for a property, so it is useless for looking for a filename from
|
|||
Instead, closure tag is appropriate in this case.
|
||||
Closure tag specifies a function and the type of the return value of the function.
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
const char *
|
||||
char *
|
||||
get_file_name (GtkListItem *item, GFileInfo *info) {
|
||||
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
|
||||
}
|
||||
|
@ -286,6 +320,30 @@ get_file_name (GtkListItem *item, GFileInfo *info) {
|
|||
"</template>"
|
||||
"</interface>"
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
char *
|
||||
get_file_name (GtkListItem *item, GFileInfo *info) {
|
||||
return G_IS_FILE_INFO (info) ? g_strdup (g_file_info_get_name (info)) : NULL;
|
||||
}
|
||||
... ...
|
||||
... ...
|
||||
|
||||
"<interface>"
|
||||
"<template class=\"GtkListItem\">"
|
||||
"<property name=\"child\">"
|
||||
"<object class=\"GtkLabel\">"
|
||||
"<binding name=\"label\">"
|
||||
"<closure type=\"gchararray\" function=\"get_file_name\">"
|
||||
"<lookup name=\"item\">GtkListItem</lookup>"
|
||||
"</closure>"
|
||||
"</binding>"
|
||||
"</object>"
|
||||
"</property>"
|
||||
"</template>"
|
||||
"</interface>"
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
- The string "gchararray" is a type name.
|
||||
The type "gchar" is a type name and it is the same as C type "char".
|
||||
|
@ -301,7 +359,7 @@ The contents of closure tag (it is between \<closure...\> and\</closure\>) is pa
|
|||
`<lookup name="item">GtkListItem</lookup>` gives the value of the item property of the GtkListItem.
|
||||
This will be the second argument of the function.
|
||||
The first parameter is always the GListItem instance, which is a 'this' object.
|
||||
The 'this' object is explained in section 28.
|
||||
The 'this' object is explained in section 31.
|
||||
- `gtk_file_name` function is the callback function for the closure tag.
|
||||
It first checks the `info` parameter.
|
||||
Because it can be NULL when GListItem `item` is unbounded.
|
||||
|
@ -341,9 +399,15 @@ $ gcc -Wl,--export-dynamic `pkg-config --cflags gtk4` list3.c `pkg-config --libs
|
|||
|
||||
You can also make a shell script to compile `list3.c`
|
||||
|
||||
@@@if gfm
|
||||
~~~bash
|
||||
gcc -Wl,--export-dynamic `pkg-config --cflags gtk4` $1.c `pkg-config --libs gtk4`
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.bash}
|
||||
gcc -Wl,--export-dynamic `pkg-config --cflags gtk4` $1.c `pkg-config --libs gtk4`
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
Save this one liner to a file `comp`.
|
||||
Then, copy it to `$HOME/bin` and give it executable permission.
|
||||
|
@ -361,4 +425,3 @@ $ ./a.out
|
|||
~~~
|
||||
|
||||
![screenshot list3](../image/list3.png){width=10cm height=7.3cm}
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ GtkGridView (model property) => GtkSingleSelection (model property) => GtkDirect
|
|||
|
||||
The following is a part of the ui file `list4.ui`.
|
||||
|
||||
@@@if gfm
|
||||
~~~xml
|
||||
<object class="GtkListView" id="list">
|
||||
<property name="model">
|
||||
|
@ -48,6 +49,24 @@ The following is a part of the ui file `list4.ui`.
|
|||
<property name="model">singleselection</property>
|
||||
</object>
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.xml}
|
||||
<object class="GtkListView" id="list">
|
||||
<property name="model">
|
||||
<object class="GtkSingleSelection" id="singleselection">
|
||||
<property name="model">
|
||||
<object class="GtkDirectoryList" id="directorylist">
|
||||
<property name="attributes">standard::name,standard::icon,standard::content-type</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
<object class="GtkGridView" id="grid">
|
||||
<property name="model">singleselection</property>
|
||||
</object>
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
GtkDirectoryList has an "attributes" property.
|
||||
It is attributes of GFileInfo such as "standard::name", "standard::icon" and "standard::content-type".
|
||||
|
@ -62,7 +81,7 @@ Such "x-" subtype is not a standard mime type.)
|
|||
Content type is also used by desktop systems.
|
||||
|
||||
GtkGridView uses the same GtkSingleSelection instance (`singleselection`).
|
||||
So, its model property is set with it.
|
||||
So, its model property is set to it.
|
||||
|
||||
## Ui file of the window
|
||||
|
||||
|
@ -112,11 +131,19 @@ Its child widget will be set with GtkListView or GtkGridView.
|
|||
|
||||
The action `view` is created, connected to the "activate" signal handler and inserted to the window (action map) as follows.
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
act_view = g_simple_action_new_stateful ("view", g_variant_type_new("s"), g_variant_new_string ("list"));
|
||||
g_signal_connect (act_view, "activate", G_CALLBACK (view_activated), NULL);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view));
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
act_view = g_simple_action_new_stateful ("view", g_variant_type_new("s"), g_variant_new_string ("list"));
|
||||
g_signal_connect (act_view, "activate", G_CALLBACK (view_activated), NULL);
|
||||
g_action_map_add_action (G_ACTION_MAP (win), G_ACTION (act_view));
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
The signal handler `view_activated` will be explained later.
|
||||
|
||||
|
@ -198,6 +225,7 @@ You can do anything you like by connecting the "activate" signal to the handler.
|
|||
|
||||
The example `list4` launches `tfe` text file editor if the item of the list is a text file.
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
static void
|
||||
list_activate (GtkListView *list, int position, gpointer user_data) {
|
||||
|
@ -217,6 +245,27 @@ grid_activate (GtkGridView *grid, int position, gpointer user_data) {
|
|||
g_signal_connect (GTK_LIST_VIEW (list), "activate", G_CALLBACK (list_activate), NULL);
|
||||
g_signal_connect (GTK_GRID_VIEW (grid), "activate", G_CALLBACK (grid_activate), NULL);
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
static void
|
||||
list_activate (GtkListView *list, int position, gpointer user_data) {
|
||||
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_list_view_get_model (list)), position));
|
||||
launch_tfe_with_file (info);
|
||||
}
|
||||
|
||||
static void
|
||||
grid_activate (GtkGridView *grid, int position, gpointer user_data) {
|
||||
GFileInfo *info = G_FILE_INFO (g_list_model_get_item (G_LIST_MODEL (gtk_grid_view_get_model (grid)), position));
|
||||
launch_tfe_with_file (info);
|
||||
}
|
||||
|
||||
... ...
|
||||
... ...
|
||||
|
||||
g_signal_connect (GTK_LIST_VIEW (list), "activate", G_CALLBACK (list_activate), NULL);
|
||||
g_signal_connect (GTK_GRID_VIEW (grid), "activate", G_CALLBACK (grid_activate), NULL);
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
The second parameter of each handler is the position of the item (GFileInfo) of the GListModel.
|
||||
So you can get the item with `g_list_model_get_item` function.
|
||||
|
@ -254,7 +303,7 @@ The last parameter is the pointer to the pointer to a GError.
|
|||
|
||||
If your distribution supports GTK 4, using `g_app_info_launch_default_for_uri` is convenient.
|
||||
The function automatically determines the default application from the file and launches it.
|
||||
For example, if the file is text, then it launches gedit with the file.
|
||||
For example, if the file is text, then it launches GNOME text editor with the file.
|
||||
Such feature comes from desktop.
|
||||
|
||||
## Compilation and execution
|
||||
|
@ -264,7 +313,7 @@ To compile and execute list4, type as follows.
|
|||
|
||||
~~~
|
||||
$ cd list4 # or cd src/list4. It depends your current directory.
|
||||
$ meson _build
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/list4
|
||||
~~~
|
||||
|
|
163
src/sec31.src.md
163
src/sec31.src.md
|
@ -56,8 +56,8 @@ The type of the value is int.
|
|||
|G\_TYPE\_INT |int |gint | |
|
||||
|G\_TYPE\_FLOAT |float |gfloat | |
|
||||
|G\_TYPE\_DOUBLE |double|gdouble | |
|
||||
|G\_TYPE\_POINTER | |gpointer | |
|
||||
|G\_TYPE\_STRING | |gchararray|null-terminated Cstring|
|
||||
|G\_TYPE\_POINTER |void *|gpointer |general pointer |
|
||||
|G\_TYPE\_STRING |char *|gchararray|null-terminated Cstring|
|
||||
|G\_TYPE\_OBJECT | |GObject | |
|
||||
|GTK\_TYPE\_WINDOW| |GtkWindow | |
|
||||
|
||||
|
@ -79,9 +79,15 @@ Constant expression is usually used to give a constant value or instance to anot
|
|||
A property expression (GtkPropertyExpression) looks up a property in a GObject instance.
|
||||
For example, a property expression that refers "label" property in a GtkLabel object is created like this.
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
The second parameter `another_expression` is one of:
|
||||
|
||||
|
@ -91,15 +97,23 @@ The instance is called `this` object.
|
|||
|
||||
For example,
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
label = gtk_label_new ("Hello");
|
||||
another_expression = gtk_constant_expression_new (GTK_TYPE_LABEL, label);
|
||||
expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
label = gtk_label_new ("Hello");
|
||||
another_expression = gtk_constant_expression_new (GTK_TYPE_LABEL, label);
|
||||
expression = gtk_property_expression_new (GTK_TYPE_LABEL, another_expression, "label");
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
If `expression` is evaluated, the second parameter `another_expression` is evaluated in advance.
|
||||
The value of `another_expression` is the `label` (GtkLabel instance).
|
||||
Then, `expression` looks up "label" property of the label and the evaluation results "Hello".
|
||||
Then, `expression` looks up "label" property of the label and the evaluation results in "Hello".
|
||||
|
||||
In the example above, the second argument of `gtk_property_expression_new` is another expression.
|
||||
But the second argument can be NULL.
|
||||
|
@ -123,7 +137,7 @@ The expression just knows how to take the property from a future-given GtkLabel
|
|||
The result is stored in the GValue `value`.
|
||||
The function `g_value_get_string` gets a string from the GValue.
|
||||
But the string is owned by the GValue so you must not free the string.
|
||||
- 18-19: Release the expression and unset the GValue.
|
||||
- 18-19: Releases the expression and unset the GValue.
|
||||
At the same time the string in the GValue is freed.
|
||||
|
||||
If the second argument of `gtk_property_expression_new` isn't NULL, it is another expression.
|
||||
|
@ -144,6 +158,7 @@ When you program in C language, GtkCClosureExpression and GCClosure are appropri
|
|||
|
||||
A closure expression is created with `gtk_cclosure_expression_new` function.
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
GtkExpression *
|
||||
gtk_cclosure_expression_new (GType value_type,
|
||||
|
@ -154,6 +169,18 @@ gtk_cclosure_expression_new (GType value_type,
|
|||
gpointer user_data,
|
||||
GClosureNotify user_destroy);
|
||||
~~~
|
||||
@else
|
||||
~~~{.C}
|
||||
GtkExpression *
|
||||
gtk_cclosure_expression_new (GType value_type,
|
||||
GClosureMarshal marshal,
|
||||
guint n_params,
|
||||
GtkExpression **params,
|
||||
GCallback callback_func,
|
||||
gpointer user_data,
|
||||
GClosureNotify user_destroy);
|
||||
~~~
|
||||
@end
|
||||
|
||||
- `value_type` is the type of the value when it is evaluated.
|
||||
- `marshal` is a marshaller.
|
||||
|
@ -183,10 +210,17 @@ callback (this, param1, param2, ...)
|
|||
|
||||
For example,
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
int
|
||||
callback (GObject *object, int x, const char *s)
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
int
|
||||
callback (GObject *object, int x, const char *s)
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
The following is `exp_closure_simple.c` in `src/expression`.
|
||||
|
||||
|
@ -203,13 +237,13 @@ If you want to return error report, change the return value type to be a pointer
|
|||
One for error and the other for the sum.
|
||||
The first argument of `gtk_cclosure_expression_new` is `G_TYPE_POINTER`.
|
||||
There is a sample program `exp_closure_with_error_report` in `src/expression` directory.
|
||||
- 19: gtk\_init initializes GTK. It is necessary for GtkLabel.
|
||||
- 19: The function `gtk_init`` initializes GTK. It is necessary for GtkLabel.
|
||||
- 20: A GtkLabel instance is created with "123+456".
|
||||
- 21: The instance has floating reference. It is changed to an ordinary reference count.
|
||||
- 22-23: Create a closure expression. Its return value type is `G_TYPE_INT` and no parameters or 'this' object.
|
||||
- 22-23: Creates a closure expression. Its return value type is `G_TYPE_INT` and no parameters or 'this' object.
|
||||
- 24: Evaluates the expression with the label as a 'this' object.
|
||||
- 25: If the evaluation successes, show the sum of "123+456". It's 579.
|
||||
- 27: If it fails, show an error message.
|
||||
- 25: If the evaluation successes, the sum of "123+456", which is 579, is shown.
|
||||
- 27: If it fails, an error message appears.
|
||||
- 28-30: Releases the expression and the label. Unsets the value.
|
||||
|
||||
Closure expression is flexible than other type of expression because you can specify your own callback function.
|
||||
|
@ -219,12 +253,14 @@ Closure expression is flexible than other type of expression because you can spe
|
|||
GtkExpressionWatch is a structure, not an object.
|
||||
It represents a watched GtkExpression.
|
||||
Two functions create GtkExpressionWatch structure.
|
||||
They are `gtk_expression_bind` and `gtk_expression_watch`.
|
||||
|
||||
### gtk\_expression\_bind function
|
||||
|
||||
This function binds the target object's property to the expression.
|
||||
If the value of the expression changes, the property reflects the value immediately.
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
GtkExpressionWatch*
|
||||
gtk_expression_bind (
|
||||
|
@ -234,6 +270,17 @@ gtk_expression_bind (
|
|||
GObject* this_
|
||||
)
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
GtkExpressionWatch*
|
||||
gtk_expression_bind (
|
||||
GtkExpression* self,
|
||||
GObject* target,
|
||||
const char* property,
|
||||
GObject* this_
|
||||
)
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
This function takes the ownership of the expression.
|
||||
So, if you want to own the expression, call `gtk_expression_ref ()` to increase the reference count of the expression.
|
||||
|
@ -282,7 +329,7 @@ The point of the program is:
|
|||
|
||||
- 41-42: Two expressions are defined.
|
||||
One is a property expression and the other is a closure expression.
|
||||
The property expression look up the "value"property of the adjustment instance.
|
||||
The property expression looks up the "value" property of the adjustment instance.
|
||||
The closure expression just converts the double into an integer.
|
||||
- 43: `gtk_expression_bind` binds the label property of the GtkLabel instance to the integer returned by the closure expression.
|
||||
It creates a GtkExpressionWatch structure.
|
||||
|
@ -296,14 +343,15 @@ This signal is emitted when the close button is clicked.
|
|||
The handler is called just before the window closes.
|
||||
It is the right moment to make the GtkExpressionWatch unwatched.
|
||||
- 10-14: "close-request" signal handler.
|
||||
`gtk_expression_watch_unwatch (watch)` makes the watch stop watching the expression.
|
||||
It releases the expression and calls `gtk_expression_watch_unref (watch)` in it.
|
||||
The function `gtk_expression_watch_unwatch (watch)` makes the watch stop watching the expression.
|
||||
It also releases the expression.
|
||||
|
||||
If you want to bind a property to an expression, `gtk_expression_bind` is the best choice.
|
||||
You can do it with `gtk_expression_watch` function, but it is less suitable.
|
||||
|
||||
### gtk\_expression\_watch function
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
GtkExpressionWatch*
|
||||
gtk_expression_watch (
|
||||
|
@ -314,6 +362,18 @@ gtk_expression_watch (
|
|||
GDestroyNotify user_destroy
|
||||
)
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
GtkExpressionWatch*
|
||||
gtk_expression_watch (
|
||||
GtkExpression* self,
|
||||
GObject* this_,
|
||||
GtkExpressionNotify notify,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_destroy
|
||||
)
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
The function doesn't take the ownership of the expression.
|
||||
It differs from `gtk_expression_bind`.
|
||||
|
@ -326,12 +386,21 @@ Put NULL if you don't need them.
|
|||
|
||||
Notify callback has the following format.
|
||||
|
||||
@@@if gfm
|
||||
~~~C
|
||||
void
|
||||
notify (
|
||||
gpointer user_data
|
||||
)
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.C}
|
||||
void
|
||||
notify (
|
||||
gpointer user_data
|
||||
)
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
This function is used to do something when the value of the expression changes.
|
||||
But if you want to bind a property to the value, use `gtk_expression_bind` instead.
|
||||
|
@ -381,6 +450,7 @@ It is put in the content of an object tag.
|
|||
Name attribute specifies the property name of the object.
|
||||
The content is an expression.
|
||||
|
||||
@@@if gfm
|
||||
~~~xml
|
||||
<constant type="gchararray">Hello world</constant>
|
||||
<lookup name="label" type="GtkLabel">label</lookup>
|
||||
|
@ -389,16 +459,27 @@ The content is an expression.
|
|||
<lookup name="default-width">win</lookup>
|
||||
</bind>
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.xml}
|
||||
<constant type="gchararray">Hello world</constant>
|
||||
<lookup name="label" type="GtkLabel">label</lookup>
|
||||
<closure type="gint" function="callback_function"></closure>
|
||||
<bind name="label">
|
||||
<lookup name="default-width">win</lookup>
|
||||
</bind>
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
These tags are usually used for GtkBuilderListItemFactory.
|
||||
|
||||
@@@if gfm
|
||||
~~~xml
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<binding name="label">
|
||||
<lookup name="name" type="string">
|
||||
<lookup name="string" type="GtkStringObject">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
|
@ -407,15 +488,31 @@ These tags are usually used for GtkBuilderListItemFactory.
|
|||
</template>
|
||||
</interface>
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.xml}
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<binding name="label">
|
||||
<lookup name="string" type="GtkStringObject">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
GtkBuilderListItemFactory uses GtkBuilder to extends the GtkListItem with the XML data.
|
||||
|
||||
In the xml file above, "GtkListItem" is an instance of the GtkListItem template.
|
||||
It is the 'this' object given to the expressions.
|
||||
(The information is in the [GTK Development Blog](https://blog.gtk.org/2020/09/)).
|
||||
|
||||
GtkBuilderListItemFactory uses GtkBuilder to build the XML data.
|
||||
It sets the current object of the GtkBuilder to the GtkListItem instance.
|
||||
|
||||
GtkBuilder calls `gtk_expression_bind` function in the binding tag analysis.
|
||||
GtkBuilder calls `gtk_expression_bind` function when it finds a binding tag.
|
||||
The function sets the 'this' object like this:
|
||||
|
||||
1. If the binding tag has object attribute, the object will be the 'this' object.
|
||||
|
@ -466,11 +563,12 @@ String duplication is necessary.
|
|||
|
||||
The C source file is very simple because almost everything is done in the ui file.
|
||||
|
||||
### Conversion between GValues
|
||||
## Conversion between GValues
|
||||
|
||||
If you bind different type properties, type conversion is automatically done.
|
||||
Suppose a label property (string) is bound to default-width property (int).
|
||||
|
||||
@@@if gfm
|
||||
~~~xml
|
||||
<object class="GtkLabel">
|
||||
<binding name="label">
|
||||
|
@ -480,6 +578,17 @@ Suppose a label property (string) is bound to default-width property (int).
|
|||
</binding>
|
||||
</object>
|
||||
~~~
|
||||
@@@else
|
||||
~~~{.xml}
|
||||
<object class="GtkLabel">
|
||||
<binding name="label">
|
||||
<lookup name="default-width">
|
||||
win
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
The expression created by the lookup tag returns a int type GValue.
|
||||
On the other hand "label" property holds a string type GValue.
|
||||
|
@ -487,3 +596,23 @@ When a GValue is copied to another GValue, the type is automatically converted i
|
|||
If the current width is 100, an int `100` is converted to a string `"100"`.
|
||||
|
||||
If you use `g_object_get` and `g_object_set` to copy properties, the value is automatically converted.
|
||||
|
||||
## Meson.build
|
||||
|
||||
The source files are in `src/expression` directory.
|
||||
You can build all the files at once.
|
||||
|
||||
~~~
|
||||
$ cd src/expression
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
~~~
|
||||
|
||||
For example, if you want to run "exp", which is the executable file from "exp.c", type `_build/exp`.
|
||||
You can run other programs as well.
|
||||
|
||||
The file `meson.build` is as follows.
|
||||
|
||||
@@@include
|
||||
expression/meson.build
|
||||
@@@
|
||||
|
|
|
@ -60,9 +60,9 @@ This is the title on the header of the column.
|
|||
- 32: Sets the "expand" property to TRUE to allow the column to expand as much as possible.
|
||||
(See the image above).
|
||||
- 33- 69: Sets the "factory" property to GtkBuilderListItemFactory.
|
||||
The factory has "bytes" property which holds a ui string to define a template to build GtkListItem composite widget.
|
||||
The factory has "bytes" property which holds a ui string to define a template to extend GtkListItem class.
|
||||
The CDATA section (line 36-66) is the ui string to put into the "bytes" property.
|
||||
The contents are the same as the ui file `factory_list.ui` in the section 27.
|
||||
The contents are the same as the ui file `factory_list.ui` in the section 30.
|
||||
- 70-77: Sets the "sorter" property to GtkStringSorter object.
|
||||
This object provides a sorter that compares strings.
|
||||
It has "expression" property.
|
||||
|
@ -196,7 +196,8 @@ All the source files are in [`src/column`](column) directory.
|
|||
Change your current directory to the directory and type the following.
|
||||
|
||||
~~~
|
||||
$ meson _build
|
||||
$ cd src/colomn
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/column
|
||||
~~~
|
||||
|
|
158
src/sec33.src.md
158
src/sec33.src.md
|
@ -6,23 +6,14 @@ GtkBuilderlistItemFactory is convenient when GtkListView just shows the contents
|
|||
Its binding direction is always from an item of a list to a child of GtkListItem.
|
||||
|
||||
When it comes to dynamic connection, it's not enough.
|
||||
For example, you want to edit the contents of a list.
|
||||
For example, suppose you want to edit the contents of a list.
|
||||
You set a child of GtkListItem to a GtkText instance so a user can edit a text with it.
|
||||
You need to bind an item in the list with the buffer of the GtkText.
|
||||
The direction is opposite from the one with GtkBuilderListItemFactory.
|
||||
It is from the GtkText instance to the item in the list.
|
||||
You can implement this with GtkSignalListItemFactory, which is more flexible than GtkBuilderListItemFactory.
|
||||
|
||||
Two things are shown in this section.
|
||||
|
||||
- Binding from a child of a GtkListItem instance to an item of a list.
|
||||
- Access a child of GtkListItem dynamically.
|
||||
This direction is the same as the one with GtkBulderListItemFactory.
|
||||
But GtkBulderListItemFactory uses GtkExpression from the item property of the GtkListItem.
|
||||
So, it updates its child widget only when the item property changes.
|
||||
In this example the child reflects the change in the same item in the list dynamically.
|
||||
|
||||
This section shows just a part of the source file `listeditor.c`.
|
||||
This section shows just some parts of the source file `listeditor.c`.
|
||||
If you want to see the whole codes, see `src/listeditor` directory of the [Gtk4 tutorial repository](https://github.com/ToshioCP/Gtk4-tutorial).
|
||||
|
||||
## A list editor
|
||||
|
@ -33,7 +24,7 @@ It reads a text file line by line.
|
|||
Each line is an item of the list.
|
||||
The list is displayed with GtkColumnView.
|
||||
There are two columns.
|
||||
The one is a button, which makes the line be a current line.
|
||||
The one is a button, which shows if the line is a current line.
|
||||
If the line is the current line, the button is colored with red.
|
||||
The other is a string which is the contents of the corresponding item of the list.
|
||||
|
||||
|
@ -47,18 +38,18 @@ You can compile end execute it as follows.
|
|||
- Type the following on your commandline.
|
||||
|
||||
~~~
|
||||
$ meson _build
|
||||
$ meson setup _build
|
||||
$ ninja -C _build
|
||||
$ _build/listeditor
|
||||
~~~
|
||||
|
||||
- Append button: appends a line after the current line, or at the last line if no current line exists.
|
||||
- Insert button: inserts a line before the current line.
|
||||
- Insert button: inserts a line before the current line, or at the top line if no current line exists.
|
||||
- Remove button: removes a current line.
|
||||
- Read button: reads a file.
|
||||
- Write button: writes the contents to a file.
|
||||
- close button: close the contents.
|
||||
- quit button: quit the application.
|
||||
- close button: closes the contents.
|
||||
- quit button: quits the application.
|
||||
- Button on the select column: makes the line current.
|
||||
- String column: GtkText. You can edit a string in the field.
|
||||
|
||||
|
@ -69,7 +60,7 @@ The file name is shown at the right of the write button.
|
|||
|
||||
The second column (GtkColumnViewColumn) sets its factory property to GtkSignalListItemFactory.
|
||||
It uses three signals setup, bind and unbind.
|
||||
The following is their sgnal handlers.
|
||||
The following shows the signal handlers.
|
||||
|
||||
@@@include
|
||||
listeditor/listeditor.c setup2_cb bind2_cb unbind2_cb
|
||||
|
@ -84,17 +75,13 @@ So, teardown signal handler isn't necessary.
|
|||
It is called when the `listitem` is bound to an item in the list.
|
||||
The list items are LeData instances.
|
||||
LeData is defined in the file `listeditor.c` (the C source file of the list editor).
|
||||
It is a child class of GObject and has two data.
|
||||
The one is `listitem` which points a first column GtkListItem instance when they are connected.
|
||||
Be careful that the GtkListItem instance is *not* the `listitem` in this handler.
|
||||
If no GtkListItem is connected, it is NULL.
|
||||
The other is `string` which is a content of the line.
|
||||
It is a child class of GObject and has string data which is the content of the line.
|
||||
- 10-11: `text` is a child of the `listitem` and it is a GtkText instance.
|
||||
And `buffer` is a GtkTextBuffer instance of the `text`.
|
||||
And `buffer` is a GtkEntryBuffer instance of the `text`.
|
||||
- 12: The LeData instance `data` is an item pointed by the `listitem`.
|
||||
- 15-16: Sets the text of `text` to `le_data_look_string (data)`.
|
||||
le\_data\_look\_string returns the string of the `data` and the ownership of the string is still taken by the `data`.
|
||||
So, the caller don't need to free the string.
|
||||
So, the caller doesn't need to free the string.
|
||||
- 18: `g_object_bind_property` binds a property and another object property.
|
||||
This line binds the "text" property of the `buffer` (source) and the "string" property of the `data` (destination).
|
||||
It is a uni-directional binding (`G_BINDING_DEFAULT`).
|
||||
|
@ -107,14 +94,19 @@ The key is a string (or GQuark) and the value is a gpointer (pointer to any type
|
|||
The function `g_object_set_data` sets the association from the key to the value.
|
||||
This line sets the association from "bind" to `bind` instance.
|
||||
It makes possible for the "unbind" handler to get the `bind` instance.
|
||||
- 22-28: `unbind2_cb` is a unbind signal handler.
|
||||
- 22-29: `unbind2_cb` is a unbind signal handler.
|
||||
- 24: Retrieves the `bind` instance from the table in the `listitem` instance.
|
||||
- 26: Unbind the binding.
|
||||
- 27: Removes the value corresponds to the "bind" key.
|
||||
- 26-27: Unbind the binding.
|
||||
- 28: Removes the value corresponds to the "bind" key.
|
||||
|
||||
This technique is not so complicated.
|
||||
You can use it when you make a cell editable application.
|
||||
|
||||
If it is impossible to use `g_object_bind_property`, use a notify signal on the GtkEntryBuffer instance.
|
||||
You can use "deleted-text" and "inserted-text" signal instead.
|
||||
The handler of the signals above copies the text in the GtkEntryBuffer instance to the LeData string.
|
||||
Connect the notify signal handler in `bind2_cb` and disconnect it in `unbind2_cb`.
|
||||
|
||||
## Change the cell of GtkColumnView dynamically
|
||||
|
||||
Next topic is to change the GtkColumnView (or GtkListView) cells dynamically.
|
||||
|
@ -139,85 +131,79 @@ The current line doesn't need to be on the display.
|
|||
It is possible to be on the line out of the Window (GtkScrolledWindow).
|
||||
Actually, the program doesn't use GtkSingleSelection.
|
||||
|
||||
It is necessary to know the corresponding GtkListItem instance from the item in the list.
|
||||
It is the opposite direction from `gtk_list_item_get_item` function.
|
||||
To accomplish this, we set a `listitem` element of LeData to point the corresponding GtkListItem instance.
|
||||
Therefore, items (LeData) in the list always know the GtkListItem.
|
||||
If there's no GtkListItem bound to the item, NULL is assigned.
|
||||
The LeWindow instance has two instance variables for recording the current line.
|
||||
|
||||
- `win->position`: An int type variable. It is the position of the current line. It is zero-based. If no current line exists, it is -1.
|
||||
- `win->current_button`: A variable points the button, located at the first column, on the current line. If no current line exists, it is NULL.
|
||||
|
||||
If the current line moves, the following two functions are called.
|
||||
They updates the two varables.
|
||||
|
||||
@@@include
|
||||
listeditor/listeditor.c select_cb setup1_cb bind1_cb unbind1_cb
|
||||
listeditor/listeditor.c update_current_position update_current_button
|
||||
@@@
|
||||
|
||||
- 8-14: `setup1_cb` is a setup signal handler on the GtkSignalListItemFactory.
|
||||
This factory is inserted to the factory property of the first GtkColumnViewColumn.
|
||||
The varable `win->position_label` points a GtkLabel instance.
|
||||
The label shows the current line position.
|
||||
|
||||
The current button has CSS "current" class.
|
||||
The button is colored red through the CSS "button.current {background: red;}".
|
||||
|
||||
The order of the call for these two functions is important.
|
||||
The first function, which updates the position, is usually called first.
|
||||
After that, a new line is appended or inserted.
|
||||
Then, the second function is called.
|
||||
|
||||
The following functions call the two functions above.
|
||||
Be careful about the order of the call.
|
||||
|
||||
@@@include
|
||||
listeditor/listeditor.c select_cb setup1_cb bind1_cb
|
||||
@@@
|
||||
|
||||
- 1-7: `select_cb` is a "clicked" signal handler.
|
||||
The handler just calls the two functions and update the position and button.
|
||||
- 9-15: `setup1_cb` is a setup signal handler on the GtkSignalListItemFactory.
|
||||
It sets the child of `listitem` to a GtkButton instance.
|
||||
The "clicked" signal on the button is connected to the handler `select_cb`.
|
||||
When the listitem is destroyed, the child (GtkButton) is also destroyed.
|
||||
At the same time, the connection of the signal and the handler is also destroyed.
|
||||
So, you don't need teardown signal handler.
|
||||
- 1-6: `select_cb` is a "clicked" signal handler.
|
||||
LeWindow is defined in `listeditor.c`.
|
||||
It's a child class of GtkApplicationWindow.
|
||||
The handler just calls the `update_current` function.
|
||||
The function will be explained later.
|
||||
- 16-31: `bind1_cb` is a bind signal handler.
|
||||
It sets the "listitem" element of the item (LeData) to point the `listitem` (GtkListItem instance).
|
||||
It makes the item possible to find the corresponding GtkListItem instance.
|
||||
If the item is the current line, the CSS class of the button includes "current" class.
|
||||
Otherwise it has no CSS class.
|
||||
This is necessary because the button may be recycled and it has had former CSS class.
|
||||
The class need to be updated.
|
||||
- 33-38: `unbind1_cb` is an unbind signal handler.
|
||||
It removes the `listitem` instance from the "listitem" element of the item.
|
||||
The element becomes NULL, which tells no GtkListItem is bound.
|
||||
When referring GtkListItem, it needs to check the "listitem" element whether it points a GtkListItem or not (NULL).
|
||||
Otherwise bad things will happen.
|
||||
- 17-24: `bind1_cb` is a bind signal handler.
|
||||
Usually, the position moves before this handler is called.
|
||||
If the item is on the current line, the button is updated.
|
||||
No unbind handler is necessary.
|
||||
|
||||
When a line is added, the current position is updated in advance.
|
||||
|
||||
@@@include
|
||||
listeditor/listeditor.c update_current
|
||||
listeditor/listeditor.c app_cb ins_cb
|
||||
@@@
|
||||
|
||||
The function `update_current` does several things.
|
||||
When a line is removed, the current position becomes -1 and no button is current.
|
||||
|
||||
- It has two parameters.
|
||||
The first one is `win`, which is an instance of LeWindow class.
|
||||
It has some elements.
|
||||
- win->position: an Integer. it is the current position. If no current line exists, it is -1.
|
||||
- win->position_label: GtkLabel. It shows the current position.
|
||||
- The second parameter is `new`, which is the new current position.
|
||||
At the beginning of the function, win->position points the old position.
|
||||
- 10-16: Update the text of GtkLabel.
|
||||
- 18-26: If the old position (win->position) is not negative, the current line exists.
|
||||
It gets a GtkListItem instance via the item (LeData) of the list.
|
||||
And it gets the GtkButton instance which is the child of the GtkListItem.
|
||||
It clears the "css-classes" property of the button.
|
||||
- 27: Updates win->position.
|
||||
- 28-36: If the new position is not negative (It's possible to be negative when the current line has been removed), the current line exists.
|
||||
It sets the "css-classes" property of the button to `{"current", NULL}`.
|
||||
It is a NULL-terminated array of strings.
|
||||
Each string is a CSS class.
|
||||
Now the button has "current" style class.
|
||||
@@@include
|
||||
listeditor/listeditor.c rm_cb
|
||||
@@@
|
||||
|
||||
The color of buttons are determined by the "background" CSS style.
|
||||
The following CSS is applied to the default GdkDisplay in advance (in the startup handler of the application).
|
||||
The following CSS node is a bit complicated.
|
||||
CSS node `column view` has `listview` child node.
|
||||
It covers the rows in the GtkColumnView.
|
||||
The `listview` node is the same as the one for GtkListView.
|
||||
It has `row` child node, which is for each child widget.
|
||||
Therefore, the following node corresponds buttons on the GtkColumnView widget.
|
||||
In addition, it is applied to the "current" class.
|
||||
|
||||
@@@if gfm
|
||||
~~~css
|
||||
columnview listview row button.current {background: red;}
|
||||
~~~
|
||||
|
||||
The selectors "columnview listview row" is needed before "button" selector.
|
||||
Otherwise the buttons in the GtkColumnview won't be found.
|
||||
The button selector has "current" class.
|
||||
So, the only "current" class button is colored with red.
|
||||
Other buttons are not colored, which means they are white.
|
||||
|
||||
## Gtk\_widget\_dispose\_template function
|
||||
|
||||
The function `gtk_widget_dispose_template` clears the template children for the given widget.
|
||||
This is the opposite of `gtk_widget_init_template()`.
|
||||
It is a new function of GTK 4.8 version.
|
||||
If your GTK version is lower than 4.8, you need to modify the program.
|
||||
@@@else
|
||||
~~~{.css}
|
||||
columnview listview row button.current {background: red;}
|
||||
~~~
|
||||
@@@end
|
||||
|
||||
## A waring from GtkText
|
||||
|
||||
|
|
Loading…
Reference in a new issue