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

typedef struct
{
  HdyDialerButton *btn_0, *btn_1, *btn_2, *btn_3, *btn_4, *btn_5, *btn_6, *btn_7, *btn_8, *btn_9;
Guido Gunther's avatar
Guido Gunther committed
26
  HdyDialerCycleButton *btn_hash, *btn_star, *cycle_btn;
27
  GtkButton *btn_submit, *btn_del;
Guido Gunther's avatar
Guido Gunther committed
28 29 30 31 32 33
  GString *number;
} HdyDialerPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (HdyDialer, hdy_dialer, GTK_TYPE_GRID)

enum {
34
  PROP_0,
Adrien Plazas's avatar
Adrien Plazas committed
35 36
  PROP_NUMBER,
  PROP_LAST_PROP,
Guido Gunther's avatar
Guido Gunther committed
37
};
38
static GParamSpec *props[PROP_LAST_PROP];
Guido Gunther's avatar
Guido Gunther committed
39 40

enum {
41
  SIGNAL_SUBMITTED,
Adrien Plazas's avatar
Adrien Plazas committed
42
  SIGNAL_LAST_SIGNAL,
Guido Gunther's avatar
Guido Gunther committed
43
};
Adrien Plazas's avatar
Adrien Plazas committed
44
static guint signals [SIGNAL_LAST_SIGNAL];
Guido Gunther's avatar
Guido Gunther committed
45

Guido Gunther's avatar
Guido Gunther committed
46 47 48 49 50 51 52 53 54 55 56
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
57
static void
Adrien Plazas's avatar
Adrien Plazas committed
58 59
digit_button_clicked (HdyDialer       *self,
                      HdyDialerButton *btn)
Guido Gunther's avatar
Guido Gunther committed
60 61 62 63 64 65 66
{
  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
67 68
  stop_cycle_mode (self);

69 70
  d = hdy_dialer_button_get_digit (btn);
  g_string_append_printf (priv->number, "%d", d);
Adrien Plazas's avatar
Adrien Plazas committed
71
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUMBER]);
Guido Gunther's avatar
Guido Gunther committed
72 73 74
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
75 76
cycle_button_clicked (HdyDialer            *self,
                      HdyDialerCycleButton *btn)
Guido Gunther's avatar
Guido Gunther committed
77 78
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);
Guido Gunther's avatar
Guido Gunther committed
79
  gunichar symbol;
Guido Gunther's avatar
Guido Gunther committed
80 81 82 83

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

Guido Gunther's avatar
Guido Gunther committed
84 85 86
  if (priv->cycle_btn != btn) {
    stop_cycle_mode (self);
    priv->cycle_btn = btn;
87
  } else if (priv->number->len && hdy_dialer_cycle_button_is_cycling (btn)) {
Guido Gunther's avatar
Guido Gunther committed
88 89 90 91 92 93
    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);

Adrien Plazas's avatar
Adrien Plazas committed
94
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUMBER]);
Guido Gunther's avatar
Guido Gunther committed
95 96
}

Guido Gunther's avatar
Guido Gunther committed
97
static void
Adrien Plazas's avatar
Adrien Plazas committed
98 99
cycle_start (HdyDialer            *self,
             HdyDialerCycleButton *btn)
Guido Gunther's avatar
Guido Gunther committed
100 101 102 103 104
{
  /* FIXME: change cursor */
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
105 106
cycle_end (HdyDialer            *self,
           HdyDialerCycleButton *btn)
Guido Gunther's avatar
Guido Gunther committed
107 108 109 110 111 112 113 114 115 116
{
  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;
    /* FIXME: change cursor */
  }
}

Guido Gunther's avatar
Guido Gunther committed
117
static void
118
submit_button_clicked (HdyDialer *self,
Adrien Plazas's avatar
Adrien Plazas committed
119
                     GtkButton *btn)
Guido Gunther's avatar
Guido Gunther committed
120 121 122 123 124 125
{
  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
126 127
  stop_cycle_mode (self);

Guido Gunther's avatar
Guido Gunther committed
128
  g_signal_emit (self, signals[SIGNAL_SUBMITTED], 0, priv->number->str);
Guido Gunther's avatar
Guido Gunther committed
129 130 131
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
132 133
del_button_clicked (HdyDialer *self,
                    GtkButton *btn)
Guido Gunther's avatar
Guido Gunther committed
134 135 136 137 138 139
{
  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
140 141
  stop_cycle_mode (self);

Guido Gunther's avatar
Guido Gunther committed
142 143 144
  if (!priv->number->len)
    return;

Guido Gunther's avatar
Guido Gunther committed
145
  hdy_string_utf8_truncate (priv->number, hdy_string_utf8_len (priv->number)-1);
Adrien Plazas's avatar
Adrien Plazas committed
146
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUMBER]);
Guido Gunther's avatar
Guido Gunther committed
147 148 149 150 151 152
}


static void
hdy_dialer_finalize (GObject *object)
{
153
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (HDY_DIALER (object));
Guido Gunther's avatar
Guido Gunther committed
154 155 156

  g_string_free (priv->number, TRUE);

157
  G_OBJECT_CLASS (hdy_dialer_parent_class)->finalize (object);
Guido Gunther's avatar
Guido Gunther committed
158 159 160
}

static void
Adrien Plazas's avatar
Adrien Plazas committed
161 162 163 164
hdy_dialer_set_property (GObject      *object,
                         guint         property_id,
                         const GValue *value,
                         GParamSpec   *pspec)
Guido Gunther's avatar
Guido Gunther committed
165 166
{
  HdyDialer *self = HDY_DIALER (object);
167
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);
Guido Gunther's avatar
Guido Gunther committed
168 169

  switch (property_id) {
Adrien Plazas's avatar
Adrien Plazas committed
170
  case PROP_NUMBER:
171
    g_string_overwrite (priv->number, 0, g_value_get_string (value));
Guido Gunther's avatar
Guido Gunther committed
172 173 174 175 176 177 178 179 180
    break;

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

static void
Adrien Plazas's avatar
Adrien Plazas committed
181 182 183 184
hdy_dialer_get_property (GObject    *object,
                         guint       property_id,
                         GValue     *value,
                         GParamSpec *pspec)
Guido Gunther's avatar
Guido Gunther committed
185 186
{
  HdyDialer *self = HDY_DIALER (object);
187
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);
Guido Gunther's avatar
Guido Gunther committed
188 189

  switch (property_id) {
Adrien Plazas's avatar
Adrien Plazas committed
190
  case PROP_NUMBER:
Guido Gunther's avatar
Guido Gunther committed
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
    g_value_set_string (value, priv->number->str);
    break;

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

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

  object_class->finalize = hdy_dialer_finalize;

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

Adrien Plazas's avatar
Adrien Plazas committed
211 212 213 214 215 216 217 218 219
  props[PROP_NUMBER] =
    g_param_spec_string ("number",
                         _("Number"),
                         _("The phone number to dial"),
                         "",
                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (object_class, PROP_LAST_PROP, props);

Guido Gunther's avatar
Guido Gunther committed
220
  /**
221
   * HdyDialer::submitted:
Guido Gunther's avatar
Guido Gunther committed
222 223 224
   * @self: The #HdyDialer instance.
   * @number: The number at the time of activation.
   *
225 226 227
   * 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.
Guido Gunther's avatar
Guido Gunther committed
228
   */
229 230
  signals[SIGNAL_SUBMITTED] =
    g_signal_new ("submitted",
Guido Gunther's avatar
Guido Gunther committed
231 232
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
233
                  G_STRUCT_OFFSET (HdyDialerClass, submitted),
Guido Gunther's avatar
Guido Gunther committed
234 235 236 237 238 239
                  NULL, NULL, NULL,
                  G_TYPE_NONE,
                  1,
                  G_TYPE_STRING);

  gtk_widget_class_set_template_from_resource (widget_class,
Adrien Plazas's avatar
Adrien Plazas committed
240
                                               "/sm/puri/handy/dialer/ui/hdy-dialer.ui");
Guido Gunther's avatar
Guido Gunther committed
241 242 243 244 245 246 247 248 249 250 251 252
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_0);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_1);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_2);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_3);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_4);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_5);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_6);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_7);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_8);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_9);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_hash);
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_star);
253
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_submit);
Guido Gunther's avatar
Guido Gunther committed
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
  gtk_widget_class_bind_template_child_private (widget_class, HdyDialer, btn_del);
}

/**
 * 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);
  GtkWidget *image;

  gtk_widget_init_template (GTK_WIDGET (self));
  g_signal_connect_object (priv->btn_0,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
279
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
280 281 282 283
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_1,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
284
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
285 286 287 288
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_2,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
289
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
290 291 292 293
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_3,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
294
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
295 296 297 298
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_4,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
299
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
300 301 302 303
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_5,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
304
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
305 306 307 308
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_6,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
309
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
310 311 312 313
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_7,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
314
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
315 316 317 318
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_8,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
319
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
320 321 322 323
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_9,
                           "clicked",
Adrien Plazas's avatar
Adrien Plazas committed
324
                           G_CALLBACK (digit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
325 326
                           self,
                           G_CONNECT_SWAPPED);
Guido Gunther's avatar
Guido Gunther committed
327 328

  g_object_connect (priv->btn_star,
Adrien Plazas's avatar
Adrien Plazas committed
329 330 331 332
                    "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
333 334

  g_object_connect (priv->btn_hash,
Adrien Plazas's avatar
Adrien Plazas committed
335 336 337 338
                    "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
339

340
  g_signal_connect_object (priv->btn_submit,
Guido Gunther's avatar
Guido Gunther committed
341
                           "clicked",
342
                           G_CALLBACK (submit_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
343 344 345
                           self,
                           G_CONNECT_SWAPPED);
  g_signal_connect_object (priv->btn_del,
Adrien Plazas's avatar
Adrien Plazas committed
346 347
                           "clicked",
                           G_CALLBACK (del_button_clicked),
Guido Gunther's avatar
Guido Gunther committed
348 349 350 351 352
                           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
353
                                        GTK_ICON_SIZE_BUTTON);
354
  gtk_button_set_image (priv->btn_del, image);
Guido Gunther's avatar
Guido Gunther committed
355 356

  gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (),
357
                                    "/sm/puri/handy/icons");
Guido Gunther's avatar
Guido Gunther committed
358
  image = gtk_image_new_from_icon_name ("phone-dial-symbolic",
Adrien Plazas's avatar
Adrien Plazas committed
359
                                        GTK_ICON_SIZE_BUTTON * 1.3);
360
  gtk_button_set_image (priv->btn_submit, image);
Guido Gunther's avatar
Guido Gunther committed
361

362
  priv->number = g_string_new (NULL);
Guido Gunther's avatar
Guido Gunther committed
363
  priv->cycle_btn = NULL;
Guido Gunther's avatar
Guido Gunther committed
364 365 366 367 368 369 370 371 372 373 374
}

/**
 * hdy_dialer_get_number:
 * @self: a #HdyDialer
 *
 * Get the currently displayed number.
 *
 * Returns: (transfer none): the current number in the display
 */
const char*
375
hdy_dialer_get_number (HdyDialer *self)
Guido Gunther's avatar
Guido Gunther committed
376 377 378 379 380 381 382 383 384 385 386 387 388 389
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);
  return priv->number->str;
}

/**
 * hdy_dialer_set_number:
 * @self: a #HdyDialer
 * @newnumber: (transfer none): the number to set
 *
 * Set the currently displayed number.
 *
 */
void
390 391
hdy_dialer_set_number (HdyDialer  *self,
                       const char *newnumber)
Guido Gunther's avatar
Guido Gunther committed
392 393 394
{
  HdyDialerPrivate *priv = hdy_dialer_get_instance_private (self);

395
  g_string_overwrite (priv->number, 0, newnumber);
Adrien Plazas's avatar
Adrien Plazas committed
396
  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_NUMBER]);
Guido Gunther's avatar
Guido Gunther committed
397
}