From ad93e5d889618a9071c84c7ad65e4b5e80b926d2 Mon Sep 17 00:00:00 2001 From: clockworkpi <35560767+clockworkpi@users.noreply.github.com> Date: Fri, 25 May 2018 20:34:07 +0800 Subject: [PATCH] Add files via upload --- Menu/GameShell/10_Settings/About/__init__.py | 345 ++++++++ .../10_Settings/Brightness/__init__.py | 17 + .../10_Settings/Brightness/brightness_page.py | 188 ++++ .../10_Settings/Brightness/myvars.py | 6 + .../GameShell/10_Settings/Brightness/pages.py | 13 + .../10_Settings/PowerOFF/__init__.py | 89 ++ Menu/GameShell/10_Settings/Sound/__init__.py | 17 + Menu/GameShell/10_Settings/Sound/myvars.py | 6 + Menu/GameShell/10_Settings/Sound/pages.py | 13 + .../GameShell/10_Settings/Sound/sound_page.py | 154 ++++ .../GameShell/10_Settings/Storage/__init__.py | 137 +++ Menu/GameShell/10_Settings/Update/__init__.py | 359 ++++++++ Menu/GameShell/10_Settings/Wifi/__init__.py | 29 + Menu/GameShell/10_Settings/Wifi/icons/_L.png | Bin 0 -> 306 bytes Menu/GameShell/10_Settings/Wifi/icons/_R.png | Bin 0 -> 294 bytes .../GameShell/10_Settings/Wifi/icons/done.png | Bin 0 -> 198 bytes .../GameShell/10_Settings/Wifi/icons/lock.png | Bin 0 -> 335 bytes .../10_Settings/Wifi/icons/preload.py | 21 + Menu/GameShell/10_Settings/Wifi/keyboard.py | 340 ++++++++ Menu/GameShell/10_Settings/Wifi/myvars.py | 5 + Menu/GameShell/10_Settings/Wifi/net_item.py | 199 +++++ Menu/GameShell/10_Settings/Wifi/pages.py | 61 ++ Menu/GameShell/10_Settings/Wifi/text_item.py | 28 + Menu/GameShell/10_Settings/Wifi/textarea.py | 133 +++ Menu/GameShell/10_Settings/Wifi/wifi_list.py | 820 ++++++++++++++++++ Menu/GameShell/10_Settings/__init__.py | 29 + Menu/GameShell/10_Settings/list_item.py | 59 ++ Menu/GameShell/10_Settings/list_page.py | 190 ++++ Menu/GameShell/10_Settings/myvars.py | 12 + Menu/GameShell/10_Settings/pages.py | 13 + Menu/GameShell/20_Retro Games/GBA.png | Bin 0 -> 2931 bytes .../20_Retro Games/GBA/action.config | 6 + Menu/GameShell/20_Retro Games/MAME.png | Bin 0 -> 3339 bytes .../20_Retro Games/MAME/action.config | 6 + Menu/GameShell/20_Retro Games/NES.png | Bin 0 -> 3072 bytes .../20_Retro Games/NES/action.config | 7 + Menu/GameShell/CaveStroy.png | Bin 0 -> 5364 bytes Menu/GameShell/CaveStroy.sh | 1 + Menu/GameShell/Music Player.png | Bin 0 -> 4095 bytes Menu/GameShell/Music Player/__init__.py | 36 + Menu/GameShell/Music Player/icons/done.png | Bin 0 -> 198 bytes Menu/GameShell/Music Player/icons/preload.py | 21 + Menu/GameShell/Music Player/list_item.py | 135 +++ .../Music Player/mpd_spectrum_page.py | 260 ++++++ .../Music Player/music_lib_list_page.py | 343 ++++++++ Menu/GameShell/Music Player/myvars.py | 8 + Menu/GameShell/Music Player/pages.py | 38 + Menu/GameShell/Music Player/play_list_page.py | 279 ++++++ Menu/GameShell/PowerOFF.png | Bin 0 -> 3287 bytes Menu/GameShell/PowerOFF/__init__.py | 89 ++ Menu/GameShell/Retro Games.png | Bin 0 -> 4007 bytes Menu/GameShell/RetroArch.png | Bin 0 -> 2803 bytes Menu/GameShell/RetroArch.sh | 1 + Menu/GameShell/Settings.png | Bin 0 -> 5071 bytes Menu/GameShell/Sleep.png | Bin 0 -> 2600 bytes Menu/GameShell/TinyCloud.png | Bin 0 -> 6207 bytes Menu/GameShell/TinyCloud/__init__.py | 220 +++++ Menu/GameShell/freeDM.png | Bin 0 -> 3320 bytes Menu/GameShell/freeDM.sh | 1 + 59 files changed, 4734 insertions(+) create mode 100644 Menu/GameShell/10_Settings/About/__init__.py create mode 100644 Menu/GameShell/10_Settings/Brightness/__init__.py create mode 100644 Menu/GameShell/10_Settings/Brightness/brightness_page.py create mode 100644 Menu/GameShell/10_Settings/Brightness/myvars.py create mode 100644 Menu/GameShell/10_Settings/Brightness/pages.py create mode 100644 Menu/GameShell/10_Settings/PowerOFF/__init__.py create mode 100644 Menu/GameShell/10_Settings/Sound/__init__.py create mode 100644 Menu/GameShell/10_Settings/Sound/myvars.py create mode 100644 Menu/GameShell/10_Settings/Sound/pages.py create mode 100644 Menu/GameShell/10_Settings/Sound/sound_page.py create mode 100644 Menu/GameShell/10_Settings/Storage/__init__.py create mode 100644 Menu/GameShell/10_Settings/Update/__init__.py create mode 100644 Menu/GameShell/10_Settings/Wifi/__init__.py create mode 100644 Menu/GameShell/10_Settings/Wifi/icons/_L.png create mode 100644 Menu/GameShell/10_Settings/Wifi/icons/_R.png create mode 100644 Menu/GameShell/10_Settings/Wifi/icons/done.png create mode 100644 Menu/GameShell/10_Settings/Wifi/icons/lock.png create mode 100644 Menu/GameShell/10_Settings/Wifi/icons/preload.py create mode 100644 Menu/GameShell/10_Settings/Wifi/keyboard.py create mode 100644 Menu/GameShell/10_Settings/Wifi/myvars.py create mode 100644 Menu/GameShell/10_Settings/Wifi/net_item.py create mode 100644 Menu/GameShell/10_Settings/Wifi/pages.py create mode 100644 Menu/GameShell/10_Settings/Wifi/text_item.py create mode 100644 Menu/GameShell/10_Settings/Wifi/textarea.py create mode 100644 Menu/GameShell/10_Settings/Wifi/wifi_list.py create mode 100644 Menu/GameShell/10_Settings/__init__.py create mode 100644 Menu/GameShell/10_Settings/list_item.py create mode 100644 Menu/GameShell/10_Settings/list_page.py create mode 100644 Menu/GameShell/10_Settings/myvars.py create mode 100644 Menu/GameShell/10_Settings/pages.py create mode 100644 Menu/GameShell/20_Retro Games/GBA.png create mode 100644 Menu/GameShell/20_Retro Games/GBA/action.config create mode 100644 Menu/GameShell/20_Retro Games/MAME.png create mode 100644 Menu/GameShell/20_Retro Games/MAME/action.config create mode 100644 Menu/GameShell/20_Retro Games/NES.png create mode 100644 Menu/GameShell/20_Retro Games/NES/action.config create mode 100644 Menu/GameShell/CaveStroy.png create mode 100644 Menu/GameShell/CaveStroy.sh create mode 100644 Menu/GameShell/Music Player.png create mode 100644 Menu/GameShell/Music Player/__init__.py create mode 100644 Menu/GameShell/Music Player/icons/done.png create mode 100644 Menu/GameShell/Music Player/icons/preload.py create mode 100644 Menu/GameShell/Music Player/list_item.py create mode 100644 Menu/GameShell/Music Player/mpd_spectrum_page.py create mode 100644 Menu/GameShell/Music Player/music_lib_list_page.py create mode 100644 Menu/GameShell/Music Player/myvars.py create mode 100644 Menu/GameShell/Music Player/pages.py create mode 100644 Menu/GameShell/Music Player/play_list_page.py create mode 100644 Menu/GameShell/PowerOFF.png create mode 100644 Menu/GameShell/PowerOFF/__init__.py create mode 100644 Menu/GameShell/Retro Games.png create mode 100644 Menu/GameShell/RetroArch.png create mode 100644 Menu/GameShell/RetroArch.sh create mode 100644 Menu/GameShell/Settings.png create mode 100644 Menu/GameShell/Sleep.png create mode 100644 Menu/GameShell/TinyCloud.png create mode 100644 Menu/GameShell/TinyCloud/__init__.py create mode 100644 Menu/GameShell/freeDM.png create mode 100644 Menu/GameShell/freeDM.sh diff --git a/Menu/GameShell/10_Settings/About/__init__.py b/Menu/GameShell/10_Settings/About/__init__.py new file mode 100644 index 0000000..eab2d5f --- /dev/null +++ b/Menu/GameShell/10_Settings/About/__init__.py @@ -0,0 +1,345 @@ +# -*- coding: utf-8 -*- + +import pygame +#import math + +#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.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 AboutPage(Page): + _FootMsg = ["Nav.","","","Back",""] + _MyList = [] + _ListFontObj = fonts["varela13"] + + _AList = {} + + _Scrolled = 0 + + _BGwidth = 320 + _BGheight = 256 + + _DrawOnce = False + _Scroller = None + + def __init__(self): + Page.__init__(self) + self._Icons = {} + + def CpuMhz(self): + with open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq") as f: + content = f.readlines() + content = [x.strip() for x in content] + + mhz = int(content[0]) / 1000.0 + + cpuscalemhz = {} + cpuscalemhz["key"] = "cpuscalemhz" + cpuscalemhz["label"] = "CPU Mhz:" + cpuscalemhz["value"] = str(mhz) + self._AList["cpuscalemhz"] = cpuscalemhz + + return + + def CpuInfo(self): + last_processor = 0 + with open("/proc/cpuinfo") as f: + for line in f: + if line.startswith("processor"): + parts = line.split(":") + cur_processor_number = int( parts[1].strip()) + if cur_processor_number > last_processor: + last_processor = cur_processor_number + + if line.startswith("model name"): + parts = line.split(":") +# print( parts[1].strip() ) + processor = {} + processor["key"]="processor" + processor["label"] = "Processor:" + processor["value"] = parts[1].strip() + + self._AList["processor"] = processor + + if line.startswith("cpu MHz"): + parts = line.split(":") +# print(parts[1].strip() ) + cpumhz = {} + cpumhz["key"] = "cpumhz" + cpumhz["label"] = "CPU MHz:" + cpumhz["value"] = parts[1].strip() + + self._AList["cpumhz"] = cpumhz + if line.startswith("cpu cores"): + parts = line.split(":") +# print(parts[1].strip() ) + cpucores = {} + cpucores["key"] = "cpucores" + cpucores["label"] = "CPU cores:" + cpucores["value"] = parts[1].strip() + self._AList["cpucores"] = cpucores + if line.startswith("Features"): + parts = line.split(":") +# print(parts[1].strip() ) + f_ = {} + f_["key"] = "features" + f_["label"] = "Features:" + f_["value"] = parts[1].strip() + self._AList["features"] = f_ + + if line.startswith("flags"): + parts = line.split(":") +# print(parts[1].strip() ) + flags = {} + flags["key"] = "flags" + flags["label"] = "Flags:" + flags["value"] = parts[1].strip() + self._AList["flags"] = flags + + + if last_processor > 0: + arm_cores = {} + arm_cores["key"]= "armcores" + arm_cores["label"] = "CPU cores:" + arm_cores["value"] = str(last_processor + 1) + self._AList["armcores"] = arm_cores + + def MemInfo(self): + + with open("/proc/meminfo") as f: + for line in f: + if line.startswith("MemTotal"): + parts = line.split(":") + parts[1] = parts[1].replace("kB","") + print( parts[1].strip() ) + + memory = {} + memory["key"] = "memory" + memory["label"] = "Memory:" + memory["value"] = str( int(parts[1].strip())/1000.0) +" Mb" + self._AList["memory"] = memory + break + + def GenList(self): + + self._MyList = [] + + start_x = 0 + start_y = 10 + last_height = 0 + + for i,u in enumerate( ["processor","armcores","cpuscalemhz","features","memory"] ): + #for i,u in enumerate( ["processor","cpucores","cpumhz","flags","memory"] ): + if u not in self._AList: + continue + + v = self._AList[u] + + li = InfoPageListItem() + li._Parent = self + li._PosX = start_x + li._PosY = start_y + last_height + li._Width = Width + li._Fonts["normal"] = self._ListFontObj + li._Fonts["small"] = fonts["varela12"] + + if self._AList[u]["label"] != "": + li.Init( self._AList[u]["label"] ) + else: + li.Init( self._AList[u]["key"] ) + + li._Flag = self._AList[u]["key"] + + li.SetSmallText( self._AList[u]["value"] ) + + 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 + + bgpng = IconItem() + 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.CpuInfo() + self.MemInfo() + self.CpuMhz() + + 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 + 40: + self._PosY -= dis + self._Scrolled -= dis + + def ScrollUp(self): + dis = 10 + if self._PosY < 0: + self._PosY += dis + self._Scrolled += dis + + + def OnLoadCb(self): + self._Scrolled = 0 + self._PosY = 0 + self._DrawOnce = 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["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): + + if self._DrawOnce == False: + self.ClearCanvas() + #self._Ps.Draw() + + self._Icons["bg"].NewCoord(self._Width/2,self._Height/2 + (self._BGheight - Height)/2 + self._Screen._TitleBar._Height) + self._Icons["bg"].Draw() + + for i in self._MyList: + i.Draw() + + self._DrawOnce = True + + 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 = AboutPage() + self._Page._Screen = main_screen + self._Page._Name ="About" + 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/Brightness/__init__.py b/Menu/GameShell/10_Settings/Brightness/__init__.py new file mode 100644 index 0000000..5f8fd9a --- /dev/null +++ b/Menu/GameShell/10_Settings/Brightness/__init__.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +## local UI import +import pages +import myvars + +def Init(main_screen): + pages.InitBrightnessPage(main_screen) + +def API(main_screen): + + if main_screen !=None: + main_screen.PushCurPage() + main_screen.SetCurPage(myvars.BrightnessPage) + main_screen.Draw() + main_screen.SwapAndShow() + diff --git a/Menu/GameShell/10_Settings/Brightness/brightness_page.py b/Menu/GameShell/10_Settings/Brightness/brightness_page.py new file mode 100644 index 0000000..12b5199 --- /dev/null +++ b/Menu/GameShell/10_Settings/Brightness/brightness_page.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- + +import pygame + + +#import math + +## local UI import +from UI.constants import Width,Height,ICON_TYPES +from UI.page import Page,PageSelector +from UI.label import Label +from UI.icon_item import IconItem +from UI.fonts import fonts +from UI.util_funcs import midRect +from UI.keys_def import CurKeys +from UI.slider import Slider +from UI.icon_pool import MyIconPool +from UI.multi_icon_item import MultiIconItem +from config import BackLight +import myvars + +class BSlider(Slider): + + + OnChangeCB = None + _BGpng = None + _BGwidth = 179 + _BGheight = 153 + + _NeedleSurf = None + _Scale = None + _Parent = None + _Icons = {} + + def __init__(self): + Slider.__init__(self) + self._Icons = {} + def Init(self): + self._Width = self._Parent._Width + self._Height = self._Parent._Height + + bgpng = IconItem() + bgpng._ImgSurf = MyIconPool._Icons["light"] + bgpng._MyType = ICON_TYPES["STAT"] + bgpng._Parent = self + bgpng.Adjust(0,0,self._BGwidth,self._BGheight,0) + self._Icons["bg"] = bgpng + ##self._NeedleSurf = pygame.Surface( (38,12),pygame.SRCALPHA ) + + scale = MultiIconItem() + scale._MyType = ICON_TYPES["STAT"] + scale._Parent = self + scale._ImgSurf = MyIconPool._Icons["scale"] + scale._IconWidth = 82 + scale._IconHeight = 63 + scale.Adjust(0,0,82,63,0) + self._Icons["scale"] = scale + + def SetValue(self,brt):#pct 0-100 + + self._Value = brt + + def Further(self): + self._Value+=1 + if self._Value < 9: + if self.OnChangeCB != None: + if callable(self.OnChangeCB): + self.OnChangeCB(self._Value) + else: + self._Value = 8 + + def StepBack(self): + self._Value-=1 + + if self._Value < 0: + self._Value = 0 + + if self.OnChangeCB != None: + if callable(self.OnChangeCB): + self.OnChangeCB(self._Value) + + def Draw(self): + + self._Icons["bg"].NewCoord(self._Width/2,self._Height/2 +11 ) + self._Icons["bg"].Draw() + + self._Icons["scale"].NewCoord(self._Width/2,self._Height/2 ) + + self._Icons["scale"]._IconIndex = self._Value + self._Icons["scale"].Draw() + """ + pygame.draw.line(self._CanvasHWND,(255,0,0), (posx,self._PosY),(self._Width,self._PosY),3) ## range line + pygame.draw.line(self._CanvasHWND,(0,0,255), (self._PosX,self._PosY),(posx,self._PosY),3) ## range line + + pygame.draw.circle(self._CanvasHWND,(255,255,255),( posx, self._PosY),7,0) + pygame.draw.circle(self._CanvasHWND,(0,0,0) ,( posx, self._PosY),7,1)## outer border + """ + + + +class BrightnessPage(Page): + + _MySlider = None + _FootMsg = ["Nav","","","Back","Enter"] + + def Init(self): + self._CanvasHWND = self._Screen._CanvasHWND + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + self._MySlider = BSlider() +# self._MySlider._Width = Width - 20 +# self._MySlider._Height = 30 +# self._MySlider._PosX = (self._Width - self._MySlider._Width)/2 +# self._MySlider._PosY = 40 + self._MySlider._Parent = self + self._MySlider.SetCanvasHWND(self._CanvasHWND) + self._MySlider.OnChangeCB = self.WhenSliderDrag + self._MySlider.Init() + + brt = self.ReadBackLight() + + self._MySlider.SetValue( brt) + + + def ReadBackLight(self): + try: + f = open(BackLight) + except IOError: + return 0 + else: + with f: + content = f.readlines() + content = [x.strip() for x in content] + return int(content[0]) + + return 0 + + def OnLoadCb(self): + brt = self.ReadBackLight() + self._MySlider.SetValue( brt) + + def SetBackLight(self,newbrt): + try: + f = open(BackLight,'w') + except IOError: + print("Open write %s failed" % BackLight) + return False + else: + with f: + f.write(str(newbrt)) + return True + + def WhenSliderDrag(self,value): ##value 0-100 + if value < 0 or value > 8: + return + + if value == 0: ## 0 == total black + value = 1 + + self.SetBackLight(value) + + def KeyDown(self,event): + + if event.key == CurKeys["Menu"] or event.key == CurKeys["A"]: + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Right"]: + self._MySlider.Further() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Left"]: + self._MySlider.StepBack() + self._Screen.Draw() + self._Screen.SwapAndShow() + + def Draw(self): + self.ClearCanvas() + + self._MySlider.Draw() + + + + + diff --git a/Menu/GameShell/10_Settings/Brightness/myvars.py b/Menu/GameShell/10_Settings/Brightness/myvars.py new file mode 100644 index 0000000..caa03de --- /dev/null +++ b/Menu/GameShell/10_Settings/Brightness/myvars.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +import os +import sys + +SoundPage = None diff --git a/Menu/GameShell/10_Settings/Brightness/pages.py b/Menu/GameShell/10_Settings/Brightness/pages.py new file mode 100644 index 0000000..643adb9 --- /dev/null +++ b/Menu/GameShell/10_Settings/Brightness/pages.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +from brightness_page import BrightnessPage + +import myvars + +def InitBrightnessPage(main_screen): + + myvars.BrightnessPage = BrightnessPage() + + myvars.BrightnessPage._Screen = main_screen + myvars.BrightnessPage._Name = "Brightness" + myvars.BrightnessPage.Init() diff --git a/Menu/GameShell/10_Settings/PowerOFF/__init__.py b/Menu/GameShell/10_Settings/PowerOFF/__init__.py new file mode 100644 index 0000000..cd32448 --- /dev/null +++ b/Menu/GameShell/10_Settings/PowerOFF/__init__.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- + +import pygame + +#UI lib +from UI.constants import RUNSYS +from UI.keys_def import CurKeys +from UI.confirm_page import ConfirmPage + +import config + +class PowerOffConfirmPage(ConfirmPage): + + _ConfirmText = "Confirm Power OFF?" + + + def CheckBattery(self): + try: + f = open(config.Battery) + except IOError: + print( "PowerOFF open %s failed" % config.Battery) + return 0 + else: + with f: + bat_uevent = {} + content = f.readlines() + content = [x.strip() for x in content] + for i in content: + pis = i.split("=") + if len(pis) > 1: + bat_uevent[pis[0]] = pis[1] + + if "POWER_SUPPLY_CAPACITY" in bat_uevent: + cur_cap = int(bat_uevent["POWER_SUPPLY_CAPACITY"]) + else: + cur_cap = 0 + + return cur_cap + + return 0 + + def KeyDown(self,event): + + if event.key == CurKeys["Menu"] or event.key == CurKeys["A"]: + + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["B"]: + if self.CheckBattery() < 20: + cmdpath = "feh --bg-center gameshell/wallpaper/gameover.png;" + else: + cmdpath = "feh --bg-center gameshell/wallpaper/seeyou.png;" + + cmdpath += "sleep 3;" + + #cmdpath += "echo 'halt -p' > /tmp/halt_cmd" + + cmdpath += "sudo halt -p" + pygame.event.post( pygame.event.Event(RUNSYS, message=cmdpath)) + + + +class APIOBJ(object): + + _StoragePage = None + def __init__(self): + pass + def Init(self,main_screen): + self._Page = PowerOffConfirmPage() + + self._Page._Screen = main_screen + self._Page._Name ="Power OFF" + 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/Sound/__init__.py b/Menu/GameShell/10_Settings/Sound/__init__.py new file mode 100644 index 0000000..db9da3e --- /dev/null +++ b/Menu/GameShell/10_Settings/Sound/__init__.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- + +## local UI import +import pages +import myvars + +def Init(main_screen): + pages.InitSoundPage(main_screen) + +def API(main_screen): + + if main_screen !=None: + main_screen.PushCurPage() + main_screen.SetCurPage(myvars.SoundPage) + main_screen.Draw() + main_screen.SwapAndShow() + diff --git a/Menu/GameShell/10_Settings/Sound/myvars.py b/Menu/GameShell/10_Settings/Sound/myvars.py new file mode 100644 index 0000000..caa03de --- /dev/null +++ b/Menu/GameShell/10_Settings/Sound/myvars.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- + +import os +import sys + +SoundPage = None diff --git a/Menu/GameShell/10_Settings/Sound/pages.py b/Menu/GameShell/10_Settings/Sound/pages.py new file mode 100644 index 0000000..76122bd --- /dev/null +++ b/Menu/GameShell/10_Settings/Sound/pages.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +from sound_page import SoundPage + +import myvars + +def InitSoundPage(main_screen): + + myvars.SoundPage = SoundPage() + + myvars.SoundPage._Screen = main_screen + myvars.SoundPage._Name = "Sound volume" + myvars.SoundPage.Init() diff --git a/Menu/GameShell/10_Settings/Sound/sound_page.py b/Menu/GameShell/10_Settings/Sound/sound_page.py new file mode 100644 index 0000000..d083613 --- /dev/null +++ b/Menu/GameShell/10_Settings/Sound/sound_page.py @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- + +import pygame + +#from libs.roundrects import aa_round_rect + +import alsaaudio + +## local UI import +from UI.constants import Width,Height,ICON_TYPES +from UI.page import Page,PageSelector +from UI.icon_item import IconItem +from UI.label import Label +from UI.fonts import fonts +from UI.util_funcs import midRect +from UI.keys_def import CurKeys +from UI.slider import Slider +from UI.multi_icon_item import MultiIconItem + + +from UI.icon_pool import MyIconPool + +import myvars + +class SoundSlider(Slider): + OnChangeCB = None + + _BGpng = None + _BGwidth = 192 + _BGheight = 173 + + _NeedleSurf = None + _Scale = None + _Parent = None + _Segs = [0,15,29, 45,55,65, 75,90,100] + snd_segs = [ [0,20],[21,40],[41,50],[51,60],[61,70],[71,85],[86,90],[91,95],[96,100] ] + + def __init__(self): + Slider.__init__(self) + + def Init(self): + self._Width = self._Parent._Width + self._Height = self._Parent._Height + + self._BGpng = IconItem() + self._BGpng._ImgSurf = MyIconPool._Icons["vol"] + self._BGpng._MyType = ICON_TYPES["STAT"] + self._BGpng._Parent = self + self._BGpng.Adjust(0,0,self._BGwidth,self._BGheight,0) + + ##self._NeedleSurf = pygame.Surface( (38,12),pygame.SRCALPHA ) + + self._Scale = MultiIconItem() + self._Scale._MyType = ICON_TYPES["STAT"] + self._Scale._Parent = self + self._Scale._ImgSurf = MyIconPool._Icons["scale"] + self._Scale._IconWidth = 82 + self._Scale._IconHeight = 63 + self._Scale.Adjust(0,0,82,63,0) + + def SetValue(self,pct):#pct 0-100 + + for i,v in enumerate(self.snd_segs): + if pct >= v[0] and pct <= v[1]: + self._Value = i + + def Further(self): + self._Value+=1 + if self._Value < len(self._Segs): + if self.OnChangeCB != None: + if callable(self.OnChangeCB): + self.OnChangeCB( self._Segs[ self._Value ] ) + else: + self._Value = len(self._Segs)-1 + + def StepBack(self): + self._Value-=1 + + if self._Value < 0: + self._Value = 0 + + if self.OnChangeCB != None: + if callable(self.OnChangeCB): + self.OnChangeCB(self._Segs[self._Value] ) + + def Draw(self): + + self._BGpng.NewCoord(self._Width/2,self._Height/2 ) + self._BGpng.Draw() + + self._Scale.NewCoord(self._Width/2,self._Height/2) + + self._Scale._IconIndex = self._Value + + self._Scale.Draw() + + + +class SoundPage(Page): + + _MySlider = None + _FootMsg = ["Nav","","","Back","Enter"] + + def Init(self): + self._CanvasHWND = self._Screen._CanvasHWND + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + self._MySlider = SoundSlider() + + + self._MySlider._Parent = self + self._MySlider.SetCanvasHWND(self._CanvasHWND) + + self._MySlider.OnChangeCB = self.WhenSliderDrag + + self._MySlider.Init() + + m = alsaaudio.Mixer() + self._MySlider.SetValue(m.getvolume()[0]) + + def WhenSliderDrag(self,value): ##value 0-100 + if value < 0 or value > 100: + return + + m = alsaaudio.Mixer() + m.setvolume(int(value)) + + def KeyDown(self,event): + + if event.key == CurKeys["Menu"] or event.key == CurKeys["A"]: + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Right"]: + self._MySlider.Further() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Left"]: + self._MySlider.StepBack() + self._Screen.Draw() + self._Screen.SwapAndShow() + + def Draw(self): + self.ClearCanvas() + + self._MySlider.Draw() + + + + + diff --git a/Menu/GameShell/10_Settings/Storage/__init__.py b/Menu/GameShell/10_Settings/Storage/__init__.py new file mode 100644 index 0000000..8a9c545 --- /dev/null +++ b/Menu/GameShell/10_Settings/Storage/__init__.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- + +import pygame +import os + + +## local UI import +from UI.page import Page +from UI.constants import ICON_TYPES,Width,Height +from UI.icon_item import IconItem +from UI.icon_pool import MyIconPool +from UI.label import Label +from UI.fonts import fonts +from UI.util_funcs import midRect + +from libs.roundrects import aa_round_rect + +class StoragePage(Page): + + _Icons = {} + _BGpng = None + _BGwidth = 96 + _BGheight = 73 + _BGlabel = None + _FreeLabel = None + + _BGmsg = "%.1fGB of %.1fGB Used" + _DskUsg = None + + _HighColor = pygame.Color(51,166,255) + + def __init__(self): + Page.__init__(self) + + self._Icons = {} + + + def DiskUsage(self): + statvfs = os.statvfs('/') + + total_space = (statvfs.f_frsize * statvfs.f_blocks)/1024.0/1024.0/1024.0 + + avail_space = ( statvfs.f_frsize * statvfs.f_bavail) / 1024.0 / 1024.0/ 1024.0 + + return avail_space,total_space + + def Init(self): + + self._DskUsg = self.DiskUsage() + + self._CanvasHWND = self._Screen._CanvasHWND + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + self._BGpng = IconItem() + self._BGpng._ImgSurf = MyIconPool._Icons["icon_sd"] + self._BGpng._MyType = ICON_TYPES["STAT"] + self._BGpng._Parent = self + + self._BGpng.AddLabel(self._BGmsg % (self._DskUsg[1]-self._DskUsg[0], self._DskUsg[1]), fonts["varela15"]) + self._BGpng.Adjust(0,0,self._BGwidth,self._BGheight,0) + + + self._BGlabel = Label() + self._BGlabel.SetCanvasHWND(self._CanvasHWND) + + usage_percent = (self._DskUsg[0]/self._DskUsg[1] )*100.0 + + self._BGlabel.Init("%d%%"% int(usage_percent),fonts["varela25"]) + self._BGlabel.SetColor( self._HighColor ) + + self._FreeLabel = Label() + self._FreeLabel.SetCanvasHWND(self._CanvasHWND) + self._FreeLabel.Init("Free",fonts["varela13"]) + self._FreeLabel.SetColor(self._BGlabel._Color) + + + def OnLoadCb(self): + pass + + def Draw(self): + self.ClearCanvas() + + self._BGpng.NewCoord(self._Width/2,self._Height/2-10) + self._BGpng.Draw() + self._BGlabel.NewCoord(self._Width/2-28,self._Height/2-30) + self._BGlabel.Draw() + + self._FreeLabel.NewCoord(self._BGlabel._PosX+10 ,self._Height/2) + self._FreeLabel.Draw() + + #bgcolor = (238,238,238), fgcolor = (126,206,244) + #aa_round_rect + usage_percent = (self._DskUsg[0]/self._DskUsg[1] ) + if usage_percent < 0.1: + usage_percent = 0.1 + + rect_ = midRect(self._Width/2,self._Height-30,170,17, Width,Height) + + aa_round_rect(self._CanvasHWND,rect_, (238,238,238),5,0,(238,238,238)) + + + rect2 = midRect(self._Width/2,self._Height-30,int(170*(1.0-usage_percent)),17, Width,Height) + + rect2.left = rect_.left + rect2.top = rect_.top + + aa_round_rect(self._CanvasHWND,rect2, (126,206,244),5,0,(126,206,244)) + +class APIOBJ(object): + + _StoragePage = None + def __init__(self): + pass + def Init(self,main_screen): + self._StoragePage = StoragePage() + + self._StoragePage._Screen = main_screen + self._StoragePage._Name ="Storage" + self._StoragePage.Init() + + + def API(self,main_screen): + if main_screen !=None: + main_screen.PushPage(self._StoragePage) + 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/Update/__init__.py b/Menu/GameShell/10_Settings/Update/__init__.py new file mode 100644 index 0000000..c4aa6a3 --- /dev/null +++ b/Menu/GameShell/10_Settings/Update/__init__.py @@ -0,0 +1,359 @@ +# -*- coding: utf-8 -*- + +import pygame +import os +import requests +import validators +import gobject + + +## local UI import +from UI.page import Page +from UI.constants import ICON_TYPES,Width,Height,RUNEVT +from UI.icon_item import IconItem +from UI.icon_pool import MyIconPool +from UI.label import Label +from UI.fonts import fonts +from UI.util_funcs import midRect,CmdClean +from UI.keys_def import CurKeys +from UI.confirm_page import ConfirmPage +from UI.download import Download +from UI.download_process_page import DownloadProcessPage + +from libs.roundrects import aa_round_rect + +import config + +class UpdateDownloadPage(DownloadProcessPage): + _MD5 = "" + + def GObjectUpdateProcessInterval(self): + if self._Screen.CurPage() == self: + if self._Downloader.isFinished(): + if self._Downloader.isSuccessful(): + print("Success!") + # Do something with obj.get_dest() + filename = self._Downloader.get_dest() + + if filename.endswith(".tar.gz"): + #/home/cpi/apps/[launcher] + cmdpath = "tar zxf " + CmdClean(filename) + " -C /home/cpi/apps ;rm -rf "+ filename + pygame.event.post( pygame.event.Event(RUNEVT, message=cmdpath)) + + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + else: + print("Download failed with the following exceptions:") + for e in self._Downloader.get_errors(): + print(unicode(e)) + + try: + self._Downloader.stop() + except: + pass + + filename = self._Downloader.get_dest() + print(filename) + os.system("rm -rf %s" % CmdClean(filename)) + + self._Screen._MsgBox.SetText("Download failed") + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() + return False + else: + self._Value = self._Downloader.get_progress() + print("Progress: %d%%" % (self._Value)) + self._Screen.Draw() + self._Screen.SwapAndShow() + return True + else: + return False + + def StartDownload(self,url,dst_dir): + if validators.url(url) and os.path.isdir(dst_dir): + self._URL = url + self._DST_DIR = dst_dir + else: + self._Screen._MsgBox.SetText("Invaid") + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() + return + + self._Downloader = Download(url,dst_dir,None) + if self._MD5 != None: + if len(self._MD5) == 32: + self._Downloader.add_hash_verification('md5' ,self._MD5) ## hashlib provide algorithms + + self._Downloader.start() + + self._DownloaderTimer = gobject.timeout_add(100, self.GObjectUpdateProcessInterval) + + + +class UpdateConfirmPage(ConfirmPage): + _ConfirmText = "Confirm Update ?" + + _DownloadPage = None + + _URL = "" + _MD5 = "" + _Version = "" + _GIT = False + + def KeyDown(self,event): + if event.key == CurKeys["Menu"] or event.key == CurKeys["A"]: + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["B"]: + if self._GIT == True: + cmdpath = "cd /home/cpi/apps/launcher ;git pull " + pygame.event.post( pygame.event.Event(RUNEVT, message=cmdpath)) + self._GIT = False + return + + if self._DownloadPage == None: + self._DownloadPage = UpdateDownloadPage() + self._DownloadPage._Screen = self._Screen + self._DownloadPage._Name = "Downloading..." + self._DownloadPage.Init() + + self._DownloadPage._MD5 = self._MD5 + self._Screen.PushPage(self._DownloadPage) + self._Screen.Draw() + self._Screen.SwapAndShow() + + if self._URL != None and validators.url(self._URL): + self._DownloadPage.StartDownload(self._URL, "/tmp") + else: + print "error url %s " % self._URL + + + def OnReturnBackCb(self): + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + def Draw(self): + self.ClearCanvas() + self.DrawBG() + for i in self._MyList: + i.Draw() + + self.Reset() + + +class InfoPageListItem(object): + _PosX = 0 + _PosY = 0 + _Width = 0 + _Height = 30 + + _Labels = {} + _Icons = {} + _Fonts = {} + + _LinkObj = None + + 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): + + #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._Height - self._Labels["Text"]._Height)/2 + self._Labels["Text"].Draw() + + if "Small" in self._Labels: + self._Labels["Small"]._PosX = self._Width - self._Labels["Small"]._Width-5 + + 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 UpdatePage(Page): + _Icons = {} + _FootMsg = ["Nav.","Check Update","","Back",""] + + _ListFontObj = fonts["varela15"] + _ConfirmPage = None + _AList = {} + _MyList = [] + + def __init__(self): + Page.__init__(self) + self._Icons = {} + + def GenList(self): + + start_x = 0 + start_y = 0 + + for i,v in enumerate( self._AList): + li = InfoPageListItem() + li._Parent = self + li._PosX = start_x + li._PosY = start_y + i*InfoPageListItem._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): + self._CanvasHWND = self._Screen._CanvasHWND + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + self._ConfirmPage = UpdateConfirmPage() + self._ConfirmPage._Screen = self._Screen + self._ConfirmPage._Name = "Update Confirm" + self._ConfirmPage._Parent = self + self._ConfirmPage.Init() + + it = {} + it["key"] = "version" + it["label"] = "Version" + it["value"] = config.VERSION + self._AList["version"] = it + + self.GenList() + + def CheckUpdate(self): + self._Screen._MsgBox.SetText("Checking update...") + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() + + try: + r = requests.get(config.UPDATE_URL, verify=False, timeout=8) + except: + print("requests get error") + return + else: + if r.status_code == requests.codes.ok: + try: + json_ = r.json() + + if "version" in json_ and "updatepath" in json_ and "md5sum" in json_: + if config.VERSION != json_["version"]: + + self._ConfirmPage._URL = json_["updatepath"] + self._ConfirmPage._MD5 = json_["md5sum"] + self._ConfirmPage._GIT = False + + self._Screen.PushPage(self._ConfirmPage) + + self._Screen.Draw() + self._ConfirmPage.SnapMsg("Confirm Update to %s ?" % json_["version"] ) + self._Screen.SwapAndShow() + + elif "gitversion" in json_: ### just use git to run update + if confirm.VERSION != json_["gitversion"]: + self._ConfirmPage._URL = None + self._ConfirmPage._MD5 = None + self._ConfirmPage._GIT = True + + self._Screen.PushPage(self._ConfirmPage) + + self._Screen.Draw() + self._ConfirmPage.SnapMsg("Update to %s ?" % json_["gitversion"] ) + self._Screen.SwapAndShow() + + return True + except: + print("r.json error") + + else: + print(" requests get error %d ", r.status_code) + + + return False + + def OnLoadCb(self): + pass + + def KeyDown(self,event): + if event.key == CurKeys["Menu"] or event.key == CurKeys["A"]: + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["X"]: + if self.CheckUpdate() == True: + self._Screen.Draw() + self._Screen.SwapAndShow() + else: + self._Screen.Draw() + self._Screen._MsgBox.SetText("Checking update failed") + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() + + def Draw(self): + self.ClearCanvas() +# self._Ps.Draw() + + for i in self._MyList: + i.Draw() + + +class APIOBJ(object): + + _UpdatePage = None + def __init__(self): + pass + def Init(self,main_screen): + self._UpdatePage = UpdatePage() + + self._UpdatePage._Screen = main_screen + self._UpdatePage._Name ="Update" + self._UpdatePage.Init() + + def API(self,main_screen): + if main_screen !=None: + main_screen.PushPage(self._UpdatePage) + 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/Wifi/__init__.py b/Menu/GameShell/10_Settings/Wifi/__init__.py new file mode 100644 index 0000000..4341f8e --- /dev/null +++ b/Menu/GameShell/10_Settings/Wifi/__init__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + + +## local UI import +import pages +import myvars +""" +try: + from icons import preload +except: + print("No icons package") +""" +from icons import preload + +def Init(main_screen): + + preload.load_icons() + pages.InitPasswordPage(main_screen) + pages.InitScanPage(main_screen) + +def API(main_screen): + + if main_screen != None: + main_screen.PushCurPage() + main_screen.SetCurPage(myvars.ScanPage) + main_screen.Draw() + main_screen.SwapAndShow() + + diff --git a/Menu/GameShell/10_Settings/Wifi/icons/_L.png b/Menu/GameShell/10_Settings/Wifi/icons/_L.png new file mode 100644 index 0000000000000000000000000000000000000000..58a2e95f39e23c3547581aa399cd29e47c07844f GIT binary patch literal 306 zcmV-20nPr2P)=rxEIb_Of4un`0a>1@_o5KBR@%nf)0LPW7q z(PDSVlFaV1UA}70nQz`XGiQcrQwx$Lsq-CU9%uL|PNZoHW@`W)++Zz_FENZ6t3W&G zVI_}W@m^+*fo5=x{jvNq?(mn#3%JKc4Aj9DwjvuWVs|XJ89?nq@(|A@kTSKxAXIdM z(*}T`?=Warxtb_|y0W8vHC#UztLPjXcxnI&9h~Ue0Ndj2|G=Zk_D4bRiv!%EZ}cGF zuve_2sH)3;kiG7gJYL08nYr$-4X}>IF0oneEP)z_v=D4X1VIqRVnx_X*gKdDSbIUVv==*TVX;^d zEhd3soF4}p{UGGzBzZYM34cuqq-k3A_i%z4u9^T@mVvpN{Y6}0hoy*f{(;n7wfXCuSOfC5VBx(zHII04@cL2cx zu5nrh{aO(;-|^lXj&T_svDlv-Ah#-t9YJTlx4)025~Q{LqcEZpJQYAM*p)xbO4Sv6 s8Ee6Qz)lmS7*SbMdAc+CfBT2}0<9V*pAHvlegFUf07*qoM6N<$f=_LBc>n+a literal 0 HcmV?d00001 diff --git a/Menu/GameShell/10_Settings/Wifi/icons/done.png b/Menu/GameShell/10_Settings/Wifi/icons/done.png new file mode 100644 index 0000000000000000000000000000000000000000..ceeadbf8a0767c544fe2978ce54e740741886be1 GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@RheUQZXt5R2Zkmwow~6$IKIieHXf zw*BI+7lqHvd~Fu#*qPr5_`}&F?HOTMdB~inV7KbaOKfqI);S*Fa5-R=KS|&aM@?h9 zbyS%!OJUON!?mVEGc4(rULdfsKv-Q#V_LR*z*^_n)sT4&2i{vFs*m wSnr#CQEj2hlQ^=EcYoY&^0n+=;JZCy&kY%#TO8T61?VsaPgg&ebxsLQ0E|^l!2kdN literal 0 HcmV?d00001 diff --git a/Menu/GameShell/10_Settings/Wifi/icons/lock.png b/Menu/GameShell/10_Settings/Wifi/icons/lock.png new file mode 100644 index 0000000000000000000000000000000000000000..1e9ac7a0fbcab90e45dc6a0c27d79ac42dd21851 GIT binary patch literal 335 zcmV-V0kHmwP)LvUMR1mWj6B9wf#K19_ zUYu>W_Xm8?FxB);ItP5kKFXN++8ykHO5M1GUz 2: + if LayoutIndex in self._Secs: + self._Secs[LayoutIndex].append(i) + else: + self._Secs[LayoutIndex] = [] + self._Secs[LayoutIndex].append(i) + else: + LayoutIndex+=1 + + def SetPassword(self,pwd): + + pwd_list = list(pwd) + self._Textarea.ResetMyWords() + for i in pwd_list: + self._Textarea.AppendText(i) + #self._Textarea.BlitText() + + def Init(self): + self._CanvasHWND = self._Screen._CanvasHWND + self.ReadLayoutFile(self._KeyboardLayoutFile) ## assign to _Secs + self._SectionNumbers = len(self._Secs) + self._PosX = self._Index*self._Screen._Width + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + fontobj = fonts["veramono24"] + word_margin = 15 + + start_x = (self._Width - fontobj.size( "".join(self._Secs[0][0]))[0]-len(self._Secs[0][0])*word_margin)/2+word_margin/2 + start_y = 0 + cnt = 0 + for i in range(0,self._SectionNumbers): + self._SecsKeys[i] = [] + for j in range(0,len(self._Secs[i])): + self._SecsKeys[i].append( [] ) + + start_x = (self._Width - fontobj.size( "".join(self._Secs[i][j]))[0]-len(self._Secs[i][j])*word_margin)/2+word_margin/2 + start_x = start_x + i*Width + start_y = 84+j*(word_margin+14) + for idx,val in enumerate(self._Secs[i][j]): + ti = TextItem() + ti._FontObj = fontobj + ti._Parent = self + + if val == "_L" or val == "_R": + it = KeyboardIcon() + it._ImgSurf = preload.ICONS_PRELOAD[val] + it._Parent = self + it._Str = val + it.Init(start_x+it._ImgSurf.get_width()/2 ,start_y,it._ImgSurf.get_width(),it._ImgSurf.get_height(),0) + #self._Icons[val] = it + self._SecsKeys[i][j].append(it) + self._IconNumbers+=1 + start_x = start_x + it._ImgSurf.get_width()+word_margin + + else: + if val == "_S": + val = "Space" + ti._FontObj = fonts["veramono15"] + ti._Bold = True + + cur_alpha_size = ti._FontObj.size( val) + ti.Init(start_x + cur_alpha_size[0]/2,start_y,cur_alpha_size[0],cur_alpha_size[1],0) + ti._Str = val + + start_x = start_x + cur_alpha_size[0]+word_margin # prepare for next alpha + self._SecsKeys[i][j].append(ti) + + self._SectionIndex = 0 + + self._Textarea = Textarea() + + self._Textarea._PosX = 4 + self._Textarea._PosY = 4 + self._Textarea._Width= self._Width - 4*2 + self._Textarea._Height = 60 + self._Textarea._CanvasHWND = self._CanvasHWND + self._Textarea.Init() + + + ps = KeyboardSelector() + ps._Parent = self + ps.Init(start_x,start_y,25,25,128) + self._Ps = ps + self._PsIndex = 0 + self._Ps._OnShow = True + + def SelectUpChar(self): + sec_idx = self._SectionIndex + self._RowIndex-=1 + if self._RowIndex <0: + self._RowIndex = len(self._SecsKeys[sec_idx])-1 + + if self._PsIndex >=len(self._SecsKeys[sec_idx][self._RowIndex]): + self._PsIndex = len(self._SecsKeys[sec_idx][self._RowIndex])-1 + + + self.ClearCanvas() + self.Draw() + self._Screen.SwapAndShow() + + def SelectDownChar(self): + sec_idx = self._SectionIndex + self._RowIndex+=1 + if self._RowIndex >= len(self._SecsKeys[sec_idx]): + self._RowIndex = 0 + + if self._PsIndex >=len(self._SecsKeys[sec_idx][self._RowIndex]): + self._PsIndex = len(self._SecsKeys[sec_idx][self._RowIndex])-1 + + self.ClearCanvas() + self.Draw() + self._Screen.SwapAndShow() + + def SelectNextChar(self): + sec_idx = self._SectionIndex + row_idx = self._RowIndex + self._PsIndex+=1 + if self._PsIndex >= len(self._SecsKeys[sec_idx][row_idx]): + self._PsIndex = 0 + self._RowIndex+=1 + if self._RowIndex >= len(self._SecsKeys[sec_idx]): + self._RowIndex = 0 + + self.ClearCanvas() + self.Draw() + self._Screen.SwapAndShow() + + def SelectPrevChar(self): + sec_idx = self._SectionIndex + self._PsIndex-=1 + if self._PsIndex < 0: + self._RowIndex-=1 + if self._RowIndex <=0: + self._RowIndex = len(self._SecsKeys[sec_idx])-1 + self._PsIndex = len(self._SecsKeys[sec_idx][self._RowIndex]) -1 + + self.ClearCanvas() + self.Draw() + self._Screen.SwapAndShow() + + def ClickOnChar(self): + sec_idx = self._SectionIndex + alphabet = self._SecsKeys[sec_idx][self._RowIndex][self._PsIndex]._Str + + if alphabet == "Space": + alphabet = " " + + if alphabet == "_L" or alphabet == "_R": + if alphabet == "_L": + self._Textarea.SubTextIndex() + elif alphabet == "_R": + self._Textarea.AddTextIndex() + else: + self._Textarea.AppendText(alphabet) + + self._Textarea.Draw() + self._Screen.SwapAndShow() + + + def KeyboardShift(self): + current_time = 0.0 + start_posx = 0.0 + current_posx = start_posx + final_posx = 320.0 + posx_init = 0.0 + dur = 30 + last_posx = 0.0 + all_last_posx = [] + + 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: + for j in range(0,self._SectionNumbers): + for u in self._SecsKeys[j]: + for x in u: + x._PosX += self._LeftOrRight*i + + self.ResetPageSelector() + self.ClearCanvas() + self.Draw() + self._Screen.SwapAndShow() + + def KeyDown(self,event):# event from pygame.event.get() + if event.key == CurKeys["Up"]: + self.SelectUpChar() + if event.key == CurKeys["Down"]: + self.SelectDownChar() + if event.key == CurKeys["Right"]: + self.SelectNextChar() + if event.key == CurKeys["Left"]: + self.SelectPrevChar() + if event.key == CurKeys["B"] or event.key == CurKeys["Enter"]: + self.ClickOnChar() + if event.key == CurKeys["X"]: + if self._SectionIndex <= 0: + self._LeftOrRight = -1 + if self._SectionIndex >= (self._SectionNumbers -1): + self._LeftOrRight = 1 + self.KeyboardShift() + + self._SectionIndex -= self._LeftOrRight + + #print(self._SectionIndex) # on which keyboard section now + self.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Menu"]: # we assume keyboard always be child page + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Y"]: #done + print("".join(self._Textarea._MyWords)) + self.ReturnToUpLevelPage() + self._Screen.SwapAndShow() + ## config and connect now + myvars.ScanPage.ConfigWireless( "".join(self._Textarea._MyWords)) + + if event.key == CurKeys["A"]: + self._Textarea.RemoveFromLastText() + self._Textarea.Draw() + self._Screen.SwapAndShow() + + def Draw(self): + self.ClearCanvas() + for i in range(0,self._SectionNumbers): + for j in self._SecsKeys[i]: + for u in j: + u.Draw() + + + self._Textarea.Draw() + self._Ps.Draw() + + diff --git a/Menu/GameShell/10_Settings/Wifi/myvars.py b/Menu/GameShell/10_Settings/Wifi/myvars.py new file mode 100644 index 0000000..987456c --- /dev/null +++ b/Menu/GameShell/10_Settings/Wifi/myvars.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- + + +ScanPage = None +PasswordPage = None diff --git a/Menu/GameShell/10_Settings/Wifi/net_item.py b/Menu/GameShell/10_Settings/Wifi/net_item.py new file mode 100644 index 0000000..defdc83 --- /dev/null +++ b/Menu/GameShell/10_Settings/Wifi/net_item.py @@ -0,0 +1,199 @@ +# -*- coding: utf-8 -*- + +import pygame + +## local UI import +from UI.page import Page +from UI.label import Label +from UI.fonts import fonts +from UI.icon_item import IconItem +from UI.multi_icon_item import MultiIconItem + +from icons import preload + +class NetItemMultiIcon(MultiIconItem): + _CanvasHWND = None + _Parent = None + _Width = 18 + _Height = 18 + + def Draw(self): + self._CanvasHWND.blit(self._ImgSurf,(self._PosX,self._PosY+(self._Parent._Height-self._Height)/2,self._Width,self._Height), + (0,self._IconIndex*self._IconHeight,self._IconWidth,self._IconHeight)) + +class NetItemIcon(IconItem): + + _CanvasHWND = None + _Parent = None + _Width = 18 + _Height = 18 + + def Draw(self): + self._CanvasHWND.blit(self._ImgSurf,(self._PosX,self._PosY+(self._Parent._Height-self._Height)/2,self._Width,self._Height)) + + +class NetItem(object): + _PosX = 0 + _PosY = 0 + _Width = 0 + _Height = 30 + + _Bssid="" # 50:3A:A0:51:18:3C + _Essid="" # MERCURY_EB88 + + ## extra infomations + _dhcphostname = "GameShell" + _ip = None #eg 192.168.31.141 + _dns_domain = None + _gateway = None #eg 192.168.31.1 + _use_global_dns = 0 ## eg 0 == False, 1 == True + _netmask = None ##eg 255.255.255.0 + _usedhcphostname= 0 + _bitrate = "auto" + _allow_lower_bitrates = 0 + _dns3 = None + _dns2 = None ## eg 1.1.1.1 + _dns1 = None ## eg 8.8.8.8 + _use_settings_globally = 0 + _use_static_dns = 0 # eg: 1 == True + _search_domain = None + + _Encrypt="" # WPA2 + _Channel="" # '10' + _Stren = "" ## 19% + _NetId = 0 ## 0-n + _Mode = "" ## Master or AdHoc + _Parent = None + _IsActive = False + + _Icons = {} ## wifi strength and security icons + _Labels = {} + _FontObj = None + + def __init__(self): + self._Labels = {} + self._Icons = {} + + def SetActive(self,act): + self._IsActive = act + + def UpdateStrenLabel(self, strenstr): ## strenstr should be 'number',eg:'90' + self._Stren = self._Parent._Daemon.FormatSignalForPrinting(strenstr) + self._Labels["stren"]._Text = self._Stren + + def Init(self, i, is_active): + # Pick which strength measure to use based on what the daemon says + # gap allocates more space to the first module + if self._Parent._Daemon.GetSignalDisplayType() == 0: + strenstr = 'quality' + gap = 4 # Allow for 100% + else: + strenstr = 'strength' + gap = 7 # -XX dbm = 7 + self._NetId = i + # All of that network property stuff + self._Stren = self._Parent._Daemon.FormatSignalForPrinting( + str(self._Parent._Wireless.GetWirelessProperty(self._NetId, strenstr))) + + self._Essid = self._Parent._Wireless.GetWirelessProperty(self._NetId, 'essid') + self._Bssid = self._Parent._Wireless.GetWirelessProperty(self._NetId, 'bssid') + + if self._Parent._Wireless.GetWirelessProperty(self._NetId, 'encryption'): + self._Encrypt = \ + self._Parent._Wireless.GetWirelessProperty(self._NetId, 'encryption_method') + else: + self._Encrypt = 'Unsecured' + + self._Mode = \ + self._Parent._Wireless.GetWirelessProperty(self._NetId, 'mode') # Master, Ad-Hoc + self._Channel = self._Parent._Wireless.GetWirelessProperty(self._NetId, 'channel') + theString = ' %-*s %25s %9s %17s %6s %4s' % \ + (gap, self._Stren, self._Essid, self._Encrypt, self._Bssid, self._Mode, + self._Channel) + + if is_active: + theString = ">> "+theString[1:] + self.SetActive(is_active) + + + + essid_label = Label() + essid_label._PosX = 36 + #essid_label._PosY = self._PosY + (self._Height - self._FontObj.render(self._Essid,True,(83,83,83)).get_height())/2 + essid_label._CanvasHWND = self._Parent._CanvasHWND + + if len(self._Essid) > 19: + essid_ = self._Essid[:20] + else: + essid_ = self._Essid + + essid_label.Init(essid_,self._FontObj) + self._Labels["essid"] = essid_label + + stren_label = Label() + #stren_label._PosY = self._PosY + (self._Height - self._FontObj.render(self._Stren,True,(83,83,83)).get_height())/2 + stren_label._CanvasHWND = self._Parent._CanvasHWND + + stren_label.Init(self._Stren,self._FontObj) + stren_label._PosX = self._Width - 23 - stren_label.Width() - 2 + self._Labels["stren"] = stren_label + + + lock_icon = NetItemIcon() + lock_icon._ImgSurf = preload.ICONS_PRELOAD["lock"] + lock_icon._CanvasHWND = self._Parent._CanvasHWND + lock_icon._Parent = self + self._Icons["lock"] = lock_icon + + done_icon = NetItemIcon() + done_icon._ImgSurf = preload.ICONS_PRELOAD["done"] + done_icon._CanvasHWND = self._Parent._CanvasHWND + done_icon._Parent = self + + self._Icons["done"] = done_icon + + + ## reuse the resource from TitleBar + nimt = NetItemMultiIcon() + nimt._ImgSurf = self._Parent._Screen._TitleBar._Icons["wifistatus"]._ImgSurf + nimt._CanvasHWND = self._Parent._CanvasHWND + nimt._Parent = self + self._Icons["wifistatus"] = nimt + + #pp(theString) + + + def Connect(self,notworkentry=None): + """ Execute connection. """ + self._Parent._Wireless.ConnectWireless(self._NetId) + + + def Draw(self): + #pygame.draw.line(self._Parent._CanvasHWND,(169,169,169),(self._PosX,self._PosY),(self._PosX+self._Width,self._PosY),1) + for i in self._Labels: + self._Labels[i]._PosY = self._PosY + (self._Height - self._Labels[i]._Height)/2 + self._Labels[i].Draw() + + if self._IsActive: + self._Icons["done"].NewCoord(14,self._PosY) + self._Icons["done"].Draw() + + if self._Encrypt != "Unsecured": + self._Icons["lock"].NewCoord( self._Width -23 - self._Labels["stren"].Width() - 2 - 18, self._PosY) + self._Icons["lock"].Draw() + + ge = self._Parent._Screen._TitleBar.GetWifiStrength( self._Stren.replace('%','')) + + if ge > 0: + self._Icons["wifistatus"]._IconIndex = ge + self._Icons["wifistatus"].NewCoord(self._Width-23,self._PosY) + self._Icons["wifistatus"].Draw() + + else: + self._Icons["wifistatus"]._IconIndex = 0 + self._Icons["wifistatus"].NewCoord(self._Width-23,self._PosY) + self._Icons["wifistatus"].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) + + diff --git a/Menu/GameShell/10_Settings/Wifi/pages.py b/Menu/GameShell/10_Settings/Wifi/pages.py new file mode 100644 index 0000000..63970ae --- /dev/null +++ b/Menu/GameShell/10_Settings/Wifi/pages.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- + + +#import dbus +#import dbus.service +#from wicd import misc +##misc.to_bool +##misc.misc.noneToString +##misc.to_unicode +##misc.Noneify +#from wicd.translations import _ +#from wicd import wpath +#from wicd import dbusmanager + + +## local UI import +from libs.DBUS import bus,daemon,wireless,wired + +from keyboard import Keyboard +from wifi_list import WifiList + +import myvars + + +def InitScanPage(main_screen): + global wireless + global daemon + global bus + + myvars.ScanPage = WifiList() + myvars.ScanPage._Name = "Scan wifi" + + myvars.ScanPage._Wireless = wireless + myvars.ScanPage._Daemon = daemon + myvars.ScanPage._Dbus = bus + + + myvars.ScanPage._Screen = main_screen + myvars.ScanPage.Init() + + + if daemon != None: + #Bind signals + myvars.ScanPage._Dbus.add_signal_receiver(myvars.ScanPage.DbusScanFinishedSig, 'SendEndScanSignal', + 'org.wicd.daemon.wireless') + myvars.ScanPage._Dbus.add_signal_receiver(myvars.ScanPage.DbusScanStarted, 'SendStartScanSignal', + 'org.wicd.daemon.wireless') + # + myvars.ScanPage._Dbus.add_signal_receiver(myvars.ScanPage.DbusDaemonStatusChangedSig, 'StatusChanged', + 'org.wicd.daemon') + myvars.ScanPage._Dbus.add_signal_receiver(myvars.ScanPage.DbusConnectResultsSent, 'ConnectResultsSent', + 'org.wicd.daemon') + +def InitPasswordPage(main_screen): + + myvars.PasswordPage = Keyboard() + myvars.PasswordPage._Name = "Enter wifi password" + + myvars.PasswordPage._Screen = main_screen + myvars.PasswordPage.Init() + diff --git a/Menu/GameShell/10_Settings/Wifi/text_item.py b/Menu/GameShell/10_Settings/Wifi/text_item.py new file mode 100644 index 0000000..9b73d10 --- /dev/null +++ b/Menu/GameShell/10_Settings/Wifi/text_item.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +#local import +from UI.constants import Width,Height,ICON_TYPES +from UI.icon_item import IconItem +from UI.util_funcs import midRect + +class TextItem(IconItem): + _PosX = 0 + _PosY = 0 + _Width = 0 + _Height = 0 + _Str = "" + _Color = (83,83,83) + _FontObj = None + _Bold = False + _MyType = ICON_TYPES["LETTER"] + _Parent = None + + def Draw(self): + self._FontObj.set_bold(self._Bold) + my_text = self._FontObj.render(self._Str,True,self._Color) + if my_text.get_width() != self._Width: + self._Width = my_text.get_width() + if my_text.get_height() != self._Height: + self._Height = my_text.get_height() + + self._Parent._CanvasHWND.blit(my_text, \ + midRect(self._PosX,self._PosY,self._Width,self._Height,Width,Height)) diff --git a/Menu/GameShell/10_Settings/Wifi/textarea.py b/Menu/GameShell/10_Settings/Wifi/textarea.py new file mode 100644 index 0000000..0957264 --- /dev/null +++ b/Menu/GameShell/10_Settings/Wifi/textarea.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- + +import pygame +from libs.roundrects import aa_round_rect + + + + +## local UI import +from UI.page import Page,PageStack,PageSelector +from UI.label import Label +from UI.fonts import fonts + +class Textarea: + _PosX =0 + _PosY = 0 + _Width = 0 + _Height = 0 + _BackgroundColor = pygame.Color(229,229,229) + _CanvasHWND = None + _MyWords = [] + _FontObj = None + _LineNumber = 0 + _TextFull = False + _TextIndex = 0 + + def __init__(self): + pass + + def Init(self): + self._FontObj = fonts["veramono24"] + #pygame.font.Font(fonts_path["veramono"],24) + + def SubTextIndex(self): + + self._TextIndex-=1 + if self._TextIndex < 0: + self._TextIndex = 0 + + def AddTextIndex(self): + self._TextIndex +=1 + if self._TextIndex > len(self._MyWords): + self._TextIndex = len(self._MyWords) + + def ResetMyWords(self): + self._MyWords = [] + self._TextIndex = 0 + + def RemoveFromLastText(self): + if len(self._MyWords) > 0: + self.SubTextIndex() + + del self._MyWords[self._TextIndex] + + return self._MyWords + + def AppendText(self,alphabet): + + self.AppendAndBlitText(alphabet) + + def AppendAndBlitText(self,alphabet): + + if self._TextFull != True: + + self._MyWords.insert(self._TextIndex,alphabet) + self.BlitText() + self.AddTextIndex() + else: + print("is Full %s" % "".join(self._MyWords)) + + + def BlitText(self): + """ + blit every single word into surface and calc the width ,check multi line + """ + w = 0 + xmargin = 5 + endmargin = 15 + x = self._PosX+xmargin + y = self._PosY + linenumber = 0 + self._TextFull = False + for i,v in enumerate(self._MyWords): + t = self._FontObj.render(v,True,(8,135,174)) + w += t.get_width() + + if w >= self._Width-endmargin and linenumber == 0: + x = self._PosX+xmargin + y = self._PosY+ t.get_height() + w = 0 + linenumber +=1 + + if w >= self._Width-endmargin*4 and linenumber > 0: + self._TextFull = True + self._CanvasHWND.blit(t, (x,y)) + break + self._CanvasHWND.blit(t, (x,y)) + x += t.get_width() + + def Cursor(self): + w = 0 + xmargin = 5 + endmargin = 15 + x = self._PosX+xmargin + y = self._PosY + linenumber = 0 + for i,v in enumerate(self._MyWords[:self._TextIndex]): + t = self._FontObj.render(v,True,(8,135,174)) + w += t.get_width() + + if w >= self._Width-endmargin and linenumber == 0: + x = self._PosX+xmargin + y = self._PosY+ t.get_height() + w = 0 + linenumber +=1 + + if w >= self._Width-endmargin*3 and linenumber > 0: + x += t.get_width() + break + x += t.get_width() + + self._CanvasHWND.blit(self._FontObj.render("_",True,(0,0,0)),(x+1,y-2)) + + def Draw(self): + #aa_round_rect(self._CanvasHWND, (4,24.5+6,312,60),self._BackgroundColor,4,0,self._BackgroundColor) + + aa_round_rect(self._CanvasHWND, + (self._PosX,self._PosY,self._Width,self._Height),self._BackgroundColor,4,0,self._BackgroundColor) + + + + self.BlitText() + self.Cursor() diff --git a/Menu/GameShell/10_Settings/Wifi/wifi_list.py b/Menu/GameShell/10_Settings/Wifi/wifi_list.py new file mode 100644 index 0000000..9602794 --- /dev/null +++ b/Menu/GameShell/10_Settings/Wifi/wifi_list.py @@ -0,0 +1,820 @@ +# -*- coding: utf-8 -*- + +import pygame + +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 +from UI.page import Page,PageSelector +from UI.label import Label +from UI.fonts import fonts +from UI.util_funcs import midRect,SwapAndShow +from UI.keys_def import CurKeys +from UI.scroller import ListScroller +from UI.confirm_page import ConfirmPage + +from net_item import NetItem + +import myvars + + +class InfoPageListItem(object): + _PosX = 0 + _PosY = 0 + _Width = 0 + _Height = 30 + + _Labels = {} + _Icons = {} + _Fonts = {} + + _LinkObj = None + + 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): + + #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._Height - self._Labels["Text"]._Height)/2 + self._Labels["Text"].Draw() + + if "Small" in self._Labels: + self._Labels["Small"]._PosX = self._Width - self._Labels["Small"]._Width-5 + + 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 WifiDisconnectConfirmPage(ConfirmPage): + + _ConfirmText = "Confirm Disconnect?" + + def KeyDown(self,event): + if event.key == CurKeys["Menu"] or event.key == CurKeys["A"]: + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["B"]: + self.SnapMsg("Disconnecting...") + self._Screen.Draw() + self._Screen.SwapAndShow() + + self._Parent._Daemon.Disconnect() + + pygame.time.delay(400) + + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + + def Draw(self): + #self.ClearCanvas() + self.DrawBG() + for i in self._MyList: + i.Draw() + + self.Reset() + +class WifiInfoPageSelector(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 = 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 WifiInfoPage(Page): + _FootMsg = ["Nav.","Disconnect","","Back",""] + _MyList = [] + _ListFontObj = fonts["varela15"] + + _Wireless = None + _Daemon = None + + _AList = {} + _NetworkId = -1 + + def GenList(self): + + self._MyList = [] + if self._NetworkId != -1: + self._AList["ip"]["value"] = "Not Connected" + + if self._Wireless.GetCurrentNetworkID(self._Wireless.GetIwconfig()) == self._NetworkId: + ip = self._Wireless.GetWirelessIP('') + + if ip is not None: + self._AList["ip"]["value"] = ip + + self._AList["bssid"]["value"] = self._Wireless.GetWirelessProperty(self._NetworkId,"bssid") + + start_x = 0 + start_y = 0 + + for i,v in enumerate( self._AList): + li = InfoPageListItem() + li._Parent = self + li._PosX = start_x + li._PosY = start_y + i*InfoPageListItem._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 = WifiInfoPageSelector() + ps._Parent = self + self._Ps = ps + self._PsIndex = 0 + + ip = {} + ip["key"] = "ip" + ip["label"] = "IP" + ip["value"] = "Not Connected" + + bssid = {} + bssid["key"] = "bssid" + bssid["label"] = "BSSID" + bssid["value"] = "" + + self._AList["ip"] = ip + self._AList["bssid"] = bssid + + self.GenList() + + self._DisconnectConfirmPage = WifiDisconnectConfirmPage() + self._DisconnectConfirmPage._Screen = self._Screen + self._DisconnectConfirmPage._Name = "Confirm Disconnect" + self._DisconnectConfirmPage._Parent = self + self._DisconnectConfirmPage.Init() + + 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 TryDisconnect(self): + if self._Wireless.GetCurrentNetworkID(self._Wireless.GetIwconfig()) == self._NetworkId \ + and self._Wireless.GetWirelessIP('') is not None: + self._Screen.PushPage(self._DisconnectConfirmPage) + self._Screen.Draw() + self._Screen.SwapAndShow() + else: + return + + def OnLoadCb(self): + if self._Wireless.GetCurrentNetworkID(self._Wireless.GetIwconfig()) == self._NetworkId \ + and self._Wireless.GetWirelessIP('') is not None: + self._FootMsg[1] = "Disconnect" + else: + self._FootMsg[1] = "" + + self.GenList() + + 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["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["Enter"]: + self.Click() + + if event.key == CurKeys["X"]: + self.TryDisconnect() + + def Draw(self): + self.ClearCanvas() + self._Ps.Draw() + + for i in self._MyList: + i.Draw() + + + + +class WifiListSelector(PageSelector): + _BackgroundColor = pygame.Color(131,199,219) + + def __init__(self): + self._PosX = 0 + self._PosY = 0 + self._Height = 0 + + def AnimateDraw(self,x2,y2): + pass + + + def Draw(self): + idx = self._Parent._PsIndex + if idx < len( self._Parent._WirelessList): + x = self._Parent._WirelessList[idx]._PosX+11 + y = self._Parent._WirelessList[idx]._PosY+1 + h = self._Parent._WirelessList[idx]._Height -3 + + self._PosX = x + self._PosY = y + self._Height = h + + aa_round_rect(self._Parent._CanvasHWND, + (x,y,self._Width,h),self._BackgroundColor,4,0,self._BackgroundColor) + + +class WifiListMessageBox(Label): + _Parent = None + + def Draw(self): + my_text = self._FontObj.render( self._Text,True,self._Color) + w = my_text.get_width() + h = my_text.get_height() + x = (self._Parent._Width - w)/2 + y = (self._Parent._Height - h)/2 + padding = 10 + pygame.draw.rect(self._CanvasHWND,(255,255,255),(x-padding,y-padding, w+padding*2,h+padding*2)) + + pygame.draw.rect(self._CanvasHWND,(0,0,0),(x-padding,y-padding, w+padding*2,h+padding*2),1) + + self._CanvasHWND.blit(my_text,(x,y,w,h)) + +class WifiList(Page): + _WirelessList = [] + #Wicd dbus part + _Wireless = None + _Daemon = None + _Dbus = None + _WifiPassword = "" + _Connecting = False + _Scanning = False + + _PrevWicdState = None + + _Selector = None + + _ShowingMessageBox = False + _MsgBox = None + _ConnectTry = 0 + _BlockingUI = False + _BlockCb = None + + _LastStatusMsg = "" + _FootMsg = ["Nav.","Scan","Info","Back","Enter"] + _EncMethods = None + _Scroller = None + _ListFontObj = fonts["notosanscjk15"] + + _InfoPage = None + + def __init__(self): + Page.__init__(self) + self._WirelessList = [] + self._CanvasHWND = None + + def ShowBox(self,msg): + self._MsgBox._Text = msg + self._ShowingMessageBox = True + self._Screen.Draw() + self._MsgBox.Draw() + self._Screen.SwapAndShow() + + def HideBox(self): + self.Draw() + self._ShowingMessageBox = False + self._Screen.SwapAndShow() + + def GenNetworkList(self): + self._WirelessList = [] + start_x = 0 + start_y = 0 + + for network_id in range(0,self._Wireless.GetNumberOfNetworks()): + is_active = \ + self._Wireless.GetCurrentSignalStrength("") != 0 and \ + self._Wireless.GetCurrentNetworkID(self._Wireless.GetIwconfig()) == network_id \ + and self._Wireless.GetWirelessIP('') is not None + + ni = NetItem() + ni._Parent = self + ni._PosX = start_x + ni._PosY = start_y + network_id* NetItem._Height + ni._Width = Width + ni._FontObj = self._ListFontObj + #ni._Bssid = self._Wireless.GetWirelessProperty(network_id,"bssid") + + ni.Init(network_id,is_active) + self._WirelessList.append(ni) + + self._PsIndex = 0 + + def Disconnect(self): + self._Connecting= False + self._Daemon.Disconnect() + ## force to disconnect + def ShutDownConnecting(self): + print("Shutdownconnecting...",self._ConnectTry) + self._Daemon.CancelConnect() + self._Daemon.SetForcedDisconnect(True) + self._Connecting = False + + def Rescan(self,sync=False): + print("start Rescan") + if self._Wireless != None: + self._Wireless.Scan(sync) + +## dbus signal functions + def DbusScanFinishedSig(self): + + if self._Screen._CurrentPage != self: + return + self.ResetPageSelector() + + self.UpdateNetList(force_check=True) + + self._Scanning = False + self.HideBox() + self._BlockingUI = False + print("dbus says scan finished") + + def DbusScanStarted(self): + if self._Screen._CurrentPage !=self: + return + + self._Scanning = True + self.ShowBox("Wifi scanning...") + self._BlockingUI = True + print("dbus says start scan...") + + + def UpdateNetList(self,state=None,info=None,force_check=False,firstrun=False): + + if self._Daemon == None: + return + + if not state: + state,trash = self._Daemon.GetConnectionStatus() + print("state") + pp(state) + print("Trash: ") + pp(trash) + + if force_check or self._PrevWicdState != state: + self.GenNetworkList() ## refresh the network list + + if info != None: + if len(info) > 3: + _id = int(info[3]) + if _id < len(self._WirelessList): + self._WirelessList[_id].UpdateStrenLabel( str(info[2])) + + self._PrevWicdState = state + + def SetConnectingStatus(self,fast): + wireless_connecting = self._Wireless.CheckIfWirelessConnecting() + + """ + if self._ConnectTry > 5000: + #wicd itself will take a very long time to try to connect ,will not block forever,just make it faster to dropout + self.ShutDownConnecting() + self._ConnectTry = 0 + self._BlockingUI = False + return False + """ + + if wireless_connecting: + if not fast: + iwconfig = self._Wireless.GetIwconfig() + else: + iwconfig = '' + essid = self._Wireless.GetCurrentNetwork(iwconfig) + stat = self._Wireless.CheckWirelessConnectingMessage() + if self._LastStatusMsg != "%s: %s"%(essid,stat): + print("%s: %s" %(essid,stat)) + self._LastStatusMsg = "%s: %s"%(essid,stat) + self.ShowBox(self._LastStatusMsg) + + self._Screen._FootBar.UpdateNavText(self._LastStatusMsg) + SwapAndShow() + + #self._ConnectTry+=1 + + return True + else: + self._Connecting = False + return self._Connecting + + def UpdateStatus(self): + print("UpdateStatus") + wireless_connecting = self._Wireless.CheckIfWirelessConnecting() + fast = not self._Daemon.NeedsExternalCalls() + + self._Connecting = wireless_connecting + + if self._Connecting: + gobject.timeout_add(250,self.SetConnectingStatus,fast) + else: + if not fast: + iwconfig = self._Wireless.GetIwconfig() + else: + iwconfig = '' + + if self.CheckForWireless(iwconfig,self._Wireless.GetWirelessIP(''),None): + return True + else: + print("Not Connected") + return True + + def DbusDaemonStatusChangedSig(self,state=None,info=None): + print("in DbusDaemonStatusChangedSig") + """ + dbus.UInt32(2L) + ['192.168.31.141', 'TP-LINK4G', '88', '0', '72.2 Mb/s'] + """ + pp(info) + self.UpdateNetList(state,info) + if info != None: + self._Screen.Draw() + self._Screen.SwapAndShow() + + + def DbusConnectResultsSent(self,result): + print(" in DbusConnectResultsSent") + """ + in DbusConnectResultsSent + 'dhcp_failed' + dbus says start scan... + + """ + if result != None: + print(result) + + self._Connecting = False + self._BlockingUI = False + if self._BlockCb != None: + self._BlockCb() + self._BlockCb = None + + self._Screen._FootBar.ResetNavText() + + def CheckForWireless(self,iwconfig,wireless_ip,set_status): + if not wireless_ip: + return False + network = self._Wireless.GetCurrentNetwork(iwconfig) + if not network: + return False + network = misc.to_unicode(network) + if daemon.GetSignalDisplayType() == 0: + strength = self._Wireless.GetCurrentSignalStrength(iwconfig) + else: + strength = self._Wireless.GetCurrentDBMStrength(iwconfig) + + if strength is None: + return False + strength = misc.to_unicode(self._Daemon.FormatSignalForPrinting(strength)) + ip = misc.to_unicode(wireless_ip) + + print(_('Connected to $A at $B (IP: $C)').replace + ('$A', network).replace + ('$B', strength).replace + ('$C', ip)) + + return True + + def ConfigWireless(self,password): + netid = self._PsIndex + print(netid," ", password) + """ + self._Wireless.SetWirelessProperty(netid,"dhcphostname","GameShell") + self._Wireless.SetWirelessProperty(netid,"ip","None") + self._Wireless.SetWirelessProperty(netid,"dns_domain","None") + self._Wireless.SetWirelessProperty(netid,"gateway","None") + self._Wireless.SetWirelessProperty(netid,"use_global_dns",0) + self._Wireless.SetWirelessProperty(netid,"netmask","None") + self._Wireless.SetWirelessProperty(netid,"usedhcphostname",0) ## set 1 to use hostname above + self._Wireless.SetWirelessProperty(netid,"bitrate","auto") + self._Wireless.SetWirelessProperty(netid,"allow_lower_bitrates",0) + self._Wireless.SetWirelessProperty(netid,"dns3","None") + self._Wireless.SetWirelessProperty(netid,"dns2","None") + self._Wireless.SetWirelessProperty(netid,"dns1","None") + self._Wireless.SetWirelessProperty(netid,"use_settings_globally",0) + self._Wireless.SetWirelessProperty(netid,"use_static_dns",0) + self._Wireless.SetWirelessProperty(netid,"search_domain","None") + """ + self._Wireless.SetWirelessProperty(netid,"enctype","wpa-psk") + self._Wireless.SetWirelessProperty(netid,"apsk",password) + self._Wireless.SetWirelessProperty(netid,"automatic",1) + + + self._WirelessList[netid].Connect() + print("after Connect") + self.UpdateStatus() + + def GetWirelessEncrypt(self,network_id): + results = [] + activeID = -1 + for x,enc_type in enumerate(self._EncMethods): + if enc_type["type"] == self._Wireless.GetWirelessProperty(network_id,"enctype"): + activeID = x + break + + if activeID == -1: + return results + + for type_ in ['required','optional']: + fields = self._EncMethods[activeID][type_] + for field in fields: + try: + text = field[1].lower().replace(' ','_') + except KeyError: + text = field[1].replace(' ','_') + + value = self._Wireless.GetWirelessProperty(network_id, field[0]) + results.append({text:value}) + """ + [{'preshared_key': 'blah blah blah',},] + + or nothing + [{'identity': None,},{'password': None,},] + + """ + return results + + def ScrollUp(self): + if len(self._WirelessList) == 0: + return + self._PsIndex-=1 + if self._PsIndex < 0: + self._PsIndex = 0 + + cur_ni = self._WirelessList[self._PsIndex] + if cur_ni._PosY < 0: + for i in range(0,len(self._WirelessList)): + self._WirelessList[i]._PosY += self._WirelessList[i]._Height + + def ScrollDown(self): + if len(self._WirelessList) == 0: + return + self._PsIndex+=1 + if self._PsIndex >= len(self._WirelessList): + self._PsIndex = len(self._WirelessList) -1 + + cur_ni = self._WirelessList[self._PsIndex] + if cur_ni._PosY + cur_ni._Height > self._Height: + for i in range(0,len(self._WirelessList)): + self._WirelessList[i]._PosY -= self._WirelessList[i]._Height + + + def AbortedAndReturnToUpLevel(self): + self.HideBox() + self._Screen._FootBar.ResetNavText() + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + def KeyDown(self,event): + + if self._BlockingUI == True: + print("UI blocking ...") + return + + if event.key == CurKeys["A"] or event.key == CurKeys["Menu"]: + if self._Wireless != None: + wireless_connecting = self._Wireless.CheckIfWirelessConnecting() + if wireless_connecting: + self.ShutDownConnecting() + self.ShowBox("ShutDownConnecting...") + self._BlockingUI=True + self._BlockCb = self.AbortedAndReturnToUpLevel + else: + self.AbortedAndReturnToUpLevel() + else: + self.HideBox() + 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() + + if event.key == CurKeys["Enter"]: ## enter to set password,enter is B on GM + if len(self._WirelessList) == 0: + return + + wicd_wirelss_encrypt_pwd = self.GetWirelessEncrypt(self._PsIndex) + + if self._WirelessList[self._PsIndex]._IsActive: + self.ShowBox( self._Wireless.GetWirelessIP('') ) + else: + self._Screen.PushCurPage() + self._Screen.SetCurPage( myvars.PasswordPage ) + + thepass = "" + for i in wicd_wirelss_encrypt_pwd: + if "preshared_key" in i: + if i["preshared_key"] != None: + if len(i["preshared_key"]) > 0: + thepass = i["preshared_key"] + break + + myvars.PasswordPage.SetPassword(thepass) + self._Screen.Draw() + self._Screen.SwapAndShow() + + """ + try: + self._Screen.Draw() + self._Screen.SwapAndShow() + except Exception as e: + print(e) + exit(-1) + """ + if event.key == CurKeys["X"]: + self.Rescan(False) + + if event.key == CurKeys["Y"]: + if len(self._WirelessList) == 0: + return + + self._InfoPage._NetworkId = self._PsIndex + self._InfoPage._Wireless = self._Wireless + self._InfoPage._Daemon = self._Daemon + + self._Screen.PushPage(self._InfoPage) + self._Screen.Draw() + self._Screen.SwapAndShow() + + + def Init(self): + + self._PosX = self._Index * self._Screen._Width + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + #self._CanvasHWND = pygame.Surface((self._Width,self._Height)) + self._CanvasHWND = self._Screen._CanvasHWND + + ps = WifiListSelector() + ps._Parent = self + ps._Width = Width - 12 + + self._Ps = ps + self._PsIndex = 0 + + msgbox = WifiListMessageBox() + msgbox._CanvasHWND = self._CanvasHWND + msgbox.Init(" ",fonts["veramono12"]) + msgbox._Parent = self + + self._MsgBox = msgbox + + self._EncMethods = misc.LoadEncryptionMethods() # load predefined templates from /etc/wicd/... + + """ + { + 'fields': [], + 'name': 'WPA 1/2 (Passphrase)', + 'optional': [], + 'protected': [ + ['apsk', 'Preshared_Key'], + ], + 'required': [ + ['apsk', 'Preshared_Key'], + ], + 'type': 'wpa-psk', + }, + """ + + self.UpdateNetList(force_check=True,firstrun=True) + + self._Scroller = ListScroller() + self._Scroller._Parent = self + self._Scroller._PosX = 2 + self._Scroller._PosY = 2 + self._Scroller.Init() + + + self._InfoPage = WifiInfoPage() + self._InfoPage._Screen = self._Screen + self._InfoPage._Name = "Wifi info" + self._InfoPage.Init() + + def Draw(self): + self.ClearCanvas() + + if len(self._WirelessList) == 0: + return + + self._Ps.Draw() + for i in self._WirelessList: + i.Draw() + + + self._Scroller.UpdateSize( len(self._WirelessList)*NetItem._Height, self._PsIndex*NetItem._Height) + self._Scroller.Draw() diff --git a/Menu/GameShell/10_Settings/__init__.py b/Menu/GameShell/10_Settings/__init__.py new file mode 100644 index 0000000..76b04b0 --- /dev/null +++ b/Menu/GameShell/10_Settings/__init__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +import pygame +from pygame.locals import * +from sys import exit +import os +import sys + +from datetime import datetime + +import base64 +from beeprint import pp + + +## local UI import +import pages +import myvars + +def Init(main_screen): + pages.InitListPage(main_screen) + +def API(main_screen): + + if main_screen !=None: + main_screen.PushCurPage() + main_screen.SetCurPage(myvars.ListPage) + main_screen.Draw() + main_screen.SwapAndShow() + diff --git a/Menu/GameShell/10_Settings/list_item.py b/Menu/GameShell/10_Settings/list_item.py new file mode 100644 index 0000000..4050d96 --- /dev/null +++ b/Menu/GameShell/10_Settings/list_item.py @@ -0,0 +1,59 @@ +# -*- coding: utf-8 -*- + +import pygame + + + +## local UI import +from UI.page import Page +from UI.label import Label +from UI.fonts import fonts + +# a item for List +# - - - - - - - - - - - -- +# | Icon Text..... > | +# ------------------------ + +import myvars # icons_path + + +class ListItem(object): + _PosX = 0 + _PosY = 0 + _Width = 0 + _Height = 30 + + _Labels = {} + _Icons = {} + _Fonts = {} + + _LinkObj = None + + def __init__(self): + self._Labels = {} + self._Icons = {} + self._Fonts = {} + + + + + def Init(self,text): + + #self._Fonts["normal"] = fonts["veramono12"] + + l = Label() + l._PosX = 16 + 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 + self._Labels["Text"].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) + + diff --git a/Menu/GameShell/10_Settings/list_page.py b/Menu/GameShell/10_Settings/list_page.py new file mode 100644 index 0000000..430ba51 --- /dev/null +++ b/Menu/GameShell/10_Settings/list_page.py @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- + +import pygame +import sys + +from libs.roundrects import aa_round_rect + +## local UI import +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.keys_def import CurKeys +from UI.scroller import ListScroller + +from list_item import ListItem + +import myvars + +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 = 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 ListPage(Page): + + _Icons = {} + _Selector=None + + _FootMsg = ["Nav","","","Back","Enter"] + _MyList = [] + _ListFontObj = fonts["varela15"] + + _Scroller = None + + def __init__(self): + Page.__init__(self) + self._Icons = {} + self._CanvasHWND = None + self._MyList = [] + + def Init(self): + self._PosX = self._Index * self._Screen._Width + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + self._CanvasHWND = self._Screen._CanvasHWND + + ps = ListPageSelector() + ps._Parent = self + self._Ps = ps + self._PsIndex = 0 + + # "" pkgname, label + alist = [["","Wifi","Wi-Fi"], + ["","Sound","Sound Volume"], + ["","Brightness","BackLight Brightness"], + ["","Storage",""], + ["","Update", ""], + ["","About", "About"], + ["","PowerOFF","PowerOFF"]] + + start_x = 0 + start_y = 0 + + sys.path.append(myvars.basepath)# add self as import path + + for i,v in enumerate(alist): + li = ListItem() + li._Parent = self + li._PosX = start_x + li._PosY = start_y + i*ListItem._Height + li._Width = Width + li._Fonts["normal"] = self._ListFontObj + + if v[2] != "": + li.Init(v[2]) + 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": + 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._Scroller = ListScroller() + self._Scroller._Parent = self + self._Scroller._PosX = self._Width - 10 + self._Scroller._PosY = 2 + self._Scroller.Init() + + 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] + if cur_li._LinkObj != None: + api_cb = getattr(cur_li._LinkObj,"API",None) + if api_cb != None: + if callable(api_cb): + cur_li._LinkObj.API(self._Screen) + + + 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() + + + if event.key == CurKeys["Enter"]: + self.Click() + + def Draw(self): + self.ClearCanvas() + + if len(self._MyList) * ListItem._Height > self._Height: + self._Ps._Width = self._Width - 11 + + self._Ps.Draw() + + for i in self._MyList: + i.Draw() + + self._Scroller.UpdateSize( len(self._MyList)*ListItem._Height, self._PsIndex*ListItem._Height) + self._Scroller.Draw() + else: + self._Ps._Width = self._Width + self._Ps.Draw() + for i in self._MyList: + i.Draw() + + diff --git a/Menu/GameShell/10_Settings/myvars.py b/Menu/GameShell/10_Settings/myvars.py new file mode 100644 index 0000000..a16dc6e --- /dev/null +++ b/Menu/GameShell/10_Settings/myvars.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +from sys import exit +import os +import sys + + +basepath = os.path.dirname(os.path.realpath(__file__)) + +icons_path = basepath+"/icons" + +ListPage = None diff --git a/Menu/GameShell/10_Settings/pages.py b/Menu/GameShell/10_Settings/pages.py new file mode 100644 index 0000000..b459b32 --- /dev/null +++ b/Menu/GameShell/10_Settings/pages.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- + +from list_page import ListPage + +import myvars + +def InitListPage(main_screen): + + myvars.ListPage = ListPage() + + myvars.ListPage._Screen = main_screen + myvars.ListPage._Name = "Setting List" + myvars.ListPage.Init() diff --git a/Menu/GameShell/20_Retro Games/GBA.png b/Menu/GameShell/20_Retro Games/GBA.png new file mode 100644 index 0000000000000000000000000000000000000000..e8c575b1c81b3c669af9bc85158fe9b09958f41a GIT binary patch literal 2931 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 literal 0 HcmV?d00001 diff --git a/Menu/GameShell/20_Retro Games/GBA/action.config b/Menu/GameShell/20_Retro Games/GBA/action.config new file mode 100644 index 0000000..a91e7df --- /dev/null +++ b/Menu/GameShell/20_Retro Games/GBA/action.config @@ -0,0 +1,6 @@ +ROM=/home/cpi/games/GBX +ROM_SO=/home/cpi/apps/emulators/mgba_libretro.so +EXT=gba,gbx +LAUNCHER=retroarch -L +TITLE=GBA Roms +SO_URL=http://buildbot.libretro.com/nightly/linux/armhf/latest/mgba_libretro.so.zip diff --git a/Menu/GameShell/20_Retro Games/MAME.png b/Menu/GameShell/20_Retro Games/MAME.png new file mode 100644 index 0000000000000000000000000000000000000000..9a859f53b8a9ab98f44ac1c88a4c86adf91d4eb4 GIT binary patch literal 3339 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 literal 0 HcmV?d00001 diff --git a/Menu/GameShell/Music Player/icons/preload.py b/Menu/GameShell/Music Player/icons/preload.py new file mode 100644 index 0000000..b4b0759 --- /dev/null +++ b/Menu/GameShell/Music Player/icons/preload.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +import pygame +from pygame.locals import * +from sys import exit +import os +import sys + +from beeprint import pp + +ICONS_PRELOAD={} + + +def load_icons(): + basepath = os.path.dirname(os.path.realpath(__file__)) + + files = os.listdir(basepath) + for i in files: + if os.path.isfile(basepath+"/"+i) and i.endswith(".png"): + keyname = i.split(".")[0] + ICONS_PRELOAD[keyname] = pygame.image.load(basepath+"/"+i).convert_alpha() diff --git a/Menu/GameShell/Music Player/list_item.py b/Menu/GameShell/Music Player/list_item.py new file mode 100644 index 0000000..2d2c369 --- /dev/null +++ b/Menu/GameShell/Music Player/list_item.py @@ -0,0 +1,135 @@ +# -*- coding: utf-8 -*- + +import pygame +from libs.roundrects import aa_round_rect + +## local UI import +from UI.constants import ICON_TYPES +from UI.page import Page +from UI.label import Label +from UI.fonts import fonts +from UI.icon_item import IconItem +from UI.util_funcs import midRect + +# a item for List +# - - - - - - - - - - - -- +# | Icon Text..... > | +# ------------------------ + +import myvars # icons_path +from icons import preload + +class ListItemIcon(IconItem): + + _CanvasHWND = None + _Parent = None + _Width = 18 + _Height = 18 + + def Draw(self): + self._CanvasHWND.blit(self._ImgSurf,(self._PosX,self._PosY+(self._Parent._Height-self._Height)/2,self._Width,self._Height)) + + +class ListItemLabel(Label): + + _ActiveColor = pygame.Color(175,90,0) + _Active = False + def Draw(self): + + self._FontObj.set_bold(self._Active) + + """ + if self._Active == True: + my_text = self._FontObj.render( self._Text,True,self._ActiveColor) + else: + my_text = self._FontObj.render( self._Text,True,self._Color) + """ + + my_text = self._FontObj.render( self._Text,True,self._Color) + self._CanvasHWND.blit(my_text,(self._PosX,self._PosY,self._Width,self._Height)) + + +class ListItem(object): + _PosX = 0 + _PosY = 0 + _Width = 0 + _Height = 30 + + _Labels = {} + _Icons = {} + _Fonts = {} + _MyType = ICON_TYPES["EXE"] + _LinkObj = None + _Path = "" + _Active = False + _Playing = False ## play or pause + _PlayingProcess = 0 # 0 - 100 + _Parent = None + + _ActiveBackgroundColor = pygame.Color(232,232,232) + + def __init__(self): + self._Labels = {} + self._Icons = {} + self._Fonts = {} + + + def Init(self,text): + + #self._Fonts["normal"] = fonts["veramono12"] + + l = ListItemLabel() + l._PosX = 22 + l.SetCanvasHWND(self._Parent._CanvasHWND) + + if self._MyType == ICON_TYPES["DIR"]: + l.Init(text,self._Fonts["normal"]) + self._Path = text + else: + l.Init(text,self._Fonts["normal"]) + self._Path = text + + + self._Labels["Text"] = l + + + def NewCoord(self,x,y): + self._PosX = x + self._PosY = y + + def Draw(self): + + if self._MyType == ICON_TYPES["DIR"] and self._Path != "[..]": + self._Parent._Icons["sys"]._IconIndex = 0 + self._Parent._Icons["sys"].NewCoord(self._PosX+12,self._PosY+ (self._Height - self._Parent._Icons["sys"]._Height)/2+self._Parent._Icons["sys"]._Height/2) + self._Parent._Icons["sys"].Draw() + + if self._MyType == ICON_TYPES["FILE"]: + self._Parent._Icons["sys"]._IconIndex = 1 + self._Parent._Icons["sys"].NewCoord(self._PosX+12,self._PosY+ (self._Height - self._Parent._Icons["sys"]._Height)/2+self._Parent._Icons["sys"]._Height/2) + self._Parent._Icons["sys"].Draw() + + if self._Active == True: + self._Labels["Text"]._Active = True + else: + self._Labels["Text"]._Active = False + + + self._Labels["Text"]._PosY = self._PosY + (self._Height - self._Labels["Text"]._Height)/2 + + 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) + + if self._Playing == True: + self._Labels["Text"]._Active =True + self._Labels["Text"].Draw() + #_rect = midRect(10,self._PosY+15,10,10,self._Parent._Width,self._Parent._Height) + #aa_round_rect(self._Parent._CanvasHWND,_rect,(0,0,0),3,0,(0,0,0)) + #pygame.draw.polygon(self._Parent._CanvasHWND, (0,0,0), [[6, self._PosY+7], [11, self._PosY+14],[6, self._PosY+21]], 2) + + if self._PlayingProcess > 0: + seek_posx = int(self._Width * self._PlayingProcess/100.0) + pygame.draw.line(self._Parent._CanvasHWND,(255,169,169),(self._PosX,self._PosY+self._Height-2),(self._PosX+seek_posx,self._PosY+self._Height-2),2) + + else: + self._Labels["Text"].Draw() + diff --git a/Menu/GameShell/Music Player/mpd_spectrum_page.py b/Menu/GameShell/Music Player/mpd_spectrum_page.py new file mode 100644 index 0000000..3e51341 --- /dev/null +++ b/Menu/GameShell/Music Player/mpd_spectrum_page.py @@ -0,0 +1,260 @@ +# -*- coding: utf-8 -*- + +import time +import pygame + +from numpy import fromstring,ceil,abs,log10,isnan,isinf,int16 +from numpy import fft as Fft + +import gobject + +from beeprint import pp + +## local UI import +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.keys_def import CurKeys + +from Queue import Queue, Empty +from threading import Thread + + + +from list_item import ListItem + +import myvars + +class PIFI(object): + _MPD_FIFO = "/tmp/mpd.fifo" + _SAMPLE_SIZE = 256 + _SAMPLING_RATE = 44100 + _FIRST_SELECTED_BIN = 5 + _NUMBER_OF_SELECTED_BINS = 10 + _SCALE_WIDTH = Height/2 - 20 + + count = 0 + average = 0 + + def __init__(self): + self.sampleSize = self._SAMPLE_SIZE + self.samplingRate = self._SAMPLING_RATE + self.firstSelectedBin = self._FIRST_SELECTED_BIN + self.numberOfSelectedBins = self._NUMBER_OF_SELECTED_BINS + + # Initialization : frequency bins + freq = Fft.fftfreq(self.sampleSize) * self.samplingRate + freqR = freq[:self.sampleSize/2] + self.bins = freqR[self.firstSelectedBin:self.firstSelectedBin+self.numberOfSelectedBins] + + self.resetSmoothing() + + def resetSmoothing(self): + self.count = 0 + self.average = 0 + + def smoothOut(self, x): + self.count += 1 + self.average = (self.average*self.count + x) / (self.count+1) + return self.average + + def scaleList(self, _list): + for i,x in enumerate(_list): + if isnan(x) or isinf(x): + _list[i] = 0 + + # Compute a simple just-above 'moving average' of maximums + maximum = 1.1*self.smoothOut(max( _list )) + if maximum == 0: + scaleFactor = 0.0 + else: + scaleFactor = self._SCALE_WIDTH/float(maximum) + + # 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 + rawSamples = fifoFile.read(self.sampleSize) # will return empty lines (non-blocking) + if len(rawSamples) == 0: + print("computeSpectrum read zero") + return [],[] + else: + pass +## print("computeSpectrum %d " % len(rawSamples)) + + pcm = fromstring(rawSamples, dtype=int16) + + # Normalize [-1; +1] + pcm = pcm / (2.**15) + + # Compute FFT + N = pcm.size + fft = Fft.fft(pcm) + uniquePts = ceil((N+1)/2.0) + fft = fft[0:int(uniquePts)] + + # Compute amplitude spectrum + amplitudeSpectrum = abs(fft) / float(N) + + # Compute power spectrum + p = amplitudeSpectrum**2 + + # Multiply by two to keep same energy + # See explanation: + # https://web.archive.org/web/20120615002031/http://www.mathworks.com/support/tech-notes/1700/1702.html + if N % 2 > 0: + # odd number of points + # odd nfft excludes Nyquist point + p[1:len(p)] = p[1:len(p)] * 2 + else: + # even number of points + p[1:len(p) -1] = p[1:len(p) - 1] * 2 + + # Power in logarithmic scale (dB) + logPower = 10*log10(p) + + # Compute RMS from power + #rms = numpy.sqrt(numpy.sum(p)) + #print "RMS(power):", rms + + # Select a significant range in the spectrum + spectrum = logPower[self.firstSelectedBin:self.firstSelectedBin+self.numberOfSelectedBins] + + # Scale the spectrum + scaledSpectrum = self.scaleList(spectrum) + + return (self.bins, scaledSpectrum) + + +class MPDSpectrumPage(Page): + + _Icons = {} + _Selector=None + _FootMsg = ["Nav","","","Back","Pause"] + _MyList = [] + _ListFont = fonts["veramono12"] + + _PIFI = None + _FiFo = None + _Color = pygame.Color(126,206,244) + _GobjectIntervalId = -1 + _Queue = None + _KeepReading = True + + def __init__(self): + Page.__init__(self) + self._Icons = {} + self._CanvasHWND = None + self._MyList = [] + self._PIFI = PIFI() + + def Init(self): + self._PosX = self._Index * self._Screen._Width + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + self._CanvasHWND = self._Screen._CanvasHWND + + self.Start() + + self._GobjectIntervalId = gobject.timeout_add(50,self.Playing) + + def Start(self): + + try: + self._FIFO = open(self._PIFI._MPD_FIFO) + q = Queue() + self._Queue = q + + t = Thread(target=self.GetSpectrum) + t.daemon = True # thread dies with the program + t.start() + + except IOError: + print("open %s failed"%self._PIFI._MPD_FIFO) + self._FIFO = None + return + + + def GetSpectrum(self): + if self._FIFO == None: + print("self._FIFO none") + return + + (bins,scaledSpectrum) = self._PIFI.computeSpectrum(self._FIFO) + self._Queue.put( scaledSpectrum ) + + self._KeepReading = False + + return ## Thread ends + + def Playing(self): + if self._Screen.CurPage() == self: + if self._KeepReading == False: + self._KeepReading = True + + t = Thread(target=self.GetSpectrum) + t.daemon=True + t.start() + + self._Screen.Draw() + self._Screen.SwapAndShow() + + else: + + return False + + return True + + def OnLoadCb(self): + + if self._Queue != None: + with self._Queue.mutex: + self._Queue.queue.clear() + + try: + if self._GobjectIntervalId != -1: + gobject.source_remove(self._GobjectIntervalId) + except: + pass + + self._GobjectIntervalId = gobject.timeout_add(50,self.Playing) + + + def KeyDown(self,event): + if event.key == CurKeys["Menu"] or event.key == CurKeys["A"]: + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Start"]: + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Enter"]: + pass + + + def Draw(self): + self.ClearCanvas() + + bw = 10 + spects = None + try: + spects = self._Queue.get_nowait() +# print("get_nowait: " , spects) + except Empty: + return + else: # got line + if len(spects) == 0: + return + w = self._Width / len(spects) + left_margin = (w-bw)/2 + for i,v in enumerate(spects): + pygame.draw.rect(self._CanvasHWND,self._Color,(i*w+left_margin,self._Height-v,bw,v),0) + diff --git a/Menu/GameShell/Music Player/music_lib_list_page.py b/Menu/GameShell/Music Player/music_lib_list_page.py new file mode 100644 index 0000000..c7a069e --- /dev/null +++ b/Menu/GameShell/Music Player/music_lib_list_page.py @@ -0,0 +1,343 @@ +# -*- coding: utf-8 -*- +import os +import pygame + +from libs.roundrects import aa_round_rect + +## 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.icon_item import IconItem +from UI.util_funcs import midRect +from UI.keys_def import CurKeys +from UI.multi_icon_item import MultiIconItem +from UI.icon_pool import MyIconPool +from UI.scroller import ListScroller + +from list_item import ListItem + + +import myvars + + +class MusicLibStack: + def __init__(self): + self.stack = list() + + def Push(self,data): + if data not in self.stack: + self.stack.append(data) + return True + return False + + def Pop(self): + if len(self.stack)<=0: + return None,False + return self.stack.pop(),True + + def Last(self): + idx = len(self.stack) -1 + if idx < 0: + return "/" + else: + return self.stack[ idx ] + + def Length(self): + return len(self.stack) + +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 MusicLibListPage(Page): + + _Icons = {} + _Selector=None + _FootMsg = ["Nav","Scan","","Back","Add to Playlist"] + _MyList = [] + _SwapMyList = [] + _ListFont = fonts["notosanscjk15"] + _MyStack = None + + _Scroller = None + + _BGpng = None + _BGwidth = 56 + _BGheight = 70 + + def __init__(self): + Page.__init__(self) + self._Icons = {} + self._CanvasHWND = None + self._MyList = [] + self._SwapMyList = [] + self._MyStack = MusicLibStack() + + def SyncList(self,path): + if myvars.Poller == None: + return + + alist = myvars.Poller.listfiles(path) + if alist == False: + print("listfiles return false") + return + + self._MyList = [] + self._SwapMyList = [] + + start_x = 0 + start_y = 0 + hasparent = 0 + if self._MyStack.Length() > 0: + hasparent = 1 + li = ListItem() + li._Parent = self + li._PosX = start_x + li._PosY = start_y + li._Width = Width + li._Fonts["normal"] = self._ListFont + li._MyType = ICON_TYPES["DIR"] + li._Parent = self + li.Init("[..]") + self._MyList.append(li) + + for i,v in enumerate(sorted(alist)): + li = ListItem() + li._Parent = self + li._PosX = start_x + li._PosY = start_y + (i+hasparent)*ListItem._Height + li._Width = Width + li._Fonts["normal"] = self._ListFont + li._MyType = ICON_TYPES["FILE"] + li._Parent = self + + if "directory" in v: + li._MyType = ICON_TYPES["DIR"] + dir_base_name = os.path.basename(v["directory"]) + li.Init( dir_base_name ) + li._Path = v["directory"] + elif "file" in v: + bname = os.path.basename(v["file"]) + li.Init( bname ) + li._Path = v["file"] + + else: + li.Init("NoName") + + self._MyList.append(li) + + for i in self._MyList: + self._SwapMyList.append(i) + + def Init(self): + self._PosX = self._Index * self._Screen._Width + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + self._CanvasHWND = self._Screen._CanvasHWND + + ps = ListPageSelector() + ps._Parent = self + self._Ps = ps + self._PsIndex = 0 + + self.SyncList("/") + + icon_for_list = MultiIconItem() + icon_for_list._ImgSurf = MyIconPool._Icons["sys"] + icon_for_list._MyType = ICON_TYPES["STAT"] + icon_for_list._Parent = self + + icon_for_list.Adjust(0,0,18,18,0) + self._Icons["sys"] = icon_for_list + + + self._BGpng = IconItem() + self._BGpng._ImgSurf = MyIconPool._Icons["empty"] + self._BGpng._MyType = ICON_TYPES["STAT"] + self._BGpng._Parent = self + self._BGpng.AddLabel("Please upload data over Wi-Fi", fonts["varela22"]) + self._BGpng.SetLableColor(pygame.Color(204,204,204)) + self._BGpng.Adjust(0,0,self._BGwidth,self._BGheight,0) + + + self._Scroller = ListScroller() + self._Scroller._Parent = self + self._Scroller._PosX = self._Width - 10 + self._Scroller._PosY = 2 + self._Scroller.Init() + + + def ScrollUp(self,Step=1): + if len(self._MyList) == 0: + return + tmp = self._PsIndex + self._PsIndex -= Step + + if self._PsIndex < 0: + self._PsIndex = 0 + dy = tmp-self._PsIndex + 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*dy + + + def ScrollDown(self,Step=1): + if len(self._MyList) == 0: + return + tmp = self._PsIndex + self._PsIndex +=Step + if self._PsIndex >= len(self._MyList): + self._PsIndex = len(self._MyList) -1 + dy = self._PsIndex - tmp + 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*dy + + def Click(self): + if len(self._MyList) == 0: + return + + cur_li = self._MyList[self._PsIndex] + + if cur_li._MyType == ICON_TYPES["DIR"]: + if cur_li._Path == "[..]": + self._MyStack.Pop() + self.SyncList( self._MyStack.Last() ) + self._PsIndex = 0 + else: + self._MyStack.Push( self._MyList[self._PsIndex]._Path ) + self.SyncList( self._MyStack.Last() ) + self._PsIndex = 0 + + if cur_li._MyType == ICON_TYPES["FILE"]: ## add to playlist only + myvars.Poller.addfile(cur_li._Path) + myvars.PlayListPage.SyncList() + print("add" , cur_li._Path) + + self._Screen.Draw() + self._Screen.SwapAndShow() + + def Rescan(self): + self.SyncList("/") + self._PsIndex = 0 + + def KeyDown(self,event): + + if event.key == CurKeys["Menu"] or event.key == CurKeys["Left"]: + + 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() + + """ + if event.key == CurKeys["Right"]: + self.ScrollDown(Step=5) + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Left"]: + self.ScrollUp(Step=5) + self._Screen.Draw() + self._Screen.SwapAndShow() + """ + + if event.key == CurKeys["X"]: + self.Rescan() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Enter"]: + self.Click() + + def Draw(self): + self.ClearCanvas() + + + """ + start_x = 0 + start_y = 0 + counter = 0 + + self._MyList = [] + + for i,v in enumerate(self._SwapMyList): + if myvars.PlayListPage.InPlayList(v._Path): + v._Active = True + else: + v._Active = False + + if v._Active == False: + v.NewCoord(start_x, start_y+counter* ListItem._Height) + counter+=1 + self._MyList.append(v) + """ + + if len(self._MyList) == 0: + self._BGpng.NewCoord(self._Width/2,self._Height/2) + self._BGpng.Draw() + return + + else: + if len(self._MyList) * ListItem._Height > self._Height: + self._Ps._Width = self._Width - 11 + + self._Ps.Draw() + for i in self._MyList: + if myvars.PlayListPage.InPlayList(i._Path): + i._Active = True + else: + i._Active = False + + i.Draw() + + self._Scroller.UpdateSize( len(self._MyList)*ListItem._Height, self._PsIndex*ListItem._Height) + self._Scroller.Draw() + else: + self._Ps._Width = self._Width + self._Ps.Draw() + for i in self._MyList: + if myvars.PlayListPage.InPlayList(i._Path): + i._Active = True + else: + i._Active = False + + i.Draw() diff --git a/Menu/GameShell/Music Player/myvars.py b/Menu/GameShell/Music Player/myvars.py new file mode 100644 index 0000000..d327570 --- /dev/null +++ b/Menu/GameShell/Music Player/myvars.py @@ -0,0 +1,8 @@ + + +Poller = None # MPD Poller +PlayListPage = None +MusicLibListPage = None + +SpectrumPage = None + diff --git a/Menu/GameShell/Music Player/pages.py b/Menu/GameShell/Music Player/pages.py new file mode 100644 index 0000000..5dba46c --- /dev/null +++ b/Menu/GameShell/Music Player/pages.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +from libs.MPD import poller + +from play_list_page import PlayListPage +from music_lib_list_page import MusicLibListPage +from mpd_spectrum_page import MPDSpectrumPage +import myvars + +from config import MPD_socket + +def InitPoller(): + try: + myvars.Poller = poller.MPDPoller(host=MPD_socket) + myvars.Poller.connect() + except: + myvars.Poller = None + + +def InitMusicLibPage(main_screen): + myvars.MusicLibListPage = MusicLibListPage() + myvars.MusicLibListPage._Screen = main_screen + myvars.MusicLibListPage._Name = "Music Library" + myvars.MusicLibListPage.Init() + +def InitListPage(main_screen): + + myvars.PlayListPage = PlayListPage() + + myvars.PlayListPage._Screen = main_screen + myvars.PlayListPage._Name = "Music List" + myvars.PlayListPage.Init() + +def InitSpectrumPage(main_screen): + myvars.SpectrumPage = MPDSpectrumPage() + myvars.SpectrumPage._Screen = main_screen + myvars.SpectrumPage._Name = "Spectrum" + myvars.SpectrumPage.Init() diff --git a/Menu/GameShell/Music Player/play_list_page.py b/Menu/GameShell/Music Player/play_list_page.py new file mode 100644 index 0000000..0dc43e5 --- /dev/null +++ b/Menu/GameShell/Music Player/play_list_page.py @@ -0,0 +1,279 @@ +# -*- coding: utf-8 -*- +import os +import pygame +import gobject + +from libs.roundrects import aa_round_rect + +## local UI import +from UI.constants import Width,Height,ICON_TYPES +from UI.page import Page,PageSelector +from UI.icon_item import IconItem +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_pool import MyIconPool + +from UI.scroller import ListScroller + +from list_item import ListItem + +import myvars + +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)-1): + idx = len(self._Parent._MyList) + if idx > 0: + idx -=1 + elif idx == 0: #Nothing + return + + 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 PlayListPage(Page): + + _Icons = {} + _Selector=None + _FootMsg = ["Nav","","Remove","Back","Play/Pause"] + _MyList = [] + _ListFont = fonts["notosanscjk15"] + + _Scroller = None + + _BGpng = None + _BGwidth = 75 + _BGheight = 70 + + def __init__(self): + self._Icons = {} + Page.__init__(self) + self._CanvasHWND = None + self._MyList = [] + + def SyncList(self): + self._MyList = [] + start_x = 0 + start_y = 0 + if myvars.Poller == None: + return + + play_list = myvars.Poller.playlist() + for i,v in enumerate(play_list): + li = ListItem() + li._Parent = self + li._PosX = start_x + li._PosY = start_y + i*ListItem._Height + li._Width = Width + li._Fonts["normal"] = self._ListFont + + if "title" in v: + li.Init( v["title"]) + if "file" in v: + li._Path = v["file"] + + elif "file" in v: + li.Init(os.path.basename(v["file"])) + li._Path = v["file"] + else: + li.Init("NoName") + + li._Labels["Text"]._PosX = 7 + self._MyList.append(li) + + + self.SyncPlaying() + + def GObjectInterval(self): ## 250 ms + if self._Screen.CurPage() == self: + self.SyncPlaying() + self._Screen.Draw() + self._Screen.SwapAndShow() + + return True + + def SyncPlaying(self): + if myvars.Poller == None: + return + + current_song = myvars.Poller.poll() + + for i ,v in enumerate(self._MyList): + self._MyList[i]._Playing = False + self._MyList[i]._PlayingProcess = 0 + + if current_song != None: + if "song" in current_song: + posid = int(current_song["song"]) + if posid < len(self._MyList): # out of index + if "state" in current_song: + if current_song["state"] == "stop": + self._MyList[posid]._Playing = False + else: + self._MyList[posid]._Playing = True + if "time" in current_song: + 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): + if v._Path == path: + return True + + def Init(self): + self._PosX = self._Index * self._Screen._Width + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + self._CanvasHWND = self._Screen._CanvasHWND + + ps = ListPageSelector() + ps._Parent = self + self._Ps = ps + self._PsIndex = 0 + + self.SyncList() + gobject.timeout_add(850,self.GObjectInterval) + + self._BGpng = IconItem() + self._BGpng._ImgSurf = MyIconPool._Icons["heart"] + self._BGpng._MyType = ICON_TYPES["STAT"] + self._BGpng._Parent = self + self._BGpng.AddLabel("my favourites", fonts["varela18"]) + self._BGpng.SetLableColor(pygame.Color(204,204,204)) + self._BGpng.Adjust(0,0,self._BGwidth,self._BGheight,0) + + self._Scroller = ListScroller() + self._Scroller._Parent = self + self._Scroller._PosX = self._Width - 10 + self._Scroller._PosY = 2 + self._Scroller.Init() + + + 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): + if len(self._MyList) == 0: + return + + cur_li = self._MyList[self._PsIndex] + play_pos_id = myvars.Poller.play(self._PsIndex) + + self.SyncPlaying() + + self._Screen.Draw() + self._Screen.SwapAndShow() + + def OnReturnBackCb(self): + self.SyncList() + + def KeyDown(self,event): + if event.key == CurKeys["A"] or event.key == CurKeys["Menu"]: + if myvars.Poller != None: + myvars.Poller.stop() + + 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() + + if event.key == CurKeys["Right"]:#add + self._Screen.PushCurPage() + self._Screen.SetCurPage(myvars.MusicLibListPage) + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Y"]:# del selected songs + myvars.Poller.delete(self._PsIndex) + self.SyncList() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["Enter"]: + self.Click() + + if event.key == CurKeys["Start"]: # start spectrum + self._Screen.PushPage(myvars.SpectrumPage) + self._Screen.Draw() + self._Screen.SwapAndShow() + + def Draw(self): + self.ClearCanvas() + + if len(self._MyList) == 0: + self._BGpng.NewCoord(self._Width/2,self._Height/2) + self._BGpng.Draw() + return + else: + if len(self._MyList) * ListItem._Height > self._Height: + self._Ps._Width = self._Width - 11 + self._Ps.Draw() + for i in self._MyList: + i.Draw() + self._Scroller.UpdateSize( len(self._MyList)*ListItem._Height, self._PsIndex*ListItem._Height) + self._Scroller.Draw() + else: + self._Ps._Width = self._Width + self._Ps.Draw() + for i in self._MyList: + i.Draw() + diff --git a/Menu/GameShell/PowerOFF.png b/Menu/GameShell/PowerOFF.png new file mode 100644 index 0000000000000000000000000000000000000000..57ee7f9904a91ba06bd60b799d7914170688b558 GIT binary patch literal 3287 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 V5SUmD6vF@j002ovPDHLkV1j|1C+PqH literal 0 HcmV?d00001 diff --git a/Menu/GameShell/PowerOFF/__init__.py b/Menu/GameShell/PowerOFF/__init__.py new file mode 100644 index 0000000..cd32448 --- /dev/null +++ b/Menu/GameShell/PowerOFF/__init__.py @@ -0,0 +1,89 @@ +# -*- coding: utf-8 -*- + +import pygame + +#UI lib +from UI.constants import RUNSYS +from UI.keys_def import CurKeys +from UI.confirm_page import ConfirmPage + +import config + +class PowerOffConfirmPage(ConfirmPage): + + _ConfirmText = "Confirm Power OFF?" + + + def CheckBattery(self): + try: + f = open(config.Battery) + except IOError: + print( "PowerOFF open %s failed" % config.Battery) + return 0 + else: + with f: + bat_uevent = {} + content = f.readlines() + content = [x.strip() for x in content] + for i in content: + pis = i.split("=") + if len(pis) > 1: + bat_uevent[pis[0]] = pis[1] + + if "POWER_SUPPLY_CAPACITY" in bat_uevent: + cur_cap = int(bat_uevent["POWER_SUPPLY_CAPACITY"]) + else: + cur_cap = 0 + + return cur_cap + + return 0 + + def KeyDown(self,event): + + if event.key == CurKeys["Menu"] or event.key == CurKeys["A"]: + + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + if event.key == CurKeys["B"]: + if self.CheckBattery() < 20: + cmdpath = "feh --bg-center gameshell/wallpaper/gameover.png;" + else: + cmdpath = "feh --bg-center gameshell/wallpaper/seeyou.png;" + + cmdpath += "sleep 3;" + + #cmdpath += "echo 'halt -p' > /tmp/halt_cmd" + + cmdpath += "sudo halt -p" + pygame.event.post( pygame.event.Event(RUNSYS, message=cmdpath)) + + + +class APIOBJ(object): + + _StoragePage = None + def __init__(self): + pass + def Init(self,main_screen): + self._Page = PowerOffConfirmPage() + + self._Page._Screen = main_screen + self._Page._Name ="Power OFF" + 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/Retro Games.png b/Menu/GameShell/Retro Games.png new file mode 100644 index 0000000000000000000000000000000000000000..2733820f5d6ca9515c9a4520a9b14b63464ed92d GIT binary patch literal 4007 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 FV1gLJL4^PS literal 0 HcmV?d00001 diff --git a/Menu/GameShell/RetroArch.sh b/Menu/GameShell/RetroArch.sh new file mode 100644 index 0000000..44f0c2a --- /dev/null +++ b/Menu/GameShell/RetroArch.sh @@ -0,0 +1 @@ +retroarch diff --git a/Menu/GameShell/Settings.png b/Menu/GameShell/Settings.png new file mode 100644 index 0000000000000000000000000000000000000000..3e194ac11bba1151ce25f4fc520113cb9566166b GIT binary patch literal 5071 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 literal 0 HcmV?d00001 diff --git a/Menu/GameShell/Sleep.png b/Menu/GameShell/Sleep.png new file mode 100644 index 0000000000000000000000000000000000000000..b2d7dd15236ceec53fd32d81c503ea3bc534d0eb GIT binary patch literal 2600 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