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/expander_box.h"
21 #include "utils/resources.h"
22 
23 #include <gtk/gtk.h>
24 
G_DEFINE_TYPE_WITH_PRIVATE(ExpanderBoxWidget,expander_box_widget,GTK_TYPE_BOX)25 G_DEFINE_TYPE_WITH_PRIVATE (
26   ExpanderBoxWidget,
27   expander_box_widget,
28   GTK_TYPE_BOX)
29 
30 #define GET_PRIVATE(s) \
31   ExpanderBoxWidgetPrivate * prv = \
32      expander_box_widget_get_private (s);
33 
34 static void
35 on_clicked (
36   GtkButton *button,
37   ExpanderBoxWidget * self)
38 {
39   GET_PRIVATE (self);
40 
41   bool revealed =
42     !gtk_revealer_get_reveal_child (
43       prv->revealer);
44   gtk_revealer_set_reveal_child (
45     prv->revealer, revealed);
46   gtk_widget_set_visible (
47     GTK_WIDGET (prv->revealer), revealed);
48 
49   if (prv->reveal_cb)
50     {
51       prv->reveal_cb (
52         self, revealed, prv->user_data);
53     }
54 }
55 
56 /**
57  * Gets the private.
58  */
59 ExpanderBoxWidgetPrivate *
expander_box_widget_get_private(ExpanderBoxWidget * self)60 expander_box_widget_get_private (
61   ExpanderBoxWidget * self)
62 {
63   return expander_box_widget_get_instance_private (
64     self);
65 }
66 
67 /**
68  * Reveals or hides the expander box's contents.
69  */
70 void
expander_box_widget_set_reveal(ExpanderBoxWidget * self,int reveal)71 expander_box_widget_set_reveal (
72   ExpanderBoxWidget * self,
73   int                 reveal)
74 {
75   GET_PRIVATE (self);
76   gtk_revealer_set_reveal_child (
77     prv->revealer, reveal);
78   gtk_widget_set_visible (
79     GTK_WIDGET (prv->revealer), reveal);
80 }
81 
82 /**
83  * Sets the label to show.
84  */
85 void
expander_box_widget_set_label(ExpanderBoxWidget * self,const char * label)86 expander_box_widget_set_label (
87   ExpanderBoxWidget * self,
88   const char *        label)
89 {
90   GET_PRIVATE (self);
91 
92   gtk_label_set_text (
93     prv->btn_label, label);
94 }
95 
96 void
expander_box_widget_set_orientation(ExpanderBoxWidget * self,GtkOrientation orientation)97 expander_box_widget_set_orientation (
98   ExpanderBoxWidget * self,
99   GtkOrientation      orientation)
100 {
101   ExpanderBoxWidgetPrivate * prv =
102     expander_box_widget_get_private (self);
103 
104   /* set the main orientation */
105   prv->orientation = orientation;
106   gtk_orientable_set_orientation (
107     GTK_ORIENTABLE (self),
108     orientation);
109 
110   /* set the orientation of the box inside the
111    * expander button */
112   gtk_orientable_set_orientation (
113     GTK_ORIENTABLE (prv->btn_box),
114     orientation == GTK_ORIENTATION_HORIZONTAL ?
115     GTK_ORIENTATION_VERTICAL :
116     GTK_ORIENTATION_HORIZONTAL);
117 
118   /* set the label angle */
119   if (orientation == GTK_ORIENTATION_HORIZONTAL)
120     gtk_label_set_angle (
121       prv->btn_label, 90.0);
122   else
123     gtk_label_set_angle (
124       prv->btn_label, 0.0);
125 
126   if (orientation == GTK_ORIENTATION_HORIZONTAL)
127     {
128       gtk_widget_set_hexpand (
129         GTK_WIDGET (prv->btn_label), 0);
130       gtk_widget_set_vexpand (
131         GTK_WIDGET (prv->btn_label), 1);
132     }
133   else
134     {
135       gtk_widget_set_hexpand (
136         GTK_WIDGET (prv->btn_label), 1);
137       gtk_widget_set_vexpand (
138         GTK_WIDGET (prv->btn_label), 0);
139     }
140 }
141 
142 /**
143  * Sets the icon name to show.
144  */
145 void
expander_box_widget_set_icon_name(ExpanderBoxWidget * self,const char * icon_name)146 expander_box_widget_set_icon_name (
147   ExpanderBoxWidget * self,
148   const char *        icon_name)
149 {
150   GET_PRIVATE (self);
151 
152   gtk_image_set_from_icon_name (
153     prv->btn_img,
154     icon_name,
155     GTK_ICON_SIZE_BUTTON);
156 }
157 
158 void
expander_box_widget_set_vexpand(ExpanderBoxWidget * self,bool expand)159 expander_box_widget_set_vexpand (
160   ExpanderBoxWidget * self,
161   bool                expand)
162 {
163   GET_PRIVATE (self);
164 
165   gtk_widget_set_vexpand (
166     GTK_WIDGET (prv->content), expand);
167 }
168 
169 void
expander_box_widget_set_reveal_callback(ExpanderBoxWidget * self,ExpanderBoxRevealFunc cb,void * user_data)170 expander_box_widget_set_reveal_callback (
171   ExpanderBoxWidget * self,
172   ExpanderBoxRevealFunc   cb,
173   void *                  user_data)
174 {
175   GET_PRIVATE (self);
176 
177   prv->reveal_cb = cb;
178   prv->user_data = user_data;
179 }
180 
181 ExpanderBoxWidget *
expander_box_widget_new(const char * label,const char * icon_name,GtkOrientation orientation)182 expander_box_widget_new (
183   const char * label,
184   const char * icon_name,
185   GtkOrientation orientation)
186 {
187   ExpanderBoxWidget * self =
188     g_object_new (EXPANDER_BOX_WIDGET_TYPE,
189                   "visible", 1,
190                   NULL);
191 
192   expander_box_widget_set_icon_name (
193     self, icon_name);
194   expander_box_widget_set_orientation (
195     self, orientation);
196   expander_box_widget_set_label (
197     self, label);
198 
199   return self;
200 }
201 
202 static void
expander_box_widget_class_init(ExpanderBoxWidgetClass * _klass)203 expander_box_widget_class_init (
204   ExpanderBoxWidgetClass * _klass)
205 {
206   GtkWidgetClass * klass = GTK_WIDGET_CLASS (_klass);
207   resources_set_class_template (
208     klass, "expander_box.ui");
209   gtk_widget_class_set_css_name (
210     klass, "expander-box");
211 
212 #define BIND_CHILD(x) \
213   gtk_widget_class_bind_template_child_private ( \
214     klass, ExpanderBoxWidget, x)
215 
216   BIND_CHILD (button);
217   BIND_CHILD (revealer);
218   BIND_CHILD (content);
219 
220 #undef BIND_CHILD
221 }
222 
223 static void
expander_box_widget_init(ExpanderBoxWidget * self)224 expander_box_widget_init (ExpanderBoxWidget * self)
225 {
226   gtk_widget_init_template (GTK_WIDGET (self));
227 
228   GET_PRIVATE (self);
229 
230   prv->btn_label =
231     GTK_LABEL (gtk_label_new ("Label"));
232   gtk_widget_set_halign (
233     GTK_WIDGET (prv->btn_label),
234     GTK_ALIGN_START);
235   prv->btn_img =
236     GTK_IMAGE (
237       gtk_image_new_from_icon_name (
238         "plugins",
239         GTK_ICON_SIZE_BUTTON));
240   GtkWidget * box =
241     gtk_box_new (GTK_ORIENTATION_HORIZONTAL,
242                  2);
243   gtk_container_add (
244     GTK_CONTAINER (box),
245     GTK_WIDGET (prv->btn_label));
246   gtk_container_add (
247     GTK_CONTAINER (box),
248     GTK_WIDGET (
249       gtk_separator_new (GTK_ORIENTATION_VERTICAL)));
250   gtk_box_pack_end (
251     GTK_BOX (box),
252     GTK_WIDGET (prv->btn_img), 0, 1, 0);
253   gtk_container_add (
254     GTK_CONTAINER (prv->button),
255     GTK_WIDGET (box));
256   prv->btn_box = GTK_BOX (box);
257 
258   gtk_widget_show_all (GTK_WIDGET (self));
259 
260   g_signal_connect (
261     G_OBJECT (prv->button), "clicked",
262     G_CALLBACK (on_clicked), self);
263 }
264