The Copy and Paste sample application demonstrates how you can incorporate a copy/cut/paste mechanism into an EFL-based application. The sample operates on a predefined text block using the system clipboard to perform the operations.
The following figure illustrates the application views.
Figure: Copy and Paste screens
The main screen consists of 2 components:
- elm_label is the text source component.
- elm_entry is the text sink component.
The copy-paste operation is initiated by a long press on the source component, and performed through a drag and drop operation. You can:
- Long press on the source component
The hover window is shown and the text is copied from the source component to the clipboard and pasted from the clipboard to the hover window.
- Drag the hover window
The hover window follows the mouse pointer.
- Drop to the sink component
The text is cut from the hover window to the clipboard and pasted from the clipboard to the sink component. The hover window is hidden.
Figure: Component layout structure
Implementation
To implement the copy/cut/paste mechanism:
-
The controller_application_view_create() function in the controller module is responsible for calling the view creation-specific routines. Also, it attaches all necessary touch (mouse) callbacks.
bool controller_application_view_create(void) { char full_path_source_extension[FILE_PATH_MAX_LEN] = {0,}; char full_path_sink_image[FILE_PATH_MAX_LEN] = {0,}; _resource_path_compile(SOURCE_THEME_EXTENSION, full_path_source_extension); _resource_path_compile(SINK_IMAGE, full_path_sink_image); if (!main_window_create()) { dlog_print(DLOG_ERROR, LOG_TAG, "View creation failed: on window handle"); return false; } if (!main_window_source_wgt_create(full_path_source_extension)) { dlog_print(DLOG_ERROR, LOG_TAG, "View creation failed: on source component"); return false; } if (!main_window_sink_entry_wgt_create(full_path_sink_image)) { dlog_print(DLOG_ERROR, LOG_TAG, "View creation failed: on sink component"); return false; } if (!main_window_hover_create(full_path_source_extension)) { dlog_print(DLOG_ERROR, LOG_TAG, "View creation failed: on hover"); return false; } _attach_callbacks(); dlog_print(DLOG_DEBUG, LOG_TAG, "View creation successful"); return true; } static void _attach_callbacks(void) { ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_DOWN, _press_cb, NULL); ecore_event_handler_add(ECORE_EVENT_MOUSE_MOVE, _move_cb, NULL); ecore_event_handler_add(ECORE_EVENT_MOUSE_BUTTON_UP, _unpress_cb, NULL); }
-
Each time the user touches the screen, the _press_cb() callback is called with a hit test. If the hit is in the source region, a hover window is shown. It uses the evas_object_show() function internally.
static Eina_Bool _press_cb(void *data, int type, void *event) { Ecore_Event_Mouse_Button *press = (Ecore_Event_Mouse_Button *)event; // State test && hit test if (!(s_controller_data.state == CONTROLLER_STATE_NORMAL && main_window_source_wgt_hit_test(press->root.x, press->root.y))) { return EINA_TRUE; } // Paste text from clipboard to hover main_window_hover_text_paste(); hover_window_coordinates_set(press->root.x, press->root.y); hover_window_show(); return EINA_TRUE; }
-
The hover window drag is implemented in the controller module _move_cb() function. It is responsible for changing the window position and uses the evas_object_move() function internally.
static Eina_Bool _move_cb(void *data, int type, void *event) { Ecore_Event_Mouse_Move *move = (Ecore_Event_Mouse_Move *)event; hover_window_coordinates_set(move->root.x, move->root.y); return EINA_TRUE; }
-
The clipboard mechanism is used to copy the text from the source to the hover window:
void hover_window_text_paste(const char * text_to_paste) { // You can just use elm_object_text_set, but for example purpose use the cnp mechanism // Use copy mechanism, fill copy buffer associated with the label elm_cnp_selection_set(s_view_data.label, ELM_SEL_TYPE_PRIMARY, ELM_SEL_FORMAT_TEXT, text_to_paste, strlen(text_to_paste)); // Get the text from the clipboard and since // you use the 'Label' component type, you have to use a custom drop callback: _text_paste_cb elm_cnp_selection_get(s_view_data.label, ELM_SEL_TYPE_PRIMARY, ELM_SEL_FORMAT_TEXT, _text_paste_cb, NULL); }
-
When the user releases the mouse or touch, the _unpress_cb() callback is called with a hit test. It checks whether the finger or cursor is in the sink component area.
static Eina_Bool _unpress_cb(void *data, int type, void *event) { Ecore_Event_Mouse_Button *unpress = (Ecore_Event_Mouse_Button *)event; hover_window_hide(); // State && hit test if (s_controller_data.state == CONTROLLER_STATE_DRAG && main_window_sink_wgt_hit_test(unpress->root.x, unpress->root.y)) { main_window_sink_wgt_text_paste(); } }
After the hit test, the clipboard mechanism is used again to copy the text to the sink component:
void sink_wgt_text_paste(Evas_Object *wgt) { // Use paste mechanism: // sink component is of the 'Entry' type so callback can be NULL elm_cnp_selection_get(wgt, ELM_SEL_TYPE_PRIMARY, ELM_SEL_FORMAT_TEXT, NULL, NULL); }