work on bettre touchscreen text selection support. not 100% done yet. been

playing with ideas. this one seems best.



SVN revision: 39579
This commit is contained in:
Carsten Haitzler 2009-03-19 13:36:46 +00:00
parent 2685a2feef
commit e5298074e7
5 changed files with 295 additions and 8 deletions

View 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

View 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);

View 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
@ -188,6 +194,15 @@ elm_hoversel_icon_set(Evas_Object *obj, Evas_Object *icon)
elm_button_icon_set(wd->btn, 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)
{

View 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);
}
@ -127,13 +132,225 @@ _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");
}

View 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)