Merge pull request #21 from PaulSchulz/main

Some more edits. Sec 9 and 22.
This commit is contained in:
ToshioCP 2022-03-07 17:57:02 +09:00 committed by GitHub
commit 978e5b1a34
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 190 additions and 174 deletions

View file

@ -3,8 +3,8 @@
#### Contents of this Repository
This tutorial illustrates how to write C programs with the Gtk4 library.
It focuses on beginners so the contents are limited to basic things.
The table of contents is shown at the end of this abstract.
It focuses on beginners so the contents are limited to the basics.
The table of contents is at the end of this abstract.
- Section 3 to 21 describes the basics, with the example of a simple editor `tfe` (Text File Editor).
- Section 22 to 24 describes GtkDrawingArea.
@ -56,7 +56,7 @@ There is a documentation \("[How to build Gtk4 Tutorial](gfm/Readme_for_develope
1. [String and memory management](gfm/sec6.md)
1. [Widgets (3)](gfm/sec7.md)
1. [Defining a Child object](gfm/sec8.md)
1. [Ui file and GtkBuilder](gfm/sec9.md)
1. [The User Interface (UI) file and GtkBuilder](gfm/sec9.md)
1. [Build system](gfm/sec10.md)
1. [Initialization and destruction of instances](gfm/sec11.md)
1. [Signals](gfm/sec12.md)

View file

@ -2,49 +2,54 @@ Up: [Readme.md](../Readme.md), Prev: [Section 21](sec21.md), Next: [Section 23]
# GtkDrawingArea and Cairo
If you want to draw dynamically, like an image window of gimp graphics editor, GtkDrawingArea widget is the most suitable widget.
You can draw or redraw an image in this widget freely.
It is called custom drawing.
If you want to draw dynamically on the screen, like an image window of gimp graphics editor, the GtkDrawingArea widget is the most suitable widget.
You can freely draw or redraw an image in this widget.
This is called custom drawing.
GtkDrawingArea provides a cairo context so users can draw images by cairo functions.
GtkDrawingArea provides a cairo drawing context so users can draw images by using cairo functions.
In this section, I will explain:
1. Cairo, but briefly.
2. GtkDrawingArea with very simple example.
1. Cairo, but only briefly; and
2. GtkDrawingArea, with a very simple example.
## Cairo
Cairo is a two dimensional graphics library.
First, you need to know surface, source, mask, destination, cairo context and transformation.
Cairo is a set of two dimensional graphical drawing functions (or graphics library).
There is a lot of documentation on [Cairo's website](https://www.cairographics.org/).
If you aren't familiar with Cairo, it is worth reading their [tutorial](https://www.cairographics.org/tutorial/).
- Surface represents an image.
The following is a gentle introduction on the Cairo library and how to use it.
Firstly, in order to use Cairo you need to know about surfaces, sources, masks, destinations, cairo context and transformations.
- A surface represents an image.
It is like a canvas.
We can draw shapes and images with different colors on surfaces.
- Source pattern, or simply source, is a kind of paint, which will be transferred to destination surface by cairo functions.
- Mask is image mask used in the transference.
- Destination is a target surface.
- Cairo context manages the transference from source to destination through mask with its functions.
For example, `cairo_stroke` is a function to draw a path to the destination by the transference.
- Transformation is applied before the transfer completes.
The transformation is called affine, which is a mathematics terminology, and represented by matrix multiplication and vector addition.
Scaling, rotation, reflection, shearing and translation are examples of affine transformation.
In this section, we don't use it.
That means we only use identity transformation.
Therefore, the coordinate in source and mask is the same as the coordinate in destination.
- The source pattern, or simply source, is like paint, which will be transferred to destination surface by cairo functions.
- The mask describes the area to be used in the copy;
- The destination is a target surface;
- The cairo context manages the transfer from source to destination, through mask with its functions;
For example, `cairo_stroke` is a function to draw a path to the destination by the transfer.
- A transformation can be applied before the transfer completes.
The transformation which is applied is called affine, which is a mathematical term meaning transofrmations
that preserve straight lines.
Scaling, rotating, reflecting, shearing and translating are all examples of affine transformations.
They are mathematically represented by matrix multiplication and vector addition.
In this section we don't use it, instead we will only use the identity transformation.
This means that the coordinates in the source and mask are the same as the coordinates in destination.
![Stroke a rectangle](../image/cairo.png)
The instruction is as follows:
1. Create a surface.
This will be a destination.
2. Create a cairo context with the surface and the surface will be the destination of the context.
This will be the destination.
2. Create a cairo context with the surface, the surface will be the destination of the context.
3. Create a source pattern within the context.
4. Create paths, which are lines, rectangles, arcs, texts or more complicated shapes in the mask.
5. Use drawing operator such as `cairo_stroke` to transfer the paint in the source to the destination.
5. Use a drawing operator such as `cairo_stroke` to transfer the paint in the source to the destination.
6. Save the destination surface to a file if necessary.
Here's a simple example code that draws a small square and save it as a png file.
Here's a simple example program that draws a small square and saves it as a png file.
~~~C
1 #include <cairo.h>
@ -69,40 +74,43 @@ Here's a simple example code that draws a small square and save it as a png file
20 /* Draw a black rectangle */
21 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
22 cairo_set_line_width (cr, 2.0);
23 cairo_rectangle (cr, width/2.0 - square_size/2, height/2.0 - square_size/2, square_size, square_size);
24 cairo_stroke (cr);
25
26 /* Write the surface to a png file and clean up cairo and surface. */
27 cairo_surface_write_to_png (surface, "rectangle.png");
28 cairo_destroy (cr);
29 cairo_surface_destroy (surface);
30
31 return 0;
32 }
23 cairo_rectangle (cr,
24 width/2.0 - square_size/2,
25 height/2.0 - square_size/2,
26 square_size,
27 square_size);
28 cairo_stroke (cr);
29
30 /* Write the surface to a png file and clean up cairo and surface. */
31 cairo_surface_write_to_png (surface, "rectangle.png");
32 cairo_destroy (cr);
33 cairo_surface_destroy (surface);
34
35 return 0;
36 }
~~~
- 1: Includes the header file of Cairo.
- 6: `cairo_surface_t` is the type of a surface.
- 7: `cairo_t` is the type of a cairo context.
- 8-10: `width` and `height` is the size of `surface`.
`square_size` is the size of a square drawn on the surface.
- 8-10: `width` and `height` are the size of `surface`.
`square_size` is the size of a square to be drawn on the surface.
- 13: `cairo_image_surface_create` creates an image surface.
`CAIRO_FORMAT_RGB24` is a constant which means that each pixel has red, green and blue data.
Each data has 8 bits quantity.
Therefore, 24 bits (3x8=24) is the size of RGB24.
`CAIRO_FORMAT_RGB24` is a constant which means that each pixel has red, green and blue data,
and each data point is an 8 bits number (for 24 bits in total).
Modern displays have this type of color depth.
Width and height are pixels and given as integers.
Width and height are in pixels and given as integers.
- 14: Creates cairo context.
The surface given as an argument will be the destination of the context.
- 18: `cairo_set_source_rgb` creates a source pattern, which is a solid white paint.
The second to fourth argument is red, green and blue color depth respectively.
Their type is float and the values are between zero and one.
(0,0,0) is black and (1,1,1) is white.
- 18: `cairo_set_source_rgb` creates a source pattern, which in this case is a solid white paint.
The second to fourth argument are red, green and blue color values respectively, and they are
of type float. The values are between zero (0.0) and one (1.0), with
black being given by (0.0,0.0,0.0) and white by (1.0,1.0,1.0).
- 19: `cairo_paint` copies everywhere in the source to destination.
The destination is filled with white pixels with this command.
- 21: Sets the source color to black.
- 22: `cairo_set_line_width` set the width of lines.
In this case, the line width is set to two pixels.
In this case, the line width is set to be two pixels and will end up that same size.
(It is because the transformation is identity.
If the transformation isn't identity, for example scaling with the factor three, the actual width in destination will be six (2x3=6) pixels.)
- 23: Draws a rectangle (square) on the mask.
@ -118,8 +126,7 @@ To compile this, type the following.
![rectangle.png](../image/rectangle.png)
There are lots of documentations in [Cairo's website](https://www.cairographics.org/).
If you aren't familiar with Cairo, it is strongly recommended to read the [tutorial](https://www.cairographics.org/tutorial/) in the website.
See the [Cairo's website](https://www.cairographics.org/) for more details.
## GtkDrawingArea
@ -132,46 +139,49 @@ The following is a very simple example.
4 draw_function (GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data) {
5 int square_size = 40.0;
6
7 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* whilte */
7 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
8 cairo_paint (cr);
9 cairo_set_line_width (cr, 2.0);
10 cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
11 cairo_rectangle (cr, width/2.0 - square_size/2, height/2.0 - square_size/2, square_size, square_size);
12 cairo_stroke (cr);
13 }
14
15 static void
16 app_activate (GApplication *app, gpointer user_data) {
17 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
18 GtkWidget *area = gtk_drawing_area_new ();
19
20 gtk_window_set_title (GTK_WINDOW (win), "da1");
21 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_function, NULL, NULL);
22 gtk_window_set_child (GTK_WINDOW (win), area);
11 cairo_rectangle (cr,
12 width/2.0 - square_size/2,
13 height/2.0 - square_size/2,
14 square_size,
15 square_size);
16 cairo_stroke (cr);
17 }
18
19 static void
20 app_activate (GApplication *app, gpointer user_data) {
21 GtkWidget *win = gtk_application_window_new (GTK_APPLICATION (app));
22 GtkWidget *area = gtk_drawing_area_new ();
23
24 gtk_widget_show (win);
25 }
26
27 #define APPLICATION_ID "com.github.ToshioCP.da1"
28
29 int
30 main (int argc, char **argv) {
31 GtkApplication *app;
32 int stat;
33
34 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
35 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
36 stat =g_application_run (G_APPLICATION (app), argc, argv);
37 g_object_unref (app);
38 return stat;
39 }
40
24 gtk_window_set_title (GTK_WINDOW (win), "da1");
25 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw_function, NULL, NULL);
26 gtk_window_set_child (GTK_WINDOW (win), area);
27
28 gtk_widget_show (win);
29 }
30
31 #define APPLICATION_ID "com.github.ToshioCP.da1"
32
33 int
34 main (int argc, char **argv) {
35 GtkApplication *app;
36 int stat;
37
38 app = gtk_application_new (APPLICATION_ID, G_APPLICATION_FLAGS_NONE);
39 g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
40 stat =g_application_run (G_APPLICATION (app), argc, argv);
41 g_object_unref (app);
42 return stat;
43 }
~~~
The function `main` is almost same as before.
The two functions `app_activate` and `draw_function` is important in this example.
The two functions `app_activate` and `draw_function` are important in this example.
- 18: Creates a GtkDrawingArea instance.
- 18: Creates a GtkDrawingArea instance; and
- 21: Sets a drawing function of the widget.
GtkDrawingArea widget uses the function to draw the contents of itself whenever its necessary.
For example, when a user drag a mouse pointer and resize a top-level window, GtkDrawingArea also changes the size.
@ -191,7 +201,7 @@ The second parameter is a cairo context given by the widget.
The destination surface of the context is connected to the contents of the widget.
What you draw to this surface will appear in the widget on the screen.
The third and fourth parameters are the size of the destination surface.
Now, look at the program of the example again.
Now, look at the program example again.
- 3-13: The drawing function.
- 7-8: Sets the source to be white and paint the destination white.
@ -202,9 +212,8 @@ Now, look at the program of the example again.
Compile and run it, then a window with a black rectangle (square) appears.
Try resizing the window.
The square always appears at the center of the window because the drawing function is invoked every moment the window is resized.
The square always appears at the center of the window because the drawing function is invoked each time the window is resized.
![Square in the window](../image/da1.png)
Up: [Readme.md](../Readme.md), Prev: [Section 21](sec21.md), Next: [Section 23](sec23.md)

View file

@ -1,13 +1,13 @@
Up: [Readme.md](../Readme.md), Prev: [Section 8](sec8.md), Next: [Section 10](sec10.md)
# Ui file and GtkBuilder
# The User Interface (UI) file and GtkBuilder
## New, open and save button
## New, Open and Save button
We made the simplest editor in the previous section.
It reads the files in `app_open` function at start-up and writes them when closing the window.
It works but is not good.
It is better to make "New", "Open", "Save" and "Close" buttons.
In the last section we made the almost simplest editor possible.
It reads files in the `app_open` function at start-up and writes them out when closing the window.
It works but is not very good.
It would be better if we had "New", "Open", "Save" and "Close" buttons.
This section describes how to put those buttons into the window.
Signals and handlers will be explained later.
@ -105,7 +105,7 @@ The function `app_open` in the source code `tfe2.c` is as follows.
86 }
~~~
The point is how to build the window.
The aim is to build the widgets of the main application window.
- 25-27: Creates a GtkApplicationWindow instance and sets the title and default size.
- 29-30: Creates a GtkBox instance `boxv`.
@ -124,18 +124,18 @@ This makes the label expands horizontally as long as possible.
This makes it expand horizontally and vertically as big as possible.
It is appended to `boxv` as the second child.
The number of lines is 33(=57-25+1) to build the widgets.
And we needed many variables (`boxv`, `boxh`, `dmy1`, ...).
Most of them aren't necessary except building the widgets.
The number of lines to build the widgets is 33(=57-25+1).
We also needed many additional variables (`boxv`, `boxh`, `dmy1`, ...),
most of which weren't necessary, except for building the widgets.
Are there any good solution to reduce these work?
Gtk provides GtkBuilder.
It reads ui data and builds a window.
It reduces the cumbersome work.
It reads user interface (UI) data and builds a window.
It reduces this cumbersome work.
## Ui file
## The UI File
First, let's look at the ui file `tfe3.ui` that defines a structure of the widgets.
First, let's look at the UI file `tfe3.ui` that is used to define the widget structure.
~~~xml
1 <?xml version="1.0" encoding="UTF-8"?>
@ -200,11 +200,11 @@ First, let's look at the ui file `tfe3.ui` that defines a structure of the widge
~~~
The structure of this file is XML.
Constructs beginning with `<` and ending with `>` are called tags.
And there are two types of tags, start tag and end tag.
Constructs that begin with `<` and end with `>` are called tags.
There are two types of tags, the start tag and the end tag.
For example, `<interface>` is a start tag and `</interface>` is an end tag.
Ui file begins and ends with interface tags.
Some tags, for example, object tags can have a class and id attributes in the start tag.
The UI file begins and ends with interface tags.
Some tags, for example object tags, can have a class and id attributes in their start tag.
- 1: The first line is XML declaration.
It specifies that the version of XML is 1.0 and the encoding is UTF-8.
@ -431,7 +431,7 @@ It describes resource files.
However, this xml has only one gresource.
- 3: The gresource has a prefix `/com/github/ToshioCP/tfe3`.
- 4: The gresource has `tfe3.ui`.
And it is pointed by `/com/github/ToshioCP/tfe3/tfe3.ui` because it needs prefix.
And it is pointed by `/com/github/ToshioCP/tfe3/tfe3.ui` because it needs prefix.
If you want to add more files, then insert them between line 4 and 5.
Save this xml text to `tfe3.gresource.xml`.
@ -485,5 +485,4 @@ build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui");
Then, compile and run it.
The window appears and it is the same as the screenshot at the beginning of this page.
Up: [Readme.md](../Readme.md), Prev: [Section 8](sec8.md), Next: [Section 10](sec10.md)

View file

@ -1,8 +1,8 @@
#### Contents of this Repository
This tutorial illustrates how to write C programs with the Gtk4 library.
It focuses on beginners so the contents are limited to basic things.
The table of contents is shown at the end of this abstract.
It focuses on beginners so the contents are limited to the basics.
The table of contents is at the end of this abstract.
- Section 3 to 21 describes the basics, with the example of a simple editor `tfe` (Text File Editor).
- Section 22 to 24 describes GtkDrawingArea.

View file

@ -20,7 +20,11 @@ main (int argc, char **argv)
/* Draw a black rectangle */
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_set_line_width (cr, 2.0);
cairo_rectangle (cr, width/2.0 - square_size/2, height/2.0 - square_size/2, square_size, square_size);
cairo_rectangle (cr,
width/2.0 - square_size/2,
height/2.0 - square_size/2,
square_size,
square_size);
cairo_stroke (cr);
/* Write the surface to a png file and clean up cairo and surface. */

View file

@ -4,11 +4,15 @@ static void
draw_function (GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer user_data) {
int square_size = 40.0;
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* whilte */
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* white */
cairo_paint (cr);
cairo_set_line_width (cr, 2.0);
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); /* black */
cairo_rectangle (cr, width/2.0 - square_size/2, height/2.0 - square_size/2, square_size, square_size);
cairo_rectangle (cr,
width/2.0 - square_size/2,
height/2.0 - square_size/2,
square_size,
square_size);
cairo_stroke (cr);
}
@ -37,4 +41,3 @@ main (int argc, char **argv) {
g_object_unref (app);
return stat;
}

View file

@ -1,48 +1,53 @@
# GtkDrawingArea and Cairo
If you want to draw dynamically, like an image window of gimp graphics editor, GtkDrawingArea widget is the most suitable widget.
You can draw or redraw an image in this widget freely.
It is called custom drawing.
If you want to draw dynamically on the screen, like an image window of gimp graphics editor, the GtkDrawingArea widget is the most suitable widget.
You can freely draw or redraw an image in this widget.
This is called custom drawing.
GtkDrawingArea provides a cairo context so users can draw images by cairo functions.
GtkDrawingArea provides a cairo drawing context so users can draw images by using cairo functions.
In this section, I will explain:
1. Cairo, but briefly.
2. GtkDrawingArea with very simple example.
1. Cairo, but only briefly; and
2. GtkDrawingArea, with a very simple example.
## Cairo
Cairo is a two dimensional graphics library.
First, you need to know surface, source, mask, destination, cairo context and transformation.
Cairo is a set of two dimensional graphical drawing functions (or graphics library).
There is a lot of documentation on [Cairo's website](https://www.cairographics.org/).
If you aren't familiar with Cairo, it is worth reading their [tutorial](https://www.cairographics.org/tutorial/).
- Surface represents an image.
The following is a gentle introduction to the Cairo library and how to use it.
Firstly, in order to use Cairo you need to know about surfaces, sources, masks, destinations, cairo context and transformations.
- A surface represents an image.
It is like a canvas.
We can draw shapes and images with different colors on surfaces.
- Source pattern, or simply source, is a kind of paint, which will be transferred to destination surface by cairo functions.
- Mask is image mask used in the transference.
- Destination is a target surface.
- Cairo context manages the transference from source to destination through mask with its functions.
For example, `cairo_stroke` is a function to draw a path to the destination by the transference.
- Transformation is applied before the transfer completes.
The transformation is called affine, which is a mathematics terminology, and represented by matrix multiplication and vector addition.
Scaling, rotation, reflection, shearing and translation are examples of affine transformation.
In this section, we don't use it.
That means we only use identity transformation.
Therefore, the coordinate in source and mask is the same as the coordinate in destination.
- The source pattern, or simply source, is like paint, which will be transferred to destination surface by cairo functions.
- The mask describes the area to be used in the copy;
- The destination is a target surface;
- The cairo context manages the transfer from source to destination, through mask with its functions;
For example, `cairo_stroke` is a function to draw a path to the destination by the transfer.
- A transformation can be applied before the transfer completes.
The transformation which is applied is called affine, which is a mathematical term meaning transofrmations
that preserve straight lines.
Scaling, rotating, reflecting, shearing and translating are all examples of affine transformations.
They are mathematically represented by matrix multiplication and vector addition.
In this section we don't use it, instead we will only use the identity transformation.
This means that the coordinates in the source and mask are the same as the coordinates in destination.
![Stroke a rectangle](../image/cairo.png){width=9.0cm height=6.0cm}
The instruction is as follows:
1. Create a surface.
This will be a destination.
2. Create a cairo context with the surface and the surface will be the destination of the context.
This will be the destination.
2. Create a cairo context with the surface, the surface will be the destination of the context.
3. Create a source pattern within the context.
4. Create paths, which are lines, rectangles, arcs, texts or more complicated shapes in the mask.
5. Use drawing operator such as `cairo_stroke` to transfer the paint in the source to the destination.
5. Use a drawing operator such as `cairo_stroke` to transfer the paint in the source to the destination.
6. Save the destination surface to a file if necessary.
Here's a simple example code that draws a small square and save it as a png file.
Here's a simple example program that draws a small square and saves it as a png file.
@@@include
misc/cairo.c
@ -51,25 +56,24 @@ misc/cairo.c
- 1: Includes the header file of Cairo.
- 6: `cairo_surface_t` is the type of a surface.
- 7: `cairo_t` is the type of a cairo context.
- 8-10: `width` and `height` is the size of `surface`.
`square_size` is the size of a square drawn on the surface.
- 8-10: `width` and `height` are the size of `surface`.
`square_size` is the size of a square to be drawn on the surface.
- 13: `cairo_image_surface_create` creates an image surface.
`CAIRO_FORMAT_RGB24` is a constant which means that each pixel has red, green and blue data.
Each data has 8 bits quantity.
Therefore, 24 bits (3x8=24) is the size of RGB24.
`CAIRO_FORMAT_RGB24` is a constant which means that each pixel has red, green and blue data,
and each data point is an 8 bits number (for 24 bits in total).
Modern displays have this type of color depth.
Width and height are pixels and given as integers.
Width and height are in pixels and given as integers.
- 14: Creates cairo context.
The surface given as an argument will be the destination of the context.
- 18: `cairo_set_source_rgb` creates a source pattern, which is a solid white paint.
The second to fourth argument is red, green and blue color depth respectively.
Their type is float and the values are between zero and one.
(0,0,0) is black and (1,1,1) is white.
- 18: `cairo_set_source_rgb` creates a source pattern, which in this case is a solid white paint.
The second to fourth argument are red, green and blue color values respectively, and they are
of type float. The values are between zero (0.0) and one (1.0), with
black being given by (0.0,0.0,0.0) and white by (1.0,1.0,1.0).
- 19: `cairo_paint` copies everywhere in the source to destination.
The destination is filled with white pixels with this command.
- 21: Sets the source color to black.
- 22: `cairo_set_line_width` set the width of lines.
In this case, the line width is set to two pixels.
In this case, the line width is set to be two pixels and will end up that same size.
(It is because the transformation is identity.
If the transformation isn't identity, for example scaling with the factor three, the actual width in destination will be six (2x3=6) pixels.)
- 23: Draws a rectangle (square) on the mask.
@ -85,8 +89,7 @@ To compile this, type the following.
![rectangle.png](../image/rectangle.png)
There are lots of documentations in [Cairo's website](https://www.cairographics.org/).
If you aren't familiar with Cairo, it is strongly recommended to read the [tutorial](https://www.cairographics.org/tutorial/) in the website.
See the [Cairo's website](https://www.cairographics.org/) for more details.
## GtkDrawingArea
@ -97,9 +100,9 @@ misc/da1.c
@@@
The function `main` is almost same as before.
The two functions `app_activate` and `draw_function` is important in this example.
The two functions `app_activate` and `draw_function` are important in this example.
- 18: Creates a GtkDrawingArea instance.
- 18: Creates a GtkDrawingArea instance; and
- 21: Sets a drawing function of the widget.
GtkDrawingArea widget uses the function to draw the contents of itself whenever its necessary.
For example, when a user drag a mouse pointer and resize a top-level window, GtkDrawingArea also changes the size.
@ -119,7 +122,7 @@ The second parameter is a cairo context given by the widget.
The destination surface of the context is connected to the contents of the widget.
What you draw to this surface will appear in the widget on the screen.
The third and fourth parameters are the size of the destination surface.
Now, look at the program of the example again.
Now, look at the program example again.
- 3-13: The drawing function.
- 7-8: Sets the source to be white and paint the destination white.
@ -130,7 +133,6 @@ Now, look at the program of the example again.
Compile and run it, then a window with a black rectangle (square) appears.
Try resizing the window.
The square always appears at the center of the window because the drawing function is invoked every moment the window is resized.
The square always appears at the center of the window because the drawing function is invoked each time the window is resized.
![Square in the window](../image/da1.png){width=8cm height=3.4cm}

View file

@ -20,7 +20,7 @@ So, readers can skip that part of this sections.
The documentation of turtle is [here](turtle/turtle_doc.src.md).
@@@elif html
The documentation of turtle is [here](../html/turtle_doc.html).
@@@if latex
@@@elif latex
The documentation of turtle is in the appendix.
@@@end
I'll show you a simple example.

View file

@ -1,11 +1,11 @@
# Ui file and GtkBuilder
# The User Interface (UI) file and GtkBuilder
## New, open and save button
## New, Open and Save button
We made the simplest editor in the previous section.
It reads the files in `app_open` function at start-up and writes them when closing the window.
It works but is not good.
It is better to make "New", "Open", "Save" and "Close" buttons.
In the last section we made the almost simplest editor possible.
It reads files in the `app_open` function at start-up and writes them out when closing the window.
It works but is not very good.
It would be better if we had "New", "Open", "Save" and "Close" buttons.
This section describes how to put those buttons into the window.
Signals and handlers will be explained later.
@ -18,7 +18,7 @@ The function `app_open` in the source code `tfe2.c` is as follows.
tfe/tfe2.c app_open
@@@
The point is how to build the window.
The aim is to build the widgets of the main application window.
- 25-27: Creates a GtkApplicationWindow instance and sets the title and default size.
- 29-30: Creates a GtkBox instance `boxv`.
@ -37,29 +37,29 @@ This makes the label expands horizontally as long as possible.
This makes it expand horizontally and vertically as big as possible.
It is appended to `boxv` as the second child.
The number of lines is 33(=57-25+1) to build the widgets.
And we needed many variables (`boxv`, `boxh`, `dmy1`, ...).
Most of them aren't necessary except building the widgets.
The number of lines to build the widgets is 33(=57-25+1).
We also needed many additional variables (`boxv`, `boxh`, `dmy1`, ...),
most of which weren't necessary, except for building the widgets.
Are there any good solution to reduce these work?
Gtk provides GtkBuilder.
It reads ui data and builds a window.
It reduces the cumbersome work.
It reads user interface (UI) data and builds a window.
It reduces this cumbersome work.
## Ui file
## The UI File
First, let's look at the ui file `tfe3.ui` that defines a structure of the widgets.
First, let's look at the UI file `tfe3.ui` that is used to define the widget structure.
@@@include
tfe/tfe3.ui
@@@
The structure of this file is XML.
Constructs beginning with `<` and ending with `>` are called tags.
And there are two types of tags, start tag and end tag.
Constructs that begin with `<` and end with `>` are called tags.
There are two types of tags, the start tag and the end tag.
For example, `<interface>` is a start tag and `</interface>` is an end tag.
Ui file begins and ends with interface tags.
Some tags, for example, object tags can have a class and id attributes in the start tag.
The UI file begins and ends with interface tags.
Some tags, for example object tags, can have a class and id attributes in their start tag.
- 1: The first line is XML declaration.
It specifies that the version of XML is 1.0 and the encoding is UTF-8.
@ -177,7 +177,7 @@ tfe/tfe3.gresource.xml
However, this xml has only one gresource.
- 3: The gresource has a prefix `/com/github/ToshioCP/tfe3`.
- 4: The gresource has `tfe3.ui`.
And it is pointed by `/com/github/ToshioCP/tfe3/tfe3.ui` because it needs prefix.
And it is pointed by `/com/github/ToshioCP/tfe3/tfe3.ui` because it needs prefix.
If you want to add more files, then insert them between line 4 and 5.
Save this xml text to `tfe3.gresource.xml`.
@ -205,4 +205,3 @@ build = gtk_builder_new_from_resource ("/com/github/ToshioCP/tfe3/tfe3.ui");
Then, compile and run it.
The window appears and it is the same as the screenshot at the beginning of this page.