Mercurial > MadButterfly
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() |