OLD | NEW |
| (Empty) |
1 # vim:set et sts=4 sw=4: | |
2 # | |
3 # ibus - The Input Bus | |
4 # | |
5 # Copyright(c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com> | |
6 # Copyright(c) 2007-2010 Red Hat, Inc. | |
7 # | |
8 # This library is free software; you can redistribute it and/or | |
9 # modify it under the terms of the GNU Lesser General Public | |
10 # License as published by the Free Software Foundation; either | |
11 # version 2 of the License, or(at your option) any later version. | |
12 # | |
13 # This library is distributed in the hope that it will be useful, | |
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 # GNU Lesser General Public License for more details. | |
17 # | |
18 # You should have received a copy of the GNU Lesser General Public | |
19 # License along with this program; if not, write to the | |
20 # Free Software Foundation, Inc., 59 Temple Place, Suite 330, | |
21 # Boston, MA 02111-1307 USA | |
22 | |
23 import gtk | |
24 import gtk.gdk as gdk | |
25 import gobject | |
26 import ibus | |
27 import icon | |
28 from handle import Handle | |
29 from menu import menu_position,\ | |
30 ImageMenuItem,\ | |
31 Menu,\ | |
32 CheckMenuItem,\ | |
33 RadioMenuItem,\ | |
34 SeparatorMenuItem | |
35 from engineabout import EngineAbout | |
36 from toolitem import ToolButton,\ | |
37 ToggleToolButton, \ | |
38 SeparatorToolItem, \ | |
39 MenuToolButton | |
40 | |
41 from i18n import _, N_ | |
42 | |
43 ICON_SIZE = gtk.ICON_SIZE_MENU | |
44 | |
45 class LanguageBar(gtk.Toolbar): | |
46 __gtype_name__ = "IBusLanguagePanel" | |
47 __gsignals__ = { | |
48 "property-activate" : ( | |
49 gobject.SIGNAL_RUN_FIRST, | |
50 gobject.TYPE_NONE, | |
51 (gobject.TYPE_STRING, gobject.TYPE_INT)), | |
52 "get-im-menu" : ( | |
53 gobject.SIGNAL_RUN_LAST, | |
54 gobject.TYPE_PYOBJECT, | |
55 ()), | |
56 "show-engine-about" : ( | |
57 gobject.SIGNAL_RUN_LAST, | |
58 gobject.TYPE_PYOBJECT, | |
59 ()), | |
60 "position-changed" : ( | |
61 gobject.SIGNAL_RUN_LAST, | |
62 gobject.TYPE_NONE, | |
63 (gobject.TYPE_INT, gobject.TYPE_INT)), | |
64 } | |
65 | |
66 def __init__ (self): | |
67 super(LanguageBar, self).__init__() | |
68 self.__show = 0 | |
69 self.__enabled = False | |
70 self.__has_focus = False | |
71 self.__show_im_name = False | |
72 self.__im_name = None | |
73 self.__props = None | |
74 self.__selected_menu_item = None | |
75 self.set_style(gtk.TOOLBAR_BOTH_HORIZ) | |
76 self.set_show_arrow(False) | |
77 self.set_property("icon-size", ICON_SIZE) | |
78 self.__create_ui() | |
79 | |
80 self.__properties = [] | |
81 self.__toplevel = gtk.Window(gtk.WINDOW_POPUP) | |
82 self.__toplevel.connect("size-allocate", self.__toplevel_size_allocate_c
b) | |
83 self.__toplevel.add(self) | |
84 self.__screen = gdk.screen_get_default() | |
85 self.__screen.connect("size-changed", self.__screen_size_changed_cb) | |
86 | |
87 self.set_position(-1, -1) | |
88 | |
89 def __create_ui(self): | |
90 # create move handle | |
91 self.__handle = gtk.ToolItem() | |
92 handle = Handle() | |
93 self.__handle.add(handle) | |
94 self.insert(self.__handle, -1) | |
95 handle.connect("move-end", self.__handle_move_end_cb) | |
96 | |
97 # create input methods menu | |
98 # prop = ibus.Property(key = "", type = ibus.PROP_TYPE_TOGGLE, icon = "i
bus", tooltip = _("Switch input method")) | |
99 self.__im_menu = gtk.ToggleToolButton() | |
100 self.__im_menu.set_homogeneous(False) | |
101 self.__im_menu.connect("toggled", self.__im_menu_toggled_cb) | |
102 self.insert(self.__im_menu, -1) | |
103 | |
104 self.__about_button = gtk.ToolButton(gtk.STOCK_ABOUT) | |
105 self.__about_button.set_no_show_all(True) | |
106 self.__about_button.set_tooltip_text(_("About the input method")) | |
107 self.__about_button.connect("clicked", self.__about_button_clicked_cb) | |
108 self.insert(self.__about_button, -1) | |
109 | |
110 def __screen_size_changed_cb(self, screen): | |
111 self.set_position(*self.__position) | |
112 | |
113 def __im_menu_toggled_cb(self, widget): | |
114 if self.__im_menu.get_active(): | |
115 menu = self.emit("get-im-menu") | |
116 menu.connect("deactivate", self.__im_menu_deactivate_cb) | |
117 menu.popup(None, None, | |
118 menu_position, | |
119 0, | |
120 gtk.get_current_event_time(), | |
121 widget) | |
122 | |
123 def __about_button_clicked_cb(self, widget): | |
124 if self.__enabled: | |
125 self.emit("show-engine-about") | |
126 | |
127 def __im_menu_deactivate_cb(self, menu): | |
128 self.__im_menu.set_active(False) | |
129 | |
130 def __handle_move_end_cb(self, handle): | |
131 x, y = self.__toplevel.get_position() | |
132 w, h = self.__toplevel.get_size() | |
133 self.__position = x + w, y + h | |
134 self.emit("position-changed", *self.__position) | |
135 | |
136 def __toplevel_size_allocate_cb(self, toplevel, allocation): | |
137 x, y = self.__position | |
138 w, h = self.__screen.get_width(), self.__screen.get_height() | |
139 if x >= w - 80 or True: | |
140 self.__toplevel.move(x - allocation.width, y - allocation.height) | |
141 | |
142 def __remove_properties(self): | |
143 # reset all properties | |
144 map(lambda i: i.destroy(), self.__properties) | |
145 self.__properties = [] | |
146 | |
147 def __set_opacity(self, opacity): | |
148 if self.__toplevel.window == None: | |
149 self.__toplevel.realize() | |
150 self.__toplevel.window.set_opacity(opacity) | |
151 | |
152 def __replace_property(self, old_prop, new_prop): | |
153 old_prop.label = new_prop.label | |
154 old_prop.icon= new_prop.icon | |
155 old_prop.tooltip = new_prop.tooltip | |
156 old_prop.sensitive = new_prop.sensitive | |
157 old_prop.visible = new_prop.visible | |
158 old_prop.state = new_prop.state | |
159 old_prop.sub_props = new_prop.sub_props | |
160 | |
161 def __label_select_cb(self, widget, data): | |
162 self.__selected_menu_item = widget | |
163 | |
164 def __label_deselect_cb(self, widget, data): | |
165 self.__selected_menu_item = None | |
166 | |
167 def __label_expose_cb(self, widget, event): | |
168 x = widget.allocation.x | |
169 y = widget.allocation.y | |
170 label = widget._prop.label.get_text() | |
171 if self.__selected_menu_item != widget: | |
172 gc = widget.style.fg_gc[gtk.STATE_NORMAL] | |
173 else: | |
174 gc = widget.style.bg_gc[gtk.STATE_NORMAL] | |
175 layout = widget.create_pango_layout(label) | |
176 widget.window.draw_layout(gc, x + 5, y + 2, layout) | |
177 | |
178 def __set_item_icon(self, item, prop): | |
179 item.set_property("always-show-image", True) | |
180 if prop.icon: | |
181 size = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU) | |
182 item.set_image(icon.IconWidget(prop.icon, size[0])) | |
183 elif prop.label and prop.label.get_text() != "": | |
184 item.set_label("") | |
185 item.connect_after("expose-event", self.__label_expose_cb) | |
186 item.connect("select", self.__label_select_cb, None) | |
187 item.connect("deselect", self.__label_deselect_cb, None) | |
188 else: | |
189 size = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU) | |
190 item.set_image(icon.IconWidget("ibus", size[0])) | |
191 | |
192 def do_show(self): | |
193 gtk.Toolbar.do_show(self) | |
194 | |
195 def do_size_request(self, requisition): | |
196 gtk.Toolbar.do_size_request(self, requisition) | |
197 self.__toplevel.resize(1, 1) | |
198 | |
199 def set_im_icon(self, icon_name): | |
200 widget = icon.IconWidget(icon_name, 18) | |
201 self.__im_menu.set_icon_widget(widget) | |
202 | |
203 def set_show_im_name(self, show): | |
204 self.__show_im_name = show | |
205 self.set_im_name(self.__im_name) | |
206 self.__im_menu.set_is_important(show) | |
207 | |
208 def set_im_name(self, text): | |
209 self.__im_name = text | |
210 if text: | |
211 self.__im_menu.set_tooltip_text(text) | |
212 self.__im_menu.set_label(text) | |
213 else: | |
214 self.__im_menu.set_tooltip_text(_("Switch input method")) | |
215 self.__im_menu.set_label("") | |
216 | |
217 def reset(self): | |
218 self.__remove_properties() | |
219 | |
220 def set_enabled(self, enabled): | |
221 self.__enabled = enabled | |
222 if self.__enabled: | |
223 self.__about_button.show() | |
224 self.__set_opacity(1.0) | |
225 if self.__has_focus: | |
226 if self.__show in (1, 2): | |
227 self.show_all() | |
228 else: | |
229 self.__about_button.hide() | |
230 self.__set_opacity(0.5) | |
231 if self.__show in (1, 0): | |
232 self.hide_all() | |
233 | |
234 def is_enabled(self): | |
235 return self.__enabled | |
236 | |
237 def set_show(self, show): | |
238 if show not in (0, 1, 2): | |
239 show = 0 | |
240 self.__show = show | |
241 if self.__has_focus: | |
242 self.focus_in() | |
243 else: | |
244 self.focus_out() | |
245 | |
246 def set_position(self, x, y): | |
247 w, h = self.__screen.get_width(), self.__screen.get_height() | |
248 if x < 0 or y < 0: | |
249 x = w - 20 | |
250 y = h - 40 | |
251 if x > w: | |
252 x = w - 20 | |
253 if y > h: | |
254 y = h - 40 | |
255 | |
256 self.__position = x, y | |
257 w, h = self.__toplevel.get_size() | |
258 self.__toplevel.move(self.__position[0] - w, self.__position[1] - h) | |
259 | |
260 def get_show(self): | |
261 return self.__show | |
262 | |
263 def register_properties(self, props): | |
264 self.__props = props | |
265 if self.__show == 0: | |
266 return | |
267 # refresh items on labguage bar | |
268 self.__remove_properties() | |
269 # create new properties | |
270 for i, prop in enumerate(props): | |
271 if prop.type == ibus.PROP_TYPE_NORMAL: | |
272 item = ToolButton(prop = prop) | |
273 elif prop.type == ibus.PROP_TYPE_TOGGLE: | |
274 item = ToggleToolButton(prop = prop) | |
275 elif prop.type == ibus.PROP_TYPE_MENU: | |
276 item = MenuToolButton(prop = prop) | |
277 elif prop.type == ibus.PROP_TYPE_SEPARATOR: | |
278 item = SeparatorToolItem() | |
279 else: | |
280 raise IBusException("Unknown property type = %d" % prop.type) | |
281 | |
282 item.connect("property-activate", | |
283 lambda w, n, s: self.emit("property-activate", n, s)) | |
284 | |
285 item.set_sensitive(prop.sensitive) | |
286 | |
287 item.set_no_show_all(True) | |
288 | |
289 if prop.visible: | |
290 item.show() | |
291 else: | |
292 item.hide() | |
293 | |
294 self.__properties.append(item) | |
295 self.insert(item, i + 2) | |
296 | |
297 def update_property(self, prop): | |
298 if self.__show == 0 and self.__props: | |
299 list = self.__props.get_properties() | |
300 for i, p in enumerate(list): | |
301 if p.key == prop.key and p.type == prop.type: | |
302 self.__replace_property(p, prop) | |
303 break | |
304 map(lambda x: x.update_property(prop), self.__properties) | |
305 | |
306 def show_all(self): | |
307 self.__toplevel.show_all() | |
308 self.__toplevel.window.raise_() | |
309 gtk.Toolbar.show_all(self) | |
310 | |
311 def hide_all(self): | |
312 try: | |
313 self.__toplevel.window.lower() | |
314 self.__toplevel.window.hide_all() | |
315 except: | |
316 pass | |
317 x, y = self.__toplevel.get_position() | |
318 self.__toplevel.hide_all() | |
319 gtk.Toolbar.hide_all(self) | |
320 | |
321 # save bar position | |
322 self.__toplevel.move(x, y) | |
323 | |
324 def focus_in(self): | |
325 self.__has_focus = True | |
326 self.__im_menu.set_sensitive(True) | |
327 if (self.__show == 1 and self.__enabled) or self.__show == 2: | |
328 self.show_all() | |
329 else: | |
330 self.hide_all() | |
331 | |
332 def focus_out(self): | |
333 self.__has_focus = False | |
334 self.__im_menu.set_sensitive(False) | |
335 if self.__show == 2: | |
336 self.show_all() | |
337 else: | |
338 self.hide_all() | |
339 | |
340 def create_im_menu(self, menu): | |
341 if not self.__enabled: | |
342 return | |
343 if self.__show != 0: | |
344 return | |
345 if not menu: | |
346 assert False | |
347 props = self.__props | |
348 if not props: | |
349 return | |
350 | |
351 self.__remove_properties() | |
352 item = SeparatorMenuItem() | |
353 item.show() | |
354 self.__properties.append(item) | |
355 menu.insert(item, 0) | |
356 | |
357 about_label = _("About") + " - " + self.__im_name | |
358 prop = ibus.Property(key=u"about", | |
359 label=unicode(about_label), | |
360 icon=unicode(gtk.STOCK_ABOUT), | |
361 tooltip=unicode(_("About the Input Method"))) | |
362 item = ImageMenuItem(prop = prop) | |
363 item.set_property("always-show-image", True) | |
364 item.set_no_show_all(True) | |
365 item.show() | |
366 self.__properties.append(item) | |
367 menu.insert(item, 0) | |
368 item.connect("property-activate", | |
369 lambda w, n, s: self.emit("show-engine-about")) | |
370 | |
371 list = props.get_properties() | |
372 list.reverse() | |
373 radio_group = None | |
374 | |
375 for i, prop in enumerate(list): | |
376 if prop.type == ibus.PROP_TYPE_NORMAL: | |
377 item = ImageMenuItem(prop = prop) | |
378 self.__set_item_icon(item, prop) | |
379 elif prop.type == ibus.PROP_TYPE_TOGGLE: | |
380 item = CheckMenuItem(prop = prop) | |
381 elif prop.type == ibus.PROP_TYPE_RADIO: | |
382 item = RadioMenuItem(radio_group, prop = prop) | |
383 radio_group = item | |
384 elif prop.type == ibus.PROP_TYPE_SEPARATOR: | |
385 item = SeparatorMenuItem() | |
386 radio_group = None | |
387 elif prop.type == ibus.PROP_TYPE_MENU: | |
388 item = ImageMenuItem(prop = prop) | |
389 self.__set_item_icon(item, prop) | |
390 submenu = Menu(prop) | |
391 item.set_submenu(submenu) | |
392 submenu.connect("property-activate", | |
393 lambda w, n, s: self.emit("property-activate", n
, s)) | |
394 else: | |
395 raise IBusException("Unknown property type = %d" % prop.type) | |
396 | |
397 item.set_sensitive(prop.sensitive) | |
398 | |
399 item.set_no_show_all(True) | |
400 | |
401 if prop.visible: | |
402 item.show() | |
403 else: | |
404 item.hide() | |
405 | |
406 self.__properties.append(item) | |
407 menu.insert(item, 0) | |
408 | |
409 item.connect("property-activate", | |
410 lambda w, n, s: self.emit("property-activate", n, s)) | |
411 | |
OLD | NEW |