diff --git a/src/calls-new-call-box.c b/src/calls-new-call-box.c
new file mode 100644
index 0000000..b3c6ceb
--- /dev/null
+++ b/src/calls-new-call-box.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2018 Purism SPC
+ *
+ * This file is part of Calls.
+ *
+ * Calls is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calls 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calls. If not, see .
+ *
+ * Author: Adrien Plazas
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#include "calls-new-call-box.h"
+
+#include "calls-origin.h"
+
+#include
+#define HANDY_USE_UNSTABLE_API
+#include
+
+
+struct _CallsNewCallBox
+{
+ GtkBox parent_instance;
+
+ GtkComboBox *origin_box;
+ GtkSearchEntry *number_entry;
+ HdyDialer *dial_pad;
+
+ gulong origin_store_row_deleted_id;
+ gulong origin_store_row_inserted_id;
+};
+
+G_DEFINE_TYPE (CallsNewCallBox, calls_new_call_box, GTK_TYPE_BOX);
+
+
+enum {
+ PROP_0,
+ PROP_ORIGIN_STORE,
+ PROP_LAST_PROP,
+};
+static GParamSpec *props[PROP_LAST_PROP];
+
+
+enum {
+ SIGNAL_SUBMITTED,
+ SIGNAL_LAST_SIGNAL,
+};
+static guint signals[SIGNAL_LAST_SIGNAL];
+
+
+enum {
+ ORIGIN_STORE_COLUMN_NAME,
+ ORIGIN_STORE_COLUMN_ORIGIN
+};
+
+
+static void
+dial_pad_symbol_clicked_cb (CallsNewCallBox *self,
+ gchar symbol,
+ HdyDialer *dialer)
+{
+ GtkEntryBuffer *buf = gtk_entry_get_buffer (GTK_ENTRY (self->number_entry));
+ guint len = gtk_entry_buffer_get_length (buf);
+
+ gtk_entry_buffer_insert_text (buf, len, &symbol, 1);
+}
+
+
+static void
+dial_pad_deleted_cb (CallsNewCallBox *self,
+ HdyDialer *dialer)
+{
+ GtkEntryBuffer *buf = gtk_entry_get_buffer (GTK_ENTRY (self->number_entry));
+ guint len = gtk_entry_buffer_get_length (buf);
+
+ gtk_entry_buffer_delete_text (buf, len - 1, 1);
+}
+
+
+static void
+dial_clicked_cb (CallsNewCallBox *self,
+ const gchar *unused,
+ GtkButton *button)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *origin_store;
+ CallsOrigin *origin;
+ const gchar *number;
+
+ gtk_combo_box_get_active_iter (self->origin_box, &iter);
+ if (!gtk_combo_box_get_active_iter (self->origin_box, &iter))
+ {
+ g_debug ("Can't submit call with no origin.");
+
+ return;
+ }
+
+ origin_store = gtk_combo_box_get_model (self->origin_box);
+ gtk_tree_model_get (origin_store, &iter,
+ ORIGIN_STORE_COLUMN_ORIGIN, &origin,
+ -1);
+ g_assert (CALLS_IS_ORIGIN (origin));
+
+ number = gtk_entry_get_text (GTK_ENTRY (self->number_entry));
+
+ g_signal_emit (self, signals[SIGNAL_SUBMITTED], 0, origin, number);
+}
+
+
+void
+update_origin_box (CallsNewCallBox *self)
+{
+ GtkTreeModel *origin_store = gtk_combo_box_get_model (self->origin_box);
+ GtkTreeIter iter;
+
+ if (origin_store == NULL ||
+ !gtk_tree_model_get_iter_first (origin_store, &iter))
+ {
+ gtk_widget_hide (GTK_WIDGET (self->origin_box));
+
+ return;
+ }
+
+ /* We know there is a model and it's not empty. */
+
+ if (!gtk_tree_model_iter_next (origin_store, &iter))
+ {
+ gtk_combo_box_set_active (self->origin_box, 0);
+ gtk_widget_hide (GTK_WIDGET (self->origin_box));
+
+ return;
+ }
+
+ /* We know there are multiple origins in the model. */
+
+ if (gtk_combo_box_get_active (self->origin_box) < 0)
+ {
+ gtk_combo_box_set_active (self->origin_box, 0);
+ }
+
+ /* We know there are multiple origins and one is selected. */
+
+ gtk_widget_show (GTK_WIDGET (self->origin_box));
+}
+
+
+static void
+calls_new_call_box_set_origin_store (CallsNewCallBox *self,
+ GtkListStore *origin_store)
+{
+ g_return_if_fail (CALLS_IS_NEW_CALL_BOX (self));
+ g_return_if_fail (origin_store == NULL || GTK_IS_LIST_STORE (origin_store));
+
+ if (self->origin_store_row_deleted_id != 0)
+ {
+ g_signal_handler_disconnect (gtk_combo_box_get_model (self->origin_box),
+ self->origin_store_row_deleted_id);
+ g_signal_handler_disconnect (gtk_combo_box_get_model (self->origin_box),
+ self->origin_store_row_inserted_id);
+ }
+
+ gtk_combo_box_set_model (self->origin_box, GTK_TREE_MODEL (origin_store));
+
+ if (origin_store != NULL)
+ {
+ self->origin_store_row_deleted_id = g_signal_connect_swapped (origin_store, "row-deleted", G_CALLBACK (update_origin_box), self);
+ self->origin_store_row_inserted_id = g_signal_connect_swapped (origin_store, "row-inserted", G_CALLBACK (update_origin_box), self);
+ }
+ else
+ {
+ self->origin_store_row_deleted_id = 0;
+ self->origin_store_row_inserted_id = 0;
+ }
+}
+
+
+static void
+calls_new_call_box_init (CallsNewCallBox *self)
+{
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ update_origin_box (self);
+}
+
+
+static void
+calls_new_call_box_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ CallsNewCallBox *self = CALLS_NEW_CALL_BOX (object);
+
+ switch (property_id)
+ {
+ case PROP_ORIGIN_STORE:
+ calls_new_call_box_set_origin_store (self, g_value_get_object (value));
+ g_object_notify_by_pspec (object, pspec);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+static void
+calls_new_call_box_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ CallsNewCallBox *self = CALLS_NEW_CALL_BOX (object);
+
+ switch (property_id)
+ {
+ case PROP_ORIGIN_STORE:
+ g_value_set_object (value, gtk_combo_box_get_model (self->origin_box));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+static void
+calls_new_call_box_class_init (CallsNewCallBoxClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->set_property = calls_new_call_box_set_property;
+ object_class->get_property = calls_new_call_box_get_property;
+
+ props[PROP_ORIGIN_STORE] =
+ g_param_spec_object ("origin-store",
+ _("Origin store"),
+ _("The storage for origins"),
+ GTK_TYPE_LIST_STORE,
+ G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
+ g_object_class_install_properties (object_class, PROP_LAST_PROP, props);
+
+ /**
+ * CallsNewCallBox::submitted:
+ * @self: The # CallsNewCallBox instance.
+ * @origin: The origin of the call.
+ * @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 for a given call origin.
+ */
+ signals[SIGNAL_SUBMITTED] =
+ g_signal_new ("submitted",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE,
+ 2,
+ CALLS_TYPE_ORIGIN,
+ G_TYPE_STRING);
+
+ gtk_widget_class_set_template_from_resource (widget_class, "/sm/puri/calls/ui/new-call-box.ui");
+ gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, origin_box);
+ gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, number_entry);
+ gtk_widget_class_bind_template_child (widget_class, CallsNewCallBox, dial_pad);
+ gtk_widget_class_bind_template_callback (widget_class, dial_clicked_cb);
+ gtk_widget_class_bind_template_callback (widget_class, dial_pad_deleted_cb);
+ gtk_widget_class_bind_template_callback (widget_class, dial_pad_symbol_clicked_cb);
+}
diff --git a/src/calls-new-call-box.h b/src/calls-new-call-box.h
new file mode 100644
index 0000000..7e7b06f
--- /dev/null
+++ b/src/calls-new-call-box.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 Purism SPC
+ *
+ * This file is part of Calls.
+ *
+ * Calls is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Calls 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Calls. If not, see .
+ *
+ * Author: Adrien Plazas
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#ifndef CALLS_NEW_CALL_BOX_H__
+#define CALLS_NEW_CALL_BOX_H__
+
+#include
+
+G_BEGIN_DECLS
+
+#define CALLS_TYPE_NEW_CALL_BOX (calls_new_call_box_get_type ())
+
+G_DECLARE_FINAL_TYPE (CallsNewCallBox, calls_new_call_box, CALLS, NEW_CALL_BOX, GtkBox);
+
+G_END_DECLS
+
+#endif /* CALLS_NEW_CALL_BOX_H__ */
diff --git a/src/calls.gresources.xml b/src/calls.gresources.xml
index b813dae..355bfc8 100644
--- a/src/calls.gresources.xml
+++ b/src/calls.gresources.xml
@@ -6,5 +6,6 @@
call-selector-item.ui
encryption-indicator.ui
history-box.ui
+ new-call-box.ui
diff --git a/src/meson.build b/src/meson.build
index 8d53d23..2a215b1 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -47,6 +47,7 @@ calls_sources = ['calls-message-source.c', 'calls-message-source.h',
'calls-call-selector-item.c', 'calls-call-selector-item.h',
'calls-encryption-indicator.c', 'calls-encryption-indicator.h',
'calls-history-box.c', 'calls-history-box.h',
+ 'calls-new-call-box.c', 'calls-new-call-box.h',
'calls-main-window.c', 'calls-main-window.h',
'util.c', 'util.h',
]
diff --git a/src/ui/new-call-box.ui b/src/ui/new-call-box.ui
new file mode 100644
index 0000000..839b904
--- /dev/null
+++ b/src/ui/new-call-box.ui
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+ False
+ center
+ 16
+ 24
+ 24
+ 16
+ vertical
+ center
+ True
+
+
+
+ False
+ True
+
+
+
+
+ True
+ False
+ edit-find-symbolic
+ False
+ True
+
+
+ False
+ True
+
+
+
+
+ True
+ True
+ 10
+ 20
+ 20
+ True
+ 8
+ False
+ 300
+ False
+
+
+
+
+ False
+ True
+
+
+
+
+ True
+ True
+ center
+ 65
+ True
+ start
+ True
+ 150
+
+
+
+
+ Dial
+
+
+
+
+ True
+ call-start-symbolic
+ 5
+
+
+
+
+ False
+ True
+
+
+
+