From dee6412f6beae82952ed0a07fc2bfdfb0cbb3e79 Mon Sep 17 00:00:00 2001 From: Vincent Vinet Date: Thu, 19 Nov 2009 16:33:26 +0000 Subject: refac property editing in the creator --- (limited to 'tutorius/creator.py') diff --git a/tutorius/creator.py b/tutorius/creator.py index 906a04e..68c5fa6 100644 --- a/tutorius/creator.py +++ b/tutorius/creator.py @@ -36,6 +36,7 @@ from .services import ObjectStore from .core import State from .tutorial import Tutorial from . import viewer +from .propwidgets import TextInputDialog, StringPropWidget class Creator(object): """ @@ -230,25 +231,7 @@ class Creator(object): meta = addon.get_addon_meta(addonname) for propname in meta['mandatory_props']: prop = getattr(type(event), propname) - if isinstance(prop, properties.TUAMProperty): - selector = WidgetSelector(self._activity) - setattr(event, propname, selector.select()) - elif isinstance(prop, properties.TEventType): - try: - dlg = SignalInputDialog(self._activity, - text="Mandatory property", - field=propname, - addr=event.object_id) - setattr(event, propname, dlg.pop()) - except AttributeError: - pass - elif isinstance(prop, properties.TStringProperty): - dlg = TextInputDialog(self._activity, - text="Mandatory property", - field=propname) - setattr(event, propname, dlg.pop()) - else: - raise NotImplementedError() + prop.widget_class.run_dialog(self._activity, event, propname) event_filters = self._tutorial.get_transition_dict(self._state) @@ -360,6 +343,7 @@ class ToolBox(object): self.tree = gtk.glade.XML(glade_file) self.window = self.tree.get_widget('mainwindow') self._propbox = self.tree.get_widget('propbox') + self._propedits = [] self.window.set_transient_for(parent) @@ -402,74 +386,38 @@ class ToolBox(object): """Refresh property values from the selected action.""" if self._action is None: return - props = self._action._props.keys() - for propnum in xrange(len(props)): - row = self._propbox.get_children()[propnum] - propname = props[propnum] - prop = getattr(type(self._action), propname) - propval = getattr(self._action, propname) - if isinstance(prop, properties.TStringProperty): - propwdg = row.get_children()[1] - propwdg.get_buffer().set_text(propval) - elif isinstance(prop, properties.TUAMProperty): - propwdg = row.get_children()[1] - propwdg.set_label(propval) - elif isinstance(prop, properties.TIntProperty): - propwdg = row.get_children()[1] - propwdg.set_value(propval) - elif isinstance(prop, properties.TArrayProperty): - propwdg = row.get_children()[1] - for i in xrange(len(propval)): - entry = propwdg.get_children()[i] - entry.set_text(str(propval[i])) - else: - propwdg = row.get_children()[1] - propwdg.set_text(str(propval)) + + #Refresh the property editors + for prop in self._propedits: + prop.refresh_widget() def set_action(self, action): """Setter for the action property.""" if self._action is action: self.refresh_properties() return + + #Clear the prop box for old_prop in self._propbox.get_children(): self._propbox.remove(old_prop) + self._propedits = [] + self._action = action if action is None: return for propname in action._props.keys(): row = gtk.HBox() + #Label row.pack_start(gtk.Label(T(propname)), False, False, 10) + + #Value field prop = getattr(type(action), propname) - propval = getattr(action, propname) - if isinstance(prop, properties.TStringProperty): - propwdg = gtk.TextView() - propwdg.get_buffer().set_text(propval) - propwdg.connect_after("focus-out-event", \ - self._str_prop_changed, action, propname) - elif isinstance(prop, properties.TUAMProperty): - propwdg = gtk.Button(propval) - propwdg.connect_after("clicked", \ - self._uam_prop_changed, action, propname) - elif isinstance(prop, properties.TIntProperty): - adjustment = gtk.Adjustment(value=propval, - lower=prop.lower_limit.limit, - upper=prop.upper_limit.limit, - step_incr=1) - propwdg = gtk.SpinButton(adjustment=adjustment) - propwdg.connect_after("focus-out-event", \ - self._int_prop_changed, action, prop) - elif isinstance(prop, properties.TArrayProperty): - propwdg = gtk.HBox() - for i in xrange(len(propval)): - entry = gtk.Entry() - propwdg.pack_start(entry) - entry.connect_after("focus-out-event", \ - self._list_prop_changed, action, propname, i) - else: - propwdg = gtk.Entry() - propwdg.set_text(str(propval)) - row.pack_end(propwdg) + propedit = prop.widget_class(self.__parent, action, propname, self._refresh_action_cb) + self._propedits.append(propedit) + row.pack_end(propedit.widget) + + #Add row self._propbox.pack_start(row, expand=False) self._propbox.show_all() self.refresh_properties() @@ -480,187 +428,10 @@ class ToolBox(object): action = property(fset=set_action, fget=get_action, doc=\ "Action to be edited through introspection.") - def _list_prop_changed(self, widget, evt, action, propname, idx): - try: - #Save props as tuples so that they can be hashed - attr = list(getattr(action, propname)) - attr[idx] = int(widget.get_text()) - setattr(action, propname, tuple(attr)) - except ValueError: - widget.set_text(str(getattr(action, propname)[idx])) - self.__parent._creator._action_refresh_cb(None, None, action) - def _uam_prop_changed(self, widget, action, propname): - selector = WidgetSelector(self.__parent) - selection = selector.select() - setattr(action, propname, selection) - self.__parent._creator._action_refresh_cb(None, None, action) - def _str_prop_changed(self, widget, evt, action, propname): - buf = widget.get_buffer() - setattr(action, propname, buf.get_text(buf.get_start_iter(), buf.get_end_iter())) - self.__parent._creator._action_refresh_cb(None, None, action) - def _int_prop_changed(self, widget, evt, action, prop): - setattr(action, propname, widget.get_value_as_int()) - self.__parent._creator._action_refresh_cb(None, None, action) - - -class WidgetSelector(object): - """ - Allow selecting a widget from within a window without interrupting the - flow of the current call. - - The selector will run on the specified window until either a widget - is selected or abort() gets called. - """ - def __init__(self, window): - super(WidgetSelector, self).__init__() - self.window = window - self._intro_mask = None - self._intro_handle = None - self._select_handle = None - self._prelight = None + def _refresh_action_cb(self): + if self._action is not None: + self.__parent._creator._action_refresh_cb(None, None, self._action) - def select(self): - """ - Starts selecting a widget, by grabbing control of the mouse and - highlighting hovered widgets until one is clicked. - @returns: a widget address or None - """ - if not self._intro_mask: - self._prelight = None - self._intro_mask = overlayer.Mask(catch_events=True) - self._select_handle = self._intro_mask.connect_after( - "button-press-event", self._end_introspect) - self._intro_handle = self._intro_mask.connect_after( - "motion-notify-event", self._intro_cb) - self.window._overlayer.put(self._intro_mask, 0, 0) - self.window._overlayer.queue_draw() - - while bool(self._intro_mask) and not gtk.main_iteration(): - pass - - return gtkutils.raddr_lookup(self._prelight) - - def _end_introspect(self, widget, evt): - if evt.type == gtk.gdk.BUTTON_PRESS and self._prelight: - self._intro_mask.catch_events = False - self._intro_mask.disconnect(self._intro_handle) - self._intro_handle = None - self._intro_mask.disconnect(self._select_handle) - self._select_handle = None - self.window._overlayer.remove(self._intro_mask) - self._intro_mask = None - # for some reason, gtk may not redraw after this unless told to. - self.window.queue_draw() - - def _intro_cb(self, widget, evt): - """ - Callback for capture of widget events, when in introspect mode. - """ - # widget has focus, let's hilight it - win = gtk.gdk.display_get_default().get_window_at_pointer() - if not win: - return - click_wdg = win[0].get_user_data() - if not click_wdg.is_ancestor(self.window._overlayer): - # as popups are not (yet) supported, it would break - # badly if we were to play with a widget not in the - # hierarchy. - return - for hole in self._intro_mask.pass_thru: - self._intro_mask.mask(hole) - self._intro_mask.unmask(click_wdg) - self._prelight = click_wdg - - self.window.queue_draw() - - def abort(self): - """ - Ends the selection. The control will return to the select() caller - with a return value of None, as selection was aborted. - """ - self._intro_mask.catch_events = False - self._intro_mask.disconnect(self._intro_handle) - self._intro_handle = None - self._intro_mask.disconnect(self._select_handle) - self._select_handle = None - self.window._overlayer.remove(self._intro_mask) - self._intro_mask = None - self._prelight = None - -class SignalInputDialog(gtk.MessageDialog): - def __init__(self, parent, text, field, addr): - """ - Create a gtk signal selection dialog. - - @param parent: the parent window this dialog should stay over. - @param text: the title of the dialog. - @param field: the field description of the dialog. - @param addr: the widget address from which to fetch signal list. - """ - gtk.MessageDialog.__init__(self, parent, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_QUESTION, - gtk.BUTTONS_OK, - None) - self.set_markup(text) - self.model = gtk.ListStore(str) - widget = gtkutils.find_widget(parent, addr) - for signal_name in gobject.signal_list_names(widget): - self.model.append(row=(signal_name,)) - self.entry = gtk.ComboBox(self.model) - cell = gtk.CellRendererText() - self.entry.pack_start(cell) - self.entry.add_attribute(cell, 'text', 0) - hbox = gtk.HBox() - lbl = gtk.Label(field) - hbox.pack_start(lbl, False) - hbox.pack_end(self.entry) - self.vbox.pack_end(hbox, True, True) - self.show_all() - - def pop(self): - """ - Show the dialog. It will run in it's own loop and return control - to the caller when a signal has been selected. - - @returns: a signal name or None if no signal was selected - """ - self.run() - self.hide() - iter = self.entry.get_active_iter() - if iter: - text = self.model.get_value(iter, 0) - return text - return None - - def _dialog_done_cb(self, entry, response): - self.response(response) - -class TextInputDialog(gtk.MessageDialog): - def __init__(self, parent, text, field): - gtk.MessageDialog.__init__(self, parent, - gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, - gtk.MESSAGE_QUESTION, - gtk.BUTTONS_OK, - None) - self.set_markup(text) - self.entry = gtk.Entry() - self.entry.connect("activate", self._dialog_done_cb, gtk.RESPONSE_OK) - hbox = gtk.HBox() - lbl = gtk.Label(field) - hbox.pack_start(lbl, False) - hbox.pack_end(self.entry) - self.vbox.pack_end(hbox, True, True) - self.show_all() - - def pop(self): - self.run() - self.hide() - text = self.entry.get_text() - return text - - def _dialog_done_cb(self, entry, response): - self.response(response) # The purpose of this function is to reformat text, as current IconView # implentation does not insert carriage returns on long lines. -- cgit v0.9.1