From 32c58e386923ce2df74c09f59057060192bf3918 Mon Sep 17 00:00:00 2001 From: cuu Date: Wed, 4 Jul 2018 17:25:46 +0800 Subject: [PATCH] restore codes --- .../10_Settings/Airplane/__init__.py | 317 ++++++++++ .../10_Settings/PowerOptions/__init__.py | 567 ++++++++++++++++++ Menu/GameShell/10_Settings/list_page.py | 16 +- .../Music Player/mpd_spectrum_page.py | 100 ++- Menu/GameShell/Music Player/play_list_page.py | 12 +- .../sys.py/gameshell/icons/DialogBoxs.png | Bin 0 -> 5206 bytes skin/default/sys.py/gameshell/icons/GS.png | Bin 0 -> 599 bytes .../sys.py/gameshell/icons/airwire.png | Bin 0 -> 111 bytes .../sys.py/gameshell/icons/sheep_bg.png | Bin 0 -> 19024 bytes .../sys.py/gameshell/icons/sheep_body.png | Bin 0 -> 4315 bytes .../sys.py/gameshell/icons/sheep_head.png | Bin 0 -> 1071 bytes .../sys.py/gameshell/titlebar_icons/wifi.png | Bin 1918 -> 1465 bytes sys.py/UI/Emulator/fav_list_page.py | 32 +- sys.py/UI/Emulator/rom_list_page.py | 38 +- sys.py/UI/constants.py | 10 +- sys.py/UI/label.py | 4 +- sys.py/UI/main_screen.py | 35 +- sys.py/UI/multi_icon_item.py | 25 +- sys.py/UI/page.py | 30 +- sys.py/UI/title_bar.py | 18 +- sys.py/config.py | 12 + sys.py/run.py | 69 ++- 22 files changed, 1193 insertions(+), 92 deletions(-) create mode 100644 Menu/GameShell/10_Settings/Airplane/__init__.py create mode 100644 Menu/GameShell/10_Settings/PowerOptions/__init__.py create mode 100644 skin/default/sys.py/gameshell/icons/DialogBoxs.png create mode 100644 skin/default/sys.py/gameshell/icons/GS.png create mode 100644 skin/default/sys.py/gameshell/icons/airwire.png create mode 100644 skin/default/sys.py/gameshell/icons/sheep_bg.png create mode 100644 skin/default/sys.py/gameshell/icons/sheep_body.png create mode 100644 skin/default/sys.py/gameshell/icons/sheep_head.png diff --git a/Menu/GameShell/10_Settings/Airplane/__init__.py b/Menu/GameShell/10_Settings/Airplane/__init__.py new file mode 100644 index 0000000..ba6e34b --- /dev/null +++ b/Menu/GameShell/10_Settings/Airplane/__init__.py @@ -0,0 +1,317 @@ +# -*- coding: utf-8 -*- + +import pygame +#import math +import commands + +#from beeprint import pp +from libs.roundrects import aa_round_rect +#import gobject +#from wicd import misc +## local UI import +from UI.constants import Width,Height,ICON_TYPES +from UI.page import Page,PageSelector +from UI.label import Label +from UI.fonts import fonts +from UI.util_funcs import midRect +from UI.keys_def import CurKeys +from UI.scroller import ListScroller +from UI.icon_pool import MyIconPool +from UI.icon_item import IconItem +from UI.multi_icon_item import MultiIconItem + +from UI.multilabel import MultiLabel + +class InfoPageListItem(object): + _PosX = 0 + _PosY = 0 + _Width = 0 + _Height = 20 + + _Labels = {} + _Icons = {} + _Fonts = {} + + _LinkObj = None + + def __init__(self): + self._Labels = {} + self._Icons = {} + self._Fonts = {} + + def SetSmallText(self,text): + + l = MultiLabel() + l.SetCanvasHWND(self._Parent._CanvasHWND) + l.Init(text,self._Fonts["small"]) + + self._Labels["Small"] = l + + #if self._Labels["Small"]._Width > self._Width: + # self._Width = self._Labels["Small"]._Width + if self._Labels["Small"]._Height >= self._Height: + self._Height = self._Labels["Small"]._Height+10 + + def Init(self,text): + + #self._Fonts["normal"] = fonts["veramono12"] + + l = Label() + l._PosX = 10 + l.SetCanvasHWND(self._Parent._CanvasHWND) + + l.Init(text,self._Fonts["normal"]) + self._Labels["Text"] = l + + def Draw(self): + + self._Labels["Text"]._PosY = self._PosY + self._Labels["Text"].Draw() + + if "Small" in self._Labels: + self._Labels["Small"]._PosX = self._Labels["Text"]._Width + 16 + self._Labels["Small"]._PosY = self._PosY + self._Labels["Small"].Draw() + + + + +class AirplanePage(Page): + _FootMsg = ["Nav.","","","Back","Toggle"] + _MyList = [] + _ListFontObj = fonts["varela13"] + + _AList = {} + + _Scrolled = 0 + + _BGwidth = 320 + _BGheight = 240-24-20 + + _DrawOnce = False + _Scroller = None + + _EasingDur = 30 + + _airwire_y = 0 + _dialog_index = 0 + + def __init__(self): + Page.__init__(self) + self._Icons = {} + + def GenList(self): + + self._MyList = [] + + + + def Init(self): + if self._Screen != None: + if self._Screen._CanvasHWND != None and self._CanvasHWND == None: + self._HWND = self._Screen._CanvasHWND + self._CanvasHWND = pygame.Surface( (self._Screen._Width,self._BGheight) ) + + self._PosX = self._Index*self._Screen._Width + self._Width = self._Screen._Width ## equal to screen width + self._Height = self._Screen._Height + + + + airwire = IconItem() + airwire._ImgSurf = MyIconPool._Icons["airwire"] + airwire._MyType = ICON_TYPES["STAT"] + airwire._Parent = self + airwire.Adjust(0,0,5,43,0) + self._Icons["airwire"] = airwire + + GS = IconItem() + GS._ImgSurf = MyIconPool._Icons["GS"] + GS._MyType = ICON_TYPES["STAT"] + GS._Parent = self + GS.Adjust(0,0,72,95,0) + self._Icons["GS"] = GS + + DialogBoxs = MultiIconItem() + DialogBoxs._ImgSurf = MyIconPool._Icons["DialogBoxs"] + DialogBoxs._MyType = ICON_TYPES["STAT"] + DialogBoxs._Parent = self + DialogBoxs._IconWidth = 134 + DialogBoxs._IconHeight = 93 + DialogBoxs.Adjust(0,0,134,372,0) + self._Icons["DialogBoxs"] = DialogBoxs + + + """ + bgpng = MultiIconItem() + bgpng._ImgSurf = MyIconPool._Icons["about_bg"] + bgpng._MyType = ICON_TYPES["STAT"] + bgpng._Parent = self + bgpng.Adjust(0,0,self._BGwidth,self._BGheight,0) + self._Icons["bg"] = bgpng + """ + + + self.GenList() + + self._Scroller = ListScroller() + self._Scroller._Parent = self + self._Scroller._PosX = self._Width - 10 + self._Scroller._PosY = 2 + self._Scroller.Init() + self._Scroller.SetCanvasHWND(self._HWND) + + def ScrollDown(self): + dis = 10 + if abs(self._Scrolled) < (self._BGheight - self._Height)/2 + 0: + self._PosY -= dis + self._Scrolled -= dis + + def ScrollUp(self): + dis = 10 + if self._PosY < 0: + self._PosY += dis + self._Scrolled += dis + + def ToggleModeAni(self): ## with animation + out = commands.getstatusoutput('sudo rfkill list | grep yes | cut -d " " -f3') + if out[1] == "yes": + data = self.EasingData(0,43) + for _,v in enumerate(data): + self._airwire_y -= v + self._dialog_index = 2 + pygame.time.delay(40) + + self._Screen.Draw() + self._Screen.SwapAndShow() + + commands.getstatusoutput("sudo rfkill unblock all") + self._Screen._TitleBar._InAirPlaneMode = False + + else: + data = self.EasingData(0,43) + data.reverse() + for _,v in enumerate(data): + self._airwire_y += v + self._dialog_index = 3 + pygame.time.delay(40) + self._Screen.Draw() + self._Screen.SwapAndShow() + + commands.getstatusoutput("sudo rfkill block all") + self._Screen._TitleBar._InAirPlaneMode = True + + + def ToggleMode(self): + out = commands.getstatusoutput('sudo rfkill list | grep yes | cut -d " " -f3') + print out + if out[1] == "yes": + self._Screen._MsgBox.SetText("Turning On") + self._Screen._MsgBox.Draw() + commands.getstatusoutput("sudo rfkill unblock all") + self._Screen._TitleBar._InAirPlaneMode = False + + else: + self._Screen._MsgBox.SetText("Turning Off") + self._Screen._MsgBox.Draw() + commands.getstatusoutput("sudo rfkill block all") + self._Screen._TitleBar._InAirPlaneMode = True + + + def OnLoadCb(self): + self._Scrolled = 0 + self._PosY = 0 + self._DrawOnce = False + out = commands.getstatusoutput('sudo rfkill list | grep yes | cut -d " " -f3') + if out[1] == "yes": + self._Screen._TitleBar._InAirPlaneMode = True + self._airwire_y = 50+43 + self._dialog_index = 1 + else: + self._airwire_y = 50 + self._dialog_index = 0 + self._Screen._TitleBar._InAirPlaneMode = False + + + def OnReturnBackCb(self): + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + def KeyDown(self,event): + if event.key == CurKeys["A"] or event.key == CurKeys["Menu"]: + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["B"]: + self.ToggleModeAni() + """ + self.ToggleMode() + self._Screen.SwapAndShow() + + pygame.time.delay(1000) + + self._Screen.Draw() + self._Screen.SwapAndShow() + """ + """ + if event.key == CurKeys["Up"]: + self.ScrollUp() + self._Screen.Draw() + self._Screen.SwapAndShow() + if event.key == CurKeys["Down"]: + self.ScrollDown() + self._Screen.Draw() + self._Screen.SwapAndShow() + """ + + def Draw(self): + self.ClearCanvas() + + self._Icons["DialogBoxs"].NewCoord(145,23) + self._Icons["airwire"].NewCoord(80,self._airwire_y) + + self._Icons["DialogBoxs"]._IconIndex = self._dialog_index + + self._Icons["DialogBoxs"].DrawTopLeft() + self._Icons["airwire"].Draw() + + self._Icons["GS"].NewCoord(98,118) + self._Icons["GS"].Draw() + + if self._HWND != None: + self._HWND.fill((255,255,255)) + + self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width, self._Height ) ) + +# self._Scroller.UpdateSize(self._BGheight,abs(self._Scrolled)*3) +# self._Scroller.Draw() + + + + +class APIOBJ(object): + + _Page = None + def __init__(self): + pass + def Init(self,main_screen): + self._Page = AirplanePage() + self._Page._Screen = main_screen + self._Page._Name ="Airplane Mode" + self._Page.Init() + + def API(self,main_screen): + if main_screen !=None: + main_screen.PushPage(self._Page) + main_screen.Draw() + main_screen.SwapAndShow() + +OBJ = APIOBJ() +def Init(main_screen): + OBJ.Init(main_screen) +def API(main_screen): + OBJ.API(main_screen) + + diff --git a/Menu/GameShell/10_Settings/PowerOptions/__init__.py b/Menu/GameShell/10_Settings/PowerOptions/__init__.py new file mode 100644 index 0000000..5ebcd5d --- /dev/null +++ b/Menu/GameShell/10_Settings/PowerOptions/__init__.py @@ -0,0 +1,567 @@ +# -*- coding: utf-8 -*- + +import pygame +#import math +#mport subprocess + +#from beeprint import pp +from libs.roundrects import aa_round_rect +#import gobject +#from wicd import misc +## local UI import +from UI.constants import Width,Height,ICON_TYPES,POWEROPT +from UI.page import Page,PageSelector +from UI.label import Label +from UI.fonts import fonts +from UI.util_funcs import midRect +from UI.keys_def import CurKeys +from UI.scroller import ListScroller +from UI.icon_pool import MyIconPool +from UI.icon_item import IconItem +from UI.multilabel import MultiLabel + +import config + +class ListPageSelector(PageSelector): + _BackgroundColor = pygame.Color(131,199,219) + + def __init__(self): + self._PosX = 0 + self._PosY = 0 + self._Height = 0 + self._Width = Width + + def AnimateDraw(self,x2,y2): + pass + + def Draw(self): + idx = self._Parent._PsIndex + + if idx < len(self._Parent._MyList): + x = self._Parent._MyList[idx]._PosX+2 + y = self._Parent._MyList[idx]._PosY+1 + h = self._Parent._MyList[idx]._Height -3 + + self._PosX = x + self._PosY = y + self._Height = h + + aa_round_rect(self._Parent._CanvasHWND, + (x,y,self._Width-4,h),self._BackgroundColor,4,0,self._BackgroundColor) + + +class PageListItem(object): + _PosX = 0 + _PosY = 0 + _Width = 0 + _Height = 30 + + _Labels = {} + _Icons = {} + _Fonts = {} + + _LinkObj = None + + _Active = False + _Value = "" + + def __init__(self): + self._Labels = {} + self._Icons = {} + self._Fonts = {} + + def SetSmallText(self,text): + + l = Label() + l._PosX = 40 + l.SetCanvasHWND(self._Parent._CanvasHWND) + l.Init(text,self._Fonts["small"]) + self._Labels["Small"] = l + + def Init(self,text): + + l = Label() + l._PosX = 10 + l.SetCanvasHWND(self._Parent._CanvasHWND) + + l.Init(text,self._Fonts["normal"]) + self._Labels["Text"] = l + + def Draw(self): + + self._Labels["Text"]._PosY = self._PosY+ (self._Height- self._Labels["Text"]._Height)/2 + + if self._Active == True: + self._Parent._Icons["done"].NewCoord( self._Parent._Width-30,self._PosY+5) + self._Parent._Icons["done"].Draw() + + self._Labels["Text"].Draw(self._Active) + + if "Small" in self._Labels: + self._Labels["Small"]._PosX = self._Width - self._Labels["Small"]._Width -10 + self._Labels["Small"]._PosY = self._PosY + (self._Height- self._Labels["Small"]._Height)/2 + self._Labels["Small"].Draw() + + pygame.draw.line(self._Parent._CanvasHWND,(169,169,169),(self._PosX,self._PosY+self._Height-1),(self._PosX+self._Width,self._PosY+self._Height-1),1) + + +class InfoPage(Page): + _FootMsg = ["Nav.","","","Back",""] + _MyList = [] + _ListFontObj = fonts["varela15"] + _AList = {} + + _Time1 = 40 + _Time2 = 120 + _Time3 = 300 + + def ConvertSecToMin(self, secs): + sec_str = "" + min_str = "" + if secs > 60: + m = int(secs/60) + s = secs % 60 + if m > 1: + min_str = "%d minutes " % m + else: + min_str = "%d minute " % m + + if s == 1: + sec_str = "%d second" % s + elif s > 1: + sec_str = "%d seconds" % s + elif secs > 0: + if secs > 1: + sec_str = "%d seconds" % secs + else: + sec_str = "%d second" % secs + + elif secs == 0: + sec_str = "Never" + + return min_str + sec_str + + def RefreshList(self): + ## after GenList ,reuse + self._AList["time1"]["value"] = self.ConvertSecToMin(self._Time1) + self._AList["time2"]["value"] = self.ConvertSecToMin(self._Time2) + self._AList["time3"]["value"] = self.ConvertSecToMin(self._Time3) + + for i,v in enumerate( self._AList ): + self._MyList[i].SetSmallText( self._AList[v]["value"] ) + + def GenList(self): + + time1 = {} + time1["key"] = "time1" + if self._Time1 == 0: + time1["value"] = "Never" + else: + time1["value"] = "%d secs" % self._Time1 + time1["label"] = "Screen dimming" + + time2 = {} + time2["key"] = "time2" + if self._Time2 == 0: + time2["value"] = "Never" + else: + time2["value"] = "%d secs" % self._Time2 + + time2["label"] = "Screen OFF" + + time3 = {} + time3["key"] = "time3" + + if self._Time3 == 0: + time3["value"] = "Never" + else: + time3["value"] = "%d secs" % self._Time3 + time3["label"] = "Power OFF" + + self._AList["time1"] = time1 + self._AList["time2"] = time2 + self._AList["time3"] = time3 + + self._MyList = [] + + start_x = 0 + start_y = 0 + + for i,v in enumerate( self._AList): + print(v) + li = PageListItem() + li._Parent = self + li._PosX = start_x + li._PosY = start_y + i*PageListItem._Height + li._Width = Width + li._Fonts["normal"] = self._ListFontObj + li._Fonts["small"] = fonts["varela12"] + + if self._AList[v]["label"] != "": + li.Init( self._AList[v]["label"] ) + else: + li.Init( self._AList[v]["key"] ) + + li._Flag = self._AList[v]["key"] + + li.SetSmallText( self._AList[v]["value"] ) + + self._MyList.append(li) + + def Init(self): + if self._Screen != None: + if self._Screen._CanvasHWND != None and self._CanvasHWND == None: + self._CanvasHWND = self._Screen._CanvasHWND + + self._PosX = self._Index*self._Screen._Width + self._Width = self._Screen._Width ## equal to screen width + self._Height = self._Screen._Height + + ps = ListPageSelector() + ps._Parent = self + self._Ps = ps + self._PsIndex = 0 + + self.GenList() + + + def ScrollUp(self): + if len(self._MyList) == 0: + return + self._PsIndex -= 1 + if self._PsIndex < 0: + self._PsIndex = 0 + cur_li = self._MyList[self._PsIndex] + if cur_li._PosY < 0: + for i in range(0, len(self._MyList)): + self._MyList[i]._PosY += self._MyList[i]._Height + + + def ScrollDown(self): + if len(self._MyList) == 0: + return + self._PsIndex +=1 + if self._PsIndex >= len(self._MyList): + self._PsIndex = len(self._MyList) -1 + + cur_li = self._MyList[self._PsIndex] + if cur_li._PosY +cur_li._Height > self._Height: + for i in range(0,len(self._MyList)): + self._MyList[i]._PosY -= self._MyList[i]._Height + + def Click(self): + cur_li = self._MyList[self._PsIndex] + print(cur_li._Flag) + + + def OnLoadCb(self): + self.RefreshList() + + def OnReturnBackCb(self): + pass + """ + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + """ + + def KeyDown(self,event): + if event.key == CurKeys["A"] or event.key == CurKeys["Menu"]: + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Up"]: + self.ScrollUp() + self._Screen.Draw() + self._Screen.SwapAndShow() + if event.key == CurKeys["Down"]: + self.ScrollDown() + self._Screen.Draw() + self._Screen.SwapAndShow() + + def Draw(self): + self.ClearCanvas() + self._Ps.Draw() + + for i in self._MyList: + i.Draw() + +class PowerOptionsPage(Page): + _FootMsg = ["Nav.","","Detail","Back","Select"] + _MyList = [] + _ListFont = fonts["notosanscjk15"] + + _AList = {} + + _Scrolled = 0 + + _BGwidth = 320 + _BGheight = 240-24-20 + + _DrawOnce = False + _Scroller = None + _InfoPage = None + + def __init__(self): + Page.__init__(self) + self._Icons = {} + + def GenList(self): + + self._MyList = [] + + start_x = 0 + start_y = 0 + last_height = 0 + + + supersaving = {} + supersaving["key"] = "super" + supersaving["label"] = "Power saving" + supersaving["value"] = "supersaving" + + powersaving = {} + powersaving["key"] = "saving" + powersaving["label"] = "Balanced" + powersaving["value"] = "powersaving" + + balance_saving = {} + balance_saving["key"] = "balance" + balance_saving["label"] = "Performance" + balance_saving["value"] = "balance_saving" + + + self._AList["supersaving"] = supersaving + self._AList["powersaving"] = powersaving + self._AList["balance_saving"] = balance_saving + + for i,u in enumerate( ["supersaving","powersaving","balance_saving"] ): + if u not in self._AList: + continue + + v = self._AList[u] + + li = PageListItem() + li._Parent = self + li._PosX = start_x + li._PosY = start_y + last_height + li._Width = Width + li._Fonts["normal"] = self._ListFont + li._Active = False + li._Value = self._AList[u]["value"] + + if self._AList[u]["label"] != "": + li.Init( self._AList[u]["label"] ) + else: + li.Init( self._AList[u]["key"] ) + + last_height += li._Height + + self._MyList.append(li) + + def Init(self): + if self._Screen != None: + if self._Screen._CanvasHWND != None and self._CanvasHWND == None: + self._HWND = self._Screen._CanvasHWND + self._CanvasHWND = pygame.Surface( (self._Screen._Width,self._BGheight) ) + + self._PosX = self._Index*self._Screen._Width + self._Width = self._Screen._Width ## equal to screen width + self._Height = self._Screen._Height + + done = IconItem() + done._ImgSurf = MyIconPool._Icons["done"] + done._MyType = ICON_TYPES["STAT"] + done._Parent = self + self._Icons["done"] = done + + ps = ListPageSelector() + ps._Parent = self + self._Ps = ps + self._PsIndex = 0 + + self.GenList() + + self._Scroller = ListScroller() + self._Scroller._Parent = self + self._Scroller._PosX = self._Width - 10 + self._Scroller._PosY = 2 + self._Scroller.Init() + self._Scroller.SetCanvasHWND(self._HWND) + + self._InfoPage = InfoPage() + self._InfoPage._Screen = self._Screen + self._InfoPage._Name = "Power option detail" + self._InfoPage.Init() + + def ScrollDown(self): + if len(self._MyList) == 0: + return + self._PsIndex +=1 + if self._PsIndex >= len(self._MyList): + self._PsIndex = len(self._MyList) -1 + + cur_li = self._MyList[self._PsIndex] + if cur_li._PosY +cur_li._Height > self._Height: + for i in range(0,len(self._MyList)): + self._MyList[i]._PosY -= self._MyList[i]._Height + + def ScrollUp(self): + if len(self._MyList) == 0: + return + self._PsIndex -= 1 + if self._PsIndex < 0: + self._PsIndex = 0 + cur_li = self._MyList[self._PsIndex] + if cur_li._PosY < 0: + for i in range(0, len(self._MyList)): + self._MyList[i]._PosY += self._MyList[i]._Height + + + def Click(self): + if len(self._MyList) == 0: + return + + cur_li = self._MyList[self._PsIndex] + if cur_li._Active == True: + return + + for i in self._MyList: + i._Active = False + + cur_li._Active = True + print(cur_li._Value) + with open(".powerlevel","w") as f: + f.write(cur_li._Value) + + config.PowerLevel = cur_li._Value + + self._Screen._MsgBox.SetText("Applying...") + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() + + pygame.event.post( pygame.event.Event(POWEROPT, message="")) + + pygame.time.delay(1000) + + self._Screen.Draw() + self._Screen.SwapAndShow() + + def OnLoadCb(self): + self._Scrolled = 0 + self._PosY = 0 + self._DrawOnce = False + with open(".powerlevel", "r") as f: + powerlevel = f.read() + + powerlevel = powerlevel.strip() + + if powerlevel == "": + powerlevel = "balance_saving" + + for i in self._MyList: + if i._Value == powerlevel: + i._Active = True + + def OnReturnBackCb(self): + pass + """ + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + """ + def KeyDown(self,event): + if event.key == CurKeys["A"] or event.key == CurKeys["Menu"]: + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["B"]: + self.Click() + + if event.key == CurKeys["Up"]: + self.ScrollUp() + self._Screen.Draw() + self._Screen.SwapAndShow() + if event.key == CurKeys["Down"]: + self.ScrollDown() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Y"]: + cur_li = self._MyList[self._PsIndex] + time1 = config.PowerLevels[cur_li._Value][0] + time2 = config.PowerLevels[cur_li._Value][1] + time3 = config.PowerLevels[cur_li._Value][2] + + self._InfoPage._Time1 = time1 + self._InfoPage._Time2 = time2 + self._InfoPage._Time3 = time3 + + self._Screen.PushPage(self._InfoPage) + self._Screen.Draw() + self._Screen.SwapAndShow() + + def Draw(self): + + self.ClearCanvas() + if len(self._MyList) == 0: + return + + else: + if len(self._MyList) * PageListItem._Height > self._Height: + self._Ps._Width = self._Width - 11 + self._Ps.Draw() + for i in self._MyList: + if i._PosY > self._Height + self._Height/2: + break + if i._PosY < 0: + continue + i.Draw() + self._Scroller.UpdateSize( len(self._MyList)*PageListItem._Height, self._PsIndex*PageListItem._Height) + self._Scroller.Draw() + + else: + self._Ps._Width = self._Width + self._Ps.Draw() + for i in self._MyList: + if i._PosY > self._Height + self._Height/2: + break + if i._PosY < 0: + continue + i.Draw() + + if self._HWND != None: + self._HWND.fill((255,255,255)) + + self._HWND.blit(self._CanvasHWND,(self._PosX,self._PosY,self._Width, self._Height ) ) + + + + + +class APIOBJ(object): + + _Page = None + def __init__(self): + pass + def Init(self,main_screen): + self._Page = PowerOptionsPage() + self._Page._Screen = main_screen + self._Page._Name ="Power Options" + self._Page.Init() + + def API(self,main_screen): + if main_screen !=None: + main_screen.PushPage(self._Page) + main_screen.Draw() + main_screen.SwapAndShow() + +OBJ = APIOBJ() +def Init(main_screen): + OBJ.Init(main_screen) +def API(main_screen): + OBJ.API(main_screen) + + diff --git a/Menu/GameShell/10_Settings/list_page.py b/Menu/GameShell/10_Settings/list_page.py index add612e..64e588a 100644 --- a/Menu/GameShell/10_Settings/list_page.py +++ b/Menu/GameShell/10_Settings/list_page.py @@ -10,7 +10,7 @@ from UI.constants import Width,Height from UI.page import Page,PageSelector from UI.label import Label from UI.fonts import fonts -from UI.util_funcs import midRect +from UI.util_funcs import midRect,FileExists from UI.keys_def import CurKeys from UI.scroller import ListScroller @@ -76,19 +76,21 @@ class ListPage(Page): self._PsIndex = 0 # "" pkgname, label - alist = [["","Wifi","Wi-Fi"], + alist = [["","Airplane","Airplane Mode"], + ["","PowerOptions","Power Options"], + ["","Wifi","Wi-Fi"], ["","Sound","Sound Volume"], ["","Brightness","BackLight Brightness"], ["","Storage",""], ["","Update", ""], ["","About", "About"], - ["","PowerOFF","Power off"]] + ["","PowerOFF","Power off"],] start_x = 0 start_y = 0 - sys.path.append(myvars.basepath)# add self as import path + sys.path.append(myvars.basepath)# add self as import path for i,v in enumerate(alist): li = ListItem() li._Parent = self @@ -102,13 +104,15 @@ class ListPage(Page): else: li.Init(v[1]) - if v[1] == "Wifi" or v[1] == "Sound" or v[1] == "Brightness" or v[1] == "Storage" or v[1] == "Update" or v[1] == "About" or v[1] == "PowerOFF": + #if v[1] == "Wifi" or v[1] == "Sound" or v[1] == "Brightness" or v[1] == "Storage" or v[1] == "Update" or v[1] == "About" or v[1] == "PowerOFF" or v[1] == "HelloWorld": + if FileExists(myvars.basepath+"/"+ v[1]): li._LinkObj = __import__(v[1]) init_cb = getattr(li._LinkObj,"Init",None) if init_cb != None: if callable(init_cb): li._LinkObj.Init(self._Screen) - self._MyList.append(li) + + self._MyList.append(li) self._Scroller = ListScroller() self._Scroller._Parent = self diff --git a/Menu/GameShell/Music Player/mpd_spectrum_page.py b/Menu/GameShell/Music Player/mpd_spectrum_page.py index f544762..d12bccf 100644 --- a/Menu/GameShell/Music Player/mpd_spectrum_page.py +++ b/Menu/GameShell/Music Player/mpd_spectrum_page.py @@ -3,7 +3,7 @@ import time import pygame -from numpy import fromstring,ceil,abs,log10,isnan,isinf,int16 +from numpy import fromstring,ceil,abs,log10,isnan,isinf,int16,sqrt,mean from numpy import fft as Fft import gobject @@ -11,12 +11,14 @@ import gobject from beeprint import pp ## local UI import -from UI.constants import Width,Height +from UI.constants import Width,Height,ICON_TYPES from UI.page import Page,PageSelector from UI.label import Label from UI.fonts import fonts from UI.util_funcs import midRect from UI.keys_def import CurKeys +from UI.icon_item import IconItem +from UI.icon_pool import MyIconPool from Queue import Queue, Empty from threading import Thread @@ -37,6 +39,9 @@ class PIFI(object): count = 0 average = 0 + + rmscount=0 + rmsaverage=0 def __init__(self): self.sampleSize = self._SAMPLE_SIZE @@ -54,7 +59,14 @@ class PIFI(object): def resetSmoothing(self): self.count = 0 self.average = 0 - + self.rmscount = 0 + self.rmsaverage = 0 + + def rms_smoothOut(self, x): + self.rmscount += 1 + self.rmsaverage = (self.rmsaverage*self.rmscount + x) / (self.rmscount+1) + return self.rmsaverage + def smoothOut(self, x): self.count += 1 self.average = (self.average*self.count + x) / (self.count+1) @@ -75,7 +87,8 @@ class PIFI(object): # Compute the scaled list of values scaledList = [int(x*scaleFactor) for x in _list ] return scaledList - + + def computeSpectrum(self, fifoFile): # Read PCM samples from fifo @@ -91,6 +104,17 @@ class PIFI(object): # Normalize [-1; +1] pcm = pcm / (2.**15) + + # Compute RMS directly from signal + rms = sqrt(mean(pcm**2)) + # Compute a simple 'moving maximum' + maximum = 2*self.rms_smoothOut(rms) + if maximum == 0: + scaleFactor = 0.0 + else: + scaleFactor = self._SCALE_WIDTH/float(maximum) + + final_rms = int(rms*scaleFactor) # Compute FFT N = pcm.size @@ -127,8 +151,8 @@ class PIFI(object): # Scale the spectrum scaledSpectrum = self.scaleList(spectrum) - - return (self.bins, scaledSpectrum) + scaledSpectrum.append( final_rms) + return scaledSpectrum class MPDSpectrumPage(Page): @@ -140,11 +164,28 @@ class MPDSpectrumPage(Page): _ListFont = fonts["veramono12"] _PIFI = None - _FiFo = None + _FIFO = None _Color = pygame.Color(126,206,244) _GobjectIntervalId = -1 _Queue = None _KeepReading = True + + _BGpng = None + _BGwidth = 320 + _BGheight = 200 + + _SheepHead = None + _SheepHeadW = 69 + _SheepHeadH = 66 + + _SheepBody = None + _SheepBodyW = 105 + _SheepBodyH = 81 + + _freq_count = 0 + _head_dir = 0 + + _Neighbor = None def __init__(self): Page.__init__(self) @@ -160,8 +201,27 @@ class MPDSpectrumPage(Page): self._CanvasHWND = self._Screen._CanvasHWND - self.Start() + """ + self._BGpng = IconItem() + self._BGpng._ImgSurf = MyIconPool._Icons["sheep_bg"] + self._BGpng._MyType = ICON_TYPES["STAT"] + self._BGpng._Parent = self + self._BGpng.Adjust(0,0,self._BGwidth,self._BGheight,0) + + self._SheepHead = IconItem() + self._SheepHead._ImgSurf = MyIconPool._Icons["sheep_head"] + self._SheepHead._MyType = ICON_TYPES["STAT"] + self._SheepHead._Parent = self + self._SheepHead.Adjust(0,0,self._SheepHeadW,self._SheepHeadH,0) + self._SheepBody = IconItem() + self._SheepBody._ImgSurf = MyIconPool._Icons["sheep_body"] + self._SheepBody._MyType = ICON_TYPES["STAT"] + self._SheepBody._Parent = self + self._SheepBody.Adjust(0,0,self._SheepBodyW,self._SheepBodyH,0) + """ + + self.Start() self._GobjectIntervalId = gobject.timeout_add(50,self.Playing) def Start(self): @@ -186,7 +246,7 @@ class MPDSpectrumPage(Page): print("self._FIFO none") return - (bins,scaledSpectrum) = self._PIFI.computeSpectrum(self._FIFO) + scaledSpectrum = self._PIFI.computeSpectrum(self._FIFO) self._Queue.put( scaledSpectrum ) self._KeepReading = False @@ -212,7 +272,9 @@ class MPDSpectrumPage(Page): return True def OnLoadCb(self): - + if self._FIFO == None: + self.Start() + if self._Queue != None: with self._Queue.mutex: self._Queue.queue.clear() @@ -228,6 +290,14 @@ class MPDSpectrumPage(Page): def KeyDown(self,event): if event.key == CurKeys["Menu"] or event.key == CurKeys["A"]: + if self._FIFO != None and self._FIFO.closed == False: + try: + self._FIFO.close() + self._FIFO = None + except Exception, e: + print(e) + + self.ReturnToUpLevelPage() self._Screen.Draw() self._Screen.SwapAndShow() @@ -238,7 +308,6 @@ class MPDSpectrumPage(Page): if event.key == CurKeys["Enter"]: pass - def Draw(self): self.ClearCanvas() @@ -246,15 +315,18 @@ class MPDSpectrumPage(Page): bw = 10 spects = None try: - spects = self._Queue.get_nowait() + spects = self._Queue.get_nowait() ## last element is rms # print("get_nowait: " , spects) except Empty: return else: # got line if len(spects) == 0: return - w = self._Width / len(spects) + w = self._Width / len( spects[0:-1] ) left_margin = (w-bw)/2 - for i,v in enumerate(spects): + for i,v in enumerate(spects[0:-1]): pygame.draw.rect(self._CanvasHWND,self._Color,(i*w+left_margin,self._Height-v,bw,v),0) + + + diff --git a/Menu/GameShell/Music Player/play_list_page.py b/Menu/GameShell/Music Player/play_list_page.py index a8334c6..308a888 100644 --- a/Menu/GameShell/Music Player/play_list_page.py +++ b/Menu/GameShell/Music Player/play_list_page.py @@ -64,6 +64,7 @@ class PlayListPage(Page): _ListFont = fonts["notosanscjk15"] _Scroller = None + _CurSongTime="0:0" _BGpng = None _BGwidth = 75 @@ -110,12 +111,13 @@ class PlayListPage(Page): self.SyncPlaying() - def GObjectInterval(self): ## 250 ms + def GObjectInterval(self): ## 250 ms + self.SyncPlaying() + if self._Screen.CurPage() == self: - self.SyncPlaying() self._Screen.Draw() self._Screen.SwapAndShow() - + return True def SyncPlaying(self): @@ -138,13 +140,14 @@ class PlayListPage(Page): else: self._MyList[posid]._Playing = True if "time" in current_song: + self._CurSongTime = current_song["time"] times_ = current_song["time"].split(":") if len(times_)> 1: cur = float(times_[0]) end = float(times_[1]) pros = int((cur/end)*100.0) self._MyList[posid]._PlayingProcess = pros - + def InPlayList(self,path): for i,v in enumerate(self._MyList): @@ -271,6 +274,7 @@ class PlayListPage(Page): self.Click() if event.key == CurKeys["Start"]: # start spectrum + myvars.SpectrumPage._Neighbor = self self._Screen.PushPage(myvars.SpectrumPage) self._Screen.Draw() self._Screen.SwapAndShow() diff --git a/skin/default/sys.py/gameshell/icons/DialogBoxs.png b/skin/default/sys.py/gameshell/icons/DialogBoxs.png new file mode 100644 index 0000000000000000000000000000000000000000..e38d227a09f32545fceed78b2da1ffea733e068f GIT binary patch literal 5206 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 KelF{r5}E+Cup~wR literal 0 HcmV?d00001 diff --git a/skin/default/sys.py/gameshell/icons/sheep_bg.png b/skin/default/sys.py/gameshell/icons/sheep_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..f373475edac8af13eb1b18ccbef3166d4987351b GIT binary patch literal 19024 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 JPDHLkV1iz06!icA literal 0 HcmV?d00001 diff --git a/skin/default/sys.py/gameshell/icons/sheep_head.png b/skin/default/sys.py/gameshell/icons/sheep_head.png new file mode 100644 index 0000000000000000000000000000000000000000..615246bb5149bbaec56ebe031d7ed747ed1a6a39 GIT binary patch literal 1071 zcmV+~1kn45P)A0q6h#010qNS#tmY4#NNd4#NS*Z>VGd000McNliru;szB2J0%Zb(T4y403B&m zSad^gZEa<4bN~PV002XBWnpw>WFU8GbZ8()Nlj2>E@cM*00WarL_t(|+U?uPiyUPb z$MMfpkCSbL89l^tLxqSj2crmz5G8_&;6W4x5fSw$9y|p920?Ja5rlXYqC%7$GzJ$G ziE#rJw-}O%3xmPnWS^zeX%F?b%*eD(XR7;syQ_cjKo!*Ct?&ERv%PN(h^q=VVI$Vy z0CwXSCDaOR!AaB?v0d0uCLrhGttK$$+hIIV1|TCCUjmSZP2iSZhq9>!APsvbhNEk@ z*5alx2Ihf-;Ep39Qu1 zQi77<{K!yNVKgNub)1L{Wv-|(6b0opeuxa^NT`(x@dd3y90|RTAsi1jjh{mFxiJEe z8GICyxhz!T!{Pckj$yWybo{@x0ry~YaHJPBd2SYaL#`5|4>FC(kUWkxdFDhI;~u<; zk6Wpq8V#UBk#des*$lQ~-Twi3Fg#o@k)6Q{&2pSqN(STKwj0;X2QprAAPsvT>nkBz zysR&{949k8)Mv3k_hq=K&tZWs&G2)d!vg)7&5JsH<$A4gv85k*)Ui#z`|yvRDmjqX zap7W1=epoy$^_#mo>fHom&@bgw^xTrlMM~ zp>SUfy_VncZJ6wx;l3@ZBv> zJ)vk&&V>GFN}9u|*ia582IUm~iV3CG&d|1u&v`2LN|{Iu%3=AoM%0y(QtM$>0cUWF zh(1&JEfFY3ix^80P)^Ga&7`17e3Jr{Ir)}lD*j||3Q(%@t;iI#f4PyTC@A&dY-9gq za0p)&RVNgcMZOmq%CGWWzGR@xV0!|e&i5%nso^vEnbsKkQ{Ft15|l=Iy)6=y19(@W z+9=LZit!>}qUZ+EL445RiP(o75>^Fwb$F$`p$jyMFFFKd0{38*kw!u? z*G?e&a7Q;m8Ib?H(9VdnRTpXvo^BJA&vA(^)mp`G*iYhNU9Rgx8Bhd}S-hwRbPnz> z2+9sUq!oC4nLu_0Kcx>Qx1AO_N75@Az^(GG`%+-c;aMfoD4q-XMl&EE$`1-fnYox6 plK;zmv;04uWB3|x%iD`l^fxZ|Wj2k!$9ez&002ovPDHLkV1n#z)?oku literal 0 HcmV?d00001 diff --git a/skin/default/sys.py/gameshell/titlebar_icons/wifi.png b/skin/default/sys.py/gameshell/titlebar_icons/wifi.png index 7384a71bb7acab31b870fa7b4edc7a4b63b73c68..bc1e2c6f54366eae1d79e77575d20c5ac36da5b7 100644 GIT binary patch delta 1309 zcmV+&1>*Yt4!H}E7Yb|$1^@s6XXfJOks&^R00v@9M??Vs0RI60puMM)00009a7bBm z000fw000fw0YWI7cmMzZ2XskIMF-*q85JHIHee9s00009c5p#w0000I0000I03$eV zN&o-^Zb?KzR9M69*=vZEMI6WR&+MKw(~`j0GRf4n@=dyuZb*jFohT9^DXl0fiwG@$ z&~B7bQFbvas>OEg1{q;tETK@DQFPJP6-y*9iKHf>dBOD(=}s@6=h*Rhp4Hv;h1U7O zyg1Ly{GOTr{GabL=NXPQg%a0J#KpJ>eQ;WOeKR)TYkY&hvP{pxEbKx&OliSP^e;5% zf!DDwqtooPl&bq1FXJTm{4jSPm6o=D+I$9su;U1(lT~)&{QUGrqqPH5YsHx2U_a4; zsXdXE3Lmz^=o3_Ar9cn-bOc5#(6g{(v11Fa!xq`vnzq^D2y|(hBgNC%hpUgopiq-a z7)@%gNnZ5@Chv9B1iIpTG@)B(jG%W~{;vx4b#EqXLY|icMVAW3pcW^mwY#x@Nc6Gb zbF3=tmn$$m5BK9P0a3GHKK7>dT}1-~ucg0dNuaizyisrq-avQJvzUt?58Sa(Q4Ova zJTABy_oAT!Pvc$DVo`6wBREmeC|D*~la^(IPjRYXs^|>S0!h+N&xvw^>4GVuA^1|z zKaI%`_*N3d3o$}44;wLFa1EY+5p~Pqp>)W13+k{A<3t|`PLRBk;6>42f@?8D@SSL) z;9>F@i3m=^98o{f0>L!V&sdAKqUD0=>B?2(13|BR9CHOhd@2q6c+5br)cCpdR#)Hw z+%A|bx~Xst4n<`&9KVYC3&slG7Q7=EC+d?fcWv=II@F#&tk|kT&?>5b5j=>i((7M{ zrU{zT0kjsTM=5yc8;rzQ37dOLUOShhb*;snD*IHODMO0{yK#B?`!P(*YMj%yUPzZe zCrRA0js=wod8`n!VP^e7guG+IotcEpr6vam*-%%1LpuCvqU#0crft?V%&c$3bE4`y z?zwYzAt4XtQ6V9tIhZehPsrd#Y{z6#Lt(e0M#xeanIr*M4L(pv$b?5DOAVk*$g+-x zjuS$*wzkgQxMAauTmRe&Dsz=`l{pm^!P))$)pY67h}x;u)zx))OHhwNIZ-Z((>MHowtmW@?-vi*zJ1%5 zWD|1tp561lTCi~A>Xoa<54~XMHC3lqJtOKC?!Ik;)vH!%+1XM^$jK%4kiQ?ahh%_g zV)q{1U+sH#U%91An)8v*?;$e@DL6n#!E8aVT`jw;SiYi6$TA_zYFnXp@UY{6kp2^U z$b?5pOgcnJ!K>nbQT&%(CS;kA$A!A04vmsCl1}M)Nk*?jRcDMwNls%T-tX+FHv9K8 z^u32`JQ@Qs>Sh!e?LAz)9>W4umZ&?+!C%;y;FK(*nzYe<8TCy?X0u8)%3%}!z$@v< zwqP&@N)DH{74^AY^3eVwdFX$T9FyrG`5fQTv!jS7Gf!Gj+N)eTqJF9KFsv_{+LgGh zs9!^=spW$`r8B`MS^jU8W>dSCe>AEy>e`i%ZK++4NR~!9N)K(jFp`x=T_qc=X51>t z{5JIux%jy_C_nT~lj{Z?6*4tcGBG+cFgh|fD=;`ZFfg?F(~*-L2OJeLHB>S&Ix{dj TGB+zQI65#e#iVO3lT8OP1ut?< literal 1918 zcmeAS@N?(olHy`uVBq!ia0vp^LO>kF!3-puq`##ADVB6cUq=Rpjs4tz5?O(Kg=CK) zUj~LMH3o);76yi2K%s^g3=E|P3=FRl7#OT(FffQ0%-I!a!@$7wJ-{c#6{ukL^jWi~ z%`(?BHP<(-tEkOM&CbuvE6yn@%_~k%Of4@e%ScRjwsv%~a!8Dd2dW>O0OAV}2}jew zY-AE5g(d>z!V$7wh#*`9$Us&GWFwn~tPGirUm2P##C&A!KsH1WPQpdN%0RIOjyPc4 zfe?g^CJ2$juK=P2StHyixUu@CGpEd$I$_F;$F#IeD z@(V^!&m3+|^ESJ%tIhrTWu_9()IZC9PvF|^uuJpfXT89G!3~TnH!xkg#;@@Dt%|c} z!R$rH&u~hqX6*j-bzioc#>}%T7p^!xM(g{WB!?T$TSA1Aw!jxB9 zS~GDfP#H)`uNXwd`xKxWMxY{7L#XK>lYef98k})I#J6_UvL;m|H$k1$2yze5Egd~Z zmhBTfz4Hozo@Y$*c6a$>!?(B|$l)yTh%5#cIM+d#(Me-=1yGQ^#M9T6{Shl4pR)S8 zDE2Iny0QYtbRZ2Xk%SnOE%Lm8C5nNki(`nz>Er|jDGm-U&h8El?#?bp)+4Ga^-hgb zw(tZvg!##x2@YTg?(#atqZPoqYE?j+RP(N5{vr!j9zC#NZS$Hyckz@xa+}<2H}w8u z<4|-~?$A!@O>|OQX0UwLOy?FI9l>+kgIHcp+V1vk60gSzwyU$Z+1KA%_%r6ry@P_b zCUfR=@LR?-OziBuc=PDhx7YQ{`Tg|;_%)uq{rr0R`uY3o9UiQYcRZ-DaKeT7#D_i! z0)juawPsCJd={P~lU(DJ6cm(H#FdpV@ZF$Ie9RY>sTO*&ty2dCq+YgXuF_Jv%Dzy}$o? zq0bC~(@m{928vS5zgk``I@p1*>p_jYi~ z3C-S~bNASxO}W4O=6?7fRkv_g_tf6rxy{AqHX+{&-rn8*|3KqkcK$+Vr>`F-E-xqn1sm>ffX9r^5xreXIZe{-Gw;X1@Ra zzT`@N&a3=7^7en@PJZ}#`px=|fWO<`{^n;(6T1?SnkaW`As0i4%=W(z78OnhCL+}m z*NBpo#FA92 1: @@ -190,6 +190,9 @@ class FavListPage(Page): li.Init(v["directory"]) elif "file" in v: li.Init(v["file"]) + + elif "gamedir" in v: + li.Init(v["gamedir"]) else: li.Init("NoName") @@ -307,11 +310,16 @@ class FavListPage(Page): self._Screen._MsgBox.SetText("Launching...") self._Screen._MsgBox.Draw() self._Screen.SwapAndShow() - print("Run ",cur_li._Path) + if self._Emulator["FILETYPE"] == "dir": + path = cur_li._Path +"/"+self._Emulator["EXT"][0] + else: + path = cur_li._Path + + print("Run ",path) # check ROM_SO exists if FileExists(self._Emulator["ROM_SO"]): - escaped_path = CmdClean( cur_li._Path) + escaped_path = CmdClean( path) custom_config = "" if self._Emulator["RETRO_CONFIG"] != "" and len(self._Emulator["RETRO_CONFIG"]) > 5: diff --git a/sys.py/UI/Emulator/rom_list_page.py b/sys.py/UI/Emulator/rom_list_page.py index f094b5f..a8d38d5 100644 --- a/sys.py/UI/Emulator/rom_list_page.py +++ b/sys.py/UI/Emulator/rom_list_page.py @@ -133,16 +133,19 @@ class RomListPage(Page): for i ,v in enumerate(files_path): dirmap = {} - #if os.path.isdir(v): - # dir_base_name = os.path.basename(v) - # if dir_base_name == ".Trash" or dir_base_name == ".Fav": - # pass - # else: - # dirmap["directory"] = v - # ret.append(dirmap) - if os.path.isfile(v): + if os.path.isdir(v) and self._Emulator["FILETYPE"] == "dir": ## like DOSBOX + gameshell_bat = self._Emulator["EXT"][0] + stats = os.stat(v) - if stats.st_gid == self._Parent._FavGID: + if stats.st_gid == self._Parent._FavGID: ##skip fav roms + continue + + if FileExists(v+"/"+gameshell_bat): + dirmap["gamedir"] = v.decode("utf8") + ret.append(dirmap) + if os.path.isfile(v) and self._Emulator["FILETYPE"] == "file": + stats = os.stat(v) + if stats.st_gid == self._Parent._FavGID: ##skip fav roms continue bname = os.path.basename(v) ### filter extension @@ -199,6 +202,8 @@ class RomListPage(Page): li.Init(v["directory"]) elif "file" in v: li.Init(v["file"]) + elif "gamedir" in v: + li.Init(v["gamedir"]) else: li.Init("NoName") @@ -336,16 +341,25 @@ class RomListPage(Page): self._Screen._MsgBox.SetText("Launching...") self._Screen._MsgBox.Draw() self._Screen.SwapAndShow() - print("Run ",cur_li._Path) + + if self._Emulator["FILETYPE"] == "dir": + path = cur_li._Path +"/"+self._Emulator["EXT"][0] + else: + path = cur_li._Path + + print("Run ",path) # check ROM_SO exists if FileExists(self._Emulator["ROM_SO"]): - escaped_path = CmdClean( cur_li._Path) + if self._Emulator["FILETYPE"] == "dir": + escaped_path = CmdClean(path) + else: + escaped_path = CmdClean(path) custom_config = "" if self._Emulator["RETRO_CONFIG"] != "" and len(self._Emulator["RETRO_CONFIG"]) > 5: custom_config = " -c " + self._Emulator["RETRO_CONFIG"] - + cmdpath = " ".join( (self._Emulator["LAUNCHER"],self._Emulator["ROM_SO"], custom_config, escaped_path)) pygame.event.post( pygame.event.Event(RUNEVT, message=cmdpath)) return diff --git a/sys.py/UI/constants.py b/sys.py/UI/constants.py index 941110e..3b43273 100644 --- a/sys.py/UI/constants.py +++ b/sys.py/UI/constants.py @@ -34,12 +34,10 @@ DT = pygame.time.Clock().tick(30) # fps in ms,eg:50 GMEVT = pygame.USEREVENT+1 update_titlebar_event = pygame.event.Event(GMEVT, message="titlebar") -RUNEVT = pygame.USEREVENT+2 -RUNSYS = pygame.USEREVENT+3 - - +RUNEVT = pygame.USEREVENT+2 +RUNSYS = pygame.USEREVENT+3 LOWLIGHT = pygame.USEREVENT+4 ## when dim screen backlight - -FOOTMSG = pygame.USEREVENT+5 ## when dim screen backlight +FOOTMSG = pygame.USEREVENT+5 ## +POWEROPT = pygame.USEREVENT+6 diff --git a/sys.py/UI/label.py b/sys.py/UI/label.py index c7ad207..2fe65a6 100644 --- a/sys.py/UI/label.py +++ b/sys.py/UI/label.py @@ -50,8 +50,8 @@ class Label: def SetCanvasHWND(self,_canvashwnd): self._CanvasHWND = _canvashwnd - def Draw(self): - self._FontObj.set_bold(False) ## avoing same font tangling set_bold to others + def Draw(self,bold=False): + self._FontObj.set_bold(bold) ## avoing same font tangling set_bold to others my_text = self._FontObj.render( self._Text,True,self._Color) self._CanvasHWND.blit(my_text,(self._PosX,self._PosY,self._Width,self._Height)) diff --git a/sys.py/UI/main_screen.py b/sys.py/UI/main_screen.py index 9c9b885..6def24e 100644 --- a/sys.py/UI/main_screen.py +++ b/sys.py/UI/main_screen.py @@ -45,8 +45,8 @@ class MessageBox(Label): def SetText(self,text): self._Text = text - - def Draw(self): + + def PreDraw(self): self._Width = 0 self._Height = 0 self._CanvasHWND.fill( (255,255,255)) @@ -87,20 +87,31 @@ class MessageBox(Label): self._Height = lines - padding = 5 - x = (self._Parent._Width - self._Width)/2 - y = (self._Parent._Height - self._Height)/2 - # print("x %d y %d w %d h %d" %(x,y,self._Width,self._Height )) + def DrawWith(self, x_,y_, withborder): - pygame.draw.rect(self._HWND,(255,255,255),(x-padding,y-padding, self._Width+padding*2,self._Height+padding*2)) + self.PreDraw() + + x_ = x_ - self._Width/2 + y_ = y_ - self._Height/2 + + padding = 5 + + pygame.draw.rect(self._HWND,(255,255,255),(x_-padding,y_-padding, self._Width+padding*2,self._Height+padding*2)) if self._HWND != None: - rect = midRect(self._Parent._Width/2,self._Parent._Height/2,self._Width,self._Height,Width,Height) + 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) - - pygame.draw.rect(self._HWND,(0,0,0),(x-padding,y-padding, self._Width+padding*2,self._Height+padding*2),1) - + + if withborder == True: + pygame.draw.rect(self._HWND,(0,0,0),(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" @@ -125,6 +136,7 @@ class MainScreen(object): _IconFont = fonts["varela15"] _SkinManager = None + def __init__(self): self._Pages = [] self._MyPageStack = PageStack() @@ -406,6 +418,7 @@ class MainScreen(object): obj["ROM"] = "" obj["ROM_SO"] ="" obj["EXT"] = [] + obj["FILETYPE"] = "file" obj["LAUNCHER"] = "" obj["TITLE"] = "Game" obj["SO_URL"] = "" diff --git a/sys.py/UI/multi_icon_item.py b/sys.py/UI/multi_icon_item.py index 4690aca..58b2af1 100644 --- a/sys.py/UI/multi_icon_item.py +++ b/sys.py/UI/multi_icon_item.py @@ -23,6 +23,27 @@ class MultiIconItem(IconItem): self._ImgSurf = pygame.image.load( self._ImageName ).convert_alpha() + def DrawTopLeft(self): + if self._Align==ALIGN["VCenter"]: #default + if self._Label != None: + self._Label._PosX = self._PosX - self._Label._Width/2 + self._Parent._PosX + self._Label._PosY = self._PosY + self._Height/2 +6 + self._Parent._PosY + + elif self._Align ==ALIGN["HLeft"]: + if self._Label != None: + self._Label._PosX = self._PosX + self._Width/2 + 3 + self._Parent._PosX + self._Label._PosY = self._PosY - self._Label._Height/2 + self._Parent._PosY + + if self._Label!=None: + self._Label.Draw() + + + if self._ImgSurf != None: + self._Parent._CanvasHWND.blit(self._ImgSurf,pygame.Rect(self._PosX+self._Parent._PosX, + self._PosY+self._Parent._PosY, + self._Width,self._Height), + (0,self._IconIndex*self._IconHeight,self._IconWidth,self._IconHeight)) + def Draw(self): if self._Align==ALIGN["VCenter"]: #default if self._Label != None: @@ -36,9 +57,11 @@ class MultiIconItem(IconItem): if self._Label!=None: self._Label.Draw() - + + if self._ImgSurf != None: self._Parent._CanvasHWND.blit(self._ImgSurf,midRect(self._PosX+self._Parent._PosX, self._PosY+self._Parent._PosY, self._Width,self._Height,Width,Height), (0,self._IconIndex*self._IconHeight,self._IconWidth,self._IconHeight)) + diff --git a/sys.py/UI/page.py b/sys.py/UI/page.py index e5e2422..9a14168 100644 --- a/sys.py/UI/page.py +++ b/sys.py/UI/page.py @@ -117,7 +117,9 @@ class Page(object): rows = int( (self._IconNumbers * icon_width)/Width + 1) if rows < 1: rows = 1 - cnt = 0 + + cnt = 0 + for i in range(0,rows): for j in range(0,cols): start_x = icon_width/2 + j*icon_width @@ -184,8 +186,8 @@ class Page(object): it = self._Icons[0] it._Parent = self it._Index = 0 - it.Adjust(start_x,start_y,icon_width-6,icon_height-6,0) - it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height)) + it.Adjust(start_x,start_y,icon_width,icon_height,0) + #it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height)) elif self._IconNumbers == 2: start_x = (self._Width - self._PageIconMargin - self._IconNumbers*icon_width) / 2 + icon_width/2 @@ -195,17 +197,16 @@ class Page(object): it = self._Icons[i] it._Parent = self it._Index = i - it.Adjust(start_x+i*self._PageIconMargin + i*icon_width,start_y, icon_width-6, icon_height-6,0) - it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height)) + it.Adjust(start_x+i*self._PageIconMargin + i*icon_width,start_y, icon_width, icon_height,0) + #it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height)) elif self._IconNumbers > 2: for i in range(0,self._IconNumbers): it = self._Icons[i] it._Parent = self it._Index = i - it.Adjust(start_x+i*self._PageIconMargin + i*icon_width,start_y,icon_width-6,icon_height-6,0) - - it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height)) + it.Adjust(start_x+i*self._PageIconMargin + i*icon_width,start_y,icon_width,icon_height,0) + #it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height)) ps = PageSelector() ps._IconSurf = MyIconPool._Icons["blueselector"] @@ -231,7 +232,7 @@ class Page(object): rows = int((self._IconNumbers * icon_width)/self._Width + 1) if rows < 1: rows = 1 - cnt = 0 + cnt = 0 for i in range(0,rows): for j in range(0,cols): start_x = icon_width/2 + j*icon_width @@ -267,9 +268,9 @@ class Page(object): it._Parent = self it._Index = i it.Adjust(start_x+i*icon_width,start_y,icon_width,icon_height,0) - ps = PageSelector() - ps._IconSurf = blueselector_surf + ps = PageSelector() + ps._IconSurf = MyIconPool._Icons["blueselector"] ps._Parent = self ps.Init(start_x,start_y,92,92,128) self._Ps = ps @@ -362,7 +363,7 @@ class Page(object): diffa = [] for i in range(0,dff): diffa.append(0) - all_pieces.extend( diffa) + all_pieces.extend( diffa) return all_pieces @@ -406,8 +407,9 @@ class Page(object): if self._Icons[self._PrevIconIndex]._PosY < self._Height/2: self._Icons[self._PrevIconIndex]._PosY+=data2[i] - self.DrawIcons() - self._Screen.SwapAndShow() + + self.DrawIcons() + self._Screen.SwapAndShow() def IconsEasingLeft(self,icon_ew): diff --git a/sys.py/UI/title_bar.py b/sys.py/UI/title_bar.py index eda0378..81ca4fb 100644 --- a/sys.py/UI/title_bar.py +++ b/sys.py/UI/title_bar.py @@ -3,6 +3,7 @@ import pygame import os import sys +import commands from datetime import datetime @@ -46,6 +47,7 @@ class TitleBar: _SkinManager = None + _InAirPlaneMode = False def __init__(self): self._Icons = {} @@ -237,7 +239,13 @@ class TitleBar: if is_wifi_connected_now(): print("wifi is connected") print( wifi_strength()) - + else: + out = commands.getstatusoutput('sudo rfkill list | grep yes | cut -d " " -f3') + if out[1] == "yes": + self._InAirPlaneMode = True + else: + self._InAirPlaneMode = False + def ClearCanvas(self): self._CanvasHWND.fill( self._SkinManager.GiveColor("TitleBg") ) @@ -291,9 +299,13 @@ class TitleBar: else: self._Icons["wifistatus"]._IconIndex = 0 self._Icons["wifistatus"].Draw() - print("strength error") + print("wifi strength error") else: - self._Icons["wifistatus"]._IconIndex = 0 + if self._InAirPlaneMode == False: + self._Icons["wifistatus"]._IconIndex = 0 + else: + self._Icons["wifistatus"]._IconIndex = 5 ## airplane mode icon + self._Icons["wifistatus"].NewCoord(start_x+self._icon_width+5,self._icon_height/2+(self._BarHeight-self._icon_height)/2) self._Icons["wifistatus"].Draw() diff --git a/sys.py/config.py b/sys.py/config.py index 5e40c83..044eca7 100644 --- a/sys.py/config.py +++ b/sys.py/config.py @@ -15,3 +15,15 @@ UPDATE_URL="https://raw.githubusercontent.com/clockworkpi/CPI/master/launcher_ve VERSION="stable 1.0" SKIN="default" + +## three timer values in seconds: dim screen, close screen,PowerOff +## zero means no action +PowerLevels = {} +PowerLevels["supersaving"] = [10,30,100] +PowerLevels["powersaving"] = [40,120,300] +PowerLevels["balance_saving"] = [40,0,0] + +PowerLevel = "balance_saving" + +##sys.py/.powerlevel + diff --git a/sys.py/run.py b/sys.py/run.py index 490d24e..207e469 100644 --- a/sys.py/run.py +++ b/sys.py/run.py @@ -30,7 +30,7 @@ else: #local UI import -from UI.constants import Width,Height,bg_color,icon_width,icon_height,DT,GMEVT,RUNEVT,RUNSYS,ICON_TYPES +from UI.constants import Width,Height,bg_color,icon_width,icon_height,DT,GMEVT,RUNEVT,RUNSYS,ICON_TYPES,POWEROPT from UI.util_funcs import ReplaceSuffix,FileExists, ReadTheFileContent,midRect,color_surface,SwapAndShow,GetExePath,X_center_mouse from UI.page import PageStack,PageSelector,Page from UI.label import Label @@ -59,6 +59,8 @@ myscriptname = os.path.basename(os.path.realpath(__file__)) everytime_keydown = time.time() +passout_time_stage = 0 + last_brt = -1 def gobject_loop(): @@ -73,7 +75,7 @@ def gobject_loop(): def RestoreLastBackLightBrightness(main_screen): - global last_brt + global last_brt,passout_time_stage if last_brt == -1: return @@ -95,17 +97,21 @@ def RestoreLastBackLightBrightness(main_screen): f.close() last_brt = -1 main_screen._TitleBar._InLowBackLight = -1 + passout_time_stage = 0 else: f.close() return def InspectionTeam(main_screen): - global everytime_keydown,last_brt + global everytime_keydown,last_brt,passout_time_stage cur_time = time.time() - - if cur_time - everytime_keydown > 40: + time_1 = config.PowerLevels[config.PowerLevel][0] + time_2 = config.PowerLevels[config.PowerLevel][1] + time_3 = config.PowerLevels[config.PowerLevel][2] + + if cur_time - everytime_keydown > time_1 and passout_time_stage == 0: print("timeout, dim screen %d" % int(cur_time - everytime_keydown)) try: @@ -117,8 +123,9 @@ def InspectionTeam(main_screen): content = f.readlines() content = [x.strip() for x in content] brt=int(content[0]) - if brt > 1: + if brt > 0: last_brt = brt ## remember brt for restore + brt = 1 f.seek(0) f.write(str(brt)) @@ -126,7 +133,39 @@ def InspectionTeam(main_screen): f.close() main_screen._TitleBar._InLowBackLight = 0 - + + if time_2 != 0: + passout_time_stage = 1 # next + everytime_keydown = cur_time + + elif cur_time - everytime_keydown > time_2 and passout_time_stage == 1: + print("timeout, close screen %d" % int(cur_time - everytime_keydown)) + + try: + f = open(config.BackLight,"r+") + except IOError: + pass + else: + with f: + brt = 0 + f.seek(0) + f.write(str(brt)) + f.truncate() + f.close() + main_screen._TitleBar._InLowBackLight = 0 + + if time_3 != 0: + passout_time_stage = 2 # next + everytime_keydown = cur_time + + elif cur_time - everytime_keydown > time_3 and passout_time_stage == 2: + print("Power Off now") + + if config.CurKeySet != "PC": + cmdpath = "sudo halt -p" + pygame.event.post( pygame.event.Event(RUNSYS, message=cmdpath)) + + passout_time_stage = 0 everytime_keydown = cur_time return True @@ -184,6 +223,12 @@ def event_process(event,main_screen): os.chdir( GetExePath()) os.exelp("python","python"," "+myscriptname) return + + if event.type == POWEROPT: + everytime_keydown = time.time() + RestoreLastBackLightBrightness(main_screen) + + return if event.type == pygame.KEYUP: pygame.event.clear(pygame.KEYDOWN) @@ -377,6 +422,16 @@ if __name__ == '__main__': print("This pygame does not support PNG") exit() + + if FileExists(".powerlevel") == False: + os.system("touch .powerlevel") + + with open(".powerlevel","r") as f: + powerlevel = f.read() + + powerlevel = powerlevel.strip() + if powerlevel != "": + config.PowerLevel = powerlevel big_loop()