Mercurial > MadButterfly
comparison pyink/FSM_window.py @ 1492:6616530c4180
Show hint when mouse over a transition
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Mon, 02 May 2011 23:23:06 +0800 |
parents | 06c101bba830 |
children | b0e113605382 |
comparison
equal
deleted
inserted
replaced
1491:06c101bba830 | 1492:6616530c4180 |
---|---|
2 import os | 2 import os |
3 import math | 3 import math |
4 import data_monitor | 4 import data_monitor |
5 import pybInkscape | 5 import pybInkscape |
6 | 6 |
7 | |
8 class _dragger(object): | |
9 _node = None | |
10 _start_x = None | |
11 _start_y = None | |
12 _state = 0 | |
13 | |
14 def __init__(self): | |
15 pass | |
16 | |
17 def mouse_event(self, evtype, button, x, y): | |
18 raise RuntimeError, 'should not be here' | |
19 | |
20 def mouse_event_waiting(self, evtype, button, x, y): | |
21 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_PRESS and \ | |
22 button == 1: | |
23 self._start_x = x | |
24 self._start_y = y | |
25 self.mouse_event = self.mouse_event_pressed | |
26 self.start_drag() | |
27 pass | |
28 pass | |
29 | |
30 def mouse_event_pressed(self, evtype, button, x, y): | |
31 rx = x - self._start_x | |
32 ry = y - self._start_y | |
33 | |
34 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE: | |
35 self.mouse_event = self.mouse_event_waiting | |
36 self.stop_drag(rx, ry) | |
37 pass | |
38 | |
39 self.update(rx, ry) | |
40 pass | |
41 | |
42 def start(self): | |
43 self.mouse_event = self.mouse_event_waiting | |
44 pass | |
45 | |
46 def stop(self): | |
47 pass | |
48 | |
49 def connect(self, node): | |
50 self.start() | |
51 | |
52 def handler(item, evtype, button, x, y): | |
53 self.mouse_event(evtype, button, x, y) | |
54 pass | |
55 | |
56 self._node = node | |
57 hdl_id = node.spitem.connect('mouse-event', handler) | |
58 self._hdl_id = hdl_id | |
59 pass | |
60 | |
61 def disconnect(self): | |
62 self.stop() | |
63 node = self._node | |
64 hdl_id = self._hdl_id | |
65 node.disconnect(hdl_id) | |
66 pass | |
67 | |
68 def start_drag(self): | |
69 pass | |
70 | |
71 def stop_drag(self, rx, ry): | |
72 pass | |
73 | |
74 def update(self, rx, ry): | |
75 pass | |
76 pass | |
77 | |
78 | |
7 class FSM_window_base(object): | 79 class FSM_window_base(object): |
8 _add_state_button = None | 80 _add_state_button = None |
9 _move_state_button = None | 81 _move_state_button = None |
10 | 82 |
11 _state_editor = None | 83 _state_editor = None |
150 def on_del_state_activate(self, *args): | 222 def on_del_state_activate(self, *args): |
151 pass | 223 pass |
152 | 224 |
153 def on_edit_state_activate(self, *args): | 225 def on_edit_state_activate(self, *args): |
154 pass | 226 pass |
227 | |
228 def on_transition_apply_clicked(self, *args): | |
229 pass | |
230 | |
231 def on_transition_cancel_clicked(self, *args): | |
232 pass | |
155 pass | 233 pass |
234 | |
156 | 235 |
157 class FSM_transition(object): | 236 class FSM_transition(object): |
158 _doc = None | 237 _doc = None |
159 _domview = None | 238 _domview = None |
160 _fsm_layer = None | 239 _fsm_layer = None |
163 _states = None | 242 _states = None |
164 trn_cond = None | 243 trn_cond = None |
165 trn_g = None | 244 trn_g = None |
166 _arrow_node = None | 245 _arrow_node = None |
167 _path_node = None | 246 _path_node = None |
247 _control_points = None | |
168 | 248 |
169 def __init__(self, trn_cond): | 249 def __init__(self, trn_cond): |
170 self.trn_cond = trn_cond | 250 self.trn_cond = trn_cond |
171 pass | 251 pass |
172 | 252 |
269 state_name = self._state.state_name | 349 state_name = self._state.state_name |
270 trn_cond = self.trn_cond | 350 trn_cond = self.trn_cond |
271 trn = domview.get_transition(state_name, trn_cond) | 351 trn = domview.get_transition(state_name, trn_cond) |
272 return trn[1] | 352 return trn[1] |
273 | 353 |
354 @property | |
355 def state(self): | |
356 return self._state | |
357 | |
274 def draw(self, parent): | 358 def draw(self, parent): |
275 path = self.path | 359 path = self.path |
276 trn_g, arrow_node, path_node = self._draw_transition_real(parent, path) | 360 trn_g, path_node, arrow_node = self._draw_transition_real(parent, path) |
277 self.trn_g = trn_g | 361 self.trn_g = trn_g |
278 self._arrow_node = arrow_node | 362 self._arrow_node = arrow_node |
279 self._path_node = path_node | 363 self._path_node = path_node |
280 pass | 364 pass |
281 | 365 |
330 c2y = stop_v[1] * c3c2_len + c3y | 414 c2y = stop_v[1] * c3c2_len + c3y |
331 new_path = [c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y] | 415 new_path = [c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y] |
332 | 416 |
333 domview = self._domview | 417 domview = self._domview |
334 domview.set_transition_path(state_name, trn_cond, new_path) | 418 domview.set_transition_path(state_name, trn_cond, new_path) |
419 pass | |
420 | |
421 def show_control_points(self): | |
422 if not self._control_points: | |
423 doc = self._doc | |
424 | |
425 c1 = doc.createElement('svg:circle') | |
426 c1.setAttribute('r', '3') | |
427 c1.setAttribute('style', 'stroke: black; stroke-width: 1; ' | |
428 'fill: white') | |
429 l01 = doc.createElement('svg:line') | |
430 l01.setAttribute('style', 'stroke: black; stroke-width: 1; ' | |
431 'stroke-dasharray: 3 2') | |
432 | |
433 c2 = doc.createElement('svg:circle') | |
434 c2.setAttribute('r', '3') | |
435 c2.setAttribute('style', 'stroke: black; stroke-width: 1; ' | |
436 'fill: white') | |
437 l32 = doc.createElement('svg:line') | |
438 l32.setAttribute('style', 'stroke: black; stroke-width: 1; ' | |
439 'stroke-dasharray: 3 2') | |
440 | |
441 control_layer = self._control_layer | |
442 | |
443 control_layer.appendChild(c1) | |
444 control_layer.appendChild(l01) | |
445 control_layer.appendChild(c2) | |
446 control_layer.appendChild(l32) | |
447 self._control_points = (c1, l01, c2, l32) | |
448 pass | |
449 | |
450 c1, l01, c2, l32 = self._control_points | |
451 path = self.path | |
452 c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y = tuple(path) | |
453 | |
454 c1.setAttribute('cx', str(c1x)) | |
455 c1.setAttribute('cy', str(c1y)) | |
456 l01.setAttribute('x1', str(c0x)) | |
457 l01.setAttribute('y1', str(c0y)) | |
458 l01.setAttribute('x2', str(c1x)) | |
459 l01.setAttribute('y2', str(c1y)) | |
460 | |
461 c2.setAttribute('cx', str(c2x)) | |
462 c2.setAttribute('cy', str(c2y)) | |
463 l32.setAttribute('x1', str(c3x)) | |
464 l32.setAttribute('y1', str(c3y)) | |
465 l32.setAttribute('x2', str(c2x)) | |
466 l32.setAttribute('y2', str(c2y)) | |
467 pass | |
468 | |
469 def hide_control_points(self): | |
470 if not self._control_points: | |
471 return | |
472 | |
473 control_layer = self._control_layer | |
474 for node in self._control_points: | |
475 control_layer.removeChild(node) | |
476 pass | |
477 self._control_points = None | |
478 pass | |
479 | |
480 def start_hint(self): | |
481 path_node = self._path_node | |
482 arrow_node = self._arrow_node | |
483 if path_node: | |
484 path_node.setAttribute('style', | |
485 'stroke: #404040; stroke-width: 3; ' | |
486 'fill: none') | |
487 arrow_node.setAttribute('style', | |
488 'stroke: #404040; stroke-width: 2; ' | |
489 'fill: #404040') | |
490 pass | |
491 pass | |
492 | |
493 def stop_hint(self): | |
494 path_node = self._path_node | |
495 arrow_node = self._arrow_node | |
496 if path_node: | |
497 path_node.setAttribute('style', | |
498 'stroke: #000000; stroke-width: 1; ' \ | |
499 'fill: none') | |
500 arrow_node.setAttribute('style', | |
501 'stroke: #000000; stroke-width: 1; ' \ | |
502 'fill: #000000') | |
503 pass | |
335 pass | 504 pass |
336 pass | 505 pass |
337 | 506 |
338 class FSM_state(object): | 507 class FSM_state(object): |
339 _doc = None | 508 _doc = None |
595 class _FSM_move_state_mode(object): | 764 class _FSM_move_state_mode(object): |
596 __metaclass__ = data_monitor.data_monitor | 765 __metaclass__ = data_monitor.data_monitor |
597 __data_monitor_prefix__ = 'on_' | 766 __data_monitor_prefix__ = 'on_' |
598 | 767 |
599 _window = None | 768 _window = None |
600 _selected_state = None | 769 _domview = None |
770 _selected_cleaner = None | |
601 | 771 |
602 def __init__(self, window, domview_ui): | 772 def __init__(self, window, domview_ui): |
603 super(_FSM_move_state_mode, self).__init__() | 773 super(_FSM_move_state_mode, self).__init__() |
604 | 774 |
605 self._window = window | 775 self._window = window |
606 self._domview = domview_ui | 776 self._domview = domview_ui |
607 self._locker = domview_ui | 777 self._locker = domview_ui |
608 pass | 778 pass |
609 | 779 |
610 def on_move_state_background(self, item, evtype, button, x, y): | 780 def on_move_state_background(self, item, evtype, button, x, y): |
781 if self._selected_cleaner is None: | |
782 return | |
783 | |
784 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE: | |
785 self._clean_select() | |
786 pass | |
611 pass | 787 pass |
612 | 788 |
613 def _select_state(self, state): | 789 def _select_state(self, state): |
614 if self._selected_state: | 790 self._clean_select() |
615 self._selected_state.hide_selected() | 791 self._selected_cleaner = state.hide_selected |
616 pass | |
617 self._selected_state = state | |
618 state.show_selected() | 792 state.show_selected() |
619 pass | 793 pass |
620 | 794 |
621 def _clear_select(self): | 795 def _clean_select(self): |
622 if self._selected_state: | 796 if self._selected_cleaner: |
623 self._selected_state.hide_selected() | 797 self._selected_cleaner() |
624 pass | 798 pass |
625 self._selected_state = None | 799 self._selected_cleaner = None |
626 pass | 800 pass |
627 | 801 |
628 def handle_move_state_state(self, state, evtype, button, x, y): | 802 def _handle_move_state_state(self, state, evtype, button, x, y): |
629 window = self._window | 803 window = self._window |
630 | 804 |
631 def moving_state(item, evtype, button, x, y): | 805 def moving_state(item, evtype, button, x, y): |
632 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE: | 806 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE: |
633 window.ungrab_mouse() | 807 window.ungrab_mouse() |
658 button == 1: | 832 button == 1: |
659 window.ungrab_mouse() | 833 window.ungrab_mouse() |
660 pass | 834 pass |
661 pass | 835 pass |
662 | 836 |
837 def _install_transition_mouse_event_handler(self, trn): | |
838 c1, l01, c2, l32 = trn._control_points | |
839 path = trn.path | |
840 c0x, c0y, c1x, c1y, c2x, c2y, c3x, c3y = tuple(path) | |
841 | |
842 state_src = trn.state | |
843 target_name = trn.target | |
844 states = trn._states | |
845 state_target = states[target_name] | |
846 domview = self._domview | |
847 window = self._window | |
848 | |
849 def c1_update(rx, ry): | |
850 nc1x = c1x + rx | |
851 nc1y = c1y + ry | |
852 cx, cy = state_src.xy | |
853 r = state_src.r | |
854 | |
855 cv = nc1x - cx, nc1y - cy | |
856 cv_len = math.sqrt(cv[0] ** 2 + cv[1] ** 2) | |
857 nc0x = cx + cv[0] * r / cv_len | |
858 nc0y = cy + cv[1] * r / cv_len | |
859 | |
860 path = list(trn.path) | |
861 path[:4] = [nc0x, nc0y, nc1x, nc1y] | |
862 | |
863 state_name = state_src.state_name | |
864 cond = trn.trn_cond | |
865 domview.set_transition_path(state_name, cond, path) | |
866 | |
867 trn.show_control_points() | |
868 trn.update() | |
869 pass | |
870 | |
871 def c1_start(): | |
872 def relay_event(item, evtype, button, x, y): | |
873 c1_dragger.mouse_event(evtype, button, x, y) | |
874 pass | |
875 | |
876 window.ungrab_bg() | |
877 window.grab_bg(relay_event) | |
878 pass | |
879 | |
880 def c1_stop(rx, ry): | |
881 window.ungrab_bg() | |
882 window.grab_bg(self.on_move_state_background) | |
883 pass | |
884 | |
885 def c2_update(rx, ry): | |
886 nc2x = c2x + rx | |
887 nc2y = c2y + ry | |
888 cx, cy = state_target.xy | |
889 r = state_target.r | |
890 | |
891 cv = nc2x - cx, nc2y - cy | |
892 cv_len = math.sqrt(cv[0] ** 2 + cv[1] ** 2) | |
893 nc3x = cx + cv[0] * r / cv_len | |
894 nc3y = cy + cv[1] * r / cv_len | |
895 | |
896 path = list(trn.path) | |
897 path[4:] = [nc2x, nc2y, nc3x, nc3y] | |
898 | |
899 state_name = state_src.state_name | |
900 cond = trn.trn_cond | |
901 domview.set_transition_path(state_name, cond, path) | |
902 | |
903 trn.show_control_points() | |
904 trn.update() | |
905 pass | |
906 | |
907 def c2_start(): | |
908 def relay_event(item, evtype, button, x, y): | |
909 c2_dragger.mouse_event(evtype, button, x, y) | |
910 pass | |
911 | |
912 window.ungrab_bg() | |
913 window.grab_bg(relay_event) | |
914 pass | |
915 | |
916 def c2_stop(rx, ry): | |
917 window.ungrab_bg() | |
918 window.grab_bg(self.on_move_state_background) | |
919 pass | |
920 | |
921 c1_dragger = _dragger() | |
922 c1_dragger.update = c1_update | |
923 c1_dragger.start_drag = c1_start | |
924 c1_dragger.stop_drag = c1_stop | |
925 c1_dragger.connect(c1) | |
926 | |
927 c2_dragger = _dragger() | |
928 c2_dragger.update = c2_update | |
929 c2_dragger.start_drag = c2_start | |
930 c2_dragger.stop_drag = c2_stop | |
931 c2_dragger.connect(c2) | |
932 pass | |
933 | |
934 def _select_transition(self, trn): | |
935 def cleaner(): | |
936 trn.hide_control_points() | |
937 del self._hint_transition | |
938 pass | |
939 self._clean_select() | |
940 self._selected_cleaner = cleaner | |
941 trn.show_control_points() | |
942 | |
943 trn.stop_hint() | |
944 self._hint_transition = lambda *args: None | |
945 window = self._window | |
946 window.ungrab_bg() | |
947 | |
948 self._install_transition_mouse_event_handler(trn) | |
949 pass | |
950 | |
951 def _hint_transition(self, trn): | |
952 def stop_hint(*args): | |
953 trn.stop_hint() | |
954 window.ungrab_bg() | |
955 window.grab_bg(self.on_move_state_background) | |
956 pass | |
957 | |
958 trn.start_hint() | |
959 | |
960 window = self._window | |
961 window.ungrab_bg() | |
962 window.grab_bg(stop_hint) | |
963 pass | |
964 | |
965 def _handle_transitoin_mouse_events(self, trn, evtype, button, x, y): | |
966 if evtype == pybInkscape.PYSPItem.PYB_EVENT_BUTTON_RELEASE and \ | |
967 button == 1: | |
968 self._select_transition(trn) | |
969 elif evtype == pybInkscape.PYSPItem.PYB_EVENT_MOUSE_ENTER: | |
970 self._hint_transition(trn) | |
971 pass | |
972 pass | |
973 | |
663 def activate(self): | 974 def activate(self): |
664 window = self._window | 975 window = self._window |
665 window._emit_leave_mode() | 976 window._emit_leave_mode() |
666 window._clear_leave_mode_cb() | 977 window._clear_leave_mode_cb() |
667 window.ungrab_all() | 978 window.ungrab_all() |
668 | 979 |
669 window.grab_bg(self.on_move_state_background) | 980 window.grab_bg(self.on_move_state_background) |
670 window.grab_state(self.handle_move_state_state) | 981 window.grab_state(self._handle_move_state_state) |
982 window.grab_transition(self._handle_transitoin_mouse_events) | |
671 pass | 983 pass |
672 | 984 |
673 def deactivate(self): | 985 def deactivate(self): |
674 if self._selected_state: | 986 self._clean_select() |
675 self._clear_select() | |
676 pass | |
677 pass | 987 pass |
678 pass | 988 pass |
679 | 989 |
680 | 990 |
681 class _FSM_add_state_mode(object): | 991 class _FSM_add_state_mode(object): |
844 _leave_mode_cb = None | 1154 _leave_mode_cb = None |
845 _move_state_mode = None | 1155 _move_state_mode = None |
846 _add_state_mode = None | 1156 _add_state_mode = None |
847 _state_mouse_event_handler = None | 1157 _state_mouse_event_handler = None |
848 _add_transition_cb = None | 1158 _add_transition_cb = None |
1159 _transition_mouse_event_handler = None | |
849 | 1160 |
850 def __init__(self, domview_ui, close_cb, destroy_cb): | 1161 def __init__(self, domview_ui, close_cb, destroy_cb): |
851 super(FSM_window, self).__init__() | 1162 super(FSM_window, self).__init__() |
852 | 1163 |
853 self._locker = domview_ui | 1164 self._locker = domview_ui |
948 def ungrab_all(self): | 1259 def ungrab_all(self): |
949 self.ungrab_bg() | 1260 self.ungrab_bg() |
950 self.ungrab_mouse() | 1261 self.ungrab_mouse() |
951 self.ungrab_state() | 1262 self.ungrab_state() |
952 self.ungrab_add_transition() | 1263 self.ungrab_add_transition() |
1264 self.ungrab_transition() | |
953 pass | 1265 pass |
954 | 1266 |
955 def on_state_mouse_event(self, state, evtype, button, x, y): | 1267 def on_state_mouse_event(self, state, evtype, button, x, y): |
956 if self._state_mouse_event_handler: | 1268 if self._state_mouse_event_handler: |
957 self._state_mouse_event_handler(state, evtype, button, x, y) | 1269 self._state_mouse_event_handler(state, evtype, button, x, y) |
963 self.on_state_mouse_event(state, evtype, button, x, y) | 1275 self.on_state_mouse_event(state, evtype, button, x, y) |
964 pass | 1276 pass |
965 state.grab(mouse_event_handler) | 1277 state.grab(mouse_event_handler) |
966 pass | 1278 pass |
967 | 1279 |
1280 def on_transition_mouse_event(self, trn, evtype, button, x, y): | |
1281 if self._transition_mouse_event_handler: | |
1282 self._transition_mouse_event_handler(trn, evtype, button, x, y) | |
1283 pass | |
1284 pass | |
1285 | |
1286 def _install_transition_event_handler(self, trn): | |
1287 def mouse_event_handler(item, evtype, button, x, y): | |
1288 self.on_transition_mouse_event(trn, evtype, button, x, y) | |
1289 pass | |
1290 trn_g = trn.trn_g | |
1291 trn_g.spitem.connect('mouse-event', mouse_event_handler) | |
1292 pass | |
1293 | |
1294 def grab_transition(self, callback): | |
1295 assert self._transition_mouse_event_handler is None | |
1296 self._transition_mouse_event_handler = callback | |
1297 pass | |
1298 | |
1299 def ungrab_transition(self): | |
1300 self._transition_mouse_event_handler = None | |
1301 pass | |
1302 | |
968 def grab_state(self, callback): | 1303 def grab_state(self, callback): |
969 assert self._state_mouse_event_handler is None | 1304 assert self._state_mouse_event_handler is None |
970 self._state_mouse_event_handler = callback | 1305 self._state_mouse_event_handler = callback |
971 pass | 1306 pass |
972 | 1307 |
987 states = self._states | 1322 states = self._states |
988 | 1323 |
989 self._draw_state_domview(state_name) | 1324 self._draw_state_domview(state_name) |
990 state = states[state_name] | 1325 state = states[state_name] |
991 self._install_state_event_handler(state) | 1326 self._install_state_event_handler(state) |
1327 | |
1328 for trn in state.transitions.values(): | |
1329 self._install_transition_event_handler(trn) | |
1330 pass | |
992 pass | 1331 pass |
993 | 1332 |
994 ## \brief Load new state incrementally. | 1333 ## \brief Load new state incrementally. |
995 # | 1334 # |
996 def _load_new_state_incr(self, state_name): | 1335 def _load_new_state_incr(self, state_name): |