page.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. # -*- coding: utf-8 -*-
  2. import pygame
  3. from pygame.locals import *
  4. from sys import exit
  5. import os
  6. import sys
  7. import math
  8. from libs import easing
  9. import base64
  10. from beeprint import pp
  11. ### local import
  12. from constants import ALIGN,icon_width,icon_height,Width,Height,ICON_TYPES
  13. from util_funcs import midRect
  14. from keys_def import CurKeys
  15. from blueselector_b64 import blueselector
  16. blueselector_surf = pygame.image.frombuffer(base64.b64decode(blueselector),(92,92),"RGBA")
  17. class PageStack:
  18. def __init__(self):
  19. self.stack = list()
  20. def Push(self,data):
  21. if data not in self.stack:
  22. self.stack.append(data)
  23. return True
  24. return False
  25. def Pop(self):
  26. if len(self.stack)<=0:
  27. return None,False
  28. return self.stack.pop(),True
  29. def Length(self):
  30. return len(self.stack)
  31. class PageSelector:
  32. _PosX = 0
  33. _PosY = 0
  34. _Width = 0
  35. _Height = 0
  36. _Parent = None
  37. _Alpha = 0
  38. _OnShow = True
  39. _IconSurf = None
  40. def __init__(self):
  41. pass
  42. def Init(self,x,y,w,h,alpha):
  43. self._PosX = x
  44. self._PosY = y
  45. self._Width = w
  46. self._Height = h
  47. self._Alpha = alpha
  48. def Adjust(self,x,y,w,h,alpha):
  49. self._PosX = x
  50. self._PosY = y
  51. self._Width = w
  52. self._Height = h
  53. self._Alpha = alpha
  54. def Draw(self):
  55. canvas = self._Parent._CanvasHWND
  56. idx = self._Parent._PsIndex
  57. iconidx = self._Parent._IconIndex
  58. if idx < len(self._Parent._Icons):
  59. x = self._Parent._Icons[idx]._PosX+self._Parent._PosX
  60. y = self._Parent._Icons[iconidx]._PosY ## only use current icon's PosY
  61. rect = midRect(x,y,self._Width,self._Height,self._Parent._Width,self._Parent._Height)
  62. if rect.width <=0 or rect.height <= 0 :
  63. return
  64. #color = (244,197,66,50)
  65. #pygame.draw.rect(canvas,color,rect,1)
  66. if self._IconSurf != None:
  67. self._Parent._CanvasHWND.blit(self._IconSurf,rect)
  68. class Page(object):
  69. _PosX=0
  70. _PosY=0
  71. _Width=0
  72. _Height=0
  73. _Icons = []
  74. _Ps = None
  75. _PsIndex = 0
  76. _IconNumbers = 0
  77. _IconIndex = 0 ## shows which icon current selected, the Selector can not move here
  78. _PrevIconIndex = 0 ## for remember the Highlighted Icon ,restore it's PosY to average
  79. _Index = 0
  80. _Align = ALIGN["SLeft"]
  81. _CanvasHWND = None #
  82. _HWND = None #
  83. _OnShow = False
  84. _Name = ""
  85. _Screen = None ## Should be the Screen Class
  86. _PageIconMargin = 20
  87. _FootMsg = ["Nav.","","","","Enter"] ## Default Page Foot info
  88. _SelectedIconTopOffset=20
  89. _EasingDur = 30
  90. def __init__(self):
  91. self._Icons = []
  92. def AdjustHLeftAlign(self): ## adjust coordinator and append the PageSelector
  93. self._PosX = self._Index*self._Screen._Width
  94. self._Width = self._Screen._Width
  95. self._Height = self._Screen._Height
  96. cols = int(Width /icon_width)
  97. rows = int( (self._IconNumbers * icon_width)/Width + 1)
  98. if rows < 1:
  99. rows = 1
  100. cnt = 0
  101. for i in range(0,rows):
  102. for j in range(0,cols):
  103. start_x = icon_width/2 + j*icon_width
  104. start_y = icon_height/2 + i*icon_height
  105. icon = self._Icons[cnt]
  106. icon.Adjust(start_x,start_y,icon_width-4,icon_height-4,0)
  107. icon._Index = cnt
  108. icon._Parent = self
  109. if cnt >= (self._IconNumbers -1):
  110. break
  111. cnt+=1
  112. #icon的实际surface是要另行赋值的,这儿只创建空的icon,输入了坐标等信息
  113. ps = PageSelector()
  114. ps._IconSurf = blueselector_surf
  115. ps._Parent = self
  116. ps.Init(icon_width/2, TitleBar._BarHeight+icon_height/2,92,92,128)
  117. self._Ps = ps
  118. self._PsIndex = 0
  119. self._OnShow = False
  120. def AdjustSLeftAlign(self): ## adjust coordinator and append the PageSelector
  121. self._PosX = self._Index*self._Screen._Width
  122. self._Width = self._Screen._Width
  123. self._Height = self._Screen._Height
  124. start_x = (self._PageIconMargin + icon_width+self._PageIconMargin) /2
  125. start_y = self._Height/2
  126. for i in range(0,self._IconNumbers):
  127. it = self._Icons[i]
  128. it._Parent = self
  129. it._Index = i
  130. it.Adjust(start_x+i*self._PageIconMargin+i*icon_width,start_y,icon_width-6,icon_height-6,0)
  131. it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height))
  132. ps = PageSelector()
  133. ps._IconSurf = blueselector_surf
  134. ps._Parent = self
  135. ps.Init(start_x,start_y,92,92,128)
  136. self._Ps = ps
  137. self._PsIndex = 0
  138. self._OnShow = False
  139. if self._IconNumbers > 1:
  140. self._PsIndex = 1
  141. self._IconIndex = self._PsIndex
  142. self._PrevIconIndex = self._IconIndex
  143. self._Icons[self._IconIndex]._PosY -= self._SelectedIconTopOffset
  144. def AdjustSAutoLeftAlign(self): ## adjust coordinator and append the PageSelector
  145. self._PosX = self._Index*self._Screen._Width
  146. self._Width = self._Screen._Width
  147. self._Height = self._Screen._Height
  148. start_x = (self._PageIconMargin + icon_width+self._PageIconMargin) /2
  149. start_y = self._Height/2
  150. if self._IconNumbers == 1:
  151. start_x = self._Width / 2
  152. start_y = self._Height/2
  153. it = self._Icons[0]
  154. it._Parent = self
  155. it._Index = 0
  156. it.Adjust(start_x,start_y,icon_width-6,icon_height-6,0)
  157. it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height))
  158. elif self._IconNumbers == 2:
  159. start_x = (self._Width - self._PageIconMargin - self._IconNumbers*icon_width) / 2 + icon_width/2
  160. start_y = self._Height /2
  161. for i in range(0,self._IconNumbers):
  162. it = self._Icons[i]
  163. it._Parent = self
  164. it._Index = i
  165. it.Adjust(start_x+i*self._PageIconMargin + i*icon_width,start_y, icon_width-6, icon_height-6,0)
  166. it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height))
  167. elif self._IconNumbers > 2:
  168. for i in range(0,self._IconNumbers):
  169. it = self._Icons[i]
  170. it._Parent = self
  171. it._Index = i
  172. it.Adjust(start_x+i*self._PageIconMargin + i*icon_width,start_y,icon_width-6,icon_height-6,0)
  173. it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height))
  174. ps = PageSelector()
  175. ps._IconSurf = blueselector_surf
  176. ps._Parent = self
  177. ps.Init(start_x,start_y,92,92,128)
  178. self._Ps = ps
  179. self._PsIndex = 0
  180. self._OnShow = False
  181. if self._IconNumbers > 1:
  182. self._PsIndex = 1
  183. self._IconIndex = self._PsIndex
  184. self._PrevIconIndex = self._IconIndex
  185. self._Icons[self._IconIndex]._PosY -= self._SelectedIconTopOffset
  186. def InitLeftAlign(self):
  187. self._PosX = self._Index*Width
  188. self._Width = self._Screen._Width
  189. self._Height = self._Screen._Height
  190. cols = int(self._Width /icon_width)
  191. rows = int((self._IconNumbers * icon_width)/self._Width + 1)
  192. if rows < 1:
  193. rows = 1
  194. cnt = 0
  195. for i in range(0,rows):
  196. for j in range(0,cols):
  197. start_x = icon_width/2 + j*icon_width
  198. start_y = TitleBar._BarHeight + icon_height/2 + i*icon_height
  199. icon = IconItem()
  200. icon.Init(start_x,start_y,icon_width-4,icon_height-4,0)
  201. icon._Index = cnt
  202. icon._Parent = self
  203. self._Icons.append(icon)
  204. if cnt >= (self._IconNumbers -1):
  205. break
  206. cnt+=1
  207. #icon的实际surface是要另行赋值的,这儿只创建空的icon,输入了坐标等信息
  208. ps = PageSelector()
  209. ps._IconSurf = blueselector_surf
  210. ps._Parent = self
  211. ps.Init(icon_width/2,icon_height/2,92,92,128)
  212. self._Ps = ps
  213. self._PsIndex = 0
  214. self._OnShow = False
  215. def Adjust(self): ## default init way,
  216. self._PosX = self._Index*self._Screen._Width
  217. self._Width = self._Screen._Width ## equal to screen width
  218. self._Height = self._Screen._Height
  219. if self._Align == ALIGN["HLeft"]:
  220. start_x = (self._Width - self._IconNumbers*icon_width)/2 + icon_width/2
  221. start_y = self._Height/2
  222. for i in range(0,self._IconNumbers):
  223. it = self._Icons[i]
  224. it._Parent = self
  225. it._Index = i
  226. it.Adjust(start_x+i*icon_width,start_y,icon_width,icon_height,0)
  227. ps = PageSelector()
  228. ps._IconSurf = blueselector_surf
  229. ps._Parent = self
  230. ps.Init(start_x,start_y,92,92,128)
  231. self._Ps = ps
  232. self._PsIndex = 0
  233. self._OnShow = False
  234. elif self._Align == ALIGN["SLeft"]:
  235. start_x = (self._PageIconMargin + icon_width+self._PageIconMargin) /2
  236. start_y = self._Height/2
  237. for i in range(0,self._IconNumbers):
  238. it = self._Icons[i]
  239. it._Parent = self
  240. it._Index = i
  241. it.Adjust(start_x+i*self._PageIconMargin+i*icon_width,start_y,icon_width,icon_height,0)
  242. ps = PageSelector()
  243. ps._IconSurf = blueselector_surf
  244. ps._Parent = self
  245. ps.Init(start_x,start_y-self._SelectedIconTopOffset,92,92,128)
  246. self._Ps = ps
  247. self._PsIndex = 0
  248. self._OnShow = False
  249. if self._IconNumbers > 1:
  250. self._PsIndex = 1
  251. self._IconIndex = self._PsIndex
  252. self._PrevIconIndex = self._IconIndex
  253. self._Icons[self._IconIndex]._PosY -= self._SelectedIconTopOffset
  254. def Init(self): ## default init way,
  255. if self._Screen != None:
  256. if self._Screen._CanvasHWND != None and self._CanvasHWND == None:
  257. self._CanvasHWND = self._Screen._CanvasHWND
  258. self._PosX = self._Index*self._Screen._Width
  259. self._Width = self._Screen._Width ## equal to screen width
  260. self._Height = self._Screen._Height
  261. start_x = (self._Width - self._IconNumbers*icon_width)/2 + icon_width/2
  262. start_y = self._Height/2
  263. for i in range(0,self._IconNumbers):
  264. it = IconItem()
  265. it._Parent = self
  266. it._Index = i
  267. it.Init(start_x+i*icon_width,start_y,icon_width,icon_height,0)
  268. self._Icons.append(it)
  269. #icon的实际surface是要另行赋值的,这儿只创建空的icon,输入了坐标等信息
  270. if self._IconNumbers > 0:
  271. ps = PageSelector()
  272. ps._IconSurf = blueselector_surf
  273. ps._Parent = self
  274. ps.Init(start_x,start_y,icon_width+4,icon_height+4,128)
  275. self._Ps = ps
  276. self._PsIndex = 0
  277. self._OnShow = False
  278. def IconStepMoveData(self,icon_eh,cuts):## no Sine,No curve,plain movement steps data
  279. all_pieces = []
  280. piece = icon_eh / cuts
  281. c = 0.0
  282. prev = 0.0
  283. for i in range(0,cuts):
  284. c+=piece
  285. dx = c-prev
  286. if dx < 0.5:
  287. dx = 1.0
  288. all_pieces.append( math.ceil(dx) )
  289. if c >= icon_eh:
  290. break
  291. c = 0
  292. bidx = 0
  293. for i in all_pieces:
  294. c+=i
  295. bidx+=1
  296. if c >= icon_eh:
  297. break
  298. all_pieces = all_pieces[0:bidx]
  299. if len(all_pieces) < cuts:
  300. dff = cuts - len(all_pieces)
  301. diffa = []
  302. for i in range(0,dff):
  303. diffa.append(0)
  304. all_pieces.extend( diffa)
  305. return all_pieces
  306. def EasingData(self,start,distance):##generate easing steps data
  307. current_time = 0.0
  308. start_posx = 0.0
  309. current_posx = start_posx
  310. final_posx = float(distance)
  311. posx_init = start
  312. dur = self._EasingDur
  313. last_posx = 0.0
  314. all_last_posx = []
  315. for i in range(0,distance*dur):
  316. current_posx = easing.SineIn(current_time,start_posx,final_posx-start_posx,float(dur))
  317. if current_posx >= final_posx:
  318. current_posx = final_posx
  319. dx = current_posx - last_posx
  320. all_last_posx.append(int(dx))
  321. current_time+=1
  322. last_posx = current_posx
  323. if current_posx >= final_posx:
  324. break
  325. c = 0
  326. for i in all_last_posx:
  327. c+=i
  328. if c < final_posx -start_posx:
  329. all_last_posx.append(final_posx - c)
  330. return all_last_posx
  331. def IconSmoothUp(self,icon_ew):
  332. data = self.EasingData(self._PosX,icon_ew)
  333. data2 = self.IconStepMoveData(self._SelectedIconTopOffset,len(data))
  334. for i,v in enumerate(data):
  335. self.ClearCanvas()
  336. self._Icons[self._IconIndex]._PosY -= data2[i]
  337. if self._Icons[self._PrevIconIndex]._PosY < self._Height/2:
  338. self._Icons[self._PrevIconIndex]._PosY+=data2[i]
  339. self.DrawIcons()
  340. self._Screen.SwapAndShow()
  341. def IconsEasingLeft(self,icon_ew):
  342. data = self.EasingData(self._PosX,icon_ew)
  343. data2 = self.IconStepMoveData(self._SelectedIconTopOffset,len(data))
  344. for i,v in enumerate(data):
  345. self.ClearCanvas()
  346. self._PosX -= v
  347. self._Icons[self._IconIndex]._PosY -= data2[i]
  348. if self._Icons[self._PrevIconIndex]._PosY < self._Height/2:
  349. self._Icons[self._PrevIconIndex]._PosY+=data2[i]
  350. self.DrawIcons()
  351. self._Screen.SwapAndShow()
  352. def IconsEasingRight(self,icon_ew):
  353. data = self.EasingData(self._PosX,icon_ew)
  354. data2 = self.IconStepMoveData(self._SelectedIconTopOffset,len(data))
  355. for i,v in enumerate(data):
  356. self.ClearCanvas()
  357. self._PosX += v
  358. self._Icons[self._IconIndex]._PosY-=data2[i]
  359. if self._Icons[self._PrevIconIndex]._PosY < self._Height/2:
  360. self._Icons[self._PrevIconIndex]._PosY+=data2[i]
  361. self.DrawIcons()
  362. self._Screen.SwapAndShow()
  363. def EasingLeft(self,ew): #ew int
  364. data = self.EasingData(self._PosX,ew)
  365. for i in data:
  366. self._PosX -=i
  367. self.Draw()
  368. self._Screen.SwapAndShow()
  369. def EasingRight(self,ew):
  370. data = self.EasingData(self._PosX,ew)
  371. for i in data:
  372. self._PosX += i
  373. self.Draw()
  374. self._Screen.SwapAndShow()
  375. def MoveLeft(self,ew):
  376. self._PosX -= ew
  377. def MoveRight(self,ew):
  378. self._PosX += ew
  379. def ResetPageSelector(self):
  380. self._PsIndex = 0
  381. self._IconIndex = 0
  382. self._Ps._OnShow = True
  383. def DrawPageSelector(self):
  384. if self._Ps._OnShow == True:
  385. self._Ps.Draw()
  386. def MoveIconIndexPrev(self):
  387. self._IconIndex-=1
  388. if self._IconIndex < 0:
  389. self._IconIndex = 0
  390. self._PrevIconIndex = self._IconIndex
  391. return False
  392. self._PrevIconIndex = self._IconIndex+1
  393. return True
  394. def MoveIconIndexNext(self):
  395. #True for Moved,False is boundary
  396. self._IconIndex+=1
  397. if self._IconIndex > (self._IconNumbers - 1):
  398. self._IconIndex = self._IconNumbers -1
  399. self._PrevIconIndex = self._IconIndex
  400. return False
  401. self._PrevIconIndex = self._IconIndex-1
  402. return True
  403. def IconClick(self):
  404. if self._IconIndex > (len(self._Icons) -1):
  405. return
  406. cur_icon = self._Icons[self._IconIndex]
  407. if self._Ps._OnShow == False:
  408. return
  409. if cur_icon._MyType == ICON_TYPES["EXE"]:
  410. print("IconClick: %s %d"%(cur_icon._CmdPath,cur_icon._Index))
  411. self._Screen.RunEXE(cur_icon._CmdPath)
  412. elif cur_icon._MyType == ICON_TYPES["DIR"]:
  413. child_page = self._Icons[self._IconIndex]._LinkPage
  414. if child_page != None:
  415. child_page.Draw()
  416. self._Screen._MyPageStack.Push(self._Screen._CurrentPage)
  417. self._Screen._CurrentPage = child_page
  418. elif cur_icon._MyType == ICON_TYPES["FUNC"]:
  419. print("IconClick API: %d"%(cur_icon._Index))
  420. print("%s"% cur_icon._CmdPath)
  421. api_cb = getattr(cur_icon._CmdPath,"API",None)
  422. if api_cb != None:
  423. if callable(api_cb):
  424. cur_icon._CmdPath.API(self._Screen)
  425. elif cur_icon._MyType == ICON_TYPES["Emulator"]:
  426. cur_icon._CmdPath.API(self._Screen)
  427. def ReturnToUpLevelPage(self):
  428. pop_page,ok = self._Screen._MyPageStack.Pop()
  429. if ok == True:
  430. #self._Screen._CurrentPage.ResetPageSelector()
  431. pop_page.Draw()
  432. self._Screen._CurrentPage = pop_page
  433. on_return_back_cb = getattr(self._Screen._CurrentPage,"OnReturnBackCb",None)
  434. if on_return_back_cb != None:
  435. if callable(on_return_back_cb):
  436. self._Screen._CurrentPage.OnReturnBackCb()
  437. else:
  438. if self._Screen._MyPageStack.Length() == 0:
  439. if len(self._Screen._Pages) > 0:
  440. self._Screen._CurrentPage = self._Screen._Pages[self._Screen._PageIndex]
  441. self._Screen._CurrentPage.Draw()
  442. print("OnTopLevel ",self._Screen._PageIndex)
  443. def ClearCanvas(self):
  444. self._CanvasHWND.fill((255,255,255))
  445. def ClearIcons(self):
  446. for i in range(0,self._IconNumbers):
  447. self._Icons[i].Clear()
  448. def DrawIcons(self):
  449. for i in range(0,self._IconNumbers):
  450. self._Icons[i].Draw()
  451. def KeyDown(self,event):##default keydown,every inherited page class should have it's own KeyDown
  452. if event.key == CurKeys["A"]:
  453. if self._FootMsg[3] == "Back":
  454. self.ReturnToUpLevelPage()
  455. self._Screen.Draw()
  456. self._Screen.SwapAndShow()
  457. return
  458. if event.key == CurKeys["Menu"]:
  459. self.ReturnToUpLevelPage()
  460. self._Screen.Draw()
  461. self._Screen.SwapAndShow()
  462. if event.key == CurKeys["Right"]:
  463. if self.MoveIconIndexNext() == True:
  464. if self._IconIndex == (self._IconNumbers -1) or self._PrevIconIndex == 0:
  465. self.IconSmoothUp(icon_width+ self._PageIconMargin) # only move up selected icon,no horizontal translation
  466. else:
  467. self.IconsEasingLeft(icon_width + self._PageIconMargin)
  468. self._PsIndex = self._IconIndex
  469. self._Screen.Draw()
  470. self._Screen.SwapAndShow()
  471. if event.key == CurKeys["Left"]:
  472. if self.MoveIconIndexPrev() == True:
  473. if self._IconIndex == 0 or self._PrevIconIndex == (self._IconNumbers -1):
  474. self.IconSmoothUp(icon_width+ self._PageIconMargin)
  475. else:
  476. self.IconsEasingRight(icon_width + self._PageIconMargin)
  477. self._PsIndex = self._IconIndex
  478. self._Screen.Draw()
  479. self._Screen.SwapAndShow()
  480. if event.key == CurKeys["Enter"]:
  481. self.IconClick()
  482. self._Screen.Draw()
  483. self._Screen.SwapAndShow()
  484. def Draw(self):
  485. self.ClearCanvas()
  486. self.DrawIcons()
  487. self.DrawPageSelector()