changeset c174cb0018d8 in joypy/Joypy details: http://hg.osdn.jp/view/joypy/Joypy?cmd=changeset;node=c174cb0018d8 user: Simon Forman <sform****@hushm*****> date: Sat May 09 19:09:23 2020 -0700 description: Bring in the listbox widget with drag. You can drag items up and down to rearrange the list. diffstat: joy/gui/controllerlistbox.py | 127 +++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 127 insertions(+), 0 deletions(-) diffs (131 lines): diff -r 10b24748d6c3 -r c174cb0018d8 joy/gui/controllerlistbox.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/joy/gui/controllerlistbox.py Sat May 09 19:09:23 2020 -0700 @@ -0,0 +1,127 @@ +''' + Copyright (C) 2004 - 2008 Simon Forman + + This file is part of Xerblin. + + Xerblin is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +''' +from Tkinter import Listbox, SINGLE +from Tkdnd import dnd_start + + +class SourceWrapper: + ''' + Helper object for drag and drop. + ''' + def __init__(self, source, widget, index=None): + ''' + source is the object being dragged, widget is the container thats + initialing the drag operation, and index s thu index of the item + in the widget's model object (which presumably is a ListModel + containing the source object.) + ''' + self.source = source + self.widget = widget + self.index = index + + def dnd_end(self, target, event): + try: + self.widget.clear() + except AttributeError: + pass + + +class DraggyListbox(Listbox): + + def __init__(self, master=None, **kw): + + # Get our stack. + self.stack = kw.pop('items') + + # Override any passed in selectmode. + kw['selectmode'] = SINGLE + + Listbox.__init__(self, master, **kw) + + self.bind('<Button-1>', self.startDrag) + self.bind('<ButtonRelease-1>', self.clear) + + def clear(self, event=None): + i = self.curselection() + if i: + i = int(i[0]) + self.selection_clear(i) + + def startDrag(self, event): + i = self.nearest(event.y) + if i >= 0: + self.selection_set(i) + source = self.stack[i] + source = SourceWrapper(source, self, i) + event.num = 1 # Don't ask. (See Tkdnd.py) + dnd_start(source, event) + return "break" + + +class ControllerListbox(DraggyListbox): + + def __init__(self, master=None, **kw): + DraggyListbox.__init__(self, master, **kw) + self._dragIndex = -1 + + def dnd_accept(self, source, event): + self.focus_force() + return self + + def dnd_enter(self, source, event): + pass + + def dnd_motion(self, source, event): + I = self.nearest(event.y_root - self.winfo_rooty()) + if self._dragIndex >= 0: + self.delete(self._dragIndex) + self._dragIndex = I + self.insert(I, '---') + + def dnd_leave(self, source, event): + if self._dragIndex >= 0: + self.delete(self._dragIndex) + self._dragIndex = -1 + + def dnd_commit(self, source, event): + i = self._dragIndex + + if i >= 0: + self.delete(i) + self._dragIndex = -1 + + try: + if self is source.widget: + + # Don't duplicate something by dropping it on itself. + if i == source.index: + return + + # Instead, move it by removing it before the pending append. + del self.stack[source.index] + if i > source.index: + i -= 1 + + self.stack.insert(i, source.source) + + finally: + self.clear() +