NOT FULLY WORKING, got the main keyboard showing up. Just show the secondary one...
[ejpi] / src / libraries / qtpieboard.py
1 #!/usr/bin/env python
2
3
4 from __future__ import division
5
6 import os
7 import warnings
8
9 from PyQt4 import QtGui
10 from PyQt4 import QtCore
11
12 import qtpie
13
14
15 class PieKeyboard(object):
16
17         SLICE_CENTER = -1
18         SLICE_NORTH = 0
19         SLICE_NORTH_WEST = 1
20         SLICE_WEST = 2
21         SLICE_SOUTH_WEST = 3
22         SLICE_SOUTH = 4
23         SLICE_SOUTH_EAST = 5
24         SLICE_EAST = 6
25         SLICE_NORTH_EAST = 7
26
27         MAX_ANGULAR_SLICES = 8
28
29         SLICE_DIRECTIONS = [
30                 SLICE_CENTER,
31                 SLICE_NORTH,
32                 SLICE_NORTH_WEST,
33                 SLICE_WEST,
34                 SLICE_SOUTH_WEST,
35                 SLICE_SOUTH,
36                 SLICE_SOUTH_EAST,
37                 SLICE_EAST,
38                 SLICE_NORTH_EAST,
39         ]
40
41         SLICE_DIRECTION_NAMES = [
42                 "CENTER",
43                 "NORTH",
44                 "NORTH_WEST",
45                 "WEST",
46                 "SOUTH_WEST",
47                 "SOUTH",
48                 "SOUTH_EAST",
49                 "EAST",
50                 "NORTH_EAST",
51         ]
52
53         def __init__(self, rows, columns):
54                 self._layout = QtGui.QGridLayout()
55
56                 self.__cells = {}
57
58         @property
59         def toplevel(self):
60                 return self._layout
61
62         def add_pie(self, row, column, pieButton):
63                 assert len(pieButton) == 8
64                 self._layout.addWidget(pieButton, row, column)
65                 self.__cells[(row, column)] = pieButton
66
67         def get_pie(self, row, column):
68                 return self.__cells[(row, column)]
69
70
71 class KeyboardModifier(object):
72
73         def __init__(self, name):
74                 self.name = name
75                 self.lock = False
76                 self.once = False
77
78         @property
79         def isActive(self):
80                 return self.lock or self.once
81
82         def on_toggle_lock(self, *args, **kwds):
83                 self.lock = not self.lock
84
85         def on_toggle_once(self, *args, **kwds):
86                 self.once = not self.once
87
88         def reset_once(self):
89                 self.once = False
90
91
92 def parse_keyboard_data(text):
93         return eval(text)
94
95
96 def _enumerate_pie_slices(pieData, iconPaths):
97         for direction, directionName in zip(
98                 PieKeyboard.SLICE_DIRECTIONS, PieKeyboard.SLICE_DIRECTION_NAMES
99         ):
100                 if directionName in pieData:
101                         sliceData = pieData[directionName]
102
103                         action = QtGui.QAction(None)
104                         try:
105                                 action.setText(sliceData["text"])
106                         except KeyError:
107                                 pass
108                         try:
109                                 relativeIconPath = sliceData["path"]
110                         except KeyError:
111                                 pass
112                         else:
113                                 for iconPath in iconPaths:
114                                         absIconPath = os.path.join(iconPath, relativeIconPath)
115                                         if os.path.exists(absIconPath):
116                                                 action.setIcon(QtGui.QIcon(absIconPath))
117                                                 break
118                         pieItem = qtpie.QActionPieItem(action)
119                 else:
120                         pieItem = qtpie.PieFiling.NULL_CENTER
121                         action = ""
122                 yield direction, pieItem, action
123
124
125 def load_keyboard(keyboardName, dataTree, keyboard, keyboardHandler, iconPaths):
126         for (row, column), pieData in dataTree.iteritems():
127                 pieItems = list(_enumerate_pie_slices(pieData, iconPaths))
128                 assert pieItems[0][0] == PieKeyboard.SLICE_CENTER, pieItems[0]
129                 _, center, centerAction = pieItems.pop(0)
130
131                 pieButton = qtpie.QPieButton(center)
132                 pieButton.set_center(center)
133                 for direction, pieItem, action in pieItems:
134                         pieButton.insertItem(pieItem)
135                 keyboard.add_pie(row, column, pieButton)
136
137
138 class KeyboardHandler(object):
139
140         def __init__(self, keyhandler):
141                 self.__keyhandler = keyhandler
142                 self.__commandHandlers = {}
143                 self.__modifiers = {}
144                 self.__sliceActions = {}
145
146                 self.register_modifier("Shift")
147                 self.register_modifier("Super")
148                 self.register_modifier("Control")
149                 self.register_modifier("Alt")
150
151         def register_command_handler(self, command, handler):
152                 #@todo Make this handle multiple handlers or switch to gobject events
153                 self.__commandHandlers["[%s]" % command] = handler
154
155         def unregister_command_handler(self, command):
156                 #@todo Make this handle multiple handlers or switch to gobject events
157                 del self.__commandHandlers["[%s]" % command]
158
159         def register_modifier(self, modifierName):
160                 mod = KeyboardModifier(modifierName)
161                 self.register_command_handler(modifierName, mod.on_toggle_lock)
162                 self.__modifiers["<%s>" % modifierName] = mod
163
164         def unregister_modifier(self, modifierName):
165                 self.unregister_command_handler(modifierName)
166                 del self.__modifiers["<%s>" % modifierName]
167
168         def map_slice_action(self, slice, action):
169                 self.__sliceActions[slice.name] = action
170
171         def __call__(self, pie, slice, direction):
172                 try:
173                         action = self.__sliceActions[slice.name]
174                 except KeyError:
175                         return
176
177                 activeModifiers = [
178                         mod.name
179                         for mod in self.__modifiers.itervalues()
180                                 if mod.isActive
181                 ]
182
183                 needResetOnce = False
184                 if action.startswith("[") and action.endswith("]"):
185                         commandName = action[1:-1]
186                         if action in self.__commandHandlers:
187                                 self.__commandHandlers[action](commandName, activeModifiers)
188                                 needResetOnce = True
189                         else:
190                                 warnings.warn("Unknown command: [%s]" % commandName)
191                 elif action.startswith("<") and action.endswith(">"):
192                         modName = action[1:-1]
193                         for mod in self.__modifiers.itervalues():
194                                 if mod.name == modName:
195                                         mod.on_toggle_once()
196                                         break
197                         else:
198                                 warnings.warn("Unknown modifier: <%s>" % modName)
199                 else:
200                         self.__keyhandler(action, activeModifiers)
201                         needResetOnce = True
202
203                 if needResetOnce:
204                         for mod in self.__modifiers.itervalues():
205                                 mod.reset_once()