hdy-dialer.c 20 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
 */

#include <glib/gi18n.h>

#include "hdy-dialer.h"
#include "hdy-dialer-button.h"
Guido Gunther's avatar
Guido Gunther committed
11 12
#include "hdy-dialer-cycle-button.h"
#include "hdy-string-utf8.h"
Guido Gunther's avatar
Guido Gunther committed
13 14 15

/**
 * SECTION:hdy-dialer
16
 * @short_description: A keypad for dialing numbers
Guido Gunther's avatar
Guido Gunther committed
17 18
 * @Title: HdyDialer
 *
19 20
 * The #HdyDialer widget is a keypad for entering numbers such as phone numbers
 * or PIN codes.
Guido Gunther's avatar
Guido Gunther committed
21 22 23 24
 */

typedef struct
{
25
  GtkGrid *grid;
26
  HdyDialerButton *number_btns[10];
Guido Gunther's avatar
Guido Gunther committed
27
  HdyDialerCycleButton *btn_hash, *btn_star, *cycle_btn;
28
  GtkButton *btn_submit, *btn_del;
29
  GtkGesture *long_press_del_gesture;
Guido Gunther's avatar
Guido Gunther committed
30
  GString *number;
31
  gboolean show_action_buttons;
32
  GtkReliefStyle relief;
Guido Gunther's avatar
Guido Gunther committed
33 34
} HdyDialerPrivate;

35
G_DEFINE_TYPE_WITH_PRIVATE (HdyDialer, hdy_dialer, GTK_TYPE_BIN)
Guido Gunther's avatar
Guido Gunther committed
36 37

enum {
38
  PROP_0,
Adrien Plazas's avatar
Adrien Plazas committed
39
  PROP_NUMBER,
40
  PROP_SHOW_ACTION_BUTTONS,
41 42
  PROP_COLUMN_SPACING,
  PROP_ROW_SPACING,
43
  PROP_RELIEF,
Adrien Plazas's avatar
Adrien Plazas committed
44
  PROP_LAST_PROP,
Guido Gunther's avatar
Guido Gunther committed
45
};
46
static GParamSpec *props[PROP_LAST_PROP];
Guido Gunther's avatar
Guido Gunther committed
47 48

enum {
49
  SIGNAL_SUBMITTED,
50
  SIGNAL_DELETED,
51
  SIGNAL_SYMBOL_CLICKED,
Adrien Plazas's avatar
Adrien Plazas committed
52
  SIGNAL_LAST_SIGNAL,
Guido Gunther's avatar
Guido Gunther committed
53
};
Adrien Plazas's avatar
Adrien Plazas committed
54
static guint signals [SIGNAL_LAST_SIGNAL];
Guido Gunther's avatar
Guido Gunther committed
55

Guido Gunther's avatar
Guido Gunther committed
56 57 58 59 60 61 62 63 64 65 66
static void
stop_cycle_mode (HdyDialer *self)
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);

  if (priv->cycle_btn) {
    hdy_dialer_cycle_button_stop_cycle (priv->cycle_btn);
    priv->cycle_btn = NULL;
  }
}

Guido Gunther's avatar
Guido Gunther committed
67
static void
Adrien Plazas's avatar
Adrien Plazas committed
68 69
digit_button_clicked (HdyDialer       *self,
                      HdyDialerButton *btn)
Guido Gunther's avatar
Guido Gunther committed
70 71 72 73 74 75 76
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);
  int d;

  g_return_if_fail (HDY_IS_DIALER (self));
  g_return_if_fail (HDY_IS_DIALER_BUTTON (btn));

Guido Gunther's avatar
Guido Gunther committed
77 78
  stop_cycle_mode (self);

79 80
  d = hdy_dialer_button_get_digit (btn);
  g_string_append_printf (priv->number, "%d", d);
81
  g_signal_emit(self, signals[SIGNAL_SYMBOL_CLICKED], 0, '0'+d);
82 83 84 85

  /* Notify about the number update at the very end so the clicked symbol is
     received before the notify signal */
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUMBER]);
Guido Gunther's avatar
Guido Gunther committed
86 87 88
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
89 90
cycle_button_clicked (HdyDialer            *self,
                      HdyDialerCycleButton *btn)
Guido Gunther's avatar
Guido Gunther committed
91 92
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);
Guido Gunther's avatar
Guido Gunther committed
93
  gunichar symbol;
Guido Gunther's avatar
Guido Gunther committed
94 95 96 97

  g_return_if_fail (HDY_IS_DIALER (self));
  g_return_if_fail (HDY_IS_DIALER_BUTTON (btn));

Guido Gunther's avatar
Guido Gunther committed
98 99 100
  if (priv->cycle_btn != btn) {
    stop_cycle_mode (self);
    priv->cycle_btn = btn;
101
  } else if (priv->number->len && hdy_dialer_cycle_button_is_cycling (btn)) {
Guido Gunther's avatar
Guido Gunther committed
102 103 104 105 106
    hdy_string_utf8_truncate (priv->number, hdy_string_utf8_len (priv->number)-1);
  }

  symbol = hdy_dialer_cycle_button_get_current_symbol (btn);
  g_string_append_unichar (priv->number, symbol);
107 108 109
  g_signal_emit(self,
                signals[SIGNAL_SYMBOL_CLICKED],
                0,
110
                hdy_dialer_button_get_symbols (HDY_DIALER_BUTTON (btn))[0]);
Guido Gunther's avatar
Guido Gunther committed
111

Adrien Plazas's avatar
Adrien Plazas committed
112
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUMBER]);
Guido Gunther's avatar
Guido Gunther committed
113 114
}

Guido Gunther's avatar
Guido Gunther committed
115
static void
Adrien Plazas's avatar
Adrien Plazas committed
116 117
cycle_start (HdyDialer            *self,
             HdyDialerCycleButton *btn)
Guido Gunther's avatar
Guido Gunther committed
118
{
119
  /* FIXME: emit signal */
Guido Gunther's avatar
Guido Gunther committed
120 121 122
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
123 124
cycle_end (HdyDialer            *self,
           HdyDialerCycleButton *btn)
Guido Gunther's avatar
Guido Gunther committed
125 126 127 128 129 130
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);

  /* reset cycle_btn so pressing it again produces a new character */
  if (priv->cycle_btn == btn) {
    priv->cycle_btn = NULL;
131
    /* FIXME: emit signal */
Guido Gunther's avatar
Guido Gunther committed
132 133 134
  }
}

Guido Gunther's avatar
Guido Gunther committed
135
static void
136
submit_button_clicked (HdyDialer *self,
Adrien Plazas's avatar
Adrien Plazas committed
137
                     GtkButton *btn)
Guido Gunther's avatar
Guido Gunther committed
138 139 140 141 142 143
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);

  g_return_if_fail (HDY_IS_DIALER (self));
  g_return_if_fail (GTK_IS_BUTTON (btn));

Guido Gunther's avatar
Guido Gunther committed
144 145
  stop_cycle_mode (self);

Guido Gunther's avatar
Guido Gunther committed
146
  g_signal_emit (self, signals[SIGNAL_SUBMITTED], 0, priv->number->str);
Guido Gunther's avatar
Guido Gunther committed
147 148 149
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
150 151
del_button_clicked (HdyDialer *self,
                    GtkButton *btn)
Guido Gunther's avatar
Guido Gunther committed
152 153 154 155 156 157
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);

  g_return_if_fail (HDY_IS_DIALER (self));
  g_return_if_fail (GTK_IS_BUTTON (btn));

Guido Gunther's avatar
Guido Gunther committed
158 159
  stop_cycle_mode (self);

Guido Gunther's avatar
Guido Gunther committed
160 161 162
  if (!priv->number->len)
    return;

Guido Gunther's avatar
Guido Gunther committed
163
  hdy_string_utf8_truncate (priv->number, hdy_string_utf8_len (priv->number)-1);
Adrien Plazas's avatar
Adrien Plazas committed
164
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUMBER]);
165
  g_signal_emit (self, signals[SIGNAL_DELETED], 0);
Guido Gunther's avatar
Guido Gunther committed
166 167 168
}


169 170 171 172 173
static void
press_btn (GtkButton *btn,
           gboolean   pressed)
{
  if (pressed) {
174
    gtk_widget_set_state_flags (GTK_WIDGET (btn), GTK_STATE_FLAG_CHECKED, FALSE);
175 176
    gtk_button_clicked (btn);
  } else {
177
    gtk_widget_unset_state_flags (GTK_WIDGET (btn), GTK_STATE_FLAG_CHECKED);
178 179 180 181 182 183 184 185 186 187 188
  }
}


static gboolean
key_press_event_cb (GtkWidget   *widget,
                    GdkEventKey *event,
                    gpointer     data)
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (HDY_DIALER (widget));
  gboolean pressed = !!GPOINTER_TO_INT (data);
189
  guint keyval;
190

191 192 193
  gdk_event_get_keyval ((GdkEvent *) event, &keyval);

  switch (keyval) {
194
  case GDK_KEY_0 ... GDK_KEY_9:
195
    press_btn (GTK_BUTTON (priv->number_btns[keyval % GDK_KEY_0]), pressed);
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
    break;
  case GDK_KEY_numbersign:
    press_btn (GTK_BUTTON (priv->btn_hash), pressed);
    break;
  case GDK_KEY_asterisk:
    press_btn (GTK_BUTTON (priv->btn_star), pressed);
    break;
  case GDK_KEY_Return:
    if (pressed)
      gtk_button_clicked (GTK_BUTTON (priv->btn_submit));
    break;
  case GDK_KEY_BackSpace:
    if (pressed)
      gtk_button_clicked (GTK_BUTTON (priv->btn_del));
    break;
  default:
    return FALSE;
  }
  return TRUE;
}


218 219 220 221 222 223 224 225
static void
grab_focus_cb (HdyDialer *dialer,
               gpointer   unused)
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (dialer);
  gtk_widget_grab_focus (GTK_WIDGET (priv->number_btns[0]));
}

226 227 228 229 230 231 232 233 234 235 236 237
static void
long_press_del_cb (GtkGestureLongPress *gesture,
                   gdouble              x,
                   gdouble              y,
                   HdyDialer           *self)
{
  stop_cycle_mode (self);
  hdy_dialer_clear_number (self);

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUMBER]);
  g_signal_emit (self, signals[SIGNAL_DELETED], 0);
}
238

Guido Gunther's avatar
Guido Gunther committed
239 240 241
static void
hdy_dialer_finalize (GObject *object)
{
242
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (HDY_DIALER (object));
Guido Gunther's avatar
Guido Gunther committed
243 244

  g_string_free (priv->number, TRUE);
245
  g_object_unref (priv->long_press_del_gesture);
Guido Gunther's avatar
Guido Gunther committed
246

247
  G_OBJECT_CLASS (hdy_dialer_parent_class)->finalize (object);
Guido Gunther's avatar
Guido Gunther committed
248 249 250
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
251 252 253 254
hdy_dialer_set_property (GObject      *object,
                         guint         property_id,
                         const GValue *value,
                         GParamSpec   *pspec)
Guido Gunther's avatar
Guido Gunther committed
255 256
{
  HdyDialer *self = HDY_DIALER (object);
257
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);
Guido Gunther's avatar
Guido Gunther committed
258 259

  switch (property_id) {
260 261 262 263
  case PROP_COLUMN_SPACING:
    gtk_grid_set_column_spacing (priv->grid, g_value_get_uint (value));
    break;

Adrien Plazas's avatar
Adrien Plazas committed
264
  case PROP_NUMBER:
265
    g_string_assign (priv->number, g_value_get_string (value));
266
    g_object_notify_by_pspec (object, pspec);
Guido Gunther's avatar
Guido Gunther committed
267 268
    break;

269 270 271 272
  case PROP_ROW_SPACING:
    gtk_grid_set_row_spacing (priv->grid, g_value_get_uint (value));
    break;

273 274 275 276 277
  case PROP_SHOW_ACTION_BUTTONS:
    hdy_dialer_set_show_action_buttons
      (self, g_value_get_boolean (value));
    break;

278 279 280 281
  case PROP_RELIEF:
    hdy_dialer_set_relief (self, g_value_get_enum (value));
    break;

Guido Gunther's avatar
Guido Gunther committed
282 283 284 285 286 287 288
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
289 290 291 292
hdy_dialer_get_property (GObject    *object,
                         guint       property_id,
                         GValue     *value,
                         GParamSpec *pspec)
Guido Gunther's avatar
Guido Gunther committed
293 294
{
  HdyDialer *self = HDY_DIALER (object);
295
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);
Guido Gunther's avatar
Guido Gunther committed
296 297

  switch (property_id) {
298 299 300 301
  case PROP_COLUMN_SPACING:
    g_value_set_uint (value, gtk_grid_get_column_spacing (priv->grid));
    break;

Adrien Plazas's avatar
Adrien Plazas committed
302
  case PROP_NUMBER:
Guido Gunther's avatar
Guido Gunther committed
303 304 305
    g_value_set_string (value, priv->number->str);
    break;

306 307 308 309
  case PROP_ROW_SPACING:
    g_value_set_uint (value, gtk_grid_get_row_spacing (priv->grid));
    break;

310 311 312 313
  case PROP_SHOW_ACTION_BUTTONS:
    g_value_set_boolean (value, priv->show_action_buttons);
    break;

314 315 316 317
  case PROP_RELIEF:
    g_value_set_enum (value, hdy_dialer_get_relief (self));
    break;

Guido Gunther's avatar
Guido Gunther committed
318 319 320 321 322 323 324 325
  default:
    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    break;
  }
}


static void
326
hdy_dialer_constructed (GObject *object)
Guido Gunther's avatar
Guido Gunther committed
327
{
328
  HdyDialer *self = HDY_DIALER (object);
Guido Gunther's avatar
Guido Gunther committed
329 330 331
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);
  GtkWidget *image;

332 333 334 335 336 337 338
  for (int i = 0; i < 10; i++) {
    g_signal_connect_object (priv->number_btns[i],
                             "clicked",
                             G_CALLBACK (digit_button_clicked),
                             self,
                             G_CONNECT_SWAPPED);
  }
Guido Gunther's avatar
Guido Gunther committed
339

340 341 342 343 344
  priv->long_press_del_gesture = gtk_gesture_long_press_new (GTK_WIDGET (priv->btn_del));
  g_signal_connect (priv->long_press_del_gesture, "pressed",
                    G_CALLBACK (long_press_del_cb), self);
  gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (priv->long_press_del_gesture),
                                              GTK_PHASE_BUBBLE);
Guido Gunther's avatar
Guido Gunther committed
345
  g_object_connect (priv->btn_star,
Adrien Plazas's avatar
Adrien Plazas committed
346 347 348 349
                    "swapped-signal::clicked", G_CALLBACK (cycle_button_clicked), self,
                    "swapped-signal::cycle-start", G_CALLBACK (cycle_start), self,
                    "swapped-signal::cycle-end", G_CALLBACK (cycle_end), self,
                    NULL);
Guido Gunther's avatar
Guido Gunther committed
350 351

  g_object_connect (priv->btn_hash,
Adrien Plazas's avatar
Adrien Plazas committed
352 353 354 355
                    "swapped-signal::clicked", G_CALLBACK (cycle_button_clicked), self,
                    "swapped-signal::cycle-start", G_CALLBACK (cycle_start), self,
                    "swapped-signal::cycle-end", G_CALLBACK (cycle_end), self,
                    NULL);
Guido Gunther's avatar
Guido Gunther committed
356

357
  g_signal_connect_object (priv->btn_submit,
Guido Gunther's avatar
Guido Gunther committed
358
                           "clicked",
359
                           G_CALLBACK (submit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
360 361 362
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_del,
Adrien Plazas's avatar
Adrien Plazas committed
363 364
                           "clicked",
                           G_CALLBACK (del_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
365 366 367 368 369
                           self,
                           G_CONNECT_SWAPPED);

  /* In GTK+4 we can just use the icon-name property */
  image = gtk_image_new_from_icon_name ("edit-clear-symbolic",
Adrien Plazas's avatar
Adrien Plazas committed
370
                                        GTK_ICON_SIZE_BUTTON);
371
  gtk_button_set_image (priv->btn_del, image);
Guido Gunther's avatar
Guido Gunther committed
372

373
  image = gtk_image_new_from_icon_name ("call-start-symbolic",
Adrien Plazas's avatar
Adrien Plazas committed
374
                                        GTK_ICON_SIZE_BUTTON * 1.3);
375
  gtk_button_set_image (priv->btn_submit, image);
376

377
  /* Keyboard and focus handling */
378 379 380 381 382 383 384 385 386
  gtk_widget_set_events (GTK_WIDGET (self), GDK_KEY_PRESS_MASK);
  g_signal_connect (G_OBJECT (self),
                    "key_press_event",
                    G_CALLBACK (key_press_event_cb),
                    GINT_TO_POINTER(TRUE));
  g_signal_connect (G_OBJECT (self),
                    "key_release_event",
                    G_CALLBACK (key_press_event_cb),
                    GINT_TO_POINTER(FALSE));
387 388 389 390
  g_signal_connect (G_OBJECT (self),
                    "grab-focus",
                    G_CALLBACK (grab_focus_cb),
                    NULL);
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
}


static void
hdy_dialer_class_init (HdyDialerClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  object_class->constructed = hdy_dialer_constructed;
  object_class->finalize = hdy_dialer_finalize;

  object_class->set_property = hdy_dialer_set_property;
  object_class->get_property = hdy_dialer_get_property;

  props[PROP_NUMBER] =
    g_param_spec_string ("number",
                         _("Number"),
                         _("The phone number to dial"),
                         "",
                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

413 414 415 416 417 418 419
  props[PROP_SHOW_ACTION_BUTTONS] =
    g_param_spec_boolean ("show-action-buttons",
                         _("Show action buttons"),
                         _("Whether to show the submit and delete buttons"),
                         TRUE,
                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

420 421 422 423 424 425 426 427 428 429 430 431 432 433
  props[PROP_COLUMN_SPACING] =
    g_param_spec_uint ("column-spacing",
                       _("Column spacing"),
                         _("The amount of space between two consecutive columns"),
                         0, G_MAXUINT, 0,
                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

  props[PROP_ROW_SPACING] =
    g_param_spec_uint ("row-spacing",
                       _("Row spacing"),
                         _("The amount of space between two consecutive rows"),
                         0, G_MAXUINT, 0,
                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

434 435 436 437 438 439 440 441 442 443 444 445 446
  /**
   * HdyDialer:relief:
   *
   * The relief style of the edges of the main buttons.
   */
  props[PROP_RELIEF] =
    g_param_spec_enum ("relief",
                       _("Main buttons' border relief"),
                       _("The border relief style of the main buttons"),
                       GTK_TYPE_RELIEF_STYLE,
                       GTK_RELIEF_NORMAL,
                       G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
  g_object_class_install_properties (object_class, PROP_LAST_PROP, props);

  /**
   * HdyDialer::submitted:
   * @self: The #HdyDialer instance.
   * @number: The number at the time of activation.
   *
   * This signal is emitted when the dialer's 'dial' button is activated.
   * Connect to this signal to perform to get notified when the user
   * wants to submit the dialed number.
   */
  signals[SIGNAL_SUBMITTED] =
    g_signal_new ("submitted",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (HdyDialerClass, submitted),
                  NULL, NULL, NULL,
                  G_TYPE_NONE,
                  1,
                  G_TYPE_STRING);

468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483
  /**
   * HdyDialer::deleted:
   * @self: The #HdyDialer instance.
   *
   * This signal is emitted when the dialer's 'deleted' button is clicked
   * to delete the last symbol.
   */
  signals[SIGNAL_DELETED] =
    g_signal_new ("deleted",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (HdyDialerClass, submitted),
                  NULL, NULL, NULL,
                  G_TYPE_NONE,
                  0);

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
  /**
   * HdyDialer::symbol-clicked:
   * @self: The #HdyDialer instance.
   * @button: The main symbol on the button that was clicked
   *
   * This signal is emitted when one of the symbol buttons (0-9, # or *)
   * is clicked. Connect to this signal to find out which button was pressed.
   * This doesn't take any cycling modes into account. So the button with "*"
   * and "+" on it will always send "*".  Delete and Submit buttons will
   * not trigger this signal.
   */
  signals[SIGNAL_SYMBOL_CLICKED] =
    g_signal_new ("symbol-clicked",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  NULL, NULL, NULL,
                  G_TYPE_NONE,
                  1,
                  G_TYPE_CHAR);

505 506
  gtk_widget_class_set_template_from_resource (widget_class,
                                               "/sm/puri/handy/dialer/ui/hdy-dialer.ui");
507 508 509 510 511 512 513 514
  for (int i=0; i < 10; i++) {
    g_autofree gchar *name = g_strdup_printf("btn_%d", i);
    g_return_if_fail (name);
    gtk_widget_class_bind_template_child_full (widget_class,
                                               name,
                                               FALSE,
                                               G_PRIVATE_OFFSET(HdyDialer, number_btns[i]));
  }
515
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, grid);
516 517 518 519
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_hash);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_star);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_submit);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_del);
520

Adrien Plazas's avatar
Adrien Plazas committed
521
  gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_DIAL);
522
  gtk_widget_class_set_css_name (widget_class, "hdydialer");
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
}

/**
 * hdy_dialer_new:
 *
 * Create a new #HdyDialer widget.
 *
 * Returns: the newly created #HdyDialer widget
 *
 */
GtkWidget *hdy_dialer_new (void)
{
  return g_object_new (HDY_TYPE_DIALER, NULL);
}

static void
hdy_dialer_init (HdyDialer *self)
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);

  gtk_widget_init_template (GTK_WIDGET (self));
544 545 546
  g_object_bind_property (self, "relief",
                          priv->number_btns[0], "relief",
                          G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
Guido Gunther's avatar
Guido Gunther committed
547

548
  priv->number = g_string_new (NULL);
Guido Gunther's avatar
Guido Gunther committed
549
  priv->cycle_btn = NULL;
Guido Gunther's avatar
Guido Gunther committed
550 551 552 553 554 555 556 557 558 559
}

/**
 * hdy_dialer_get_number:
 * @self: a #HdyDialer
 *
 * Get the currently displayed number.
 *
 * Returns: (transfer none): the current number in the display
 */
560
const gchar *
561
hdy_dialer_get_number (HdyDialer *self)
Guido Gunther's avatar
Guido Gunther committed
562
{
563 564 565 566 567
  HdyDialerPrivate *priv;

  g_return_val_if_fail (HDY_IS_DIALER (self), NULL);

  priv = hdy_dialer_get_instance_private (self);
Guido Gunther's avatar
Guido Gunther committed
568 569 570 571 572 573
  return priv->number->str;
}

/**
 * hdy_dialer_set_number:
 * @self: a #HdyDialer
574
 * @number: (transfer none): the number to set
Guido Gunther's avatar
Guido Gunther committed
575 576 577 578 579
 *
 * Set the currently displayed number.
 *
 */
void
580 581
hdy_dialer_set_number (HdyDialer   *self,
                       const gchar *number)
Guido Gunther's avatar
Guido Gunther committed
582
{
583 584 585
  HdyDialerPrivate *priv;

  g_return_if_fail (HDY_IS_DIALER (self));
586
  g_return_if_fail (number != NULL);
587 588

  priv = hdy_dialer_get_instance_private (self);
Guido Gunther's avatar
Guido Gunther committed
589

590
  g_string_assign (priv->number, number);
Adrien Plazas's avatar
Adrien Plazas committed
591
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUMBER]);
Guido Gunther's avatar
Guido Gunther committed
592
}
593

594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
/**
 * hdy_dialer_clear_number:
 * @self: a #HdyDialer
 *
 * Set the current number to the empty string. When the number is already
 * cleared no action is performed.
 *
 */
void
hdy_dialer_clear_number (HdyDialer   *self)
{
  HdyDialerPrivate *priv;

  g_return_if_fail (HDY_IS_DIALER (self));

  priv = hdy_dialer_get_instance_private (self);
  if (g_strcmp0(priv->number->str, "")) {
    hdy_dialer_set_number (self, "");
  }
}

615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
/**
 * hdy_dialer_get_show_action_buttons:
 * @self: a #HdyDialer
 *
 * Get whether the submit and delete buttons are to be shown.
 *
 * Returns: whether the buttons are to be shown
 */
gboolean
hdy_dialer_get_show_action_buttons (HdyDialer *self)
{
  HdyDialerPrivate *priv;

  g_return_val_if_fail (HDY_IS_DIALER (self), FALSE);

  priv = hdy_dialer_get_instance_private (self);
  return priv->show_action_buttons;
}


/**
 * hdy_dialer_set_show_action_buttons:
 * @self: a #HdyDialer
 * @show: whether to show the buttons
 *
 * Set whether to show the submit and delete buttons.
 *
 */
void
hdy_dialer_set_show_action_buttons (HdyDialer *self,
                                    gboolean   show)
{
  HdyDialerPrivate *priv;

  g_return_if_fail (HDY_IS_DIALER (self));

  priv = hdy_dialer_get_instance_private (self);
  priv->show_action_buttons = show;

  gtk_widget_set_visible (GTK_WIDGET (priv->btn_submit), show);
  gtk_widget_set_visible (GTK_WIDGET (priv->btn_del), show);

  g_object_notify_by_pspec
    (G_OBJECT (self), props[PROP_SHOW_ACTION_BUTTONS]);
}
660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707

/**
 * hdy_dialer_set_relief:
 * @self: The #HdyDialer whose main buttons you want to set relief styles of
 * @relief: The #GtkReliefStyle as described above
 *
 * Sets the relief style of the edges of the main buttons for the given
 * #HdyDialer widget.
 * Two styles exist, %GTK_RELIEF_NORMAL and %GTK_RELIEF_NONE.
 * The default style is, as one can guess, %GTK_RELIEF_NORMAL.
 */
void
hdy_dialer_set_relief (HdyDialer      *self,
                       GtkReliefStyle  relief)
{
  HdyDialerPrivate *priv;

  g_return_if_fail (HDY_IS_DIALER (self));

  priv = hdy_dialer_get_instance_private (self);

  if (priv->relief == relief)
    return;

  priv->relief = relief;
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_RELIEF]);
}

/**
 * hdy_dialer_get_relief:
 * @self: The #HdyDialer whose main buttons you want the #GtkReliefStyle from
 *
 * Returns the current relief style of the main buttons for the given
 * #HdyDialer.
 *
 * Returns: The current #GtkReliefStyle
 */
GtkReliefStyle
hdy_dialer_get_relief (HdyDialer *self)
{
  HdyDialerPrivate *priv;

  g_return_val_if_fail (HDY_IS_DIALER (self), GTK_RELIEF_NORMAL);

  priv = hdy_dialer_get_instance_private (self);

  return priv->relief;
}