1 /*
2  *  This file is part of GNOME Twitch - 'Enjoy Twitch on your GNU/Linux desktop'
3  *  Copyright © 2017 Vincent Szolnoky <vinszent@vinszent.com>
4  *
5  *  GNOME Twitch is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  GNOME Twitch is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with GNOME Twitch. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "gt-container-view.h"
20 #include "gt-item-container.h"
21 
22 #define TAG "GtContainerView"
23 #include "gnome-twitch/gt-log.h"
24 
25 typedef struct
26 {
27     gboolean search_active;
28     gboolean show_back_button;
29 
30     GtkWidget* search_bar;
31     GtkWidget* search_entry;
32     GtkWidget* menu_button;
33     GtkWidget* container_stack;
34 } GtContainerViewPrivate;
35 
36 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(GtContainerView, gt_container_view, GTK_TYPE_BOX);
37 
38 enum
39 {
40     PROP_0,
41     PROP_SEARCH_ACTIVE,
42     PROP_SHOW_BACK_BUTTON,
43     NUM_PROPS
44 };
45 
46 static GParamSpec* props[NUM_PROPS];
47 
48 static void
get_property(GObject * obj,guint prop,GValue * val,GParamSpec * pspec)49 get_property(GObject* obj,
50     guint prop,
51     GValue* val,
52     GParamSpec* pspec)
53 {
54     GtContainerView* self = GT_CONTAINER_VIEW(obj);
55     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
56 
57     switch (prop)
58     {
59         case PROP_SEARCH_ACTIVE:
60             g_value_set_boolean(val, priv->search_active);
61             break;
62         case PROP_SHOW_BACK_BUTTON:
63             g_value_set_boolean(val, priv->show_back_button);
64             break;
65         default:
66             G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec);
67     }
68 }
69 
70 static void
set_property(GObject * obj,guint prop,const GValue * val,GParamSpec * pspec)71 set_property(GObject* obj,
72     guint prop,
73     const GValue* val,
74     GParamSpec* pspec)
75 {
76     GtContainerView* self = GT_CONTAINER_VIEW(obj);
77     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
78 
79     switch (prop)
80     {
81         case PROP_SEARCH_ACTIVE:
82             priv->search_active = g_value_get_boolean(val);
83             break;
84         case PROP_SHOW_BACK_BUTTON:
85             priv->show_back_button = g_value_get_boolean(val);
86             break;
87         default:
88             G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop, pspec);
89     }
90 }
91 
92 
93 static void
gt_container_view_class_init(GtContainerViewClass * klass)94 gt_container_view_class_init(GtContainerViewClass* klass)
95 {
96     G_OBJECT_CLASS(klass)->get_property = get_property;
97     G_OBJECT_CLASS(klass)->set_property = set_property;
98 
99     props[PROP_SHOW_BACK_BUTTON] = g_param_spec_boolean(
100         "show-back-button",
101         "Show back button",
102         "Whether showing back button",
103         FALSE,
104         G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
105 
106     props[PROP_SEARCH_ACTIVE] = g_param_spec_boolean(
107         "search-active",
108         "Search active",
109         "Whether search active",
110         FALSE,
111         G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
112 
113     g_object_class_install_properties(G_OBJECT_CLASS(klass), NUM_PROPS, props);
114 
115     gtk_widget_class_set_template_from_resource(GTK_WIDGET_CLASS(klass),
116         "/com/vinszent/GnomeTwitch/ui/gt-container-view.ui");
117 
118     gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtContainerView, container_stack);
119     gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtContainerView, search_bar);
120     gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtContainerView, search_entry);
121     gtk_widget_class_bind_template_child_private(GTK_WIDGET_CLASS(klass), GtContainerView, menu_button);
122 }
123 
124 static void
gt_container_view_init(GtContainerView * self)125 gt_container_view_init(GtContainerView* self)
126 {
127     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
128 
129     gtk_widget_init_template(GTK_WIDGET(self));
130 
131     gtk_search_bar_connect_entry(GTK_SEARCH_BAR(priv->search_bar),
132         GTK_ENTRY(priv->search_entry));
133 
134     g_object_bind_property(self, "search-active",
135         priv->search_bar, "search-mode-enabled",
136         G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
137 }
138 
139 /* Should only be used by children */
140 void
gt_container_view_add_container(GtContainerView * self,GtItemContainer * container)141 gt_container_view_add_container(GtContainerView* self, GtItemContainer* container)
142 {
143     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
144 
145     gtk_container_add(GTK_CONTAINER(priv->container_stack),
146         GTK_WIDGET(container));
147 
148     gtk_widget_show_all(GTK_WIDGET(container));
149 }
150 
151 void
gt_container_view_set_search_popover_widget(GtContainerView * self,GtkWidget * widget)152 gt_container_view_set_search_popover_widget(GtContainerView* self, GtkWidget* widget)
153 {
154     g_assert(GT_IS_CONTAINER_VIEW(self));
155     g_assert(GTK_IS_WIDGET(widget));
156 
157     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
158     GtkWidget* popover = gtk_popover_new(priv->menu_button);
159 
160     gtk_container_add(GTK_CONTAINER(popover), widget);
161 
162     gtk_menu_button_set_popover(GTK_MENU_BUTTON(priv->menu_button), GTK_WIDGET(popover));
163 
164     gtk_widget_show_all(priv->menu_button);
165     gtk_widget_show_all(widget);
166 }
167 
168 void
gt_container_view_refresh(GtContainerView * self)169 gt_container_view_refresh(GtContainerView* self)
170 {
171     g_assert(GT_IS_CONTAINER_VIEW(self));
172     g_assert_nonnull(GT_CONTAINER_VIEW_GET_CLASS(self)->refresh);
173 
174     GT_CONTAINER_VIEW_GET_CLASS(self)->refresh(self);
175 }
176 
177 void
gt_container_view_go_back(GtContainerView * self)178 gt_container_view_go_back(GtContainerView* self)
179 {
180     g_assert(GT_IS_CONTAINER_VIEW(self));
181     g_assert_nonnull(GT_CONTAINER_VIEW_GET_CLASS(self)->go_back);
182 
183     GT_CONTAINER_VIEW_GET_CLASS(self)->go_back(self);
184 }
185 
186 void
gt_container_view_set_search_active(GtContainerView * self,gboolean search_active)187 gt_container_view_set_search_active(GtContainerView* self, gboolean search_active)
188 {
189     g_assert(GT_IS_CONTAINER_VIEW(self));
190 
191     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
192 
193     priv->search_active = search_active;
194 }
195 
196 gboolean
gt_container_view_get_search_active(GtContainerView * self)197 gt_container_view_get_search_active(GtContainerView* self)
198 {
199     g_assert(GT_IS_CONTAINER_VIEW(self));
200 
201     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
202 
203     return priv->search_active;
204 }
205 
206 gboolean
gt_container_view_get_show_back_button(GtContainerView * self)207 gt_container_view_get_show_back_button(GtContainerView* self)
208 {
209     g_assert(GT_IS_CONTAINER_VIEW(self));
210 
211     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
212 
213     return priv->show_back_button;
214 }
215 
216 GtkWidget*
gt_container_view_get_container_stack(GtContainerView * self)217 gt_container_view_get_container_stack(GtContainerView* self)
218 {
219     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
220 
221     g_assert(GT_IS_CONTAINER_VIEW(self));
222 
223     return priv->container_stack;
224 }
225 
226 GtkWidget*
gt_container_view_get_search_entry(GtContainerView * self)227 gt_container_view_get_search_entry(GtContainerView* self)
228 {
229     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
230 
231     g_assert(GT_IS_CONTAINER_VIEW(self));
232 
233     return priv->search_entry;
234 }
235 
236 GtkWidget*
gt_container_view_get_search_bar(GtContainerView * self)237 gt_container_view_get_search_bar(GtContainerView* self)
238 {
239     g_assert(GT_IS_CONTAINER_VIEW(self));
240 
241     GtContainerViewPrivate* priv = gt_container_view_get_instance_private(self);
242 
243     return priv->search_bar;
244 }
245