Mercurial > MadButterfly
view pyink/FSM_window.py @ 1532:4a92b639a1cd
Clear selection set when switching current scene.
To clear selection set after switching away from current to another scene.
It avoids Inkscape select on nodes they are not saw after switching.
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Fri, 30 Sep 2011 12:31:33 +0800 |
parents | d46ba9e7f837 |
children |
line wrap: on
line source
import gtk import os import math import data_monitor import pybInkscape ## \brief Wrap domview to provide a view for FSM of a component. # # This class is a decorator of domview to provide a view for FSM of a # component. All accesses to FSM states and transitions will be # dispatched to domview with name of a specified component as one of # argument list. Caller don't need to know the component that it is # working on. # class _compview(object): _domview = None _comp_name = None def __init__(self, domview, comp_name): self._domview = domview self._comp_name = comp_name pass def switch_component(self, comp_name): self._comp_name = comp_name pass def all_actions(self): action_names = self._domview.all_timeline_names() return action_names def all_state_names(self): return self._domview.all_state_names(self._comp_name) def get_start_state_name(self): return self._domview.get_start_state_name(self._comp_name) def rm_state(self, state_name): self._domview.rm_state(self._comp_name, state_name) pass def add_state(self, state_name): self._domview.add_state(self._comp_name, state_name) pass def rename_state(self, state_name, new_name): self._domview.rename_state(self._comp_name, state_name, new_name) pass def set_start_state(self, state_name): self._domview.set_start_state(self._comp_name, state_name) pass def set_state_entry_action(self, state_name, entry_action): self._domview.set_state_entry_action(self._comp_name, state_name, entry_action) pass def set_state_r(self, state_name, r): self._domview.set_state_r(self._comp_name, state_name, r) pass def set_state_xy(self, state_name, x, y): self._domview.set_state_xy(self._comp_name, state_name, x, y) pass def get_state_entry_action(self, state_name): return self._domview.get_state_entry_action(self._comp_name, state_name) def get_state_r(self, state_name): return self._domview.get_state_r(self._comp_name, state_name) def get_state_xy(self, state_name): return self._domview.get_state_xy(self._comp_name, state_name) def all_transitions(self, state_name): return self._domview.all_transitions(self._comp_name, state_name) def add_transition(self, state_name, cond, target): self._domview.add_transition(self._comp_name, state_name, cond, target) pass def rm_transition(self, state_name, cond): self._domview.rm_transition(self._comp_name, state_name, cond) pass def change_transition_cond(self, state_name, old_cond, new_cond): self._domview.change_transition_cond(self._comp_name, state_name, old_cond, new_cond) pass def get_transition(self, state_name, cond): return self._domview.get_transition(self._comp_name, state_name, cond) def set_transition_action(self, state_name, cond, action): self._domview.set_transition_action(self._comp_name, state_name, cond, action) pass def set_transition_path(self, state_name, cond, path): self._domview.set_transition_path(self._comp_name, state_name, cond, path) pass def chg_transition_cond(self, state_name, cond, new_cond): self._domview.chg_transition_cond(self._comp_name, state_name, cond, new_cond) pass pass class _dragger(object): _node = None _start_x = None _start_y = None _state = 0 def __init__(self): pass ## \brief Mouse event handler # # This is a placeholder for mouse vent handlers. This attribute # of instances is switched between _mouse_event_waiting and # _mouse_event_pressed. # def mouse_event(self, evtype, button, x, y): raise RuntimeError, 'should not be here' def _mouse_event_waiting(self, evtype, button, x, y): if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS and \ button == 1: self._start_x = x self._start_y = y self.mouse_event = self._mouse_event_pressed self.start_drag() pass pass def _mouse_event_pressed(self, evtype, button, x, y): rx = x - self._start_x ry = y - self._start_y if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE: self.mouse_event = self._mouse_event_waiting self.stop_drag(rx, ry) pass self.update(rx, ry) pass def start(self): self.mouse_event = self._mouse_event_waiting pass def stop(self): pass def connect(self, node): self.start() def handler(item, evtype, button, x, y): self.mouse_event(evtype, button, x, y) pass self._node = node hdl_id = node.spitem.connect('mouse-event', handler) self._hdl_id = hdl_id pass def disconnect(self): self.stop() node = self._node hdl_id = self._hdl_id node.disconnect(hdl_id) pass def start_drag(self): pass def stop_drag(self, rx, ry): pass def update(self, rx, ry): pass pass class FSM_window_base(object): _add_state_button = None _move_state_button = None _state_editor = None _state_name = None _state_radius = None _error_dialog = None _error_dialog_label = None _state_menu = None _action_picker = None _picked_action = None _picked_action_txt = None _action_list = None _action_store = None def __init__(self): super(FSM_window_base, self).__init__() dirname = os.path.dirname(__file__) fname = os.path.join(dirname, 'FSM_window.glade') builder = gtk.Builder() builder.add_from_file(fname) main_win = builder.get_object('FSM_main_win') comp_name_label = builder.get_object('comp_name') view_box = builder.get_object("view_box") add_state_button = builder.get_object('add_state') move_state_button = builder.get_object('move_state') state_editor = builder.get_object('state_editor') state_name = builder.get_object('state_name') state_radius = builder.get_object('state_radius') state_entry_action = builder.get_object('state_entry_action') error_dialog = builder.get_object('error_dialog') error_dialog_label = builder.get_object('error_dialog_label') transition_editor = builder.get_object('transition_editor') transition_cond = builder.get_object('transition_cond') transition_action = builder.get_object('transition_action') state_menu = builder.get_object('state_menu') transition_menu = builder.get_object('transition_menu') action_picker = builder.get_object('action_picker') picked_action = builder.get_object('picked_action') action_store = builder.get_object('action_store') builder.connect_signals(self) self._builder = builder self._main_win = main_win self._view_box = view_box self._add_state_button = add_state_button self._move_state_button = move_state_button self._state_editor = state_editor self._state_name = state_name self._state_radius = state_radius self._state_entry_action = state_entry_action self._transition_editor = transition_editor self._transition_cond = transition_cond self._transition_action = transition_action self._error_dialog = error_dialog self._error_dialog_label = error_dialog_label self._state_menu = state_menu self._transition_menu = transition_menu self._comp_name_label = comp_name_label self._action_picker = action_picker self._picked_action = picked_action self._action_store = action_store pass def show_error(self, msg): error_dialog = self._error_dialog error_dialog_label = self._error_dialog_label error_dialog_label.set_text(msg) error_dialog.show() pass def hide_error(self): error_dialog = self._error_dialog error_dialog.hide() pass def show_state_editor(self, state_name='', radius=30, entry_action=''): state_name_inp = self._state_name state_radius_inp = self._state_radius state_entry_action = self._state_entry_action state_editor = self._state_editor state_name_inp.set_text(state_name) state_radius_inp.set_text(str(radius)) state_entry_action.set_text(entry_action or '') state_editor.show() pass def hide_state_editor(self): state_editor = self._state_editor state_editor.hide() pass def show_transition_editor(self, cond='', action=''): transition_cond = self._transition_cond transition_action = self._transition_action transition_editor = self._transition_editor transition_cond.set_text(cond) transition_action.set_text(action) transition_editor.show() pass def hide_transition_editor(self): transition_editor = self._transition_editor transition_editor.hide() pass def popup_state_menu(self): menu = self._state_menu menu.popup(None, None, None, 0, 0) pass def popup_transition_menu(self): menu = self._transition_menu menu.popup(None, None, None, 0, 0) pass def show_action_picker(self): self._picked_action.set_text('') self._picked_action_txt = None self._action_picker.show() pass def hide_action_picker(self): self._action_picker.hide() pass def show(self): self._main_win.show() self._add_state_button.set_active(True) pass def hide(self): self._main_win.hide() pass def gtk_widget_hide(self, widget, event, *data): widget.hide() return True def on_start_state_activate(self, *args): pass def on_rename_state_activate(self, *args): pass def on_remove_state_activate(self, *args): pass def on_zoom_out_clicked(self, *args): pass def on_zoom_in_clicked(self, *args): pass def on_move_state_toggled(self, *args): pass def on_add_state_toggled(self, *args): pass def on_close_window_activate(self, *args): pass def on_FSM_main_win_destroy_event(self, *args): pass def on_state_apply_clicked(self, *args): pass def on_state_cancel_clicked(self, *args): state_editor = self._state_editor state_editor.hide() pass def on_error_dialog_ok_clicked(self, *args): error_dialog = self._error_dialog error_dialog.hide() pass def on_add_transition_activate(self, *args): pass def on_del_state_activate(self, *args): pass def on_edit_state_activate(self, *args): pass def on_transition_apply_clicked(self, *args): pass def on_transition_cancel_clicked(self, *args): transition_editor = self._transition_editor transition_editor.hide() pass def on_transition_pick_act_clicked(self, *args): self.show_action_picker() pass def on_del_transition_activate(self, *args): pass def on_edit_transition_activate(self, *args): pass def on_action_cancel_clicked(self, *args): action_picker = self._action_picker action_picker.hide() pass def on_action_ok_clicked(self, *args): if self._picked_action_txt: self._transition_action.set_text(self._picked_action_txt) pass self.hide_action_picker() pass def on_action_list_row_activated(self, view, path, col): action_store = self._action_store action_iter = action_store.get_iter(path) action_text = action_store.get_value(action_iter, 0) self._picked_action_txt = action_text self._picked_action.set_text(action_text) pass pass class FSM_transition(object): _doc = None _compview = None _fsm_layer = None _control_layer = None _state = None _states = None trn_cond = None trn_g = None _arrow_node = None _path_node = None _control_points = None _selected_rect = None def __init__(self, trn_cond): self.trn_cond = trn_cond pass def init(self, doc, compview, state, states, fsm_layer, control_layer): self._doc = doc self._compview = compview self._state = state self._states = states self._fsm_layer = fsm_layer self._control_layer = control_layer pass def _translate_page_xy(self, x, y): doc = self._doc root = doc.root() page_h_txt = root.getAttribute('height') page_h = float(page_h_txt) svgx = x svgy = page_h - y return svgx, svgy @staticmethod def _update_graph(path, arrow_node, path_node): path_txt = 'M %f,%f C %f,%f %f,%f %f,%f' % tuple(path) path_node.setAttribute('d', path_txt) path_node.setAttribute('style', 'stroke: #000000; stroke-width: 1; ' 'fill: none') # c0 c1 c2 c3 of cubic curve c3 = (path[6], path[7]) c2 = (path[4], path[5]) c23_v = (c3[0] - c2[0], c3[1] - c2[1]) c23_len = math.sqrt(c23_v[0] * c23_v[0] + c23_v[1] * c23_v[1]) adir = (c23_v[0] / c23_len, c23_v[1] / c23_len) # arrow direction odir = (-adir[1], adir[0]) # othogonal direction arrow_pts = (c3[0], c3[1], -adir[0] * 10 + odir[0] * 4, -adir[1] * 10 + odir[1] * 4, -odir[0] * 8, -odir[1] * 8) arrow_txt = 'M %f,%f l %f,%f l %f,%f z' % arrow_pts arrow_node.setAttribute('d', arrow_txt) arrow_node.setAttribute('style', 'stroke: #000000; stroke-width: 1; ' 'fill: #000000') pass def _draw_transition_real(self, parent, path): doc = self._doc trn_g = doc.createElement('svg:g') path_node = doc.createElement('svg:path') arrow_node = doc.createElement('svg:path') self._update_graph(path, arrow_node, path_node) trn_g.appendChild(path_node) trn_g.appendChild(arrow_node) parent.appendChild(trn_g) return trn_g, path_node, arrow_node def _gen_path(self): states = self._states target_name = self.target target_state = states[target_name] src_state = self._state src_x, src_y = src_state.xy src_r = src_state.r target_x, target_y = target_state.xy target_r = target_state.r src_target_v = (target_x - src_x, target_y - src_y) src_target_len = \ math.sqrt(src_target_v[0] ** 2 + src_target_v[1] ** 2) distance = src_target_len - src_r - target_r distance3 = distance / 3 src_target_uv = (src_target_v[0] / src_target_len, src_target_v[1] / src_target_len) c0x = src_x + src_target_uv[0] * src_r c0y = src_y + src_target_uv[1] * src_r c1x = c0x + src_target_uv[0] * distance3 c1y = c0y + src_target_uv[1] * distance3 c3x = target_x - src_target_uv[0] * target_r c3y = target_y - src_target_uv[1] * target_r c2x = c3x - src_target_uv[0] * distance3 c2y = c3y - src_target_uv[1] * distance3 path = [c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y] return path @property def path(self): compview = self._compview state_name = self._state.state_name trn_cond = self.trn_cond trn = compview.get_transition(state_name, trn_cond) path = trn[3] if not path: path = self._gen_path() pass return path @property def target(self): compview = self._compview state_name = self._state.state_name trn_cond = self.trn_cond trn = compview.get_transition(state_name, trn_cond) return trn[1] @property def state(self): return self._state @property def action(self): compview = self._compview state_name = self._state.state_name trn_cond = self.trn_cond trn = compview.get_transition(state_name, trn_cond) return trn[2] def draw(self): path = self.path fsm_layer = self._fsm_layer trn_g, path_node, arrow_node = \ self._draw_transition_real(fsm_layer, path) self.trn_g = trn_g self._arrow_node = arrow_node self._path_node = path_node pass def clear(self): trn_g = self.trn_g parent = trn_g.parent() parent.removeChild(trn_g) pass def update(self): path = self.path arrow_node = self._arrow_node path_node = self._path_node self._update_graph(path, arrow_node, path_node) pass def adjust_by_ends(self): states = self._states state = self._state state_name = state.state_name trn_cond = self.trn_cond path = self.path start_state = self._state start_x, start_y = start_state.xy start_r = start_state.r target_name = self.target stop_state = states[target_name] stop_x, stop_y = stop_state.xy stop_r = stop_state.r c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y = tuple(path) c0c1 = (c1x - c0x, c1y - c0y) c0c1_len = math.sqrt(c0c1[0] ** 2 + c0c1[1] ** 2) start_v = (c0c1[0] / c0c1_len, c0c1[1] / c0c1_len) c3c2 = (c2x - c3x, c2y - c3y) c3c2_len = math.sqrt(c3c2[0] ** 2 + c3c2[1] ** 2) stop_v = (c3c2[0] / c3c2_len, c3c2[1] / c3c2_len) c0x = start_v[0] * start_r + start_x c0y = start_v[1] * start_r + start_y c1x = start_v[0] * c0c1_len + c0x c1y = start_v[1] * c0c1_len + c0y c3x = stop_v[0] * stop_r + stop_x c3y = stop_v[1] * stop_r + stop_y c2x = stop_v[0] * c3c2_len + c3x c2y = stop_v[1] * c3c2_len + c3y new_path = [c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y] compview = self._compview compview.set_transition_path(state_name, trn_cond, new_path) pass def show_control_points(self): if not self._control_points: doc = self._doc c1 = doc.createElement('svg:circle') c1.setAttribute('r', '3') c1.setAttribute('style', 'stroke: black; stroke-width: 1; ' 'fill: white') l01 = doc.createElement('svg:line') l01.setAttribute('style', 'stroke: black; stroke-width: 1; ' 'stroke-dasharray: 3 2') c2 = doc.createElement('svg:circle') c2.setAttribute('r', '3') c2.setAttribute('style', 'stroke: black; stroke-width: 1; ' 'fill: white') l32 = doc.createElement('svg:line') l32.setAttribute('style', 'stroke: black; stroke-width: 1; ' 'stroke-dasharray: 3 2') control_layer = self._control_layer control_layer.appendChild(c1) control_layer.appendChild(l01) control_layer.appendChild(c2) control_layer.appendChild(l32) self._control_points = (c1, l01, c2, l32) pass c1, l01, c2, l32 = self._control_points path = self.path c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y = tuple(path) c1.setAttribute('cx', str(c1x)) c1.setAttribute('cy', str(c1y)) l01.setAttribute('x1', str(c0x)) l01.setAttribute('y1', str(c0y)) l01.setAttribute('x2', str(c1x)) l01.setAttribute('y2', str(c1y)) c2.setAttribute('cx', str(c2x)) c2.setAttribute('cy', str(c2y)) l32.setAttribute('x1', str(c3x)) l32.setAttribute('y1', str(c3y)) l32.setAttribute('x2', str(c2x)) l32.setAttribute('y2', str(c2y)) pass def hide_control_points(self): if not self._control_points: return control_layer = self._control_layer for node in self._control_points: control_layer.removeChild(node) pass self._control_points = None pass def start_hint(self): path_node = self._path_node arrow_node = self._arrow_node if path_node: path_node.setAttribute('style', 'stroke: #404040; stroke-width: 3; ' 'fill: none') arrow_node.setAttribute('style', 'stroke: #404040; stroke-width: 2; ' 'fill: #404040') pass pass def stop_hint(self): path_node = self._path_node arrow_node = self._arrow_node if path_node: path_node.setAttribute('style', 'stroke: #000000; stroke-width: 1; ' \ 'fill: none') arrow_node.setAttribute('style', 'stroke: #000000; stroke-width: 1; ' \ 'fill: #000000') pass pass def show_selected(self): if not self._selected_rect: doc = self._doc rect = doc.createElement('svg:rect') control_layer = self._control_layer rect.setAttribute('style', 'stroke: #404040; stroke-width: 1; ' 'stroke-dasharray: 6 4; fill: none') control_layer.appendChild(rect) self._selected_rect = rect pass trn_g = self.trn_g rect = self._selected_rect px, py, pw, ph = trn_g.getBBox() x, y = self._translate_page_xy(px, py) y = y - ph # px, py is left-bottom corner rect.setAttribute('x', str(x - 2)) rect.setAttribute('y', str(y - 2)) rect.setAttribute('width', str(pw + 4)) rect.setAttribute('height', str(ph + 4)) pass def hide_selected(self): if not self._selected_rect: return control_layer = self._control_layer rect = self._selected_rect control_layer.removeChild(rect) self._selected_rect = None pass pass class FSM_state(object): _doc = None _compview = None _states = None _fsm_layer = None _control_layer = None state_name = None state_g = None _text_node = None _circle_node = None transitions = None from_states = None # There is one or more transitions # from these states (name). _state_g_hdl_id = None _selected_rect = None def __init__(self, state_name): self.state_name = state_name self.transitions = {} self.from_states = set() pass def init(self, doc, compview, states, fsm_layer, control_layer): self._doc = doc self._compview = compview self._states = states self._fsm_layer = fsm_layer self._control_layer = control_layer pass def _update_graph(self, text_node, text_content, circle_node, state_name, r, x, y): circle_node.setAttribute('r', str(r)) circle_node.setAttribute('cx', str(x)) circle_node.setAttribute('cy', str(y)) circle_node.setAttribute('style', 'stroke: #000000; stroke-width: 1; ' 'fill: #ffffff') text_node.setAttribute('style', 'stroke: #000000; fill: #000000; ' 'font-size: 16px') text_content.setContent(state_name) doc = self._doc spdoc = doc.spdoc spdoc.ensureUpToDate() tx, ty, tw, th = text_node.getBBox() text_node.setAttribute('x', str(x - tw / 2)) text_node.setAttribute('y', str(y + th / 2)) pass def grab(self, callback): assert not self._state_g_hdl_id state_g = self.state_g state_g_spitem = state_g.spitem state_g_hdl_id = state_g_spitem.connect('mouse-event', callback) self._state_g_hdl_id = state_g_hdl_id pass def ungrab(self): if not self._state_g_hdl: return state_g = self.state_g state_g_hdl_id = self._state_g_hdl_id state_g.disconnect(state_g_hdl_id) pass def _translate_page_xy(self, x, y): doc = self._doc root = doc.root() page_h_txt = root.getAttribute('height') page_h = float(page_h_txt) svgx = x svgy = page_h - y return svgx, svgy def show_selected(self): if not self._selected_rect: doc = self._doc rect = doc.createElement('svg:rect') control_layer = self._control_layer rect.setAttribute('style', 'stroke: #404040; stroke-width: 1; ' 'stroke-dasharray: 6 4; fill: none') control_layer.appendChild(rect) self._selected_rect = rect pass state_g = self.state_g rect = self._selected_rect px, py, pw, ph = state_g.getBBox() x, y = self._translate_page_xy(px, py) y = y - ph # px, py is left-bottom corner rect.setAttribute('x', str(x - 2)) rect.setAttribute('y', str(y - 2)) rect.setAttribute('width', str(pw + 4)) rect.setAttribute('height', str(ph + 4)) pass def hide_selected(self): if not self._selected_rect: return control_layer = self._control_layer rect = self._selected_rect control_layer.removeChild(rect) self._selected_rect = None pass def _draw_state_real(self, parent, state_name, r, x, y): doc = self._doc state_g = doc.createElement('svg:g') text = doc.createElement('svg:text') circle = doc.createElement('svg:circle') text_content = doc.createTextNode(state_name) text.appendChild(text_content) state_g.appendChild(circle) state_g.appendChild(text) parent.appendChild(state_g) self._update_graph(text, text_content, circle, state_name, r, x, y) return state_g, text, text_content, circle @property def r(self): compview = self._compview state_name = self.state_name r = compview.get_state_r(state_name) return r @property def xy(self): compview = self._compview state_name = self.state_name xy = compview.get_state_xy(state_name) return xy @property def entry_action(self): compview = self._compview state_name = self.state_name entry_action = compview.get_state_entry_action(state_name) return entry_action @property def all_transitions(self): compview = self._compview state_name = self.state_name conds = compview.all_transitions(state_name) return conds def _load_transition_compview(self, parent, condition): compview = self._compview states = self._states trn = FSM_transition(condition) trn.init(self._doc, compview, self, states, self._fsm_layer, self._control_layer) trn.draw() self.transitions[condition] = trn pass def draw(self): state_name = self.state_name fsm_layer = self._fsm_layer r = self.r x, y = self.xy state_g, text_node, text_content, circle_node = \ self._draw_state_real(fsm_layer, state_name, r, x, y) self.state_g = state_g self._text_node = text_node self._text_content = text_content self._circle_node = circle_node for trn_cond in self.all_transitions: self._load_transition_compview(fsm_layer, trn_cond) pass pass def clear(self): state_g = self.state_g parent = state_g.parent() parent.removeChild(state_g) pass def update(self): text_node = self._text_node text_content = self._text_content circle_node = self._circle_node state_name = self.state_name r = self.r x, y = self.xy self._update_graph(text_node, text_content, circle_node, state_name, r, x, y) pass ## \brief Tell states there are transitions to them. # # This function is only called when loading states of a FSM from # compview. When loading, not all states was loaded that target # state may not in the memory. So, we call this function after # all states being loaded. Transitions added later does need to # call this function to notify end state. # def tell_target_states(self): states = self._states transitions = self.transitions target_state_names = [trn.target for trn in transitions.values()] target_states = [states[target_name] for target_name in target_state_names] state_name = self.state_name for target_state in target_states: target_state.from_states.add(state_name) pass pass def rm_target_from_states(self): state_name = self.state_name transitions = self.transitions.values() target_names = [trn.target for trn in transitions] states = self._states for target_name in target_names: target_state = states[target_name] target_state.from_states.remove(state_name) pass pass def adjust_transitions(self): import itertools states = self._states for trn in self.transitions.values(): trn.adjust_by_ends() trn.update() pass state_name = self.state_name from_states = [states[from_state_name] for from_state_name in self.from_states] states_transitions = [state.transitions.values() for state in from_states] in_state_transitions = [[trn for trn in state_transitions if trn.target == state_name] for state_transitions in states_transitions] in_transitions = itertools.chain(*in_state_transitions) for trn in in_transitions: trn.adjust_by_ends() trn.update() pass pass def add_transition(self, parent, condition): self._load_transition_compview(parent, condition) transitions = self.transitions trn = transitions[condition] target_name = trn.target state_name = self.state_name states = self._states target_state = states[target_name] target_state.from_states.add(state_name) pass ## \brief Remove state from from_states of a given target. # # The state was removed only when there is no transition targeted # on given target state. # def _rm_from_states_for_target(self, target_name): transitions = self.transitions same_targets = [trn.target for trn in transitions.values() if trn.target == target_name] same_target_cnt = len(same_targets) if same_target_cnt == 0: states = self._states target_state = states[target_name] state_name = self.state_name target_state.from_states.remove(state_name) pass pass def rm_transition(self, condition): transitions = self.transitions trn = transitions[condition] target_name = trn.target del transitions[condition] trn.clear() self._rm_from_states_for_target(target_name) pass def start_hint(self): circle_node = self._circle_node circle_node.setAttribute('style', 'stroke: #000000; stroke-width: 3; ' 'fill: #ffffff') pass def stop_hint(self): circle_node = self._circle_node circle_node.setAttribute('style', 'stroke: #000000; stroke-width: 1; ' 'fill: #ffffff') pass pass ## \brief Management selections # # There is only one state, control points of a transition, or # transition being selected at any instance. This class manage # selection to keep the requirement consisted. When caller select a # new state, control points of a transition, or transition, the class # will de-select previous one automatically. # class _select_manager(object): selected_state = None selected_transition = None controlled_transition = None def deselect(self): pass def select_state(self, state): self.deselect() self.selected_state = state state.show_selected() def hide(): state.hide_selected() self.reset() pass self.deselect = hide pass def select_transition(self, transition): self.deselect() self.selected_transition = transition transition.show_selected() def hide(): transition.hide_selected() self.reset() pass self.deselect = hide pass def control_transition(self, transition): self.deselect() self.controlled_transition = transition transition.show_control_points() def hide(): transition.hide_control_points() self.reset() pass self.deselect = hide pass ## \brief Forget all state of the instance # def reset(self): try: del self.deselect except AttributeError: pass self.selected_state = None self.selected_transition = None self.controlled_transition = None pass pass ## \brief Handle popup menu for states and transitions. # # _FSM_popup.popup_install_handler() must be called to install event # handlers. It should be called when FSM_window entering a new mode # since it will ungrab all events to activate a new mode. # class _FSM_popup(object): _window = None _compview = None _menu_state = None _menu_transition = None _candidate_target = None _select = None def __init__(self, window, compview, select_man): super(_FSM_popup, self).__init__() self._window = window self._compview = compview self._select = select_man pass def _show_state_menu(self, state): self._menu_state = state window = self._window window.popup_state_menu() pass def _show_transition_menu(self, trn): self._menu_transition = trn window = self._window window.popup_transition_menu() pass ## \brief Handle mouse events for state objects. # # This method must be called by mode object to handle mouse events # that is not handled by them. # def _handle_state_mouse_events(self, state, evtype, button, x, y): if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS and \ button == 3: self._show_state_menu(state) self._select.select_state(state) elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_ENTER: state.start_hint() elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_LEAVE: state.stop_hint() pass pass ## \brief Handle mouse events for transition objects. # # This method must be called by mode object to handle mouse events # that is not handled by them. # def _handle_transition_mouse_events(self, trn, evtype, button, x, y): if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS and \ button == 3: self._select.select_transition(trn) self._show_transition_menu(trn) elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_ENTER: trn.start_hint() elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_LEAVE: trn.stop_hint() pass pass def _handle_select_transition_target(self, state, evtype, button, x, y): if self._candidate_target != state and self._menu_state != state: if self._candidate_target: self._candidate_target.stop_hint() pass self._candidate_target = state state.start_hint() pass if evtype != pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE: return if button != 1: return window = self._window if state == self._menu_state: window.pop_grabs() return fsm_layer = window._fsm_layer target_state = state target_name = target_state.state_name src_state = self._menu_state src_name = src_state.state_name cond = '' compview = self._compview try: compview.add_transition(src_name, cond, target_name) except: import traceback traceback.print_exc() window.show_error('invalid condition: %s' % (cond)) else: src_state.add_transition(fsm_layer, cond) trn = src_state.transitions[cond] window._install_transition_event_handler(trn) pass window.pop_grabs() target_state.stop_hint() select = self._select select.deselect() pass def _handle_add_transition(self, *args): def restore_bg(item, evtype, *args): if evtype != pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS: if self._candidate_target: self._candidate_target.stop_hint() self._candidate_target = None pass return self._select.deselect() window.pop_grabs() pass window = self._window window.push_grabs() window.ungrab_bg() window.grab_bg(restore_bg) window.ungrab_state() window.grab_state(self._handle_select_transition_target) self._select.select_state(self._menu_state) self._menu_state.stop_hint() pass def _handle_edit_transition(self, *args): trn = self._select.selected_transition cond = trn.trn_cond action = trn.action or '' window = self._window window.show_transition_editor(cond, action) pass def _handle_transition_apply(self, *args): trn = self._select.selected_transition window = self._window compview = self._compview transition_cond = window._transition_cond transition_action = window._transition_action trn_cond = trn.trn_cond trn_action = trn.action trn_state = trn.state trn_state_name = trn_state.state_name new_cond = transition_cond.get_text() new_action = transition_action.get_text() if new_action != trn_action: compview.set_transition_action(trn_state_name, trn_cond, new_action) pass if new_cond != trn_cond: trn_state.rm_transition(trn_cond) compview.chg_transition_cond(trn_state_name, trn_cond, new_cond) fsm_layer = window._fsm_layer trn_state.add_transition(fsm_layer, new_cond) transitions = trn_state.transitions new_trn = transitions[new_cond] window._install_transition_event_handler(new_trn) pass window.hide_transition_editor() pass def _handle_edit_state(self, *args): select = self._select state = select.selected_state name = state.state_name r = state.r entry_action = state.entry_action window = self._window window.show_state_editor(name, r, entry_action) pass def _handle_state_change(self): window = self._window compview = self._compview select = self._select state_name_txt = window._state_name state_radius_txt = window._state_radius state_entry_action_txt = window._state_entry_action state_name = state_name_txt.get_text() state_radius = state_radius_txt.get_text() state_entry_action = state_entry_action_txt.get_text() state_radius_f = float(state_radius) state = select.selected_state old_state_name = state.state_name if old_state_name != state_name: compview.rename_state(old_state_name, state_name) state.state_name = state_name pass compview.set_state_r(state_name, state_radius_f) compview.set_state_entry_action(state_name, state_entry_action) state.update() window.hide_state_editor() select.deselect() pass def _handle_del_state(self, *args): window = self._window select = self._select compview = self._compview state = select.selected_state state_name = state.state_name select.deselect() states = window._states del states[state_name] state.clear() # Remove out transitions transitions = state.transitions for trn in transitions.values(): trn.clear() pass state.rm_target_from_states() # Remove in-transition src_state_names = state.from_states for src_state_name in src_state_names: src_state = states[src_state_name] in_cond_trns = [(in_cond, in_trn) for in_cond, in_trn in \ src_state.transitions.items() if in_trn.target == state_name] for in_cond, in_trn in in_cond_trns: in_trn.clear() del src_state.transitions[in_cond] compview.rm_transition(src_state_name, in_cond) pass pass compview.rm_state(state_name) pass def _handle_del_transition(self, *args): window = self._window select = self._select compview = self._compview trn = select.selected_transition trn.clear() trn_cond = trn.trn_cond trn_state = trn.state trn_state_name = trn_state.state_name trn_target_name = trn.target target_names = [trn.target for trn in trn_state.transitions.values()] # the transition must live until getting all info. compview.rm_transition(trn_state_name, trn_cond) if trn_target_name not in target_names: trn_target_state = window._states[trn_target_name] trn_target_state.from_states.remove(trn_state_name) pass del trn_state.transitions[trn_cond] pass def popup_install_handler(self): window = self._window window.grab_add_transition(self._handle_add_transition) window.grab_edit_transition(self._handle_edit_transition) window.grab_edit_state(self._handle_edit_state) window.grab_transition_apply(self._handle_transition_apply) window.grab_state_apply(self._handle_state_change) window.grab_del_state(self._handle_del_state) window.grab_del_transition(self._handle_del_transition) pass pass class _FSM_move_state_mode(object): _popup = None _window = None _compview = None _select = None _controlling_transition = None def __init__(self, window, compview, select_man): super(_FSM_move_state_mode, self).__init__() self._window = window self._compview = compview self._locker = compview self._popup = _FSM_popup(window, compview, select_man) self._select = select_man pass def _handle_move_state_background(self, item, evtype, button, x, y): if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE: self._select.deselect() pass pass def _handle_move_state_state(self, state, evtype, button, x, y): window = self._window def moving_state(item, evtype, button, x, y): if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE: window.ungrab_mouse() pass new_state_x = orign_state_x + x - start_x new_state_y = orign_state_y + y - start_y compview = self._compview compview.set_state_xy(state.state_name, new_state_x, new_state_y) state.update() state.adjust_transitions() state.show_selected() pass if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS and \ button == 1: start_x = x start_y = y orign_state_x, orign_state_y = state.xy self._select.select_state(state) window.grab_mouse(moving_state) pass elif evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE and \ button == 1: window.ungrab_mouse() pass else: self._popup._handle_state_mouse_events(state, evtype, button, x, y) pass pass ## \brief Install event handler for control points of a transitions. # def _install_trn_cps_mouse(self, trn): c1, l01, c2, l32 = trn._control_points path = trn.path c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y = tuple(path) state_src = trn.state target_name = trn.target states = trn._states state_target = states[target_name] compview = self._compview window = self._window select = self._select def c1_update(rx, ry): nc1x = c1x + rx nc1y = c1y + ry cx, cy = state_src.xy r = state_src.r cv = nc1x - cx, nc1y - cy cv_len = math.sqrt(cv[0] ** 2 + cv[1] ** 2) nc0x = cx + cv[0] * r / cv_len nc0y = cy + cv[1] * r / cv_len path = list(trn.path) path[:4] = [nc0x, nc0y, nc1x, nc1y] state_name = state_src.state_name cond = trn.trn_cond compview.set_transition_path(state_name, cond, path) trn.update() trn.show_control_points() pass def c1_start(): def relay_event(item, evtype, button, x, y): c1_dragger.mouse_event(evtype, button, x, y) pass window.push_grabs() window.ungrab_bg() window.grab_bg(relay_event) pass def c1_stop(rx, ry): window.pop_grabs() pass def c2_update(rx, ry): nc2x = c2x + rx nc2y = c2y + ry cx, cy = state_target.xy r = state_target.r cv = nc2x - cx, nc2y - cy cv_len = math.sqrt(cv[0] ** 2 + cv[1] ** 2) nc3x = cx + cv[0] * r / cv_len nc3y = cy + cv[1] * r / cv_len path = list(trn.path) path[4:] = [nc2x, nc2y, nc3x, nc3y] state_name = state_src.state_name cond = trn.trn_cond compview.set_transition_path(state_name, cond, path) trn.update() trn.show_control_points() pass def c2_start(): def relay_event(item, evtype, button, x, y): c2_dragger.mouse_event(evtype, button, x, y) pass window.push_grabs() window.ungrab_bg() window.grab_bg(relay_event) pass def c2_stop(rx, ry): window.pop_grabs() pass c1_dragger = _dragger() c1_dragger.update = c1_update c1_dragger.start_drag = c1_start c1_dragger.stop_drag = c1_stop c1_dragger.connect(c1) c2_dragger = _dragger() c2_dragger.update = c2_update c2_dragger.start_drag = c2_start c2_dragger.stop_drag = c2_stop c2_dragger.connect(c2) pass ## \brief A transition was selected. # def _control_transition(self, trn): def handle_bg(item, evtype, button, x, y): if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS: window.pop_grabs() window.ungrab_bg() select.deselect() del self._hint_transition self._controlling_transition = None pass pass select = self._select select.control_transition(trn) self._hint_transition = lambda trn: None trn.stop_hint() window = self._window window.push_grabs() window.ungrab_bg() window.grab_bg(handle_bg) self._install_trn_cps_mouse(trn) pass ## \brief Hint for mouse over a transition. # def _hint_transition(self, trn): def stop_hint(*args): trn.stop_hint() window.ungrab_bg() window.grab_bg(self._handle_move_state_background) pass trn.start_hint() window = self._window window.ungrab_bg() window.grab_bg(stop_hint) pass def _handle_del_transition(self, *args): pass ## \brief Handle mouse events when selecting no transition. # def _handle_transitoin_mouse_events(self, trn, evtype, button, x, y): if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE and \ button == 1: self._control_transition(trn) else: self._popup._handle_transition_mouse_events(trn, evtype, button, x, y) pass pass def activate(self): window = self._window window._emit_leave_mode() window._clear_leave_mode_cb() window.ungrab_all() window.ungrab_bg() window.grab_bg(self._handle_move_state_background) window.grab_state(self._handle_move_state_state) window.grab_transition(self._handle_transitoin_mouse_events) self._popup.popup_install_handler() pass def deactivate(self): self._select.deselect() if self._controlling_transition: window = self._window window.pop_grabs() del self._hint_transition self._controlling_transition = None pass pass pass class _FSM_add_state_mode(object): _window = None _compview = None _saved_x = 0 _saved_y = 0 _popup = None _select = None def __init__(self, window, compview, select_man): super(_FSM_add_state_mode, self).__init__() self._window = window self._compview = compview self._locker = compview self._select = select_man self._popup = _FSM_popup(window, compview, select_man) pass def _handle_add_new_state(self): import traceback compview = self._compview window = self._window x, y = window._translate_xy(self._saved_x, self._saved_y) state_name = window._state_name.get_text() r_txt = window._state_radius.get_text() try: r = float(r_txt) except ValueError: traceback.print_exc() window.show_error('Invalid value: "%s" is not a valid value ' 'for radius.' % (r_txt)) return try: compview.add_state(state_name) except: traceback.print_exc() window.show_error('Invalid state name: "%s" is existing' % (state_name)) return compview.set_state_xy(state_name, x, y) compview.set_state_r(state_name, r) window._load_new_state_incr(state_name) window.hide_state_editor() pass def _handle_add_state_background(self, item, evtype, button, x, y): window = self._window select = self._select if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE and \ button == 1: self._saved_x = x self._saved_y = y select.deselect() window.show_state_editor() pass pass ## \brief Dispatching state apply event to _FSM_popup or this class. # # When user change properties of a state, this event is deliveried to # _FSM_popup. Otherwise, dispatch the event to this class. # def _handle_state_apply(self): select = self._select if select.selected_state: # selected the state while user request to edit a state. popup = self._popup popup._handle_state_change() else: # deselected while user click on bg to add a new state. self._handle_add_new_state() pass pass def activate(self): window = self._window window._emit_leave_mode() window.ungrab_all() window.grab_bg(self._handle_add_state_background) # # Install event handlers for _FSM_popup # window.grab_state(self._popup._handle_state_mouse_events) window.grab_transition(self._popup._handle_transition_mouse_events) self._popup.popup_install_handler() # # Workaround to make state apply events dispatched to right # place according history of user actions. # # see _handle_state_apply() # window.ungrab_state_apply() window.grab_state_apply(self._handle_state_apply) pass def deactivate(self): pass pass class FSM_window(FSM_window_base): __metaclass__ = data_monitor.data_monitor __data_monitor_prefix__ = 'on_' _domview = None _comp_name = 'main' _comview = None _background = None _fsm_layer = None _control_layer = None width = 1024 height = 768 _grab_mouse_hdl = None _bg_hdl = None _bg_mouse_event_cb = None _leave_mode_cb = None _move_state_mode = None _add_state_mode = None _state_mouse_event_handler = None _add_transition_cb = None _edit_transition_cb = None _transition_apply_cb = None _transition_mouse_event_handler = None _edit_state_cb = None _state_apply_cb = None _del_state_cb = None _del_transition_cb = None _grab_stack = None _select = None def __init__(self, domview_ui, close_cb, destroy_cb): super(FSM_window, self).__init__() self._locker = domview_ui self._domview = domview_ui self._compview = _compview(domview_ui, self._comp_name) self._states = {} self._close_cb = close_cb # callback to close editor window (hide) self._destroy_cb = destroy_cb # callback to destroy editor window _select = _select_manager() self._select = _select self._move_state_mode = \ _FSM_move_state_mode(self, self._compview, _select) self._add_state_mode = \ _FSM_add_state_mode(self, self._compview, _select) self._grab_stack = [] pass def _init_layers(self): doc = self._doc() root = self._root() root.setAttribute('inkscape:groupmode', 'layer') background = doc.createElement('svg:rect') background.setAttribute('x', '0') background.setAttribute('y', '0') background.setAttribute('width', str(self.width)) background.setAttribute('height', str(self.height)) background.setAttribute('style', 'fill: #ffffff') root.appendChild(background) self._background = background fsm_layer = doc.createElement('svg:g') fsm_layer.setAttribute('inkscape:groupmode', 'layer') root.appendChild(fsm_layer) self._fsm_layer = fsm_layer control_layer = doc.createElement('svg:g') control_layer.setAttribute('inkscape:groupmode', 'layer') root.appendChild(control_layer) self._control_layer = control_layer bg_hdl = background.spitem.connect('mouse-event', self.on_bg_mouse_events) self._bg_hdl = bg_hdl pass def _doc(self): view_widget = self._view_widget view = view_widget.view doc = view.doc().rdoc return doc def _root(self): doc = self._doc() root = doc.root() return root def _translate_xy(self, x, y): return x, y def _clear_view(self): if not self._background: self._init_layers() return children = [child for child in self._fsm_layer.childList()] + \ [child for child in self._control_layer.childList()] for child in children: parent = child.parent() parent.removeChild(child) pass self._states = {} pass def _make_state_compview(self, state_name): compview = self._compview doc = self._doc() fsm_layer = self._fsm_layer states = self._states state = FSM_state(state_name) state.init(doc, compview, states, self._fsm_layer, self._control_layer) self._states[state_name] = state return state def _set_leave_mode_cb(self, callback): self._leave_mode_cb = callback pass def _clear_leave_mode_cb(self): self._leave_mode_cb = None pass def _emit_leave_mode(self): if self._leave_mode_cb: self._leave_mode_cb() self._leave_mode_cb = None pass pass def ungrab_all(self): self.ungrab_bg() self.ungrab_state() self.ungrab_add_transition() self.ungrab_transition() self.ungrab_edit_transition() self.ungrab_edit_state() self.ungrab_transition_apply() self.ungrab_state_apply() self.ungrab_del_state() self.ungrab_del_transition() pass def save_grabs(self): save = (self._bg_mouse_event_cb, self._state_mouse_event_handler, self._transition_mouse_event_handler, self._add_transition_cb, self._edit_transition_cb, self._transition_apply_cb, self._edit_state_cb, self._state_apply_cb, self._del_state_cb, self._del_transition_cb) return save def restore_grabs(self, save): self._bg_mouse_event_cb, \ self._state_mouse_event_handler, \ self._transition_mouse_event_handler, \ self._add_transition_cb, \ self._edit_transition_cb, \ self._transition_apply_cb, \ self._edit_state_cb, \ self._state_apply_cb, \ self._del_state_cb, \ self._del_transition_cb \ = save pass ## \brief Push current setting of grab handles into the stack. # def push_grabs(self): save = self.save_grabs() self._grab_stack.append(save) pass ## \brief Restore setting of grab handles from the stack. # def pop_grabs(self): save = self._grab_stack.pop() self.restore_grabs(save) pass def on_state_mouse_event(self, state, evtype, button, x, y): if self._state_mouse_event_handler: self._state_mouse_event_handler(state, evtype, button, x, y) pass pass def _install_state_event_handler(self, state): def mouse_event_handler(item, evtype, button, x, y): self.on_state_mouse_event(state, evtype, button, x, y) pass state.grab(mouse_event_handler) pass def on_transition_mouse_event(self, trn, evtype, button, x, y): if self._transition_mouse_event_handler: self._transition_mouse_event_handler(trn, evtype, button, x, y) pass pass def _install_transition_event_handler(self, trn): def mouse_event_handler(item, evtype, button, x, y): self.on_transition_mouse_event(trn, evtype, button, x, y) pass trn_g = trn.trn_g trn_g.spitem.connect('mouse-event', mouse_event_handler) pass def grab_transition(self, callback): assert self._transition_mouse_event_handler is None self._transition_mouse_event_handler = callback pass def ungrab_transition(self): self._transition_mouse_event_handler = None pass def grab_state(self, callback): assert self._state_mouse_event_handler is None self._state_mouse_event_handler = callback pass def ungrab_state(self): self._state_mouse_event_handler = None pass def grab_add_transition(self, callback): assert self._add_transition_cb is None self._add_transition_cb = callback pass def ungrab_add_transition(self): self._add_transition_cb = None pass def grab_edit_transition(self, callback): assert self._edit_transition_cb is None self._edit_transition_cb = callback pass def ungrab_edit_transition(self): self._edit_transition_cb = None pass def grab_transition_apply(self, callback): assert self._transition_apply_cb is None self._transition_apply_cb = callback pass def ungrab_transition_apply(self): self._transition_apply_cb = None pass def grab_edit_state(self, callback): assert self._edit_state_cb is None self._edit_state_cb = callback pass def ungrab_edit_state(self): self._edit_state_cb = None pass def grab_state_apply(self, callback): assert self._state_apply_cb is None self._state_apply_cb = callback pass def ungrab_state_apply(self): self._state_apply_cb = None pass def grab_del_state(self, callback): assert self._del_state_cb is None self._del_state_cb = callback pass def ungrab_del_state(self): self._del_state_cb = None pass def grab_del_transition(self, callback): assert self._del_transition_cb is None self._del_transition_cb = callback pass def ungrab_del_transition(self): self._del_transition_cb = None pass def _draw_new_state(self, state_name): states = self._states state = states[state_name] state.draw() self._install_state_event_handler(state) for trn in state.transitions.values(): self._install_transition_event_handler(trn) pass pass def _load_new_state(self, state_name): state = self._make_state_compview(state_name) self._draw_new_state(state_name) pass ## \brief Load new state incrementally. # def _load_new_state_incr(self, state_name): self._load_new_state(state_name) states = self._states state = states[state_name] state.tell_target_states() pass def _rebuild_from_states(self): states = self._states compview = self._compview state_names = compview.all_state_names() for state_name in state_names: state = states[state_name] self._draw_new_state(state_name) state.tell_target_states() pass pass def _update_view(self): self._clear_view() states = self._states compview = self._compview state_names = compview.all_state_names() for state_name in state_names: self._make_state_compview(state_name) pass self._rebuild_from_states() pass def set_svg_view(self, view): self._view_box.add(view) self._view_widget = view root = self._root() root.setAttribute('width', '1024') root.setAttribute('height', '768') view.setResize(True, 800, 600) pass def _update_action_store(self): action_store = self._action_store compview = self._compview action_store.clear() action_names = compview.all_actions() for action_name in action_names: action_store.append((action_name,)) pass pass def show_action_picker(self): self._update_action_store() super(FSM_window, self).show_action_picker() pass def on_close_window_activate(self, *args): self._emit_leave_mode() self._close_cb() pass def on_FSM_main_win_destroy_event(self, *args): self._emit_leave_mode() self._destroy_cb() pass def on_FSM_main_win_delete_event(self, *args): self._emit_leave_mode() self._destroy_cb() pass def on_add_state_toggled(self, *args): mode = self._add_state_mode mode.activate() self._set_leave_mode_cb(lambda: mode.deactivate()) pass def on_move_state_toggled(self, *args): mode = self._move_state_mode mode.activate() self._set_leave_mode_cb(lambda: mode.deactivate()) pass def on_state_apply_clicked(self, *args): if self._state_apply_cb: self._state_apply_cb() pass pass def on_add_transition_activate(self, *args): if self._add_transition_cb: self._add_transition_cb(*args) pass pass def on_edit_transition_activate(self, *args): if self._edit_transition_cb: self._edit_transition_cb(*args) pass pass def on_transition_apply_clicked(self, *args): if self._transition_apply_cb: self._transition_apply_cb(*args) pass pass def on_edit_state_activate(self, *args): if self._edit_state_cb: self._edit_state_cb(*args) pass pass def on_del_state_activate(self, *args): if self._del_state_cb: self._del_state_cb(*args) pass pass def on_del_transition_activate(self, *args): if self._del_transition_cb: self._del_transition_cb(*args) pass pass def _install_test_data(self): self._init_layers() compview = self._compview view = self._view_widget.view doc = view.doc() rdoc = doc.rdoc root_node = doc.root().repr line_node = rdoc.createElement('svg:line') line_node.setAttribute('x1', '10') line_node.setAttribute('y1', '10') line_node.setAttribute('x2', '100') line_node.setAttribute('y2', '100') line_node.setAttribute('style', 'stroke: #000000; stroke-width:2') root_node.appendChild(line_node) def show_msg(*args, **kws): print 'mouse_event' print args pass print 'before connect' hdl_id = line_node.spitem.connect('mouse-event', show_msg) print hdl_id state1 = 'state 1' compview.add_state(state1) compview.set_state_r(state1, 50) compview.set_state_xy(state1, 200, 100) state2 = 'state 2' compview.add_state(state2) compview.set_state_r(state2, 30) compview.set_state_xy(state2, 300, 100) compview.add_transition(state1, 'event1', state2) compview.set_transition_path(state1, 'event1', (200, 150, 240, 180, 260, 180, 300, 130)) pass def show(self): if _install_test_data_flag: self._install_test_data() self._install_test_data = lambda: None pass # # Crash if without line. # This line remove selection infor to prevent select manager to # deselect an object selected in previous session. It would crash # if we don't reset it and compview of previous session were # removed. # self._select.reset() self._update_view() self._add_state_mode.activate() super(FSM_window, self).show() pass def grab_mouse(self, callback): assert self._grab_mouse_hdl is None root = self._root() root.setAttribute('inkscape:groupmode', '') self._grab_mouse_hdl = root.spitem.connect('mouse-event', callback) pass def ungrab_mouse(self): if not self._grab_mouse_hdl: return root = self._root() root.spitem.disconnect(self._grab_mouse_hdl) self._grab_mouse_hdl = None root.setAttribute('inkscape:groupmode', 'layer') pass def on_bg_mouse_events(self, item, evtype, button, x, y): if not self._bg_mouse_event_cb: return self._bg_mouse_event_cb(item, evtype, button, x, y) pass def grab_bg(self, callback): assert self._bg_mouse_event_cb is None self._bg_mouse_event_cb = callback pass def ungrab_bg(self): if not self._bg_mouse_event_cb: return self._bg_mouse_event_cb = None pass def switch_component(self, comp_name): self._compview.switch_component(comp_name) self._comp_name = comp_name self._comp_name_label.set_text(comp_name) pass def current_component(self): return self._comp_name pass _install_test_data_flag = False if __name__ == '__main__': _install_test_data_flag = True win = FSM_window() win._main_win.connect('destroy', gtk.main_quit) win.show() gtk.main() pass