Copy and paste Sample Overview

Mobile native

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

Main view Drag operation Text paste view

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

component layout structure

Implementation

To implement the copy/cut/paste mechanism:

  1. 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);
    }
    
  2. 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;
    }
    
  3. 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;
    }
    
  4. 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);
    }
    
  5. 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);
    }