hdy-title-bar.c 5.74 KB
Newer Older
Adrien Plazas's avatar
Adrien Plazas 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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
/*
 * Copyright (C) 2018 Purism SPC
 *
 * SPDX-License-Identifier: LGPL-2.1+
 */

#include "hdy-title-bar.h"

#include <glib/gi18n.h>
#include <math.h>

/**
 * SECTION:hdy-title-bar
 * @short_description: A simple title bar container.
 * @Title: HdyTitleBar
 *
 * HdyTitleBar is meant to be used as the top-level widget of your window's
 * title bar. It will be drawn with the same style as a GtkHeaderBar but it
 * won't force a widget layout on you: you can put whatever widget you want in
 * it, including a GtkHeaderBar.
 *
 * HdyTitleBar becomes really useful when you want to animate header bars, like
 * an adaptive application using #HdyTitleBar would do.
 */

enum {
  PROP_0,
  PROP_SELECTION_MODE,
  LAST_PROP,
};

#define HDY_EASE_OUT_TAN_CUBIC 3

struct _HdyTitleBar
{
  GtkBin parent_instance;

  gboolean selection_mode;
};

G_DEFINE_TYPE (HdyTitleBar, hdy_title_bar, GTK_TYPE_BIN)

static GParamSpec *props[LAST_PROP];

/**
 * hdy_title_bar_set_selection_mode:
 * @self: a #HdyTitleBar
 * @selection_mode: %TRUE to enable the selection mode
 *
 * Sets whether @self is in selection mode.
 */
void
hdy_title_bar_set_selection_mode (HdyTitleBar *self,
                                  gboolean     selection_mode)
{
  GtkStyleContext *context;

  g_return_if_fail (HDY_IS_TITLE_BAR (self));

  selection_mode = !!selection_mode;

  context = gtk_widget_get_style_context (GTK_WIDGET (self));

  if (self->selection_mode == selection_mode)
    return;

  self->selection_mode = selection_mode;

  if (selection_mode)
    gtk_style_context_add_class (context, "selection-mode");
  else
    gtk_style_context_remove_class (context, "selection-mode");

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SELECTION_MODE]);
}

/**
 * hdy_title_bar_get_selection_mode:
 * @self: a #HdyTitleBar
 *
 * Returns wether whether @self is in selection mode.
 *
 * Returns: %TRUE if the title bar is in selection mode
 */
gboolean
hdy_title_bar_get_selection_mode (HdyTitleBar *self)
{
  g_return_val_if_fail (HDY_IS_TITLE_BAR (self), FALSE);

  return self->selection_mode;
}

static void
style_updated_cb (HdyTitleBar *self)
{
  GtkStyleContext *context;
  gboolean selection_mode;

  g_assert (HDY_IS_TITLE_BAR (self));

  context = gtk_widget_get_style_context (GTK_WIDGET (self));
  selection_mode = gtk_style_context_has_class (context, "selection-mode");

  if (self->selection_mode == selection_mode)
    return;

  self->selection_mode = selection_mode;

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_SELECTION_MODE]);
}

static void
hdy_title_bar_get_property (GObject    *object,
                            guint       prop_id,
                            GValue     *value,
                            GParamSpec *pspec)
{
  HdyTitleBar *self = HDY_TITLE_BAR (object);

  switch (prop_id) {
  case PROP_SELECTION_MODE:
    g_value_set_boolean (value, hdy_title_bar_get_selection_mode (self));
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  }
}

static void
hdy_title_bar_set_property (GObject      *object,
                            guint         prop_id,
                            const GValue *value,
                            GParamSpec   *pspec)
{
  HdyTitleBar *self = HDY_TITLE_BAR (object);

  switch (prop_id) {
  case PROP_SELECTION_MODE:
    hdy_title_bar_set_selection_mode (self, g_value_get_boolean (value));
    break;
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  }
}

static gboolean
hdy_title_bar_draw (GtkWidget *widget,
                    cairo_t   *cr)
{
  GtkStyleContext *context;

  context = gtk_widget_get_style_context (widget);
  /* GtkWidget draws nothing by default so we have to render the background
   * explicitely for HdyTitleBar to render the typical titlebar background.
   */
  gtk_render_background (context,
                         cr,
                         0, 0,
                         gtk_widget_get_allocated_width (widget),
                         gtk_widget_get_allocated_height (widget));

  return GTK_WIDGET_CLASS (hdy_title_bar_parent_class)->draw (widget, cr);
}

static void
hdy_title_bar_class_init (HdyTitleBarClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);

  object_class->get_property = hdy_title_bar_get_property;
  object_class->set_property = hdy_title_bar_set_property;

  widget_class->draw = hdy_title_bar_draw;

  /**
   * HdyTitleBar:selection_mode:
   *
   * %TRUE if the title bar is in selection mode.
   */
  props[PROP_SELECTION_MODE] =
      g_param_spec_boolean ("selection-mode",
                            _("Selection mode"),
                            _("Whether or not the title bar is in selection mode"),
                            FALSE,
                            G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (object_class, LAST_PROP, props);

  /* Adwaita states it expects a headerbar to be the top-level titlebar widget,
   * so style-wise HdyTitleBar pretends to be one as its role is to be the
   * top-level titlebar widget.
   */
  gtk_widget_class_set_css_name (widget_class, "headerbar");
  gtk_container_class_handle_border_width (container_class);
}

static void
hdy_title_bar_init (HdyTitleBar *self)
{
  GtkStyleContext *context;

  context = gtk_widget_get_style_context (GTK_WIDGET (self));
  /* Ensure the widget has the titlebar style class. */
  gtk_style_context_add_class (context, "titlebar");

  g_signal_connect (self, "style-updated", G_CALLBACK (style_updated_cb), NULL);
}

/**
 * hdy_title_bar_new:
 *
 * Creates a new #HdyTitleBar.
 *
 * Returns: a new #HdyTitleBar
 */
HdyTitleBar *
hdy_title_bar_new (void)
{
  return g_object_new (HDY_TYPE_TITLE_BAR, NULL);
}