1 /*
2 * Copyright (C) 2019-2021 Alexandros Theodotou <alex at zrythm dot org>
3 *
4 * This file is part of Zrythm
5 *
6 * Zrythm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Zrythm is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU 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 Zrythm. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "gui/widgets/foldable_notebook.h"
21 #include "gui/widgets/main_window.h"
22 #include "utils/gtk.h"
23 #include "utils/ui.h"
24 #include "zrythm_app.h"
25
G_DEFINE_TYPE(FoldableNotebookWidget,foldable_notebook_widget,GTK_TYPE_NOTEBOOK)26 G_DEFINE_TYPE (
27 FoldableNotebookWidget,
28 foldable_notebook_widget,
29 GTK_TYPE_NOTEBOOK)
30
31 static void
32 on_switch_page (
33 GtkNotebook * notebook,
34 GtkWidget * page,
35 guint page_num,
36 FoldableNotebookWidget * self)
37 {
38 int num_pages =
39 gtk_notebook_get_n_pages (notebook);
40 GtkWidget * widget;
41 for (int i = 0; i < num_pages; i++)
42 {
43 /* set the child visible */
44 widget =
45 foldable_notebook_widget_get_widget_at_page (
46 self, i);
47 gtk_widget_set_visible (
48 widget, (guint) i == page_num ? 1 : 0);
49 }
50 }
51
52 /**
53 * Sets the folded space visible or not.
54 */
55 void
foldable_notebook_widget_set_visibility(FoldableNotebookWidget * self,bool new_visibility)56 foldable_notebook_widget_set_visibility (
57 FoldableNotebookWidget * self,
58 bool new_visibility)
59 {
60 /* toggle visibility of all box children.
61 * do this on the children because toggling
62 * the visibility of the box causes gtk to
63 * automatically hide the tab too */
64 int num_pages =
65 gtk_notebook_get_n_pages (
66 GTK_NOTEBOOK (self));
67 for (int i = 0; i < num_pages; i++)
68 {
69 GtkWidget * widget =
70 foldable_notebook_widget_get_widget_at_page (
71 self, i);
72 gtk_widget_set_visible (
73 widget, new_visibility);
74 }
75
76 if (new_visibility)
77 {
78 if (self->paned && self->prev_pos > 0)
79 {
80 gtk_paned_set_position (
81 self->paned, self->prev_pos);
82 }
83 }
84 else
85 {
86 if (self->paned)
87 {
88 /* remember position before hiding */
89 self->prev_pos =
90 gtk_paned_get_position (self->paned);
91
92 /* hide */
93 int position;
94 if (self->pos_in_paned == GTK_POS_BOTTOM)
95 {
96 position =
97 gtk_widget_get_allocated_height (
98 GTK_WIDGET (self->paned));
99 }
100 else if (self->pos_in_paned ==
101 GTK_POS_RIGHT)
102 {
103 position =
104 gtk_widget_get_allocated_width (
105 GTK_WIDGET (self->paned));
106 }
107 else
108 {
109 position = 0;
110 }
111 gtk_paned_set_position (
112 self->paned, position);
113 }
114 }
115 }
116
117 /**
118 * Returns if the content of the foldable notebook
119 * is visible.
120 */
121 int
foldable_notebook_widget_is_content_visible(FoldableNotebookWidget * self)122 foldable_notebook_widget_is_content_visible (
123 FoldableNotebookWidget * self)
124 {
125 GtkWidget * widget =
126 foldable_notebook_widget_get_current_widget (
127 self);
128 return
129 gtk_widget_get_visible (widget);
130 }
131
132 /**
133 * Get the widget currently visible.
134 */
135 GtkWidget *
foldable_notebook_widget_get_current_widget(FoldableNotebookWidget * self)136 foldable_notebook_widget_get_current_widget (
137 FoldableNotebookWidget * self)
138 {
139 GtkContainer * current_box =
140 GTK_CONTAINER (
141 z_gtk_notebook_get_current_page_widget (
142 GTK_NOTEBOOK (self)));
143 GtkWidget * widget =
144 z_gtk_container_get_single_child (
145 GTK_CONTAINER (current_box));
146 return widget;
147 }
148
149 /**
150 * Combines the above.
151 */
152 void
foldable_notebook_widget_toggle_visibility(FoldableNotebookWidget * self)153 foldable_notebook_widget_toggle_visibility (
154 FoldableNotebookWidget * self)
155 {
156 g_return_if_fail (self);
157 foldable_notebook_widget_set_visibility (
158 self,
159 !foldable_notebook_widget_is_content_visible (
160 self));
161 }
162
163 GtkWidget *
foldable_notebook_widget_get_widget_at_page(FoldableNotebookWidget * self,int page)164 foldable_notebook_widget_get_widget_at_page (
165 FoldableNotebookWidget * self,
166 int page)
167 {
168 GtkContainer * container =
169 GTK_CONTAINER (
170 gtk_notebook_get_nth_page (
171 GTK_NOTEBOOK (self), page));
172 GtkWidget * widget =
173 z_gtk_container_get_single_child (
174 GTK_CONTAINER (container));
175 return widget;
176 }
177
178 /**
179 * Tab release callback.
180 */
181 static void
on_multipress_released(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,FoldableNotebookWidget * self)182 on_multipress_released (
183 GtkGestureMultiPress * gesture,
184 gint n_press,
185 gdouble x,
186 gdouble y,
187 FoldableNotebookWidget * self)
188 {
189 bool hit =
190 ui_is_child_hit (
191 GTK_WIDGET (self),
192 self->tab_during_press,
193 1, 1, x, y, 16, 3);
194 if (hit)
195 {
196
197 int new_visibility =
198 !foldable_notebook_widget_is_content_visible (
199 self);
200
201 foldable_notebook_widget_set_visibility (
202 self, new_visibility);
203 }
204 }
205
206 /**
207 * Tab press callback.
208 */
209 static void
on_multipress_pressed(GtkGestureMultiPress * gesture,gint n_press,gdouble x,gdouble y,FoldableNotebookWidget * self)210 on_multipress_pressed (
211 GtkGestureMultiPress *gesture,
212 gint n_press,
213 gdouble x,
214 gdouble y,
215 FoldableNotebookWidget * self)
216 {
217 self->tab_during_press =
218 z_gtk_notebook_get_current_tab_label_widget (
219 GTK_NOTEBOOK (self));
220 }
221
222 FoldableNotebookWidget *
foldable_notebook_widget_new()223 foldable_notebook_widget_new ()
224 {
225 FoldableNotebookWidget * self =
226 g_object_new (FOLDABLE_NOTEBOOK_WIDGET_TYPE,
227 NULL);
228
229 return self;
230 }
231
232 static void
foldable_notebook_widget_finalize(FoldableNotebookWidget * self)233 foldable_notebook_widget_finalize (
234 FoldableNotebookWidget * self)
235 {
236 G_OBJECT_CLASS (
237 foldable_notebook_widget_parent_class)->
238 finalize (G_OBJECT (self));
239 }
240
241 /**
242 * Sets up an existing FoldableNotebookWidget.
243 */
244 void
foldable_notebook_widget_setup(FoldableNotebookWidget * self,GtkPaned * paned,GtkPositionType pos_in_paned)245 foldable_notebook_widget_setup (
246 FoldableNotebookWidget * self,
247 GtkPaned * paned,
248 GtkPositionType pos_in_paned)
249 {
250 self->paned = paned;
251 self->pos_in_paned = pos_in_paned;
252
253 /* add events */
254 gtk_widget_add_events (
255 GTK_WIDGET (self),
256 GDK_ALL_EVENTS_MASK);
257
258 /* make detachable */
259 z_gtk_notebook_make_detachable (
260 GTK_NOTEBOOK (self), GTK_WINDOW (MAIN_WINDOW));
261
262 /* add signals */
263 self->mp =
264 GTK_GESTURE_MULTI_PRESS (
265 gtk_gesture_multi_press_new (
266 GTK_WIDGET (self)));
267 gtk_event_controller_set_propagation_phase (
268 GTK_EVENT_CONTROLLER (self->mp),
269 GTK_PHASE_CAPTURE);
270 g_signal_connect (
271 G_OBJECT (self->mp), "pressed",
272 G_CALLBACK (on_multipress_pressed), self);
273 g_signal_connect (
274 G_OBJECT (self->mp), "released",
275 G_CALLBACK (on_multipress_released), self);
276 g_signal_connect (
277 G_OBJECT (self), "switch-page",
278 G_CALLBACK (on_switch_page), self);
279 }
280
281 static void
foldable_notebook_widget_class_init(FoldableNotebookWidgetClass * klass)282 foldable_notebook_widget_class_init (
283 FoldableNotebookWidgetClass * klass)
284 {
285 GObjectClass * oklass = G_OBJECT_CLASS (klass);
286 oklass->finalize =
287 (GObjectFinalizeFunc)
288 foldable_notebook_widget_finalize;
289 }
290
291 static void
foldable_notebook_widget_init(FoldableNotebookWidget * self)292 foldable_notebook_widget_init (
293 FoldableNotebookWidget * self)
294 {
295 }
296