sccd.xml 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. <?xml version="1.0" ?>
  2. <diagram author="Sam Pieters" name="Elevator Balls">
  3. <top>
  4. from sccd.runtime.libs.ui import ui
  5. import random
  6. import time
  7. CANVAS_WIDTH = 800
  8. CANVAS_HEIGHT = 550
  9. </top>
  10. <inport name="ui" />
  11. <outport name="ui" />
  12. <class name="MainApp" default="true">
  13. <relationships>
  14. <association name="elevator" class="Elevator" />
  15. </relationships>
  16. <attribute name="window_id" />
  17. <attribute name="canvas_id" />
  18. <attribute name="floor_dimensions" />
  19. <atrribute name="floor_height" />
  20. <inport name="field_ui"/>
  21. <scxml initial="creating_window">
  22. <state id="creating_window">
  23. <onentry>
  24. <raise port="ui" event="create_window">
  25. <parameter expr="CANVAS_WIDTH"/><!-- width -->
  26. <parameter expr="CANVAS_HEIGHT"/><!-- height -->
  27. <parameter expr='"Bouncing Balls Elevator"'/><!-- title -->
  28. <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
  29. </raise>
  30. </onentry>
  31. <transition event="window_created" target="../creating_canvas">
  32. <parameter name="window_id" type="int" />
  33. <script>
  34. self.window_id = window_id
  35. </script>
  36. <raise port="ui" event="bind_event">
  37. <parameter expr="window_id"/><!-- widget_id -->
  38. <parameter expr="ui.EVENTS.WINDOW_CLOSE"/><!-- tk_event -->
  39. <parameter expr="'window_close'"/><!-- sccd_event_name -->
  40. <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
  41. </raise>
  42. <raise port="ui" event="bind_event">
  43. <parameter expr="window_id"/><!-- widget_id -->
  44. <parameter expr="ui.EVENTS.KEY_PRESS"/><!-- tk_event -->
  45. <parameter expr="'key_press'"/><!-- sccd_event_name -->
  46. <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
  47. </raise>
  48. </transition>
  49. </state>
  50. <state id="creating_canvas">
  51. <onentry>
  52. <raise port="ui" event="create_canvas">
  53. <parameter expr="self.window_id"/><!-- window_id -->
  54. <parameter expr="CANVAS_WIDTH"/><!-- width -->
  55. <parameter expr="CANVAS_HEIGHT - 200"/><!-- height -->
  56. <parameter expr="{'background':'#fff'}"/><!-- style -->
  57. <parameter expr="self.inports['field_ui']"/><!-- inport for response -->
  58. </raise>
  59. </onentry>
  60. <transition event="canvas_created" target="../create_elevator">
  61. <parameter name="canvas_id" type="int"/>
  62. <script>
  63. self.canvas_id = canvas_id
  64. </script>
  65. </transition>
  66. </state>
  67. <state id="create_elevator">
  68. <transition target="../creating">
  69. <raise scope="cd" event="create_instance">
  70. <parameter expr='"elevator"' />
  71. <parameter expr='"Elevator"' />
  72. <parameter expr="self.canvas_id" />
  73. </raise>
  74. </transition>
  75. </state>
  76. <state id="creating">
  77. <transition event="instance_created" target="../waiting">
  78. <parameter name="association_name" type="string"/>
  79. <raise scope="cd" event="start_instance">
  80. <parameter expr="association_name" />
  81. </raise>
  82. <raise scope="narrow" event="set_association_name" target="association_name">
  83. <parameter expr="association_name" />
  84. <parameter expr="self.canvas_id" />
  85. <parameter expr="self.window_id" />
  86. </raise>
  87. </transition>
  88. </state>
  89. <state id="waiting">
  90. </state>
  91. </scxml>
  92. </class>
  93. <class name="Elevator">
  94. <attribute name="window_id" />
  95. <attribute name="canvas_id" />
  96. <attribute name="elevator_id" />
  97. <atrribute name="pos" />
  98. <inport name="elevator_ui"/>
  99. <relationships>
  100. <association name="balls" class="Ball" />
  101. <association name="parent" class="MainApp" min="1" max="1" />
  102. </relationships>
  103. <constructor>
  104. <parameter name="canvas_id" />
  105. <body>
  106. <![CDATA[
  107. self.canvas_id = canvas_id;
  108. self.button_ids = {
  109. 'up': None,
  110. 'down': None,
  111. 'open': None
  112. };
  113. self.open_button = None;
  114. self.is_open = False;
  115. self.dim = {'x': 80, 'y': 150};
  116. self.vel = {'x': 0, 'y': -2};
  117. self.pos = {'x': 400, 'y': 75};
  118. self.smooth = 0.6; # value between 0 and 1
  119. ]]>
  120. </body>
  121. </constructor>
  122. <scxml initial="root">
  123. <state id="root" initial="waiting">
  124. <state id="waiting">
  125. <transition event="set_association_name" target="../creating_elevator">
  126. <parameter name="association_name" type="str" />
  127. <parameter name="canvas_id" type="int" />
  128. <parameter name="window_id" type="int" />
  129. <script>
  130. self.association_name = association_name
  131. self.canvas_id = canvas_id
  132. self.window_id = window_id
  133. </script>
  134. </transition>
  135. </state>
  136. <state id="creating_elevator">
  137. <onentry>
  138. <raise port="ui" event="create_rectangle">
  139. <parameter expr="self.canvas_id" />
  140. <parameter expr="self.pos['x']"/>
  141. <parameter expr="self.pos['y']"/>
  142. <parameter expr="self.dim['x']" />
  143. <parameter expr="self.dim['y']"/>
  144. <parameter expr="{'fill':'white', 'outline': 'black'}"/><!-- style -->
  145. <parameter expr="self.inports['elevator_ui']"/><!-- inport for response -->
  146. </raise>
  147. </onentry>
  148. <transition event="rectangle_created" target="../create_elevator_controls">
  149. <parameter name="canvas_id" type="int" />
  150. <parameter name="rect_id" type="int" />
  151. <script>
  152. self.elevator_id = rect_id
  153. </script>
  154. <raise port="ui" event="bind_event">
  155. <parameter expr="canvas_id"/><!-- widget_id -->
  156. <parameter expr="ui.EVENTS.MOUSE_RIGHT_CLICK"/><!-- tk_event -->
  157. <parameter expr="'right_click'"/><!-- sccd_event_name -->
  158. <parameter expr="self.inports['elevator_ui']"/><!-- inport for response -->
  159. </raise>
  160. </transition>
  161. </state>
  162. <state id="create_elevator_controls" initial="create_up">
  163. <state id="create_up">
  164. <onentry>
  165. <raise port="ui" event="create_button">
  166. <parameter expr="self.window_id"/>
  167. <parameter expr="'START'"/>
  168. <parameter expr="self.inports['elevator_ui']"/>
  169. </raise>
  170. </onentry>
  171. <transition event="button_created" target="../create_down">
  172. <parameter name="button_id" type="int"/>
  173. <script>
  174. self.button_ids['up'] = button_id
  175. </script>
  176. </transition>
  177. </state>
  178. <state id="create_down">
  179. <onentry>
  180. <raise port="ui" event="create_button">
  181. <parameter expr="self.window_id"/>
  182. <parameter expr="'STOP'"/>
  183. <parameter expr="self.inports['elevator_ui']"/>
  184. </raise>
  185. </onentry>
  186. <transition event="button_created" target="../create_open">
  187. <parameter name="button_id" type="int"/>
  188. <script>
  189. self.button_ids['down'] = button_id
  190. </script>
  191. </transition>
  192. </state>
  193. <state id="create_open">
  194. <onentry>
  195. <raise port="ui" event="create_button">
  196. <parameter expr="self.window_id"/>
  197. <parameter expr="'OPEN'"/>
  198. <parameter expr="self.inports['elevator_ui']"/>
  199. </raise>
  200. </onentry>
  201. <transition event="button_created" target="../../running">
  202. <parameter name="button_id" type="int"/>
  203. <script>
  204. self.button_ids['open'] = button_id
  205. </script>
  206. </transition>
  207. </state>
  208. </state>
  209. <state id="running">
  210. <transition after="0.02" target=".">
  211. <script>
  212. <![CDATA[
  213. # Invert velocity when colliding with canvas border:
  214. if self.pos['y']-(self.dim['y']/2) <= 0 or self.pos['y']+(self.dim['y']/2) >= CANVAS_HEIGHT:
  215. self.vel['y'] = -self.vel['y'];
  216. ]]>
  217. </script>
  218. <raise port="ui" event="move_element">
  219. <parameter expr="self.canvas_id"/>
  220. <parameter expr="self.elevator_id"/>
  221. <parameter expr="self.vel['x']"/>
  222. <parameter expr="self.vel['y']"/>
  223. </raise>
  224. <script>
  225. self.pos['x'] += self.vel['x']
  226. self.pos['y'] += self.vel['y']
  227. </script>
  228. <raise scope="narrow" event="update_bounds" target="'balls'">
  229. <parameter expr="self.pos" />
  230. <parameter expr="self.dim" />
  231. <parameter expr="self.vel" />
  232. </raise>
  233. </transition>
  234. <transition port="elevator_ui" event="right_click" target=".">
  235. <parameter name="x" />
  236. <parameter name="y" />
  237. <parameter name="button" />
  238. <raise scope="cd" event="create_instance">
  239. <parameter expr='"balls"' />
  240. <parameter expr='"Ball"' />
  241. <parameter expr="self.canvas_id" />
  242. <parameter expr="x" />
  243. <parameter expr="y" />
  244. </raise>
  245. </transition>
  246. <transition event="instance_created" target=".">
  247. <parameter name="association_name" type="string"/>
  248. <raise scope="cd" event="start_instance">
  249. <parameter expr="association_name" />
  250. </raise>
  251. <raise scope="narrow" event="set_association_name" target="association_name">
  252. <parameter expr="association_name" />
  253. </raise>
  254. </transition>
  255. </state>
  256. </state>
  257. </scxml>
  258. </class>
  259. <class name="Ball">
  260. <attribute name="canvas_id" />
  261. <atrribute name="circle_id" />
  262. <attribute name="pos" />
  263. <inport name="ball_ui" />
  264. <relationships>
  265. <association name="parent" class="Field" min="1" max="1" />
  266. </relationships>
  267. <constructor>
  268. <parameter name="canvas_id" />
  269. <parameter name="x" />
  270. <parameter name="y" />
  271. <body>
  272. <![CDATA[
  273. self.canvas_id = canvas_id;
  274. self.r = 5.0;
  275. self.vel = {'x': random.uniform(-5.0, 5.0), 'y': random.uniform(-5.0, 5.0)};
  276. self.pos = {'x': x, 'y': y};
  277. self.smooth = 0.6; # value between 0 and 1
  278. ]]>
  279. </body>
  280. </constructor>
  281. <destructor>
  282. </destructor>
  283. <scxml initial="main_behaviour">
  284. <state id="main_behaviour" initial="initializing">
  285. <state id="initializing">
  286. <transition event="set_association_name" target="../creating_circle">
  287. <parameter name="association_name" type="str" />
  288. <script>
  289. self.association_name = association_name
  290. </script>
  291. </transition>
  292. </state>
  293. <state id="creating_circle">
  294. <onentry>
  295. <raise port="ui" event="create_circle">
  296. canvas_id, x, y, r, style, res_port
  297. <parameter expr="self.canvas_id"/><!-- canvas_id -->
  298. <parameter expr="self.pos['x']"/><!-- x -->
  299. <parameter expr="self.pos['y']"/><!-- y -->
  300. <parameter expr="self.r"/><!-- r -->
  301. <parameter expr="{'fill':'#000'}"/><!-- style -->
  302. <parameter expr="self.inports['ball_ui']"/><!-- inport for response -->
  303. </raise>
  304. </onentry>
  305. <transition event="circle_created" target="../bouncing">
  306. <parameter name="canvas_id"/>
  307. <parameter name="circle_id"/>
  308. <script>
  309. self.circle_id = circle_id
  310. </script>
  311. <raise port="ui" event="bind_canvas_event">
  312. <parameter expr="self.canvas_id"/>
  313. <parameter expr="circle_id"/>
  314. <parameter expr="ui.EVENTS.MOUSE_PRESS"/>
  315. <parameter expr="'mouse_press'"/>
  316. <parameter expr="self.inports['ball_ui']"/>
  317. </raise>
  318. <raise port="ui" event="bind_canvas_event">
  319. <parameter expr="self.canvas_id"/>
  320. <parameter expr="circle_id"/>
  321. <parameter expr="ui.EVENTS.MOUSE_MOVE"/>
  322. <parameter expr="'mouse_move'"/>
  323. <parameter expr="self.inports['ball_ui']"/>
  324. </raise>
  325. <raise port="ui" event="bind_canvas_event">
  326. <parameter expr="self.canvas_id"/>
  327. <parameter expr="circle_id"/>
  328. <parameter expr="ui.EVENTS.MOUSE_RELEASE"/>
  329. <parameter expr="'mouse_release'"/>
  330. <parameter expr="self.inports['ball_ui']"/>
  331. </raise>
  332. </transition>
  333. </state>
  334. <state id="bouncing">
  335. <transition after="0.02" target=".">
  336. <script>
  337. <![CDATA[
  338. # Check collision with the left and right borders
  339. if self.pos['x'] - self.r < self.rect_pos['x'] - (self.rect_dim['x'] / 2):
  340. self.pos['x'] = self.rect_pos['x'] - (self.rect_dim['x'] / 2) + self.r # Correct position
  341. self.vel['x'] = -self.vel['x'] + self.rect_vel['x']
  342. elif self.pos['x'] + self.r > self.rect_pos['x'] + (self.rect_dim['x'] / 2):
  343. self.pos['x'] = self.rect_pos['x'] + (self.rect_dim['x'] / 2) - self.r # Correct position
  344. self.vel['x'] = -self.vel['x'] + self.rect_vel['x']
  345. # Check collision with the top and bottom borders
  346. if self.pos['y'] - self.r < self.rect_pos['y'] - (self.rect_dim['y'] / 2):
  347. self.pos['y'] = self.rect_pos['y'] - (self.rect_dim['y'] / 2) + self.r # Correct position
  348. self.vel['y'] = -self.vel['y'] + self.rect_vel['y']
  349. elif self.pos['y'] + self.r > self.rect_pos['y'] + (self.rect_dim['y'] / 2):
  350. self.pos['y'] = self.rect_pos['y'] + (self.rect_dim['y'] / 2) - self.r # Correct position
  351. self.vel['y'] = -self.vel['y'] + self.rect_vel['y']
  352. ]]>
  353. </script>
  354. <raise port="ui" event="move_element">
  355. <parameter expr="self.canvas_id"/>
  356. <parameter expr="self.circle_id"/>
  357. <parameter expr="self.vel['x']"/>
  358. <parameter expr="self.vel['y']"/>
  359. </raise>
  360. <script>
  361. self.pos['x'] += self.vel['x']
  362. self.pos['y'] += self.vel['y']
  363. </script>
  364. </transition>
  365. <transition port="ball_ui" event="mouse_press" target="../selected" cond="button == ui.MOUSE_BUTTONS.LEFT">
  366. <parameter name="x" />
  367. <parameter name="y" />
  368. <parameter name="button" />
  369. <raise port="ui" event="set_element_color">
  370. <parameter expr="self.canvas_id"/>
  371. <parameter expr="self.circle_id"/>
  372. <parameter expr="'#ff0'"/>
  373. </raise>
  374. </transition>
  375. <transition event="update_bounds" target=".">
  376. <parameter name="pos" type="dict" />
  377. <parameter name="dim" type="dict" />
  378. <parameter name="vel" type="dict" />
  379. <script>
  380. self.rect_pos = pos
  381. self.rect_dim = dim
  382. self.rect_vel = vel
  383. </script>
  384. </transition>
  385. </state>
  386. <state id="dragging">
  387. <transition port="ball_ui" event="mouse_move" target=".">
  388. <parameter name="x" />
  389. <parameter name="y" />
  390. <parameter name="button" />
  391. <script>
  392. <![CDATA[
  393. # Always keep ball within canvas:
  394. x = min(max(0+self.r, x), CANVAS_WIDTH-self.r)
  395. y = min(max(0+self.r, y), CANVAS_HEIGHT-self.r)
  396. dx = x - self.pos['x']
  397. dy = y - self.pos['y']
  398. self.vel = {
  399. 'x': (1-self.smooth)*dx + self.smooth*self.vel['x'],
  400. 'y': (1-self.smooth)*dy + self.smooth*self.vel['y']
  401. }
  402. self.pos = {'x': x, 'y': y}
  403. ]]>
  404. </script>
  405. <raise port="ui" event="set_element_pos">
  406. <parameter expr="self.canvas_id"/>
  407. <parameter expr="self.circle_id"/>
  408. <parameter expr="x-self.r"/>
  409. <parameter expr="y-self.r"/>
  410. </raise>
  411. </transition>
  412. <transition port="ball_ui" event="mouse_release" target="../bouncing">
  413. <parameter name="x" />
  414. <parameter name="y" />
  415. <raise port="ui" event="set_element_color">
  416. <parameter expr="self.canvas_id"/>
  417. <parameter expr="self.circle_id"/>
  418. <parameter expr="'#f00'"/>
  419. </raise>
  420. </transition>
  421. </state>
  422. <state id='selected'>
  423. <transition port="ball_ui" event="mouse_press" target="../dragging" cond="button == ui.MOUSE_BUTTONS.LEFT">
  424. <parameter name="x" />
  425. <parameter name="y" />
  426. <parameter name="button" />
  427. <script>
  428. <![CDATA[
  429. self.mouse_pos = {'x':x, 'y':y};
  430. ]]>
  431. </script>
  432. </transition>
  433. <transition event="delete_self" target='../../deleted'>
  434. <raise event="delete_ball" scope="narrow" target="'parent'">
  435. <parameter expr='self.association_name' />
  436. </raise>
  437. <raise port="ui" event="destroy_element">
  438. <parameter expr="self.canvas_id" />
  439. <parameter expr="self.element_id" />
  440. </raise>
  441. </transition>
  442. </state>
  443. </state>
  444. <state id='deleted' />
  445. </scxml>
  446. </class>
  447. </diagram>