Elementary: Initial support for copy & paste. selection_get/set/clear

works with Entry and has a test, the generic drop_cb is unfinished and
untested.
This commit is contained in:
Kai Huuhko 2013-04-29 09:37:07 +00:00
parent c14ab47b09
commit 5a1180d1a0
6 changed files with 263 additions and 89 deletions

View File

@ -1,7 +1,7 @@
"""Structure holding the info about selected data.
"""
cdef class SelectionData(object):
"""Structure holding the info about selected data."""
cdef Elm_Selection_Data *sel_data
property x:
@ -15,13 +15,13 @@ cdef class SelectionData(object):
return self.sel_data.y
property format:
""":type: Elm_Selection_Format"""
""":type: :ref:`Elm_Selection_Format`"""
def __get__(self):
return self.sel_data.format
property data:
def __get__(self):
# TODO
# TODO: void *
return None
property len:
@ -32,7 +32,7 @@ cdef class SelectionData(object):
property action:
"""The action to perform with the data
:type: Elm_Xdnd_Action
:type: :ref:`Elm_Xdnd_Action`
:since: 1.8
"""
@ -40,23 +40,40 @@ cdef class SelectionData(object):
return self.sel_data.action
cdef Eina_Bool elm_drop_cb(void *data, Evas_Object *obj, Elm_Selection_Data *ev):
"""Callback invoked in when the selected data is 'dropped' at its destination.
"""Callback invoked when the selected data is 'dropped' at its destination.
:param data: Application specific data
:param obj: The evas object where selected data is 'dropped'.
:param ev: struct holding information about selected data
"""
pass
cdef:
SelectionData sd = SelectionData.__new__(SelectionData)
bint ret
sd.sel_data = ev
o = <object>data
cb_func = o.cnp_drop_cb
cb_data = o.cnp_drop_data
ret = cb_func(o, sd, cb_data)
sd.sel_data = NULL
return ret
cdef void elm_selection_loss_cb(void *data, Elm_Sel_Type selection):
"""Callback invoked in when the selection ownership for a given selection is lost.
"""Callback invoked when the selection ownership for a given selection is lost.
:param data: Application specific data
:param selection: The selection that is lost
"""
pass
o = <object>data
cb_func = o.cnp_selection_loss_cb
cb_data = o.cnp_selection_loss_data
cb_func(selection, cb_data)
cdef Evas_Object *elm_drag_icon_create_cb(void *data, Evas_Object *win, Evas_Coord *xoff, Evas_Coord *yoff):
"""Callback called to create a drag icon object

View File

@ -3,7 +3,8 @@ from efl.evas cimport Eina_Bool, Eina_Rectangle, Evas_Object, \
from enums cimport Elm_Wrap_Type, Elm_Text_Format, Elm_Cnp_Mode, \
Elm_Scroller_Policy, Elm_Input_Panel_Layout, Elm_Input_Panel_Lang, \
Elm_Input_Panel_Lang, Elm_Input_Panel_Return_Key_Type, \
Elm_Autocapital_Type, Elm_Icon_Type
Elm_Autocapital_Type, Elm_Icon_Type, Elm_Sel_Type, Elm_Sel_Format, \
Elm_Xdnd_Action
from libc.string cimport const_char
from libc.stdlib cimport const_void
@ -25,6 +26,13 @@ cdef extern from "Elementary.h":
Eina_Bool hover_top
Eina_Bool hover_bottom
ctypedef struct Elm_Selection_Data:
Evas_Coord x, y
Elm_Sel_Format format
void *data
size_t len
Elm_Xdnd_Action action
ctypedef struct Elm_Entry_Context_Menu_Item:
pass
@ -32,6 +40,8 @@ cdef extern from "Elementary.h":
ctypedef void (*Elm_Entry_Filter_Cb)(void *data, Evas_Object *entry, char **text)
ctypedef Eina_Bool (*Elm_Drop_Cb) (void *data, Evas_Object *obj, Elm_Selection_Data *ev)
# Data for the elm_entry_filter_limit_size() entry filter.
ctypedef struct Elm_Entry_Filter_Limit_Size:
int max_char_count # The maximum number of characters allowed.
@ -139,3 +149,5 @@ cdef extern from "Elementary.h":
const_char * elm_entry_context_menu_item_label_get(const_Elm_Entry_Context_Menu_Item *item)
void elm_entry_context_menu_item_icon_get(const_Elm_Entry_Context_Menu_Item *item, const_char **icon_file, const_char **icon_group, Elm_Icon_Type *icon_type)
Eina_Bool elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)

View File

@ -1925,6 +1925,26 @@ cdef class Entry(Object):
elm_entry_anchor_hover_end(self.obj)
# Copy and paste
def cnp_selection_get(self, selection, format):
"""Retrieve data from a widget that has a selection.
Gets the current selection data from a widget.
.. seealso::
:py:func:`efl.elementary.object.Object.cnp_selection_get`
:param selection: Selection type for copying and pasting
:param format: Selection format
:raise RuntimeError: if getting cnp data fails.
"""
if not elm_cnp_selection_get(self.obj, selection, format, NULL, NULL):
raise RuntimeError("Could not get cnp data from widget.")
def callback_changed_add(self, func, *args, **kwargs):
"""The text within the entry was changed."""
self._callback_add("changed", func, *args, **kwargs)

View File

@ -152,10 +152,10 @@ cdef extern from "Elementary.h":
const_char * elm_object_translatable_text_get(Evas_Object *obj)
# TODO: CnP
# Eina_Bool elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, const_void *buf, size_t buflen)
# Eina_Bool elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
# Eina_Bool elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection)
# void elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const_void *data)
Eina_Bool elm_cnp_selection_set(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, const_void *buf, size_t buflen)
Eina_Bool elm_cnp_selection_get(Evas_Object *obj, Elm_Sel_Type selection, Elm_Sel_Format format, Elm_Drop_Cb datacb, void *udata)
Eina_Bool elm_object_cnp_selection_clear(Evas_Object *obj, Elm_Sel_Type selection)
void elm_cnp_selection_loss_callback_set(Evas_Object *obj, Elm_Sel_Type selection, Elm_Selection_Loss_Cb func, const_void *data)
# Eina_Bool elm_drop_target_add(Evas_Object *obj, Elm_Sel_Format format, Elm_Drag_State entercb, void *enterdata, Elm_Drag_State leavecb, void *leavedata, Elm_Drag_Pos poscb, void *posdata, Elm_Drop_Cb dropcb, void *cbdata)
# Eina_Bool elm_drop_target_del(Evas_Object *obj)
# Eina_Bool elm_drag_start(Evas_Object *obj, Elm_Sel_Format format, const_char *data, Elm_Xdnd_Action action, Elm_Drag_Icon_Create_Cb createicon, void *createdata, Elm_Drag_Pos dragpos, void *dragdata, Elm_Drag_Accept acceptcb, void *acceptdata, Elm_Drag_State dragdone, void *donecbdata)
@ -171,9 +171,10 @@ cdef class Canvas(evasCanvas):
pass
cdef class Object(evasObject):
cdef object _elmcallbacks
cdef object _elm_event_cbs
cdef object _elm_signal_cbs
cdef:
object _elmcallbacks, _elm_event_cbs, _elm_signal_cbs
object cnp_drop_cb, cnp_drop_data
object cnp_selection_loss_cb, cnp_selection_loss_data
cpdef text_set(self, text)
cpdef text_get(self)

View File

@ -22,9 +22,11 @@ Copy and Paste
--------------
Implements the following functionality
a. select, copy/cut and paste
b. clipboard
c. drag and drop
a. select, copy/cut and paste
b. clipboard
c. drag and drop
in order to share data across application windows.
Contains functions to select text or a portion of data,
@ -46,11 +48,13 @@ Clipboard selection is for explicit copying behavior
Thus, in applications most cases only use the clipboard selection.
As stated before, taking ownership of a selection doesn't move any actual data.
Copying and Pasting is described as follows:
1. Copy text in Program A : Program A takes ownership of the selection
2. Paste text in Program B : Program B notes that Program A owns the selection
3. Program B asks A for the text
4. Program A responds and sends the text to program B
5. Program B pastes the response
1. Copy text in Program A : Program A takes ownership of the selection
2. Paste text in Program B : Program B notes that Program A owns the selection
3. Program B asks A for the text
4. Program A responds and sends the text to program B
5. Program B pastes the response
More information is on
- http://www.jwz.org/doc/x-cut-and-paste.html
- X11R6 Inter-Client Communication Conventions Manual, section 2
@ -79,7 +83,8 @@ Selection type
==============
Defines the types of selection property names.
:see: `http://www.x.org/docs/X11/xlib.pdf`_ for more details.
:see: http://www.x.org/docs/X11/xlib.pdf for more details.
.. data:: ELM_SEL_TYPE_PRIMARY
@ -140,6 +145,7 @@ XDND action
===========
Defines the kind of action associated with the drop data if for XDND
:since: 1.8
.. data:: ELM_XDND_ACTION_UNKNOWN
@ -156,7 +162,7 @@ Defines the kind of action associated with the drop data if for XDND
.. data:: ELM_XDND_ACTION_PRIVATE
Pricate action type
Private action type
.. data:: ELM_XDND_ACTION_ASK
@ -177,7 +183,8 @@ Defines the kind of action associated with the drop data if for XDND
"""
from cpython cimport PyObject, Py_INCREF, Py_DECREF, PyObject_GetAttr
from cpython cimport PyObject, Py_INCREF, Py_DECREF, PyObject_GetAttr, \
PyObject_GetBuffer, PyBuffer_Release, PyBUF_SIMPLE, PyObject_CheckBuffer
include "widget_header.pxi"
include "tooltips.pxi"
@ -243,7 +250,7 @@ cdef void _object_callback(void *data,
else:
ei = event_conv(<long>event_info)
func(obj, ei, *args, **kargs)
except Exception, e:
except:
traceback.print_exc()
cdef bint _event_dispatcher(Object obj, Object src, Evas_Callback_Type t, event_info):
@ -252,7 +259,7 @@ cdef bint _event_dispatcher(Object obj, Object src, Evas_Callback_Type t, event_
for func, args, kargs in obj._elm_event_cbs:
try:
ret = func(obj, src, t, event_info, *args, **kargs)
except Exception, e:
except:
traceback.print_exc()
else:
return ret
@ -292,10 +299,10 @@ cdef void signal_callback(void *data, Evas_Object *obj,
for func, args, kargs in lst:
try:
func(self, _ctouni(emission), _ctouni(source), *args, **kargs)
except Exception, e:
except:
traceback.print_exc()
# TODO: include "cnp_callbacks.pxi"
include "cnp_callbacks.pxi"
# TODO: Is this handled in Eo now?
cdef void _event_data_del_cb(void *data, Evas_Object *o, void *event_info) with gil:
@ -587,6 +594,7 @@ cdef class Object(evasObject):
:type: string
"""
# FIXME: Now that we have Eo, is this useful anymore?
def __get__(self):
return elm_object_widget_type_get(self.obj)
@ -1588,83 +1596,97 @@ cdef class Object(evasObject):
"""
return <long>self.obj
# TODO: Copy and Paste
# def cnp_selection_set(self, Elm_Sel_Type selection, Elm_Sel_Format format, buf, buflen):
# """Set copy data for a widget.
# Copy and Paste
def cnp_selection_set(self, Elm_Sel_Type selection, Elm_Sel_Format format, buf):
"""Set copy data for a widget.
# Set copy data and take ownership of selection. Format is used for specifying the selection type,
# and this is used during pasting.
Set copy data and take ownership of selection. Format is used for specifying the selection type,
and this is used during pasting.
# :param selection: Selection type for copying and pasting
# :param format: Selection format
# :param buf: The data selected
# :param buflen: The size of @p buf
# :raise RuntimeError: if setting cnp data fails.
:param selection: Selection type for copying and pasting
:type selection: :ref:`Elm_Sel_Type`
:param format: Selection format
:type format: :ref:`Elm_Sel_Format`
:param buf: The data selected
:type buf: An object that supports the new buffer interface
# """
# if not elm_cnp_selection_set(self.obj, selection, format, const_void *buf, size_t buflen):
# raise RuntimeError("Could not set cnp data for widget.")
:raise RuntimeError: if setting cnp data fails.
# def cnp_selection_get(self, selection, format, datacb, udata):
# """Retrieve data from a widget that has a selection.
"""
cdef Py_buffer view
if isinstance(buf, unicode): buf = PyUnicode_AsUTF8String(buf)
if not PyObject_CheckBuffer(buf):
raise TypeError("The provided object does not support buffer interface.")
PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE)
if not elm_cnp_selection_set(self.obj, selection, format, <const_void *>view.buf, view.itemsize):
raise RuntimeError("Could not set cnp data for widget.")
PyBuffer_Release(&view)
# Gets the current selection data from a widget.
# The widget input here will usually be elm_entry,
# in which case @p datacb and @p udata can be NULL.
# If a different widget is passed, @p datacb and @p udata are used for retrieving data.
def cnp_selection_get(self, selection, format, datacb, udata = None):
"""Retrieve data from a widget that has a selection.
# @see also elm_cnp_selection_set()
Gets the current selection data from a widget.
The widget input here will usually be elm_entry,
in which case @p datacb and @p udata can be NULL.
If a different widget is passed, @p datacb and @p udata are used for retrieving data.
# :param selection: Selection type for copying and pasting
# :param format: Selection format
# :param datacb: The user data callback if the target widget isn't elm_entry
# :param udata: The user data pointer for @p datacb
# :raise RuntimeError: if getting cnp data fails.
:param selection: Selection type for copying and pasting
:param format: Selection format
:param datacb: The user data callback if the target widget isn't elm_entry
:param udata: The user data pointer for @p datacb
# """
# if not elm_cnp_selection_get(self.obj, selection, format, Elm_Drop_Cb datacb, void *udata):
# raise RuntimeError("Could not get cnp data from widget.")
:raise RuntimeError: if getting cnp data fails.
# def cnp_selection_clear(self, Elm_Sel_Type selection):
# """Clear the selection data of a widget.
"""
if not callable(datacb):
raise TypeError("datacb is not callable.")
self.cnp_drop_cb = datacb
self.cnp_drop_data = udata
if not elm_cnp_selection_get(self.obj, selection, format, elm_drop_cb, <void *>self):
raise RuntimeError("Could not get cnp data from widget.")
# Clear all data from the selection which is owned by a widget.
def cnp_selection_clear(self, Elm_Sel_Type selection):
"""Clear the selection data of a widget.
# @see also elm_cnp_selection_set()
Clear all data from the selection which is owned by a widget.
# :param selection: Selection type for copying and pasting
# :raise RuntimeError: if clearing cnp data fails.
:param selection: Selection type for copying and pasting
:type selection: :ref:`Elm_Sel_Type`
# """
# if not elm_object_cnp_selection_clear(self.obj, selection):
# raise RuntimeError("Could not clear cnp data from widget.")
:raise RuntimeError: if clearing cnp data fails.
"""
if not elm_object_cnp_selection_clear(self.obj, selection):
raise RuntimeError("Could not clear cnp data from widget.")
# def cnp_selection_loss_callback_set(self, Elm_Sel_Type selection, func, data):
# """Set a function to be called when a selection is lost
def cnp_selection_loss_callback_set(self, Elm_Sel_Type selection, func, data = None):
"""Set a function to be called when a selection is lost
# The function @p func is set of be called when selection @p selection is lost
# to another process or when elm_cnp_selection_set() is called. If @p func
# is NULL then it is not called. @p data is passed as the data parameter to
# the callback functions and selection is passed in as the selection that
# has been lost.
The function @p func is set of be called when selection @p selection is lost
to another process or when elm_cnp_selection_set() is called. If @p func
is NULL then it is not called. @p data is passed as the data parameter to
the callback functions and selection is passed in as the selection that
has been lost.
# elm_cnp_selection_set() and elm_object_cnp_selection_clear() automatically
# set this los callback to NULL when called. If you wish to take the selection
# and then be notified of loss please do this (for example)::
elm_cnp_selection_set() and elm_object_cnp_selection_clear() automatically
set this loss callback to NULL when called. If you wish to take the selection
and then be notified of loss please do this (for example)::
# elm_cnp_selection_set(obj, ELM_SEL_TYPE_PRIMARY, ELM_SEL_FORMAT_TEXT, "hello", strlen(hello));
# elm_cnp_selection_loss_callback_set(obj, ELM_SEL_TYPE_PRIMARY, loss_cb, NULL);
obj.cnp_selection_set(ELM_SEL_TYPE_PRIMARY, ELM_SEL_FORMAT_TEXT, "hello")
obj.cnp_selection_loss_callback_set(ELM_SEL_TYPE_PRIMARY, loss_cb)
# @see also elm_cnp_selection_set()
:param selection: Selection to be notified of for loss
:param func: The function to call
:param data: The data pointer passed to the function.
# :param selection: Selection to be notified of for loss
# :param func: The function to call
# :param data: The data pointer passed to the function.
# """
# elm_cnp_selection_loss_callback_set(self.obj, selection, Elm_Selection_Loss_Cb func, const void *data)
"""
if not callable(func):
raise TypeError("func is not callable.")
self.cnp_selection_loss_cb = func
self.cnp_selection_loss_data = data
elm_cnp_selection_loss_callback_set(self.obj, selection, elm_selection_loss_cb, <const_void *>data)
# TODO:
# def drop_target_add(self, Elm_Sel_Format format, entercb, enterdata, leavecb, leavedata, poscb, posdata, dropcb, dropdata):
# """Set the given object as a target for drops for drag-and-drop

View File

@ -0,0 +1,102 @@
from efl import elementary
from efl.evas import EVAS_HINT_FILL, EVAS_HINT_EXPAND
from efl.elementary.window import StandardWindow
from efl.elementary.label import Label
from efl.elementary.entry import Entry, ELM_WRAP_CHAR
from efl.elementary.grid import Grid
from efl.elementary.button import Button
from efl.elementary.object import ELM_SEL_TYPE_CLIPBOARD, ELM_SEL_FORMAT_TEXT
def bt_copy_clicked(obj, data):
en = data
txt = en.text
glb.text = txt
en.parent_widget.cnp_selection_set(ELM_SEL_TYPE_CLIPBOARD, \
ELM_SEL_FORMAT_TEXT, txt)
def bt_paste_clicked(obj, data):
en = data
en.cnp_selection_get(ELM_SEL_TYPE_CLIPBOARD, ELM_SEL_FORMAT_TEXT)
def bt_clear_clicked(obj, data):
en = data
glb.text = ""
en.parent_widget.cnp_selection_clear(ELM_SEL_TYPE_CLIPBOARD)
def cnp_clicked(obj):
win = StandardWindow("copypaste", "CopyPaste")
win.autodel = True
if obj is None:
win.callback_delete_request_add(lambda o: elementary.exit())
gd = Grid(win)
gd.size = 100, 100
gd.size_hint_weight = EVAS_HINT_EXPAND, EVAS_HINT_EXPAND
win.resize_object_add(gd)
gd.show()
en = Entry(win)
en.scrollable = True
en.line_wrap = ELM_WRAP_CHAR
en.size_hint_weight = EVAS_HINT_EXPAND, EVAS_HINT_EXPAND
en.size_hint_align = EVAS_HINT_FILL, EVAS_HINT_FILL
en.text = "Elementary provides "
gd.pack(en, 10, 10, 60, 30)
en.show()
bt = Button(win)
bt.text = "Copy from left entry"
bt.callback_clicked_add(bt_copy_clicked, en)
gd.pack(bt, 70, 10, 22, 30)
bt.show()
bt = Button(win)
bt.text = "Clear clipboard"
bt.callback_clicked_add(bt_clear_clicked, en)
gd.pack(bt, 70, 70, 22, 20)
bt.show()
en = Entry(win)
en.scrollable = True
en.line_wrap = ELM_WRAP_CHAR
en.size_hint_weight = EVAS_HINT_EXPAND, EVAS_HINT_EXPAND
en.size_hint_align = EVAS_HINT_FILL, EVAS_HINT_FILL
en.text = "rich copying and pasting functionality,"
gd.pack(en, 10, 40, 60, 30)
en.show()
bt = Button(win)
bt.text = "Paste to left entry"
bt.callback_clicked_add(bt_paste_clicked, en)
gd.pack(bt, 70, 40, 22, 30)
bt.show()
lb = Label(win)
lb.text = "<b>Clipboard:</b>"
lb.size_hint_weight = 0.0, 0.0
lb.size_hint_align = EVAS_HINT_FILL, EVAS_HINT_FILL
gd.pack(lb, 10, 70, 60, 10)
lb.show()
global glb
glb = Label(win)
glb.text = ""
glb.size_hint_weight = 0.0, 0.0
glb.size_hint_align = EVAS_HINT_FILL, EVAS_HINT_FILL
gd.pack(glb, 10, 80, 60, 10)
glb.show()
win.size = 480, 200
win.show()
if __name__ == "__main__":
elementary.init()
cnp_clicked(None)
elementary.run()
elementary.shutdown()