mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2025-01-11 20:03:35 +01:00
Add section 20.
This commit is contained in:
parent
7f1228cb26
commit
26fc01e64e
22 changed files with 1003 additions and 11 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -15,6 +15,7 @@ src/tfe/resources.c
|
|||
src/tfe5/_build
|
||||
src/tfe5/hello.txt
|
||||
src/menu/a.out
|
||||
src/color/_build
|
||||
|
||||
html/*
|
||||
latex/*
|
||||
|
|
|
@ -32,3 +32,4 @@ You can read it without download.
|
|||
1. [Stateful action](gfm/sec17.md)
|
||||
1. [Ui file for menu and action entries](gfm/sec18.md)
|
||||
1. [GtkDrawingArea and Cairo](gfm/sec19.md)
|
||||
1. [Combine GtkDrawingArea and TfeTextView](gfm/sec20.md)
|
||||
|
|
|
@ -5,7 +5,7 @@ Up: [Readme.md](../Readme.md), Prev: [Section 9](sec9.md), Next: [Section 11](s
|
|||
This section and the following four sections are explanations about the next version of the text file editor (tfe).
|
||||
It is tfe5.
|
||||
It has many changes from the prior version.
|
||||
All the sources are listed after the five sections.
|
||||
All the sources are listed in [Section 15](sec15.md).
|
||||
|
||||
## Encapsulation
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ We can draw shapes and images with different colors on surfaces.
|
|||
- 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 mathematicsterminology, and represented by matrix multiplication and vector addition.
|
||||
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.
|
||||
|
|
372
gfm/sec20.md
Normal file
372
gfm/sec20.md
Normal file
|
@ -0,0 +1,372 @@
|
|||
Up: [Readme.md](../Readme.md), Prev: [Section 19](sec19.md)
|
||||
|
||||
# Combine GtkDrawingArea and TfeTextView
|
||||
|
||||
Now, we will make a new application which has GtkDrawingArea and TfeTextView in it.
|
||||
Its name is "color".
|
||||
If you write a color in TfeTextView and click on the `run` button, then the color of GtkDrawingArea changes to the color given by you.
|
||||
|
||||
![color](../image/color.png)
|
||||
|
||||
The following colors are available.
|
||||
|
||||
- white
|
||||
- black
|
||||
- red
|
||||
- green
|
||||
- blue
|
||||
|
||||
In addition the following two options are also available.
|
||||
|
||||
- light: Make the color of the drawing area lighter.
|
||||
- dark: Make the color of the drawing area darker.
|
||||
|
||||
This application can only do very simple things.
|
||||
However, it tells us that if we add powerful parser to it, we will be able to make it more efficient.
|
||||
I want to show it to you in the later section by making a turtle graphics language like Logo program language.
|
||||
|
||||
In this section, we focus on how to bind the two objects.
|
||||
|
||||
# Color.ui and color.gresource.xml
|
||||
|
||||
First, We need to make the ui file of the widgets.
|
||||
The image in the previous subsection gives us the structure of the widgets.
|
||||
Title bar, four buttons in the tool bar and two widgets textview and drawing area.
|
||||
The ui file is as follows.
|
||||
|
||||
1 <interface>
|
||||
2 <object class="GtkApplicationWindow" id="win">
|
||||
3 <property name="title">color changer</property>
|
||||
4 <property name="default-width">600</property>
|
||||
5 <property name="default-height">400</property>
|
||||
6 <child>
|
||||
7 <object class="GtkBox" id="boxv">
|
||||
8 <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
9 <child>
|
||||
10 <object class="GtkBox" id="boxh1">
|
||||
11 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
12 <child>
|
||||
13 <object class="GtkLabel" id="dmy1">
|
||||
14 <property name="width-chars">10</property>
|
||||
15 </object>
|
||||
16 </child>
|
||||
17 <child>
|
||||
18 <object class="GtkButton" id="btnr">
|
||||
19 <property name="label">Run</property>
|
||||
20 <signal name="clicked" handler="run_cb"></signal>
|
||||
21
|
||||
22 </object>
|
||||
23 </child>
|
||||
24 <child>
|
||||
25 <object class="GtkButton" id="btno">
|
||||
26 <property name="label">Open</property>
|
||||
27 <signal name="clicked" handler="open_cb"></signal>
|
||||
28 </object>
|
||||
29 </child>
|
||||
30 <child>
|
||||
31 <object class="GtkLabel" id="dmy2">
|
||||
32 <property name="hexpand">TRUE</property>
|
||||
33 </object>
|
||||
34 </child>
|
||||
35 <child>
|
||||
36 <object class="GtkButton" id="btns">
|
||||
37 <property name="label">Save</property>
|
||||
38 <signal name="clicked" handler="save_cb"></signal>
|
||||
39 </object>
|
||||
40 </child>
|
||||
41 <child>
|
||||
42 <object class="GtkButton" id="btnc">
|
||||
43 <property name="label">Close</property>
|
||||
44 <signal name="clicked" handler="close_cb"></signal>
|
||||
45 </object>
|
||||
46 </child>
|
||||
47 <child>
|
||||
48 <object class="GtkLabel" id="dmy3">
|
||||
49 <property name="width-chars">10</property>
|
||||
50 </object>
|
||||
51 </child>
|
||||
52 </object>
|
||||
53 </child>
|
||||
54 <child>
|
||||
55 <object class="GtkBox" id="boxh2">
|
||||
56 <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
57 <property name="homogeneous">TRUE</property>
|
||||
58 <child>
|
||||
59 <object class="GtkScrolledWindow" id="scr">
|
||||
60 <property name="hexpand">TRUE</property>
|
||||
61 <property name="vexpand">TRUE</property>
|
||||
62 <child>
|
||||
63 <object class="TfeTextView" id="tv">
|
||||
64 <property name="wrap-mode">GTK_WRAP_WORD_CHAR</property>
|
||||
65 </object>
|
||||
66 </child>
|
||||
67 </object>
|
||||
68 </child>
|
||||
69 <child>
|
||||
70 <object class="GtkDrawingArea" id="da">
|
||||
71 <property name="hexpand">TRUE</property>
|
||||
72 <property name="vexpand">TRUE</property>
|
||||
73 </object>
|
||||
74 </child>
|
||||
75 </object>
|
||||
76 </child>
|
||||
77 </object>
|
||||
78 </child>
|
||||
79 </object>
|
||||
80 </interface>
|
||||
81
|
||||
|
||||
- 9-53: This part describes the tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
|
||||
This is similar to the toolbar of tfe text editor in [Section 8](sec8.md).
|
||||
There are two differences.
|
||||
`Run` button replaces `New` button.
|
||||
Signal element are added to each button object.
|
||||
It has "name" attribute which is a signal name and "handler" attribute which is the name of its signal handler function.
|
||||
Options "-WI, --export-dynamic" CFLAG is necessary when you compile the application.
|
||||
You can achieve this by adding "export_dynamic: true" argument to executable function in `meson.build`.
|
||||
And be careful that the handler must be defined without 'static' class.
|
||||
- 54-76: Put GtkScrolledWindow and GtkDrawingArea into GtkBox.
|
||||
GtkBox has "homogeneous property with TRUE value, so the two children have the same width in the box.
|
||||
TfeTextView is a child of GtkScrolledWindow.
|
||||
|
||||
The xml file for the resource compiler is almost same as before.
|
||||
Just substitute "color" for "tfe".
|
||||
|
||||
1 <?xml version="1.0" encoding="UTF-8"?>
|
||||
2 <gresources>
|
||||
3 <gresource prefix="/com/github/ToshioCP/color">
|
||||
4 <file>color.ui</file>
|
||||
5 </gresource>
|
||||
6 </gresources>
|
||||
|
||||
# Tfetextview.h, tfetextview.c and color.h
|
||||
|
||||
First two files are almost same as before.
|
||||
The only difference is the header file in tfettextview.c.
|
||||
|
||||
$ diff tfe5/tfetextview.c color/tfetextview.c
|
||||
1c1
|
||||
< #include "tfe.h"
|
||||
---
|
||||
> #include "color.h"
|
||||
|
||||
Color.h just includes tfetextview.h.
|
||||
|
||||
1 #include <gtk/gtk.h>
|
||||
2
|
||||
3 #include "tfetextview.h"
|
||||
|
||||
# Colorapplication.c
|
||||
|
||||
This is the main file.
|
||||
It deals with:
|
||||
|
||||
- Build widgets by GtkBuilder.
|
||||
- Set drawing function to GtkDrawingArea.
|
||||
And connect a handler to "resize" signal on GtkDrawingArea.
|
||||
- Implement each call back functions.
|
||||
Particularly, `Run` signal handler is the point in this program.
|
||||
|
||||
The following is `colorapplication.c`.
|
||||
|
||||
1 #include "color.h"
|
||||
2
|
||||
3 static GtkWidget *win;
|
||||
4 static GtkWidget *tv;
|
||||
5 static GtkWidget *da;
|
||||
6
|
||||
7 static cairo_surface_t *surface = NULL;
|
||||
8
|
||||
9 static void
|
||||
10 run (void) {
|
||||
11 GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
12 GtkTextIter start_iter;
|
||||
13 GtkTextIter end_iter;
|
||||
14 char *contents;
|
||||
15 cairo_t *cr;
|
||||
16
|
||||
17 gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
18 contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
19 if (surface) {
|
||||
20 cr = cairo_create (surface);
|
||||
21 if (g_strcmp0 ("red", contents) == 0)
|
||||
22 cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
23 else if (g_strcmp0 ("green", contents) == 0)
|
||||
24 cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
25 else if (g_strcmp0 ("blue", contents) == 0)
|
||||
26 cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
27 else if (g_strcmp0 ("white", contents) == 0)
|
||||
28 cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
29 else if (g_strcmp0 ("black", contents) == 0)
|
||||
30 cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
31 else if (g_strcmp0 ("light", contents) == 0)
|
||||
32 cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
|
||||
33 else if (g_strcmp0 ("dark", contents) == 0)
|
||||
34 cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
35 else
|
||||
36 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
37 cairo_paint (cr);
|
||||
38 cairo_destroy (cr);
|
||||
39 }
|
||||
40 }
|
||||
41
|
||||
42 void
|
||||
43 run_cb (GtkWidget *btnr) {
|
||||
44 run ();
|
||||
45 gtk_widget_queue_draw (GTK_WIDGET (da));
|
||||
46 }
|
||||
47
|
||||
48 void
|
||||
49 open_cb (GtkWidget *btno) {
|
||||
50 tfe_text_view_open (TFE_TEXT_VIEW (tv), win);
|
||||
51 }
|
||||
52
|
||||
53 void
|
||||
54 save_cb (GtkWidget *btns) {
|
||||
55 tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
56 }
|
||||
57
|
||||
58 void
|
||||
59 close_cb (GtkWidget *btnc) {
|
||||
60 if (surface)
|
||||
61 cairo_surface_destroy (surface);
|
||||
62 gtk_window_destroy (GTK_WINDOW (win));
|
||||
63 }
|
||||
64
|
||||
65 static void
|
||||
66 resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
67 if (surface)
|
||||
68 cairo_surface_destroy (surface);
|
||||
69 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
70 run ();
|
||||
71 }
|
||||
72
|
||||
73 static void
|
||||
74 draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
75 if (surface) {
|
||||
76 cairo_set_source_surface (cr, surface, 0, 0);
|
||||
77 cairo_paint (cr);
|
||||
78 }
|
||||
79 }
|
||||
80
|
||||
81 static void
|
||||
82 activate (GApplication *application) {
|
||||
83 gtk_widget_show (win);
|
||||
84 }
|
||||
85
|
||||
86 static void
|
||||
87 startup (GApplication *application) {
|
||||
88 GtkApplication *app = GTK_APPLICATION (application);
|
||||
89 GtkBuilder *build;
|
||||
90
|
||||
91 build = gtk_builder_new_from_resource ("/com/github/ToshioCP/color/color.ui");
|
||||
92 win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
93 gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
94 tv = GTK_WIDGET (gtk_builder_get_object (build, "tv"));
|
||||
95 da = GTK_WIDGET (gtk_builder_get_object (build, "da"));
|
||||
96 g_object_unref(build);
|
||||
97 g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
98 gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
|
||||
99
|
||||
100 GdkDisplay *display;
|
||||
101
|
||||
102 display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
103 GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
104 gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
105 gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
106 }
|
||||
107
|
||||
108 int
|
||||
109 main (int argc, char **argv) {
|
||||
110 GtkApplication *app;
|
||||
111 int stat;
|
||||
112
|
||||
113 app = gtk_application_new ("com.github.ToshioCP.color", G_APPLICATION_FLAGS_NONE);
|
||||
114
|
||||
115 g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
|
||||
116 g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
|
||||
117
|
||||
118 stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
119 g_object_unref (app);
|
||||
120 return stat;
|
||||
121 }
|
||||
122
|
||||
|
||||
- 108-121: The function `main` is almost same as before but there are some differences.
|
||||
The application ID is "com.github.ToshioCP.color".
|
||||
`G_APPLICATION_FLAGS_NONE` is specified so no open signal handler is necessary.
|
||||
- 86-106: Startup handler.
|
||||
- 91-96: Build widgets.
|
||||
The pointers of the top window, TfeTextView and GtkDrawingArea objects are stored to static variables `win`, `tv` and `da` respectively.
|
||||
This is because these objects are often used in handlers.
|
||||
They never be rewritten so they're thread safe.
|
||||
- 97: connect "resize" signal and the handler.
|
||||
- 98: set the drawing function.
|
||||
- 81-84: Activate handler, which just show the widgets.
|
||||
- 73-79: The drawing function.
|
||||
It just copy `surface` to destination.
|
||||
- 65-71: Resize handler.
|
||||
Re-create the surface to fit the width and height of the drawing area and paint by calling the function `run`.
|
||||
- 58-63: Close handler.
|
||||
It destroys `surface` if it exists.
|
||||
Then it destroys the top window and quits the application.
|
||||
- 48-56: Open and save handler.
|
||||
They just call the corresponding functions of TfeTextView.
|
||||
- 42-46: Run handler.
|
||||
It calls run function to paint the surface.
|
||||
After that `gtk_widget_queue_draw` is called.
|
||||
This fhunction adds the widget (GtkDrawingArea) to the queue to be redrawn.
|
||||
It is important to know that the drawing function is called when it is necessary.
|
||||
For example, when another window is moved and uncovers part of the widget, or when the window containing it is resized.
|
||||
But repaint of `surface` is not automatically notified to gtk.
|
||||
Therefore, you need to call `gtk_widget_queue_draw` to redraw the widget.
|
||||
- 9-40: Run function paint the surface.
|
||||
First, it gets the contents of GtkTextBuffer.
|
||||
Then compare it to "red", "green" and so on.
|
||||
If it matches the color, then the surface is painted the color.
|
||||
If it matches "light" or "dark", then the color of the surface is lightened or darkened respectively.
|
||||
Alpha channel is used.
|
||||
|
||||
# Meson.build
|
||||
|
||||
This file is almost same as before.
|
||||
An argument "export_dynamic: true" is added to executable function.
|
||||
|
||||
1 project('color', 'c')
|
||||
2
|
||||
3 gtkdep = dependency('gtk4')
|
||||
4
|
||||
5 gnome=import('gnome')
|
||||
6 resources = gnome.compile_resources('resources','color.gresource.xml')
|
||||
7
|
||||
8 sourcefiles=files('colorapplication.c', 'tfetextview.c')
|
||||
9
|
||||
10 executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)
|
||||
|
||||
# Compile and execute it
|
||||
|
||||
First you need to export some variables (refer to [Section 2](sec2.md)).
|
||||
|
||||
$ . env.sh
|
||||
|
||||
Then type the following to compile it.
|
||||
|
||||
$ meson _build
|
||||
$ ninja -C _build
|
||||
|
||||
The application is made in `_build` directory.
|
||||
Type the following to execute it.
|
||||
|
||||
$ _build/color
|
||||
|
||||
Type "red", "green", "blue", "white", black", "light" or "dark" in the TfeTextView.
|
||||
Then, click on `Run` button.
|
||||
Make sure the color of GtkDrawingArea changes.
|
||||
|
||||
In this program TfeTextView is used to change the color.
|
||||
You can use buttons or menus instead of textview.
|
||||
Probably it is more appropriate.
|
||||
Using textview is unnatural.
|
||||
It is a good practice to make such application by yourself.
|
||||
|
||||
Up: [Readme.md](../Readme.md), Prev: [Section 19](sec19.md)
|
|
@ -127,8 +127,8 @@ The function `g_signal_connect` has four arguments.
|
|||
4. Data to pass to the handler. If no data is necessary, NULL should be given.
|
||||
|
||||
You can find the description of each signal in API reference.
|
||||
For example, "activate" signal is in GApplication subsection in GIO API reference.
|
||||
The handler function is described in that subsection.
|
||||
For example, "activate" signal is in GApplication section in GIO API reference.
|
||||
The handler function is described in that section.
|
||||
|
||||
In addition, `g_signal_connect` is described in GObject API reference.
|
||||
API reference is very important.
|
||||
|
|
|
@ -49,7 +49,7 @@ For example, TfeTextView has GtkTextbuffer correspods to GtkTextView inside TfeT
|
|||
And important thing is that TfeTextView can have a memory to keep a pointer to GFile.
|
||||
|
||||
However, to understand the general theory about gobjects is very hard especially for beginners.
|
||||
So, I will just show you the way how to write the code and avoid the theoretical side in the next section.
|
||||
So, I will just show you the way how to write the code and avoid the theoretical side in the next subsection.
|
||||
|
||||
## How to define a child widget of GtkTextView
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 65 KiB |
BIN
image/color.png
Normal file
BIN
image/color.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -142,7 +142,7 @@ def change_rel_link line, src_dir, basedir
|
|||
p_basedir = Pathname.new basedir
|
||||
left = ""
|
||||
right = line
|
||||
while right =~ /(!?\[[^\]]*\])\((.*)\)/
|
||||
while right =~ /(!?\[[^\]]*\])\(([^\)]*)\)/
|
||||
left = $`
|
||||
right = $'
|
||||
name = $1
|
||||
|
|
6
src/color/color.gresource.xml
Normal file
6
src/color/color.gresource.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<gresources>
|
||||
<gresource prefix="/com/github/ToshioCP/color">
|
||||
<file>color.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
3
src/color/color.h
Normal file
3
src/color/color.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#include <gtk/gtk.h>
|
||||
|
||||
#include "tfetextview.h"
|
81
src/color/color.ui
Normal file
81
src/color/color.ui
Normal file
|
@ -0,0 +1,81 @@
|
|||
<interface>
|
||||
<object class="GtkApplicationWindow" id="win">
|
||||
<property name="title">color changer</property>
|
||||
<property name="default-width">600</property>
|
||||
<property name="default-height">400</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="boxv">
|
||||
<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="boxh1">
|
||||
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="dmy1">
|
||||
<property name="width-chars">10</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btnr">
|
||||
<property name="label">Run</property>
|
||||
<signal name="clicked" handler="run_cb"></signal>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btno">
|
||||
<property name="label">Open</property>
|
||||
<signal name="clicked" handler="open_cb"></signal>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="dmy2">
|
||||
<property name="hexpand">TRUE</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btns">
|
||||
<property name="label">Save</property>
|
||||
<signal name="clicked" handler="save_cb"></signal>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="btnc">
|
||||
<property name="label">Close</property>
|
||||
<signal name="clicked" handler="close_cb"></signal>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="dmy3">
|
||||
<property name="width-chars">10</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="boxh2">
|
||||
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
|
||||
<property name="homogeneous">TRUE</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="scr">
|
||||
<property name="hexpand">TRUE</property>
|
||||
<property name="vexpand">TRUE</property>
|
||||
<child>
|
||||
<object class="TfeTextView" id="tv">
|
||||
<property name="wrap-mode">GTK_WRAP_WORD_CHAR</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkDrawingArea" id="da">
|
||||
<property name="hexpand">TRUE</property>
|
||||
<property name="vexpand">TRUE</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
122
src/color/colorapplication.c
Normal file
122
src/color/colorapplication.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include "color.h"
|
||||
|
||||
static GtkWidget *win;
|
||||
static GtkWidget *tv;
|
||||
static GtkWidget *da;
|
||||
|
||||
static cairo_surface_t *surface = NULL;
|
||||
|
||||
static void
|
||||
run (void) {
|
||||
GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
GtkTextIter start_iter;
|
||||
GtkTextIter end_iter;
|
||||
char *contents;
|
||||
cairo_t *cr;
|
||||
|
||||
gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
if (surface) {
|
||||
cr = cairo_create (surface);
|
||||
if (g_strcmp0 ("red", contents) == 0)
|
||||
cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
else if (g_strcmp0 ("green", contents) == 0)
|
||||
cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
else if (g_strcmp0 ("blue", contents) == 0)
|
||||
cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
else if (g_strcmp0 ("white", contents) == 0)
|
||||
cairo_set_source_rgb (cr, 1, 1, 1);
|
||||
else if (g_strcmp0 ("black", contents) == 0)
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
else if (g_strcmp0 ("light", contents) == 0)
|
||||
cairo_set_source_rgba (cr, 1, 1, 1, 0.5);
|
||||
else if (g_strcmp0 ("dark", contents) == 0)
|
||||
cairo_set_source_rgba (cr, 0, 0, 0, 0.5);
|
||||
else
|
||||
cairo_set_source_surface (cr, surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run_cb (GtkWidget *btnr) {
|
||||
run ();
|
||||
gtk_widget_queue_draw (GTK_WIDGET (da));
|
||||
}
|
||||
|
||||
void
|
||||
open_cb (GtkWidget *btno) {
|
||||
tfe_text_view_open (TFE_TEXT_VIEW (tv), win);
|
||||
}
|
||||
|
||||
void
|
||||
save_cb (GtkWidget *btns) {
|
||||
tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
}
|
||||
|
||||
void
|
||||
close_cb (GtkWidget *btnc) {
|
||||
if (surface)
|
||||
cairo_surface_destroy (surface);
|
||||
gtk_window_destroy (GTK_WINDOW (win));
|
||||
}
|
||||
|
||||
static void
|
||||
resize_cb (GtkDrawingArea *drawing_area, int width, int height, gpointer user_data) {
|
||||
if (surface)
|
||||
cairo_surface_destroy (surface);
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
run ();
|
||||
}
|
||||
|
||||
static void
|
||||
draw_func (GtkDrawingArea *drawing_area, cairo_t *cr, int width, int height, gpointer user_data) {
|
||||
if (surface) {
|
||||
cairo_set_source_surface (cr, surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
activate (GApplication *application) {
|
||||
gtk_widget_show (win);
|
||||
}
|
||||
|
||||
static void
|
||||
startup (GApplication *application) {
|
||||
GtkApplication *app = GTK_APPLICATION (application);
|
||||
GtkBuilder *build;
|
||||
|
||||
build = gtk_builder_new_from_resource ("/com/github/ToshioCP/color/color.ui");
|
||||
win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||||
gtk_window_set_application (GTK_WINDOW (win), app);
|
||||
tv = GTK_WIDGET (gtk_builder_get_object (build, "tv"));
|
||||
da = GTK_WIDGET (gtk_builder_get_object (build, "da"));
|
||||
g_object_unref(build);
|
||||
g_signal_connect (GTK_DRAWING_AREA (da), "resize", G_CALLBACK (resize_cb), NULL);
|
||||
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (da), draw_func, NULL, NULL);
|
||||
|
||||
GdkDisplay *display;
|
||||
|
||||
display = gtk_widget_get_display (GTK_WIDGET (win));
|
||||
GtkCssProvider *provider = gtk_css_provider_new ();
|
||||
gtk_css_provider_load_from_data (provider, "textview {padding: 10px; font-family: monospace; font-size: 12pt;}", -1);
|
||||
gtk_style_context_add_provider_for_display (display, GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv) {
|
||||
GtkApplication *app;
|
||||
int stat;
|
||||
|
||||
app = gtk_application_new ("com.github.ToshioCP.color", G_APPLICATION_FLAGS_NONE);
|
||||
|
||||
g_signal_connect (app, "startup", G_CALLBACK (startup), NULL);
|
||||
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
|
||||
|
||||
stat =g_application_run (G_APPLICATION (app), argc, argv);
|
||||
g_object_unref (app);
|
||||
return stat;
|
||||
}
|
||||
|
10
src/color/meson.build
Normal file
10
src/color/meson.build
Normal file
|
@ -0,0 +1,10 @@
|
|||
project('color', 'c')
|
||||
|
||||
gtkdep = dependency('gtk4')
|
||||
|
||||
gnome=import('gnome')
|
||||
resources = gnome.compile_resources('resources','color.gresource.xml')
|
||||
|
||||
sourcefiles=files('colorapplication.c', 'tfetextview.c')
|
||||
|
||||
executable('color', sourcefiles, resources, dependencies: gtkdep, export_dynamic: true)
|
218
src/color/tfetextview.c
Normal file
218
src/color/tfetextview.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
#include "color.h"
|
||||
|
||||
struct _TfeTextView
|
||||
{
|
||||
GtkTextView parent;
|
||||
GFile *file;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);
|
||||
|
||||
enum {
|
||||
CHANGE_FILE,
|
||||
OPEN_RESPONSE,
|
||||
NUMBER_OF_SIGNALS
|
||||
};
|
||||
|
||||
static guint tfe_text_view_signals[NUMBER_OF_SIGNALS];
|
||||
|
||||
static void
|
||||
tfe_text_view_dispose (GObject *gobject) {
|
||||
TfeTextView *tv = TFE_TEXT_VIEW (gobject);
|
||||
|
||||
if (G_IS_FILE (tv->file))
|
||||
g_clear_object (&tv->file);
|
||||
|
||||
G_OBJECT_CLASS (tfe_text_view_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
tfe_text_view_init (TfeTextView *tv) {
|
||||
GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
|
||||
tv->file = NULL;
|
||||
gtk_text_buffer_set_modified (tb, FALSE);
|
||||
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
|
||||
}
|
||||
|
||||
static void
|
||||
tfe_text_view_class_init (TfeTextViewClass *class) {
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->dispose = tfe_text_view_dispose;
|
||||
tfe_text_view_signals[CHANGE_FILE] = g_signal_newv ("change-file",
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
|
||||
NULL /* closure */,
|
||||
NULL /* accumulator */,
|
||||
NULL /* accumulator data */,
|
||||
NULL /* C marshaller */,
|
||||
G_TYPE_NONE /* return_type */,
|
||||
0 /* n_params */,
|
||||
NULL /* param_types */);
|
||||
GType param_types[] = {G_TYPE_INT};
|
||||
tfe_text_view_signals[OPEN_RESPONSE] = g_signal_newv ("open-response",
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
|
||||
NULL /* closure */,
|
||||
NULL /* accumulator */,
|
||||
NULL /* accumulator data */,
|
||||
NULL /* C marshaller */,
|
||||
G_TYPE_NONE /* return_type */,
|
||||
1 /* n_params */,
|
||||
param_types);
|
||||
}
|
||||
|
||||
GFile *
|
||||
tfe_text_view_get_file (TfeTextView *tv) {
|
||||
g_return_val_if_fail (TFE_IS_TEXT_VIEW (tv), NULL);
|
||||
|
||||
return g_file_dup (tv->file);
|
||||
}
|
||||
|
||||
static void
|
||||
open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||
GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
GFile *file;
|
||||
char *contents;
|
||||
gsize length;
|
||||
GtkWidget *message_dialog;
|
||||
GError *err = NULL;
|
||||
|
||||
if (response != GTK_RESPONSE_ACCEPT)
|
||||
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL);
|
||||
else if (! G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog))))
|
||||
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
||||
else if (! g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) { /* read error */
|
||||
if (G_IS_FILE (file))
|
||||
g_object_unref (file);
|
||||
message_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||
"%s.\n", err->message);
|
||||
g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||
gtk_widget_show (message_dialog);
|
||||
g_error_free (err);
|
||||
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
|
||||
} else {
|
||||
gtk_text_buffer_set_text (tb, contents, length);
|
||||
g_free (contents);
|
||||
if (G_IS_FILE (tv->file))
|
||||
g_object_unref (tv->file);
|
||||
tv->file = file;
|
||||
gtk_text_buffer_set_modified (tb, FALSE);
|
||||
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
|
||||
}
|
||||
gtk_window_destroy (GTK_WINDOW (dialog));
|
||||
}
|
||||
|
||||
void
|
||||
tfe_text_view_open (TfeTextView *tv, GtkWidget *win) {
|
||||
g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||
g_return_if_fail (GTK_IS_WINDOW (win));
|
||||
|
||||
GtkWidget *dialog;
|
||||
|
||||
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), tv);
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {
|
||||
GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
GFile *file;
|
||||
|
||||
if (response == GTK_RESPONSE_ACCEPT) {
|
||||
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
|
||||
if (G_IS_FILE(file)) {
|
||||
tv->file = file;
|
||||
gtk_text_buffer_set_modified (tb, TRUE);
|
||||
g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||
tfe_text_view_save (TFE_TEXT_VIEW (tv));
|
||||
}
|
||||
}
|
||||
gtk_window_destroy (GTK_WINDOW (dialog));
|
||||
}
|
||||
|
||||
void
|
||||
tfe_text_view_save (TfeTextView *tv) {
|
||||
g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||
|
||||
GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
GtkTextIter start_iter;
|
||||
GtkTextIter end_iter;
|
||||
gchar *contents;
|
||||
GtkWidget *message_dialog;
|
||||
GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||
GError *err = NULL;
|
||||
|
||||
if (! gtk_text_buffer_get_modified (tb))
|
||||
return; /* no necessary to save it */
|
||||
else if (tv->file == NULL)
|
||||
tfe_text_view_saveas (tv);
|
||||
else {
|
||||
gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
|
||||
contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
|
||||
if (g_file_replace_contents (tv->file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, &err))
|
||||
gtk_text_buffer_set_modified (tb, FALSE);
|
||||
else {
|
||||
/* It is possible that tv->file is broken. */
|
||||
/* It is a good idea to set tv->file to NULL. */
|
||||
if (G_IS_FILE (tv->file))
|
||||
g_object_unref (tv->file);
|
||||
tv->file =NULL;
|
||||
g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
|
||||
gtk_text_buffer_set_modified (tb, TRUE);
|
||||
message_dialog = gtk_message_dialog_new (GTK_WINDOW (win), GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
|
||||
"%s.\n", err->message);
|
||||
g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
|
||||
gtk_widget_show (message_dialog);
|
||||
g_error_free (err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tfe_text_view_saveas (TfeTextView *tv) {
|
||||
g_return_if_fail (TFE_IS_TEXT_VIEW (tv));
|
||||
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);
|
||||
|
||||
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), tv);
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
tfe_text_view_new_with_file (GFile *file) {
|
||||
g_return_val_if_fail (G_IS_FILE (file), NULL);
|
||||
|
||||
GtkWidget *tv;
|
||||
GtkTextBuffer *tb;
|
||||
char *contents;
|
||||
gsize length;
|
||||
|
||||
if (! g_file_load_contents (file, NULL, &contents, &length, NULL, NULL)) /* read error */
|
||||
return NULL;
|
||||
|
||||
tv = tfe_text_view_new();
|
||||
tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
|
||||
gtk_text_buffer_set_text (tb, contents, length);
|
||||
g_free (contents);
|
||||
TFE_TEXT_VIEW (tv)->file = g_file_dup (file);
|
||||
return tv;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
tfe_text_view_new (void) {
|
||||
return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
|
||||
}
|
||||
|
29
src/color/tfetextview.h
Normal file
29
src/color/tfetextview.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
|
||||
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)
|
||||
|
||||
/* "open-response" signal response */
|
||||
enum
|
||||
{
|
||||
TFE_OPEN_RESPONSE_SUCCESS,
|
||||
TFE_OPEN_RESPONSE_CANCEL,
|
||||
TFE_OPEN_RESPONSE_ERROR
|
||||
};
|
||||
|
||||
GFile *
|
||||
tfe_text_view_get_file (TfeTextView *tv);
|
||||
|
||||
void
|
||||
tfe_text_view_open (TfeTextView *tv, GtkWidget *win);
|
||||
|
||||
void
|
||||
tfe_text_view_save (TfeTextView *tv);
|
||||
|
||||
void
|
||||
tfe_text_view_saveas (TfeTextView *tv);
|
||||
|
||||
GtkWidget *
|
||||
tfe_text_view_new_with_file (GFile *file);
|
||||
|
||||
GtkWidget *
|
||||
tfe_text_view_new (void);
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
This section and the following four sections are explanations about the next version of the text file editor (tfe).
|
||||
It is tfe5.
|
||||
It has many changes from the prior version.
|
||||
All the sources are listed after the five sections.
|
||||
All the sources are listed in [Section 15](sec15.src.md).
|
||||
|
||||
## Encapsulation
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ We can draw shapes and images with different colors on surfaces.
|
|||
- 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 mathematicsterminology, and represented by matrix multiplication and vector addition.
|
||||
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.
|
||||
|
|
149
src/sec20.src.md
Normal file
149
src/sec20.src.md
Normal file
|
@ -0,0 +1,149 @@
|
|||
# Combine GtkDrawingArea and TfeTextView
|
||||
|
||||
Now, we will make a new application which has GtkDrawingArea and TfeTextView in it.
|
||||
Its name is "color".
|
||||
If you write a color in TfeTextView and click on the `run` button, then the color of GtkDrawingArea changes to the color given by you.
|
||||
|
||||
![color](../image/color.png)
|
||||
|
||||
The following colors are available.
|
||||
|
||||
- white
|
||||
- black
|
||||
- red
|
||||
- green
|
||||
- blue
|
||||
|
||||
In addition the following two options are also available.
|
||||
|
||||
- light: Make the color of the drawing area lighter.
|
||||
- dark: Make the color of the drawing area darker.
|
||||
|
||||
This application can only do very simple things.
|
||||
However, it tells us that if we add powerful parser to it, we will be able to make it more efficient.
|
||||
I want to show it to you in the later section by making a turtle graphics language like Logo program language.
|
||||
|
||||
In this section, we focus on how to bind the two objects.
|
||||
|
||||
# Color.ui and color.gresource.xml
|
||||
|
||||
First, We need to make the ui file of the widgets.
|
||||
The image in the previous subsection gives us the structure of the widgets.
|
||||
Title bar, four buttons in the tool bar and two widgets textview and drawing area.
|
||||
The ui file is as follows.
|
||||
|
||||
@@@ color/color.ui
|
||||
|
||||
- 9-53: This part describes the tool bar which has four buttons, `Run`, `Open`, `Save` and `Close`.
|
||||
This is similar to the toolbar of tfe text editor in [Section 8](sec8.src.md).
|
||||
There are two differences.
|
||||
`Run` button replaces `New` button.
|
||||
Signal element are added to each button object.
|
||||
It has "name" attribute which is a signal name and "handler" attribute which is the name of its signal handler function.
|
||||
Options "-WI, --export-dynamic" CFLAG is necessary when you compile the application.
|
||||
You can achieve this by adding "export_dynamic: true" argument to executable function in `meson.build`.
|
||||
And be careful that the handler must be defined without 'static' class.
|
||||
- 54-76: Put GtkScrolledWindow and GtkDrawingArea into GtkBox.
|
||||
GtkBox has "homogeneous property with TRUE value, so the two children have the same width in the box.
|
||||
TfeTextView is a child of GtkScrolledWindow.
|
||||
|
||||
The xml file for the resource compiler is almost same as before.
|
||||
Just substitute "color" for "tfe".
|
||||
|
||||
@@@ color/color.gresource.xml
|
||||
|
||||
# Tfetextview.h, tfetextview.c and color.h
|
||||
|
||||
First two files are almost same as before.
|
||||
The only difference is the header file in tfettextview.c.
|
||||
|
||||
$$$
|
||||
diff tfe5/tfetextview.c color/tfetextview.c
|
||||
$$$
|
||||
|
||||
Color.h just includes tfetextview.h.
|
||||
|
||||
@@@ color/color.h
|
||||
|
||||
# Colorapplication.c
|
||||
|
||||
This is the main file.
|
||||
It deals with:
|
||||
|
||||
- Build widgets by GtkBuilder.
|
||||
- Set drawing function to GtkDrawingArea.
|
||||
And connect a handler to "resize" signal on GtkDrawingArea.
|
||||
- Implement each call back functions.
|
||||
Particularly, `Run` signal handler is the point in this program.
|
||||
|
||||
The following is `colorapplication.c`.
|
||||
|
||||
@@@ color/colorapplication.c
|
||||
|
||||
- 108-121: The function `main` is almost same as before but there are some differences.
|
||||
The application ID is "com.github.ToshioCP.color".
|
||||
`G_APPLICATION_FLAGS_NONE` is specified so no open signal handler is necessary.
|
||||
- 86-106: Startup handler.
|
||||
- 91-96: Build widgets.
|
||||
The pointers of the top window, TfeTextView and GtkDrawingArea objects are stored to static variables `win`, `tv` and `da` respectively.
|
||||
This is because these objects are often used in handlers.
|
||||
They never be rewritten so they're thread safe.
|
||||
- 97: connect "resize" signal and the handler.
|
||||
- 98: set the drawing function.
|
||||
- 81-84: Activate handler, which just show the widgets.
|
||||
- 73-79: The drawing function.
|
||||
It just copy `surface` to destination.
|
||||
- 65-71: Resize handler.
|
||||
Re-create the surface to fit the width and height of the drawing area and paint by calling the function `run`.
|
||||
- 58-63: Close handler.
|
||||
It destroys `surface` if it exists.
|
||||
Then it destroys the top window and quits the application.
|
||||
- 48-56: Open and save handler.
|
||||
They just call the corresponding functions of TfeTextView.
|
||||
- 42-46: Run handler.
|
||||
It calls run function to paint the surface.
|
||||
After that `gtk_widget_queue_draw` is called.
|
||||
This fhunction adds the widget (GtkDrawingArea) to the queue to be redrawn.
|
||||
It is important to know that the drawing function is called when it is necessary.
|
||||
For example, when another window is moved and uncovers part of the widget, or when the window containing it is resized.
|
||||
But repaint of `surface` is not automatically notified to gtk.
|
||||
Therefore, you need to call `gtk_widget_queue_draw` to redraw the widget.
|
||||
- 9-40: Run function paint the surface.
|
||||
First, it gets the contents of GtkTextBuffer.
|
||||
Then compare it to "red", "green" and so on.
|
||||
If it matches the color, then the surface is painted the color.
|
||||
If it matches "light" or "dark", then the color of the surface is lightened or darkened respectively.
|
||||
Alpha channel is used.
|
||||
|
||||
# Meson.build
|
||||
|
||||
This file is almost same as before.
|
||||
An argument "export_dynamic: true" is added to executable function.
|
||||
|
||||
@@@ color/meson.build
|
||||
|
||||
# Compile and execute it
|
||||
|
||||
First you need to export some variables (refer to [Section 2](sec2.src.md)).
|
||||
|
||||
$ . env.sh
|
||||
|
||||
Then type the following to compile it.
|
||||
|
||||
$ meson _build
|
||||
$ ninja -C _build
|
||||
|
||||
The application is made in `_build` directory.
|
||||
Type the following to execute it.
|
||||
|
||||
$ _build/color
|
||||
|
||||
Type "red", "green", "blue", "white", black", "light" or "dark" in the TfeTextView.
|
||||
Then, click on `Run` button.
|
||||
Make sure the color of GtkDrawingArea changes.
|
||||
|
||||
In this program TfeTextView is used to change the color.
|
||||
You can use buttons or menus instead of textview.
|
||||
Probably it is more appropriate.
|
||||
Using textview is unnatural.
|
||||
It is a good practice to make such application by yourself.
|
|
@ -95,8 +95,8 @@ The function `g_signal_connect` has four arguments.
|
|||
4. Data to pass to the handler. If no data is necessary, NULL should be given.
|
||||
|
||||
You can find the description of each signal in API reference.
|
||||
For example, "activate" signal is in GApplication subsection in GIO API reference.
|
||||
The handler function is described in that subsection.
|
||||
For example, "activate" signal is in GApplication section in GIO API reference.
|
||||
The handler function is described in that section.
|
||||
|
||||
In addition, `g_signal_connect` is described in GObject API reference.
|
||||
API reference is very important.
|
||||
|
|
|
@ -47,7 +47,7 @@ For example, TfeTextView has GtkTextbuffer correspods to GtkTextView inside TfeT
|
|||
And important thing is that TfeTextView can have a memory to keep a pointer to GFile.
|
||||
|
||||
However, to understand the general theory about gobjects is very hard especially for beginners.
|
||||
So, I will just show you the way how to write the code and avoid the theoretical side in the next section.
|
||||
So, I will just show you the way how to write the code and avoid the theoretical side in the next subsection.
|
||||
|
||||
## How to define a child widget of GtkTextView
|
||||
|
||||
|
|
Loading…
Reference in a new issue