main_screen.py 21 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. from operator import itemgetter
  8. from libs import easing
  9. from datetime import datetime
  10. from beeprint import pp
  11. ## local package import
  12. from constants import ICON_TYPES,icon_ext,icon_width,icon_height,RUNEVT
  13. from icon_item import IconItem
  14. from page import Page,PageStack
  15. from title_bar import TitleBar
  16. from foot_bar import FootBar
  17. from constants import Width,Height,bg_color
  18. from util_funcs import midRect,FileExists,ReplaceSuffix,ReadTheFileContent,CmdClean,MakeExecutable,SkinMap
  19. from fonts import fonts
  20. from keys_def import CurKeys
  21. from label import Label
  22. from untitled_icon import UntitledIcon
  23. from Emulator import MyEmulator
  24. from skin_manager import MySkinManager
  25. from counter_screen import CounterScreen
  26. class MessageBox(Label):
  27. _Parent = None
  28. def __init__(self):
  29. pass
  30. def Init(self,text,font_obj,color=MySkinManager.GiveColor('Text')):
  31. self._Color = color
  32. self._FontObj = font_obj
  33. self._Text = text
  34. self._Width = 0
  35. self._Height = 0
  36. self._CanvasHWND = pygame.Surface( ( int(self._Parent._Width),int(self._Parent._Height)))
  37. self._HWND = self._Parent._CanvasHWND
  38. def SetText(self,text):
  39. self._Text = text
  40. def PreDraw(self):
  41. self._Width = 0
  42. self._Height = 0
  43. self._CanvasHWND.fill(MySkinManager.GiveColor('White'))
  44. words = self._Text.split(' ')
  45. space = self._FontObj.size(' ')[0]
  46. max_width = self._Parent._Width-40
  47. x ,y = (0,0)
  48. row_total_width = 0
  49. lines = 0
  50. for word in words:
  51. word_surface = self._FontObj.render(word, True, self._Color)
  52. word_width = word_surface.get_width()
  53. word_height = word_surface.get_height()
  54. row_total_width += word_width
  55. if lines == 0:
  56. lines += word_height
  57. if row_total_width+space >= max_width:
  58. x = 0 # Reset the x.
  59. y += word_height # Start on new row.
  60. row_total_width = word_width
  61. lines += word_height
  62. self._CanvasHWND.blit(word_surface, (x, y))
  63. if len(words) == 1: # single line
  64. x += word_width
  65. else:
  66. x += word_width + space
  67. if x > self._Width:
  68. self._Width = x
  69. if lines >= (self._Parent._Height - 40):
  70. break
  71. self._Height = lines
  72. def DrawWith(self, x_,y_, withborder):
  73. self.PreDraw()
  74. x_ = x_ - self._Width/2
  75. y_ = y_ - self._Height/2
  76. padding = 5
  77. pygame.draw.rect(self._HWND,MySkinManager.GiveColor('White'),(x_-padding,y_-padding, self._Width+padding*2,self._Height+padding*2))
  78. if self._HWND != None:
  79. rect = pygame.Rect(x_,y_,self._Width,self._Height)
  80. self._HWND.blit(self._CanvasHWND,rect,(0,0,self._Width,self._Height))
  81. #self._HWND.blit(self._CanvasHWND,rect)
  82. if withborder == True:
  83. pygame.draw.rect(self._HWND,MySkinManager.GiveColor('Black'),(x_-padding,y_-padding, self._Width+padding*2,self._Height+padding*2),1)
  84. def Draw(self):
  85. x = (self._Parent._Width)/2
  86. y = (self._Parent._Height)/2
  87. self.DrawWith(x,y,True)
  88. python_package_flag = "__init__.py"
  89. emulator_flag = "action.config"
  90. ##Abstract object for manage Pages ,not the pygame's physic screen
  91. class MainScreen(object):
  92. _Pages = []
  93. _PageMax = 0
  94. _PageIndex = 0
  95. _PosX = 0
  96. _PosY = TitleBar._BarHeight+1
  97. _Width = Width
  98. _Height = Height -FootBar._BarHeight -TitleBar._BarHeight
  99. _MyPageStack = None
  100. _CurrentPage = None # pointer to the current displaying Page Class
  101. _CanvasHWND = None
  102. _HWND = None
  103. _TitleBar = None
  104. _FootBar = None
  105. _MsgBox = None
  106. _MsgBoxFont = fonts["veramono20"]
  107. _IconFont = fonts["varela15"]
  108. _SkinManager = None
  109. _Closed = False
  110. _CounterScreen = None
  111. def __init__(self):
  112. self._Pages = []
  113. self._MyPageStack = PageStack()
  114. def Init(self):
  115. self._CanvasHWND = pygame.Surface((self._Width,self._Height))
  116. self._MsgBox= MessageBox()
  117. self._MsgBox._Parent= self
  118. self._MsgBox.Init(" ", self._MsgBoxFont)
  119. self._SkinManager = MySkinManager
  120. self._CounterScreen = CounterScreen()
  121. self._CounterScreen._HWND = self._HWND
  122. self._CounterScreen.Init()
  123. def FartherPages(self):
  124. self._PageMax = len(self._Pages)
  125. for i in range(0,self._PageMax):
  126. self._Pages[i]._Index = i
  127. self._Pages[i]._CanvasHWND = self._CanvasHWND
  128. self._Pages[i]._IconNumbers = len(self._Pages[i]._Icons)
  129. self._Pages[i]._Screen = self
  130. self._Pages[i].Adjust()
  131. if self._Pages[i]._IconNumbers > 1:
  132. self._Pages[i]._PsIndex = 1
  133. self._Pages[i]._IconIndex = self._Pages[i]._PsIndex
  134. self._CurrentPage = self._Pages[self._PageIndex]
  135. self._CurrentPage._OnShow = True
  136. def GetMyRightSidePage(self):
  137. ret = self._PageIndex +1
  138. if ret > (self._PageMax -1):
  139. ret = self._PageMax -1
  140. return ret
  141. def PageMoveLeft(self):
  142. self._Pages[self._PageIndex]._OnShow = False
  143. if self._PageIndex < (self._PageMax - 1):
  144. my_right_side_page = self.GetMyRightSidePage()
  145. for i in range(0,self._PageMax):
  146. if i!= self._PageIndex and i != my_right_side_page:
  147. self._Pages[i].MoveLeft(Width)
  148. self._Pages[self._PageIndex].EasingLeft(Width)
  149. if self._PageIndex != my_right_side_page:
  150. self._Pages[my_right_side_page].EasingLeft(Width)
  151. self._Pages[self._PageIndex].ResetPageSelector()
  152. self._PageIndex+=1
  153. if self._PageIndex > (self._PageMax -1):
  154. self._PageIndex = (self._PageMax -1)
  155. self._Pages[self._PageIndex]._OnShow = True
  156. self._CurrentPage = self._Pages[self._PageIndex]
  157. def GetMyLeftSidePage(self):
  158. ret = self._PageIndex -1
  159. if ret < 0:
  160. ret = 0
  161. return ret
  162. def PageMoveRight(self):
  163. self._Pages[self._PageIndex]._OnShow = False
  164. if self._PageIndex > 0:
  165. my_left_side_page = self.GetMyLeftSidePage()
  166. for i in range(0,self._PageMax):
  167. if i!= self._PageIndex and i!= my_left_side_page:
  168. pass
  169. #self._Pages[i].MoveRight(Width)
  170. self._Pages[self._PageIndex].EasingRight(Width)
  171. if self._PageIndex != my_left_side_page:
  172. self._Pages[my_left_side_page].EasingRight(Width)
  173. self._Pages[self._PageIndex].ResetPageSelector()
  174. self._PageIndex-=1
  175. if self._PageIndex < 0:
  176. self._PageIndex = 0
  177. self._Pages[self._PageIndex]._OnShow = True
  178. self._CurrentPage = self._Pages[self._PageIndex]
  179. def EasingAllPageLeft(self):
  180. current_time = 0.0
  181. start_posx = 0.0
  182. current_posx = start_posx
  183. final_posx = float(Width)
  184. posx_init = 0
  185. dur = 30
  186. last_posx = 0.0
  187. all_last_posx = []
  188. if self._PageIndex >= (self._PageMax - 1):
  189. return
  190. for i in range(0,Width*dur):
  191. current_posx = easing.SineIn(current_time,start_posx,final_posx-start_posx,float(dur))
  192. if current_posx >= final_posx:
  193. current_posx = final_posx
  194. dx = current_posx - last_posx
  195. all_last_posx.append(int(dx))
  196. current_time+=1
  197. last_posx = current_posx
  198. if current_posx >= final_posx:
  199. break
  200. c = 0
  201. for i in all_last_posx:
  202. c+=i
  203. if c < final_posx - start_posx:
  204. all_last_posx.append( final_posx - c )
  205. for i in all_last_posx:
  206. self.ClearCanvas()
  207. for j in self._Pages:
  208. j._PosX -= i
  209. j.DrawIcons()
  210. j._Screen.SwapAndShow()
  211. self._Pages[self._PageIndex]._OnShow = False
  212. self._PageIndex+=1
  213. if self._PageIndex > (self._PageMax -1):
  214. self._PageIndex = (self._PageMax -1)
  215. self._Pages[self._PageIndex]._OnShow = True
  216. self._CurrentPage = self._Pages[self._PageIndex]
  217. def EasingAllPageRight(self):
  218. current_time = 0.0
  219. start_posx = 0.0
  220. current_posx = start_posx
  221. final_posx = float(Width)
  222. posx_init = 0
  223. dur = 30
  224. last_posx = 0.0
  225. all_last_posx = []
  226. if self._PageIndex <= 0:
  227. return
  228. for i in range(0,Width*dur):
  229. current_posx = easing.SineIn(current_time,start_posx,final_posx-start_posx,float(dur))
  230. if current_posx >= final_posx:
  231. current_posx = final_posx
  232. dx = current_posx - last_posx
  233. all_last_posx.append(int(dx))
  234. current_time+=1
  235. last_posx = current_posx
  236. if current_posx >= final_posx:
  237. break
  238. c = 0
  239. for i in all_last_posx:
  240. c+=i
  241. if c < final_posx - start_posx:
  242. all_last_posx.append( final_posx - c )
  243. for i in all_last_posx:
  244. self.ClearCanvas()
  245. for j in reversed(self._Pages):
  246. j._PosX += i
  247. j.DrawIcons()
  248. j._Screen.SwapAndShow()
  249. self._Pages[self._PageIndex]._OnShow = False
  250. self._PageIndex-=1
  251. if self._PageIndex < 0:
  252. self._PageIndex = 0
  253. self._Pages[self._PageIndex]._OnShow = True
  254. self._CurrentPage = self._Pages[self._PageIndex]
  255. def CurPage(self):
  256. return self._CurrentPage
  257. def PushCurPage(self):
  258. self._MyPageStack.Push(self._CurrentPage)
  259. def SetCurPage(self,page):
  260. self._CurrentPage = page
  261. on_load_cb = getattr(self._CurrentPage,"OnLoadCb",None)
  262. if on_load_cb != None:
  263. if callable( on_load_cb ):
  264. self._CurrentPage.OnLoadCb()
  265. def PushPage(self,page):
  266. self.PushCurPage()
  267. self.SetCurPage(page)
  268. def AppendPage(self,Page):
  269. self._Pages.append(Page)
  270. def ClearCanvas(self):
  271. self._CanvasHWND.fill(self._SkinManager.GiveColor('White'))
  272. def SwapAndShow(self):
  273. if self._Closed == True:
  274. return
  275. if self._HWND != None:
  276. self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width,self._Height))
  277. pygame.display.update()
  278. def ExtraName(self,name):
  279. ## extra name like 1_xxx to be => xxx,
  280. parts = name.split("_")
  281. if len(parts) > 1:
  282. return parts[1]
  283. elif len(parts) == 1:
  284. return parts[0]
  285. else:
  286. return name
  287. def IsExecPackage(self,dirname):
  288. files = os.listdir(dirname)
  289. bname = os.path.basename(dirname)
  290. bname = self.ExtraName(bname)
  291. for i in sorted(files):
  292. if i == bname+".sh":
  293. return True
  294. return False
  295. def IsEmulatorPackage(self,dirname):
  296. files = os.listdir(dirname)
  297. for i in sorted(files):
  298. if i.endswith(emulator_flag):
  299. return True
  300. return False
  301. def IsPythonPackage(self,dirname):
  302. files = os.listdir(dirname)
  303. for i in sorted(files):
  304. if i.endswith(python_package_flag):
  305. return True
  306. return False
  307. def ReunionPagesIcons(self): #This is for combining /home/cpi/apps/Menu and ~/launcher/Menu/GameShell
  308. for p in self._Pages:
  309. tmp = []
  310. for i,x in enumerate(p._Icons):
  311. tup = ('',0)
  312. if hasattr(x, '_FileName'):
  313. if str.find(x._FileName,"_") < 0:
  314. tup = ("98_"+x._FileName,i) # prefer to maintain PowerOFF in last position if the filename has no order labels
  315. else:
  316. tup = (x._FileName, i)
  317. else:
  318. tup = ("",i)
  319. tmp.append(tup)
  320. tmp = sorted(tmp, key=itemgetter(0))
  321. #print(tmp)
  322. new_icons = []
  323. for x in tmp:
  324. new_icons.append( p._Icons[ x[1] ] )
  325. p._Icons = new_icons
  326. def ReadTheDirIntoPages(self,_dir,pglevel,cur_page):
  327. if FileExists(_dir) == False and os.path.isdir(_dir) == False:
  328. return
  329. files = os.listdir(_dir)
  330. for i in sorted(files):
  331. if os.path.isdir(_dir+"/"+i): # TOPLEVEL only is dir
  332. if pglevel == 0:
  333. page = Page()
  334. page._Name = self.ExtraName(i)
  335. page._Icons = []
  336. self._Pages.append(page)
  337. self.ReadTheDirIntoPages(_dir+"/"+i, pglevel+1 ,self._Pages[ len(self._Pages) -1])
  338. else: ## On CurPage now
  339. i2 = self.ExtraName(i)
  340. iconitem = IconItem()
  341. iconitem._FileName = i
  342. iconitem._CmdPath = ""
  343. iconitem.AddLabel(i2,self._IconFont)
  344. if FileExists( _dir+"/"+i+"/"+i2+".png"): ### 20_Prog/Prog.png , cut 20_
  345. iconitem._ImageName = _dir+"/"+i+"/"+i2+".png"
  346. elif FileExists( SkinMap(_dir+"/"+i2+".png") ):
  347. iconitem._ImageName = SkinMap(_dir+"/"+i2+".png")
  348. else:
  349. untitled = UntitledIcon()
  350. untitled.Init()
  351. if len(i2) > 1:
  352. untitled.SetWords(i2[:2])
  353. elif len(i2) == 1:
  354. untitled.SetWords([i2[0],i2[0]])
  355. else:
  356. untitled.SetWords(["G","s"])
  357. iconitem._ImgSurf = untitled.Surface()
  358. iconitem._ImageName = ""
  359. if self.IsPythonPackage(_dir+"/"+i):
  360. iconitem._MyType = ICON_TYPES["FUNC"]
  361. sys.path.append(_dir)
  362. iconitem._CmdPath = __import__(i)
  363. init_cb = getattr(iconitem._CmdPath,"Init",None)
  364. if init_cb != None:
  365. if callable(init_cb):
  366. iconitem._CmdPath.Init(self)
  367. cur_page._Icons.append(iconitem)
  368. elif self.IsEmulatorPackage(_dir+"/"+i):
  369. obj = {}
  370. obj["ROM"] = ""
  371. obj["ROM_SO"] =""
  372. obj["EXT"] = []
  373. obj["EXCLUDE"] = []
  374. obj["FILETYPE"] = "file"
  375. obj["LAUNCHER"] = ""
  376. obj["TITLE"] = "Game"
  377. obj["SO_URL"] = ""
  378. obj["RETRO_CONFIG"] = "" ##
  379. try:
  380. f = open(_dir+"/"+i+"/"+emulator_flag)
  381. except IOError:
  382. print("action config open failed")
  383. return
  384. else:
  385. with f:
  386. content = f.readlines()
  387. content = [x.strip() for x in content]
  388. for c in content:
  389. pis = c.split("=")
  390. if len(pis) > 1:
  391. if "EXT" in pis[0]:
  392. obj[pis[0]] = pis[1].split(",")
  393. elif "EXCLUDE" in pis[0]:
  394. obj[pis[0]] = pis[1].split(",")
  395. else:
  396. obj[pis[0]] = pis[1]
  397. if FileExists(_dir+"/"+i+"/retroarch-local.cfg"):
  398. obj["RETRO_CONFIG"] = CmdClean(os.path.abspath( _dir+"/"+i+"/retroarch-local.cfg" ))
  399. print("a local retroarch cfg:", obj["RETRO_CONFIG"])
  400. em = MyEmulator()
  401. em._Emulator = obj
  402. em.Init(self)
  403. iconitem._CmdPath = em
  404. iconitem._MyType = ICON_TYPES["Emulator"]
  405. cur_page._Icons.append(iconitem)
  406. elif self.IsExecPackage(_dir+"/"+i):
  407. iconitem._MyType = ICON_TYPES["EXE"]
  408. iconitem._CmdPath = os.path.realpath(_dir+"/"+i+"/"+i2+".sh")
  409. MakeExecutable(iconitem._CmdPath)
  410. cur_page._Icons.append(iconitem)
  411. else:
  412. iconitem._MyType = ICON_TYPES["DIR"]
  413. iconitem._LinkPage = Page()
  414. iconitem._LinkPage._Name = i2
  415. cur_page._Icons.append(iconitem)
  416. self.ReadTheDirIntoPages(_dir+"/"+i,pglevel+1,iconitem._LinkPage)
  417. elif os.path.isfile(_dir+"/"+i) and pglevel > 0:
  418. if i.lower().endswith(icon_ext):
  419. i2 = self.ExtraName(i)
  420. #cmd = ReadTheFileContent(_dir+"/"+i)
  421. iconitem = IconItem()
  422. iconitem._FileName = i
  423. iconitem._CmdPath = os.path.realpath(_dir+"/"+i)
  424. MakeExecutable(iconitem._CmdPath)
  425. iconitem._MyType = ICON_TYPES["EXE"]
  426. if FileExists( SkinMap( _dir+"/"+ReplaceSuffix(i2,"png"))):
  427. iconitem._ImageName = SkinMap(_dir+"/"+ReplaceSuffix(i2,"png"))
  428. else:
  429. untitled = UntitledIcon()
  430. untitled.Init()
  431. if len(i2) > 1:
  432. untitled.SetWords(i2[:2])
  433. elif len(i2) == 1:
  434. untitled.SetWords([i2[0],i2[0]])
  435. else:
  436. untitled.SetWords(["G","s"])
  437. iconitem._ImgSurf = untitled.Surface()
  438. iconitem._ImageName = ""
  439. iconitem.AddLabel(i2.split(".")[0],self._IconFont)
  440. iconitem._LinkPage = None
  441. cur_page._Icons.append(iconitem)
  442. def RunEXE(self,cmdpath):
  443. self.DrawRun()
  444. self.SwapAndShow()
  445. pygame.time.delay(1000)
  446. cmdpath = cmdpath.strip()
  447. cmdpath = CmdClean(cmdpath)
  448. pygame.event.post( pygame.event.Event(RUNEVT, message=cmdpath))
  449. def OnExitCb(self,event):
  450. ## leave rest to Pages
  451. on_exit_cb = getattr(self._CurrentPage,"OnExitCb",None)
  452. if on_exit_cb != None:
  453. if callable( on_exit_cb ):
  454. self._CurrentPage.OnExitCb(event)
  455. return
  456. def KeyDown(self,event):
  457. """
  458. if event.key == pygame.K_PAGEUP:
  459. self.EasingAllPageLeft()
  460. #self.SwapAndShow()
  461. if event.key == pygame.K_PAGEDOWN:
  462. self.EasingAllPageRight()
  463. #self.SwapAndShow()
  464. """
  465. if event.key == pygame.K_t:
  466. self.DrawRun()
  467. self.SwapAndShow()
  468. """
  469. if event.key == CurKeys["Space"]:
  470. self._CounterScreen.Draw()
  471. self._CounterScreen.SwapAndShow()
  472. self._CounterScreen.StartCounter()
  473. """
  474. ## leave rest to Pages
  475. current_page_key_down_cb = getattr(self._CurrentPage,"KeyDown",None)
  476. if current_page_key_down_cb != None:
  477. if callable( current_page_key_down_cb ):
  478. self._CurrentPage.KeyDown(event)
  479. def DrawRun(self):
  480. self._MsgBox.SetText("Launching....")
  481. self._MsgBox.Draw()
  482. def Draw(self):
  483. if self._Closed == True:
  484. return
  485. self._CurrentPage.Draw()
  486. #if self._HWND != None:
  487. # self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width,self._Height))
  488. if self._TitleBar != None:
  489. self._TitleBar.Draw(self._CurrentPage._Name)
  490. if self._FootBar != None:
  491. if hasattr(self._CurrentPage,"_FootMsg"):
  492. self._FootBar.SetLabelTexts(self._CurrentPage._FootMsg)
  493. self._FootBar.Draw()