bouncing_balls.py.xml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. <?xml version="1.0" ?>
  2. <diagram name="Bouncing_Balls" author="Simon Van Mierlo+Joeri Exelmans+Raphael Mannadiar">
  3. <description>
  4. Tkinter frame with bouncing balls in it.
  5. </description>
  6. <inport name="field_ui"/>
  7. <inport name="ball_ui"/>
  8. <inport name="ui"/>
  9. <top>
  10. from python_runtime.libs.ui import *
  11. from python_runtime.libs.utils import *
  12. </top>
  13. <class name="Button">
  14. <relationships>
  15. <association name="parent" class="Field" min="1" max="1"/>
  16. </relationships>
  17. <method name="Button">
  18. <parameter name="parent" type="Field"/>
  19. <parameter name="event_name" type="str"/>
  20. <parameter name="button_text" type="str"/>
  21. <body>
  22. <![CDATA[
  23. self.event_name = event_name
  24. button = ui.append_button(parent.field_window, event_name)
  25. ui.bind_event(button.element, ui.EVENTS.MOUSE_CLICK, self.controller, 'mouse_click')
  26. ]]>
  27. </body>
  28. </method>
  29. <scxml initial="initializing">
  30. <state id="initializing">
  31. <transition target="../running">
  32. <raise event="button_created" scope="narrow" target="'parent'">
  33. </raise>
  34. </transition>
  35. </state>
  36. <state id="running">
  37. <transition port="ui" target="." event="mouse_click" cond="button == ui.MOUSE_BUTTONS.LEFT">
  38. <parameter name="x" type="int"/>
  39. <parameter name="y" type="int"/>
  40. <parameter name="button" type="Button"/>
  41. <raise event="button_pressed" scope="narrow" target="'parent'">
  42. <parameter expr="self.event_name"/>
  43. </raise>
  44. </transition>
  45. </state>
  46. </scxml>
  47. </class>
  48. <class name="Field">
  49. <inport name="field_ui"/>
  50. <relationships>
  51. <association name="parent" class="MainApp" min="1" max="1"/>
  52. <association name="buttons" class="Button"/>
  53. <association name="balls" class="Ball"/>
  54. </relationships>
  55. <attribute name="field_window"/>
  56. <attribute name="canvas"/>
  57. <method name="Field">
  58. <body>
  59. <![CDATA[
  60. self.field_window = ui.new_window(400, 450)
  61. self.canvas = ui.append_canvas(self.field_window, 400, 400, {'background':'#eee'})
  62. ui.bind_event(self.field_window, ui.EVENTS.WINDOW_CLOSE, self.controller, 'window_close')
  63. ui.bind_event(self.field_window, ui.EVENTS.KEY_PRESS, self.controller, 'key_press')
  64. ui.bind_event(self.canvas.element, ui.EVENTS.MOUSE_RIGHT_CLICK, self.controller, 'right_click', self.inports['field_ui'])
  65. ui.bind_event(self.canvas.element, ui.EVENTS.MOUSE_MOVE, self.controller, 'mouse_move')
  66. ui.bind_event(self.canvas.element, ui.EVENTS.MOUSE_RELEASE, self.controller, 'mouse_release')
  67. ]]>
  68. </body>
  69. </method>
  70. <method name="~Field">
  71. <body>
  72. <![CDATA[
  73. ui.close_window(self.field_window)
  74. ]]>
  75. </body>
  76. </method>
  77. <scxml initial="root">
  78. <state id="root" initial="waiting">
  79. <state id="waiting">
  80. <transition target="../initializing" event="set_association_name">
  81. <parameter name="association_name" type="str"/>
  82. <script>
  83. <![CDATA[
  84. self.association_name = association_name
  85. ]]>
  86. </script>
  87. </transition>
  88. </state>
  89. <state id="packing">
  90. <transition target="../running" event="button_created">
  91. </transition>
  92. </state>
  93. <state id="deleting">
  94. <transition after="0.05" target="../deleted">
  95. <raise event="delete_field" scope="narrow" target="'parent'">
  96. <parameter expr="self.association_name"/>
  97. </raise>
  98. </transition>
  99. </state>
  100. <state id="creating">
  101. <transition target="../packing" event="instance_created">
  102. <parameter name="association_name" type="string"/>
  103. <raise event="start_instance" scope="cd">
  104. <parameter expr="association_name"/>
  105. </raise>
  106. </transition>
  107. </state>
  108. <state id="initializing">
  109. <transition target="../creating">
  110. <raise event="create_instance" scope="cd">
  111. <parameter expr="'buttons'"/>
  112. <parameter expr="'Button'"/>
  113. <parameter expr="self"/>
  114. <parameter expr="'create_new_field'"/>
  115. <parameter expr="'Spawn New Window'"/>
  116. </raise>
  117. </transition>
  118. </state>
  119. <state id="deleted">
  120. </state>
  121. <parallel id="running">
  122. <transition port="ui" target="../deleting" event="window_close" cond="window == self.field_window or window == ui.window">
  123. <parameter name="window" type="Window"/>
  124. <raise event="delete_instance" scope="cd">
  125. <parameter expr="'buttons'"/>
  126. </raise>
  127. <raise event="delete_self" scope="narrow" target="'balls'">
  128. </raise>
  129. </transition>
  130. <state id="main_behaviour" initial="running">
  131. <state id="running">
  132. <transition port="field_ui" target="../creating" event="right_click">
  133. <parameter name="x" type="int"/>
  134. <parameter name="y" type="int"/>
  135. <parameter name="button" type="Button"/>
  136. <raise event="create_instance" scope="cd">
  137. <parameter expr="'balls'"/>
  138. <parameter expr="'Ball'"/>
  139. <parameter expr="self.canvas"/>
  140. <parameter expr="x"/>
  141. <parameter expr="y"/>
  142. <parameter expr="self.field_window"/>
  143. </raise>
  144. </transition>
  145. </state>
  146. <state id="creating">
  147. <transition target="../running" event="instance_created">
  148. <parameter name="association_name" type="string"/>
  149. <raise event="set_association_name" scope="narrow" target="association_name">
  150. <parameter expr="association_name"/>
  151. </raise>
  152. <raise event="start_instance" scope="cd">
  153. <parameter expr="association_name"/>
  154. </raise>
  155. </transition>
  156. </state>
  157. </state>
  158. <state id="deleting_behaviour" initial="running">
  159. <state id="running">
  160. <transition target="." event="delete_ball">
  161. <parameter name="association_name" type="str"/>
  162. <raise event="delete_instance" scope="cd">
  163. <parameter expr="association_name"/>
  164. </raise>
  165. </transition>
  166. </state>
  167. </state>
  168. <state id="child_behaviour" initial="listening">
  169. <state id="listening">
  170. <transition target="." event="button_pressed">
  171. <parameter name="event_name" type="str"/>
  172. <raise event="button_pressed" scope="narrow" target="'parent'">
  173. <parameter expr="event_name"/>
  174. </raise>
  175. </transition>
  176. </state>
  177. </state>
  178. </parallel>
  179. </state>
  180. </scxml>
  181. </class>
  182. <class name="MainApp" default="True">
  183. <relationships>
  184. <association name="fields" class="Field"/>
  185. </relationships>
  186. <method name="MainApp">
  187. <body>
  188. <![CDATA[
  189. self.nr_of_fields = 0
  190. ui.bind_event(ui.window, ui.EVENTS.WINDOW_CLOSE, self.controller, 'window_close')
  191. ]]>
  192. </body>
  193. </method>
  194. <scxml initial="running">
  195. <state id="running" initial="root">
  196. <state id="stopped">
  197. </state>
  198. <parallel id="root">
  199. <state id="main_behaviour" initial="initializing">
  200. <state id="initializing">
  201. <transition target="../running">
  202. <raise event="create_field">
  203. </raise>
  204. </transition>
  205. </state>
  206. <state id="running">
  207. <transition target="." event="button_pressed" cond="event_name == 'create_new_field'">
  208. <parameter name="event_name" type="str"/>
  209. <raise event="create_field">
  210. </raise>
  211. </transition>
  212. </state>
  213. </state>
  214. <state id="cd_behaviour" initial="waiting">
  215. <state id="creating">
  216. <transition target="../waiting" event="instance_created">
  217. <parameter name="association_name" type="string"/>
  218. <raise event="start_instance" scope="cd">
  219. <parameter expr="association_name"/>
  220. </raise>
  221. <raise event="set_association_name" scope="narrow" target="association_name">
  222. <parameter expr="association_name"/>
  223. </raise>
  224. <script>
  225. <![CDATA[
  226. self.nr_of_fields += 1
  227. ]]>
  228. </script>
  229. </transition>
  230. </state>
  231. <state id="waiting">
  232. <transition target="../creating" event="create_field">
  233. <raise event="create_instance" scope="cd">
  234. <parameter expr="'fields'"/>
  235. </raise>
  236. </transition>
  237. <transition target="../check_nr_of_fields" event="delete_field">
  238. <parameter name="association_name" type="str"/>
  239. <raise event="delete_instance" scope="cd">
  240. <parameter expr="association_name"/>
  241. </raise>
  242. <script>
  243. <![CDATA[
  244. self.nr_of_fields -= 1
  245. ]]>
  246. </script>
  247. </transition>
  248. </state>
  249. <state id="check_nr_of_fields">
  250. <transition target="../waiting" cond="self.nr_of_fields != 0">
  251. </transition>
  252. <transition target="../../../stopped" cond="self.nr_of_fields == 0">
  253. <script>
  254. <![CDATA[
  255. ui.close_window(ui.window)
  256. ]]>
  257. </script>
  258. </transition>
  259. </state>
  260. </state>
  261. </parallel>
  262. </state>
  263. </scxml>
  264. </class>
  265. <class name="Ball">
  266. <inport name="ball_ui"/>
  267. <relationships>
  268. <association name="parent" class="Field" min="1" max="1"/>
  269. </relationships>
  270. <attribute name="field_window"/>
  271. <attribute name="canvas"/>
  272. <attribute name="element"/>
  273. <method name="Ball">
  274. <parameter name="canvas"/>
  275. <parameter name="x"/>
  276. <parameter name="y"/>
  277. <parameter name="field_window"/>
  278. <body>
  279. <![CDATA[
  280. self.canvas = canvas
  281. self.field_window = field_window
  282. self.r = 20.0
  283. self.vel = {'x':utils.random() * 2.0 - 1.0, 'y':utils.random() * 2.0 - 1.0}
  284. self.mouse_pos = {'':''}
  285. self.smooth = 0.4
  286. circle = self.canvas.add_circle(x, y, self.r, {'fill':'#000'})
  287. ui.bind_event(circle, ui.EVENTS.MOUSE_PRESS, self.controller, 'mouse_press', self.inports['ball_ui'])
  288. ui.bind_event(circle, ui.EVENTS.MOUSE_RIGHT_CLICK, self.controller, 'right_click')
  289. self.element = circle
  290. ]]>
  291. </body>
  292. </method>
  293. <method name="~Ball">
  294. <body>
  295. <![CDATA[
  296. self.canvas.remove_element(self.element)
  297. ]]>
  298. </body>
  299. </method>
  300. <scxml initial="main_behaviour">
  301. <state id="main_behaviour" initial="initializing">
  302. <transition target="../deleted" event="delete_self">
  303. <raise event="delete_ball" scope="narrow" target="'parent'">
  304. <parameter expr="self.association_name"/>
  305. </raise>
  306. </transition>
  307. <state id="dragging">
  308. <transition port="ui" target="../bouncing" event="mouse_release">
  309. <parameter name="x" type="int"/>
  310. <parameter name="y" type="int"/>
  311. <script>
  312. <![CDATA[
  313. self.element.set_color('#f00')
  314. ]]>
  315. </script>
  316. </transition>
  317. <transition port="ui" target="." event="mouse_move">
  318. <parameter name="x" type="int"/>
  319. <parameter name="y" type="int"/>
  320. <parameter name="button" type="Button"/>
  321. <script>
  322. <![CDATA[
  323. dx = x - self.mouse_pos['x']
  324. dy = y - self.mouse_pos['y']
  325. self.element.move(dx, dy)
  326. pos = self.element.get_position()
  327. if pos.x - self.r <= 0:
  328. pos.x = self.r + 1
  329. else:
  330. if pos.x + self.r >= self.canvas.width:
  331. pos.x = self.canvas.width - self.r - 1
  332. if pos.y - self.r <= 0:
  333. pos.y = self.r + 1
  334. else:
  335. if pos.y + self.r >= self.canvas.height:
  336. pos.y = self.canvas.height - self.r - 1
  337. self.element.set_position(pos.x, pos.y)
  338. self.mouse_pos = {'x':x, 'y':y}
  339. self.vel = {'x':(1 - self.smooth) * dx + self.smooth * self.vel['x'], 'y':(1 - self.smooth) * dy + self.smooth * self.vel['y']}
  340. ]]>
  341. </script>
  342. </transition>
  343. </state>
  344. <state id="selected">
  345. <transition port="ball_ui" target="../dragging" event="mouse_press" cond="button == ui.MOUSE_BUTTONS.LEFT">
  346. <parameter name="x" type="int"/>
  347. <parameter name="y" type="int"/>
  348. <parameter name="button" type="Button"/>
  349. <script>
  350. <![CDATA[
  351. self.mouse_pos = {'x':x, 'y':y}
  352. ]]>
  353. </script>
  354. </transition>
  355. <transition port="ui" target="." event="key_press" cond="key == ui.KEYCODES.DELETE and active_window == self.field_window">
  356. <parameter name="key" type="Key"/>
  357. <parameter name="active_window" type="Window"/>
  358. <raise event="delete_self" scope="local">
  359. </raise>
  360. </transition>
  361. </state>
  362. <state id="initializing">
  363. <transition target="../bouncing" event="set_association_name">
  364. <parameter name="association_name" type="str"/>
  365. <script>
  366. <![CDATA[
  367. self.association_name = association_name
  368. ]]>
  369. </script>
  370. </transition>
  371. </state>
  372. <state id="bouncing">
  373. <transition after="0.01" target=".">
  374. <script>
  375. <![CDATA[
  376. pos = self.element.get_position()
  377. if pos.x - self.r <= 0 or pos.x + self.r >= self.canvas.width:
  378. self.vel['x'] = -self.vel['x']
  379. if pos.y - self.r <= 0 or pos.y + self.r >= self.canvas.height:
  380. self.vel['y'] = -self.vel['y']
  381. self.element.move(self.vel['x'], self.vel['y'])
  382. ]]>
  383. </script>
  384. </transition>
  385. <transition port="ball_ui" target="../selected" event="mouse_press" cond="button == ui.MOUSE_BUTTONS.LEFT">
  386. <parameter name="x" type="int"/>
  387. <parameter name="y" type="int"/>
  388. <parameter name="button" type="Button"/>
  389. <script>
  390. <![CDATA[
  391. self.element.set_color('#ff0')
  392. ]]>
  393. </script>
  394. </transition>
  395. </state>
  396. </state>
  397. <state id="deleted">
  398. </state>
  399. </scxml>
  400. </class>
  401. </diagram>