aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheJackiMonster <thejackimonster@gmail.com>2021-11-25 22:45:04 +0100
committerTheJackiMonster <thejackimonster@gmail.com>2021-11-25 22:45:04 +0100
commit9b67d565baf5ce0f555cb38abdda22696cbfe778 (patch)
treeb0da8719278f02b15c5360329e8488130d9cbfb5
parent5df934d452aaedf319028740987de0e0dcac52d5 (diff)
downloadmessenger-gtk-9b67d565baf5ce0f555cb38abdda22696cbfe778.tar.gz
messenger-gtk-9b67d565baf5ce0f555cb38abdda22696cbfe778.zip
Added emoji picker
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r--.gitmodules3
-rw-r--r--Makefile5
-rw-r--r--resources/css/style.css8
-rw-r--r--resources/ui/chat.ui19
-rw-r--r--resources/ui/picker.ui508
-rw-r--r--src/application.c2
-rw-r--r--src/ui/chat.c35
-rw-r--r--src/ui/chat.h5
-rw-r--r--src/ui/messenger.c2
-rw-r--r--src/ui/picker.c251
-rw-r--r--src/ui/picker.h65
m---------submodules/gnome-characters0
12 files changed, 897 insertions, 6 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..65ecbeb
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
1[submodule "submodules/gnome-characters"]
2 path = submodules/gnome-characters
3 url = https://gitlab.gnome.org/GNOME/gnome-characters.git
diff --git a/Makefile b/Makefile
index 2869414..6484d14 100644
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,7 @@ SOURCES = messenger_gtk.c\
15 ui/messenger.c\ 15 ui/messenger.c\
16 ui/new_contact.c\ 16 ui/new_contact.c\
17 ui/new_platform.c\ 17 ui/new_platform.c\
18 ui/picker.c\
18 ui/profile_entry.c\ 19 ui/profile_entry.c\
19 ui/settings.c 20 ui/settings.c
20 21
@@ -22,6 +23,7 @@ HEADERS =
22 23
23LIBRARIES = gnunetchat 24LIBRARIES = gnunetchat
24PACKAGES = gnunetutil libhandy-1 gtk+-3.0 libnotify zbar libqrencode 25PACKAGES = gnunetutil libhandy-1 gtk+-3.0 libnotify zbar libqrencode
26INCLUDES = submodules/gnome-characters/lib
25 27
26GNU_CC ?= gcc 28GNU_CC ?= gcc
27GNU_LD ?= gcc 29GNU_LD ?= gcc
@@ -38,6 +40,7 @@ OBJECT_FILES = $(SOURCE_FILES:%.c=%.o)
38HEADER_FILES = $(addprefix $(SOURCE_DIR), $(HEADERS)) 40HEADER_FILES = $(addprefix $(SOURCE_DIR), $(HEADERS))
39LIBRARY_FLAGS = $(addprefix -l, $(LIBRARIES)) 41LIBRARY_FLAGS = $(addprefix -l, $(LIBRARIES))
40PACKAGE_FLAGS = $(shell pkg-config --cflags --libs $(PACKAGES)) 42PACKAGE_FLAGS = $(shell pkg-config --cflags --libs $(PACKAGES))
43INCLUDE_FLAGS = $(addprefix -I, $(INCLUDES))
41 44
42all: $(BINARY) 45all: $(BINARY)
43 46
@@ -48,7 +51,7 @@ release: CFLAGS += $(RELEASEFLAGS)
48release: $(BINARY) 51release: $(BINARY)
49 52
50%.o: %.c 53%.o: %.c
51 $(GNU_CC) $(CFLAGS) -c $< -o $@ $(LIBRARY_FLAGS) $(PACKAGE_FLAGS) 54 $(GNU_CC) $(CFLAGS) -c $< -o $@ $(LIBRARY_FLAGS) $(PACKAGE_FLAGS) $(INCLUDE_FLAGS)
52 55
53$(BINARY): $(OBJECT_FILES) 56$(BINARY): $(OBJECT_FILES)
54 $(GNU_LD) $(LDFLAGS) $^ -o $@ $(LIBRARY_FLAGS) $(PACKAGE_FLAGS) 57 $(GNU_LD) $(LDFLAGS) $^ -o $@ $(LIBRARY_FLAGS) $(PACKAGE_FLAGS)
diff --git a/resources/css/style.css b/resources/css/style.css
index a75a5e2..1f923d6 100644
--- a/resources/css/style.css
+++ b/resources/css/style.css
@@ -61,6 +61,14 @@
61 padding: 2px 4px; 61 padding: 2px 4px;
62} 62}
63 63
64.picker-switcher-box {
65 padding: 0px 8px;
66}
67
68.emoji-flow-box {
69 font-size: large;
70}
71
64.settings-entry { 72.settings-entry {
65 margin: 8px; 73 margin: 8px;
66} 74}
diff --git a/resources/ui/chat.ui b/resources/ui/chat.ui
index c653b3e..f6e8cc8 100644
--- a/resources/ui/chat.ui
+++ b/resources/ui/chat.ui
@@ -169,6 +169,22 @@ Author: Tobias Frisch
169 </packing> 169 </packing>
170 </child> 170 </child>
171 <child> 171 <child>
172 <object class="GtkRevealer" id="picker_revealer">
173 <property name="visible">True</property>
174 <property name="can-focus">False</property>
175 <property name="transition-type">slide-up</property>
176 <child>
177 <placeholder/>
178 </child>
179 </object>
180 <packing>
181 <property name="expand">False</property>
182 <property name="fill">True</property>
183 <property name="pack-type">end</property>
184 <property name="position">2</property>
185 </packing>
186 </child>
187 <child>
172 <object class="GtkBox"> 188 <object class="GtkBox">
173 <property name="visible">True</property> 189 <property name="visible">True</property>
174 <property name="can-focus">False</property> 190 <property name="can-focus">False</property>
@@ -263,7 +279,8 @@ Author: Tobias Frisch
263 <packing> 279 <packing>
264 <property name="expand">False</property> 280 <property name="expand">False</property>
265 <property name="fill">True</property> 281 <property name="fill">True</property>
266 <property name="position">2</property> 282 <property name="pack-type">end</property>
283 <property name="position">3</property>
267 </packing> 284 </packing>
268 </child> 285 </child>
269 </object> 286 </object>
diff --git a/resources/ui/picker.ui b/resources/ui/picker.ui
new file mode 100644
index 0000000..fec48e5
--- /dev/null
+++ b/resources/ui/picker.ui
@@ -0,0 +1,508 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<!-- Generated with glade 3.38.2
3
4Copyright (C) 2021 GNUnet e.V.
5
6GNUnet is free software: you can redistribute it and/or modify it
7under the terms of the GNU Affero General Public License as published
8by the Free Software Foundation, either version 3 of the License,
9or (at your option) any later version.
10
11GNUnet is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14Affero General Public License for more details.
15
16You should have received a copy of the GNU Affero General Public License
17along with this program. If not, see <http://www.gnu.org/licenses/>.
18
19SPDX-License-Identifier: AGPL3.0-or-later
20Author: Tobias Frisch
21
22-->
23<interface>
24 <requires lib="gtk+" version="3.24"/>
25 <requires lib="libhandy" version="1.2"/>
26 <object class="GtkBox" id="picker_box">
27 <property name="height-request">250</property>
28 <property name="visible">True</property>
29 <property name="can-focus">False</property>
30 <property name="orientation">vertical</property>
31 <child>
32 <object class="GtkStack" id="picker_stack">
33 <property name="visible">True</property>
34 <property name="can-focus">False</property>
35 <child>
36 <object class="GtkBox">
37 <property name="visible">True</property>
38 <property name="can-focus">False</property>
39 <property name="orientation">vertical</property>
40 <child>
41 <object class="GtkScrolledWindow">
42 <property name="visible">True</property>
43 <property name="can-focus">True</property>
44 <property name="vscrollbar-policy">never</property>
45 <property name="shadow-type">in</property>
46 <child>
47 <object class="GtkViewport">
48 <property name="visible">True</property>
49 <property name="can-focus">False</property>
50 <child>
51 <object class="HdyViewSwitcherBar" id="emoji_switcher_bar">
52 <property name="visible">True</property>
53 <property name="can-focus">False</property>
54 <property name="stack">emoji_stack</property>
55 <property name="reveal">True</property>
56 </object>
57 </child>
58 </object>
59 </child>
60 </object>
61 <packing>
62 <property name="expand">False</property>
63 <property name="fill">True</property>
64 <property name="position">0</property>
65 </packing>
66 </child>
67 <child>
68 <object class="GtkStack" id="emoji_stack">
69 <property name="visible">True</property>
70 <property name="can-focus">False</property>
71 <child>
72 <object class="GtkScrolledWindow">
73 <property name="visible">True</property>
74 <property name="can-focus">True</property>
75 <property name="shadow-type">in</property>
76 <child>
77 <object class="GtkViewport">
78 <property name="visible">True</property>
79 <property name="can-focus">False</property>
80 <child>
81 <object class="GtkFlowBox" id="recent_flow_box">
82 <property name="visible">True</property>
83 <property name="can-focus">False</property>
84 <property name="border-width">8</property>
85 <property name="homogeneous">True</property>
86 <property name="max-children-per-line">8</property>
87 <property name="selection-mode">none</property>
88 <style>
89 <class name="emoji-flow-box"/>
90 </style>
91 </object>
92 </child>
93 </object>
94 </child>
95 </object>
96 <packing>
97 <property name="name">recent</property>
98 <property name="icon-name">emoji-recent-symbolic</property>
99 </packing>
100 </child>
101 <child>
102 <object class="GtkScrolledWindow">
103 <property name="visible">True</property>
104 <property name="can-focus">True</property>
105 <property name="shadow-type">in</property>
106 <child>
107 <object class="GtkViewport">
108 <property name="visible">True</property>
109 <property name="can-focus">False</property>
110 <child>
111 <object class="GtkFlowBox" id="people_flow_box">
112 <property name="visible">True</property>
113 <property name="can-focus">False</property>
114 <property name="border-width">8</property>
115 <property name="homogeneous">True</property>
116 <property name="max-children-per-line">8</property>
117 <property name="selection-mode">none</property>
118 <style>
119 <class name="emoji-flow-box"/>
120 </style>
121 </object>
122 </child>
123 </object>
124 </child>
125 </object>
126 <packing>
127 <property name="name">people</property>
128 <property name="icon-name">emoji-people-symbolic</property>
129 <property name="position">1</property>
130 </packing>
131 </child>
132 <child>
133 <object class="GtkScrolledWindow">
134 <property name="visible">True</property>
135 <property name="can-focus">True</property>
136 <property name="shadow-type">in</property>
137 <child>
138 <object class="GtkViewport">
139 <property name="visible">True</property>
140 <property name="can-focus">False</property>
141 <child>
142 <object class="GtkFlowBox" id="nature_flow_box">
143 <property name="visible">True</property>
144 <property name="can-focus">False</property>
145 <property name="border-width">8</property>
146 <property name="homogeneous">True</property>
147 <property name="max-children-per-line">8</property>
148 <property name="selection-mode">none</property>
149 <style>
150 <class name="emoji-flow-box"/>
151 </style>
152 </object>
153 </child>
154 </object>
155 </child>
156 </object>
157 <packing>
158 <property name="name">nature</property>
159 <property name="icon-name">emoji-nature-symbolic</property>
160 <property name="position">2</property>
161 </packing>
162 </child>
163 <child>
164 <object class="GtkScrolledWindow">
165 <property name="visible">True</property>
166 <property name="can-focus">True</property>
167 <property name="shadow-type">in</property>
168 <child>
169 <object class="GtkViewport">
170 <property name="visible">True</property>
171 <property name="can-focus">False</property>
172 <child>
173 <object class="GtkFlowBox" id="food_flow_box">
174 <property name="visible">True</property>
175 <property name="can-focus">False</property>
176 <property name="border-width">8</property>
177 <property name="homogeneous">True</property>
178 <property name="max-children-per-line">8</property>
179 <property name="selection-mode">none</property>
180 <style>
181 <class name="emoji-flow-box"/>
182 </style>
183 </object>
184 </child>
185 </object>
186 </child>
187 </object>
188 <packing>
189 <property name="name">food</property>
190 <property name="icon-name">emoji-food-symbolic</property>
191 <property name="position">3</property>
192 </packing>
193 </child>
194 <child>
195 <object class="GtkScrolledWindow">
196 <property name="visible">True</property>
197 <property name="can-focus">True</property>
198 <property name="shadow-type">in</property>
199 <child>
200 <object class="GtkViewport">
201 <property name="visible">True</property>
202 <property name="can-focus">False</property>
203 <child>
204 <object class="GtkFlowBox" id="activities_flow_box">
205 <property name="visible">True</property>
206 <property name="can-focus">False</property>
207 <property name="border-width">8</property>
208 <property name="homogeneous">True</property>
209 <property name="max-children-per-line">8</property>
210 <property name="selection-mode">none</property>
211 <style>
212 <class name="emoji-flow-box"/>
213 </style>
214 </object>
215 </child>
216 </object>
217 </child>
218 </object>
219 <packing>
220 <property name="name">activities</property>
221 <property name="icon-name">emoji-activities-symbolic</property>
222 <property name="position">4</property>
223 </packing>
224 </child>
225 <child>
226 <object class="GtkScrolledWindow">
227 <property name="visible">True</property>
228 <property name="can-focus">True</property>
229 <property name="shadow-type">in</property>
230 <child>
231 <object class="GtkViewport">
232 <property name="visible">True</property>
233 <property name="can-focus">False</property>
234 <child>
235 <object class="GtkFlowBox" id="travel_flow_box">
236 <property name="visible">True</property>
237 <property name="can-focus">False</property>
238 <property name="border-width">8</property>
239 <property name="homogeneous">True</property>
240 <property name="max-children-per-line">8</property>
241 <property name="selection-mode">none</property>
242 <style>
243 <class name="emoji-flow-box"/>
244 </style>
245 </object>
246 </child>
247 </object>
248 </child>
249 </object>
250 <packing>
251 <property name="name">travel</property>
252 <property name="icon-name">emoji-travel-symbolic</property>
253 <property name="position">5</property>
254 </packing>
255 </child>
256 <child>
257 <object class="GtkScrolledWindow">
258 <property name="visible">True</property>
259 <property name="can-focus">True</property>
260 <property name="shadow-type">in</property>
261 <child>
262 <object class="GtkViewport">
263 <property name="visible">True</property>
264 <property name="can-focus">False</property>
265 <child>
266 <object class="GtkFlowBox" id="objects_flow_box">
267 <property name="visible">True</property>
268 <property name="can-focus">False</property>
269 <property name="border-width">8</property>
270 <property name="homogeneous">True</property>
271 <property name="max-children-per-line">8</property>
272 <property name="selection-mode">none</property>
273 <style>
274 <class name="emoji-flow-box"/>
275 </style>
276 </object>
277 </child>
278 </object>
279 </child>
280 </object>
281 <packing>
282 <property name="name">objects</property>
283 <property name="icon-name">emoji-objects-symbolic</property>
284 <property name="position">6</property>
285 </packing>
286 </child>
287 <child>
288 <object class="GtkScrolledWindow">
289 <property name="visible">True</property>
290 <property name="can-focus">True</property>
291 <property name="shadow-type">in</property>
292 <child>
293 <object class="GtkViewport">
294 <property name="visible">True</property>
295 <property name="can-focus">False</property>
296 <child>
297 <object class="GtkFlowBox" id="symbols_flow_box">
298 <property name="visible">True</property>
299 <property name="can-focus">False</property>
300 <property name="border-width">8</property>
301 <property name="homogeneous">True</property>
302 <property name="max-children-per-line">8</property>
303 <property name="selection-mode">none</property>
304 <style>
305 <class name="emoji-flow-box"/>
306 </style>
307 </object>
308 </child>
309 </object>
310 </child>
311 </object>
312 <packing>
313 <property name="name">symbols</property>
314 <property name="icon-name">emoji-symbols-symbolic</property>
315 <property name="position">7</property>
316 </packing>
317 </child>
318 <child>
319 <object class="GtkScrolledWindow">
320 <property name="visible">True</property>
321 <property name="can-focus">True</property>
322 <property name="shadow-type">in</property>
323 <child>
324 <object class="GtkViewport">
325 <property name="visible">True</property>
326 <property name="can-focus">False</property>
327 <child>
328 <object class="GtkFlowBox" id="flags_flow_box">
329 <property name="visible">True</property>
330 <property name="can-focus">False</property>
331 <property name="border-width">8</property>
332 <property name="homogeneous">True</property>
333 <property name="max-children-per-line">8</property>
334 <property name="selection-mode">none</property>
335 <style>
336 <class name="emoji-flow-box"/>
337 </style>
338 </object>
339 </child>
340 </object>
341 </child>
342 </object>
343 <packing>
344 <property name="name">flags</property>
345 <property name="icon-name">emoji-flags-symbolic</property>
346 <property name="position">8</property>
347 </packing>
348 </child>
349 </object>
350 <packing>
351 <property name="expand">True</property>
352 <property name="fill">True</property>
353 <property name="pack-type">end</property>
354 <property name="position">1</property>
355 </packing>
356 </child>
357 <child>
358 <object class="HdySearchBar" id="emoji_search_bar">
359 <property name="visible">True</property>
360 <property name="can-focus">False</property>
361 <property name="show-close-button">True</property>
362 <child>
363 <object class="GtkSearchEntry" id="emoji_search_entry">
364 <property name="visible">True</property>
365 <property name="can-focus">True</property>
366 <property name="primary-icon-name">edit-find-symbolic</property>
367 <property name="primary-icon-activatable">False</property>
368 <property name="primary-icon-sensitive">False</property>
369 </object>
370 </child>
371 </object>
372 <packing>
373 <property name="expand">False</property>
374 <property name="fill">True</property>
375 <property name="position">2</property>
376 </packing>
377 </child>
378 </object>
379 <packing>
380 <property name="name">emoji</property>
381 <property name="title" translatable="yes">Emoji</property>
382 <property name="icon-name">face-smile-symbolic</property>
383 </packing>
384 </child>
385 <child>
386 <object class="GtkBox">
387 <property name="visible">True</property>
388 <property name="can-focus">False</property>
389 <property name="orientation">vertical</property>
390 <child>
391 <placeholder/>
392 </child>
393 <child>
394 <placeholder/>
395 </child>
396 <child>
397 <placeholder/>
398 </child>
399 </object>
400 <packing>
401 <property name="name">gif</property>
402 <property name="title" translatable="yes">GIF</property>
403 <property name="icon-name">video-x-generic-symbolic</property>
404 <property name="position">1</property>
405 </packing>
406 </child>
407 <child>
408 <object class="GtkBox">
409 <property name="visible">True</property>
410 <property name="can-focus">False</property>
411 <property name="orientation">vertical</property>
412 <child>
413 <placeholder/>
414 </child>
415 <child>
416 <placeholder/>
417 </child>
418 <child>
419 <placeholder/>
420 </child>
421 </object>
422 <packing>
423 <property name="name">stickers</property>
424 <property name="title" translatable="yes">Stickers</property>
425 <property name="icon-name">image-x-generic-symbolic</property>
426 <property name="position">2</property>
427 </packing>
428 </child>
429 </object>
430 <packing>
431 <property name="expand">True</property>
432 <property name="fill">True</property>
433 <property name="position">1</property>
434 </packing>
435 </child>
436 <child>
437 <object class="GtkBox">
438 <property name="visible">True</property>
439 <property name="can-focus">False</property>
440 <child>
441 <object class="GtkButton" id="search_button">
442 <property name="visible">True</property>
443 <property name="can-focus">True</property>
444 <property name="receives-default">True</property>
445 <property name="valign">center</property>
446 <property name="relief">none</property>
447 <child>
448 <object class="GtkImage">
449 <property name="visible">True</property>
450 <property name="can-focus">False</property>
451 <property name="icon-name">system-search-symbolic</property>
452 </object>
453 </child>
454 </object>
455 <packing>
456 <property name="expand">False</property>
457 <property name="fill">True</property>
458 <property name="position">0</property>
459 </packing>
460 </child>
461 <child>
462 <object class="HdyViewSwitcherBar" id="picker_switcher_bar">
463 <property name="visible">True</property>
464 <property name="can-focus">False</property>
465 <property name="policy">auto</property>
466 <property name="stack">picker_stack</property>
467 <property name="reveal">True</property>
468 </object>
469 <packing>
470 <property name="expand">True</property>
471 <property name="fill">True</property>
472 <property name="position">1</property>
473 </packing>
474 </child>
475 <child>
476 <object class="GtkButton" id="settings_button">
477 <property name="visible">True</property>
478 <property name="can-focus">True</property>
479 <property name="receives-default">True</property>
480 <property name="valign">center</property>
481 <property name="relief">none</property>
482 <child>
483 <object class="GtkImage">
484 <property name="visible">True</property>
485 <property name="can-focus">False</property>
486 <property name="icon-name">preferences-other-symbolic</property>
487 </object>
488 </child>
489 </object>
490 <packing>
491 <property name="expand">False</property>
492 <property name="fill">True</property>
493 <property name="pack-type">end</property>
494 <property name="position">2</property>
495 </packing>
496 </child>
497 <style>
498 <class name="picker-switcher-box"/>
499 </style>
500 </object>
501 <packing>
502 <property name="expand">False</property>
503 <property name="fill">True</property>
504 <property name="position">3</property>
505 </packing>
506 </child>
507 </object>
508</interface>
diff --git a/src/application.c b/src/application.c
index dfb214a..2062b82 100644
--- a/src/application.c
+++ b/src/application.c
@@ -157,8 +157,6 @@ application_run(MESSENGER_Application *app)
157 157
158 pthread_join(app->chat.tid, NULL); 158 pthread_join(app->chat.tid, NULL);
159 159
160 ui_messenger_cleanup(&(app->ui.messenger));
161
162 g_hash_table_destroy(app->ui.bindings); 160 g_hash_table_destroy(app->ui.bindings);
163 161
164 notify_uninit(); 162 notify_uninit();
diff --git a/src/ui/chat.c b/src/ui/chat.c
index b4dcca9..42943c3 100644
--- a/src/ui/chat.c
+++ b/src/ui/chat.c
@@ -25,6 +25,7 @@
25#include "chat.h" 25#include "chat.h"
26 26
27#include "messenger.h" 27#include "messenger.h"
28#include "picker.h"
28#include "../application.h" 29#include "../application.h"
29 30
30static void 31static void
@@ -67,7 +68,7 @@ handle_send_text_buffer_changed(GtkTextBuffer *buffer,
67 68
68 gtk_image_set_from_icon_name( 69 gtk_image_set_from_icon_name(
69 symbol, 70 symbol,
70 0 < g_utf8_strlen(text, 1)? 71 0 < strlen(text)?
71 "mail-send-symbolic" : 72 "mail-send-symbolic" :
72 "audio-input-microphone-symbolic", 73 "audio-input-microphone-symbolic",
73 GTK_ICON_SIZE_BUTTON 74 GTK_ICON_SIZE_BUTTON
@@ -86,7 +87,7 @@ _send_text_from_view(MESSENGER_Application *app,
86 87
87 const gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE); 88 const gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
88 89
89 if (0 == g_utf8_strlen(text, 1)) 90 if (0 == strlen(text))
90 return FALSE; 91 return FALSE;
91 92
92 struct GNUNET_CHAT_Context *context = g_hash_table_lookup( 93 struct GNUNET_CHAT_Context *context = g_hash_table_lookup(
@@ -132,6 +133,16 @@ handle_send_text_key_press (GtkWidget *widget,
132 return _send_text_from_view(app, GTK_TEXT_VIEW(widget)); 133 return _send_text_from_view(app, GTK_TEXT_VIEW(widget));
133} 134}
134 135
136static void
137handle_picker_button_click(UNUSED GtkButton *button,
138 gpointer user_data)
139{
140 GtkRevealer *revealer = GTK_REVEALER(user_data);
141 gboolean reveal = !gtk_revealer_get_child_revealed(revealer);
142
143 gtk_revealer_set_reveal_child(revealer, reveal);
144}
145
135UI_CHAT_Handle* 146UI_CHAT_Handle*
136ui_chat_new(MESSENGER_Application *app) 147ui_chat_new(MESSENGER_Application *app)
137{ 148{
@@ -239,12 +250,32 @@ ui_chat_new(MESSENGER_Application *app)
239 handle->send_text_view 250 handle->send_text_view
240 ); 251 );
241 252
253 handle->picker_revealer = GTK_REVEALER(
254 gtk_builder_get_object(handle->builder, "picker_revealer")
255 );
256
257 handle->picker = ui_picker_new(app, handle);
258
259 gtk_container_add(
260 GTK_CONTAINER(handle->picker_revealer),
261 handle->picker->picker_box
262 );
263
264 g_signal_connect(
265 handle->emoji_button,
266 "clicked",
267 G_CALLBACK(handle_picker_button_click),
268 handle->picker_revealer
269 );
270
242 return handle; 271 return handle;
243} 272}
244 273
245void 274void
246ui_chat_delete(UI_CHAT_Handle *handle) 275ui_chat_delete(UI_CHAT_Handle *handle)
247{ 276{
277 ui_picker_delete(handle->picker);
278
248 g_object_unref(handle->builder); 279 g_object_unref(handle->builder);
249 280
250 g_free(handle); 281 g_free(handle);
diff --git a/src/ui/chat.h b/src/ui/chat.h
index 250ac08..77e4553 100644
--- a/src/ui/chat.h
+++ b/src/ui/chat.h
@@ -30,6 +30,7 @@
30#include <libnotify/notify.h> 30#include <libnotify/notify.h>
31 31
32typedef struct MESSENGER_Application MESSENGER_Application; 32typedef struct MESSENGER_Application MESSENGER_Application;
33typedef struct UI_PICKER_Handle UI_PICKER_Handle;
33 34
34typedef struct UI_CHAT_Handle 35typedef struct UI_CHAT_Handle
35{ 36{
@@ -49,6 +50,10 @@ typedef struct UI_CHAT_Handle
49 GtkButton *emoji_button; 50 GtkButton *emoji_button;
50 GtkButton *send_record_button; 51 GtkButton *send_record_button;
51 GtkImage *send_record_symbol; 52 GtkImage *send_record_symbol;
53
54 GtkRevealer *picker_revealer;
55
56 UI_PICKER_Handle *picker;
52} UI_CHAT_Handle; 57} UI_CHAT_Handle;
53 58
54UI_CHAT_Handle* 59UI_CHAT_Handle*
diff --git a/src/ui/messenger.c b/src/ui/messenger.c
index 669ef19..8f463ca 100644
--- a/src/ui/messenger.c
+++ b/src/ui/messenger.c
@@ -150,6 +150,8 @@ handle_main_window_destroy(UNUSED GtkWidget *window,
150{ 150{
151 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 151 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
152 152
153 ui_messenger_cleanup(&(app->ui.messenger));
154
153 application_exit(app, MESSENGER_QUIT); 155 application_exit(app, MESSENGER_QUIT);
154} 156}
155 157
diff --git a/src/ui/picker.c b/src/ui/picker.c
new file mode 100644
index 0000000..f6c89a6
--- /dev/null
+++ b/src/ui/picker.c
@@ -0,0 +1,251 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/*
21 * @author Tobias Frisch
22 * @file ui/picker.c
23 */
24
25#include "picker.h"
26
27#include "../application.h"
28
29#include <emoji.h>
30
31static void
32handle_emoji_button_click(GtkButton *button,
33 gpointer user_data)
34{
35 GtkTextView *text_view = GTK_TEXT_VIEW(user_data);
36 GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(text_view);
37
38 const gchar *label = gtk_button_get_label(button);
39
40 if (label)
41 gtk_text_buffer_insert_at_cursor(text_buffer, label, strlen(label));
42}
43
44static void
45_add_emoji_buttons(GtkFlowBox *flow_box,
46 GtkTextView *text_view,
47 size_t characters_count,
48 const uint32_t *characters)
49{
50 for (size_t i = 0; i < characters_count; i++) {
51 GString *string = g_string_new("");
52 g_string_append_unichar(string, (gunichar) characters[i]);
53
54 GtkButton *emoji_button = GTK_BUTTON(
55 gtk_button_new_with_label(string->str)
56 );
57
58 gtk_button_set_relief(emoji_button, GTK_RELIEF_NONE);
59
60 g_signal_connect(
61 emoji_button,
62 "clicked",
63 G_CALLBACK(handle_emoji_button_click),
64 text_view
65 );
66
67 gtk_flow_box_insert(flow_box, GTK_WIDGET(emoji_button), -1);
68 gtk_widget_show(GTK_WIDGET(emoji_button));
69
70 g_string_free(string, TRUE);
71 }
72}
73
74static void
75handle_search_button_click(UNUSED GtkButton *button,
76 gpointer user_data)
77{
78 UI_PICKER_Handle *handle = (UI_PICKER_Handle*) user_data;
79
80 const gchar* picked = gtk_stack_get_visible_child_name(handle->picker_stack);
81
82 HdySearchBar *search_bar = NULL;
83
84 if (0 == g_strcmp0(picked, "emoji"))
85 search_bar = handle->emoji_search_bar;
86
87 if (search_bar)
88 hdy_search_bar_set_search_mode(
89 search_bar,
90 !hdy_search_bar_get_search_mode(search_bar)
91 );
92}
93
94UI_PICKER_Handle*
95ui_picker_new(UNUSED MESSENGER_Application *app,
96 UI_CHAT_Handle *chat)
97{
98 UI_PICKER_Handle *handle = g_malloc(sizeof(UI_PICKER_Handle));
99
100 handle->builder = gtk_builder_new_from_file(
101 "resources/ui/picker.ui"
102 );
103
104 handle->picker_box = GTK_WIDGET(
105 gtk_builder_get_object(handle->builder, "picker_box")
106 );
107
108 handle->picker_stack = GTK_STACK(
109 gtk_builder_get_object(handle->builder, "picker_stack")
110 );
111
112 handle->emoji_stack = GTK_STACK(
113 gtk_builder_get_object(handle->builder, "emoji_stack")
114 );
115
116 handle->picker_switcher_bar = HDY_VIEW_SWITCHER_BAR(
117 gtk_builder_get_object(handle->builder, "picker_switcher_bar")
118 );
119
120 handle->emoji_switcher_bar = HDY_VIEW_SWITCHER_BAR(
121 gtk_builder_get_object(handle->builder, "emoji_switcher_bar")
122 );
123
124 handle->recent_flow_box = GTK_FLOW_BOX(
125 gtk_builder_get_object(handle->builder, "recent_flow_box")
126 );
127
128 handle->people_flow_box = GTK_FLOW_BOX(
129 gtk_builder_get_object(handle->builder, "people_flow_box")
130 );
131
132 _add_emoji_buttons(
133 handle->people_flow_box,
134 chat->send_text_view,
135 EMOJI_SMILEYS_CHARACTER_COUNT,
136 emoji_smileys_characters
137 );
138
139 handle->nature_flow_box = GTK_FLOW_BOX(
140 gtk_builder_get_object(handle->builder, "nature_flow_box")
141 );
142
143 _add_emoji_buttons(
144 handle->nature_flow_box,
145 chat->send_text_view,
146 EMOJI_ANIMALS_CHARACTER_COUNT,
147 emoji_animals_characters
148 );
149
150 handle->food_flow_box = GTK_FLOW_BOX(
151 gtk_builder_get_object(handle->builder, "food_flow_box")
152 );
153
154 _add_emoji_buttons(
155 handle->food_flow_box,
156 chat->send_text_view,
157 EMOJI_FOOD_CHARACTER_COUNT,
158 emoji_food_characters
159 );
160
161 handle->activities_flow_box = GTK_FLOW_BOX(
162 gtk_builder_get_object(handle->builder, "activities_flow_box")
163 );
164
165 _add_emoji_buttons(
166 handle->activities_flow_box,
167 chat->send_text_view,
168 EMOJI_ACTIVITIES_CHARACTER_COUNT,
169 emoji_activities_characters
170 );
171
172 handle->travel_flow_box = GTK_FLOW_BOX(
173 gtk_builder_get_object(handle->builder, "travel_flow_box")
174 );
175
176 _add_emoji_buttons(
177 handle->travel_flow_box,
178 chat->send_text_view,
179 EMOJI_TRAVEL_CHARACTER_COUNT,
180 emoji_travel_characters
181 );
182
183 handle->objects_flow_box = GTK_FLOW_BOX(
184 gtk_builder_get_object(handle->builder, "objects_flow_box")
185 );
186
187 _add_emoji_buttons(
188 handle->objects_flow_box,
189 chat->send_text_view,
190 EMOJI_OBJECTS_CHARACTER_COUNT,
191 emoji_objects_characters
192 );
193
194 handle->symbols_flow_box = GTK_FLOW_BOX(
195 gtk_builder_get_object(handle->builder, "symbols_flow_box")
196 );
197
198 _add_emoji_buttons(
199 handle->symbols_flow_box,
200 chat->send_text_view,
201 EMOJI_SYMBOLS_CHARACTER_COUNT,
202 emoji_symbols_characters
203 );
204
205 handle->flags_flow_box = GTK_FLOW_BOX(
206 gtk_builder_get_object(handle->builder, "flags_flow_box")
207 );
208
209 _add_emoji_buttons(
210 handle->flags_flow_box,
211 chat->send_text_view,
212 EMOJI_FLAGS_CHARACTER_COUNT,
213 emoji_flags_characters
214 );
215
216 handle->emoji_search_bar = HDY_SEARCH_BAR(
217 gtk_builder_get_object(handle->builder, "emoji_search_bar")
218 );
219
220 handle->emoji_search_entry = GTK_SEARCH_ENTRY(
221 gtk_builder_get_object(handle->builder, "emoji_search_entry")
222 );
223
224 handle->search_button = GTK_BUTTON(
225 gtk_builder_get_object(handle->builder, "search_button")
226 );
227
228 g_signal_connect(
229 handle->search_button,
230 "clicked",
231 G_CALLBACK(handle_search_button_click),
232 handle
233 );
234
235 handle->settings_button = GTK_BUTTON(
236 gtk_builder_get_object(handle->builder, "settings_button")
237 );
238
239 return handle;
240}
241
242void
243ui_picker_delete(UI_PICKER_Handle *handle)
244{
245 hdy_view_switcher_bar_set_stack(handle->picker_switcher_bar, NULL);
246 hdy_view_switcher_bar_set_stack(handle->emoji_switcher_bar, NULL);
247
248 g_object_unref(handle->builder);
249
250 g_free(handle);
251}
diff --git a/src/ui/picker.h b/src/ui/picker.h
new file mode 100644
index 0000000..99c7fa2
--- /dev/null
+++ b/src/ui/picker.h
@@ -0,0 +1,65 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/*
21 * @author Tobias Frisch
22 * @file ui/picker.h
23 */
24
25#ifndef UI_PICKER_H_
26#define UI_PICKER_H_
27
28#include "chat.h"
29
30typedef struct UI_PICKER_Handle
31{
32 GtkBuilder *builder;
33 GtkWidget *picker_box;
34
35 GtkStack *picker_stack;
36 GtkStack *emoji_stack;
37
38 HdyViewSwitcherBar *picker_switcher_bar;
39 HdyViewSwitcherBar *emoji_switcher_bar;
40
41 GtkFlowBox *recent_flow_box;
42 GtkFlowBox *people_flow_box;
43 GtkFlowBox *nature_flow_box;
44 GtkFlowBox *food_flow_box;
45 GtkFlowBox *activities_flow_box;
46 GtkFlowBox *travel_flow_box;
47 GtkFlowBox *objects_flow_box;
48 GtkFlowBox *symbols_flow_box;
49 GtkFlowBox *flags_flow_box;
50
51 HdySearchBar *emoji_search_bar;
52 GtkSearchEntry *emoji_search_entry;
53
54 GtkButton *search_button;
55 GtkButton *settings_button;
56} UI_PICKER_Handle;
57
58UI_PICKER_Handle*
59ui_picker_new(MESSENGER_Application *app,
60 UI_CHAT_Handle *chat);
61
62void
63ui_picker_delete(UI_PICKER_Handle *handle);
64
65#endif /* UI_PICKER_H_ */
diff --git a/submodules/gnome-characters b/submodules/gnome-characters
new file mode 160000
Subproject f732b513cd5b8882d4176ed6ada1a78aba61a63