diff options
author | TheJackiMonster <thejackimonster@gmail.com> | 2021-12-21 18:59:39 +0100 |
---|---|---|
committer | TheJackiMonster <thejackimonster@gmail.com> | 2021-12-21 18:59:39 +0100 |
commit | bd545ea846e668112e5a54b702acc9c9f9231aea (patch) | |
tree | 1b0c6ccadd11ac4e98ef597fc36e8a640c834a43 | |
parent | d8a0d99da00d29ae50a0a8831d1d396769ed94f6 (diff) | |
download | messenger-gtk-bd545ea846e668112e5a54b702acc9c9f9231aea.tar.gz messenger-gtk-bd545ea846e668112e5a54b702acc9c9f9231aea.zip |
Implemented preview for sending files and added ui for message content
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r-- | resources/css/style.css | 4 | ||||
-rw-r--r-- | resources/ui/message-sent.ui | 59 | ||||
-rw-r--r-- | resources/ui/message-status.ui | 106 | ||||
-rw-r--r-- | resources/ui/message.ui | 58 | ||||
-rw-r--r-- | resources/ui/message_content.ui | 187 | ||||
-rw-r--r-- | resources/ui/send_file.ui | 1 | ||||
-rw-r--r-- | src/event.c | 19 | ||||
-rw-r--r-- | src/ui/chat.c | 15 | ||||
-rw-r--r-- | src/ui/chat.h | 2 | ||||
-rw-r--r-- | src/ui/message.c | 65 | ||||
-rw-r--r-- | src/ui/message.h | 17 | ||||
-rw-r--r-- | src/ui/new_contact.c | 2 | ||||
-rw-r--r-- | src/ui/send_file.c | 176 | ||||
-rw-r--r-- | src/ui/send_file.h | 6 |
14 files changed, 512 insertions, 205 deletions
diff --git a/resources/css/style.css b/resources/css/style.css index afda9fe..084a639 100644 --- a/resources/css/style.css +++ b/resources/css/style.css | |||
@@ -61,6 +61,10 @@ | |||
61 | padding: 2px 4px; | 61 | padding: 2px 4px; |
62 | } | 62 | } |
63 | 63 | ||
64 | .timestamp-label { | ||
65 | font-size: x-small; | ||
66 | } | ||
67 | |||
64 | .picker-switcher-box { | 68 | .picker-switcher-box { |
65 | padding: 0px 8px; | 69 | padding: 0px 8px; |
66 | } | 70 | } |
diff --git a/resources/ui/message-sent.ui b/resources/ui/message-sent.ui index 25ac52c..6e939ea 100644 --- a/resources/ui/message-sent.ui +++ b/resources/ui/message-sent.ui | |||
@@ -50,68 +50,13 @@ Author: Tobias Frisch | |||
50 | <property name="label-xalign">0</property> | 50 | <property name="label-xalign">0</property> |
51 | <property name="shadow-type">none</property> | 51 | <property name="shadow-type">none</property> |
52 | <child> | 52 | <child> |
53 | <object class="GtkBox"> | 53 | <object class="GtkBox" id="content_box"> |
54 | <property name="visible">True</property> | 54 | <property name="visible">True</property> |
55 | <property name="can-focus">False</property> | 55 | <property name="can-focus">False</property> |
56 | <property name="orientation">vertical</property> | 56 | <property name="orientation">vertical</property> |
57 | <property name="spacing">4</property> | ||
58 | <child> | 57 | <child> |
59 | <object class="GtkLabel" id="text_label"> | 58 | <placeholder/> |
60 | <property name="visible">True</property> | ||
61 | <property name="can-focus">False</property> | ||
62 | <property name="wrap">True</property> | ||
63 | <property name="max-width-chars">64</property> | ||
64 | <property name="xalign">0</property> | ||
65 | </object> | ||
66 | <packing> | ||
67 | <property name="expand">True</property> | ||
68 | <property name="fill">True</property> | ||
69 | <property name="position">0</property> | ||
70 | </packing> | ||
71 | </child> | 59 | </child> |
72 | <child> | ||
73 | <object class="GtkBox"> | ||
74 | <property name="visible">True</property> | ||
75 | <property name="can-focus">False</property> | ||
76 | <property name="spacing">4</property> | ||
77 | <child> | ||
78 | <object class="GtkImage" id="read_receipt_image"> | ||
79 | <property name="visible">True</property> | ||
80 | <property name="can-focus">False</property> | ||
81 | <property name="icon-name">emblem-default-symbolic</property> | ||
82 | </object> | ||
83 | <packing> | ||
84 | <property name="expand">False</property> | ||
85 | <property name="fill">True</property> | ||
86 | <property name="pack-type">end</property> | ||
87 | <property name="position">0</property> | ||
88 | </packing> | ||
89 | </child> | ||
90 | <child> | ||
91 | <object class="GtkLabel" id="timestamp_label"> | ||
92 | <property name="visible">True</property> | ||
93 | <property name="can-focus">False</property> | ||
94 | <attributes> | ||
95 | <attribute name="weight" value="light"/> | ||
96 | </attributes> | ||
97 | </object> | ||
98 | <packing> | ||
99 | <property name="expand">False</property> | ||
100 | <property name="fill">True</property> | ||
101 | <property name="pack-type">end</property> | ||
102 | <property name="position">1</property> | ||
103 | </packing> | ||
104 | </child> | ||
105 | </object> | ||
106 | <packing> | ||
107 | <property name="expand">False</property> | ||
108 | <property name="fill">True</property> | ||
109 | <property name="position">1</property> | ||
110 | </packing> | ||
111 | </child> | ||
112 | <style> | ||
113 | <class name="message-content"/> | ||
114 | </style> | ||
115 | </object> | 60 | </object> |
116 | </child> | 61 | </child> |
117 | <child type="label"> | 62 | <child type="label"> |
diff --git a/resources/ui/message-status.ui b/resources/ui/message-status.ui index fb2057e..8536162 100644 --- a/resources/ui/message-status.ui +++ b/resources/ui/message-status.ui | |||
@@ -39,15 +39,23 @@ Author: Tobias Frisch | |||
39 | <property name="can-focus">False</property> | 39 | <property name="can-focus">False</property> |
40 | <property name="spacing">8</property> | 40 | <property name="spacing">8</property> |
41 | <child> | 41 | <child> |
42 | <object class="GtkButton" id="deny_button"> | 42 | <object class="GtkRevealer" id="deny_revealer"> |
43 | <property name="can-focus">True</property> | 43 | <property name="visible">True</property> |
44 | <property name="receives-default">True</property> | 44 | <property name="can-focus">False</property> |
45 | <property name="relief">none</property> | 45 | <property name="transition-type">slide-left</property> |
46 | <property name="reveal-child">True</property> | ||
46 | <child> | 47 | <child> |
47 | <object class="GtkImage"> | 48 | <object class="GtkButton" id="deny_button"> |
48 | <property name="visible">True</property> | 49 | <property name="can-focus">True</property> |
49 | <property name="can-focus">False</property> | 50 | <property name="receives-default">True</property> |
50 | <property name="icon-name">edit-delete-symbolic</property> | 51 | <property name="relief">none</property> |
52 | <child> | ||
53 | <object class="GtkImage"> | ||
54 | <property name="visible">True</property> | ||
55 | <property name="can-focus">False</property> | ||
56 | <property name="icon-name">edit-delete-symbolic</property> | ||
57 | </object> | ||
58 | </child> | ||
51 | </object> | 59 | </object> |
52 | </child> | 60 | </child> |
53 | </object> | 61 | </object> |
@@ -58,65 +66,12 @@ Author: Tobias Frisch | |||
58 | </packing> | 66 | </packing> |
59 | </child> | 67 | </child> |
60 | <child> | 68 | <child> |
61 | <object class="GtkBox"> | 69 | <object class="GtkBox" id="content_box"> |
62 | <property name="visible">True</property> | 70 | <property name="visible">True</property> |
63 | <property name="can-focus">False</property> | 71 | <property name="can-focus">False</property> |
64 | <property name="orientation">vertical</property> | 72 | <property name="orientation">vertical</property> |
65 | <child> | 73 | <child> |
66 | <object class="GtkLabel" id="text_label"> | 74 | <placeholder/> |
67 | <property name="visible">True</property> | ||
68 | <property name="can-focus">False</property> | ||
69 | <property name="justify">center</property> | ||
70 | <property name="wrap">True</property> | ||
71 | <property name="xalign">0.5</property> | ||
72 | </object> | ||
73 | <packing> | ||
74 | <property name="expand">True</property> | ||
75 | <property name="fill">True</property> | ||
76 | <property name="position">0</property> | ||
77 | </packing> | ||
78 | </child> | ||
79 | <child> | ||
80 | <object class="GtkBox"> | ||
81 | <property name="visible">True</property> | ||
82 | <property name="can-focus">False</property> | ||
83 | <property name="spacing">4</property> | ||
84 | <child> | ||
85 | <object class="GtkImage" id="read_receipt_image"> | ||
86 | <property name="can-focus">False</property> | ||
87 | <property name="xalign">1</property> | ||
88 | <property name="icon-name">emblem-default-symbolic</property> | ||
89 | </object> | ||
90 | <packing> | ||
91 | <property name="expand">False</property> | ||
92 | <property name="fill">True</property> | ||
93 | <property name="pack-type">end</property> | ||
94 | <property name="position">0</property> | ||
95 | </packing> | ||
96 | </child> | ||
97 | <child> | ||
98 | <object class="GtkLabel" id="timestamp_label"> | ||
99 | <property name="can-focus">False</property> | ||
100 | <property name="justify">right</property> | ||
101 | <property name="xalign">1</property> | ||
102 | <attributes> | ||
103 | <attribute name="weight" value="light"/> | ||
104 | </attributes> | ||
105 | </object> | ||
106 | <packing> | ||
107 | <property name="expand">False</property> | ||
108 | <property name="fill">True</property> | ||
109 | <property name="pack-type">end</property> | ||
110 | <property name="position">1</property> | ||
111 | </packing> | ||
112 | </child> | ||
113 | </object> | ||
114 | <packing> | ||
115 | <property name="expand">False</property> | ||
116 | <property name="fill">True</property> | ||
117 | <property name="pack-type">end</property> | ||
118 | <property name="position">1</property> | ||
119 | </packing> | ||
120 | </child> | 75 | </child> |
121 | </object> | 76 | </object> |
122 | <packing> | 77 | <packing> |
@@ -126,22 +81,29 @@ Author: Tobias Frisch | |||
126 | </packing> | 81 | </packing> |
127 | </child> | 82 | </child> |
128 | <child> | 83 | <child> |
129 | <object class="GtkButton" id="accept_button"> | 84 | <object class="GtkRevealer" id="accept_revealer"> |
130 | <property name="can-focus">True</property> | 85 | <property name="visible">True</property> |
131 | <property name="receives-default">True</property> | 86 | <property name="can-focus">False</property> |
132 | <property name="relief">none</property> | 87 | <property name="transition-type">slide-right</property> |
88 | <property name="reveal-child">True</property> | ||
133 | <child> | 89 | <child> |
134 | <object class="GtkImage"> | 90 | <object class="GtkButton" id="accept_button"> |
135 | <property name="visible">True</property> | 91 | <property name="can-focus">True</property> |
136 | <property name="can-focus">False</property> | 92 | <property name="receives-default">True</property> |
137 | <property name="icon-name">emblem-ok-symbolic</property> | 93 | <property name="relief">none</property> |
94 | <child> | ||
95 | <object class="GtkImage"> | ||
96 | <property name="visible">True</property> | ||
97 | <property name="can-focus">False</property> | ||
98 | <property name="icon-name">emblem-ok-symbolic</property> | ||
99 | </object> | ||
100 | </child> | ||
138 | </object> | 101 | </object> |
139 | </child> | 102 | </child> |
140 | </object> | 103 | </object> |
141 | <packing> | 104 | <packing> |
142 | <property name="expand">False</property> | 105 | <property name="expand">False</property> |
143 | <property name="fill">True</property> | 106 | <property name="fill">True</property> |
144 | <property name="pack-type">end</property> | ||
145 | <property name="position">2</property> | 107 | <property name="position">2</property> |
146 | </packing> | 108 | </packing> |
147 | </child> | 109 | </child> |
diff --git a/resources/ui/message.ui b/resources/ui/message.ui index 42bde4d..9e501c8 100644 --- a/resources/ui/message.ui +++ b/resources/ui/message.ui | |||
@@ -49,67 +49,13 @@ Author: Tobias Frisch | |||
49 | <property name="label-xalign">0</property> | 49 | <property name="label-xalign">0</property> |
50 | <property name="shadow-type">none</property> | 50 | <property name="shadow-type">none</property> |
51 | <child> | 51 | <child> |
52 | <object class="GtkBox"> | 52 | <object class="GtkBox" id="content_box"> |
53 | <property name="visible">True</property> | 53 | <property name="visible">True</property> |
54 | <property name="can-focus">False</property> | 54 | <property name="can-focus">False</property> |
55 | <property name="orientation">vertical</property> | 55 | <property name="orientation">vertical</property> |
56 | <property name="spacing">4</property> | ||
57 | <child> | 56 | <child> |
58 | <object class="GtkLabel" id="text_label"> | 57 | <placeholder/> |
59 | <property name="visible">True</property> | ||
60 | <property name="can-focus">False</property> | ||
61 | <property name="wrap">True</property> | ||
62 | <property name="max-width-chars">64</property> | ||
63 | <property name="xalign">0</property> | ||
64 | </object> | ||
65 | <packing> | ||
66 | <property name="expand">True</property> | ||
67 | <property name="fill">True</property> | ||
68 | <property name="position">0</property> | ||
69 | </packing> | ||
70 | </child> | 58 | </child> |
71 | <child> | ||
72 | <object class="GtkBox"> | ||
73 | <property name="visible">True</property> | ||
74 | <property name="can-focus">False</property> | ||
75 | <property name="spacing">4</property> | ||
76 | <child> | ||
77 | <object class="GtkImage" id="read_receipt_image"> | ||
78 | <property name="can-focus">False</property> | ||
79 | <property name="icon-name">emblem-default-symbolic</property> | ||
80 | </object> | ||
81 | <packing> | ||
82 | <property name="expand">False</property> | ||
83 | <property name="fill">True</property> | ||
84 | <property name="pack-type">end</property> | ||
85 | <property name="position">0</property> | ||
86 | </packing> | ||
87 | </child> | ||
88 | <child> | ||
89 | <object class="GtkLabel" id="timestamp_label"> | ||
90 | <property name="visible">True</property> | ||
91 | <property name="can-focus">False</property> | ||
92 | <attributes> | ||
93 | <attribute name="weight" value="light"/> | ||
94 | </attributes> | ||
95 | </object> | ||
96 | <packing> | ||
97 | <property name="expand">False</property> | ||
98 | <property name="fill">True</property> | ||
99 | <property name="pack-type">end</property> | ||
100 | <property name="position">1</property> | ||
101 | </packing> | ||
102 | </child> | ||
103 | </object> | ||
104 | <packing> | ||
105 | <property name="expand">False</property> | ||
106 | <property name="fill">True</property> | ||
107 | <property name="position">1</property> | ||
108 | </packing> | ||
109 | </child> | ||
110 | <style> | ||
111 | <class name="message-content"/> | ||
112 | </style> | ||
113 | </object> | 59 | </object> |
114 | </child> | 60 | </child> |
115 | <child type="label"> | 61 | <child type="label"> |
diff --git a/resources/ui/message_content.ui b/resources/ui/message_content.ui new file mode 100644 index 0000000..bca5165 --- /dev/null +++ b/resources/ui/message_content.ui | |||
@@ -0,0 +1,187 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <!-- Generated with glade 3.38.2 | ||
3 | |||
4 | Copyright (C) 2021 GNUnet e.V. | ||
5 | |||
6 | GNUnet is free software: you can redistribute it and/or modify it | ||
7 | under the terms of the GNU Affero General Public License as published | ||
8 | by the Free Software Foundation, either version 3 of the License, | ||
9 | or (at your option) any later version. | ||
10 | |||
11 | GNUnet is distributed in the hope that it will be useful, but | ||
12 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | Affero General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU Affero General Public License | ||
17 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | |||
19 | SPDX-License-Identifier: AGPL3.0-or-later | ||
20 | Author: Tobias Frisch | ||
21 | |||
22 | --> | ||
23 | <interface> | ||
24 | <requires lib="gtk+" version="3.24"/> | ||
25 | <object class="GtkBox" id="message_content_box"> | ||
26 | <property name="visible">True</property> | ||
27 | <property name="can-focus">False</property> | ||
28 | <property name="orientation">vertical</property> | ||
29 | <property name="spacing">4</property> | ||
30 | <child> | ||
31 | <object class="GtkBox"> | ||
32 | <property name="visible">True</property> | ||
33 | <property name="can-focus">False</property> | ||
34 | <property name="spacing">4</property> | ||
35 | <child> | ||
36 | <object class="GtkImage" id="read_receipt_image"> | ||
37 | <property name="can-focus">False</property> | ||
38 | <property name="icon-name">emblem-default-symbolic</property> | ||
39 | </object> | ||
40 | <packing> | ||
41 | <property name="expand">False</property> | ||
42 | <property name="fill">True</property> | ||
43 | <property name="pack-type">end</property> | ||
44 | <property name="position">0</property> | ||
45 | </packing> | ||
46 | </child> | ||
47 | <child> | ||
48 | <object class="GtkLabel" id="timestamp_label"> | ||
49 | <property name="visible">True</property> | ||
50 | <property name="can-focus">False</property> | ||
51 | <attributes> | ||
52 | <attribute name="weight" value="ultralight"/> | ||
53 | </attributes> | ||
54 | <style> | ||
55 | <class name="timestamp-label"/> | ||
56 | </style> | ||
57 | </object> | ||
58 | <packing> | ||
59 | <property name="expand">False</property> | ||
60 | <property name="fill">True</property> | ||
61 | <property name="pack-type">end</property> | ||
62 | <property name="position">1</property> | ||
63 | </packing> | ||
64 | </child> | ||
65 | </object> | ||
66 | <packing> | ||
67 | <property name="expand">False</property> | ||
68 | <property name="fill">True</property> | ||
69 | <property name="pack-type">end</property> | ||
70 | <property name="position">0</property> | ||
71 | </packing> | ||
72 | </child> | ||
73 | <child> | ||
74 | <object class="GtkStack"> | ||
75 | <property name="visible">True</property> | ||
76 | <property name="can-focus">False</property> | ||
77 | <child> | ||
78 | <object class="GtkLabel" id="text_label"> | ||
79 | <property name="visible">True</property> | ||
80 | <property name="can-focus">False</property> | ||
81 | <property name="wrap">True</property> | ||
82 | <property name="max-width-chars">64</property> | ||
83 | <property name="xalign">0</property> | ||
84 | </object> | ||
85 | <packing> | ||
86 | <property name="name">text_page</property> | ||
87 | </packing> | ||
88 | </child> | ||
89 | <child> | ||
90 | <object class="GtkRevealer" id="file_revealer"> | ||
91 | <property name="visible">True</property> | ||
92 | <property name="can-focus">False</property> | ||
93 | <property name="transition-type">none</property> | ||
94 | <child> | ||
95 | <object class="GtkBox"> | ||
96 | <property name="visible">True</property> | ||
97 | <property name="can-focus">False</property> | ||
98 | <property name="spacing">4</property> | ||
99 | <child> | ||
100 | <object class="GtkBox"> | ||
101 | <property name="visible">True</property> | ||
102 | <property name="can-focus">False</property> | ||
103 | <property name="valign">center</property> | ||
104 | <property name="orientation">vertical</property> | ||
105 | <property name="spacing">4</property> | ||
106 | <child> | ||
107 | <object class="GtkLabel" id="filename_label"> | ||
108 | <property name="visible">True</property> | ||
109 | <property name="can-focus">False</property> | ||
110 | </object> | ||
111 | <packing> | ||
112 | <property name="expand">False</property> | ||
113 | <property name="fill">True</property> | ||
114 | <property name="position">0</property> | ||
115 | </packing> | ||
116 | </child> | ||
117 | <child> | ||
118 | <object class="GtkProgressBar"> | ||
119 | <property name="visible">True</property> | ||
120 | <property name="can-focus">False</property> | ||
121 | </object> | ||
122 | <packing> | ||
123 | <property name="expand">False</property> | ||
124 | <property name="fill">True</property> | ||
125 | <property name="position">1</property> | ||
126 | </packing> | ||
127 | </child> | ||
128 | </object> | ||
129 | <packing> | ||
130 | <property name="expand">True</property> | ||
131 | <property name="fill">True</property> | ||
132 | <property name="position">0</property> | ||
133 | </packing> | ||
134 | </child> | ||
135 | <child> | ||
136 | <object class="GtkButton" id="file_button"> | ||
137 | <property name="visible">True</property> | ||
138 | <property name="can-focus">True</property> | ||
139 | <property name="receives-default">True</property> | ||
140 | <property name="halign">center</property> | ||
141 | <property name="valign">center</property> | ||
142 | <property name="relief">none</property> | ||
143 | <child> | ||
144 | <object class="GtkImage"> | ||
145 | <property name="visible">True</property> | ||
146 | <property name="can-focus">False</property> | ||
147 | <property name="icon-name">folder-download-symbolic</property> | ||
148 | </object> | ||
149 | </child> | ||
150 | </object> | ||
151 | <packing> | ||
152 | <property name="expand">False</property> | ||
153 | <property name="fill">True</property> | ||
154 | <property name="pack-type">end</property> | ||
155 | <property name="position">1</property> | ||
156 | </packing> | ||
157 | </child> | ||
158 | </object> | ||
159 | </child> | ||
160 | </object> | ||
161 | <packing> | ||
162 | <property name="name">file_page</property> | ||
163 | <property name="position">1</property> | ||
164 | </packing> | ||
165 | </child> | ||
166 | <child> | ||
167 | <object class="GtkDrawingArea" id="preview_drawing_area"> | ||
168 | <property name="visible">True</property> | ||
169 | <property name="can-focus">False</property> | ||
170 | </object> | ||
171 | <packing> | ||
172 | <property name="name">preview_page</property> | ||
173 | <property name="position">2</property> | ||
174 | </packing> | ||
175 | </child> | ||
176 | </object> | ||
177 | <packing> | ||
178 | <property name="expand">True</property> | ||
179 | <property name="fill">True</property> | ||
180 | <property name="position">1</property> | ||
181 | </packing> | ||
182 | </child> | ||
183 | <style> | ||
184 | <class name="message-content"/> | ||
185 | </style> | ||
186 | </object> | ||
187 | </interface> | ||
diff --git a/resources/ui/send_file.ui b/resources/ui/send_file.ui index 38bd5e8..5603aea 100644 --- a/resources/ui/send_file.ui +++ b/resources/ui/send_file.ui | |||
@@ -78,6 +78,7 @@ Author: Tobias Frisch | |||
78 | <property name="spacing">4</property> | 78 | <property name="spacing">4</property> |
79 | <child> | 79 | <child> |
80 | <object class="GtkDrawingArea" id="file_drawing_area"> | 80 | <object class="GtkDrawingArea" id="file_drawing_area"> |
81 | <property name="width-request">250</property> | ||
81 | <property name="height-request">250</property> | 82 | <property name="height-request">250</property> |
82 | <property name="visible">True</property> | 83 | <property name="visible">True</property> |
83 | <property name="can-focus">False</property> | 84 | <property name="can-focus">False</property> |
diff --git a/src/event.c b/src/event.c index c3e4ac6..2280785 100644 --- a/src/event.c +++ b/src/event.c | |||
@@ -190,7 +190,10 @@ event_joining_contact(MESSENGER_Application *app, | |||
190 | 190 | ||
191 | ui_chat_entry_update(handle, app, context); | 191 | ui_chat_entry_update(handle, app, context); |
192 | 192 | ||
193 | UI_MESSAGE_Handle *message = ui_message_new(UI_MESSAGE_STATUS); | 193 | UI_MESSAGE_Handle *message = ui_message_new( |
194 | UI_MESSAGE_STATUS, | ||
195 | UI_MESSAGE_CONTENT_TEXT | ||
196 | ); | ||
194 | 197 | ||
195 | struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( | 198 | struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( |
196 | msg | 199 | msg |
@@ -209,7 +212,7 @@ event_joining_contact(MESSENGER_Application *app, | |||
209 | message->message_box | 212 | message->message_box |
210 | ); | 213 | ); |
211 | 214 | ||
212 | ui_message_delete(message); | 215 | handle->chat->messages = g_list_append(handle->chat->messages, message); |
213 | } | 216 | } |
214 | 217 | ||
215 | void | 218 | void |
@@ -259,7 +262,10 @@ event_invitation(UNUSED MESSENGER_Application *app, | |||
259 | if (!invitation) | 262 | if (!invitation) |
260 | return; | 263 | return; |
261 | 264 | ||
262 | UI_MESSAGE_Handle *message = ui_message_new(UI_MESSAGE_STATUS); | 265 | UI_MESSAGE_Handle *message = ui_message_new( |
266 | UI_MESSAGE_STATUS, | ||
267 | UI_MESSAGE_CONTENT_TEXT | ||
268 | ); | ||
263 | 269 | ||
264 | const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( | 270 | const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( |
265 | msg | 271 | msg |
@@ -285,7 +291,7 @@ event_invitation(UNUSED MESSENGER_Application *app, | |||
285 | message->message_box | 291 | message->message_box |
286 | ); | 292 | ); |
287 | 293 | ||
288 | ui_message_delete(message); | 294 | handle->chat->messages = g_list_append(handle->chat->messages, message); |
289 | } | 295 | } |
290 | 296 | ||
291 | void | 297 | void |
@@ -301,7 +307,8 @@ event_receive_message(UNUSED MESSENGER_Application *app, | |||
301 | const int sent = GNUNET_CHAT_message_is_sent(msg); | 307 | const int sent = GNUNET_CHAT_message_is_sent(msg); |
302 | 308 | ||
303 | UI_MESSAGE_Handle *message = ui_message_new( | 309 | UI_MESSAGE_Handle *message = ui_message_new( |
304 | GNUNET_YES == sent? UI_MESSAGE_SENT : UI_MESSAGE_DEFAULT | 310 | GNUNET_YES == sent? UI_MESSAGE_SENT : UI_MESSAGE_DEFAULT, |
311 | UI_MESSAGE_CONTENT_TEXT | ||
305 | ); | 312 | ); |
306 | 313 | ||
307 | const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( | 314 | const struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( |
@@ -329,7 +336,7 @@ event_receive_message(UNUSED MESSENGER_Application *app, | |||
329 | message->message_box | 336 | message->message_box |
330 | ); | 337 | ); |
331 | 338 | ||
332 | ui_message_delete(message); | 339 | handle->chat->messages = g_list_append(handle->chat->messages, message); |
333 | 340 | ||
334 | gtk_label_set_text(handle->text_label, text? text : ""); | 341 | gtk_label_set_text(handle->text_label, text? text : ""); |
335 | gtk_label_set_text(handle->timestamp_label, time? time : ""); | 342 | gtk_label_set_text(handle->timestamp_label, time? time : ""); |
diff --git a/src/ui/chat.c b/src/ui/chat.c index a8547ba..42ccb9e 100644 --- a/src/ui/chat.c +++ b/src/ui/chat.c | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <gdk/gdkkeysyms.h> | 27 | #include <gdk/gdkkeysyms.h> |
28 | 28 | ||
29 | #include "message.h" | ||
29 | #include "messenger.h" | 30 | #include "messenger.h" |
30 | #include "picker.h" | 31 | #include "picker.h" |
31 | #include "profile_entry.h" | 32 | #include "profile_entry.h" |
@@ -252,6 +253,8 @@ ui_chat_new(MESSENGER_Application *app) | |||
252 | UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle)); | 253 | UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle)); |
253 | UI_MESSENGER_Handle *messenger = &(app->ui.messenger); | 254 | UI_MESSENGER_Handle *messenger = &(app->ui.messenger); |
254 | 255 | ||
256 | handle->messages = NULL; | ||
257 | |||
255 | handle->builder = gtk_builder_new_from_file( | 258 | handle->builder = gtk_builder_new_from_file( |
256 | "resources/ui/chat.ui" | 259 | "resources/ui/chat.ui" |
257 | ); | 260 | ); |
@@ -552,5 +555,17 @@ ui_chat_delete(UI_CHAT_Handle *handle) | |||
552 | 555 | ||
553 | g_object_unref(handle->builder); | 556 | g_object_unref(handle->builder); |
554 | 557 | ||
558 | GList *list = handle->messages; | ||
559 | |||
560 | while (list) { | ||
561 | if (list->data) | ||
562 | ui_message_delete((UI_MESSAGE_Handle*) list->data); | ||
563 | |||
564 | list = list->next; | ||
565 | } | ||
566 | |||
567 | if (handle->messages) | ||
568 | g_list_free(handle->messages); | ||
569 | |||
555 | g_free(handle); | 570 | g_free(handle); |
556 | } | 571 | } |
diff --git a/src/ui/chat.h b/src/ui/chat.h index ae0880e..f065f61 100644 --- a/src/ui/chat.h +++ b/src/ui/chat.h | |||
@@ -36,6 +36,8 @@ typedef struct UI_PICKER_Handle UI_PICKER_Handle; | |||
36 | 36 | ||
37 | typedef struct UI_CHAT_Handle | 37 | typedef struct UI_CHAT_Handle |
38 | { | 38 | { |
39 | GList *messages; | ||
40 | |||
39 | GtkBuilder *builder; | 41 | GtkBuilder *builder; |
40 | GtkWidget *chat_box; | 42 | GtkWidget *chat_box; |
41 | 43 | ||
diff --git a/src/ui/message.c b/src/ui/message.c index cacf666..4c89edb 100644 --- a/src/ui/message.c +++ b/src/ui/message.c | |||
@@ -27,7 +27,8 @@ | |||
27 | #include "../application.h" | 27 | #include "../application.h" |
28 | 28 | ||
29 | UI_MESSAGE_Handle* | 29 | UI_MESSAGE_Handle* |
30 | ui_message_new(UI_MESSAGE_Type type) | 30 | ui_message_new(UI_MESSAGE_Type type, |
31 | UI_MESSAGE_ContentType content_type) | ||
31 | { | 32 | { |
32 | UI_MESSAGE_Handle* handle = g_malloc(sizeof(UI_MESSAGE_Handle)); | 33 | UI_MESSAGE_Handle* handle = g_malloc(sizeof(UI_MESSAGE_Handle)); |
33 | 34 | ||
@@ -62,12 +63,16 @@ ui_message_new(UI_MESSAGE_Type type) | |||
62 | gtk_builder_get_object(handle->builder, "sender_label") | 63 | gtk_builder_get_object(handle->builder, "sender_label") |
63 | ); | 64 | ); |
64 | 65 | ||
65 | handle->text_label = GTK_LABEL( | ||
66 | gtk_builder_get_object(handle->builder, "text_label") | ||
67 | ); | ||
68 | |||
69 | if (UI_MESSAGE_STATUS == handle->type) | 66 | if (UI_MESSAGE_STATUS == handle->type) |
70 | { | 67 | { |
68 | handle->deny_revealer = GTK_REVEALER( | ||
69 | gtk_builder_get_object(handle->builder, "deny_revealer") | ||
70 | ); | ||
71 | |||
72 | handle->accept_revealer = GTK_REVEALER( | ||
73 | gtk_builder_get_object(handle->builder, "accept_revealer") | ||
74 | ); | ||
75 | |||
71 | handle->deny_button = GTK_BUTTON( | 76 | handle->deny_button = GTK_BUTTON( |
72 | gtk_builder_get_object(handle->builder, "deny_button") | 77 | gtk_builder_get_object(handle->builder, "deny_button") |
73 | ); | 78 | ); |
@@ -78,18 +83,64 @@ ui_message_new(UI_MESSAGE_Type type) | |||
78 | } | 83 | } |
79 | else | 84 | else |
80 | { | 85 | { |
86 | handle->deny_revealer = NULL; | ||
87 | handle->accept_revealer = NULL; | ||
88 | |||
81 | handle->deny_button = NULL; | 89 | handle->deny_button = NULL; |
82 | handle->accept_button = NULL; | 90 | handle->accept_button = NULL; |
83 | } | 91 | } |
84 | 92 | ||
93 | GtkContainer *content_box = GTK_CONTAINER( | ||
94 | gtk_builder_get_object(handle->builder, "content_box") | ||
95 | ); | ||
96 | |||
97 | GtkBuilder *builder = gtk_builder_new_from_file( | ||
98 | "resources/ui/message_content.ui" | ||
99 | ); | ||
100 | |||
85 | handle->timestamp_label = GTK_LABEL( | 101 | handle->timestamp_label = GTK_LABEL( |
86 | gtk_builder_get_object(handle->builder, "timestamp_label") | 102 | gtk_builder_get_object(builder, "timestamp_label") |
87 | ); | 103 | ); |
88 | 104 | ||
89 | handle->read_receipt_image = GTK_IMAGE( | 105 | handle->read_receipt_image = GTK_IMAGE( |
90 | gtk_builder_get_object(handle->builder, "read_receipt_image") | 106 | gtk_builder_get_object(builder, "read_receipt_image") |
107 | ); | ||
108 | |||
109 | handle->text_label = GTK_LABEL( | ||
110 | gtk_builder_get_object(builder, "text_label") | ||
111 | ); | ||
112 | |||
113 | handle->file_revealer = GTK_REVEALER( | ||
114 | gtk_builder_get_object(builder, "file_revealer") | ||
91 | ); | 115 | ); |
92 | 116 | ||
117 | handle->preview_drawing_area = GTK_DRAWING_AREA( | ||
118 | gtk_builder_get_object(builder, "preview_drawing_area") | ||
119 | ); | ||
120 | |||
121 | switch (handle->type) | ||
122 | { | ||
123 | case UI_MESSAGE_STATUS: | ||
124 | gtk_widget_set_visible(GTK_WIDGET(handle->timestamp_label), FALSE); | ||
125 | break; | ||
126 | default: | ||
127 | break; | ||
128 | } | ||
129 | |||
130 | switch (content_type) | ||
131 | { | ||
132 | case UI_MESSAGE_CONTENT_FILE: | ||
133 | gtk_revealer_set_reveal_child(handle->file_revealer, TRUE); | ||
134 | break; | ||
135 | default: | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | gtk_container_add(content_box, GTK_WIDGET( | ||
140 | gtk_builder_get_object(builder, "message_content_box") | ||
141 | )); | ||
142 | |||
143 | g_object_unref(builder); | ||
93 | return handle; | 144 | return handle; |
94 | } | 145 | } |
95 | 146 | ||
diff --git a/src/ui/message.h b/src/ui/message.h index a17247c..b380960 100644 --- a/src/ui/message.h +++ b/src/ui/message.h | |||
@@ -39,6 +39,13 @@ typedef enum UI_MESSAGE_Type | |||
39 | UI_MESSAGE_STATUS = 2 | 39 | UI_MESSAGE_STATUS = 2 |
40 | } UI_MESSAGE_Type; | 40 | } UI_MESSAGE_Type; |
41 | 41 | ||
42 | typedef enum UI_MESSAGE_ContentType | ||
43 | { | ||
44 | UI_MESSAGE_CONTENT_TEXT = 0, | ||
45 | UI_MESSAGE_CONTENT_FILE = 1, | ||
46 | UI_MESSAGE_CONTENT_PREVIEW = 2 | ||
47 | } UI_MESSAGE_ContentType; | ||
48 | |||
42 | typedef struct UI_MESSAGE_Handle | 49 | typedef struct UI_MESSAGE_Handle |
43 | { | 50 | { |
44 | UI_MESSAGE_Type type; | 51 | UI_MESSAGE_Type type; |
@@ -49,17 +56,23 @@ typedef struct UI_MESSAGE_Handle | |||
49 | HdyAvatar *sender_avatar; | 56 | HdyAvatar *sender_avatar; |
50 | GtkLabel *sender_label; | 57 | GtkLabel *sender_label; |
51 | 58 | ||
52 | GtkLabel *text_label; | 59 | GtkRevealer *deny_revealer; |
60 | GtkRevealer *accept_revealer; | ||
53 | 61 | ||
54 | GtkButton *deny_button; | 62 | GtkButton *deny_button; |
55 | GtkButton *accept_button; | 63 | GtkButton *accept_button; |
56 | 64 | ||
57 | GtkLabel *timestamp_label; | 65 | GtkLabel *timestamp_label; |
58 | GtkImage *read_receipt_image; | 66 | GtkImage *read_receipt_image; |
67 | |||
68 | GtkLabel *text_label; | ||
69 | GtkRevealer *file_revealer; | ||
70 | GtkDrawingArea *preview_drawing_area; | ||
59 | } UI_MESSAGE_Handle; | 71 | } UI_MESSAGE_Handle; |
60 | 72 | ||
61 | UI_MESSAGE_Handle* | 73 | UI_MESSAGE_Handle* |
62 | ui_message_new(UI_MESSAGE_Type type); | 74 | ui_message_new(UI_MESSAGE_Type type, |
75 | UI_MESSAGE_ContentType content_type); | ||
63 | 76 | ||
64 | void | 77 | void |
65 | ui_message_delete(UI_MESSAGE_Handle *handle); | 78 | ui_message_delete(UI_MESSAGE_Handle *handle); |
diff --git a/src/ui/new_contact.c b/src/ui/new_contact.c index 3acae1a..7e6f9c6 100644 --- a/src/ui/new_contact.c +++ b/src/ui/new_contact.c | |||
@@ -69,7 +69,7 @@ handle_id_drawing_area_draw(GtkWidget* drawing_area, | |||
69 | GdkPixbuf *image = NULL; | 69 | GdkPixbuf *image = NULL; |
70 | 70 | ||
71 | if (!handle->image) | 71 | if (!handle->image) |
72 | goto render_image; | 72 | return FALSE; |
73 | 73 | ||
74 | uint w, h; | 74 | uint w, h; |
75 | zbar_image_get_size(handle->image, &w, &h); | 75 | zbar_image_get_size(handle->image, &w, &h); |
diff --git a/src/ui/send_file.c b/src/ui/send_file.c index cde2c4d..2d3f4a6 100644 --- a/src/ui/send_file.c +++ b/src/ui/send_file.c | |||
@@ -71,6 +71,146 @@ handle_dialog_destroy(UNUSED GtkWidget *window, | |||
71 | ui_send_file_dialog_cleanup((UI_SEND_FILE_Handle*) user_data); | 71 | ui_send_file_dialog_cleanup((UI_SEND_FILE_Handle*) user_data); |
72 | } | 72 | } |
73 | 73 | ||
74 | static int | ||
75 | handle_file_redraw_animation(gpointer user_data) | ||
76 | { | ||
77 | UI_SEND_FILE_Handle *handle = (UI_SEND_FILE_Handle*) user_data; | ||
78 | |||
79 | handle->redraw_animation = 0; | ||
80 | |||
81 | if (handle->file_drawing_area) | ||
82 | gtk_widget_queue_draw(GTK_WIDGET(handle->file_drawing_area)); | ||
83 | |||
84 | return FALSE; | ||
85 | } | ||
86 | |||
87 | static gboolean | ||
88 | handle_file_drawing_area_draw(GtkWidget* drawing_area, | ||
89 | cairo_t* cairo, | ||
90 | gpointer user_data) | ||
91 | { | ||
92 | UI_SEND_FILE_Handle *handle = (UI_SEND_FILE_Handle*) user_data; | ||
93 | |||
94 | GtkStyleContext* context = gtk_widget_get_style_context(drawing_area); | ||
95 | |||
96 | const guint width = gtk_widget_get_allocated_width(drawing_area); | ||
97 | const guint height = gtk_widget_get_allocated_height(drawing_area); | ||
98 | |||
99 | gtk_render_background(context, cairo, 0, 0, width, height); | ||
100 | |||
101 | GdkPixbuf *image = handle->image; | ||
102 | |||
103 | if (!handle->animation) | ||
104 | goto render_image; | ||
105 | |||
106 | if (handle->animation_iter) | ||
107 | gdk_pixbuf_animation_iter_advance(handle->animation_iter, NULL); | ||
108 | else | ||
109 | handle->animation_iter = gdk_pixbuf_animation_get_iter( | ||
110 | handle->animation, NULL | ||
111 | ); | ||
112 | |||
113 | image = gdk_pixbuf_animation_iter_get_pixbuf(handle->animation_iter); | ||
114 | |||
115 | const int delay = gdk_pixbuf_animation_iter_get_delay_time( | ||
116 | handle->animation_iter | ||
117 | ); | ||
118 | |||
119 | handle->redraw_animation = g_timeout_add( | ||
120 | delay, handle_file_redraw_animation, handle | ||
121 | ); | ||
122 | |||
123 | render_image: | ||
124 | if (!image) | ||
125 | return FALSE; | ||
126 | |||
127 | int dwidth = gdk_pixbuf_get_width(image); | ||
128 | int dheight = gdk_pixbuf_get_height(image); | ||
129 | |||
130 | double ratio_width = 1.0 * width / dwidth; | ||
131 | double ratio_height = 1.0 * height / dheight; | ||
132 | |||
133 | const double ratio = ratio_width < ratio_height? ratio_width : ratio_height; | ||
134 | |||
135 | dwidth = (int) (dwidth * ratio); | ||
136 | dheight = (int) (dheight * ratio); | ||
137 | |||
138 | double dx = (width - dwidth) * 0.5; | ||
139 | double dy = (height - dheight) * 0.5; | ||
140 | |||
141 | const int interp_type = (ratio >= 1.0? | ||
142 | GDK_INTERP_NEAREST : | ||
143 | GDK_INTERP_BILINEAR | ||
144 | ); | ||
145 | |||
146 | GdkPixbuf* scaled = gdk_pixbuf_scale_simple( | ||
147 | image, | ||
148 | dwidth, | ||
149 | dheight, | ||
150 | interp_type | ||
151 | ); | ||
152 | |||
153 | gtk_render_icon(context, cairo, scaled, dx, dy); | ||
154 | |||
155 | cairo_fill(cairo); | ||
156 | |||
157 | g_object_unref(scaled); | ||
158 | return FALSE; | ||
159 | } | ||
160 | |||
161 | static void | ||
162 | _clear_file_preview_data(UI_SEND_FILE_Handle *handle) | ||
163 | { | ||
164 | if (handle->image) | ||
165 | { | ||
166 | g_object_unref(handle->image); | ||
167 | handle->image = NULL; | ||
168 | } | ||
169 | |||
170 | if (handle->redraw_animation) | ||
171 | { | ||
172 | g_source_remove(handle->redraw_animation); | ||
173 | handle->redraw_animation = 0; | ||
174 | } | ||
175 | |||
176 | if (handle->animation_iter) | ||
177 | { | ||
178 | g_object_unref(handle->animation_iter); | ||
179 | handle->animation_iter = NULL; | ||
180 | } | ||
181 | |||
182 | if (handle->animation) | ||
183 | { | ||
184 | g_object_unref(handle->animation); | ||
185 | handle->animation = NULL; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | static void | ||
190 | handle_file_chooser_button_file_set(GtkFileChooserButton *file_chooser_button, | ||
191 | gpointer user_data) | ||
192 | { | ||
193 | UI_SEND_FILE_Handle *handle = (UI_SEND_FILE_Handle*) user_data; | ||
194 | |||
195 | _clear_file_preview_data(handle); | ||
196 | |||
197 | char *filename = gtk_file_chooser_get_filename( | ||
198 | GTK_FILE_CHOOSER(file_chooser_button) | ||
199 | ); | ||
200 | |||
201 | if (filename) | ||
202 | { | ||
203 | handle->animation = gdk_pixbuf_animation_new_from_file(filename, NULL); | ||
204 | |||
205 | if (!handle->animation) | ||
206 | handle->image = gdk_pixbuf_new_from_file(filename, NULL); | ||
207 | |||
208 | g_free(filename); | ||
209 | } | ||
210 | |||
211 | gtk_widget_queue_draw(GTK_WIDGET(handle->file_drawing_area)); | ||
212 | } | ||
213 | |||
74 | void | 214 | void |
75 | ui_send_file_dialog_init(MESSENGER_Application *app, | 215 | ui_send_file_dialog_init(MESSENGER_Application *app, |
76 | UI_SEND_FILE_Handle *handle) | 216 | UI_SEND_FILE_Handle *handle) |
@@ -99,6 +239,20 @@ ui_send_file_dialog_init(MESSENGER_Application *app, | |||
99 | gtk_builder_get_object(handle->builder, "file_chooser_button") | 239 | gtk_builder_get_object(handle->builder, "file_chooser_button") |
100 | ); | 240 | ); |
101 | 241 | ||
242 | g_signal_connect( | ||
243 | handle->file_drawing_area, | ||
244 | "draw", | ||
245 | G_CALLBACK(handle_file_drawing_area_draw), | ||
246 | handle | ||
247 | ); | ||
248 | |||
249 | g_signal_connect( | ||
250 | handle->file_chooser_button, | ||
251 | "file-set", | ||
252 | G_CALLBACK(handle_file_chooser_button_file_set), | ||
253 | handle | ||
254 | ); | ||
255 | |||
102 | handle->cancel_button = GTK_BUTTON( | 256 | handle->cancel_button = GTK_BUTTON( |
103 | gtk_builder_get_object(handle->builder, "cancel_button") | 257 | gtk_builder_get_object(handle->builder, "cancel_button") |
104 | ); | 258 | ); |
@@ -127,22 +281,36 @@ ui_send_file_dialog_init(MESSENGER_Application *app, | |||
127 | G_CALLBACK(handle_dialog_destroy), | 281 | G_CALLBACK(handle_dialog_destroy), |
128 | handle | 282 | handle |
129 | ); | 283 | ); |
284 | |||
285 | handle->image = NULL; | ||
286 | handle->animation = NULL; | ||
287 | handle->animation_iter = NULL; | ||
288 | |||
289 | handle->redraw_animation = 0; | ||
130 | } | 290 | } |
131 | 291 | ||
132 | void | 292 | void |
133 | ui_send_file_dialog_update(UI_SEND_FILE_Handle *handle, | 293 | ui_send_file_dialog_update(UI_SEND_FILE_Handle *handle, |
134 | const gchar *filename) | 294 | const gchar *filename) |
135 | { | 295 | { |
136 | if ((!filename) || (!gtk_file_chooser_set_filename( | 296 | if (!handle->file_chooser_button) |
137 | GTK_FILE_CHOOSER(handle->file_chooser_button), | ||
138 | filename))) | ||
139 | return; | 297 | return; |
140 | 298 | ||
141 | // TODO: update preview | 299 | gtk_file_chooser_set_filename( |
300 | GTK_FILE_CHOOSER(handle->file_chooser_button), | ||
301 | filename | ||
302 | ); | ||
303 | |||
304 | handle_file_chooser_button_file_set( | ||
305 | handle->file_chooser_button, | ||
306 | handle | ||
307 | ); | ||
142 | } | 308 | } |
143 | 309 | ||
144 | void | 310 | void |
145 | ui_send_file_dialog_cleanup(UI_SEND_FILE_Handle *handle) | 311 | ui_send_file_dialog_cleanup(UI_SEND_FILE_Handle *handle) |
146 | { | 312 | { |
313 | _clear_file_preview_data(handle); | ||
314 | |||
147 | g_object_unref(handle->builder); | 315 | g_object_unref(handle->builder); |
148 | } | 316 | } |
diff --git a/src/ui/send_file.h b/src/ui/send_file.h index cb58285..1a68681 100644 --- a/src/ui/send_file.h +++ b/src/ui/send_file.h | |||
@@ -39,6 +39,12 @@ typedef struct UI_SEND_FILE_Handle | |||
39 | 39 | ||
40 | GtkButton *cancel_button; | 40 | GtkButton *cancel_button; |
41 | GtkButton *send_button; | 41 | GtkButton *send_button; |
42 | |||
43 | GdkPixbuf *image; | ||
44 | GdkPixbufAnimation *animation; | ||
45 | GdkPixbufAnimationIter *animation_iter; | ||
46 | |||
47 | guint redraw_animation; | ||
42 | } UI_SEND_FILE_Handle; | 48 | } UI_SEND_FILE_Handle; |
43 | 49 | ||
44 | void | 50 | void |