1 | #include <gtk/gtk.h> |
2 | |
3 | #include "exampleapp.h" |
4 | #include "exampleappwin.h" |
5 | |
6 | struct _ExampleAppWindow |
7 | { |
8 | GtkApplicationWindow parent; |
9 | |
10 | GSettings *settings; |
11 | GtkWidget *stack; |
12 | GtkWidget *gears; |
13 | GtkWidget *search; |
14 | GtkWidget *searchbar; |
15 | }; |
16 | |
17 | G_DEFINE_TYPE (ExampleAppWindow, example_app_window, GTK_TYPE_APPLICATION_WINDOW) |
18 | |
19 | static void |
20 | search_text_changed (GtkEntry *entry, |
21 | ExampleAppWindow *win) |
22 | { |
23 | const char *text; |
24 | GtkWidget *tab; |
25 | GtkWidget *view; |
26 | GtkTextBuffer *buffer; |
27 | GtkTextIter start, match_start, match_end; |
28 | |
29 | text = gtk_editable_get_text (GTK_EDITABLE (entry)); |
30 | |
31 | if (text[0] == '\0') |
32 | return; |
33 | |
34 | tab = gtk_stack_get_visible_child (GTK_STACK (win->stack)); |
35 | view = gtk_scrolled_window_get_child (GTK_SCROLLED_WINDOW (tab)); |
36 | buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); |
37 | |
38 | /* Very simple-minded search implementation */ |
39 | gtk_text_buffer_get_start_iter (buffer, iter: &start); |
40 | if (gtk_text_iter_forward_search (iter: &start, str: text, flags: GTK_TEXT_SEARCH_CASE_INSENSITIVE, |
41 | match_start: &match_start, match_end: &match_end, NULL)) |
42 | { |
43 | gtk_text_buffer_select_range (buffer, ins: &match_start, bound: &match_end); |
44 | gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (view), iter: &match_start, |
45 | within_margin: 0.0, FALSE, xalign: 0.0, yalign: 0.0); |
46 | } |
47 | } |
48 | |
49 | static void |
50 | visible_child_changed (GObject *stack, |
51 | GParamSpec *pspec, |
52 | ExampleAppWindow *win) |
53 | { |
54 | if (gtk_widget_in_destruction (GTK_WIDGET (stack))) |
55 | return; |
56 | |
57 | gtk_search_bar_set_search_mode (GTK_SEARCH_BAR (win->searchbar), FALSE); |
58 | } |
59 | |
60 | static void |
61 | example_app_window_init (ExampleAppWindow *win) |
62 | { |
63 | GtkBuilder *builder; |
64 | GMenuModel *; |
65 | |
66 | gtk_widget_init_template (GTK_WIDGET (win)); |
67 | |
68 | builder = gtk_builder_new_from_resource (resource_path: "/org/gtk/exampleapp/gears-menu.ui" ); |
69 | menu = G_MENU_MODEL (gtk_builder_get_object (builder, "menu" )); |
70 | gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (win->gears), menu_model: menu); |
71 | g_object_unref (object: builder); |
72 | |
73 | win->settings = g_settings_new (schema_id: "org.gtk.exampleapp" ); |
74 | |
75 | g_settings_bind (settings: win->settings, key: "transition" , |
76 | object: win->stack, property: "transition-type" , |
77 | flags: G_SETTINGS_BIND_DEFAULT); |
78 | |
79 | g_object_bind_property (source: win->search, source_property: "active" , |
80 | target: win->searchbar, target_property: "search-mode-enabled" , |
81 | flags: G_BINDING_BIDIRECTIONAL); |
82 | } |
83 | |
84 | static void |
85 | example_app_window_dispose (GObject *object) |
86 | { |
87 | ExampleAppWindow *win; |
88 | |
89 | win = EXAMPLE_APP_WINDOW (ptr: object); |
90 | |
91 | g_clear_object (&win->settings); |
92 | |
93 | G_OBJECT_CLASS (example_app_window_parent_class)->dispose (object); |
94 | } |
95 | |
96 | static void |
97 | example_app_window_class_init (ExampleAppWindowClass *class) |
98 | { |
99 | G_OBJECT_CLASS (class)->dispose = example_app_window_dispose; |
100 | |
101 | gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class), |
102 | resource_name: "/org/gtk/exampleapp/window.ui" ); |
103 | |
104 | gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, stack); |
105 | gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, gears); |
106 | gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, search); |
107 | gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (class), ExampleAppWindow, searchbar); |
108 | |
109 | gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), search_text_changed); |
110 | gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (class), visible_child_changed); |
111 | } |
112 | |
113 | ExampleAppWindow * |
114 | example_app_window_new (ExampleApp *app) |
115 | { |
116 | return g_object_new (EXAMPLE_APP_WINDOW_TYPE, first_property_name: "application" , app, NULL); |
117 | } |
118 | |
119 | void |
120 | example_app_window_open (ExampleAppWindow *win, |
121 | GFile *file) |
122 | { |
123 | char *basename; |
124 | GtkWidget *scrolled, *view; |
125 | char *contents; |
126 | gsize length; |
127 | GtkTextBuffer *buffer; |
128 | GtkTextTag *tag; |
129 | GtkTextIter start_iter, end_iter; |
130 | |
131 | basename = g_file_get_basename (file); |
132 | |
133 | scrolled = gtk_scrolled_window_new (); |
134 | gtk_widget_set_hexpand (widget: scrolled, TRUE); |
135 | gtk_widget_set_vexpand (widget: scrolled, TRUE); |
136 | view = gtk_text_view_new (); |
137 | gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE); |
138 | gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE); |
139 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), child: view); |
140 | gtk_stack_add_titled (GTK_STACK (win->stack), child: scrolled, name: basename, title: basename); |
141 | |
142 | buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); |
143 | |
144 | if (g_file_load_contents (file, NULL, contents: &contents, length: &length, NULL, NULL)) |
145 | { |
146 | gtk_text_buffer_set_text (buffer, text: contents, len: length); |
147 | g_free (mem: contents); |
148 | } |
149 | |
150 | tag = gtk_text_buffer_create_tag (buffer, NULL, NULL); |
151 | g_settings_bind (settings: win->settings, key: "font" , |
152 | object: tag, property: "font" , |
153 | flags: G_SETTINGS_BIND_DEFAULT); |
154 | |
155 | gtk_text_buffer_get_start_iter (buffer, iter: &start_iter); |
156 | gtk_text_buffer_get_end_iter (buffer, iter: &end_iter); |
157 | gtk_text_buffer_apply_tag (buffer, tag, start: &start_iter, end: &end_iter); |
158 | |
159 | g_free (mem: basename); |
160 | |
161 | gtk_widget_set_sensitive (widget: win->search, TRUE); |
162 | } |
163 | |