# -*- coding: utf-8 -*- import pygame from pygame.locals import * from sys import exit import os import sys from operator import itemgetter from libs import easing from datetime import datetime from beeprint import pp ## local package import from constants import ICON_TYPES,icon_ext,icon_width,icon_height,RUNEVT from icon_item import IconItem from page import Page,PageStack from title_bar import TitleBar from foot_bar import FootBar from constants import Width,Height,bg_color from util_funcs import midRect,FileExists,ReplaceSuffix,ReadTheFileContent,CmdClean,MakeExecutable,SkinMap from fonts import fonts from keys_def import CurKeys from label import Label from untitled_icon import UntitledIcon from Emulator import MyEmulator from skin_manager import MySkinManager from counter_screen import CounterScreen class MessageBox(Label): _Parent = None def __init__(self): pass def Init(self,text,font_obj,color=MySkinManager.GiveColor('Text')): self._Color = color self._FontObj = font_obj self._Text = text self._Width = 0 self._Height = 0 self._CanvasHWND = pygame.Surface( ( int(self._Parent._Width),int(self._Parent._Height))) self._HWND = self._Parent._CanvasHWND def SetText(self,text): self._Text = text def PreDraw(self): self._Width = 0 self._Height = 0 self._CanvasHWND.fill(MySkinManager.GiveColor('White')) words = self._Text.split(' ') space = self._FontObj.size(' ')[0] max_width = self._Parent._Width-40 x ,y = (0,0) row_total_width = 0 lines = 0 for word in words: word_surface = self._FontObj.render(word, True, self._Color) word_width = word_surface.get_width() word_height = word_surface.get_height() row_total_width += word_width if lines == 0: lines += word_height if row_total_width+space >= max_width: x = 0 # Reset the x. y += word_height # Start on new row. row_total_width = word_width lines += word_height self._CanvasHWND.blit(word_surface, (x, y)) if len(words) == 1: # single line x += word_width else: x += word_width + space if x > self._Width: self._Width = x if lines >= (self._Parent._Height - 40): break self._Height = lines def DrawWith(self, x_,y_, withborder): self.PreDraw() x_ = x_ - self._Width/2 y_ = y_ - self._Height/2 padding = 5 pygame.draw.rect(self._HWND,MySkinManager.GiveColor('White'),(x_-padding,y_-padding, self._Width+padding*2,self._Height+padding*2)) if self._HWND != None: rect = pygame.Rect(x_,y_,self._Width,self._Height) self._HWND.blit(self._CanvasHWND,rect,(0,0,self._Width,self._Height)) #self._HWND.blit(self._CanvasHWND,rect) if withborder == True: pygame.draw.rect(self._HWND,MySkinManager.GiveColor('Black'),(x_-padding,y_-padding, self._Width+padding*2,self._Height+padding*2),1) def Draw(self): x = (self._Parent._Width)/2 y = (self._Parent._Height)/2 self.DrawWith(x,y,True) python_package_flag = "__init__.py" emulator_flag = "action.config" ##Abstract object for manage Pages ,not the pygame's physic screen class MainScreen(object): _Pages = [] _PageMax = 0 _PageIndex = 0 _PosX = 0 _PosY = TitleBar._BarHeight+1 _Width = Width _Height = Height -FootBar._BarHeight -TitleBar._BarHeight _MyPageStack = None _CurrentPage = None # pointer to the current displaying Page Class _CanvasHWND = None _HWND = None _TitleBar = None _FootBar = None _MsgBox = None _MsgBoxFont = fonts["veramono20"] _IconFont = fonts["varela15"] _SkinManager = None _Closed = False _CounterScreen = None def __init__(self): self._Pages = [] self._MyPageStack = PageStack() def Init(self): self._CanvasHWND = pygame.Surface((self._Width,self._Height)) self._MsgBox= MessageBox() self._MsgBox._Parent= self self._MsgBox.Init(" ", self._MsgBoxFont) self._SkinManager = MySkinManager self._CounterScreen = CounterScreen() self._CounterScreen._HWND = self._HWND self._CounterScreen.Init() def FartherPages(self): self._PageMax = len(self._Pages) for i in range(0,self._PageMax): self._Pages[i]._Index = i self._Pages[i]._CanvasHWND = self._CanvasHWND self._Pages[i]._IconNumbers = len(self._Pages[i]._Icons) self._Pages[i]._Screen = self self._Pages[i].Adjust() if self._Pages[i]._IconNumbers > 1: self._Pages[i]._PsIndex = 1 self._Pages[i]._IconIndex = self._Pages[i]._PsIndex self._CurrentPage = self._Pages[self._PageIndex] self._CurrentPage._OnShow = True def GetMyRightSidePage(self): ret = self._PageIndex +1 if ret > (self._PageMax -1): ret = self._PageMax -1 return ret def PageMoveLeft(self): self._Pages[self._PageIndex]._OnShow = False if self._PageIndex < (self._PageMax - 1): my_right_side_page = self.GetMyRightSidePage() for i in range(0,self._PageMax): if i!= self._PageIndex and i != my_right_side_page: self._Pages[i].MoveLeft(Width) self._Pages[self._PageIndex].EasingLeft(Width) if self._PageIndex != my_right_side_page: self._Pages[my_right_side_page].EasingLeft(Width) self._Pages[self._PageIndex].ResetPageSelector() self._PageIndex+=1 if self._PageIndex > (self._PageMax -1): self._PageIndex = (self._PageMax -1) self._Pages[self._PageIndex]._OnShow = True self._CurrentPage = self._Pages[self._PageIndex] def GetMyLeftSidePage(self): ret = self._PageIndex -1 if ret < 0: ret = 0 return ret def PageMoveRight(self): self._Pages[self._PageIndex]._OnShow = False if self._PageIndex > 0: my_left_side_page = self.GetMyLeftSidePage() for i in range(0,self._PageMax): if i!= self._PageIndex and i!= my_left_side_page: pass #self._Pages[i].MoveRight(Width) self._Pages[self._PageIndex].EasingRight(Width) if self._PageIndex != my_left_side_page: self._Pages[my_left_side_page].EasingRight(Width) self._Pages[self._PageIndex].ResetPageSelector() self._PageIndex-=1 if self._PageIndex < 0: self._PageIndex = 0 self._Pages[self._PageIndex]._OnShow = True self._CurrentPage = self._Pages[self._PageIndex] def EasingAllPageLeft(self): current_time = 0.0 start_posx = 0.0 current_posx = start_posx final_posx = float(Width) posx_init = 0 dur = 30 last_posx = 0.0 all_last_posx = [] if self._PageIndex >= (self._PageMax - 1): return for i in range(0,Width*dur): current_posx = easing.SineIn(current_time,start_posx,final_posx-start_posx,float(dur)) if current_posx >= final_posx: current_posx = final_posx dx = current_posx - last_posx all_last_posx.append(int(dx)) current_time+=1 last_posx = current_posx if current_posx >= final_posx: break c = 0 for i in all_last_posx: c+=i if c < final_posx - start_posx: all_last_posx.append( final_posx - c ) for i in all_last_posx: self.ClearCanvas() for j in self._Pages: j._PosX -= i j.DrawIcons() j._Screen.SwapAndShow() self._Pages[self._PageIndex]._OnShow = False self._PageIndex+=1 if self._PageIndex > (self._PageMax -1): self._PageIndex = (self._PageMax -1) self._Pages[self._PageIndex]._OnShow = True self._CurrentPage = self._Pages[self._PageIndex] def EasingAllPageRight(self): current_time = 0.0 start_posx = 0.0 current_posx = start_posx final_posx = float(Width) posx_init = 0 dur = 30 last_posx = 0.0 all_last_posx = [] if self._PageIndex <= 0: return for i in range(0,Width*dur): current_posx = easing.SineIn(current_time,start_posx,final_posx-start_posx,float(dur)) if current_posx >= final_posx: current_posx = final_posx dx = current_posx - last_posx all_last_posx.append(int(dx)) current_time+=1 last_posx = current_posx if current_posx >= final_posx: break c = 0 for i in all_last_posx: c+=i if c < final_posx - start_posx: all_last_posx.append( final_posx - c ) for i in all_last_posx: self.ClearCanvas() for j in reversed(self._Pages): j._PosX += i j.DrawIcons() j._Screen.SwapAndShow() self._Pages[self._PageIndex]._OnShow = False self._PageIndex-=1 if self._PageIndex < 0: self._PageIndex = 0 self._Pages[self._PageIndex]._OnShow = True self._CurrentPage = self._Pages[self._PageIndex] def CurPage(self): return self._CurrentPage def PushCurPage(self): self._MyPageStack.Push(self._CurrentPage) def SetCurPage(self,page): self._CurrentPage = page on_load_cb = getattr(self._CurrentPage,"OnLoadCb",None) if on_load_cb != None: if callable( on_load_cb ): self._CurrentPage.OnLoadCb() def PushPage(self,page): self.PushCurPage() self.SetCurPage(page) def AppendPage(self,Page): self._Pages.append(Page) def ClearCanvas(self): self._CanvasHWND.fill(self._SkinManager.GiveColor('White')) def SwapAndShow(self): if self._Closed == True: return if self._HWND != None: self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width,self._Height)) pygame.display.update() def ExtraName(self,name): ## extra name like 1_xxx to be => xxx, parts = name.split("_") if len(parts) > 1: return parts[1] elif len(parts) == 1: return parts[0] else: return name def IsExecPackage(self,dirname): files = os.listdir(dirname) bname = os.path.basename(dirname) bname = self.ExtraName(bname) for i in sorted(files): if i == bname+".sh": return True return False def IsEmulatorPackage(self,dirname): files = os.listdir(dirname) for i in sorted(files): if i.endswith(emulator_flag): return True return False def IsPythonPackage(self,dirname): files = os.listdir(dirname) for i in sorted(files): if i.endswith(python_package_flag): return True return False def ReunionPagesIcons(self): #This is for combining /home/cpi/apps/Menu and ~/launcher/Menu/GameShell for p in self._Pages: tmp = [] for i,x in enumerate(p._Icons): tup = ('',0) if hasattr(x, '_FileName'): if str.find(x._FileName,"_") < 0: tup = ("98_"+x._FileName,i) # prefer to maintain PowerOFF in last position if the filename has no order labels else: tup = (x._FileName, i) else: tup = ("",i) tmp.append(tup) tmp = sorted(tmp, key=itemgetter(0)) #print(tmp) new_icons = [] for x in tmp: new_icons.append( p._Icons[ x[1] ] ) p._Icons = new_icons def ReadTheDirIntoPages(self,_dir,pglevel,cur_page): if FileExists(_dir) == False and os.path.isdir(_dir) == False: return files = os.listdir(_dir) for i in sorted(files): if os.path.isdir(_dir+"/"+i): # TOPLEVEL only is dir if pglevel == 0: page = Page() page._Name = self.ExtraName(i) page._Icons = [] self._Pages.append(page) self.ReadTheDirIntoPages(_dir+"/"+i, pglevel+1 ,self._Pages[ len(self._Pages) -1]) else: ## On CurPage now i2 = self.ExtraName(i) iconitem = IconItem() iconitem._FileName = i iconitem._CmdPath = "" iconitem.AddLabel(i2,self._IconFont) if FileExists( _dir+"/"+i+"/"+i2+".png"): ### 20_Prog/Prog.png , cut 20_ iconitem._ImageName = _dir+"/"+i+"/"+i2+".png" elif FileExists( SkinMap(_dir+"/"+i2+".png") ): iconitem._ImageName = SkinMap(_dir+"/"+i2+".png") else: untitled = UntitledIcon() untitled.Init() if len(i2) > 1: untitled.SetWords(i2[:2]) elif len(i2) == 1: untitled.SetWords([i2[0],i2[0]]) else: untitled.SetWords(["G","s"]) iconitem._ImgSurf = untitled.Surface() iconitem._ImageName = "" if self.IsPythonPackage(_dir+"/"+i): iconitem._MyType = ICON_TYPES["FUNC"] sys.path.append(_dir) iconitem._CmdPath = __import__(i) init_cb = getattr(iconitem._CmdPath,"Init",None) if init_cb != None: if callable(init_cb): iconitem._CmdPath.Init(self) cur_page._Icons.append(iconitem) elif self.IsEmulatorPackage(_dir+"/"+i): obj = {} obj["ROM"] = "" obj["ROM_SO"] ="" obj["EXT"] = [] obj["EXCLUDE"] = [] obj["FILETYPE"] = "file" obj["LAUNCHER"] = "" obj["TITLE"] = "Game" obj["SO_URL"] = "" obj["RETRO_CONFIG"] = "" ## try: f = open(_dir+"/"+i+"/"+emulator_flag) except IOError: print("action config open failed") return else: with f: content = f.readlines() content = [x.strip() for x in content] for c in content: pis = c.split("=") if len(pis) > 1: if "EXT" in pis[0]: obj[pis[0]] = pis[1].split(",") elif "EXCLUDE" in pis[0]: obj[pis[0]] = pis[1].split(",") else: obj[pis[0]] = pis[1] if FileExists(_dir+"/"+i+"/retroarch-local.cfg"): obj["RETRO_CONFIG"] = CmdClean(os.path.abspath( _dir+"/"+i+"/retroarch-local.cfg" )) print("a local retroarch cfg:", obj["RETRO_CONFIG"]) em = MyEmulator() em._Emulator = obj em.Init(self) iconitem._CmdPath = em iconitem._MyType = ICON_TYPES["Emulator"] cur_page._Icons.append(iconitem) elif self.IsExecPackage(_dir+"/"+i): iconitem._MyType = ICON_TYPES["EXE"] iconitem._CmdPath = os.path.realpath(_dir+"/"+i+"/"+i2+".sh") MakeExecutable(iconitem._CmdPath) cur_page._Icons.append(iconitem) else: iconitem._MyType = ICON_TYPES["DIR"] iconitem._LinkPage = Page() iconitem._LinkPage._Name = i2 cur_page._Icons.append(iconitem) self.ReadTheDirIntoPages(_dir+"/"+i,pglevel+1,iconitem._LinkPage) elif os.path.isfile(_dir+"/"+i) and pglevel > 0: if i.lower().endswith(icon_ext): i2 = self.ExtraName(i) #cmd = ReadTheFileContent(_dir+"/"+i) iconitem = IconItem() iconitem._FileName = i iconitem._CmdPath = os.path.realpath(_dir+"/"+i) MakeExecutable(iconitem._CmdPath) iconitem._MyType = ICON_TYPES["EXE"] if FileExists( SkinMap( _dir+"/"+ReplaceSuffix(i2,"png"))): iconitem._ImageName = SkinMap(_dir+"/"+ReplaceSuffix(i2,"png")) else: untitled = UntitledIcon() untitled.Init() if len(i2) > 1: untitled.SetWords(i2[:2]) elif len(i2) == 1: untitled.SetWords([i2[0],i2[0]]) else: untitled.SetWords(["G","s"]) iconitem._ImgSurf = untitled.Surface() iconitem._ImageName = "" iconitem.AddLabel(i2.split(".")[0],self._IconFont) iconitem._LinkPage = None cur_page._Icons.append(iconitem) def RunEXE(self,cmdpath): self.DrawRun() self.SwapAndShow() pygame.time.delay(1000) cmdpath = cmdpath.strip() cmdpath = CmdClean(cmdpath) pygame.event.post( pygame.event.Event(RUNEVT, message=cmdpath)) def OnExitCb(self,event): ## leave rest to Pages on_exit_cb = getattr(self._CurrentPage,"OnExitCb",None) if on_exit_cb != None: if callable( on_exit_cb ): self._CurrentPage.OnExitCb(event) return def KeyDown(self,event): """ if event.key == pygame.K_PAGEUP: self.EasingAllPageLeft() #self.SwapAndShow() if event.key == pygame.K_PAGEDOWN: self.EasingAllPageRight() #self.SwapAndShow() """ if event.key == pygame.K_t: self.DrawRun() self.SwapAndShow() """ if event.key == CurKeys["Space"]: self._CounterScreen.Draw() self._CounterScreen.SwapAndShow() self._CounterScreen.StartCounter() """ ## leave rest to Pages current_page_key_down_cb = getattr(self._CurrentPage,"KeyDown",None) if current_page_key_down_cb != None: if callable( current_page_key_down_cb ): self._CurrentPage.KeyDown(event) def DrawRun(self): self._MsgBox.SetText("Launching....") self._MsgBox.Draw() def Draw(self): if self._Closed == True: return self._CurrentPage.Draw() #if self._HWND != None: # self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width,self._Height)) if self._TitleBar != None: self._TitleBar.Draw(self._CurrentPage._Name) if self._FootBar != None: if hasattr(self._CurrentPage,"_FootMsg"): self._FootBar.SetLabelTexts(self._CurrentPage._FootMsg) self._FootBar.Draw()