1 # vim:set et sts=4 sw=4:
5 # Copyright(c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
6 # Copyright(c) 2007-2010 Red Hat, Inc.
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.1 of the License, or (at your option) any later version.
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 GNU
16 # Lesser General Public License for more details.
18 # You should have received a copy of the GNU Lesser General Public
19 # License along with this library; if not, write to the Free Software
20 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
27 from propitem import PropItem
29 class Menu(gtk.Menu, PropItem):
30 __gtype_name__ = "IBusMenu"
32 "property-activate" :(
33 gobject.SIGNAL_RUN_FIRST,
35 (gobject.TYPE_STRING, gobject.TYPE_INT)),
38 def __init__(self, prop):
39 gtk.Menu.__init__(self)
40 PropItem.__init__(self, prop)
42 self.set_take_focus(False)
43 self.__create_items(self._prop.sub_props)
45 self.set_sensitive(prop.sensitive)
47 def __create_items(self, props):
51 if prop.type == ibus.PROP_TYPE_NORMAL:
52 item = ImageMenuItem(prop)
53 elif prop.type == ibus.PROP_TYPE_TOGGLE:
54 item = CheckMenuItem(prop)
55 elif prop.type == ibus.PROP_TYPE_RADIO:
56 item = RadioMenuItem(radio_group, prop)
58 elif prop.type == ibus.PROP_TYPE_SEPARATOR:
59 item = SeparatorMenuItem()
61 elif prop.type == ibus.PROP_TYPE_MENU:
62 item = ImageMenuItem(prop)
64 size = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU)
65 item.set_image(icon.IconWidget(prop.icon, size[0]))
67 item.set_label(prop.label.text)
68 item.set_submenu(Menu(prop))
73 item.set_tooltip_text(prop.tooltip.text)
74 item.set_sensitive(prop.sensitive)
76 item.set_no_show_all(False)
79 item.set_no_show_all(True)
83 self._sub_items.append(item)
85 if prop.type not in (ibus.PROP_TYPE_NORMAL, ibus.PROP_TYPE_TOGGLE, ibus.PROP_TYPE_RADIO):
87 item.connect("property-activate",
88 lambda w,n,s: self.emit("property-activate", n, s))
90 def popup(self, button, active_time, widget):
91 gtk.Menu.popup(self, None, None, menu_position,
92 button, active_time, widget)
94 def _property_clicked(self, item, prop):
98 class ImageMenuItem(gtk.ImageMenuItem, PropItem):
99 __gtype_name__ = "IBusImageMenuItem"
101 "property-activate" :(
102 gobject.SIGNAL_RUN_FIRST,
104 (gobject.TYPE_STRING, gobject.TYPE_INT)),
107 def __init__(self, prop):
108 gtk.ImageMenuItem.__init__(self)
109 PropItem.__init__(self, prop)
112 size = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU)
113 self.set_image(icon.IconWidget(prop.icon, size[0]))
115 self.set_label(prop.label.text)
117 if self._prop.visible:
118 self.set_no_show_all(False)
121 self.set_no_show_all(True)
124 def do_activate(self):
125 self.emit("property-activate", self._prop.key, self._prop.state)
127 def property_changed(self):
128 self.set_sensitive(self._prop.sensitive)
129 if self._prop.visible:
130 self.set_no_show_all(False)
133 self.set_no_show_all(True)
137 class CheckMenuItem(gtk.CheckMenuItem, PropItem):
138 __gtype_name__ = "IBusCheckMenuItem"
140 "property-activate" :(
141 gobject.SIGNAL_RUN_FIRST,
143 (gobject.TYPE_STRING, gobject.TYPE_INT)),
146 def __init__(self, prop):
147 gtk.CheckMenuItem.__init__(self, label=prop.label.text)
148 PropItem.__init__(self, prop)
150 self.set_active(self._prop.state == ibus.PROP_STATE_CHECKED)
152 if self._prop.visible:
153 self.set_no_show_all(False)
156 self.set_no_show_all(True)
159 def do_toggled(self):
160 # Do not send property-activate to engine in case the event is
163 if self.get_active():
164 if self._prop.state != ibus.PROP_STATE_CHECKED:
166 self._prop.state = ibus.PROP_STATE_CHECKED
168 if self._prop.state != ibus.PROP_STATE_UNCHECKED:
170 self._prop.state = ibus.PROP_STATE_UNCHECKED
172 self.emit("property-activate", self._prop.key, self._prop.state)
174 def property_changed(self):
175 self.set_active(self._prop.state == ibus.PROP_STATE_CHECKED)
176 self.set_sensitive(self._prop.sensitive)
177 if self._prop.visible:
178 self.set_no_show_all(False)
181 self.set_no_show_all(True)
185 class RadioMenuItem(gtk.RadioMenuItem, PropItem):
186 __gtype_name__ = "IBusRadioMenuItem"
188 "property-activate" :(
189 gobject.SIGNAL_RUN_FIRST,
191 (gobject.TYPE_STRING, gobject.TYPE_INT)),
194 def __init__(self, group, prop):
195 gtk.RadioMenuItem.__init__(self, group, label = prop.label.text)
196 PropItem.__init__(self, prop)
198 self.set_active(self._prop.state == ibus.PROP_STATE_CHECKED)
201 self.set_no_show_all(False)
204 self.set_no_show_all(True)
207 def property_changed(self):
208 self.set_active(self._prop.state == ibus.PROP_STATE_CHECKED)
209 self.set_sensitive(self._prop.sensitive)
210 if self._prop.visible:
211 self.set_no_show_all(False)
214 self.set_no_show_all(True)
217 def do_toggled(self):
218 # Do not send property-activate to engine in case the event is
221 if self.get_active():
222 if self._prop.state != ibus.PROP_STATE_CHECKED:
224 self._prop.state = ibus.PROP_STATE_CHECKED
226 if self._prop.state != ibus.PROP_STATE_UNCHECKED:
228 self._prop.state = ibus.PROP_STATE_UNCHECKED
230 self.emit("property-activate", self._prop.key, self._prop.state)
232 class SeparatorMenuItem(gtk.SeparatorMenuItem, PropItem):
233 __gtype_name__ = "IBusSeparatorMenuItem"
235 "property-activate" :(
236 gobject.SIGNAL_RUN_FIRST,
238 (gobject.TYPE_STRING, gobject.TYPE_INT)),
242 gtk.SeparatorMenuItem.__init__(self)
243 PropItem.__init__(self, None)
246 def menu_position(menu, button):
247 screen = button.get_screen()
248 monitor = screen.get_monitor_at_window(button.window)
249 monitor_allocation = screen.get_monitor_geometry(monitor)
251 x, y = button.window.get_origin()
252 x += button.allocation.x
253 y += button.allocation.y
255 menu_width, menu_height = menu.size_request()
257 if x + menu_width >= monitor_allocation.width:
258 x -= menu_width - button.allocation.width
259 elif x - menu_width <= 0:
262 if x <= monitor_allocation.width * 3 / 4:
265 x -= menu_width - button.allocation.width
267 if y + button.allocation.height + menu_height >= monitor_allocation.height:
269 elif y - menu_height <= 0:
270 y += button.allocation.height
272 if y <= monitor_allocation.height * 3 / 4:
273 y += button.allocation.height