work on bettre touchscreen text selection support. not 100% done yet. been
authorCarsten Haitzler <raster@rasterman.com>
Thu, 19 Mar 2009 13:36:46 +0000 (13:36 +0000)
committerCarsten Haitzler <raster@rasterman.com>
Thu, 19 Mar 2009 13:36:46 +0000 (13:36 +0000)
playing with ideas. this one seems best.

SVN revision: 39579

data/themes/default.edc
src/lib/Elementary.h.in
src/lib/elc_hoversel.c
src/lib/elm_entry.c
src/lib/els_scroller.c

index b443680..82dc9ca 100644 (file)
@@ -3649,6 +3649,7 @@ collections {
            mouse_events: 1;
            scale: 1;
            entry_mode: EDITABLE;
+           select_mode: EXPLICIT;
            multiline: 1;
            source: "elm/entry/selection/default"; // selection under
 //         source2: "X"; // selection over
@@ -3681,6 +3682,7 @@ collections {
            mouse_events: 1;
            scale: 1;
            entry_mode: EDITABLE;
+           select_mode: EXPLICIT;
            multiline: 1;
            source: "elm/entry/selection/default"; // selection under
            source4: "elm/entry/cursor/default"; // cursorover
@@ -3692,6 +3694,20 @@ collections {
               }
            }
         }
+        part { name: "sel";
+           type: RECT;
+            mouse_events: 0;
+           description { state: "default" 0.0;
+               align: 1.0 1.0;
+               max: 16 16;
+               aspect: 1.0 1.0;
+               color: 255 0 0 0;
+           }
+           description { state: "visible" 0.0;
+               inherit: "default" 0.0;
+               color: 255 0 0 50;
+            }
+        }
       }
       programs {
         program { name: "focus";
@@ -3700,6 +3716,18 @@ collections {
            action: FOCUS_SET;
            target: "elm.text";
         }
+        program { name: "selmode0";
+            signal: "elm,state,select,on";
+           source: "elm";
+           action: STATE_SET "visible" 0.0;
+           target: "sel";
+        }
+        program { name: "selmode1";
+            signal: "elm,state,select,off";
+           source: "elm";
+           action: STATE_SET "default" 0.0;
+           target: "sel";
+        }
       }
    }
 
@@ -3722,6 +3750,7 @@ collections {
            mouse_events: 1;
            scale: 1;
            entry_mode: EDITABLE;
+           select_mode: EXPLICIT;
            multiline: 0;
            source: "elm/entry/selection/default"; // selection under
            source4: "elm/entry/cursor/default"; // cursorover
@@ -3751,6 +3780,7 @@ collections {
            mouse_events: 1;
            scale: 1;
            entry_mode: PLAIN;
+           select_mode: EXPLICIT;
            multiline: 0;
            source: "elm/entry/selection/default"; // selection under
            source5: "elm/entry/anchor/default"; // anchor under
@@ -3779,6 +3809,7 @@ collections {
            mouse_events: 1;
            scale: 1;
            entry_mode: PLAIN;
+           select_mode: EXPLICIT;
            multiline: 1;
            source: "elm/entry/selection/default"; // selection under
            source5: "elm/entry/anchor/default"; // anchor under
@@ -3807,6 +3838,7 @@ collections {
            mouse_events: 1;
            scale: 1;
            entry_mode: PLAIN;
+           select_mode: EXPLICIT;
            multiline: 1;
            source: "elm/entry/selection/default"; // selection under
            source5: "elm/entry/anchor/default"; // anchor under
@@ -3835,6 +3867,7 @@ collections {
            mouse_events: 1;
            scale: 1;
            entry_mode: PASSWORD;
+           select_mode: EXPLICIT;
            multiline: 0;
            source: "elm/entry/selection/default"; // selection under
            source4: "elm/entry/cursor/default"; // cursorover
index fd74d21..eeec12e 100644 (file)
@@ -489,6 +489,7 @@ extern "C" {
    EAPI void         elm_hoversel_hover_parent_set(Evas_Object *obj, Evas_Object *parent);
    EAPI void         elm_hoversel_label_set(Evas_Object *obj, const char *label);
    EAPI void         elm_hoversel_icon_set(Evas_Object *obj, Evas_Object *icon);
+   EAPI void         elm_hoversel_hover_begin(Evas_Object *obj);
    EAPI void         elm_hoversel_hover_end(Evas_Object *obj);
    EAPI Elm_Hoversel_Item *elm_hoversel_item_add(Evas_Object *obj, const char *label, const char *icon_file, Elm_Icon_Type icon_type, void (*func) (void *data, Evas_Object *obj, void *event_info), const void *data);
    EAPI void         elm_hoversel_item_del(Elm_Hoversel_Item *item);
index 87f792c..3404d82 100644 (file)
@@ -78,17 +78,17 @@ _item_clicked(void *data, Evas_Object *obj, void *event_info)
 }
 
 static void
-_button_clicked(void *data, Evas_Object *obj, void *event_info)
+_activate(Evas_Object *obj)
 {
-   Widget_Data *wd = elm_widget_data_get(data);
+   Widget_Data *wd = elm_widget_data_get(obj);
    if (!wd) return;
    Evas_Object *bt, *bx, *ic;
    const Eina_List *l;
    const Elm_Hoversel_Item *it;
 
-   wd->hover = elm_hover_add(data);
+   wd->hover = elm_hover_add(obj);
    elm_hover_style_set(wd->hover, "hoversel_vertical");
-   evas_object_smart_callback_add(wd->hover, "clicked", _hover_clicked, data);
+   evas_object_smart_callback_add(wd->hover, "clicked", _hover_clicked, obj);
    elm_hover_parent_set(wd->hover, wd->hover_parent);
    elm_hover_target_set(wd->hover, wd->btn);
 
@@ -102,7 +102,7 @@ _button_clicked(void *data, Evas_Object *obj, void *event_info)
         elm_button_label_set(bt, it->label);
         if (it->icon_file)
           {
-             ic = elm_icon_add(data);
+             ic = elm_icon_add(obj);
              elm_icon_scale_set(ic, 0, 1);
              if (it->icon_type == ELM_ICON_FILE)
                elm_icon_file_set(ic, it->icon_file, NULL);
@@ -125,7 +125,13 @@ _button_clicked(void *data, Evas_Object *obj, void *event_info)
    evas_object_show(bx);
    
    evas_object_show(wd->hover);
-   evas_object_smart_callback_call(data, "clicked", NULL);
+   evas_object_smart_callback_call(obj, "clicked", NULL);
+}
+
+static void
+_button_clicked(void *data, Evas_Object *obj, void *event_info)
+{
+  _activate(data); 
 }
 
 static void
@@ -189,6 +195,15 @@ elm_hoversel_icon_set(Evas_Object *obj, Evas_Object *icon)
 }
 
 EAPI void
+elm_hoversel_hover_begin(Evas_Object *obj)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   if (!wd) return;
+   if (wd->hover) return;
+   _activate(obj);
+}
+
+EAPI void
 elm_hoversel_hover_end(Evas_Object *obj)
 {
    Widget_Data *wd = elm_widget_data_get(obj);
index 3fa3dd3..bac3b3e 100644 (file)
@@ -6,11 +6,14 @@ typedef struct _Widget_Data Widget_Data;
 struct _Widget_Data
 {
    Evas_Object *ent;
+   Evas_Object *hoversel;
    Ecore_Job *deferred_recalc_job;
    Ecore_Event_Handler *sel_notify_handler; 
    Ecore_Event_Handler *sel_clear_handler;
+   Ecore_Timer *longpress_timer;
    const char *cut_sel;
    Evas_Coord lastw;
+   Evas_Coord downx, downy;
    Evas_Bool changed : 1;
    Evas_Bool linewrap : 1;
    Evas_Bool single_line : 1;
@@ -18,6 +21,7 @@ struct _Widget_Data
    Evas_Bool editable : 1;
    Evas_Bool selection_asked : 1;
    Evas_Bool have_selection : 1;
+   Evas_Bool selmode : 1;
 };
 
 static void _del_hook(Evas_Object *obj);
@@ -48,6 +52,7 @@ _del_hook(Evas_Object *obj)
 #endif   
    if (wd->cut_sel) eina_stringshare_del(wd->cut_sel);
    if (wd->deferred_recalc_job) ecore_job_del(wd->deferred_recalc_job);
+   if (wd->longpress_timer) ecore_timer_del(wd->longpress_timer);
    free(wd);
 }
 
@@ -128,12 +133,224 @@ _on_focus_hook(void *data, Evas_Object *obj)
 }
 
 static void
+_hoversel_position(Evas_Object *obj)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   Evas_Coord cx, cy, cw, ch, x, y, mw, mh;
+   evas_object_geometry_get(wd->ent, &x, &y, NULL, NULL);
+   edje_object_part_text_cursor_geometry_get(wd->ent, "elm.text", 
+                                             &cx, &cy, &cw, &ch);
+   evas_object_size_hint_min_get(wd->hoversel, &mw, &mh);
+   if (cw < mw)
+     {
+        cx += (cw - mw) / 2;
+        cw = mw;
+     }
+   if (ch < mh)
+     {
+        cy += (ch - mh) / 2;
+        ch = mh;
+     }
+   evas_object_move(wd->hoversel, x + cx, y + cy);
+   evas_object_resize(wd->hoversel, cw, ch);
+}
+
+static void
+_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   if (wd->hoversel) _hoversel_position(data);
+}
+
+static void
 _resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
 {
    Widget_Data *wd = elm_widget_data_get(data);
    if (wd->linewrap) _sizing_eval(data);
-   Evas_Coord ww, hh;
-   evas_object_geometry_get(wd->ent, NULL, NULL, &ww, &hh);
+   if (wd->hoversel) _hoversel_position(data);
+//   Evas_Coord ww, hh;
+//   evas_object_geometry_get(wd->ent, NULL, NULL, &ww, &hh);
+}
+
+static void
+_dismissed(void *data, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   if (wd->hoversel) evas_object_hide(wd->hoversel);
+   if (wd->selmode)
+     edje_object_part_text_select_allow_set(wd->ent, "elm.text", 1);
+}
+
+static void
+_select(void *data, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   wd->selmode = 1;
+   edje_object_part_text_select_none(wd->ent, "elm.text");
+   edje_object_part_text_select_allow_set(wd->ent, "elm.text", 1);
+   edje_object_signal_emit(wd->ent, "elm,state,select,on", "elm");
+   elm_widget_scroll_hold_push(data);
+}
+
+static void
+_paste(void *data, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   evas_object_smart_callback_call(data, "selection,paste", NULL);
+   if (wd->sel_notify_handler)
+     {
+#ifdef HAVE_ELEMENTARY_X
+        if (elm_win_xwindow_get(elm_widget_top_get(data)))
+          {
+             ecore_x_selection_primary_request
+               (elm_win_xwindow_get(elm_widget_top_get(data)),
+                ECORE_X_SELECTION_TARGET_UTF8_STRING);
+             wd->selection_asked = 1;
+          }
+#endif        
+     }
+}
+
+static void
+_store_selection(Evas_Object *obj)
+{
+   Widget_Data *wd = elm_widget_data_get(obj);
+   const char *sel = edje_object_part_text_selection_get(wd->ent, "elm.text");
+   if (wd->cut_sel) eina_stringshare_del(wd->cut_sel);
+   wd->cut_sel = eina_stringshare_add(sel);
+}
+
+static void
+_cut(void *data, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   wd->selmode = 0;
+   edje_object_part_text_select_allow_set(wd->ent, "elm.text", 0);
+   edje_object_signal_emit(wd->ent, "elm,state,select,off", "elm");
+   elm_widget_scroll_hold_pop(data);
+   _store_selection(data);
+   edje_object_part_text_insert(wd->ent, "elm.text", "");
+   edje_object_part_text_select_none(wd->ent, "elm.text");
+}
+
+static void
+_copy(void *data, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   wd->selmode = 0;
+   edje_object_part_text_select_allow_set(wd->ent, "elm.text", 0);
+   edje_object_signal_emit(wd->ent, "elm,state,select,off", "elm");
+   elm_widget_scroll_hold_pop(data);
+   _store_selection(data);
+   edje_object_part_text_select_none(wd->ent, "elm.text");
+}
+
+static int
+_long_press(void *data)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   if (wd->hoversel) evas_object_del(wd->hoversel);
+   wd->hoversel = elm_hoversel_add(data);
+   elm_widget_sub_object_add(data, wd->hoversel);
+   elm_hoversel_label_set(wd->hoversel, "Text");
+   elm_hoversel_hover_parent_set(wd->hoversel, elm_widget_top_get(data));
+   evas_object_smart_callback_add(wd->hoversel, "dismissed", _dismissed, data);
+   if (!wd->selmode)
+     {
+        elm_hoversel_item_add(wd->hoversel, "Select", NULL, ELM_ICON_NONE, _select, data);
+        elm_hoversel_item_add(wd->hoversel, "Paste", NULL, ELM_ICON_NONE, _paste, data);
+     }
+   else
+     {
+        elm_hoversel_item_add(wd->hoversel, "Copy", NULL, ELM_ICON_NONE, _copy, data);
+        elm_hoversel_item_add(wd->hoversel, "Cut", NULL, ELM_ICON_NONE, _cut, data);
+     }
+   if (wd->hoversel)
+     {
+        _hoversel_position(data);
+        evas_object_show(wd->hoversel);
+        elm_hoversel_hover_begin(wd->hoversel);
+     }
+   wd->longpress_timer = NULL;
+   edje_object_part_text_select_allow_set(wd->ent, "elm.text", 0);
+   return 0;
+}
+
+static void
+_mouse_down(void *data, Evas *evas, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   Evas_Event_Mouse_Down *ev = event_info;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+   if (ev->button != 1) return;
+   //   if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
+   if (wd->longpress_timer) ecore_timer_del(wd->longpress_timer);
+   wd->longpress_timer = ecore_timer_add(1.0, _long_press, data);
+   wd->downx = ev->canvas.x;
+   wd->downy = ev->canvas.y;
+}
+
+static void
+_mouse_up(void *data, Evas *evas, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   Evas_Event_Mouse_Up *ev = event_info;
+   if (ev->button != 1) return;
+   if (wd->longpress_timer)
+     {
+        ecore_timer_del(wd->longpress_timer);
+        wd->longpress_timer = NULL;
+     }
+}
+
+static void
+_mouse_move(void *data, Evas *evas, Evas_Object *obj, void *event_info)
+{
+   Widget_Data *wd = elm_widget_data_get(data);
+   Evas_Event_Mouse_Move *ev = event_info;
+   if (!wd->selmode)
+     {
+        if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
+          {
+             if (wd->longpress_timer)
+               {
+                  ecore_timer_del(wd->longpress_timer);
+                  wd->longpress_timer = NULL;
+               }
+          }
+        else if (wd->longpress_timer)
+          {
+             Evas_Coord dx, dy;
+             
+             dx = wd->downx - ev->cur.canvas.x;
+             dx *= dx;
+             dy = wd->downy - ev->cur.canvas.y;
+             dy *= dy;
+             if ((dx + dy) > 
+                 ((_elm_config->finger_size / 2) * 
+                  (_elm_config->finger_size / 2)))
+               {
+                  ecore_timer_del(wd->longpress_timer);
+                  wd->longpress_timer = NULL;
+               }
+          }     
+     }
+   else if (wd->longpress_timer)
+     {
+        Evas_Coord dx, dy;
+        
+        dx = wd->downx - ev->cur.canvas.x;
+        dx *= dx;
+        dy = wd->downy - ev->cur.canvas.y;
+        dy *= dy;
+        if ((dx + dy) > 
+            ((_elm_config->finger_size / 2) * 
+             (_elm_config->finger_size / 2)))
+          {
+             ecore_timer_del(wd->longpress_timer);
+             wd->longpress_timer = NULL;
+          }
+     }
 }
 
 static const char *
@@ -335,6 +552,7 @@ _text_to_mkup(const char *text)
         else if (ch == '\t') str = _str_append(str, "<\t>", &str_len, &str_alloc);
         else if (ch == '<') str = _str_append(str, "&lt;", &str_len, &str_alloc);
         else if (ch == '>') str = _str_append(str, "&gt;", &str_len, &str_alloc);
+        else if (ch == '&') str = _str_append(str, "&amp;", &str_len, &str_alloc);
         else
           {
              char tstr[16];
@@ -594,6 +812,7 @@ _event_selection_notify(void *data, int type, void *event)
                   char *txt = _text_to_mkup(text_data->text);
                   if (txt)
                     {
+                       printf("inst: %s\n", txt);
                        elm_entry_entry_insert(data, txt);
                        free(txt);
                     }
@@ -639,7 +858,11 @@ elm_entry_add(Evas_Object *parent)
    wd->editable = 1;
    
    wd->ent = edje_object_add(e);
+   evas_object_event_callback_add(wd->ent, EVAS_CALLBACK_MOVE, _move, obj);
    evas_object_event_callback_add(wd->ent, EVAS_CALLBACK_RESIZE, _resize, obj);
+   evas_object_event_callback_add(wd->ent, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down, obj);
+   evas_object_event_callback_add(wd->ent, EVAS_CALLBACK_MOUSE_UP, _mouse_up, obj);
+   evas_object_event_callback_add(wd->ent, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move, obj);
                                          
    _elm_theme_set(wd->ent, "entry", "base", "default");
    edje_object_signal_callback_add(wd->ent, "entry,changed", "elm.text", _signal_entry_changed, obj);
@@ -782,6 +1005,12 @@ EAPI void
 elm_entry_select_none(Evas_Object *obj)
 {
    Widget_Data *wd = elm_widget_data_get(obj);
+   if (wd->selmode)
+     {
+        wd->selmode = 0;
+        edje_object_part_text_select_allow_set(wd->ent, "elm.text", 0);
+        edje_object_signal_emit(wd->ent, "elm,state,select,off", "elm");
+     }
    wd->have_selection = 0;
    edje_object_part_text_select_none(wd->ent, "elm.text");
 }
@@ -790,6 +1019,12 @@ EAPI void
 elm_entry_select_all(Evas_Object *obj)
 {
    Widget_Data *wd = elm_widget_data_get(obj);
+   if (wd->selmode)
+     {
+        wd->selmode = 0;
+        edje_object_part_text_select_allow_set(wd->ent, "elm.text", 0);
+        edje_object_signal_emit(wd->ent, "elm,state,select,off", "elm");
+     }
    wd->have_selection = 1;
    edje_object_part_text_select_all(wd->ent, "elm.text");
 }
index f4a615b..bb78767 100644 (file)
@@ -205,6 +205,7 @@ elm_smart_scroller_child_pos_set(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
    double vx, vy;
    
    API_ENTRY return;
+   // FIXME: allow for bounce outside of range
    sd->pan_func.max_get(sd->pan_obj, &mx, &my);
    if (mx > 0) vx = (double)x / (double)mx;
    else vx = 0.0;
@@ -514,6 +515,7 @@ _smart_event_mouse_up(void *data, Evas *e, Evas_Object *obj, void *event_info)
 
    sd = data;
    ev = event_info;
+   // FIXME: respect elm_widget_scroll_hold_get of parent container
    if (_elm_config->thumbscroll_enable)
      {
        if (ev->button == 1)
@@ -583,6 +585,7 @@ _smart_event_mouse_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
 
    sd = data;
    ev = event_info;
+   // FIXME: respect elm_widget_scroll_hold_get of parent container
    if (_elm_config->thumbscroll_enable)
      {
        if (sd->down.now)