Commit dc858c96 authored by Matthias Clasen's avatar Matthias Clasen

docs: Convert treeview and textview overview to markdown

parent 581b39a3
......@@ -178,7 +178,7 @@
<chapter id="TextWidgetObjects">
<title>Multiline Text Editor</title>
<xi:include href="xml/text_widget.xml" />
<xi:include href="section-text-widget.xml" />
<xi:include href="xml/gtktextiter.xml" />
<xi:include href="xml/gtktextmark.xml" />
<xi:include href="xml/gtktextbuffer.xml" />
......@@ -189,7 +189,7 @@
<chapter id="TreeWidgetObjects">
<title>Tree, List and Icon Grid Widgets</title>
<xi:include href="xml/tree_widget.xml" />
<xi:include href="section-tree-widget.xml" />
<xi:include href="xml/gtktreemodel.xml" />
<xi:include href="xml/gtktreeselection.xml" />
<xi:include href="xml/gtktreeviewcolumn.xml" />
......
......@@ -352,15 +352,11 @@ content_files = [
'gtk4-widget-factory.xml',
'overview.xml',
'question_index.xml',
'text_widget.xml',
'tree_widget.xml',
'visual_index.xml',
]
expand_content_files = [
'question_index.xml',
'text_widget.xml',
'tree_widget.xml',
]
expand_content_md_files = [
......@@ -368,7 +364,7 @@ expand_content_md_files = [
'osx.md',
'wayland.md',
'windows.md',
: 'x11.md',
'x11.md',
'getting_started.md',
'resources.md',
'building.md',
......@@ -380,7 +376,9 @@ expand_content_md_files = [
'input-handling.md',
'drawing-model.md',
'css-overview.md',
'css-properties.md'
'css-properties.md',
'section-text-widget.md',
'section-tree-widget.md',
]
types_conf = configuration_data()
......
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="TextWidget">
<refmeta>
<refentrytitle>Text Widget Overview</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Text Widget Overview</refname>
<refpurpose>Overview of GtkTextBuffer, GtkTextView, and friends</refpurpose>
</refnamediv>
<refsect1>
<title>Conceptual Overview</title>
<para>
# Text Widget Overview {#TextWidget}
GTK has an extremely powerful framework for multiline text editing. The
primary objects involved in the process are #GtkTextBuffer, which represents the
text being edited, and #GtkTextView, a widget which can display a #GtkTextBuffer.
Each buffer can be displayed by any number of views.
</para>
<para>
One of the important things to remember about text in GTK is that it's in the
UTF-8 encoding. This means that one character can be encoded as multiple
bytes. Character counts are usually referred to as
<firstterm>offsets</firstterm>, while byte counts are called
<firstterm>indexes</firstterm>. If you confuse these two, things will work fine
One of the important things to remember about text in GTK is that it's in
the UTF-8 encoding. This means that one character can be encoded as multiple
bytes. Character counts are usually referred to as _offsets_, while byte
counts are called _indexes_. If you confuse these two, things will work fine
with ASCII, but as soon as your buffer contains multibyte characters, bad
things will happen.
</para>
<para>
Text in a buffer can be marked with <firstterm>tags</firstterm>. A tag is an
attribute that can be applied to some range of text. For example, a tag might
be called "bold" and make the text inside the tag bold. However, the tag
concept is more general than that; tags don't have to affect appearance. They
can instead affect the behavior of mouse and key presses, "lock" a range of
text so the user can't edit it, or countless other things. A tag is
represented by a #GtkTextTag object. One #GtkTextTag can be applied to any
number of text ranges in any number of buffers.
</para>
<para>
Text in a buffer can be marked with _tags_. A tag is an attribute that can
be applied to some range of text. For example, a tag might be called "bold"
and make the text inside the tag bold. However, the tag concept is more
general than that; tags don't have to affect appearance. They can instead
affect the behavior of mouse and key presses, "lock" a range of text so the
user can't edit it, or countless other things. A tag is represented by a
#GtkTextTag object. One #GtkTextTag can be applied to any number of text
ranges in any number of buffers.
Each tag is stored in a #GtkTextTagTable. A tag table defines a set of
tags that can be used together. Each buffer has one tag table associated with
it; only tags from that tag table can be used with the buffer. A single tag
table can be shared between multiple buffers, however.
</para>
<para>
Tags can have names, which is convenient sometimes (for example, you can name
your tag that makes things bold "bold"), but they can also be anonymous (which
is convenient if you're creating tags on-the-fly).
</para>
<para>
Most text manipulation is accomplished with <firstterm>iterators</firstterm>,
represented by a #GtkTextIter. An iterator represents a position between two
characters in the text buffer. #GtkTextIter is a struct designed to be
allocated on the stack; it's guaranteed to be copiable by value and never
contain any heap-allocated data. Iterators are not valid indefinitely;
whenever the buffer is modified in a way that affects the number of characters
in the buffer, all outstanding iterators become invalid. (Note that deleting
5 characters and then reinserting 5 still invalidates iterators, though you
Most text manipulation is accomplished with _iterators_, represented by a
#GtkTextIter. An iterator represents a position between two characters in
the text buffer. #GtkTextIter is a struct designed to be allocated on the
stack; it's guaranteed to be copiable by value and never contain any
heap-allocated data. Iterators are not valid indefinitely; whenever the
buffer is modified in a way that affects the number of characters in the
buffer, all outstanding iterators become invalid. (Note that deleting 5
characters and then reinserting 5 still invalidates iterators, though you
end up with the same number of characters you pass through a state with a
different number).
</para>
<para>
Because of this, iterators can't be used to preserve positions across buffer
modifications. To preserve a position, the #GtkTextMark object is ideal. You
can think of a mark as an invisible cursor or insertion point; it floats in
the buffer, saving a position. If the text surrounding the mark is deleted,
the mark remains in the position the text once occupied; if text is inserted
at the mark, the mark ends up either to the left or to the right of the new
text, depending on its <firstterm>gravity</firstterm>. The standard text
cursor in left-to-right languages is a mark with right gravity, because it
stays to the right of inserted text.
</para>
<para>
Like tags, marks can be either named or anonymous. There are two marks built-in
to #GtkTextBuffer; these are named <literal>"insert"</literal> and
<literal>"selection_bound"</literal> and refer to the insertion point and the
boundary of the selection which is not the insertion point, respectively. If
no text is selected, these two marks will be in the same position. You can
manipulate what is selected and where the cursor appears by moving these
marks around.
<footnote>
<para>
text, depending on its _gravity_. The standard text cursor in left-to-right
languages is a mark with right gravity, because it stays to the right of
inserted text.
Like tags, marks can be either named or anonymous. There are two marks
built-in to #GtkTextBuffer; these are named "insert" and "selection_bound"
and refer to the insertion point and the boundary of the selection which
is not the insertion point, respectively. If no text is selected, these
two marks will be in the same position. You can manipulate what is selected
and where the cursor appears by moving these marks around.
If you want to place the cursor in response to a user action, be sure to use
gtk_text_buffer_place_cursor(), which moves both at once without causing a
temporary selection (moving one then the other temporarily selects the range in
between the old and new positions).
</para>
</footnote>
</para>
<para>
Text buffers always contain at least one line, but may be empty (that
is, buffers can contain zero characters). The last line in the text
buffer never ends in a line separator (such as newline); the other
......@@ -110,9 +71,7 @@ count as characters when computing character counts and character
offsets. Note that some Unicode line separators are represented with
multiple bytes in UTF-8, and the two-character sequence "\r\n" is also
considered a line separator.
</para>
<para>
Text buffers support undo and redo if gtk_text_buffer_set_enable_undo()
has been set to %TRUE. Use gtk_text_buffer_undo() or gtk_text_buffer_redo()
to perform the necessary action. Note that these operations are ignored if
......@@ -120,96 +79,79 @@ the buffer is not editable. Developers may want some operations to not be
undoable. To do this, wrap your changes in
gtk_text_buffer_begin_irreversible_action() and
gtk_text_buffer_end_irreversible_action().
</para>
</refsect1>
## Simple Example
The simplest usage of #GtkTextView might look like this:
<refsect1>
<title>Simple Example</title>
``` {.c}
GtkWidget *view;
GtkTextBuffer *buffer;
<para>
The simplest usage of #GtkTextView might look like this:
<informalexample><programlisting>
GtkWidget *view;
GtkTextBuffer *buffer;
view = gtk_text_view_new ();
view = gtk_text_view_new (<!-- -->);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1);
gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1);
/* Now you might put the view in a container and display it on the
* screen; when the user edits the text, signals on the buffer
* will be emitted, such as "changed", "insert_text", and so on.
*/
```
/* Now you might put the view in a container and display it on the
* screen; when the user edits the text, signals on the buffer
* will be emitted, such as "changed", "insert_text", and so on.
*/
</programlisting></informalexample>
In many cases it's also convenient to first create the buffer with
gtk_text_buffer_new(), then create a widget for that buffer with
gtk_text_view_new_with_buffer(). Or you can change the buffer the widget
displays after the widget is created with gtk_text_view_set_buffer().
</para>
</refsect1>
<refsect1>
<title>Example of Changing Text Attributes</title>
<para>
## Example of Changing Text Attributes
The way to affect text attributes in #GtkTextView is to
apply tags that change the attributes for a region of text.
For text features that come from the theme &mdash; such as font and
foreground color &mdash; use CSS to override their default values.
<informalexample><programlisting>
GtkWidget *view;
GtkTextBuffer *buffer;
GtkTextIter start, end;
PangoFontDescription *font_desc;
GdkRGBA rgba;
GtkTextTag *tag;
GtkCssProvider *provider;
GtkStyleContext *context;
view = gtk_text_view_new (<!-- -->);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1);
/* Change default font and color throughout the widget */
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider,
"textview {"
" font: 15 serif;"
" color: green;"
"}",
-1);
context = gtk_widget_get_style_context (view);
gtk_style_context_add_provider (context,
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
/* Change left margin throughout the widget */
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 30);
/* Use a tag to change the color for just one part of the widget */
tag = gtk_text_buffer_create_tag (buffer, "blue_foreground",
"foreground", "blue", NULL);
gtk_text_buffer_get_iter_at_offset (buffer, &amp;start, 7);
gtk_text_buffer_get_iter_at_offset (buffer, &amp;end, 12);
gtk_text_buffer_apply_tag (buffer, tag, &amp;start, &amp;end);
</programlisting></informalexample>
</para>
<para>
The <application>gtk-demo</application> application that comes with
foreground color -- use CSS to override their default values.
```
GtkWidget *view;
GtkTextBuffer *buffer;
GtkTextIter start, end;
PangoFontDescription *font_desc;
GdkRGBA rgba;
GtkTextTag *tag;
GtkCssProvider *provider;
GtkStyleContext *context;
view = gtk_text_view_new ();
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_set_text (buffer, "Hello, this is some text", -1);
/* Change default font and color throughout the widget */
provider = gtk_css_provider_new ();
gtk_css_provider_load_from_data (provider,
"textview {"
" font: 15 serif;"
" color: green;"
"}",
-1);
context = gtk_widget_get_style_context (view);
gtk_style_context_add_provider (context,
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
/* Change left margin throughout the widget */
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 30);
/* Use a tag to change the color for just one part of the widget */
tag = gtk_text_buffer_create_tag (buffer, "blue_foreground",
"foreground", "blue",
NULL);
gtk_text_buffer_get_iter_at_offset (buffer, &amp;start, 7);
gtk_text_buffer_get_iter_at_offset (buffer, &amp;end, 12);
gtk_text_buffer_apply_tag (buffer, tag, &amp;start, &amp;end);
```
The `gtk4-demo` application that comes with
GTK contains more example code for #GtkTextView.
</para>
</refsect1>
</refentry>
<?xml version="1.0"?>
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
"http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<refentry id="TreeWidget">
<refmeta>
<refentrytitle>Tree and List Widget Overview</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>GTK Library</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Tree and List Widget Overview</refname>
<refpurpose>Overview of GtkTreeModel, GtkTreeView, and friends</refpurpose>
</refnamediv>
<refsect1>
<title>Overview</title>
<para>
To create a tree or list in GTK, use the #GtkTreeModel interface in
conjunction with the #GtkTreeView widget. This widget is
designed around a <firstterm>Model/View/Controller</firstterm>
design and consists of four major parts:
<simplelist>
<member>The tree view widget (<structname>GtkTreeView</structname>)</member>
<member>The view column (<structname>GtkTreeViewColumn</structname>)</member>
<member>The cell renderers (<structname>GtkCellRenderer</structname> etc.)</member>
<member>The model interface (<structname>GtkTreeModel</structname>)</member>
</simplelist>
The <emphasis>View</emphasis> is composed of the first three
objects, while the last is the <emphasis>Model</emphasis>. One
of the prime benefits of the MVC design is that multiple views
can be created of a single model. For example, a model mapping
the file system could be created for a file manager. Many views
could be created to display various parts of the file system,
but only one copy need be kept in memory.
</para>
<para>
The purpose of the cell renderers is to provide extensibility to the
widget and to allow multiple ways of rendering the same type of data.
For example, consider how to render a boolean variable. Should it
render it as a string of "True" or "False", "On" or "Off", or should
it be rendered as a checkbox?
</para>
</refsect1>
<refsect1>
<title>Creating a model</title>
<para>
GTK provides two simple models that can be used: the #GtkListStore
and the #GtkTreeStore. GtkListStore is used to model list widgets,
while the GtkTreeStore models trees. It is possible to develop a new
type of model, but the existing models should be satisfactory for all
but the most specialized of situations. Creating the model is quite
simple:
</para>
<informalexample><programlisting><![CDATA[
# Tree and List Widget Overview {#TreeWidget}
To create a tree or list in GTK, use the #GtkTreeModel interface in
conjunction with the #GtkTreeView widget. This widget is designed around
a _Model/View/Controller_ design and consists of four major parts:
- The tree view widget (GtkTreeView)
- The view column (GtkTreeViewColumn)
- The cell renderers (GtkCellRenderer etc.)
- The model interface (GtkTreeModel)
The _View_ is composed of the first three objects, while the last is the
_Model_. One of the prime benefits of the MVC design is that multiple views
can be created of a single model. For example, a model mapping the file
system could be created for a file manager. Many views could be created
to display various parts of the file system, but only one copy need be
kept in memory.
The purpose of the cell renderers is to provide extensibility to the
widget and to allow multiple ways of rendering the same type of data.
For example, consider how to render a boolean variable. Should it
render it as a string of "True" or "False", "On" or "Off", or should
it be rendered as a checkbox?
## Creating a model
GTK provides two simple models that can be used: the #GtkListStore
and the #GtkTreeStore. GtkListStore is used to model list widgets,
while the GtkTreeStore models trees. It is possible to develop a new
type of model, but the existing models should be satisfactory for all
but the most specialized of situations. Creating the model is quite
``` {.c}
GtkListStore *store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_BOOLEAN);
]]></programlisting></informalexample>
<para>
This creates a list store with two columns: a string column and a boolean
column. Typically the 2 is never passed directly like that; usually an
enum is created wherein the different columns are enumerated, followed by
a token that represents the total number of columns. The next example will
illustrate this, only using a tree store instead of a list store. Creating
a tree store operates almost exactly the same.
</para>
<informalexample><programlisting><![CDATA[
```
This creates a list store with two columns: a string column and a boolean
column. Typically the 2 is never passed directly like that; usually an
enum is created wherein the different columns are enumerated, followed by
a token that represents the total number of columns. The next example will
illustrate this, only using a tree store instead of a list store. Creating
a tree store operates almost exactly the same.
``` {.c}
enum
{
TITLE_COLUMN,
......@@ -77,20 +54,19 @@ GtkTreeStore *store = gtk_tree_store_new (N_COLUMNS, /* Total number of co
G_TYPE_STRING, /* Book title */
G_TYPE_STRING, /* Author */
G_TYPE_BOOLEAN); /* Is checked out? */
]]></programlisting></informalexample>
<para>
Adding data to the model is done using gtk_tree_store_set() or
gtk_list_store_set(), depending upon which sort of model was
created. To do this, a #GtkTreeIter must be acquired. The iterator
points to the location where data will be added.
</para>
<para>
Once an iterator has been acquired, gtk_tree_store_set() is used to
apply data to the part of the model that the iterator points to.
Consider the following example:
</para>
<informalexample><programlisting><![CDATA[
GtkTreeIter iter;
```
Adding data to the model is done using gtk_tree_store_set() or
gtk_list_store_set(), depending upon which sort of model was
created. To do this, a #GtkTreeIter must be acquired. The iterator
points to the location where data will be added.
Once an iterator has been acquired, gtk_tree_store_set() is used to
apply data to the part of the model that the iterator points to.
Consider the following example:
``` {.c}
GtkTreeIter iter;
gtk_tree_store_append (store, &iter, NULL); /* Acquire an iterator */
......@@ -99,21 +75,19 @@ gtk_tree_store_set (store, &iter,
AUTHOR_COLUMN, "Martin Heidegger",
CHECKED_COLUMN, FALSE,
-1);
]]></programlisting></informalexample>
<para>
Notice that the last argument is -1. This is always done because
this is a variable-argument function and it needs to know when to stop
processing arguments. It can be used to set the data in any or all
columns in a given row.
</para>
<para>
The third argument to gtk_tree_store_append() is the parent iterator. It
is used to add a row to a GtkTreeStore as a child of an existing row. This
means that the new row will only be visible when its parent is visible and
in its expanded state. Consider the following example:
</para>
<informalexample><programlisting><![CDATA[
```
Notice that the last argument is -1. This is always done because
this is a variable-argument function and it needs to know when to stop
processing arguments. It can be used to set the data in any or all
columns in a given row.
The third argument to gtk_tree_store_append() is the parent iterator.
It is used to add a row to a GtkTreeStore as a child of an existing row.
This means that the new row will only be visible when its parent is visible
and in its expanded state. Consider the following example:
``` {.c}
GtkTreeIter iter1; /* Parent iter */
GtkTreeIter iter2; /* Child iter */
......@@ -138,44 +112,39 @@ gtk_tree_store_append (store, &iter2, &iter1);
gtk_tree_store_set (store, &iter2,
TITLE_COLUMN, "Volume 3: Sorting and Searching",
-1);
]]></programlisting></informalexample>
</refsect1>
<refsect1>
<title>Creating the view component</title>
<para>
While there are several different models to choose from, there is
only one view widget to deal with. It works with either the list
or the tree store. Setting up a #GtkTreeView is not a difficult
matter. It needs a #GtkTreeModel to know where to retrieve its data
from.
</para>
<informalexample><programlisting><![CDATA[
```
## Creating the view component
While there are several different models to choose from, there is
only one view widget to deal with. It works with either the list
or the tree store. Setting up a #GtkTreeView is not a difficult
matter. It needs a #GtkTreeModel to know where to retrieve its data
from.
``` {.c}
GtkWidget *tree;
tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
]]></programlisting></informalexample>
<refsect2>
<title>Columns and cell renderers</title>
<para>
Once the #GtkTreeView widget has a model, it will need to know how
to display the model. It does this with columns and cell renderers.
</para>
<para>
Cell renderers are used to draw the data in the tree model in a
way. There are a number of cell renderers that come with GTK,
including the #GtkCellRendererText, #GtkCellRendererPixbuf and
the #GtkCellRendererToggle.
It is relatively easy to write a custom renderer.
</para>
<para>
A #GtkTreeViewColumn is the object that GtkTreeView uses to organize
the vertical columns in the tree view. It needs to know the name of
the column to label for the user, what type of cell renderer to use,
and which piece of data to retrieve from the model for a given row.
</para>
<informalexample><programlisting>
```
## Colums and cell renderers
Once the #GtkTreeView widget has a model, it will need to know how
to display the model. It does this with columns and cell renderers.
Cell renderers are used to draw the data in the tree model in a
way. There are a number of cell renderers that come with GTK,
including the #GtkCellRendererText, #GtkCellRendererPixbuf and
the #GtkCellRendererToggle. It is relatively easy to write a
custom renderer.
A #GtkTreeViewColumn is the object that GtkTreeView uses to organize
the vertical columns in the tree view. It needs to know the name of
the column to label for the user, what type of cell renderer to use,
and which piece of data to retrieve from the model for a given row.
``` {.c}
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
......@@ -185,23 +154,20 @@ column = gtk_tree_view_column_new_with_attributes ("Author",
"text", AUTHOR_COLUMN,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree), column);
</programlisting></informalexample>
<para>
At this point, all the steps in creating a displayable tree have been
covered. The model is created, data is stored in it, a tree view is
created and columns are added to it.
</para>
</refsect2>
<refsect2>
<title>Selection handling</title>
<para>
Most applications will need to not only deal with displaying data, but
also receiving input events from users. To do this, simply get a
reference to a selection object and connect to the
#GtkTreeSelection::changed signal.
</para>
<informalexample><programlisting><![CDATA[
```