__init__.py 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  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._Screen.Draw()
  907. self._Screen.SwapAndShow()
  908. if event.key == CurKeys["Down"]:
  909. self.ScrollDown()
  910. self._Screen.Draw()
  911. self._Screen.SwapAndShow()
  912. def RestoreScrolled(self):
  913. for i in range(0, len(self._MyList)):
  914. self._MyList[i]._PosY += self._Scrolled_cnt
  915. def Draw(self):
  916. self.ClearCanvas()
  917. if len(self._MyList) == 0:
  918. return
  919. else:
  920. if len(self._MyList) * self._MyList[0]._Height > self._Height:
  921. self._Ps._Width = self._Width - 11
  922. self._Ps.Draw()
  923. for i in self._MyList:
  924. if i._PosY > self._Height + self._Height/2:
  925. break
  926. if i._PosY < 0:
  927. continue
  928. i.Draw()
  929. self._Scroller.UpdateSize( len(self._MyList)*self._MyList[0]._Height, self._PsIndex*self._MyList[0]._Height)
  930. self._Scroller.Draw()
  931. else:
  932. self._Ps._Width = self._Width
  933. self._Ps.Draw()
  934. for i in self._MyList:
  935. if i._PosY > self._Height + self._Height/2:
  936. break
  937. if i._PosY < 0:
  938. continue
  939. i.Draw()
  940. if self._HWND != None:
  941. self._HWND.fill(MySkinManager.GiveColor("White"))
  942. self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width, self._Height ) )
  943. class APIOBJ(object):
  944. _Page = None
  945. def __init__(self):
  946. pass
  947. def Init(self,main_screen):
  948. self._Page = GameStorePage()
  949. self._Page._Screen = main_screen
  950. self._Page._Name ="Warehouse"
  951. self._Page.Init()
  952. def API(self,main_screen):
  953. if main_screen !=None:
  954. main_screen.PushPage(self._Page)
  955. main_screen.Draw()
  956. main_screen.SwapAndShow()
  957. OBJ = APIOBJ()
  958. def Init(main_screen):
  959. OBJ.Init(main_screen)
  960. def API(main_screen):
  961. OBJ.API(main_screen)