gui: add editable entry support to simple popup.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Tue, 21 Aug 2012 02:58:10 +0000 (23:58 -0300)
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Tue, 21 Aug 2012 08:10:52 +0000 (05:10 -0300)
This refactors the internal popup to keep a context and store the
entry and message, as well as a button. The logic is now changed to
evaluate the context whenever there is at least a message or an entry.

Dismiss button also uses the buttons_set() infra, which will delete
previous buttons if any.

data/themes/includes/popup.edc
data/themes/includes/scroller.edc
dialer/gui.c
dialer/gui.h

index 1a070e9..b88491e 100644 (file)
@@ -371,8 +371,91 @@ group {
 }
 
 group {
-   name: "elm/entry/base/dialer-popup";
-   alias: "elm/entry/base-noedit/dialer-popup";
+   name: "elm/entry/cursor/dialer";
+   parts {
+      part {
+         name: "cursor";
+         type: RECT;
+         mouse_events: 0;
+         scale: 1;
+         description {
+            state: "default" 0.0;
+            color_class: "action";
+            min: ITEM_PADDING (SEPARATOR_HEIGHT / 2);
+            align: 0.5 1.0;
+            rel1 {
+               relative: 0.0 1.0;
+               offset: 0 -1;
+            }
+         }
+         description {
+            state: "faded" 0.0;
+            inherit: "default" 0.0;
+            color: 255 255 255 128;
+         }
+      }
+      programs {
+         program {
+            name: "focus";
+            signal: "elm,action,focus";
+            source: "elm";
+            action: ACTION_STOP;
+            target: "unfocus";
+            target: "unfocus2";
+            after: "focus2";
+         }
+         program {
+            name: "focus2";
+            action: STATE_SET "default" 0.0;
+            transition: ACCELERATE 0.3;
+            target: "cursor";
+            after: "focus3";
+         }
+         program {
+            name: "focus3";
+            action: STATE_SET "faded" 0.0;
+            transition: ACCELERATE 0.3;
+            target: "cursor";
+            after: "focus2";
+         }
+
+         program {
+            name: "unfocus";
+            signal: "elm,action,unfocus";
+            source: "elm";
+            action: ACTION_STOP;
+            target: "focus";
+            target: "focus2";
+            target: "focus3";
+            after: "unfocus2";
+         }
+         program {
+            name: "unfocus2";
+            action: STATE_SET "faded" 0.0;
+            transition: ACCELERATE 0.3;
+            target: "cursor";
+         }
+      }
+   }
+}
+
+group {
+   name: "elm/entry/selection/dialer";
+   parts {
+      part {
+         name: "bg";
+         type: RECT;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            color_class: "dark";
+         }
+      }
+   }
+}
+
+group {
+   name: "elm/entry/base-noedit/dialer-popup";
 
    styles {
       style {
@@ -388,6 +471,7 @@ group {
          tag: "br" "\n";
       }
    }
+
    parts {
       part {
          name: "elm.text";
@@ -395,6 +479,8 @@ group {
          mouse_events: 1;
          scale: 1;
          multiline: 1;
+         source: "elm/entry/selection/dialer";
+         source4: "elm/entry/cursor/dialer";
          description {
             state: "default" 0.0;
             text {
@@ -435,3 +521,74 @@ group {
       }
    }
 }
+
+group {
+   name: "elm/entry/base/dialer-popup-editable";
+
+   styles {
+      style {
+         name: "entry_textblock_editable_style";
+         base: "font="FONT_NORMAL" font_size="SIZE_MEDIUM" color="TEXTBLOCK_COLOR_ACTION" wrap=word valign=top align=auto";
+         tag:  "b" "+ font_weight=Bold";
+         tag: "br" "\n";
+      }
+      style {
+         name: "entry_textblock_editable_disabled_style";
+         base: "font="FONT_NORMAL" font_size="SIZE_MEDIUM" color="TEXTBLOCK_COLOR_ACTION" wrap=word valign=top align=auto";
+         tag:  "b" "+ font_weight=Bold";
+         tag: "br" "\n";
+      }
+   }
+
+   parts {
+      part {
+         name: "elm.text";
+         type: TEXTBLOCK;
+         mouse_events: 1;
+         scale: 1;
+         entry_mode: EDITABLE;
+         select_mode: EXPLICIT;
+         source: "elm/entry/selection/dialer";
+         source4: "elm/entry/cursor/dialer";
+         multiline: 1;
+         description {
+            state: "default" 0.0;
+            align: 0.0 0.0;
+            text {
+               style: "entry_textblock_editable_style";
+               min: 0 1;
+               max: 1 1;
+               align: -1.0 0.0;
+            }
+         }
+         description {
+            state: "disabled" 0.0;
+            inherit: "default" 0.0;
+            text {
+               style: "entry_textblock_editable_disabled_style";
+            }
+         }
+      }
+   }
+
+   programs {
+      program {
+         signal: "load";
+         source: "";
+         action: FOCUS_SET;
+         target: "elm.text";
+      }
+      program {
+         signal: "elm,state,disabled";
+         source: "elm";
+         action: STATE_SET "disabled" 0.0;
+         target: "elm.text";
+      }
+      program {
+         signal: "elm,state,enabled";
+         source: "elm";
+         action: STATE_SET "default" 0.0;
+         target: "elm.text";
+      }
+   }
+}
index 6792afc..9237ba4 100644 (file)
@@ -439,3 +439,244 @@ group {
       }
    }
 }
+
+group {
+   name: "elm/scroller/entry/dialer-popup-editable";
+
+   script {
+      public sbvis_v, sbalways_v, sbvis_timer;
+      public timer0(val) {
+         new v;
+         v = get_int(sbvis_v);
+         if (v) {
+            v = get_int(sbalways_v);
+            if (!v) {
+               emit("do-hide-vbar", "");
+               set_int(sbvis_v, 0);
+            }
+         }
+         set_int(sbvis_timer, 0);
+         return 0;
+      }
+   }
+
+   parts {
+      part {
+         name: "clipper";
+         type: RECT;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+         }
+      }
+
+      part {
+         name: "bg-color";
+         type: RECT;
+         clip_to: "clipper";
+         description {
+            state: "default" 0.0;
+            color_class: "action";
+         }
+      }
+      part {
+         name: "bg-nocolor";
+         type: RECT;
+         clip_to: "clipper";
+         description {
+            state: "default" 0.0;
+            color_class: "bg";
+            rel1.offset: 1 1;
+            rel2.offset: -2 -2;
+         }
+      }
+      part {
+         name: "elm.swallow.content";
+         clip_to: "clipper";
+         type: SWALLOW;
+         description {
+            state: "default" 0.0;
+            rel1.offset: BORDER_PADDING 2;
+            rel2.offset: (-BORDER_PADDING - 1) -3;
+         }
+      }
+
+      part {
+         name: "sb_vbar_clip_master";
+         type: RECT;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+         }
+         description {
+            state: "hidden" 0.0;
+            color: 255 255 255 0;
+            visible: 0;
+         }
+      }
+
+      part {
+         name: "sb_vbar_clip";
+         clip_to: "sb_vbar_clip_master";
+         type: RECT;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+         }
+         description {
+            state: "hidden" 0.0;
+            color: 255 255 255 0;
+            visible: 0;
+         }
+      }
+
+      part {
+         name: "sb_vbar";
+         type: RECT;
+         mouse_events: 0;
+         description {
+            state: "default" 0.0;
+            fixed: 1 1;
+            visible: 0;
+            min: SCROLLBAR_WIDTH SCROLLBAR_HEIGHT;
+            align: 1.0 0.0;
+            rel1 {
+               relative: 1.0 0.0;
+               offset: -3 2;
+            }
+            rel2 {
+               relative: 1.0 1.0;
+               offset: -3 -3;
+            }
+         }
+      }
+
+      part {
+         name: "elm.dragable.vbar";
+         type: RECT;
+         clip_to: "sb_vbar_clip";
+         mouse_events: 0;
+         dragable {
+            x: 0 0 0;
+            y: 1 1 0;
+            confine: "sb_vbar";
+         }
+         description {
+            state: "default" 0.0;
+            color: 255 255 255 255;
+            color_class: "light";
+            fixed: 1 1;
+            min: SCROLLBAR_WIDTH SCROLLBAR_HEIGHT;
+            max: SCROLLBAR_WIDTH 99999;
+            rel1 {
+               relative: 0.5 0.5;
+               offset: 0 0;
+               to: "sb_vbar";
+            }
+            rel2 {
+               relative: 0.5 0.5;
+               offset: 0 0;
+               to: "sb_vbar";
+            }
+         }
+      }
+   }
+
+   programs {
+      program {
+         signal: "load";
+         source: "";
+         script {
+            set_state(PART:"sb_vbar_clip", "hidden", 0.0);
+            set_int(sbvis_v, 0);
+            set_int(sbalways_v, 0);
+            set_int(sbvis_timer, 0);
+         }
+      }
+
+      program {
+         name: "vbar_show";
+         signal: "elm,action,show,vbar";
+         source: "elm";
+         action:  STATE_SET "default" 0.0;
+         target: "sb_vbar_clip_master";
+      }
+
+      program {
+         name: "vbar_hide";
+         signal: "elm,action,hide,vbar";
+         source: "elm";
+         action:  STATE_SET "hidden" 0.0;
+         target: "sb_vbar_clip_master";
+      }
+
+      program {
+         name: "vbar_show_always";
+         signal: "elm,action,show_always,vbar";
+         source: "elm";
+         script {
+            new v;
+            v = get_int(sbvis_v);
+            v |= get_int(sbalways_v);
+            if (!v) {
+               set_int(sbalways_v, 1);
+               emit("do-show-vbar", "");
+               set_int(sbvis_v, 1);
+            }
+         }
+      }
+
+      program {
+         name: "vbar_show_notalways";
+         signal: "elm,action,show_notalways,vbar";
+         source: "elm";
+         script {
+            new v;
+            v = get_int(sbalways_v);
+            if (v) {
+               set_int(sbalways_v, 0);
+               v = get_int(sbvis_v);
+               if (!v) {
+                  emit("do-hide-vbar", "");
+                  set_int(sbvis_v, 0);
+               }
+            }
+         }
+      }
+
+      program {
+         signal: "do-show-vbar";
+         source: "";
+         action:  STATE_SET "default" 0.0;
+         transition: LINEAR 0.5;
+         target: "sb_vbar_clip";
+      }
+
+      program {
+         signal: "do-hide-vbar";
+         source: "";
+         action:  STATE_SET "hidden" 0.0;
+         transition: LINEAR 0.5;
+         target: "sb_vbar_clip";
+      }
+
+      program {
+         name: "scroll";
+         signal: "elm,action,scroll";
+         source: "elm";
+         script {
+            new v;
+            v = get_int(sbvis_v);
+            v |= get_int(sbalways_v);
+            if (!v) {
+               emit("do-show-vbar", "");
+               set_int(sbvis_v, 1);
+            }
+            v = get_int(sbvis_timer);
+            if (v > 0) cancel_timer(v);
+            v = timer(1.0, "timer0", 0);
+            set_int(sbvis_timer, v);
+         }
+      }
+   }
+}
index 3f71e33..9f78262 100644 (file)
@@ -52,6 +52,15 @@ static void _gui_show(Evas_Object *o)
        elm_object_focus_set(o, EINA_TRUE);
 }
 
+typedef struct _Simple_Popup
+{
+       Evas_Object *popup;
+       Evas_Object *box;
+       Evas_Object *message;
+       Evas_Object *entry;
+       Ecore_Timer *recalc_timer; /* HACK */
+} Simple_Popup;
+
 static void _popup_close(void *data, Evas_Object *bt __UNUSED__, void *event __UNUSED__)
 {
        Evas_Object *popup = data;
@@ -70,65 +79,169 @@ void gui_simple_popup_title_set(Evas_Object *p, const char *title)
 }
 
 /* HACK: force recalc from an idler to fix elm_entry problem */
-static Eina_Bool _gui_simple_popup_message_reeval(void *data)
+static Eina_Bool _gui_simple_popup_entries_reeval(void *data)
 {
-       Evas_Object *en = data;
-       elm_entry_calc_force(en);
-       evas_object_data_del(en, "reeval_timer");
+       Simple_Popup *ctx = data;
+       if (ctx->message)
+               elm_entry_calc_force(ctx->message);
+       if (ctx->entry)
+               elm_entry_calc_force(ctx->entry);
+       ctx->recalc_timer = NULL;
        return EINA_FALSE;
 }
 
-static void _gui_simple_popup_message_reeval_del(void *data __UNUSED__,
-                                                       Evas *e __UNUSED__,
-                                                       Evas_Object *en,
-                                                       void *einfo __UNUSED__)
+static void _gui_simple_popup_timer_cancel_if_needed(Simple_Popup *ctx)
+{
+       if (!ctx->recalc_timer)
+               return;
+       if (ctx->message || ctx->entry)
+               return;
+       ecore_timer_del(ctx->recalc_timer);
+       ctx->recalc_timer = NULL;
+}
+
+static void _gui_simple_popup_message_del(void *data, Evas *e __UNUSED__,
+                                               Evas_Object *en __UNUSED__,
+                                               void *einfo __UNUSED__)
+{
+       Simple_Popup *ctx = data;
+       ctx->message = NULL;
+       _gui_simple_popup_timer_cancel_if_needed(ctx);
+}
+
+static void _gui_simple_popup_entry_del(void *data, Evas *e __UNUSED__,
+                                       Evas_Object *en __UNUSED__,
+                                       void *einfo __UNUSED__)
 {
-       Ecore_Timer *timer = evas_object_data_del(en, "reeval_timer");
-       if (timer)
-               ecore_timer_del(timer);
+       Simple_Popup *ctx = data;
+       ctx->entry = NULL;
+       _gui_simple_popup_timer_cancel_if_needed(ctx);
+}
+
+static void _gui_simple_popup_reeval_content(Simple_Popup *ctx)
+{
+       if ((!ctx->message) && (!ctx->entry)) {
+               elm_object_part_content_unset(ctx->popup,
+                                               "elm.swallow.content");
+               elm_object_signal_emit(ctx->popup, "hide,content", "gui");
+               evas_object_hide(ctx->box);
+               return;
+       }
+
+       elm_box_unpack_all(ctx->box);
+       if (ctx->message) {
+               elm_box_pack_end(ctx->box, ctx->message);
+               evas_object_show(ctx->message);
+       }
+       if (ctx->entry) {
+               elm_box_pack_end(ctx->box, ctx->entry);
+               evas_object_show(ctx->entry);
+       }
+
+       elm_object_part_content_set(ctx->popup, "elm.swallow.content",
+                                       ctx->box);
+       elm_object_signal_emit(ctx->popup, "show,content", "gui");
+
+       /* HACK: elm_entry is not evaluating properly and the text is
+        * not centered as it should be. Then we must force a
+        * calculation from an timer.
+        */
+       if (ctx->recalc_timer)
+               ecore_timer_del(ctx->recalc_timer);
+       ctx->recalc_timer = ecore_timer_add(
+               0.02, _gui_simple_popup_entries_reeval, ctx);
 }
 
 void gui_simple_popup_message_set(Evas_Object *p, const char *msg)
 {
+       Simple_Popup *ctx = evas_object_data_get(p, "simple_popup");
        Evas_Object *en;
-       Ecore_Timer *timer;
+
+       EINA_SAFETY_ON_NULL_RETURN(ctx);
 
        if (!msg) {
-               elm_object_part_content_set(p, "elm.swallow.content", NULL);
-               elm_object_signal_emit(p, "hide,content", "gui");
+               if (ctx->message)
+                       evas_object_del(ctx->message);
+               _gui_simple_popup_reeval_content(ctx);
                return;
        }
 
-       en = elm_entry_add(p);
-       elm_object_style_set(en, "dialer-popup");
-       elm_entry_editable_set(en, EINA_FALSE);
+       if (ctx->message)
+               en = ctx->message;
+       else {
+               en = ctx->message = elm_entry_add(p);
+               elm_object_style_set(en, "dialer-popup");
+               elm_entry_editable_set(en, EINA_FALSE);
+               elm_entry_scrollable_set(en, EINA_TRUE);
+               elm_entry_scrollbar_policy_set(en, ELM_SCROLLER_POLICY_OFF,
+                                               ELM_SCROLLER_POLICY_AUTO);
+
+               evas_object_event_callback_add(en, EVAS_CALLBACK_DEL,
+                                       _gui_simple_popup_message_del,
+                                       ctx);
+               evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND,
+                                                       EVAS_HINT_EXPAND);
+               evas_object_size_hint_align_set(en, EVAS_HINT_FILL,
+                                               EVAS_HINT_FILL);
+       }
+
+       elm_object_text_set(en, msg);
+       _gui_simple_popup_reeval_content(ctx);
+}
+
+void gui_simple_popup_entry_enable(Evas_Object *p)
+{
+       Simple_Popup *ctx = evas_object_data_get(p, "simple_popup");
+       Evas_Object *en;
+
+       EINA_SAFETY_ON_NULL_RETURN(ctx);
+
+       if (ctx->entry)
+               return;
+       en = ctx->entry = elm_entry_add(p);
+       elm_object_style_set(en, "dialer-popup-editable");
+       elm_entry_editable_set(en, EINA_TRUE);
        elm_entry_scrollable_set(en, EINA_TRUE);
        elm_entry_scrollbar_policy_set(en, ELM_SCROLLER_POLICY_OFF,
                                        ELM_SCROLLER_POLICY_AUTO);
-       elm_object_text_set(en, msg);
-       elm_object_part_content_set(p, "elm.swallow.content", en);
-       elm_object_signal_emit(p, "show,content", "gui");
 
-       /* HACK: elm_entry is not evaluating properly and the text is
-        * not centered as it should be. Then we must force a
-        * calculation from an timer.
-        */
-       timer = ecore_timer_add(0.02, _gui_simple_popup_message_reeval, en);
-       evas_object_data_set(en, "reeval_timer", timer);
+       evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND,
+                                               EVAS_HINT_EXPAND);
+       evas_object_size_hint_align_set(en, EVAS_HINT_FILL,
+                                       EVAS_HINT_FILL);
+
        evas_object_event_callback_add(en, EVAS_CALLBACK_DEL,
-                                       _gui_simple_popup_message_reeval_del,
-                                       NULL);
+                                       _gui_simple_popup_entry_del,
+                                       ctx);
+       _gui_simple_popup_reeval_content(ctx);
 }
 
-void gui_simple_popup_button_dismiss_set(Evas_Object *p)
+void gui_simple_popup_entry_disable(Evas_Object *p)
+{
+       Simple_Popup *ctx = evas_object_data_get(p, "simple_popup");
+       EINA_SAFETY_ON_NULL_RETURN(ctx);
+       if (!ctx->entry)
+               return;
+       evas_object_del(ctx->entry);
+       _gui_simple_popup_reeval_content(ctx);
+}
+
+const char *gui_simple_popup_entry_get(const Evas_Object *p)
 {
-       Evas_Object *bt = elm_button_add(p);
-       elm_object_style_set(bt, "dialer");
-       elm_object_text_set(bt, "Dismiss");
+       Simple_Popup *ctx = evas_object_data_get(p, "simple_popup");
+       EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
+       EINA_SAFETY_ON_NULL_RETURN_VAL(ctx->entry, NULL);
+       return elm_object_text_get(ctx->entry);
+}
 
-       elm_object_part_content_set(p, "elm.swallow.button1", bt);
-       elm_object_signal_emit(p, "buttons,1", "gui");
-       evas_object_smart_callback_add(bt, "clicked", _popup_close, p);
+void gui_simple_popup_button_dismiss_set(Evas_Object *p)
+{
+       gui_simple_popup_buttons_set(p,
+                                       "Dismiss",
+                                       "dialer",
+                                       _popup_close,
+                                       NULL, NULL, NULL,
+                                       p);
 }
 
 void gui_simple_popup_buttons_set(Evas_Object *p,
@@ -170,19 +283,44 @@ void gui_simple_popup_buttons_set(Evas_Object *p,
 
        if (count == 2)
                elm_object_signal_emit(p, "buttons,2", "gui");
-       else if (count == 1)
+       else if (count == 1) {
                elm_object_signal_emit(p, "buttons,1", "gui");
-       else
+               elm_object_part_content_set(p, "elm.swallow.button2", NULL);
+       } else {
                elm_object_signal_emit(p, "buttons,0", "gui");
+               elm_object_part_content_set(p, "elm.swallow.button1", NULL);
+               elm_object_part_content_set(p, "elm.swallow.button2", NULL);
+       }
+}
+
+static void _gui_simple_popup_del(void *data, Evas *e __UNUSED__,
+                                       Evas_Object *o __UNUSED__,
+                                       void *event_info __UNUSED__)
+{
+       Simple_Popup *ctx = data;
+       free(ctx);
 }
 
 Evas_Object *gui_simple_popup(const char *title, const char *message)
 {
        Evas_Object *p = gui_layout_add(win, "popup");
+       Simple_Popup *ctx;
+
+       EINA_SAFETY_ON_NULL_RETURN_VAL(p, NULL);
+
+       ctx = calloc(1, sizeof(Simple_Popup));
+       EINA_SAFETY_ON_NULL_GOTO(ctx, failed_calloc);
+
+       evas_object_data_set(p, "simple_popup", ctx);
+       ctx->popup = p;
+       evas_object_event_callback_add(p, EVAS_CALLBACK_DEL,
+                                       _gui_simple_popup_del, ctx);
 
        evas_object_size_hint_weight_set(p, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
        elm_win_resize_object_add(win, p);
 
+       ctx->box = elm_box_add(p);
+
        gui_simple_popup_title_set(p, title);
        gui_simple_popup_message_set(p, message);
        gui_simple_popup_button_dismiss_set(p);
@@ -190,6 +328,10 @@ Evas_Object *gui_simple_popup(const char *title, const char *message)
        evas_object_show(p);
 
        return p;
+
+failed_calloc:
+       evas_object_del(p);
+       return NULL;
 }
 
 void gui_activate(void)
index 3281e8a..6c1c5bd 100644 (file)
@@ -20,6 +20,10 @@ void gui_simple_popup_buttons_set(Evas_Object *p,
                                        Evas_Smart_Cb b2_cb,
                                        const void *data);
 
+void gui_simple_popup_entry_enable(Evas_Object *p);
+void gui_simple_popup_entry_disable(Evas_Object *p);
+const char *gui_simple_popup_entry_get(const Evas_Object *p);
+
 
 void gui_activate(void);
 void gui_number_set(const char *number, Eina_Bool auto_dial);