__init__.py 42 KB

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