PikaUI.py 5.3 KB

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