comparison pyink/FSM_window.py @ 1502:376a8cb7312e

Refactor popup menu and selection of states and transition
author Thinker K.F. Li <thinker@codemud.net>
date Sat, 07 May 2011 21:48:47 +0800
parents 4a57650bb926
children 4d582306df85
comparison
equal deleted inserted replaced
1501:4a57650bb926 1502:376a8cb7312e
840 del transitions[condition] 840 del transitions[condition]
841 trn.clear() 841 trn.clear()
842 842
843 self._rm_from_states_for_target(target_name) 843 self._rm_from_states_for_target(target_name)
844 pass 844 pass
845
846 def start_hint(self):
847 pass
848
849 def stop_hint(self):
850 pass
851 pass
852
853
854 class _select_manager(object):
855 selected_state = None
856 selected_transition = None
857
858 def deselect(self):
859 pass
860
861 def select_state(self, state):
862 self.deselect()
863 self.selected_state = state
864 state.show_selected()
865 def hide():
866 state.hide_selected()
867 self.selected_state = None
868 pass
869 self.deselect = hide
870 pass
871
872 def select_transition(self, transition):
873 self.deselect()
874 self.selected_transition = transition
875 transition.show_control_points()
876 def hide():
877 transition.hide_control_points()
878 self.selected_transition = None
879 pass
880 self.deselect = hide
881 pass
882 pass
883
884
885 class _FSM_popup(object):
886 _window = None
887 _domview = None
888
889 _menu_state = None
890 _menu_transition = None
891
892 _candidate_target = None
893
894 _select = None
895
896 def __init__(self, window, domview_ui, select_man):
897 super(_FSM_popup, self).__init__()
898 self._window = window
899 self._domview = domview_ui
900 self._select = select_man
901 pass
902
903 def _show_state_menu(self, state):
904 self._menu_state = state
905 window = self._window
906 window.popup_state_menu()
907 pass
908
909 def _show_transition_menu(self, trn):
910 self._menu_transition = trn
911 window = self._window
912 window.popup_transition_menu()
913 pass
914
915 ## \brief Handle mouse events for state objects.
916 #
917 # This method must be called by mode object to handle mouse events
918 # that is not handled by them.
919 #
920 def _handle_state_mouse_events(self, state, evtype, button, x, y):
921 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS and \
922 button == 3:
923 self._show_state_menu(state)
924 elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_ENTER:
925 state.start_hint()
926 elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_LEAVE:
927 state.stop_hint()
928 pass
929 pass
930
931 ## \brief Handle mouse events for transition objects.
932 #
933 # This method must be called by mode object to handle mouse events
934 # that is not handled by them.
935 #
936 def _handle_transition_mouse_events(self, trn, evtype, button, x, y):
937 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS and \
938 button == 3:
939 self._show_transition_menu(trn)
940 elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_ENTER:
941 trn.start_hint()
942 elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_LEAVE:
943 trn.stop_hint()
944 pass
945 pass
946
947 def _handle_select_transition_target(self, state, evtype, button, x, y):
948 if self._candidate_target != state and self._menu_state != state:
949 if self._candidate_target:
950 self._candidate_target.hide_selected()
951 pass
952 self._candidate_target = state
953 state.show_selected()
954 pass
955
956 if evtype != pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE:
957 return
958 if button != 1:
959 return
960
961 window = self._window
962
963 if state == self._menu_state:
964 window.pop_grabs()
965 return
966
967 fsm_layer = window._fsm_layer
968
969 target_state = state
970 target_name = target_state.state_name
971 src_state = self._menu_state
972 src_name = src_state.state_name
973 cond = ''
974
975 domview = self._domview
976 domview.add_transition(src_name, cond, target_name)
977 src_state.add_transition(fsm_layer, cond)
978
979 trn = src_state.transitions[cond]
980 window._install_transition_event_handler(trn)
981
982 window.pop_grabs()
983 pass
984
985 def _handle_add_transition(self, *args):
986 def restore_bg(item, evtype, *args):
987 if evtype != pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS:
988 if self._candidate_target:
989 self._candidate_target.hide_selected()
990 self._candidate_target = None
991 pass
992 return
993 self._select.deselect()
994 window.pop_grabs()
995 pass
996
997 window = self._window
998 window.push_grabs()
999 window.ungrab_bg()
1000 window.grab_bg(restore_bg)
1001
1002 window.ungrab_state()
1003 window.grab_state(self._handle_select_transition_target)
1004 self._select.select_state(self._menu_state)
1005 pass
1006
1007 def _handle_edit_transition(self, *args):
1008 trn = self._select.selected_transition
1009
1010 cond = trn.trn_cond
1011 action = trn.action or ''
1012
1013 window = self._window
1014 window.show_transition_editor(cond, action)
1015 pass
1016
1017 def _handle_transition_apply(self, *args):
1018 trn = self._select.selected_transition
1019 window = self._window
1020 domview = self._domview
1021 transition_cond = window._transition_cond
1022 transition_action = window._transition_action
1023
1024 trn_cond = trn.trn_cond
1025 trn_action = trn.action
1026 trn_state = trn.state
1027 trn_state_name = trn_state.state_name
1028
1029 new_cond = transition_cond.get_text()
1030 new_action = transition_action.get_text()
1031
1032 if new_action != trn_action:
1033 domview.set_transition_action(trn_state_name, trn_cond, new_action)
1034 pass
1035
1036 if new_cond != trn_cond:
1037 trn_state.rm_transition(trn_cond)
1038
1039 domview.chg_transition_cond(trn_state_name, trn_cond, new_cond)
1040
1041 fsm_layer = window._fsm_layer
1042 trn_state.add_transition(fsm_layer, new_cond)
1043
1044 transitions = trn_state.transitions
1045 new_trn = transitions[new_cond]
1046 window._install_transition_event_handler(new_trn)
1047 pass
1048
1049 window.hide_transition_editor()
1050 pass
1051
1052 def _handle_edit_state(self, *args):
1053 pass
1054
1055 def popup_install_handler(self):
1056 window = self._window
1057
1058 window.grab_add_transition(self._handle_add_transition)
1059 window.grab_edit_transition(self._handle_edit_transition)
1060 window.grab_edit_state(self._handle_edit_state)
1061 window.grab_transition_apply(self._handle_transition_apply)
1062 pass
845 pass 1063 pass
846 1064
847 1065
848 class _FSM_move_state_mode(object): 1066 class _FSM_move_state_mode(object):
849 __metaclass__ = data_monitor.data_monitor 1067 __metaclass__ = data_monitor.data_monitor
850 __data_monitor_prefix__ = 'on_' 1068 __data_monitor_prefix__ = 'on_'
1069
1070 _popup = None
851 1071
852 _window = None 1072 _window = None
853 _domview = None 1073 _domview = None
854 _selected_cleaner = None 1074
855 1075 _select = None
856 _selected_transition = None 1076
857 1077 def __init__(self, window, domview_ui, select_man):
858 def __init__(self, window, domview_ui):
859 super(_FSM_move_state_mode, self).__init__() 1078 super(_FSM_move_state_mode, self).__init__()
860 1079
861 self._window = window 1080 self._window = window
862 self._domview = domview_ui 1081 self._domview = domview_ui
863 self._locker = domview_ui 1082 self._locker = domview_ui
1083
1084 self._popup = _FSM_popup(window, domview_ui, select_man)
1085 self._select = select_man
864 pass 1086 pass
865 1087
866 def on_move_state_background(self, item, evtype, button, x, y): 1088 def on_move_state_background(self, item, evtype, button, x, y):
867 if self._selected_cleaner is None:
868 return
869
870 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE: 1089 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE:
871 self._deselect_state() 1090 self._select.deselect()
872 pass 1091 pass
873 pass
874
875 def _select_state(self, state):
876 self._deselect_state()
877 self._selected_cleaner = state.hide_selected
878 state.show_selected()
879 pass
880
881 def _deselect_state(self):
882 if self._selected_cleaner:
883 self._selected_cleaner()
884 pass
885 self._selected_cleaner = None
886 pass 1092 pass
887 1093
888 def _handle_move_state_state(self, state, evtype, button, x, y): 1094 def _handle_move_state_state(self, state, evtype, button, x, y):
889 window = self._window 1095 window = self._window
890 1096
908 button == 1: 1114 button == 1:
909 start_x = x 1115 start_x = x
910 start_y = y 1116 start_y = y
911 orign_state_x, orign_state_y = state.xy 1117 orign_state_x, orign_state_y = state.xy
912 1118
913 self._select_state(state) 1119 self._select.select_state(state)
914 window.grab_mouse(moving_state) 1120 window.grab_mouse(moving_state)
915 pass 1121 pass
916 1122 elif evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE and \
917 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE and \
918 button == 1: 1123 button == 1:
919 window.ungrab_mouse() 1124 window.ungrab_mouse()
1125 pass
1126 else:
1127 self._popup._handle_state_mouse_events(state, evtype, button, x, y)
920 pass 1128 pass
921 pass 1129 pass
922 1130
923 ## \brief Install event handler for control points of a transitions. 1131 ## \brief Install event handler for control points of a transitions.
924 # 1132 #
1020 pass 1228 pass
1021 1229
1022 ## \brief A transition was selected. 1230 ## \brief A transition was selected.
1023 # 1231 #
1024 def _select_transition(self, trn): 1232 def _select_transition(self, trn):
1025 def deselect(): 1233 self._select.select_transition(trn)
1026 trn.hide_control_points()
1027 del self._hint_transition # enable _hint_transition
1028 pass
1029
1030 self._hint_transition = lambda *args: None # disable _hint_transition
1031
1032 self._deselect_state()
1033 self._selected_cleaner = deselect
1034 trn.show_control_points()
1035 1234
1036 trn.stop_hint() 1235 trn.stop_hint()
1037 window = self._window 1236 window = self._window
1038 window.ungrab_bg() 1237 window.ungrab_bg()
1039 1238
1055 window.ungrab_bg() 1254 window.ungrab_bg()
1056 window.grab_bg(stop_hint) 1255 window.grab_bg(stop_hint)
1057 pass 1256 pass
1058 1257
1059 def _handle_del_transition(self, *args): 1258 def _handle_del_transition(self, *args):
1060 pass
1061
1062 def _handle_edit_transition(self, *args):
1063 trn = self._selected_transition
1064
1065 cond = trn.trn_cond
1066 action = trn.action or ''
1067
1068 window = self._window
1069 window.show_transition_editor(cond, action)
1070 pass
1071
1072 def _handle_transition_apply(self, *args):
1073 trn = self._selected_transition
1074 window = self._window
1075 domview = self._domview
1076 transition_cond = window._transition_cond
1077 transition_action = window._transition_action
1078
1079 trn_cond = trn.trn_cond
1080 trn_action = trn.action
1081 trn_state = trn.state
1082 trn_state_name = trn_state.state_name
1083
1084 new_cond = transition_cond.get_text()
1085 new_action = transition_action.get_text()
1086
1087 if new_action != trn_action:
1088 domview.set_transition_action(trn_state_name, trn_cond, new_action)
1089 pass
1090
1091 if new_cond != trn_cond:
1092 trn_state.rm_transition(trn_cond)
1093
1094 domview.chg_transition_cond(trn_state_name, trn_cond, new_cond)
1095
1096 fsm_layer = window._fsm_layer
1097 trn_state.add_transition(fsm_layer, new_cond)
1098
1099 transitions = trn_state.transitions
1100 new_trn = transitions[new_cond]
1101 window._install_transition_event_handler(new_trn)
1102 pass
1103
1104 window.hide_transition_editor()
1105 pass
1106
1107 def _show_transition_menu(self, trn):
1108 self._selected_transition = trn
1109
1110 window = self._window
1111 window.popup_transition_menu()
1112 pass 1259 pass
1113 1260
1114 ## \brief Handle mouse events when selecting no transition. 1261 ## \brief Handle mouse events when selecting no transition.
1115 # 1262 #
1116 def _handle_transitoin_mouse_events(self, trn, evtype, button, x, y): 1263 def _handle_transitoin_mouse_events(self, trn, evtype, button, x, y):
1118 button == 1: 1265 button == 1:
1119 self._select_transition(trn) 1266 self._select_transition(trn)
1120 elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_ENTER: 1267 elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_ENTER:
1121 self._hint_transition(trn) 1268 self._hint_transition(trn)
1122 pass 1269 pass
1123 elif evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS and \ 1270 else:
1124 button == 3: 1271 self._popup._handle_transition_mouse_events(trn, evtype, button,
1125 self._show_transition_menu(trn) 1272 x, y)
1126 pass 1273 pass
1127 pass 1274 pass
1128 1275
1129 def activate(self): 1276 def activate(self):
1130 window = self._window 1277 window = self._window
1133 window.ungrab_all() 1280 window.ungrab_all()
1134 1281
1135 window.grab_bg(self.on_move_state_background) 1282 window.grab_bg(self.on_move_state_background)
1136 window.grab_state(self._handle_move_state_state) 1283 window.grab_state(self._handle_move_state_state)
1137 window.grab_transition(self._handle_transitoin_mouse_events) 1284 window.grab_transition(self._handle_transitoin_mouse_events)
1138 window.grab_edit_transition(self._handle_edit_transition) 1285 #window.grab_edit_transition(self._handle_edit_transition)
1139 window.grab_transition_apply(self._handle_transition_apply) 1286 #window.grab_transition_apply(self._handle_transition_apply)
1287
1288 self._popup.popup_install_handler()
1140 pass 1289 pass
1141 1290
1142 def deactivate(self): 1291 def deactivate(self):
1143 self._deselect_state() 1292 self._select.deselect()
1144 pass 1293 pass
1145 pass 1294 pass
1146 1295
1147 1296
1148 class _FSM_add_state_mode(object): 1297 class _FSM_add_state_mode(object):
1155 _saved_x = 0 1304 _saved_x = 0
1156 _saved_y = 0 1305 _saved_y = 0
1157 1306
1158 _select_state = None 1307 _select_state = None
1159 _candidate_state = None 1308 _candidate_state = None
1160 1309
1161 def __init__(self, window, domview_ui): 1310 _select = None
1311
1312 def __init__(self, window, domview_ui, select_man):
1162 super(_FSM_add_state_mode, self).__init__() 1313 super(_FSM_add_state_mode, self).__init__()
1163 1314
1164 self._window = window 1315 self._window = window
1165 self._domview = domview_ui 1316 self._domview = domview_ui
1166 self._locker = domview_ui 1317 self._locker = domview_ui
1318
1319 self._select = select_man
1167 pass 1320 pass
1168 1321
1169 def handle_new_state(self): 1322 def handle_new_state(self):
1170 import traceback 1323 import traceback
1171 1324
1287 window._emit_leave_mode() 1440 window._emit_leave_mode()
1288 window.ungrab_all() 1441 window.ungrab_all()
1289 1442
1290 window.grab_bg(self.on_add_state_background) 1443 window.grab_bg(self.on_add_state_background)
1291 window.grab_state(self._handle_state_mouse_events) 1444 window.grab_state(self._handle_state_mouse_events)
1292 window.grab_add_transition(self._handle_add_transition)
1293 pass 1445 pass
1294 1446
1295 def deactivate(self): 1447 def deactivate(self):
1296 if self._select_state: 1448 if self._select_state:
1297 self._select_state.hide_selected() 1449 self._select_state.hide_selected()
1322 _state_mouse_event_handler = None 1474 _state_mouse_event_handler = None
1323 _add_transition_cb = None 1475 _add_transition_cb = None
1324 _edit_transition_cb = None 1476 _edit_transition_cb = None
1325 _transition_apply_cb = None 1477 _transition_apply_cb = None
1326 _transition_mouse_event_handler = None 1478 _transition_mouse_event_handler = None
1479 _edit_state_cb = None
1480
1481 _grab_stack = None
1482
1483 _select = None
1327 1484
1328 def __init__(self, domview_ui, close_cb, destroy_cb): 1485 def __init__(self, domview_ui, close_cb, destroy_cb):
1329 super(FSM_window, self).__init__() 1486 super(FSM_window, self).__init__()
1330 1487
1331 self._locker = domview_ui 1488 self._locker = domview_ui
1334 self._states = {} 1491 self._states = {}
1335 1492
1336 self._close_cb = close_cb # callback to close editor window (hide) 1493 self._close_cb = close_cb # callback to close editor window (hide)
1337 self._destroy_cb = destroy_cb # callback to destroy editor window 1494 self._destroy_cb = destroy_cb # callback to destroy editor window
1338 1495
1339 self._move_state_mode = _FSM_move_state_mode(self, domview_ui) 1496 _select = _select_manager()
1340 self._add_state_mode = _FSM_add_state_mode(self, domview_ui) 1497 self._select = _select
1498
1499 self._move_state_mode = _FSM_move_state_mode(self, domview_ui, _select)
1500 self._add_state_mode = _FSM_add_state_mode(self, domview_ui, _select)
1501
1502 self._grab_stack = []
1341 pass 1503 pass
1342 1504
1343 def _init_layers(self): 1505 def _init_layers(self):
1344 doc = self._doc() 1506 doc = self._doc()
1345 root = self._root() 1507 root = self._root()
1428 self.ungrab_mouse() 1590 self.ungrab_mouse()
1429 self.ungrab_state() 1591 self.ungrab_state()
1430 self.ungrab_add_transition() 1592 self.ungrab_add_transition()
1431 self.ungrab_transition() 1593 self.ungrab_transition()
1432 self.ungrab_edit_transition() 1594 self.ungrab_edit_transition()
1595 self.ungrab_edit_state()
1433 self.ungrab_transition_apply() 1596 self.ungrab_transition_apply()
1597 pass
1598
1599 def save_grabs(self):
1600 save = (self._bg_hdl,
1601 self._grab_mouse_hdl,
1602 self._state_mouse_event_handler,
1603 self._add_transition_cb,
1604 self._edit_transition_cb,
1605 self._transition_apply_cb,
1606 self._edit_state_cb)
1607 return save
1608
1609 def restore_grabs(self, save):
1610 self._bg_hdl, \
1611 self._grab_mouse_hdl, \
1612 self._state_mouse_event_handler, \
1613 self._add_transition_cb, \
1614 self._edit_transition_cb, \
1615 self._transition_apply_cb, \
1616 self._edit_state_cb \
1617 = save
1618 pass
1619
1620 def push_grabs(self):
1621 save = self.save_grabs()
1622 self._grab_stack.append(save)
1623 pass
1624
1625 def pop_grabs(self):
1626 save = self._grab_stack.pop()
1627 self.restore_grabs(save)
1434 pass 1628 pass
1435 1629
1436 def on_state_mouse_event(self, state, evtype, button, x, y): 1630 def on_state_mouse_event(self, state, evtype, button, x, y):
1437 if self._state_mouse_event_handler: 1631 if self._state_mouse_event_handler:
1438 self._state_mouse_event_handler(state, evtype, button, x, y) 1632 self._state_mouse_event_handler(state, evtype, button, x, y)
1501 self._transition_apply_cb = callback 1695 self._transition_apply_cb = callback
1502 pass 1696 pass
1503 1697
1504 def ungrab_transition_apply(self): 1698 def ungrab_transition_apply(self):
1505 self._transition_apply_cb = None 1699 self._transition_apply_cb = None
1700 pass
1701
1702 def grab_edit_state(self, callback):
1703 assert self._edit_state_cb is None
1704 self._edit_state_cb = callback
1705 pass
1706
1707 def ungrab_edit_state(self):
1708 self._edit_state_cb = None
1506 pass 1709 pass
1507 1710
1508 def _load_new_state(self, state_name): 1711 def _load_new_state(self, state_name):
1509 states = self._states 1712 states = self._states
1510 1713
1603 pass 1806 pass
1604 1807
1605 def on_transition_apply_clicked(self, *args): 1808 def on_transition_apply_clicked(self, *args):
1606 if self._transition_apply_cb: 1809 if self._transition_apply_cb:
1607 self._transition_apply_cb(*args) 1810 self._transition_apply_cb(*args)
1811 pass
1812 pass
1813
1814 def on_edit_state_activate(self, *args):
1815 if self._edit_state_cb:
1816 self._edit_state_cb(*args)
1608 pass 1817 pass
1609 pass 1818 pass
1610 1819
1611 def _install_test_data(self): 1820 def _install_test_data(self):
1612 self._init_layers() 1821 self._init_layers()