__init__.py 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import pygame
  4. import platform
  5. #import commands
  6. import glob
  7. import json
  8. import gobject
  9. import sqlite3
  10. #from beeprint import pp
  11. from libs.roundrects import aa_round_rect
  12. from shutil import copyfile,rmtree
  13. ## local UI import
  14. from UI.constants import Width,Height,ICON_TYPES,RESTARTUI
  15. from UI.page import Page,PageSelector
  16. from UI.label import Label
  17. from UI.util_funcs import midRect,FileExists,ArmSystem
  18. from UI.keys_def import CurKeys, IsKeyStartOrA, IsKeyMenuOrB
  19. from UI.scroller import ListScroller
  20. from UI.icon_pool import MyIconPool
  21. from UI.icon_item import IconItem
  22. from UI.multilabel import MultiLabel
  23. from UI.skin_manager import MySkinManager
  24. from UI.lang_manager import MyLangManager
  25. from UI.info_page_list_item import InfoPageListItem
  26. from UI.info_page_selector import InfoPageSelector
  27. from UI.yes_cancel_confirm_page import YesCancelConfirmPage
  28. from UI.keyboard import Keyboard
  29. from UI.download import Download
  30. import config
  31. class RPCStack:
  32. def __init__(self):
  33. self.stack = list()
  34. def Push(self,data):
  35. if data not in self.stack:
  36. self.stack.append(data)
  37. return True
  38. return False
  39. def Pop(self):
  40. if len(self.stack)<=0:
  41. return None,False
  42. return self.stack.pop(),True
  43. def Last(self):
  44. idx = len(self.stack) -1
  45. if idx < 0:
  46. return None
  47. else:
  48. return self.stack[ idx ]
  49. def Length(self):
  50. return len(self.stack)
  51. class LoadHousePage(Page):
  52. _FootMsg = ["Nav.","","","Back","Cancel"]
  53. _DownloaderTimer = -1
  54. _Value = 0
  55. _URL = None
  56. _ListFontObj = MyLangManager.TrFont("varela18")
  57. _URLColor = MySkinManager.GiveColor('URL')
  58. _TextColor = MySkinManager.GiveColor('Text')
  59. _Caller=None
  60. _img = None
  61. _Downloader=None
  62. _DownloaderTimer=-1
  63. def __init__(self):
  64. Page.__init__(self)
  65. self._Icons = {}
  66. self._CanvasHWND = None
  67. def Init(self):
  68. self._PosX = self._Index * self._Screen._Width
  69. self._Width = self._Screen._Width
  70. self._Height = self._Screen._Height
  71. self._CanvasHWND = self._Screen._CanvasHWND
  72. self._LoadingLabel = Label()
  73. self._LoadingLabel.SetCanvasHWND(self._CanvasHWND)
  74. self._LoadingLabel.Init("Loading",self._ListFontObj)
  75. self._LoadingLabel.SetColor(self._TextColor )
  76. def OnLoadCb(self):
  77. if self._URL is None:
  78. return
  79. self._img = None
  80. self.ClearCanvas()
  81. self._Screen.Draw()
  82. self._Screen.SwapAndShow()
  83. filename = self._URL.split("/")[-1].strip()
  84. local_dir = self._URL.split("raw.githubusercontent.com")
  85. if len(local_dir) >1:
  86. menu_file = local_dir[1]
  87. local_menu_file = "%s/aria2download%s" % (os.path.expanduser('~'),menu_file )
  88. if FileExists(local_menu_file):
  89. #load json
  90. with open(local_menu_file) as json_file:
  91. try:
  92. local_menu_json = json.load(json_file)
  93. self._Caller._MyStack.Push(local_menu_json["list"])
  94. except:
  95. pass
  96. self.Leave()
  97. else:
  98. self._Downloader = Download(self._URL,"/tmp",None)
  99. self._Downloader.start()
  100. self._DownloaderTimer = gobject.timeout_add(400, self.GObjectUpdateProcessInterval)
  101. def GObjectUpdateProcessInterval(self):
  102. ret = True
  103. if self._Screen.CurPage() == self:
  104. if self._Downloader._stop == True:
  105. ret = False
  106. dst_filename = self._Downloader.get_dest()
  107. if self._Downloader.isFinished():
  108. if self._Downloader.isSuccessful():
  109. filename = self._URL.split("/")[-1].strip()
  110. local_dir = self._URL.split("raw.githubusercontent.com")
  111. menu_file = local_dir[1]
  112. local_menu_file = "%s/aria2download%s" % (os.path.expanduser('~'),menu_file )
  113. dl_file = os.path.join("/tmp",filename)
  114. if not os.path.exists(os.path.dirname(local_menu_file)):
  115. os.makedirs(os.path.dirname(local_menu_file))
  116. copyfile(dl_file, local_menu_file)
  117. with open(local_menu_file) as json_file:
  118. try:
  119. local_menu_json = json.load(json_file)
  120. self._Caller._MyStack.Push(local_menu_json["list"])
  121. except:
  122. pass
  123. ret = False
  124. self.Leave()
  125. return ret
  126. else:
  127. return False
  128. def Leave(self):
  129. if self._DownloaderTimer != -1:
  130. gobject.source_remove(self._DownloaderTimer)
  131. self._DownloaderTimer = -1
  132. if self._Downloader != None:
  133. try:
  134. self._Downloader.stop()
  135. except:
  136. print("user canceled ")
  137. self.ReturnToUpLevelPage()
  138. self._Screen.Draw()
  139. self._Screen.SwapAndShow()
  140. self._URL = None
  141. def KeyDown(self,event):
  142. if IsKeyMenuOrB(event.key):
  143. self.Leave()
  144. def Draw(self):
  145. self.ClearCanvas()
  146. self._LoadingLabel.NewCoord( (Width-self._LoadingLabel._Width)/2,(Height-44)/2)
  147. self._LoadingLabel.Draw()
  148. if self._img is not None:
  149. self._CanvasHWND.blit(self._img,midRect(Width/2,
  150. (Height-44)/2,
  151. pygame.Surface.get_width(self._img),pygame.Surface.get_height(self._img),Width,Height-44))
  152. class ImageDownloadProcessPage(Page):
  153. _FootMsg = ["Nav.","","","Back","Cancel"]
  154. _DownloaderTimer = -1
  155. _Value = 0
  156. _URL = None
  157. _ListFontObj = MyLangManager.TrFont("varela13")
  158. _URLColor = MySkinManager.GiveColor('URL')
  159. _TextColor = MySkinManager.GiveColor('Text')
  160. _img = None
  161. _Downloader=None
  162. _DownloaderTimer=-1
  163. def __init__(self):
  164. Page.__init__(self)
  165. self._Icons = {}
  166. self._CanvasHWND = None
  167. def Init(self):
  168. self._PosX = self._Index * self._Screen._Width
  169. self._Width = self._Screen._Width
  170. self._Height = self._Screen._Height
  171. self._CanvasHWND = self._Screen._CanvasHWND
  172. self._LoadingLabel = Label()
  173. self._LoadingLabel.SetCanvasHWND(self._CanvasHWND)
  174. self._LoadingLabel.Init("Loading",self._ListFontObj)
  175. self._LoadingLabel.SetColor(self._TextColor )
  176. def OnLoadCb(self):
  177. if self._URL is None:
  178. return
  179. self._img = None
  180. self.ClearCanvas()
  181. self._Screen.Draw()
  182. self._Screen.SwapAndShow()
  183. filename = self._URL.split("/")[-1].strip()
  184. local_dir = self._URL.split("raw.githubusercontent.com")
  185. if len(local_dir) >1:
  186. menu_file = local_dir[1]
  187. local_menu_file = "%s/aria2download%s" % (os.path.expanduser('~'),menu_file )
  188. if FileExists(local_menu_file):
  189. self._img = pygame.image.load(local_menu_file).convert_alpha()
  190. self._Screen.Draw()
  191. self._Screen.SwapAndShow()
  192. else:
  193. self._Downloader = Download(self._URL,"/tmp",None)
  194. self._Downloader.start()
  195. self._DownloaderTimer = gobject.timeout_add(300, self.GObjectUpdateProcessInterval)
  196. def GObjectUpdateProcessInterval(self):
  197. ret = True
  198. if self._Screen.CurPage() == self:
  199. if self._Downloader._stop == True:
  200. ret = False
  201. dst_filename = self._Downloader.get_dest()
  202. if self._Downloader.isFinished():
  203. if self._Downloader.isSuccessful():
  204. filename = self._URL.split("/")[-1].strip()
  205. local_dir = self._URL.split("raw.githubusercontent.com")
  206. menu_file = local_dir[1]
  207. local_menu_file = "%s/aria2download%s" % (os.path.expanduser('~'),menu_file )
  208. dl_file = os.path.join("/tmp",filename)
  209. if not os.path.exists(os.path.dirname(local_menu_file)):
  210. os.makedirs(os.path.dirname(local_menu_file))
  211. copyfile(dl_file, local_menu_file)
  212. ret = False
  213. #print("dest ",dst_filename)
  214. if FileExists(dst_filename):
  215. try:
  216. #print("load and draw")
  217. self._img = pygame.image.load(dst_filename).convert_alpha()
  218. self._Screen.Draw()
  219. self._Screen.SwapAndShow()
  220. except Exception as ex:
  221. print(ex)
  222. return ret
  223. else:
  224. return False
  225. def KeyDown(self,event):
  226. if IsKeyMenuOrB(event.key):
  227. gobject.source_remove(self._DownloaderTimer)
  228. self._DownloaderTimer = -1
  229. if self._Downloader != None:
  230. try:
  231. self._Downloader.stop()
  232. except:
  233. print("user canceled ")
  234. self.ReturnToUpLevelPage()
  235. self._Screen.Draw()
  236. self._Screen.SwapAndShow()
  237. self._URL = None
  238. def Draw(self):
  239. self.ClearCanvas()
  240. self._LoadingLabel.NewCoord( (Width-self._LoadingLabel._Width)/2,(Height-44)/2)
  241. self._LoadingLabel.Draw()
  242. if self._img is not None:
  243. self._CanvasHWND.blit(self._img,midRect(Width/2,
  244. (Height-44)/2,
  245. pygame.Surface.get_width(self._img),pygame.Surface.get_height(self._img),Width,Height-44))
  246. class Aria2DownloadProcessPage(Page):
  247. _FootMsg = ["Nav.","","Pause","Back","Cancel"]
  248. _DownloaderTimer = -1
  249. _Value = 0
  250. _GID = None
  251. _PngSize = {}
  252. _FileNameLabel = None
  253. _SizeLabel = None
  254. _URLColor = MySkinManager.GiveColor('URL')
  255. _TextColor = MySkinManager.GiveColor('Text')
  256. def __init__(self):
  257. Page.__init__(self)
  258. self._Icons = {}
  259. self._CanvasHWND = None
  260. def Init(self):
  261. self._PosX = self._Index * self._Screen._Width
  262. self._Width = self._Screen._Width
  263. self._Height = self._Screen._Height
  264. self._CanvasHWND = self._Screen._CanvasHWND
  265. bgpng = IconItem()
  266. bgpng._ImgSurf = MyIconPool.GiveIconSurface("rom_download")
  267. bgpng._MyType = ICON_TYPES["STAT"]
  268. bgpng._Parent = self
  269. bgpng.Adjust(0,0,self._PngSize["bg"][0],self._PngSize["bg"][1],0)
  270. self._Icons["bg"] = bgpng
  271. self._FileNameLabel = Label()
  272. self._FileNameLabel.SetCanvasHWND(self._CanvasHWND)
  273. self._FileNameLabel.Init("", MyLangManager.TrFont("varela12"))
  274. self._SizeLabel = Label()
  275. self._SizeLabel.SetCanvasHWND(self._CanvasHWND)
  276. self._SizeLabel.Init("0/0Kb",MyLangManager.TrFont("varela12"))
  277. self._SizeLabel.SetColor( self._URLColor )
  278. def GObjectUpdateProcessInterval(self):
  279. if self._Screen.CurPage() == self and self._GID is not None:
  280. self._Value = config.RPC.tellStatus(self._GID)
  281. downloaded = 0
  282. total = 0
  283. if self._Value["status"] == "waiting":
  284. self._FileNameLabel.SetText( "waiting to download..." )
  285. if self._Value["status"] == "paused":
  286. self._FileNameLabel.SetText( "download paused..." )
  287. if self._Value["status"] == "error":
  288. self._FileNameLabel.SetText("download errors,cancel it please")
  289. if self._Value["status"] == "active":
  290. downloaded = self._Value["completedLength"]
  291. total = self._Value["totalLength"]
  292. downloaded = downloaded/1000.0/1000.0
  293. total = total/1000.0/1000.0
  294. self._SizeLabel.SetText( "%.2f" % downloaded+"/"+ "%.2f" % total +"Mb")
  295. print("Progress: %d%%" % (self._Value))
  296. self._Screen.Draw()
  297. self._Screen.SwapAndShow()
  298. return True
  299. else:
  300. return False
  301. def CheckDownload(self,aria2_gid):
  302. self._GID = aria2_gid
  303. self._DownloaderTimer = gobject.timeout_add(234, self.GObjectUpdateProcessInterval)
  304. def KeyDown(self,event):
  305. if IsKeyMenuOrB(event.key):
  306. gobject.source_remove(self._DownloaderTimer)
  307. self._DownloaderTimer = -1
  308. #if self._Downloader != None:
  309. # try:
  310. # self._Downloader.stop()
  311. # except:
  312. # print("user canceled ")
  313. self.ReturnToUpLevelPage()
  314. self._Screen.Draw()
  315. self._Screen.SwapAndShow()
  316. def Draw(self):
  317. self.ClearCanvas()
  318. self._Icons["bg"].NewCoord(self._Width/2,self._Height/2-20)
  319. self._Icons["bg"].Draw()
  320. percent = self._Value
  321. if percent < 10:
  322. percent = 10
  323. rect_ = midRect(self._Width/2,self._Height/2+33,170,17, Width,Height)
  324. aa_round_rect(self._CanvasHWND,rect_,MySkinManager.GiveColor('TitleBg'),5,0,MySkinManager.GiveColor('TitleBg'))
  325. rect2 = midRect(self._Width/2,self._Height/2+33,int(170*(percent/100.0)),17, Width,Height)
  326. rect2.left = rect_.left
  327. rect2.top = rect_.top
  328. aa_round_rect(self._CanvasHWND,rect2,MySkinManager.GiveColor('Front'),5,0,MySkinManager.GiveColor('Front'))
  329. rect3 = midRect(self._Width/2,self._Height/2+53,self._FileNameLabel._Width, self._FileNameLabel._Height,Width,Height)
  330. rect4 = midRect(self._Width/2,self._Height/2+70,self._SizeLabel._Width, self._SizeLabel._Height,Width,Height)
  331. self._FileNameLabel.NewCoord(rect3.left,rect3.top)
  332. self._SizeLabel.NewCoord(rect4.left, rect4.top)
  333. self._FileNameLabel.Draw()
  334. self._SizeLabel.Draw()
  335. def dict_factory(cursor, row):
  336. d = {}
  337. for idx, col in enumerate(cursor.description):
  338. d[col[0]] = row[idx]
  339. return d
  340. class GameStoreListItem(InfoPageListItem):
  341. _Type = None #source,dir,launcher,pico8
  342. _CanvasHWND = None
  343. def Init(self,text):
  344. #self._Fonts["normal"] = fonts["veramono12"]
  345. l = Label()
  346. l._PosX = 10
  347. l.SetCanvasHWND(self._Parent._CanvasHWND)
  348. l.Init(text,self._Fonts["normal"])
  349. self._Labels["Text"] = l
  350. add_icon = IconItem()
  351. add_icon._ImgSurf = MyIconPool.GiveIconSurface("add")
  352. add_icon._CanvasHWND = self._CanvasHWND
  353. add_icon._Parent = self
  354. add_icon.Init(0,0,MyIconPool.Width("add"),MyIconPool.Height("add"),0)
  355. ware_icon = IconItem()
  356. ware_icon._ImgSurf = MyIconPool.GiveIconSurface("ware")
  357. ware_icon._CanvasHWND = self._CanvasHWND
  358. ware_icon._Parent = self
  359. ware_icon.Init(0,0,MyIconPool.Width("ware"),MyIconPool.Height("ware"),0)
  360. app_icon = IconItem()
  361. app_icon._ImgSurf = MyIconPool.GiveIconSurface("app")
  362. app_icon._CanvasHWND = self._CanvasHWND
  363. app_icon._Parent = self
  364. app_icon.Init(0,0,MyIconPool.Width("app"),MyIconPool.Height("app"),0)
  365. appdling_icon = IconItem()
  366. appdling_icon._ImgSurf = MyIconPool.GiveIconSurface("appdling")
  367. appdling_icon._CanvasHWND = self._CanvasHWND
  368. appdling_icon._Parent = self
  369. appdling_icon.Init(0,0,MyIconPool.Width("appdling"),MyIconPool.Height("appdling"),0)
  370. blackheart_icon = IconItem()
  371. blackheart_icon._ImgSurf = MyIconPool.GiveIconSurface("blackheart")
  372. blackheart_icon._Width = MyIconPool.Width("blackheart")
  373. blackheart_icon._Height = MyIconPool.Height("blackheart")
  374. blackheart_icon._CanvasHWND = self._CanvasHWND
  375. blackheart_icon._Parent = self
  376. self._Icons["add"] = add_icon
  377. self._Icons["ware"] = ware_icon
  378. self._Icons["app"] = app_icon
  379. self._Icons["appdling"] = appdling_icon
  380. self._Icons["blackheart"] = blackheart_icon
  381. def Draw(self):
  382. if self._ReadOnly == True:
  383. self._Labels["Text"].SetColor(MySkinManager.GiveColor("ReadOnlyText"))
  384. else:
  385. self._Labels["Text"].SetColor(MySkinManager.GiveColor("Text"))
  386. padding = 17
  387. if self._Type == None:
  388. padding = 0
  389. if self._Type == "source" or self._Type == "dir":
  390. self._Icons["ware"].NewCoord( 4, (self._Height - self._Icons["ware"]._Height)/2 )
  391. self._Icons["ware"].DrawTopLeft()
  392. if self._Type == "launcher" or self._Type == "pico8":
  393. _icon = "app"
  394. if self._ReadOnly == True:
  395. _icon = "appdling"
  396. self._Icons[_icon].NewCoord( 4, (self._Height - self._Icons[_icon]._Height)/2)
  397. self._Icons[_icon].DrawTopLeft()
  398. if self._Type == "add_house":
  399. self._Icons["add"].NewCoord( 4, (self._Height - self._Icons["add"]._Height)/2)
  400. self._Icons["add"].DrawTopLeft()
  401. self._Labels["Text"]._PosX = self._Labels["Text"]._PosX + self._PosX + padding
  402. self._Labels["Text"]._PosY = self._PosY + (self._Height - self._Labels["Text"]._Height)/2
  403. self._Labels["Text"].Draw()
  404. self._Labels["Text"]._PosX = self._Labels["Text"]._PosX - self._PosX - padding
  405. if "Small" in self._Labels:
  406. self._Labels["Small"]._PosX = self._Width - self._Labels["Small"]._Width-5
  407. self._Labels["Small"]._PosY = self._PosY + (self._Height - self._Labels["Small"]._Height)/2
  408. self._Labels["Small"].Draw()
  409. pygame.draw.line(self._Parent._CanvasHWND,MySkinManager.GiveColor('Line'),(self._PosX,self._PosY+self._Height-1),(self._PosX+self._Width,self._PosY+self._Height-1),1)
  410. class GameStorePage(Page):
  411. _FootMsg = ["Nav","UpdateWare","Up","Back","Select"]
  412. _MyList = []
  413. _ListFont12 = MyLangManager.TrFont("notosanscjk12")
  414. _ListFont15 = MyLangManager.TrFont("varela15")
  415. _AList = {}
  416. _Scrolled = 0
  417. _BGwidth = 320
  418. _BGheight = 240-24-20
  419. _DrawOnce = False
  420. _Scroller = None
  421. _InfoPage = None
  422. _Downloading = None
  423. _aria2_db = "aria2tasks.db"
  424. _warehouse_db = "warehouse.db"
  425. _GobjTimer = -1
  426. def __init__(self):
  427. Page.__init__(self)
  428. self._Icons = {}
  429. self._MyStack = RPCStack()
  430. #title path type
  431. repos = [
  432. {"title":"github.com/cuu/gamestore","file":"https://raw.githubusercontent.com/cuu/gamestore/master/index.json","type":"source"}
  433. ]
  434. self._MyStack.Push(repos)
  435. def GObjectUpdateProcessInterval(self):
  436. ret = True
  437. dirty = False
  438. for x in self._MyList:
  439. if x._Type == "launcher" or x._Type == "pico8" or x._Type == "tic80":
  440. percent = config.RPC.getPercent(x._Value["file"])
  441. if percent is not None:
  442. x.SetSmallText(str(percent)+"%")
  443. dirty = True
  444. else:
  445. x.SetSmallText("")
  446. if self._Screen.CurPage() == self and dirty == True:
  447. self._Screen.Draw()
  448. self._Screen.SwapAndShow()
  449. return ret
  450. def SyncWarehouse(self):
  451. try:
  452. conn = sqlite3.connect(self._warehouse_db)
  453. conn.row_factory = dict_factory
  454. c = conn.cursor()
  455. ret = c.execute("SELECT * FROM warehouse").fetchall()
  456. conn.close()
  457. return ret
  458. except Exception as ex:
  459. print(ex)
  460. return None
  461. return None
  462. def SyncTasks(self):
  463. try:
  464. conn = sqlite3.connect(self._aria2_db)
  465. conn.row_factory = dict_factory
  466. c = conn.cursor()
  467. ret = c.execute("SELECT * FROM tasks").fetchall()
  468. conn.close()
  469. return ret
  470. except Exception as ex:
  471. print(ex)
  472. return None
  473. return None
  474. def SyncList(self):
  475. self._MyList = []
  476. start_x = 0
  477. start_y = 0
  478. last_height = 0
  479. repos = []
  480. stk = self._MyStack.Last()
  481. stk_lev = self._MyStack.Length()
  482. repos.extend(stk)
  483. add_new_house = [
  484. {"title":"Add new warehouse...","file":"master/index.json","type":"add_house","status":"complete"}
  485. ]
  486. if stk_lev == 1: # on top
  487. ware_menu= self.SyncWarehouse()
  488. if ware_menu != None and len(ware_menu) > 0:
  489. #print(ware_menu)
  490. repos.extend(ware_menu )
  491. tasks_menu= self.SyncTasks()
  492. if tasks_menu != None and len(tasks_menu) > 0:
  493. #print(tasks_menu)
  494. repos.extend(tasks_menu )
  495. #print(repos)
  496. repos.extend(add_new_house)
  497. for i,u in enumerate( repos ):
  498. #print(i,u)
  499. li = GameStoreListItem()
  500. li._CanvasHWND = self._CanvasHWND
  501. li._Parent = self
  502. li._PosX = start_x
  503. li._PosY = start_y + last_height
  504. li._Width = Width
  505. li._Fonts["normal"] = self._ListFont15
  506. li._Fonts["small"] = self._ListFont12
  507. li._Active = False
  508. li._ReadOnly = True
  509. li._Value = u
  510. li._Type = u["type"]
  511. li.Init( u["title"] )
  512. if stk_lev >1:
  513. remote_file_url = u["file"]
  514. menu_file = remote_file_url.split("raw.githubusercontent.com")[1]
  515. local_menu_file = "%s/aria2download%s" % (os.path.expanduser('~'),menu_file )
  516. if FileExists(local_menu_file):
  517. li._ReadOnly = False
  518. else:
  519. li._ReadOnly = True
  520. elif stk_lev == 1:
  521. if "status" in u:
  522. if u["status"] == "complete":
  523. li._ReadOnly = False
  524. if u["type"]=="source":
  525. li._ReadOnly = False
  526. last_height += li._Height
  527. if li._Type == "launcher" or li._Type == "pico8" or li._Type == "tic80":
  528. li.SetSmallText("")
  529. self._MyList.append(li)
  530. def Init(self):
  531. if self._Screen != None:
  532. if self._Screen._CanvasHWND != None and self._CanvasHWND == None:
  533. self._HWND = self._Screen._CanvasHWND
  534. self._CanvasHWND = pygame.Surface( (self._Screen._Width,self._BGheight) )
  535. self._PosX = self._Index*self._Screen._Width
  536. self._Width = self._Screen._Width ## equal to screen width
  537. self._Height = self._Screen._Height
  538. done = IconItem()
  539. done._ImgSurf = MyIconPool.GiveIconSurface("done")
  540. done._MyType = ICON_TYPES["STAT"]
  541. done._Parent = self
  542. self._Icons["done"] = done
  543. ps = InfoPageSelector()
  544. ps._Parent = self
  545. self._Ps = ps
  546. self._PsIndex = 0
  547. self.SyncList()
  548. self._Scroller = ListScroller()
  549. self._Scroller._Parent = self
  550. self._Scroller._PosX = self._Width - 10
  551. self._Scroller._PosY = 2
  552. self._Scroller.Init()
  553. self._Scroller.SetCanvasHWND(self._HWND)
  554. self._remove_page = YesCancelConfirmPage()
  555. self._remove_page._Screen = self._Screen
  556. self._remove_page._StartOrA_Event = self.RemoveGame
  557. self._remove_page._Name ="Are you sure?"
  558. self._remove_page.Init()
  559. self._Keyboard = Keyboard()
  560. self._Keyboard._Name = "Enter warehouse addr"
  561. self._Keyboard._Screen = self._Screen
  562. self._Keyboard.Init()
  563. self._Keyboard.SetPassword("github.com/clockworkpi/warehouse")
  564. self._Keyboard._Caller = self
  565. self._PreviewPage = ImageDownloadProcessPage()
  566. self._PreviewPage._Screen = self._Screen
  567. self._PreviewPage._Name = "preview"
  568. self._PreviewPage.Init()
  569. self._LoadHousePage = LoadHousePage()
  570. self._LoadHousePage._Screen = self._Screen
  571. self._LoadHousePage._Name = "Warehouse"
  572. self._LoadHousePage._Caller = self
  573. self._LoadHousePage.Init()
  574. def ResetHouse(self):
  575. if self._PsIndex > len(self._MyList) -1:
  576. return
  577. cur_li = self._MyList[self._PsIndex]
  578. if cur_li._Value["type"] == "source":
  579. remote_file_url = cur_li._Value["file"]
  580. menu_file = remote_file_url.split("raw.githubusercontent.com")[1] #assume master branch
  581. local_menu_file = "%s/aria2download%s" % (os.path.expanduser('~'),menu_file )
  582. local_menu_file_path = os.path.dirname(local_menu_file)
  583. print(local_menu_file_path)
  584. local_jsons = glob.glob(local_menu_file_path+"/**/*.json")
  585. try:
  586. if os.path.exists(local_menu_file):
  587. os.remove(local_menu_file)
  588. if os.path.exists(local_menu_file+".aria2"):
  589. os.remove(local_menu_file+".aria2")
  590. for x in local_jsons:
  591. os.remove(x)
  592. except Exception as ex:
  593. print(ex)
  594. self._Screen._MsgBox.SetText("Done")
  595. self._Screen._MsgBox.Draw()
  596. self._Screen.SwapAndShow()
  597. def LoadHouse(self):
  598. if self._PsIndex > len(self._MyList) -1:
  599. return
  600. cur_li = self._MyList[self._PsIndex]
  601. if cur_li._Value["type"] == "source" or cur_li._Value["type"] == "dir":
  602. self._LoadHousePage._URL = cur_li._Value["file"]
  603. self._Screen.PushPage(self._LoadHousePage)
  604. self._Screen.Draw()
  605. self._Screen.SwapAndShow()
  606. def PreviewGame(self):
  607. if self._PsIndex > len(self._MyList) -1:
  608. return
  609. cur_li = self._MyList[self._PsIndex]
  610. if cur_li._Value["type"] == "launcher" or cur_li._Value["type"] == "pico8" or cur_li._Value["type"] == "tic80":
  611. if "shots" in cur_li._Value:
  612. print(cur_li._Value["shots"])
  613. self._PreviewPage._URL = cur_li._Value["shots"]
  614. self._Screen.PushPage(self._PreviewPage)
  615. self._Screen.Draw()
  616. self._Screen.SwapAndShow()
  617. def RemoveGame(self):
  618. if self._PsIndex > len(self._MyList) -1:
  619. return
  620. cur_li = self._MyList[self._PsIndex]
  621. #if cur_li._Active == True:
  622. # return
  623. print("Remove cur_li._Value",cur_li._Value)
  624. if cur_li._Value["type"] == "source":
  625. print("remove a source")
  626. try:
  627. conn = sqlite3.connect(self._warehouse_db)
  628. conn.row_factory = dict_factory
  629. c = conn.cursor()
  630. c.execute("DELETE FROM warehouse WHERE file = '%s'" % cur_li._Value["file"] )
  631. conn.commit()
  632. conn.close()
  633. except Exception as ex:
  634. print(ex)
  635. elif cur_li._Value["type"] == "launcher" or cur_li._Value["type"] == "pico8" or cur_li._Value["type"] == "tic80":
  636. remote_file_url = cur_li._Value["file"]
  637. menu_file = remote_file_url.split("raw.githubusercontent.com")[1]
  638. local_menu_file = "%s/aria2download%s" % (os.path.expanduser('~'),menu_file )
  639. local_menu_file_path = os.path.dirname(local_menu_file)
  640. gid,ret = config.RPC.urlDownloading(remote_file_url)
  641. if ret == True:
  642. config.RPC.remove(gid)
  643. try:
  644. if os.path.exists(local_menu_file):
  645. os.remove(local_menu_file)
  646. if os.path.exists(local_menu_file+".aria2"):
  647. os.remove(local_menu_file+".aria2")
  648. if os.path.exists( os.path.join(local_menu_file_path,cur_li._Value["title"])):
  649. rmtree(os.path.join(local_menu_file_path,cur_li._Value["title"]) )
  650. except Exception as ex:
  651. print(ex)
  652. def Click(self):
  653. if self._PsIndex > len(self._MyList) -1:
  654. return
  655. cur_li = self._MyList[self._PsIndex]
  656. #if cur_li._Active == True:
  657. # return
  658. print("cur_li._Value",cur_li._Value)
  659. if cur_li._Value["type"] == "source" or cur_li._Value["type"] == "dir":
  660. remote_file_url = cur_li._Value["file"]
  661. menu_file = remote_file_url.split("raw.githubusercontent.com")[1] #assume master branch
  662. local_menu_file = "%s/aria2download%s" % (os.path.expanduser('~'),menu_file )
  663. print(local_menu_file)
  664. if FileExists( local_menu_file ) == False:
  665. self.LoadHouse()
  666. else:
  667. #read the local_menu_file, push into stack,display menu
  668. self._Downloading = None
  669. try:
  670. with open(local_menu_file) as json_file:
  671. local_menu_json = json.load(json_file)
  672. print(local_menu_json)
  673. self._MyStack.Push(local_menu_json["list"])
  674. self.SyncList()
  675. self._Screen.Draw()
  676. self._Screen.SwapAndShow()
  677. except Exception as ex:
  678. print(ex)
  679. self._Screen._MsgBox.SetText("Open house failed ")
  680. self._Screen._MsgBox.Draw()
  681. self._Screen.SwapAndShow()
  682. elif cur_li._Value["type"] == "add_house":
  683. print("show keyboard to add ware house")
  684. self._Screen.PushCurPage()
  685. self._Screen.SetCurPage( self._Keyboard )
  686. else:
  687. #download the game probably
  688. remote_file_url = cur_li._Value["file"]
  689. menu_file = remote_file_url.split("raw.githubusercontent.com")[1]
  690. local_menu_file = "%s/aria2download%s" % (os.path.expanduser('~'),menu_file )
  691. if FileExists( local_menu_file ) == False:
  692. gid,ret = config.RPC.urlDownloading(remote_file_url)
  693. if ret == False:
  694. gid = config.RPC.addUri( remote_file_url, options={"out": menu_file})
  695. self._Downloading = gid
  696. print("stack length ",self._MyStack.Length())
  697. """
  698. if self._MyStack.Length() > 1:## not on the top list page
  699. try:
  700. conn = sqlite3.connect(self._aria2_db)
  701. c = conn.cursor()
  702. c.execute("INSERT INTO tasks(gid,title,file,type,status,fav) VALUES ('"+gid+"','"+cur_li._Value["title"]+"','"+cur_li._Value["file"]+"','"+cur_li._Value["type"]+"','active','0')")
  703. conn.commit()
  704. conn.close()
  705. except Exception as ex:
  706. print("SQLITE3 ",ex)
  707. """
  708. else:
  709. print(config.RPC.tellStatus(gid,["status","totalLength","completedLength"]))
  710. self._Screen._MsgBox.SetText("Getting the game now")
  711. self._Screen._MsgBox.Draw()
  712. self._Screen.SwapAndShow()
  713. pygame.time.delay(800)
  714. self._Screen._TitleBar.Redraw()
  715. else:
  716. print("file downloaded")# maybe check it if is installed,then execute it
  717. if cur_li._Value["type"]=="launcher" and cur_li._ReadOnly == False:
  718. local_menu_file_path = os.path.dirname(local_menu_file)
  719. game_sh = os.path.join( local_menu_file_path, cur_li._Value["title"],cur_li._Value["title"]+".sh")
  720. #game_sh = reconstruct_broken_string( game_sh)
  721. print("run game: ",game_sh, os.path.exists( game_sh))
  722. self._Screen.RunEXE(game_sh)
  723. if cur_li._Value["type"]=="pico8" and cur_li._ReadOnly == False:
  724. if os.path.exists("/home/cpi/games/PICO-8/pico-8/pico8") == True:
  725. game_sh = "/home/cpi/launcher/Menu/GameShell/50_PICO-8/PICO-8.sh"
  726. self._Screen.RunEXE(game_sh)
  727. else:
  728. self._Screen._MsgBox.SetText("Purchase pico8")
  729. self._Screen._MsgBox.Draw()
  730. self._Screen.SwapAndShow()
  731. if cur_li._Value["type"]=="tic80" and cur_li._ReadOnly == False:
  732. game_sh = "/home/cpi/apps/Menu/51_TIC-80/TIC-80.sh"
  733. self._Screen.RunEXE(game_sh)
  734. def OnAria2CompleteCb(self,gid):
  735. print("OnAria2CompleteCb ", gid)
  736. def raw_github_com(self,_url):#eg: github.com/clockworkpi/warehouse
  737. if _url.startswith("github.com")== False:
  738. return False
  739. parts = _url.split("/")
  740. if len(parts) != 3:
  741. return False
  742. return "/".join(["https://raw.githubusercontent.com",parts[1],parts[2],"master/index.json"])
  743. def OnKbdReturnBackCb(self):
  744. inputed = "".join(self._Keyboard._Textarea._MyWords).strip()
  745. inputed = inputed.replace("http://","")
  746. inputed = inputed.replace("https://","")
  747. if inputed.endswith(".git"):
  748. inputed = inputed[:len(inputed)-4]
  749. if inputed.endswith("/"):
  750. inputed = inputed[:len(inputed)-1]
  751. print("last: ",inputed)
  752. try:
  753. conn = sqlite3.connect(self._warehouse_db)
  754. conn.row_factory = dict_factory
  755. c = conn.cursor()
  756. ret = c.execute("SELECT * FROM warehouse WHERE title='%s'" % inputed ).fetchone()
  757. if ret != None:
  758. self._Screen._MsgBox.SetText("Warehouse existed!")
  759. self._Screen._MsgBox.Draw()
  760. self._Screen.SwapAndShow()
  761. else:
  762. valid_url= self.raw_github_com(inputed)
  763. if valid_url == False:
  764. self._Screen._MsgBox.SetText("Warehouse existed!")
  765. self._Screen._MsgBox.Draw()
  766. self._Screen.SwapAndShow()
  767. else:
  768. sql_insert = """ INSERT INTO warehouse(title,file,type) VALUES(
  769. '%s',
  770. '%s',
  771. 'source');""" % (inputed,valid_url)
  772. c.execute(sql_insert)
  773. conn.commit()
  774. self.SyncList()
  775. self._Screen.Draw()
  776. self._Screen.SwapAndShow()
  777. conn.close()
  778. except Exception as ex:
  779. print(ex)
  780. def OnLoadCb(self):
  781. self._Scrolled = 0
  782. self._PosY = 0
  783. self._DrawOnce = False
  784. #sync
  785. print("OnLoadCb")
  786. if self._MyStack.Length() == 1:
  787. self._FootMsg[2] = "Remove"
  788. self._FootMsg[1] = "UpdateWare"
  789. else:
  790. self._FootMsg[2] = "Remove"
  791. self._FootMsg[1] = "Preview"
  792. self._GobjTimer = gobject.timeout_add(500, self.GObjectUpdateProcessInterval)
  793. self.SyncList()
  794. def OnReturnBackCb(self):
  795. if self._MyStack.Length() == 1:
  796. self._FootMsg[2] = "Remove"
  797. self._FootMsg[1] = "UpdateWare"
  798. else:
  799. self._FootMsg[2] = "Remove"
  800. self._FootMsg[1] = "Preview"
  801. self.SyncList()
  802. self._Screen.Draw()
  803. self._Screen.SwapAndShow()
  804. """
  805. self.ReturnToUpLevelPage()
  806. self._Screen.Draw()
  807. self._Screen.SwapAndShow()
  808. """
  809. def KeyDown(self,event):
  810. if IsKeyMenuOrB(event.key):
  811. if self._MyStack.Length() > 1:
  812. self._MyStack.Pop()
  813. if self._MyStack.Length() == 1:
  814. self._FootMsg[2] = "Remove"
  815. self._FootMsg[1] = "UpdateWare"
  816. else:
  817. self._FootMsg[2] = "Remove"
  818. self._FootMsg[1] = "Preview"
  819. self.SyncList()
  820. self._Screen.Draw()
  821. self._Screen.SwapAndShow()
  822. elif self._MyStack.Length() == 1:
  823. self.ReturnToUpLevelPage()
  824. self._Screen.Draw()
  825. self._Screen.SwapAndShow()
  826. gobject.source_remove(self._GobjTimer)
  827. if IsKeyStartOrA(event.key):
  828. self.Click()
  829. if self._MyStack.Length() == 1:
  830. self._FootMsg[2] = "Remove"
  831. self._FootMsg[1] = "UpdateWare"
  832. else:
  833. self._FootMsg[2] = "Remove"
  834. self._FootMsg[1] = "Preview"
  835. self._Screen.Draw()
  836. self._Screen.SwapAndShow()
  837. if event.key == CurKeys["X"]:
  838. #print(self._MyStack.Length() )
  839. if self._PsIndex <= len(self._MyList) -1:
  840. cur_li = self._MyList[self._PsIndex]
  841. if cur_li._Type != "dir":
  842. if self._MyStack.Length() == 1 and self._PsIndex == 0:
  843. pass
  844. #predefined source
  845. else:
  846. self._Screen.PushPage(self._remove_page)
  847. self._remove_page._StartOrA_Event = self.RemoveGame
  848. self._Screen.Draw()
  849. self._Screen.SwapAndShow()
  850. return
  851. self.SyncList()
  852. self._Screen.Draw()
  853. self._Screen.SwapAndShow()
  854. if event.key == CurKeys["Y"]:
  855. if self._MyStack.Length() == 1:
  856. self.ResetHouse()
  857. else:
  858. self.PreviewGame()
  859. if event.key == CurKeys["Up"]:
  860. self.ScrollUp()
  861. self._Screen.Draw()
  862. self._Screen.SwapAndShow()
  863. if event.key == CurKeys["Down"]:
  864. self.ScrollDown()
  865. self._Screen.Draw()
  866. self._Screen.SwapAndShow()
  867. def Draw(self):
  868. self.ClearCanvas()
  869. if len(self._MyList) == 0:
  870. return
  871. else:
  872. if len(self._MyList) * self._MyList[0]._Height > self._Height:
  873. self._Ps._Width = self._Width - 11
  874. self._Ps.Draw()
  875. for i in self._MyList:
  876. if i._PosY > self._Height + self._Height/2:
  877. break
  878. if i._PosY < 0:
  879. continue
  880. i.Draw()
  881. self._Scroller.UpdateSize( len(self._MyList)*self._MyList[0]._Height, self._PsIndex*self._MyList[0]._Height)
  882. self._Scroller.Draw()
  883. else:
  884. self._Ps._Width = self._Width
  885. self._Ps.Draw()
  886. for i in self._MyList:
  887. if i._PosY > self._Height + self._Height/2:
  888. break
  889. if i._PosY < 0:
  890. continue
  891. i.Draw()
  892. if self._HWND != None:
  893. self._HWND.fill(MySkinManager.GiveColor("White"))
  894. self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width, self._Height ) )
  895. class APIOBJ(object):
  896. _Page = None
  897. def __init__(self):
  898. pass
  899. def Init(self,main_screen):
  900. self._Page = GameStorePage()
  901. self._Page._Screen = main_screen
  902. self._Page._Name ="Warehouse"
  903. self._Page.Init()
  904. def API(self,main_screen):
  905. if main_screen !=None:
  906. main_screen.PushPage(self._Page)
  907. main_screen.Draw()
  908. main_screen.SwapAndShow()
  909. OBJ = APIOBJ()
  910. def Init(main_screen):
  911. OBJ.Init(main_screen)
  912. def API(main_screen):
  913. OBJ.API(main_screen)