gtkactionbar.c 11 KB
Newer Older
William Jon McCann's avatar
William Jon McCann committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * Copyright (c) 2013 - 2014 Red Hat, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "config.h"

#include "gtkactionbar.h"
#include "gtkintl.h"
#include "gtkbuildable.h"
#include "gtktypebuiltins.h"
26
#include "gtkbox.h"
William Jon McCann's avatar
William Jon McCann committed
27
#include "gtkrevealer.h"
28
#include "gtkwidgetprivate.h"
Timm Bäder's avatar
Timm Bäder committed
29
#include "gtkprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
30
#include "gtkcenterbox.h"
Timm Bäder's avatar
Timm Bäder committed
31
#include "gtkbinlayout.h"
William Jon McCann's avatar
William Jon McCann committed
32
33
34
35

#include <string.h>

/**
Matthias Clasen's avatar
Matthias Clasen committed
36
 * GtkActionBar:
William Jon McCann's avatar
William Jon McCann committed
37
 *
Matthias Clasen's avatar
Matthias Clasen committed
38
39
40
41
42
43
 * `GtkActionBar` is designed to present contextual actions.
 *
 * ![An example GtkActionBar](action-bar.png)
 *
 * It is expected to be displayed below the content and expand
 * horizontally to fill the area.
William Jon McCann's avatar
William Jon McCann committed
44
45
46
47
48
 *
 * It allows placing children at the start or the end. In addition, it
 * contains an internal centered box which is centered with respect to
 * the full width of the box, even if the children at either side take
 * up different amounts of space.
49
50
51
 *
 * # CSS nodes
 *
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 * ```
 * actionbar
 * ╰── revealer
 *     ╰── box
 *         ├── box.start
 *         │   ╰── [start children]
 *         ├── [center widget]
 *         ╰── box.end
 *             ╰── [end children]
 * ```
 *
 * A `GtkActionBar`'s CSS node is called `actionbar`. It contains a `revealer`
 * subnode, which contains a `box` subnode, which contains two `box` subnodes at
 * the start and end of the action bar, with `start` and `end style classes
 * respectively, as well as a center node that represents the center child.
 *
 * Each of the boxes contains children packed for that side.
William Jon McCann's avatar
William Jon McCann committed
69
70
 */

Matthias Clasen's avatar
Matthias Clasen committed
71
72
73
74
typedef struct _GtkActionBarClass         GtkActionBarClass;

struct _GtkActionBar
{
75
  GtkWidget parent;
Matthias Clasen's avatar
Matthias Clasen committed
76

77
78
79
  GtkWidget *center_box;
  GtkWidget *start_box;
  GtkWidget *end_box;
William Jon McCann's avatar
William Jon McCann committed
80
81
82
  GtkWidget *revealer;
};

83
84
struct _GtkActionBarClass
{
85
  GtkWidgetClass parent_class;
86
87
};

Timm Bäder's avatar
Timm Bäder committed
88
enum {
89
  PROP_0,
Timm Bäder's avatar
Timm Bäder committed
90
91
92
93
94
  PROP_REVEALED,
  LAST_PROP
};
static GParamSpec *props[LAST_PROP] = { NULL, };

95
static void gtk_action_bar_buildable_interface_init (GtkBuildableIface *iface);
William Jon McCann's avatar
William Jon McCann committed
96

97
G_DEFINE_TYPE_WITH_CODE (GtkActionBar, gtk_action_bar, GTK_TYPE_WIDGET,
William Jon McCann's avatar
William Jon McCann committed
98
99
100
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                gtk_action_bar_buildable_interface_init))

Timm Bäder's avatar
Timm Bäder committed
101
102
103
104
105
106
static void
gtk_action_bar_set_property (GObject      *object,
                             guint         prop_id,
                             const GValue *value,
                             GParamSpec   *pspec)
{
107
  GtkActionBar *self = GTK_ACTION_BAR (object);
Timm Bäder's avatar
Timm Bäder committed
108
109
110
111

  switch (prop_id)
    {
    case PROP_REVEALED:
112
      gtk_action_bar_set_revealed (self, g_value_get_boolean (value));
Timm Bäder's avatar
Timm Bäder committed
113
114
115
116
117
118
119
120
121
122
123
124
125
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_action_bar_get_property (GObject    *object,
                             guint       prop_id,
                             GValue     *value,
                             GParamSpec *pspec)
{
126
  GtkActionBar *self = GTK_ACTION_BAR (object);
Timm Bäder's avatar
Timm Bäder committed
127
128
129
130

  switch (prop_id)
    {
    case PROP_REVEALED:
131
      g_value_set_boolean (value, gtk_action_bar_get_revealed (self));
Timm Bäder's avatar
Timm Bäder committed
132
133
134
135
136
137
138
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

139
static void
140
gtk_action_bar_dispose (GObject *object)
141
{
142
  GtkActionBar *self = GTK_ACTION_BAR (object);
143

144
  g_clear_pointer (&self->revealer, gtk_widget_unparent);
145

146
  self->center_box = NULL;
147
148
  self->start_box = NULL;
  self->end_box = NULL;
149

150
  G_OBJECT_CLASS (gtk_action_bar_parent_class)->dispose (object);
151
152
}

William Jon McCann's avatar
William Jon McCann committed
153
154
155
static void
gtk_action_bar_class_init (GtkActionBarClass *klass)
{
156
  GObjectClass *object_class;
William Jon McCann's avatar
William Jon McCann committed
157
158
  GtkWidgetClass *widget_class;

159
  object_class = G_OBJECT_CLASS (klass);
William Jon McCann's avatar
William Jon McCann committed
160
161
  widget_class = GTK_WIDGET_CLASS (klass);

Timm Bäder's avatar
Timm Bäder committed
162
163
  object_class->set_property = gtk_action_bar_set_property;
  object_class->get_property = gtk_action_bar_get_property;
164
  object_class->dispose = gtk_action_bar_dispose;
165

166
  widget_class->focus = gtk_widget_focus_child;
William Jon McCann's avatar
William Jon McCann committed
167

Matthias Clasen's avatar
Matthias Clasen committed
168
169
170
171
172
  /**
   * GtkActionBar:revealed: (attributes org.gtk.Property.get=gtk_action_bar_get_revealed org.gtk.Property.set=gtk_action_bar_set_revealed)
   *
   * Controls whether the action bar shows its contents.
   */
Timm Bäder's avatar
Timm Bäder committed
173
174
175
176
177
178
179
  props[PROP_REVEALED] =
    g_param_spec_boolean ("revealed",
                          P_("Reveal"),
                          P_("Controls whether the action bar shows its contents or not"),
                          TRUE,
                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);

180
181
  g_object_class_install_properties (object_class, LAST_PROP, props);

Timm Bäder's avatar
Timm Bäder committed
182
  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
Matthias Clasen's avatar
Matthias Clasen committed
183
  gtk_widget_class_set_css_name (widget_class, I_("actionbar"));
William Jon McCann's avatar
William Jon McCann committed
184
185
186
}

static void
187
gtk_action_bar_init (GtkActionBar *self)
William Jon McCann's avatar
William Jon McCann committed
188
{
189
  GtkWidget *widget = GTK_WIDGET (self);
William Jon McCann's avatar
William Jon McCann committed
190

191
192
  self->revealer = gtk_revealer_new ();
  gtk_widget_set_parent (self->revealer, widget);
William Jon McCann's avatar
William Jon McCann committed
193

194
195
  gtk_revealer_set_reveal_child (GTK_REVEALER (self->revealer), TRUE);
  gtk_revealer_set_transition_type (GTK_REVEALER (self->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP);
196

197
198
  self->start_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
  self->end_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
199

200
201
202
  gtk_widget_add_css_class (self->start_box, "start");
  gtk_widget_add_css_class (self->end_box, "end");

203
204
205
  self->center_box = gtk_center_box_new ();
  gtk_center_box_set_start_widget (GTK_CENTER_BOX (self->center_box), self->start_box);
  gtk_center_box_set_end_widget (GTK_CENTER_BOX (self->center_box), self->end_box);
206

207
  gtk_revealer_set_child (GTK_REVEALER (self->revealer), self->center_box);
208
209
}

210
211
static GtkBuildableIface *parent_buildable_iface;

William Jon McCann's avatar
William Jon McCann committed
212
213
214
215
static void
gtk_action_bar_buildable_add_child (GtkBuildable *buildable,
                                    GtkBuilder   *builder,
                                    GObject      *child,
Benjamin Otte's avatar
Benjamin Otte committed
216
                                    const char   *type)
William Jon McCann's avatar
William Jon McCann committed
217
{
218
  GtkActionBar *self = GTK_ACTION_BAR (buildable);
William Jon McCann's avatar
William Jon McCann committed
219

220
  if (g_strcmp0 (type, "start") == 0)
221
    gtk_action_bar_pack_start (self, GTK_WIDGET (child));
222
223
  else if (g_strcmp0 (type, "center") == 0)
    gtk_action_bar_set_center_widget (self, GTK_WIDGET (child));
Matthias Clasen's avatar
Matthias Clasen committed
224
  else if (g_strcmp0 (type, "end") == 0)
225
    gtk_action_bar_pack_end (self, GTK_WIDGET (child));
226
227
  else if (type == NULL && GTK_IS_WIDGET (child))
    gtk_action_bar_pack_start (self, GTK_WIDGET (child));
William Jon McCann's avatar
William Jon McCann committed
228
  else
229
    parent_buildable_iface->add_child (buildable, builder, child, type);
William Jon McCann's avatar
William Jon McCann committed
230
231
232
233
234
235
236
237
238
239
240
}

static void
gtk_action_bar_buildable_interface_init (GtkBuildableIface *iface)
{
  parent_buildable_iface = g_type_interface_peek_parent (iface);
  iface->add_child = gtk_action_bar_buildable_add_child;
}

/**
 * gtk_action_bar_pack_start:
Matthias Clasen's avatar
Matthias Clasen committed
241
242
 * @action_bar: A `GtkActionBar`
 * @child: the `GtkWidget` to be added to @action_bar
William Jon McCann's avatar
William Jon McCann committed
243
244
245
246
247
248
249
250
 *
 * Adds @child to @action_bar, packed with reference to the
 * start of the @action_bar.
 */
void
gtk_action_bar_pack_start (GtkActionBar *action_bar,
                           GtkWidget    *child)
{
251
  gtk_box_append (GTK_BOX (action_bar->start_box), child);
William Jon McCann's avatar
William Jon McCann committed
252
253
254
255
}

/**
 * gtk_action_bar_pack_end:
Matthias Clasen's avatar
Matthias Clasen committed
256
257
 * @action_bar: A `GtkActionBar`
 * @child: the `GtkWidget` to be added to @action_bar
William Jon McCann's avatar
William Jon McCann committed
258
259
260
261
262
263
264
265
 *
 * Adds @child to @action_bar, packed with reference to the
 * end of the @action_bar.
 */
void
gtk_action_bar_pack_end (GtkActionBar *action_bar,
                         GtkWidget    *child)
{
266
  gtk_box_insert_child_after (GTK_BOX (action_bar->end_box), child, NULL);
William Jon McCann's avatar
William Jon McCann committed
267
268
}

269
270
/**
 * gtk_action_bar_remove:
Matthias Clasen's avatar
Matthias Clasen committed
271
272
 * @action_bar: a `GtkActionBar`
 * @child: the `GtkWidget` to be removed
273
274
275
276
277
278
279
 *
 * Removes a child from @action_bar.
 */
void
gtk_action_bar_remove (GtkActionBar *action_bar,
                       GtkWidget    *child)
{
280
  if (gtk_widget_get_parent (child) == action_bar->start_box)
281
    gtk_box_remove (GTK_BOX (action_bar->start_box), child);
282
  else if (gtk_widget_get_parent (child) == action_bar->end_box)
283
    gtk_box_remove (GTK_BOX (action_bar->end_box), child);
284
285
286
287
288
  else if (child == gtk_center_box_get_center_widget (GTK_CENTER_BOX (action_bar->center_box)))
    gtk_center_box_set_center_widget (GTK_CENTER_BOX (action_bar->center_box), NULL);
  else
    g_warning ("Can't remove non-child %s %p from GtkActionBar %p",
               G_OBJECT_TYPE_NAME (child), child, action_bar);
289
290
}

William Jon McCann's avatar
William Jon McCann committed
291
292
/**
 * gtk_action_bar_set_center_widget:
Matthias Clasen's avatar
Matthias Clasen committed
293
 * @action_bar: a `GtkActionBar`
294
 * @center_widget: (nullable): a widget to use for the center
William Jon McCann's avatar
William Jon McCann committed
295
 *
Matthias Clasen's avatar
Matthias Clasen committed
296
 * Sets the center widget for the `GtkActionBar`.
William Jon McCann's avatar
William Jon McCann committed
297
298
299
300
301
 */
void
gtk_action_bar_set_center_widget (GtkActionBar *action_bar,
                                  GtkWidget    *center_widget)
{
302
  gtk_center_box_set_center_widget (GTK_CENTER_BOX (action_bar->center_box), center_widget);
William Jon McCann's avatar
William Jon McCann committed
303
304
305
306
}

/**
 * gtk_action_bar_get_center_widget:
Matthias Clasen's avatar
Matthias Clasen committed
307
 * @action_bar: a `GtkActionBar`
William Jon McCann's avatar
William Jon McCann committed
308
309
310
 *
 * Retrieves the center bar widget of the bar.
 *
Matthias Clasen's avatar
Matthias Clasen committed
311
 * Returns: (transfer none) (nullable): the center `GtkWidget`
William Jon McCann's avatar
William Jon McCann committed
312
313
314
315
316
317
 */
GtkWidget *
gtk_action_bar_get_center_widget (GtkActionBar *action_bar)
{
  g_return_val_if_fail (GTK_IS_ACTION_BAR (action_bar), NULL);

318
  return gtk_center_box_get_center_widget (GTK_CENTER_BOX (action_bar->center_box));
William Jon McCann's avatar
William Jon McCann committed
319
320
321
322
323
}

/**
 * gtk_action_bar_new:
 *
Matthias Clasen's avatar
Matthias Clasen committed
324
 * Creates a new `GtkActionBar` widget.
William Jon McCann's avatar
William Jon McCann committed
325
 *
Matthias Clasen's avatar
Matthias Clasen committed
326
 * Returns: a new `GtkActionBar`
William Jon McCann's avatar
William Jon McCann committed
327
328
329
330
331
332
 */
GtkWidget *
gtk_action_bar_new (void)
{
  return GTK_WIDGET (g_object_new (GTK_TYPE_ACTION_BAR, NULL));
}
Timm Bäder's avatar
Timm Bäder committed
333
334

/**
Matthias Clasen's avatar
Matthias Clasen committed
335
336
 * gtk_action_bar_set_revealed: (attributes org.gtk.Method.set_property=revealed)
 * @action_bar: a `GtkActionBar`
Timm Bäder's avatar
Timm Bäder committed
337
338
 * @revealed: The new value of the property
 *
Matthias Clasen's avatar
Matthias Clasen committed
339
 * Reveals or conceals the content of the action bar.
Timm Bäder's avatar
Timm Bäder committed
340
 *
Matthias Clasen's avatar
Matthias Clasen committed
341
342
343
 * Note: this does not show or hide @action_bar in the
 * [property@Gtk.Widget:visible] sense, so revealing has
 * no effect if the action bar is hidden.
Timm Bäder's avatar
Timm Bäder committed
344
345
346
347
348
349
350
 */
void
gtk_action_bar_set_revealed (GtkActionBar *action_bar,
                             gboolean      revealed)
{
  g_return_if_fail (GTK_IS_ACTION_BAR (action_bar));

351
352
353
354
355
  if (revealed == gtk_revealer_get_reveal_child (GTK_REVEALER (action_bar->revealer)))
    return;

  gtk_revealer_set_reveal_child (GTK_REVEALER (action_bar->revealer), revealed);
  g_object_notify_by_pspec (G_OBJECT (action_bar), props[PROP_REVEALED]);
Timm Bäder's avatar
Timm Bäder committed
356
357
358
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
359
360
 * gtk_action_bar_get_revealed: (attributes org.gtk.Method.get_property=revealed)
 * @action_bar: a `GtkActionBar`
Timm Bäder's avatar
Timm Bäder committed
361
 *
Matthias Clasen's avatar
Matthias Clasen committed
362
 * Gets whether the contents of the action bar are revealed.
363
 *
Matthias Clasen's avatar
Matthias Clasen committed
364
 * Returns: the current value of the [property@Gtk.ActionBar:revealed]
Matthias Clasen's avatar
Matthias Clasen committed
365
 *   property
Timm Bäder's avatar
Timm Bäder committed
366
367
368
369
370
371
 */
gboolean
gtk_action_bar_get_revealed (GtkActionBar *action_bar)
{
  g_return_val_if_fail (GTK_IS_ACTION_BAR (action_bar), FALSE);

372
  return gtk_revealer_get_reveal_child (GTK_REVEALER (action_bar->revealer));
Timm Bäder's avatar
Timm Bäder committed
373
}