mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-26 19:58:29 +01:00
Merge pull request #21 from PaulSchulz/main
Some more edits. Sec 9 and 22.
This commit is contained in:
commit
978e5b1a34
9 changed files with 190 additions and 174 deletions
|
@ -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)
|
||||
|
|
173
gfm/sec22.md
173
gfm/sec22.md
|
@ -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)
|
||||
|
|
39
gfm/sec9.md
39
gfm/sec9.md
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue