hdy-dialer-button.c 8.71 KB
Newer Older
Guido Gunther's avatar
Guido Gunther committed
1 2
/*
 * Copyright (C) 2017 Purism SPC
Guido Gunther's avatar
Guido Gunther committed
3
 *
4
 * SPDX-License-Identifier: LGPL-2.1+
Guido Gunther's avatar
Guido Gunther committed
5 6 7 8 9 10 11 12 13 14 15 16
 */

#include <glib/gi18n.h>

#include "hdy-dialer-button.h"

/**
 * SECTION:hdy-dialer-button
 * @short_description: A button on a #HdyDialer keypad
 * @Title: HdyDialerButton
 *
 * The #HdyDialerButton widget is a single button on an #HdyDialer. It
17 18
 * can represent a single symbol (typically a digit) plus an arbitrary
 * number of symbols that are displayed below it.
Guido Gunther's avatar
Guido Gunther committed
19 20 21
 */

enum {
22
  PROP_0,
23
  PROP_DIGIT,
24
  PROP_SYMBOLS,
25
  PROP_LAST_PROP,
Guido Gunther's avatar
Guido Gunther committed
26
};
27
static GParamSpec *props[PROP_LAST_PROP];
Guido Gunther's avatar
Guido Gunther committed
28 29 30

typedef struct
{
31
  GtkLabel *label, *secondary_label;
32
  gchar *symbols;
Guido Gunther's avatar
Guido Gunther committed
33 34 35 36
} HdyDialerButtonPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (HdyDialerButton, hdy_dialer_button, GTK_TYPE_BUTTON)

37
static void
Guido Gunther's avatar
Guido Gunther committed
38 39 40
format_label(HdyDialerButton *self)
{
  HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);
41 42 43 44 45 46 47 48 49 50 51 52 53
  gchar *symbols = priv->symbols != NULL ? priv->symbols : "";
  g_autofree gchar *text = NULL;
  gchar *secondary_text = NULL;

  if (*symbols != '\0') {
    secondary_text = g_utf8_find_next_char (symbols, NULL);
    /* Allocate memory for the first character and '\0'. */
    text = g_malloc0 (secondary_text - symbols + 1);
    g_utf8_strncpy (text, symbols, 1);
  }
  else {
    text = g_malloc0 (sizeof (gchar));
    secondary_text = "";
Guido Gunther's avatar
Guido Gunther committed
54 55
  }

56
  gtk_label_set_label (priv->label, text);
57
  gtk_label_set_label (priv->secondary_label, secondary_text);
Guido Gunther's avatar
Guido Gunther committed
58 59 60
}

static void
61 62 63 64
hdy_dialer_button_set_property (GObject      *object,
                                guint         property_id,
                                const GValue *value,
                                GParamSpec   *pspec)
Guido Gunther's avatar
Guido Gunther committed
65 66 67 68 69
{
  HdyDialerButton *self = HDY_DIALER_BUTTON (object);
  HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);

  switch (property_id) {
70 71 72
  case PROP_SYMBOLS:
    g_free (priv->symbols);
    priv->symbols = g_value_dup_string (value);
Guido Gunther's avatar
Guido Gunther committed
73 74 75 76 77 78 79 80 81 82
    format_label(self);
    break;

  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }
}

static void
83 84 85
hdy_dialer_button_get_property (GObject    *object,
                                guint       property_id,
                                GValue     *value,
86
                                GParamSpec *pspec)
Guido Gunther's avatar
Guido Gunther committed
87 88 89 90 91
{
  HdyDialerButton *self = HDY_DIALER_BUTTON (object);
  HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);

  switch (property_id) {
92
  case PROP_DIGIT:
93
    g_value_set_int (value, hdy_dialer_button_get_digit (self));
Guido Gunther's avatar
Guido Gunther committed
94 95
    break;

96 97
  case PROP_SYMBOLS:
    g_value_set_string (value, priv->symbols);
Guido Gunther's avatar
Guido Gunther committed
98 99 100 101 102 103 104 105
    break;

  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }
}

106 107 108
/* This private method is prefixed by the call name because it will be a virtual
 * method in GTK+ 4.
 */
109
static void
110 111 112 113 114 115 116
hdy_dialer_button_measure (GtkWidget      *widget,
                           GtkOrientation  orientation,
                           int             for_size,
                           int            *minimum,
                           int            *natural,
                           int            *minimum_baseline,
                           int            *natural_baseline)
117 118
{
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (hdy_dialer_button_parent_class);
119
  gint min1, min2, nat1, nat2;
120

121 122 123 124 125 126 127 128 129 130 131
  if (for_size < 0) {
    widget_class->get_preferred_width (widget, &min1, &nat1);
    widget_class->get_preferred_height (widget, &min2, &nat2);
  }
  else {
    if (orientation == GTK_ORIENTATION_HORIZONTAL)
      widget_class->get_preferred_width_for_height (widget, for_size, &min1, &nat1);
    else
      widget_class->get_preferred_height_for_width (widget, for_size, &min1, &nat1);
    min2 = nat2 = for_size;
  }
132

133 134 135 136 137 138 139 140 141 142 143 144 145
  if (minimum)
    *minimum = MAX (min1, min2);
  if (natural)
    *natural = MAX (nat1, nat2);
}

static void
hdy_dialer_button_get_preferred_width (GtkWidget *widget,
                                       gint      *minimum_width,
                                       gint      *natural_width)
{
  hdy_dialer_button_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1,
                             minimum_width, natural_width, NULL, NULL);
146 147 148 149 150 151 152
}

static void
hdy_dialer_button_get_preferred_height (GtkWidget *widget,
                                        gint      *minimum_height,
                                        gint      *natural_height)
{
153 154
  hdy_dialer_button_measure (widget, GTK_ORIENTATION_VERTICAL, -1,
                             minimum_height, natural_height, NULL, NULL);
155 156 157 158 159 160 161 162
}

static void
hdy_dialer_button_get_preferred_width_for_height (GtkWidget *widget,
                                                  gint       height,
                                                  gint      *minimum_width,
                                                  gint      *natural_width)
{
163 164
  hdy_dialer_button_measure (widget, GTK_ORIENTATION_HORIZONTAL, height,
                             minimum_width, natural_width, NULL, NULL);
165 166 167 168 169 170 171 172
}

static void
hdy_dialer_button_get_preferred_height_for_width (GtkWidget *widget,
                                                  gint       width,
                                                  gint      *minimum_height,
                                                  gint      *natural_height)
{
173 174
  hdy_dialer_button_measure (widget, GTK_ORIENTATION_VERTICAL, width,
                             minimum_height, natural_height, NULL, NULL);
175
}
Guido Gunther's avatar
Guido Gunther committed
176

177 178 179 180 181 182 183

static void
hdy_dialer_button_finalize (GObject *object)
{
  HdyDialerButton *self = HDY_DIALER_BUTTON (object);
  HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);

184
  g_clear_pointer (&priv->symbols, g_free);
185
  G_OBJECT_CLASS (hdy_dialer_button_parent_class)->finalize (object);
186 187 188
}


Guido Gunther's avatar
Guido Gunther committed
189 190 191 192
static void
hdy_dialer_button_class_init (HdyDialerButtonClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
193
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
Guido Gunther's avatar
Guido Gunther committed
194 195 196 197

  object_class->set_property = hdy_dialer_button_set_property;
  object_class->get_property = hdy_dialer_button_get_property;

198 199
  object_class->finalize = hdy_dialer_button_finalize;

200 201 202 203 204
  widget_class->get_preferred_width = hdy_dialer_button_get_preferred_width;
  widget_class->get_preferred_height = hdy_dialer_button_get_preferred_height;
  widget_class->get_preferred_width_for_height = hdy_dialer_button_get_preferred_width_for_height;
  widget_class->get_preferred_height_for_width = hdy_dialer_button_get_preferred_height_for_width;

205 206 207 208 209
  props[PROP_DIGIT] =
    g_param_spec_int ("digit",
                      _("Digit"),
                      _("The dialer digit of the button"),
                      -1, INT_MAX, 0,
210
                      G_PARAM_READABLE);
211

212 213 214 215
  props[PROP_SYMBOLS] =
    g_param_spec_string ("symbols",
                         _("Symbols"),
                         _("The dialer symbols of the button"),
216
                         "",
217
                         G_PARAM_READWRITE);
218 219

  g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
220 221

  gtk_widget_class_set_template_from_resource (widget_class,
222
                                               "/sm/puri/handy/dialer/ui/hdy-dialer-button.ui");
223 224
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialerButton, label);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialerButton, secondary_label);
Guido Gunther's avatar
Guido Gunther committed
225 226 227 228
}

/**
 * hdy_dialer_button_new:
229
 * @symbols: (nullable): the symbols displayed on the #HdyDialerButton
Guido Gunther's avatar
Guido Gunther committed
230
 *
231 232 233
 * Create a new #HdyDialerButton which displays
 * @symbols. If
 * @symbols is %NULL no symbols will be displayed.
Guido Gunther's avatar
Guido Gunther committed
234 235 236
 *
 * Returns: the newly created #HdyDialerButton widget
 */
237
GtkWidget *hdy_dialer_button_new (const gchar *symbols)
Guido Gunther's avatar
Guido Gunther committed
238
{
239
  return g_object_new (HDY_TYPE_DIALER_BUTTON, "symbols", symbols, NULL);
Guido Gunther's avatar
Guido Gunther committed
240 241 242 243 244 245 246
}

static void
hdy_dialer_button_init (HdyDialerButton *self)
{
  HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);

247 248
  gtk_widget_init_template (GTK_WIDGET (self));

249
  priv->symbols = NULL;
Guido Gunther's avatar
Guido Gunther committed
250 251 252 253 254 255 256 257 258 259 260
}

/**
 * hdy_dialer_button_get_digit:
 * @self: a #HdyDialerButton
 *
 * Get the #HdyDialerButton's digit.
 *
 * Returns: the button's digit
 */
gint
261
hdy_dialer_button_get_digit (HdyDialerButton *self)
Guido Gunther's avatar
Guido Gunther committed
262
{
263 264
  HdyDialerButtonPrivate *priv;
  gchar *symbols;
Guido Gunther's avatar
Guido Gunther committed
265 266

  g_return_val_if_fail (HDY_IS_DIALER_BUTTON (self), -1);
267

268 269 270 271 272 273 274
  priv = hdy_dialer_button_get_instance_private(self);
  symbols = priv->symbols;

  g_return_val_if_fail (symbols != NULL, -1);
  g_return_val_if_fail (g_ascii_isdigit (*symbols), -1);

  return *symbols - '0';
Guido Gunther's avatar
Guido Gunther committed
275 276 277
}

/**
278
 * hdy_dialer_button_get_symbols:
Guido Gunther's avatar
Guido Gunther committed
279 280
 * @self: a #HdyDialerButton
 *
281
 * Get the #HdyDialerButton's symbols.
Guido Gunther's avatar
Guido Gunther committed
282
 *
283
 * Returns: the button's symbols.
Guido Gunther's avatar
Guido Gunther committed
284
 */
285
const char*
286
hdy_dialer_button_get_symbols (HdyDialerButton *self)
Guido Gunther's avatar
Guido Gunther committed
287 288 289 290
{
  HdyDialerButtonPrivate *priv = hdy_dialer_button_get_instance_private(self);

  g_return_val_if_fail (HDY_IS_DIALER_BUTTON (self), NULL);
291

292
  return priv->symbols;
Guido Gunther's avatar
Guido Gunther committed
293
}