rom_list_page.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import pygame
  4. import glob
  5. import re
  6. import shutil
  7. import gobject
  8. import validators
  9. #from pySmartDL import SmartDL
  10. import time
  11. from libs.roundrects import aa_round_rect
  12. ## local UI import
  13. from UI.constants import Width,Height,ICON_TYPES,RUNEVT
  14. from UI.page import Page,PageSelector
  15. from UI.label import Label
  16. from UI.icon_item import IconItem
  17. from UI.util_funcs import midRect,CmdClean,FileExists
  18. from UI.keys_def import CurKeys, IsKeyStartOrA, IsKeyMenuOrB
  19. from UI.multi_icon_item import MultiIconItem
  20. from UI.icon_pool import MyIconPool
  21. from UI.scroller import ListScroller
  22. from UI.skin_manager import MySkinManager
  23. from UI.lang_manager import MyLangManager
  24. from rom_so_confirm_page import RomSoConfirmPage
  25. from UI.Emulator.list_item import ListItem
  26. import config
  27. class RomStack:
  28. _Emulator = None
  29. def __init__(self):
  30. self.stack = list()
  31. def Push(self,data):
  32. if data not in self.stack:
  33. self.stack.append(data)
  34. return True
  35. return False
  36. def Pop(self):
  37. if len(self.stack)<=0:
  38. return None,False
  39. return self.stack.pop(),True
  40. def Last(self):
  41. idx = len(self.stack) -1
  42. if idx < 0:## empty stack,return root path
  43. return self._Emulator["ROM"]
  44. else:
  45. return self.stack[ idx ]
  46. def Length(self):
  47. return len(self.stack)
  48. class ListPageSelector(PageSelector):
  49. _BackgroundColor = MySkinManager.GiveColor('Front')
  50. def __init__(self):
  51. self._PosX = 0
  52. self._PosY = 0
  53. self._Height = 0
  54. self._Width = Width-12
  55. def AnimateDraw(self,x2,y2):
  56. pass
  57. def Draw(self):
  58. idx = self._Parent._PsIndex
  59. if idx > (len(self._Parent._MyList)-1):
  60. idx = len(self._Parent._MyList)
  61. if idx > 0:
  62. idx -=1
  63. elif idx == 0:##nothing in _MyList
  64. return
  65. self._Parent._PsIndex = idx ## sync PsIndex
  66. x = self._Parent._MyList[idx]._PosX+2
  67. y = self._Parent._MyList[idx]._PosY+1
  68. h = self._Parent._MyList[idx]._Height -3
  69. self._PosX = x
  70. self._PosY = y
  71. self._Height = h
  72. aa_round_rect(self._Parent._CanvasHWND,
  73. (x,y,self._Width-4,h),self._BackgroundColor,4,0,self._BackgroundColor)
  74. class RomListPage(Page):
  75. _Icons = {}
  76. _Selector=None
  77. _FootMsg = ["Nav","Del","Scan","Back","Run","AddFav"]
  78. _MyList = []
  79. _ListFont = MyLangManager.TrFont("notosanscjk15")
  80. _MyStack = None
  81. _Emulator = None
  82. _Parent = None
  83. _Scroller = None
  84. # _Scrolled = 0
  85. _BGwidth = 56
  86. _BGheight = 70
  87. _RomSoConfirmDownloadPage = None
  88. _Backspace = False
  89. def __init__(self):
  90. Page.__init__(self)
  91. self._Icons = {}
  92. self._CanvasHWND = None
  93. self._MyList = []
  94. self._MyStack = RomStack()
  95. self._Emulator = {}
  96. def GeneratePathList(self,path):
  97. if os.path.isdir(path) == False:
  98. return False
  99. files_path = glob.glob(path+"/*")
  100. ret = []
  101. for i ,v in enumerate(files_path):
  102. dirmap = {}
  103. if os.path.isdir(v) and self._Emulator["FILETYPE"] == "dir": ## like DOSBOX
  104. gameshell_bat = self._Emulator["EXT"][0]
  105. stats = os.stat(v)
  106. if stats.st_gid == self._Parent._FavGID: ##skip fav roms
  107. continue
  108. if FileExists(v+"/"+gameshell_bat):
  109. try:
  110. dirmap["gamedir"] = v.decode("utf8","ignore")
  111. except:
  112. dirmap["gamedir"] = v.decode("ascii","ignore")
  113. ret.append(dirmap)
  114. if os.path.isfile(v) and self._Emulator["FILETYPE"] == "file":
  115. stats = os.stat(v)
  116. if stats.st_gid == self._Parent._FavGID: ##skip fav roms
  117. continue
  118. bname = os.path.basename(v) ### filter extension
  119. if len(bname)> 1:
  120. is_excluded = False
  121. for exclude_ext in self._Emulator["EXCLUDE"]:## only compares filename endswith ext in EXCLUDE,splited by ,
  122. if len(exclude_ext) > 1 and bname.endswith(exclude_ext):
  123. is_excluded = True
  124. break
  125. if not is_excluded:
  126. pieces = bname.split(".")
  127. if len(pieces) > 1:
  128. if pieces[ len(pieces)-1 ].lower() in self._Emulator["EXT"]:
  129. try:
  130. dirmap["file"] = v.decode("utf8","ignore")
  131. except:
  132. dirmap["file"] = v.decode("ascii","ignore")
  133. ret.append(dirmap)
  134. # else:
  135. # print("not file or dir")
  136. return ret
  137. def SyncList(self,path):
  138. alist = self.GeneratePathList(path)
  139. if alist == False:
  140. print("listfiles return false")
  141. return
  142. self._MyList = []
  143. start_x = 0
  144. start_y = 0
  145. hasparent = 0
  146. if self._MyStack.Length() > 0:
  147. hasparent = 1
  148. li = ListItem()
  149. li._Parent = self
  150. li._PosX = start_x
  151. li._PosY = start_y
  152. li._Width = Width
  153. li._Fonts["normal"] = self._ListFont
  154. li._MyType = ICON_TYPES["DIR"]
  155. li._Parent = self
  156. li.Init("[..]")
  157. self._MyList.append(li)
  158. for i,v in enumerate(sorted(alist)):
  159. li = ListItem()
  160. li._Parent = self
  161. li._PosX = start_x
  162. li._PosY = start_y + (i+hasparent)*ListItem._Height
  163. li._Width = Width
  164. li._Fonts["normal"] = self._ListFont
  165. li._MyType = ICON_TYPES["FILE"]
  166. li._Parent = self
  167. if "directory" in v:
  168. li._MyType = ICON_TYPES["DIR"]
  169. li.Init(v["directory"])
  170. elif "file" in v:
  171. li.Init(v["file"])
  172. elif "gamedir" in v:
  173. li.Init(v["gamedir"])
  174. else:
  175. li.Init("NoName")
  176. self._MyList.append(li)
  177. def Init(self):
  178. self._PosX = self._Index * self._Screen._Width
  179. self._Width = self._Screen._Width
  180. self._Height = self._Screen._Height
  181. self._CanvasHWND = self._Screen._CanvasHWND
  182. ps = ListPageSelector()
  183. ps._Parent = self
  184. self._Ps = ps
  185. self._PsIndex = 0
  186. self.SyncList(self._Emulator["ROM"])
  187. ### will also mkdir of the ***ROM self
  188. try:
  189. os.makedirs(self._Emulator["ROM"]+"/.Trash")
  190. except OSError:
  191. if not os.path.isdir(self._Emulator["ROM"]+"/.Trash"):
  192. raise
  193. try:
  194. os.makedirs(self._Emulator["ROM"]+"/.Fav")
  195. except OSError:
  196. if not os.path.isdir(self._Emulator["ROM"]+"/.Fav"):
  197. raise
  198. self._MyStack._Emulator = self._Emulator
  199. icon_for_list = MultiIconItem()
  200. icon_for_list._ImgSurf = self._Parent._Icons["sys"]
  201. icon_for_list._MyType = ICON_TYPES["STAT"]
  202. icon_for_list._Parent = self
  203. icon_for_list.Adjust(0,0,18,18,0)
  204. self._Icons["sys"] = icon_for_list
  205. bgpng = IconItem()
  206. bgpng._ImgSurf = MyIconPool.GiveIconSurface("empty")
  207. bgpng._MyType = ICON_TYPES["STAT"]
  208. bgpng._Parent = self
  209. bgpng.AddLabel(MyLangManager.Tr("Please upload data over Wi-Fi"), MyLangManager.TrFont("Eurostile22"))
  210. bgpng.SetLableColor(MySkinManager.GiveColor('Disabled'))
  211. bgpng.Adjust(0,0,self._BGwidth,self._BGheight,0)
  212. self._Icons["bg"] = bgpng
  213. self._Scroller = ListScroller()
  214. self._Scroller._Parent = self
  215. self._Scroller._PosX = self._Width - 10
  216. self._Scroller._PosY = 2
  217. self._Scroller.Init()
  218. rom_so_confirm_page = RomSoConfirmPage()
  219. rom_so_confirm_page._Screen = self._Screen
  220. rom_so_confirm_page._Name = "Download Confirm"
  221. rom_so_confirm_page._Parent = self
  222. rom_so_confirm_page.Init()
  223. self._RomSoConfirmDownloadPage = rom_so_confirm_page
  224. # def ScrollUp(self):
  225. # if len(self._MyList) == 0:
  226. # return
  227. # tmp = self._PsIndex
  228. # self._PsIndex -= self._ScrollStep
  229. # if self._PsIndex < 0:
  230. # self._PsIndex = 0
  231. # dy = tmp - self._PsIndex
  232. # cur_li = self._MyList[self._PsIndex]
  233. # if cur_li._PosY < 0:
  234. # for i in range(0, len(self._MyList)):
  235. # self._MyList[i]._PosY += self._MyList[i]._Height*dy
  236. # self._Scrolled +=dy
  237. # def ScrollDown(self):
  238. # if len(self._MyList) == 0:
  239. # return
  240. # tmp = self._PsIndex
  241. # self._PsIndex +=self._ScrollStep
  242. # if self._PsIndex >= len(self._MyList):
  243. # self._PsIndex = len(self._MyList) -1
  244. # dy = self._PsIndex - tmp
  245. # cur_li = self._MyList[self._PsIndex]
  246. # if cur_li._PosY +cur_li._Height > self._Height:
  247. # for i in range(0,len(self._MyList)):
  248. # self._MyList[i]._PosY -= self._MyList[i]._Height*dy
  249. # self._Scrolled -= dy
  250. # def SyncScroll(self):
  251. #
  252. # if self._Scrolled == 0:
  253. # return
  254. # if self._PsIndex < len(self._MyList):
  255. # cur_li = self._MyList[self._PsIndex]
  256. # if self._Scrolled > 0:
  257. # if cur_li._PosY < 0:
  258. # for i in range(0, len(self._MyList)):
  259. # self._MyList[i]._PosY += self._Scrolled * self._MyList[i]._Height
  260. # elif self._Scrolled < 0:
  261. # if cur_li._PosY +cur_li._Height > self._Height:
  262. # for i in range(0,len(self._MyList)):
  263. # self._MyList[i]._PosY += self._Scrolled * self._MyList[i]._Height
  264. def Click(self):
  265. if len(self._MyList) == 0:
  266. return
  267. if self._PsIndex > len(self._MyList) - 1:
  268. return
  269. cur_li = self._MyList[self._PsIndex]
  270. if cur_li._MyType == ICON_TYPES["DIR"]:
  271. if cur_li._Path == "[..]":
  272. self._MyStack.Pop()
  273. self.SyncList( self._MyStack.Last() )
  274. self._PsIndex = 0
  275. else:
  276. self._MyStack.Push( self._MyList[self._PsIndex]._Path )
  277. self.SyncList( self._MyStack.Last() )
  278. self._PsIndex = 0
  279. if cur_li._MyType == ICON_TYPES["FILE"]:
  280. self._Screen._MsgBox.SetText("Launching")
  281. self._Screen._MsgBox.Draw()
  282. self._Screen.SwapAndShow()
  283. if self._Emulator["FILETYPE"] == "dir":
  284. path = cur_li._Path +"/"+self._Emulator["EXT"][0]
  285. else:
  286. path = cur_li._Path
  287. print("Run ",path)
  288. if self._Emulator["FILETYPE"] == "dir":
  289. escaped_path = CmdClean(path)
  290. else:
  291. escaped_path = CmdClean(path)
  292. custom_config = ""
  293. if self._Emulator["RETRO_CONFIG"] != "" and len(self._Emulator["RETRO_CONFIG"]) > 5:
  294. custom_config = " -c " + self._Emulator["RETRO_CONFIG"]
  295. cmdpath = " ".join( (self._Emulator["LAUNCHER"],self._Emulator["ROM_SO"], custom_config, escaped_path))
  296. if self._Emulator["ROM_SO"] =="": #empty means No needs for rom so
  297. pygame.event.post( pygame.event.Event(RUNEVT, message=cmdpath))
  298. else:
  299. if FileExists(self._Emulator["ROM_SO"].split(" ")[0]):
  300. pygame.event.post( pygame.event.Event(RUNEVT, message=cmdpath))
  301. else:
  302. self._Screen.PushPage(self._RomSoConfirmDownloadPage)
  303. self._Screen.Draw()
  304. self._Screen.SwapAndShow()
  305. return
  306. self._Screen.Draw()
  307. self._Screen.SwapAndShow()
  308. def ReScan(self):
  309. if self._MyStack.Length() == 0:
  310. self.SyncList(self._Emulator["ROM"])
  311. else:
  312. self.SyncList( self._MyStack.Last() )
  313. idx = self._PsIndex
  314. if idx > (len(self._MyList)-1):
  315. idx = len(self._MyList)
  316. if idx > 0:
  317. idx -=1
  318. elif idx == 0:##nothing in _MyList
  319. pass
  320. self._PsIndex = idx ## sync PsIndex
  321. self.SyncScroll()
  322. def OnReturnBackCb(self):
  323. self.ReScan()
  324. self._Screen.Draw()
  325. self._Screen.SwapAndShow()
  326. # def SpeedScroll(self, thekey):
  327. # if self._Screen._LastKey == thekey:
  328. # self._ScrollStep+=1
  329. # if self._ScrollStep >=5:
  330. # self._ScrollStep = 5
  331. # else:
  332. # self._ScrollStep = 1
  333. # cur_time = time.time()
  334. # if cur_time - self._Screen._LastKeyDown > 0.3:
  335. # self._ScrollStep = 1
  336. def KeyDown(self,event):
  337. if IsKeyMenuOrB(event.key):
  338. self.ReturnToUpLevelPage()
  339. self._Screen.Draw()
  340. self._Screen.SwapAndShow()
  341. if event.key == CurKeys["Right"]:
  342. # self._Screen.PushCurPage()
  343. # self._Screen.SetCurPage(self._Parent.FavListPage)
  344. if not self._Backspace:
  345. self._Screen.PushCurPage()
  346. self._Screen.SetCurPage(self._Parent.FavListPage)
  347. else:
  348. self.ScrollDown(5)
  349. self._Screen.Draw()
  350. self._Screen.SwapAndShow()
  351. if event.key == CurKeys["Left"]:
  352. if self._Backspace:
  353. self.ScrollUp(5)
  354. self._Screen.Draw()
  355. self._Screen.SwapAndShow()
  356. if event.key == CurKeys["Up"]:
  357. self.SpeedScroll(event.key)
  358. # self.ScrollUp()
  359. self.ScrollUp(self._ScrollStep)
  360. self._Screen.Draw()
  361. self._Screen.SwapAndShow()
  362. if event.key == CurKeys["Down"]:
  363. self.SpeedScroll(event.key)
  364. # self.ScrollDown()
  365. self.ScrollDown(self._ScrollStep)
  366. self._Screen.Draw()
  367. self._Screen.SwapAndShow()
  368. if IsKeyStartOrA(event.key):
  369. self.Click()
  370. if event.key == CurKeys["Select"]:
  371. if len(self._MyList) == 0:
  372. return
  373. cur_li = self._MyList[self._PsIndex]
  374. if cur_li.IsFile():
  375. # remove any dup first
  376. try:
  377. os.system("chgrp " + self._Parent._FavGname +" "+ CmdClean(cur_li._Path))
  378. except:
  379. pass
  380. self._Screen._MsgBox.SetText("AddFavList")
  381. self._Screen._MsgBox.Draw()
  382. self._Screen.SwapAndShow()
  383. pygame.time.delay(600)
  384. self.ReScan()
  385. self._Screen.Draw()
  386. self._Screen.SwapAndShow()
  387. if event.key == CurKeys["X"]: #Scan current
  388. self.ReScan()
  389. self._Screen.Draw()
  390. self._Screen.SwapAndShow()
  391. if event.key == CurKeys["Y"]: #del
  392. if len(self._MyList) == 0:
  393. return
  394. cur_li = self._MyList[self._PsIndex]
  395. if cur_li.IsFile():
  396. self._Parent.DeleteConfirmPage.SetFileName(cur_li._Path)
  397. self._Parent.DeleteConfirmPage.SetTrashDir(self._Emulator["ROM"]+"/.Trash")
  398. self._Screen.PushCurPage()
  399. self._Screen.SetCurPage(self._Parent.DeleteConfirmPage)
  400. self._Screen.Draw()
  401. self._Screen.SwapAndShow()
  402. if event.key == CurKeys["Backspace"]: # Shift + Menu
  403. self._Backspace = not self._Backspace
  404. if self._Backspace:
  405. self._Screen._MsgBox.SetText("Page Up/Down: ON")
  406. else:
  407. self._Screen._MsgBox.SetText("Page Up/Down: OFF")
  408. self._Screen._MsgBox.Draw()
  409. self._Screen.SwapAndShow()
  410. def Draw(self):
  411. self.ClearCanvas()
  412. if len(self._MyList) == 0:
  413. self._Icons["bg"].NewCoord(self._Width/2,self._Height/2)
  414. self._Icons["bg"].Draw()
  415. else:
  416. if len(self._MyList) * ListItem._Height > self._Height:
  417. self._Ps._Width = self._Width - 10
  418. self._Ps.Draw()
  419. for i in self._MyList:
  420. if i._PosY > self._Height + self._Height/2:
  421. break
  422. if i._PosY < 0:
  423. continue
  424. i.Draw()
  425. self._Scroller.UpdateSize( len(self._MyList)*ListItem._Height, self._PsIndex*ListItem._Height)
  426. self._Scroller.Draw()
  427. else:
  428. self._Ps._Width = self._Width
  429. self._Ps.Draw()
  430. for i in self._MyList:
  431. i.Draw()