1 """The Menu widget provides an easy way to create menus that allow the user to
2 define keyboard shortcuts, and saves the shortcuts automatically. You only define
3 each Menu once, and attach it to windows as required.
7 from rox.Menu import Menu, set_save_name
12 ('/File', '', '<Branch>'),
13 ('/File/Save', 'save', ''),
14 ('/File/Open Parent', 'up', ''),
15 ('/File/Close', 'close', ''),
16 ('/File/', '', '<Separator>'),
17 ('/File/New', 'new', ''),
18 ('/Edit', '', '<Branch>'),
19 ('/Edit/Undo', 'undo', ''),
20 ('/Edit/Redo', 'redo', ''),
21 ('/Edit/', '', '<Separator>'),
22 ('/Edit/Search...', 'search', ''),
23 ('/Edit/Goto line...', 'goto', ''),
24 ('/Edit/', '', '<Separator>'),
25 ('/Edit/Process...', 'process', ''),
26 ('/Options', 'show_options', ''),
27 ('/Help', 'help', '<StockItem>', 'F1', g.STOCK_HELP),
36 def set_save_name(prog
, leaf
= 'menus'):
37 """Set the directory/leafname (see choices) used to save the menu keys.
38 Call this before creating any menus."""
40 _save_name
= (prog
, leaf
)
43 def __init__(self
, name
, items
):
44 """names should be unique (eg, 'popup', 'main', etc).
45 items is a list of menu items:
46 [(name, callback_name, type, key), ...].
47 'name' is the item's path.
48 'callback_name' is the NAME of a method to call.
49 'type' is as for g.ItemFactory.
50 'key' is only used if no bindings are in Choices."""
52 raise Exception('Call rox.Menu.set_save_name() first!')
56 factory
= g
.ItemFactory(g
.Menu
, '<%s>' % name
, ag
)
58 program
, save_leaf
= _save_name
59 path
= choices
.load(program
, save_leaf
)
67 (label
, fn
, type) = item
69 (label
, fn
, type, key
) = item
71 (label
, fn
, type, key
, stock
) = item
78 out
.append((label
, key
, cb
, len(self
.fns
) - 1, type, stock
))
80 out
.append((label
, key
, cb
, len(self
.fns
) - 1, type))
82 factory
.create_items(out
)
83 self
.factory
= factory
86 g
.accel_map_load(path
)
88 self
.caller
= None # Caller of currently open menu
89 self
.menu
= factory
.get_widget('<%s>' % name
)
91 def keys_changed(*unused
):
92 program
, name
= _save_name
93 path
= choices
.save(program
, name
)
96 g
.accel_map_save(path
)
97 except AttributeError:
98 print "Error saving keybindings to", path
99 ag
.connect('accel_changed', keys_changed
)
101 def attach(self
, window
, object):
102 """Keypresses on this window will be treated as menu shortcuts
103 for this object, calling 'object.<callback_name>' when used."""
107 window
.connect('key-press-event', kev
)
108 window
.add_accel_group(self
.accel_group
)
110 def _position(self
, menu
):
111 x
, y
, mods
= g
.gdk
.get_default_root_window().get_pointer()
112 width
, height
= menu
.size_request()
113 return (x
- width
* 3 / 4, y
- 16, True)
115 def popup(self
, caller
, event
, position_fn
= None):
116 """Display the menu. Call 'caller.<callback_name>' when an item is chosen.
117 For applets, position_fn should be my_applet.position_menu)."""
120 self
.menu
.popup(None, None, position_fn
or self
._position
, event
.button
, event
.time
)
122 self
.menu
.popup(None, None, position_fn
or self
._position
, 0, 0)
124 def _activate(self
, action
, widget
):
127 getattr(self
.caller
, self
.fns
[action
])()
129 rox
.report_exception()
131 raise Exception("No caller for menu!")