[california] Rename calendars in Calendar Manager: Closes bug #726809
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california] Rename calendars in Calendar Manager: Closes bug #726809
- Date: Thu, 1 May 2014 05:05:37 +0000 (UTC)
commit c9a2fd0effd029b5715ef0671b92f496a79f2b94
Author: Jim Nelson <jim yorba org>
Date: Wed Apr 30 22:04:49 2014 -0700
Rename calendars in Calendar Manager: Closes bug #726809
When a selected calendar is clicked on, the calendar title can be
renamed by the user.
src/Makefile.am | 1 +
src/manager/manager-calendar-list-item.vala | 59 ++++++++++++++++++++++++++-
src/manager/manager-calendar-list.vala | 21 ++++++++-
src/rc/calendar-manager-list-item.ui | 47 ++++++++++++---------
src/rc/calendar-manager-list.ui | 1 +
src/toolkit/toolkit-calendar-popup.vala | 2 +-
src/toolkit/toolkit-editable-label.vala | 60 +++++++++++++++++++++++++++
src/toolkit/toolkit-popup.vala | 34 +++++++++++++--
8 files changed, 195 insertions(+), 30 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 99df41d..30fa900 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -111,6 +111,7 @@ california_VALASOURCES = \
toolkit/toolkit-combo-box-text-model.vala \
toolkit/toolkit-deck.vala \
toolkit/toolkit-deck-window.vala \
+ toolkit/toolkit-editable-label.vala \
toolkit/toolkit-listbox-model.vala \
toolkit/toolkit-mutable-widget.vala \
toolkit/toolkit-popup.vala \
diff --git a/src/manager/manager-calendar-list-item.vala b/src/manager/manager-calendar-list-item.vala
index 977453d..fd62bde 100644
--- a/src/manager/manager-calendar-list-item.vala
+++ b/src/manager/manager-calendar-list-item.vala
@@ -11,11 +11,16 @@ namespace California.Manager {
*/
[GtkTemplate (ui = "/org/yorba/california/rc/calendar-manager-list-item.ui")]
-public class CalendarListItem : Gtk.Grid {
+internal class CalendarListItem : Gtk.Grid, Toolkit.MutableWidget {
private const int COLOR_DIM = 16;
public Backing.CalendarSource source { get; private set; }
+ /**
+ * Set by { link CalendarList}.
+ */
+ public bool is_selected { get; set; default = false; }
+
[GtkChild]
private Gtk.Image readonly_icon;
@@ -23,16 +28,23 @@ public class CalendarListItem : Gtk.Grid {
private Gtk.CheckButton visible_check_button;
[GtkChild]
+ private Gtk.EventBox title_eventbox;
+
+ [GtkChild]
private Gtk.Label title_label;
[GtkChild]
private Gtk.ColorButton color_button;
+ private Toolkit.EditableLabel? editable_label = null;
+
public CalendarListItem(Backing.CalendarSource source) {
this.source = source;
has_tooltip = true;
+ source.notify[Backing.Source.PROP_TITLE].connect(on_title_changed);
+
source.bind_property(Backing.Source.PROP_TITLE, title_label, "label",
BindingFlags.SYNC_CREATE);
source.bind_property(Backing.Source.PROP_VISIBLE, visible_check_button, "active",
@@ -43,6 +55,17 @@ public class CalendarListItem : Gtk.Grid {
() => source.read_only ? "changes-prevent-symbolic" : "");
Properties.xform_to_string(source, Backing.Source.PROP_READONLY, readonly_icon, "tooltip-text",
() => source.read_only ? _("Calendar is read-only") : null);
+
+ title_eventbox.button_release_event.connect(on_title_button_release);
+ }
+
+ ~CalendarListItem() {
+ source.notify[Backing.Source.PROP_TITLE].disconnect(on_title_changed);
+ }
+
+ private void on_title_changed() {
+ // title determines sort order, so this is important
+ mutated();
}
public override bool query_tooltip(int x, int y, bool keyboard_mode, Gtk.Tooltip tooltip) {
@@ -67,6 +90,40 @@ public class CalendarListItem : Gtk.Grid {
return true;
}
+
+ private void activate_editable_label() {
+ assert(editable_label == null);
+
+ editable_label = new Toolkit.EditableLabel(title_label);
+ editable_label.accepted.connect(on_title_edit_accepted);
+ editable_label.dismissed.connect(remove_editable_label);
+
+ editable_label.show_all();
+ }
+
+ private void remove_editable_label() {
+ assert(editable_label != null);
+
+ editable_label.destroy();
+ editable_label = null;
+ }
+
+ private bool on_title_button_release(Gdk.EventButton event) {
+ // if already accepting input or not selected, don't activate text entry for rename (but
+ // allow signal to propagate further)
+ if (editable_label != null || !is_selected)
+ return false;
+
+ activate_editable_label();
+
+ // don't propagate
+ return true;
+ }
+
+ private void on_title_edit_accepted(string text) {
+ if (!String.is_empty(text))
+ source.title = text;
+ }
}
}
diff --git a/src/manager/manager-calendar-list.vala b/src/manager/manager-calendar-list.vala
index 48246b0..8287e7d 100644
--- a/src/manager/manager-calendar-list.vala
+++ b/src/manager/manager-calendar-list.vala
@@ -11,7 +11,9 @@ namespace California.Manager {
*/
[GtkTemplate (ui = "/org/yorba/california/rc/calendar-manager-list.ui")]
-public class CalendarList : Gtk.Grid, Toolkit.Card {
+internal class CalendarList : Gtk.Grid, Toolkit.Card {
+ public const string PROP_SELECTED = "selected";
+
public const string ID = "CalendarList";
public string card_id { get { return ID; } }
@@ -22,6 +24,8 @@ public class CalendarList : Gtk.Grid, Toolkit.Card {
public Gtk.Widget? initial_focus { get { return calendar_list_box; } }
+ public CalendarListItem? selected { get; private set; default = null; }
+
[GtkChild]
private Gtk.ListBox calendar_list_box;
@@ -84,8 +88,19 @@ public class CalendarList : Gtk.Grid, Toolkit.Card {
[GtkCallback]
private void on_calendar_list_box_row_activated(Gtk.ListBoxRow row) {
- CalendarListItem item = (CalendarListItem) row.get_child();
- debug("activated %s", item.source.to_string());
+ }
+
+ [GtkCallback]
+ private void on_calendar_list_box_row_selected(Gtk.ListBoxRow? row) {
+ if (selected != null)
+ selected.is_selected = false;
+
+ if (row != null) {
+ selected = (CalendarListItem) row.get_child();
+ selected.is_selected = true;
+ } else {
+ selected = null;
+ }
}
[GtkCallback]
diff --git a/src/rc/calendar-manager-list-item.ui b/src/rc/calendar-manager-list-item.ui
index 2b756cf..6b5f2d7 100644
--- a/src/rc/calendar-manager-list-item.ui
+++ b/src/rc/calendar-manager-list-item.ui
@@ -7,26 +7,6 @@
<property name="can_focus">False</property>
<property name="column_spacing">4</property>
<child>
- <object class="GtkLabel" id="title_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="valign">center</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="xalign">0</property>
- <property name="yalign">0</property>
- <property name="label">calendar name</property>
- <property name="ellipsize">end</property>
- <property name="single_line_mode">True</property>
- </object>
- <packing>
- <property name="left_attach">3</property>
- <property name="top_attach">0</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
- </child>
- <child>
<object class="GtkColorButton" id="color_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -79,5 +59,32 @@
<property name="height">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkEventBox" id="title_eventbox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="events">GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
+ <child>
+ <object class="GtkLabel" id="title_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="label">calendar name</property>
+ <property name="ellipsize">end</property>
+ <property name="single_line_mode">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
</template>
</interface>
diff --git a/src/rc/calendar-manager-list.ui b/src/rc/calendar-manager-list.ui
index c61bc11..65d2a74 100644
--- a/src/rc/calendar-manager-list.ui
+++ b/src/rc/calendar-manager-list.ui
@@ -61,6 +61,7 @@
<property name="vexpand">True</property>
<property name="activate_on_single_click">False</property>
<signal name="row-activated" handler="on_calendar_list_box_row_activated"
object="CaliforniaManagerCalendarList" swapped="no"/>
+ <signal name="row-selected" handler="on_calendar_list_box_row_selected"
object="CaliforniaManagerCalendarList" swapped="no"/>
</object>
</child>
</object>
diff --git a/src/toolkit/toolkit-calendar-popup.vala b/src/toolkit/toolkit-calendar-popup.vala
index 391dab0..0c0633c 100644
--- a/src/toolkit/toolkit-calendar-popup.vala
+++ b/src/toolkit/toolkit-calendar-popup.vala
@@ -35,7 +35,7 @@ public class CalendarPopup : Popup {
* inheritDoc
*/
public CalendarPopup(Gtk.Widget relative_to, Calendar.Date initial_date) {
- base (relative_to);
+ base (relative_to, Popup.Position.BELOW);
calendar.day = initial_date.day_of_month.value;
calendar.month = initial_date.month.value - 1;
diff --git a/src/toolkit/toolkit-editable-label.vala b/src/toolkit/toolkit-editable-label.vala
new file mode 100644
index 0000000..46bd05f
--- /dev/null
+++ b/src/toolkit/toolkit-editable-label.vala
@@ -0,0 +1,60 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+namespace California.Toolkit {
+
+/**
+ * Uses a { link Popup} to place a Gtk.Entry over a Gtk.Label, creating the illusion that the user
+ * can "edit" the label.
+ *
+ * If the user presses Enter, { link accepted} will fire. It is up to the caller to set the
+ * Gtk.Label's text to this field.
+ *
+ * Callers should subscribe to the { link dismissed} label to destroy this widget.
+ *
+ * This currently doesn't deal with font issues (i.e. the editable field will use the system editing
+ * font).
+ */
+
+public class EditableLabel : Popup {
+ /**
+ * The Gtk.Label being "edited".
+ */
+ public Gtk.Label label { get; private set; }
+
+ private Gtk.Entry entry = new Gtk.Entry();
+
+ /**
+ * Fired when the user presses Enter indicating the text should be accepted.
+ *
+ * It is up to the caller to set the Gtk.Label's text to this text (if so desired). The
+ * { link EditableLabel} will be dismissed after this signal completes.
+ */
+ public signal void accepted(string text);
+
+ public EditableLabel(Gtk.Label label) {
+ base (label, Popup.Position.VERTICAL_CENTER);
+
+ // set up Gtk.Entry to look and be sized exactly like the Gtk.Label
+ entry.text = label.label;
+ entry.width_chars = label.width_chars;
+ add(entry);
+
+ // make sure the Popup window is hugging close to label as well
+ margin = 0;
+
+ // Enter accepts
+ entry.activate.connect(on_entry_accepted);
+ }
+
+ private void on_entry_accepted() {
+ accepted(entry.text);
+ dismissed();
+ }
+}
+
+}
+
diff --git a/src/toolkit/toolkit-popup.vala b/src/toolkit/toolkit-popup.vala
index beb76b8..fcee4f5 100644
--- a/src/toolkit/toolkit-popup.vala
+++ b/src/toolkit/toolkit-popup.vala
@@ -14,8 +14,16 @@ namespace California.Toolkit {
*/
public class Popup : Gtk.Window {
+ public enum Position {
+ BELOW,
+ VERTICAL_CENTER
+ }
+
private Gtk.Widget relative_to;
+ private Position position;
private Gtk.Widget? prev_focus = null;
+ private int relative_x = 0;
+ private int relative_y = 0;
/**
* Fired when the { link Popup} is hidden, either due to user interaction (losing focus) or
@@ -29,17 +37,16 @@ public class Popup : Gtk.Window {
*
* The GtkWidget must be realized when this is invoked.
*/
- public Popup(Gtk.Widget relative_to) {
+ public Popup(Gtk.Widget relative_to, Position position) {
Object(type:Gtk.WindowType.TOPLEVEL);
assert(relative_to.get_realized());
this.relative_to = relative_to;
+ this.position = position;
set_screen(relative_to.get_screen());
- // move Popup window directly below relative_to widget aligned on the left-hand side
- // TODO: RTL support
- // TODO: Better detection to ensure Popup is always fully mapped onto the screen
+ // get coordinates of relative_to widget
Gtk.Window? relative_to_win = relative_to.get_ancestor(typeof (Gtk.Window)) as Gtk.Window;
if (relative_to_win != null && relative_to_win.is_toplevel()) {
int gtk_x, gtk_y;
@@ -50,7 +57,8 @@ public class Popup : Gtk.Window {
int gdk_x, gdk_y;
gdk_win.get_position(out gdk_x, out gdk_y);
- move(gtk_x + gdk_x, gtk_y + gdk_y + relative_to.get_allocated_height());
+ relative_x = gtk_x + gdk_x;
+ relative_y = gtk_y + gdk_y;
}
decorated = false;
@@ -82,6 +90,22 @@ public class Popup : Gtk.Window {
public override void map() {
base.map();
+ switch (position) {
+ case Position.BELOW:
+ // move Popup window directly below relative_to widget aligned on the left-hand side
+ // TODO: RTL support
+ // TODO: Better detection to ensure Popup is always fully mapped onto the same screen
+ move(relative_x, relative_y + relative_to.get_allocated_height());
+ break;
+
+ case Position.VERTICAL_CENTER:
+ move(relative_x, relative_y + ((relative_to.get_allocated_height() - get_allocated_height())
/ 2));
+ break;
+
+ default:
+ assert_not_reached();
+ }
+
prev_focus = get_focus();
Gtk.grab_add(this);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]