PikaUI.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import weakref
  2. ALIGN = None
  3. GPU = None
  4. def set_GPU(backend):
  5. global GPU
  6. global ALIGN
  7. GPU = backend
  8. ALIGN = GPU.ALIGN
  9. class Widget:
  10. backend = None
  11. width = 0
  12. height = 0
  13. pos = None
  14. parent = None
  15. align = None
  16. text = None
  17. isroot = False
  18. needbuild = True
  19. _label = None
  20. _child = []
  21. def __init__(self,
  22. text=None,
  23. width=100,
  24. height=100,
  25. pos=None,
  26. align=ALIGN.TOP_MID,
  27. onclick=None):
  28. self.width = width
  29. self.height = height
  30. self.pos = pos
  31. self.align = align
  32. self.text = text
  33. self.onclick = onclick
  34. def build(self):
  35. pass
  36. def _set_perent(self, parent):
  37. # use weakref to avoid circular reference
  38. self.parent = weakref.ref(parent)
  39. def update(self):
  40. if self.needbuild:
  41. built = self.build()
  42. if not built is None:
  43. self = self.add(built)
  44. self.needbuild = False
  45. if self.parent is None:
  46. print('self.parent is None')
  47. return
  48. if self.parent.backend is None:
  49. print('self.parent.backend is None')
  50. return
  51. if self.backend is None:
  52. self.backend = self._create_backend(self.parent)
  53. if not self.isroot:
  54. self._update_backend()
  55. for c in self._child:
  56. c.update()
  57. def _create_backend(self, parent: "Widget"):
  58. return GPU.widget(parent.backend)
  59. def _update_backend(self):
  60. self._update_align(self.align)
  61. self._update_attr(self.width, self.height, self.pos)
  62. self._update_text(self.text)
  63. self._update_event()
  64. def _update_align(self, align):
  65. self.backend.align(align, 0, 0)
  66. def _update_attr(self,
  67. width,
  68. height,
  69. pos):
  70. self.backend.set_width(width)
  71. self.backend.set_height(height)
  72. if not pos is None:
  73. self.backend.set_pos(pos[0], pos[1])
  74. def _update_text(self, text):
  75. if not None is text:
  76. self._label = GPU.label(self.backend)
  77. self._label.set_text(self.text)
  78. self._label.align(GPU.ALIGN.CENTER, 0, 0)
  79. def _update_event(self):
  80. if not None is self.onclick:
  81. self.backend.add_event_cb(self.onclick, GPU.EVENT.CLICKED, 0)
  82. def add(self, *child):
  83. for c in child:
  84. if type(c) == list:
  85. for cc in c:
  86. cc._set_perent(self)
  87. self._child.append(cc)
  88. else:
  89. c._set_perent(self)
  90. self._child.append(c)
  91. return self
  92. def clean(self):
  93. if self.backend is None:
  94. return
  95. if self.needbuild:
  96. return
  97. for c in self._child:
  98. c.clean()
  99. if not self.isroot:
  100. self.backend.del_()
  101. self.needbuild = True
  102. self._child = []
  103. class Container(Widget):
  104. def _create_backend(self, parent: Widget):
  105. return GPU.container(parent.backend)
  106. class Button(Widget):
  107. def _create_backend(self, parent: Widget):
  108. return GPU.btn(parent.backend)
  109. class Text(Widget):
  110. def _create_backend(self, parent: Widget):
  111. return GPU.label(parent.backend)
  112. def _update_text(self, text):
  113. self.backend.set_text(text)
  114. class Page(Widget):
  115. def __init__(self):
  116. super().__init__()
  117. self._set_perent(self)
  118. self.isroot = True
  119. self.backend = GPU.screen()
  120. class PageManager:
  121. pageThis: Page = None
  122. pageList = []
  123. pageNeedEnter = None
  124. pageNeedBack = False
  125. def enter(self, page: Page):
  126. if not self.pageNeedEnter is None:
  127. return
  128. self.pageNeedEnter = page
  129. def back(self):
  130. if self.pageNeedBack:
  131. return
  132. self.pageNeedBack = True
  133. def handle_timer(self):
  134. if not self.pageNeedEnter is None:
  135. page = self.pageNeedEnter
  136. self.clean()
  137. self.pageThis = page
  138. self.pageList.append(page)
  139. self.update()
  140. self.pageNeedEnter = None
  141. if self.pageNeedBack:
  142. if len(self.pageList) <= 1:
  143. return
  144. self.clean()
  145. _ = self.pageList.pop()
  146. self.pageThis = self.pageList[-1]
  147. self.update()
  148. self.pageNeedBack = False
  149. def update(self):
  150. if self.pageThis is None:
  151. return
  152. self.pageThis.update()
  153. def clean(self):
  154. if self.pageThis is None:
  155. return
  156. self.pageThis.clean()
  157. class _App:
  158. pageManager = PageManager()
  159. timer = None
  160. def cb_timer(self, src):
  161. self.pageManager.handle_timer()
  162. def __init__(self):
  163. self.timer = GPU.timer()
  164. self.timer.set_period(50)
  165. self.timer.set_cb(self.cb_timer)
  166. def update(self):
  167. self.pageManager.update()
  168. def show(self, page: Page):
  169. self.pageManager.enter(page)
  170. try:
  171. import PikaUI_GPU_lvgl
  172. set_GPU(PikaUI_GPU_lvgl)
  173. print('PikaUI: Using lvgl GPU')
  174. except:
  175. pass
  176. try:
  177. import PikaUI_GPU_text
  178. set_GPU(PikaUI_GPU_text)
  179. print('PikaUI: Using text GPU')
  180. except:
  181. pass
  182. app = _App()
  183. def App():
  184. return app
  185. def cleanup():
  186. app.timer._del()