main_screen.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  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 SkinManager
  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=SkinManager().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(SkinManager().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,SkinManager().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,SkinManager().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 = SkinManager()
  120. self._SkinManager.Init()
  121. self._CounterScreen = CounterScreen()
  122. self._CounterScreen._HWND = self._HWND
  123. self._CounterScreen.Init()
  124. def FartherPages(self):
  125. self._PageMax = len(self._Pages)
  126. for i in range(0,self._PageMax):
  127. self._Pages[i]._Index = i
  128. self._Pages[i]._CanvasHWND = self._CanvasHWND
  129. self._Pages[i]._IconNumbers = len(self._Pages[i]._Icons)
  130. self._Pages[i]._Screen = self
  131. self._Pages[i].Adjust()
  132. if self._Pages[i]._IconNumbers > 1:
  133. self._Pages[i]._PsIndex = 1
  134. self._Pages[i]._IconIndex = self._Pages[i]._PsIndex
  135. self._CurrentPage = self._Pages[self._PageIndex]
  136. self._CurrentPage._OnShow = True
  137. def GetMyRightSidePage(self):
  138. ret = self._PageIndex +1
  139. if ret > (self._PageMax -1):
  140. ret = self._PageMax -1
  141. return ret
  142. def PageMoveLeft(self):
  143. self._Pages[self._PageIndex]._OnShow = False
  144. if self._PageIndex < (self._PageMax - 1):
  145. my_right_side_page = self.GetMyRightSidePage()
  146. for i in range(0,self._PageMax):
  147. if i!= self._PageIndex and i != my_right_side_page:
  148. self._Pages[i].MoveLeft(Width)
  149. self._Pages[self._PageIndex].EasingLeft(Width)
  150. if self._PageIndex != my_right_side_page:
  151. self._Pages[my_right_side_page].EasingLeft(Width)
  152. self._Pages[self._PageIndex].ResetPageSelector()
  153. self._PageIndex+=1
  154. if self._PageIndex > (self._PageMax -1):
  155. self._PageIndex = (self._PageMax -1)
  156. self._Pages[self._PageIndex]._OnShow = True
  157. self._CurrentPage = self._Pages[self._PageIndex]
  158. def GetMyLeftSidePage(self):
  159. ret = self._PageIndex -1
  160. if ret < 0:
  161. ret = 0
  162. return ret
  163. def PageMoveRight(self):
  164. self._Pages[self._PageIndex]._OnShow = False
  165. if self._PageIndex > 0:
  166. my_left_side_page = self.GetMyLeftSidePage()
  167. for i in range(0,self._PageMax):
  168. if i!= self._PageIndex and i!= my_left_side_page:
  169. pass
  170. #self._Pages[i].MoveRight(Width)
  171. self._Pages[self._PageIndex].EasingRight(Width)
  172. if self._PageIndex != my_left_side_page:
  173. self._Pages[my_left_side_page].EasingRight(Width)
  174. self._Pages[self._PageIndex].ResetPageSelector()
  175. self._PageIndex-=1
  176. if self._PageIndex < 0:
  177. self._PageIndex = 0
  178. self._Pages[self._PageIndex]._OnShow = True
  179. self._CurrentPage = self._Pages[self._PageIndex]
  180. def EasingAllPageLeft(self):
  181. current_time = 0.0
  182. start_posx = 0.0
  183. current_posx = start_posx
  184. final_posx = float(Width)
  185. posx_init = 0
  186. dur = 30
  187. last_posx = 0.0
  188. all_last_posx = []
  189. if self._PageIndex >= (self._PageMax - 1):
  190. return
  191. for i in range(0,Width*dur):
  192. current_posx = easing.SineIn(current_time,start_posx,final_posx-start_posx,float(dur))
  193. if current_posx >= final_posx:
  194. current_posx = final_posx
  195. dx = current_posx - last_posx
  196. all_last_posx.append(int(dx))
  197. current_time+=1
  198. last_posx = current_posx
  199. if current_posx >= final_posx:
  200. break
  201. c = 0
  202. for i in all_last_posx:
  203. c+=i
  204. if c < final_posx - start_posx:
  205. all_last_posx.append( final_posx - c )
  206. for i in all_last_posx:
  207. self.ClearCanvas()
  208. for j in self._Pages:
  209. j._PosX -= i
  210. j.DrawIcons()
  211. j._Screen.SwapAndShow()
  212. self._Pages[self._PageIndex]._OnShow = False
  213. self._PageIndex+=1
  214. if self._PageIndex > (self._PageMax -1):
  215. self._PageIndex = (self._PageMax -1)
  216. self._Pages[self._PageIndex]._OnShow = True
  217. self._CurrentPage = self._Pages[self._PageIndex]
  218. def EasingAllPageRight(self):
  219. current_time = 0.0
  220. start_posx = 0.0
  221. current_posx = start_posx
  222. final_posx = float(Width)
  223. posx_init = 0
  224. dur = 30
  225. last_posx = 0.0
  226. all_last_posx = []
  227. if self._PageIndex <= 0:
  228. return
  229. for i in range(0,Width*dur):
  230. current_posx = easing.SineIn(current_time,start_posx,final_posx-start_posx,float(dur))
  231. if current_posx >= final_posx:
  232. current_posx = final_posx
  233. dx = current_posx - last_posx
  234. all_last_posx.append(int(dx))
  235. current_time+=1
  236. last_posx = current_posx
  237. if current_posx >= final_posx:
  238. break
  239. c = 0
  240. for i in all_last_posx:
  241. c+=i
  242. if c < final_posx - start_posx:
  243. all_last_posx.append( final_posx - c )
  244. for i in all_last_posx:
  245. self.ClearCanvas()
  246. for j in reversed(self._Pages):
  247. j._PosX += i
  248. j.DrawIcons()
  249. j._Screen.SwapAndShow()
  250. self._Pages[self._PageIndex]._OnShow = False
  251. self._PageIndex-=1
  252. if self._PageIndex < 0:
  253. self._PageIndex = 0
  254. self._Pages[self._PageIndex]._OnShow = True
  255. self._CurrentPage = self._Pages[self._PageIndex]
  256. def CurPage(self):
  257. return self._CurrentPage
  258. def PushCurPage(self):
  259. self._MyPageStack.Push(self._CurrentPage)
  260. def SetCurPage(self,page):
  261. self._CurrentPage = page
  262. on_load_cb = getattr(self._CurrentPage,"OnLoadCb",None)
  263. if on_load_cb != None:
  264. if callable( on_load_cb ):
  265. self._CurrentPage.OnLoadCb()
  266. def PushPage(self,page):
  267. self.PushCurPage()
  268. self.SetCurPage(page)
  269. def AppendPage(self,Page):
  270. self._Pages.append(Page)
  271. def ClearCanvas(self):
  272. self._CanvasHWND.fill(SkinManager().GiveColor('White'))
  273. def SwapAndShow(self):
  274. if self._Closed == True:
  275. return
  276. if self._HWND != None:
  277. self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width,self._Height))
  278. pygame.display.update()
  279. def ExtraName(self,name):
  280. ## extra name like 1_xxx to be => xxx,
  281. parts = name.split("_")
  282. if len(parts) > 1:
  283. return parts[1]
  284. elif len(parts) == 1:
  285. return parts[0]
  286. else:
  287. return name
  288. def IsExecPackage(self,dirname):
  289. files = os.listdir(dirname)
  290. bname = os.path.basename(dirname)
  291. bname = self.ExtraName(bname)
  292. for i in sorted(files):
  293. if i == bname+".sh":
  294. return True
  295. return False
  296. def IsEmulatorPackage(self,dirname):
  297. files = os.listdir(dirname)
  298. for i in sorted(files):
  299. if i.endswith(emulator_flag):
  300. return True
  301. return False
  302. def IsPythonPackage(self,dirname):
  303. files = os.listdir(dirname)
  304. for i in sorted(files):
  305. if i.endswith(python_package_flag):
  306. return True
  307. return False
  308. def ReunionPagesIcons(self): #This is for combining /home/cpi/apps/Menu and ~/launcher/Menu/GameShell
  309. for p in self._Pages:
  310. tmp = []
  311. for i,x in enumerate(p._Icons):
  312. tup = ('',0)
  313. if hasattr(x, '_FileName'):
  314. if str.find(x._FileName,"_") < 0:
  315. tup = ("98_"+x._FileName,i) # prefer to maintain PowerOFF in last position if the filename has no order labels
  316. else:
  317. tup = (x._FileName, i)
  318. else:
  319. tup = ("",i)
  320. tmp.append(tup)
  321. tmp = sorted(tmp, key=itemgetter(0))
  322. #print(tmp)
  323. new_icons = []
  324. for x in tmp:
  325. new_icons.append( p._Icons[ x[1] ] )
  326. p._Icons = new_icons
  327. def ReadTheDirIntoPages(self,_dir,pglevel,cur_page):
  328. if FileExists(_dir) == False and os.path.isdir(_dir) == False:
  329. return
  330. files = os.listdir(_dir)
  331. for i in sorted(files):
  332. if os.path.isdir(_dir+"/"+i): # TOPLEVEL only is dir
  333. if pglevel == 0:
  334. page = Page()
  335. page._Name = self.ExtraName(i)
  336. page._Icons = []
  337. self._Pages.append(page)
  338. self.ReadTheDirIntoPages(_dir+"/"+i, pglevel+1 ,self._Pages[ len(self._Pages) -1])
  339. else: ## On CurPage now
  340. i2 = self.ExtraName(i)
  341. iconitem = IconItem()
  342. iconitem._FileName = i
  343. iconitem._CmdPath = ""
  344. iconitem.AddLabel(i2,self._IconFont)
  345. if FileExists( _dir+"/"+i+"/"+i2+".png"): ### 20_Prog/Prog.png , cut 20_
  346. iconitem._ImageName = _dir+"/"+i+"/"+i2+".png"
  347. elif FileExists( SkinMap(_dir+"/"+i2+".png") ):
  348. iconitem._ImageName = SkinMap(_dir+"/"+i2+".png")
  349. else:
  350. untitled = UntitledIcon()
  351. untitled.Init()
  352. if len(i2) > 1:
  353. untitled.SetWords(i2[:2])
  354. elif len(i2) == 1:
  355. untitled.SetWords([i2[0],i2[0]])
  356. else:
  357. untitled.SetWords(["G","s"])
  358. iconitem._ImgSurf = untitled.Surface()
  359. iconitem._ImageName = ""
  360. if self.IsPythonPackage(_dir+"/"+i):
  361. iconitem._MyType = ICON_TYPES["FUNC"]
  362. sys.path.append(_dir)
  363. iconitem._CmdPath = __import__(i)
  364. init_cb = getattr(iconitem._CmdPath,"Init",None)
  365. if init_cb != None:
  366. if callable(init_cb):
  367. iconitem._CmdPath.Init(self)
  368. cur_page._Icons.append(iconitem)
  369. elif self.IsEmulatorPackage(_dir+"/"+i):
  370. obj = {}
  371. obj["ROM"] = ""
  372. obj["ROM_SO"] =""
  373. obj["EXT"] = []
  374. obj["EXCLUDE"] = []
  375. obj["FILETYPE"] = "file"
  376. obj["LAUNCHER"] = ""
  377. obj["TITLE"] = "Game"
  378. obj["SO_URL"] = ""
  379. obj["RETRO_CONFIG"] = "" ##
  380. try:
  381. f = open(_dir+"/"+i+"/"+emulator_flag)
  382. except IOError:
  383. print("action config open failed")
  384. return
  385. else:
  386. with f:
  387. content = f.readlines()
  388. content = [x.strip() for x in content]
  389. for c in content:
  390. pis = c.split("=")
  391. if len(pis) > 1:
  392. if "EXT" in pis[0]:
  393. obj[pis[0]] = pis[1].split(",")
  394. elif "EXCLUDE" in pis[0]:
  395. obj[pis[0]] = pis[1].split(",")
  396. else:
  397. obj[pis[0]] = pis[1]
  398. if FileExists(_dir+"/"+i+"/retroarch-local.cfg"):
  399. obj["RETRO_CONFIG"] = CmdClean(os.path.abspath( _dir+"/"+i+"/retroarch-local.cfg" ))
  400. print("a local retroarch cfg:", obj["RETRO_CONFIG"])
  401. em = MyEmulator()
  402. em._Emulator = obj
  403. em.Init(self)
  404. iconitem._CmdPath = em
  405. iconitem._MyType = ICON_TYPES["Emulator"]
  406. cur_page._Icons.append(iconitem)
  407. elif self.IsExecPackage(_dir+"/"+i):
  408. iconitem._MyType = ICON_TYPES["EXE"]
  409. iconitem._CmdPath = os.path.realpath(_dir+"/"+i+"/"+i2+".sh")
  410. MakeExecutable(iconitem._CmdPath)
  411. cur_page._Icons.append(iconitem)
  412. else:
  413. iconitem._MyType = ICON_TYPES["DIR"]
  414. iconitem._LinkPage = Page()
  415. iconitem._LinkPage._Name = i2
  416. cur_page._Icons.append(iconitem)
  417. self.ReadTheDirIntoPages(_dir+"/"+i,pglevel+1,iconitem._LinkPage)
  418. elif os.path.isfile(_dir+"/"+i) and pglevel > 0:
  419. if i.lower().endswith(icon_ext):
  420. i2 = self.ExtraName(i)
  421. #cmd = ReadTheFileContent(_dir+"/"+i)
  422. iconitem = IconItem()
  423. iconitem._FileName = i
  424. iconitem._CmdPath = os.path.realpath(_dir+"/"+i)
  425. MakeExecutable(iconitem._CmdPath)
  426. iconitem._MyType = ICON_TYPES["EXE"]
  427. if FileExists( SkinMap( _dir+"/"+ReplaceSuffix(i2,"png"))):
  428. iconitem._ImageName = SkinMap(_dir+"/"+ReplaceSuffix(i2,"png"))
  429. else:
  430. untitled = UntitledIcon()
  431. untitled.Init()
  432. if len(i2) > 1:
  433. untitled.SetWords(i2[:2])
  434. elif len(i2) == 1:
  435. untitled.SetWords([i2[0],i2[0]])
  436. else:
  437. untitled.SetWords(["G","s"])
  438. iconitem._ImgSurf = untitled.Surface()
  439. iconitem._ImageName = ""
  440. iconitem.AddLabel(i2.split(".")[0],self._IconFont)
  441. iconitem._LinkPage = None
  442. cur_page._Icons.append(iconitem)
  443. def RunEXE(self,cmdpath):
  444. self.DrawRun()
  445. self.SwapAndShow()
  446. pygame.time.delay(1000)
  447. cmdpath = cmdpath.strip()
  448. cmdpath = CmdClean(cmdpath)
  449. pygame.event.post( pygame.event.Event(RUNEVT, message=cmdpath))
  450. def OnExitCb(self,event):
  451. ## leave rest to Pages
  452. on_exit_cb = getattr(self._CurrentPage,"OnExitCb",None)
  453. if on_exit_cb != None:
  454. if callable( on_exit_cb ):
  455. self._CurrentPage.OnExitCb(event)
  456. return
  457. def KeyDown(self,event):
  458. """
  459. if event.key == pygame.K_PAGEUP:
  460. self.EasingAllPageLeft()
  461. #self.SwapAndShow()
  462. if event.key == pygame.K_PAGEDOWN:
  463. self.EasingAllPageRight()
  464. #self.SwapAndShow()
  465. """
  466. if event.key == pygame.K_t:
  467. self.DrawRun()
  468. self.SwapAndShow()
  469. """
  470. if event.key == CurKeys["Space"]:
  471. self._CounterScreen.Draw()
  472. self._CounterScreen.SwapAndShow()
  473. self._CounterScreen.StartCounter()
  474. """
  475. ## leave rest to Pages
  476. current_page_key_down_cb = getattr(self._CurrentPage,"KeyDown",None)
  477. if current_page_key_down_cb != None:
  478. if callable( current_page_key_down_cb ):
  479. self._CurrentPage.KeyDown(event)
  480. def DrawRun(self):
  481. self._MsgBox.SetText("Launching....")
  482. self._MsgBox.Draw()
  483. def Draw(self):
  484. if self._Closed == True:
  485. return
  486. self._CurrentPage.Draw()
  487. #if self._HWND != None:
  488. # self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width,self._Height))
  489. if self._TitleBar != None:
  490. self._TitleBar.Draw(self._CurrentPage._Name)
  491. if self._FootBar != None:
  492. if hasattr(self._CurrentPage,"_FootMsg"):
  493. self._FootBar.SetLabelTexts(self._CurrentPage._FootMsg)
  494. self._FootBar.Draw()