launcher/sys.py/UI/page.py
2019-08-07 15:27:45 +08:00

676 lines
23 KiB
Python

# -*- coding: utf-8 -*-
import pygame
from pygame.locals import *
from sys import exit
import os
import sys
import math
import fnmatch
import random
from libs import easing
# import base64
# from beeprint import pp
# local import
from constants import ALIGN, icon_width, icon_height, Width, Height, ICON_TYPES
from util_funcs import midRect,FileExists
from keys_def import CurKeys, IsKeyStartOrA, IsKeyMenuOrB
from icon_pool import MyIconPool
from lang_manager import MyLangManager
from widget import Widget
import config
class PageStack:
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 Length(self):
return len(self.stack)
class PageSelector(Widget):
_Parent = None
_Alpha = 0
_OnShow = True
_IconSurf = None
def __init__(self):
pass
def Init(self, x, y, w, h, alpha):
self._PosX = x
self._PosY = y
self._Width = w
self._Height = h
self._Alpha = alpha
def Adjust(self, x, y, w, h, alpha):
self._PosX = x
self._PosY = y
self._Width = w
self._Height = h
self._Alpha = alpha
def Draw(self):
canvas = self._Parent._CanvasHWND
idx = self._Parent._PsIndex
iconidx = self._Parent._IconIndex
if idx < len(self._Parent._Icons):
x = self._Parent._Icons[idx]._PosX+self._Parent._PosX
# only use current icon's PosY
y = self._Parent._Icons[iconidx]._PosY
rect = midRect(x, y, self._Width, self._Height,
self._Parent._Width, self._Parent._Height)
if rect.width <= 0 or rect.height <= 0:
return
# color = (244,197,66,50)
# pygame.draw.rect(canvas,color,rect,1)
if self._IconSurf != None:
self._Parent._CanvasHWND.blit(self._IconSurf, rect)
class Page(Widget):
_Icons = []
_Ps = None
_PsIndex = 0
_IconNumbers = 0
_IconIndex = 0 # shows which icon current selected, the Selector can not move here
_PrevIconIndex = 0 # for remember the Highlighted Icon ,restore it's PosY to average
_Index = 0
_Align = ALIGN["SLeft"]
_CanvasHWND = None
_HWND = None
_OnShow = False
_Name = ""
_Screen = None # Should be the Screen Class
_PageIconMargin = 20
_FootMsg = ["Nav", "", "", "", "Enter"] # Default Page Foot info
_Wallpaper = None
_SelectedIconTopOffset = 20
_EasingDur = 30
_Padding = pygame.Rect(0, 0, 0, 0) # x,y,w,h
_Margin = pygame.Rect(0, 0, 0, 0)
_ScrollStep = 1
def __init__(self):
self._Icons = []
## so every theme can have a background.png for displaying as the background of the launcher,except the topbar and footbar
## https://forum.clockworkpi.com/t/give-your-gs-a-custom-wallpaper/3724
bg_img_path = config.SKIN+"/background.png"
if FileExists(bg_img_path):
self._Wallpaper = pygame.transform.scale(pygame.image.load(bg_img_path).convert(), (320,240))
def AdjustHLeftAlign(self): ## adjust coordinator and append the PageSelector
self._PosX = self._Index*self._Screen._Width
self._Width = self._Screen._Width
self._Height = self._Screen._Height
cols = int(Width /icon_width)
rows = int( (self._IconNumbers * icon_width)/Width + 1)
if rows < 1:
rows = 1
cnt = 0
for i in range(0,rows):
for j in range(0,cols):
start_x = icon_width/2 + j*icon_width
start_y = icon_height/2 + i*icon_height
icon = self._Icons[cnt]
icon.Adjust(start_x,start_y,icon_width-4,icon_height-4,0)
icon._Index = cnt
icon._Parent = self
if cnt >= (self._IconNumbers -1):
break
cnt+=1
ps = PageSelector()
ps._IconSurf = MyIconPool.GiveIconSurface("blueselector")
ps._Parent = self
ps.Init(icon_width/2, TitleBar._BarHeight+icon_height/2,92,92,128)
self._Ps = ps
self._PsIndex = 0
self._OnShow = False
def AdjustSLeftAlign(self): ## adjust coordinator and append the PageSelector
self._PosX = self._Index*self._Screen._Width
self._Width = self._Screen._Width
self._Height = self._Screen._Height
start_x = (self._PageIconMargin + icon_width+self._PageIconMargin) /2
start_y = self._Height/2
for i in range(0,self._IconNumbers):
it = self._Icons[i]
it._Parent = self
it._Index = i
it.Adjust(start_x+i*self._PageIconMargin+i*icon_width,start_y,icon_width-6,icon_height-6,0)
it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height))
ps = PageSelector()
ps._IconSurf = MyIconPool.GiveIconSurface("blueselector")
ps._Parent = self
ps.Init(start_x,start_y,92,92,128)
self._Ps = ps
self._PsIndex = 0
self._OnShow = False
if self._IconNumbers > 1:
self._PsIndex = 1
self._IconIndex = self._PsIndex
self._PrevIconIndex = self._IconIndex
self._Icons[self._IconIndex]._PosY -= self._SelectedIconTopOffset
def AdjustSAutoLeftAlign(self): ## adjust coordinator and append the PageSelector
self._PosX = self._Index*self._Screen._Width
self._Width = self._Screen._Width
self._Height = self._Screen._Height
start_x = (self._PageIconMargin + icon_width+self._PageIconMargin) /2
start_y = self._Height/2
if self._IconNumbers == 1:
start_x = self._Width / 2
start_y = self._Height/2
it = self._Icons[0]
it._Parent = self
it._Index = 0
it.Adjust(start_x,start_y,icon_width,icon_height,0)
# it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height))
elif self._IconNumbers == 2:
start_x = (self._Width - self._PageIconMargin - self._IconNumbers*icon_width) / 2 + icon_width/2
start_y = self._Height /2
for i in range(0,self._IconNumbers):
it = self._Icons[i]
it._Parent = self
it._Index = i
it.Adjust(start_x+i*self._PageIconMargin + i*icon_width,start_y, icon_width, icon_height,0)
# it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height))
elif self._IconNumbers > 2:
for i in range(0,self._IconNumbers):
it = self._Icons[i]
it._Parent = self
it._Index = i
it.Adjust(start_x+i*self._PageIconMargin + i*icon_width,start_y,icon_width,icon_height,0)
# it._ImgSurf = pygame.transform.smoothscale(it._ImgSurf,(it._Width,it._Height))
ps = PageSelector()
ps._IconSurf = MyIconPool.GiveIconSurface("blueselector")
ps._Parent = self
ps.Init(start_x,start_y,92,92,128)
self._Ps = ps
self._PsIndex = 0
self._OnShow = False
if self._IconNumbers > 1:
self._PsIndex = 1
self._IconIndex = self._PsIndex
self._PrevIconIndex = self._IconIndex
self._Icons[self._IconIndex]._PosY -= self._SelectedIconTopOffset
def InitLeftAlign(self):
self._PosX = self._Index*Width
self._Width = self._Screen._Width
self._Height = self._Screen._Height
cols = int(self._Width /icon_width)
rows = int((self._IconNumbers * icon_width)/self._Width + 1)
if rows < 1:
rows = 1
cnt = 0
for i in range(0,rows):
for j in range(0,cols):
start_x = icon_width/2 + j*icon_width
start_y = TitleBar._BarHeight + icon_height/2 + i*icon_height
icon = IconItem()
icon.Init(start_x,start_y,icon_width-4,icon_height-4,0)
icon._Index = cnt
icon._Parent = self
self._Icons.append(icon)
if cnt >= (self._IconNumbers -1):
break
cnt+=1
ps = PageSelector()
ps._IconSurf = MyIconPool.GiveIconSurface("blueselector")
ps._Parent = self
ps.Init(icon_width/2,icon_height/2,92,92,128)
self._Ps = ps
self._PsIndex = 0
self._OnShow = False
def Adjust(self): ## default init way,
self._PosX = self._Index*self._Screen._Width
self._Width = self._Screen._Width ## equal to screen width
self._Height = self._Screen._Height
if self._Align == ALIGN["HLeft"]:
start_x = (self._Width - self._IconNumbers*icon_width)/2 + icon_width/2
start_y = self._Height/2
for i in range(0,self._IconNumbers):
it = self._Icons[i]
it._Parent = self
it._Index = i
it.Adjust(start_x+i*icon_width,start_y,icon_width,icon_height,0)
ps = PageSelector()
ps._IconSurf = MyIconPool.GiveIconSurface("blueselector")
ps._Parent = self
ps.Init(start_x,start_y,92,92,128)
self._Ps = ps
self._PsIndex = 0
self._OnShow = False
elif self._Align == ALIGN["SLeft"]:
start_x = (self._PageIconMargin + icon_width+self._PageIconMargin) /2
start_y = self._Height/2
for i in range(0,self._IconNumbers):
it = self._Icons[i]
it._Parent = self
it._Index = i
it.Adjust(start_x+i*self._PageIconMargin+i*icon_width,start_y,icon_width,icon_height,0)
ps = PageSelector()
ps._IconSurf = MyIconPool.GiveIconSurface("blueselector")
ps._Parent = self
ps.Init(start_x,start_y-self._SelectedIconTopOffset,92,92,128)
self._Ps = ps
self._PsIndex = 0
self._OnShow = False
if self._IconNumbers > 1:
self._PsIndex = 1
self._IconIndex = self._PsIndex
self._PrevIconIndex = self._IconIndex
self._Icons[self._IconIndex]._PosY -= self._SelectedIconTopOffset
def Init(self): ## default init way,
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
start_x = (self._Width - self._IconNumbers*icon_width)/2 + icon_width/2
start_y = self._Height/2
for i in range(0,self._IconNumbers):
it = IconItem()
it._Parent = self
it._Index = i
it.Init(start_x+i*icon_width,start_y,icon_width,icon_height,0)
self._Icons.append(it)
if self._IconNumbers > 0:
ps = PageSelector()
ps._IconSurf = MyIconPool.GiveIconSurface("blueselector")
ps._Parent = self
ps.Init(start_x,start_y,icon_width+4,icon_height+4,128)
self._Ps = ps
self._PsIndex = 0
self._OnShow = False
def IconStepMoveData(self,icon_eh,cuts):## no Sine,No curve,plain movement steps data
all_pieces = []
piece = icon_eh / cuts
c = 0.0
prev = 0.0
for i in range(0,cuts):
c+=piece
dx = c-prev
if dx < 0.5:
dx = 1.0
all_pieces.append( math.ceil(dx) )
if c >= icon_eh:
break
c = 0
bidx = 0
for i in all_pieces:
c+=i
bidx+=1
if c >= icon_eh:
break
all_pieces = all_pieces[0:bidx]
if len(all_pieces) < cuts:
dff = cuts - len(all_pieces)
diffa = []
for i in range(0,dff):
diffa.append(0)
all_pieces.extend( diffa)
return all_pieces
def EasingData(self,start,distance):##generate easing steps data
current_time = 0.0
start_posx = 0.0
current_posx = start_posx
final_posx = float(distance)
posx_init = start
dur = self._EasingDur
last_posx = 0.0
all_last_posx = []
for i in range(0,distance*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)
return all_last_posx
def IconSmoothUp(self,icon_ew):
data = self.EasingData(self._PosX,icon_ew)
data2 = self.IconStepMoveData(self._SelectedIconTopOffset,len(data))
for i,v in enumerate(data):
self.ClearCanvas()
self._Icons[self._IconIndex]._PosY -= data2[i]
if self._Icons[self._PrevIconIndex]._PosY < self._Height/2:
self._Icons[self._PrevIconIndex]._PosY+=data2[i]
self.DrawIcons()
self._Screen.SwapAndShow()
def IconsEasingLeft(self,icon_ew):
data = self.EasingData(self._PosX,icon_ew)
data2 = self.IconStepMoveData(self._SelectedIconTopOffset,len(data))
for i,v in enumerate(data):
self.ClearCanvas()
self._PosX -= v
self._Icons[self._IconIndex]._PosY -= data2[i]
if self._Icons[self._PrevIconIndex]._PosY < self._Height/2:
self._Icons[self._PrevIconIndex]._PosY+=data2[i]
self.DrawIcons()
self._Screen.SwapAndShow()
def IconsEasingRight(self,icon_ew):
data = self.EasingData(self._PosX,icon_ew)
data2 = self.IconStepMoveData(self._SelectedIconTopOffset,len(data))
for i,v in enumerate(data):
self.ClearCanvas()
self._PosX += v
self._Icons[self._IconIndex]._PosY-=data2[i]
if self._Icons[self._PrevIconIndex]._PosY < self._Height/2:
self._Icons[self._PrevIconIndex]._PosY+=data2[i]
self.DrawIcons()
self._Screen.SwapAndShow()
def EasingLeft(self,ew): #ew int
data = self.EasingData(self._PosX,ew)
for i in data:
self._PosX -=i
self.Draw()
self._Screen.SwapAndShow()
def EasingRight(self,ew):
data = self.EasingData(self._PosX,ew)
for i in data:
self._PosX += i
self.Draw()
self._Screen.SwapAndShow()
def MoveLeft(self,ew):
self._PosX -= ew
def MoveRight(self,ew):
self._PosX += ew
def ResetPageSelector(self):
self._PsIndex = 0
self._IconIndex = 0
self._Ps._OnShow = True
def DrawPageSelector(self):
if self._Ps._OnShow == True:
self._Ps.Draw()
def MoveIconIndexPrev(self):
self._PrevIconIndex = self._IconIndex
self._IconIndex-=1
if self._IconIndex < 0:
self._IconIndex = max(0, self._IconNumbers - 1) # Wrap Icon Index
return False
return True
def MoveIconIndexNext(self):
self._PrevIconIndex = self._IconIndex
self._IconIndex+=1
if self._IconIndex > (self._IconNumbers - 1):
self._IconIndex = 0 # Wrap Icon Index
return False
return True
def IconClick(self):
if self._IconIndex > (len(self._Icons) -1):
return
cur_icon = self._Icons[self._IconIndex]
if self._Ps._OnShow == False:
return
if cur_icon._MyType == ICON_TYPES["EXE"]:
print("IconClick: %s %d"%(cur_icon._CmdPath,cur_icon._Index))
self._Screen.RunEXE(cur_icon._CmdPath)
elif cur_icon._MyType == ICON_TYPES["DIR"]:
child_page = self._Icons[self._IconIndex]._LinkPage
if child_page != None:
child_page.Draw()
self._Screen._MyPageStack.Push(self._Screen._CurrentPage)
self._Screen._CurrentPage = child_page
elif cur_icon._MyType == ICON_TYPES["FUNC"]:
print("IconClick API: %d"%(cur_icon._Index))
# print("%s"% cur_icon._CmdPath)
api_cb = getattr(cur_icon._CmdPath,"API",None)
if api_cb != None:
if callable(api_cb):
cur_icon._CmdPath.API(self._Screen)
elif cur_icon._MyType == ICON_TYPES["Emulator"] or cur_icon._MyType == ICON_TYPES["Commercial"]:
cur_icon._CmdPath.API(self._Screen)
def ReturnToUpLevelPage(self):
pop_page,ok = self._Screen._MyPageStack.Pop()
if ok == True:
# self._Screen._CurrentPage.ResetPageSelector()
pop_page.Draw()
self._Screen._CurrentPage = pop_page
on_return_back_cb = getattr(self._Screen._CurrentPage,"OnReturnBackCb",None)
if on_return_back_cb != None:
if callable(on_return_back_cb):
self._Screen._CurrentPage.OnReturnBackCb()
else:
if self._Screen._MyPageStack.Length() == 0:
if len(self._Screen._Pages) > 0:
self._Screen._CurrentPage = self._Screen._Pages[self._Screen._PageIndex]
self._Screen._CurrentPage.Draw()
print("OnTopLevel ",self._Screen._PageIndex)
def ClearCanvas(self):
if self._Wallpaper:
self._CanvasHWND.blit(self._Wallpaper,(0,0))
else:
self._CanvasHWND.fill(self._Screen._SkinManager.GiveColor("White"))
def ClearIcons(self):
for i in range(0,self._IconNumbers):
self._Icons[i].Clear()
def DrawIcons(self):
for i in range(0,self._IconNumbers):
self._Icons[i].Draw()
# make sure the Class has the _MyList
def ScrollDown(self):
if len(self._MyList) == 0:
return
self._PsIndex +=1
if self._PsIndex >= len(self._MyList):
self._PsIndex = len(self._MyList) -1
cur_li = self._MyList[self._PsIndex]
if cur_li._PosY +cur_li._Height > self._Height:
for i in range(0,len(self._MyList)):
self._MyList[i]._PosY -= self._MyList[i]._Height
def ScrollUp(self):
if len(self._MyList) == 0:
return
self._PsIndex -= 1
if self._PsIndex < 0:
self._PsIndex = 0
cur_li = self._MyList[self._PsIndex]
if cur_li._PosY < 0:
for i in range(0, len(self._MyList)):
self._MyList[i]._PosY += self._MyList[i]._Height
def FScrollUp(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 RefreshPsIndex(self):
if len(self._MyList) == 0:
self._PsIndex = 0
if self._PsIndex > (len(self._MyList) -1):
self._PsIndex = len(self._MyList) -1
def FScrollDown(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 KeyDown(self,event):##default keydown,every inherited page class should have it's own KeyDown
if IsKeyMenuOrB(event.key):
self.ReturnToUpLevelPage()
self._Screen.Draw()
self._Screen.SwapAndShow()
if event.key == CurKeys["Right"]:
if self.MoveIconIndexNext() == True:
if self._IconIndex == (self._IconNumbers -1) or self._PrevIconIndex == 0:
self.IconSmoothUp(icon_width + self._PageIconMargin)
else:
self.IconsEasingLeft(icon_width + self._PageIconMargin)
else:
screen_icons = int(math.floor(self._Screen._Width / (icon_width + self._PageIconMargin)))
if self._IconNumbers > screen_icons:
self.IconsEasingRight((icon_width + self._PageIconMargin) * (self._IconNumbers - screen_icons))
elif self._IconNumbers > 0:
self.IconSmoothUp(icon_width+ self._PageIconMargin)
self._PsIndex = self._IconIndex
self._Screen.Draw()
self._Screen.SwapAndShow()
if event.key == CurKeys["Left"]:
if self.MoveIconIndexPrev() == True:
if self._IconIndex == 0 or self._PrevIconIndex == (self._IconNumbers -1):
self.IconSmoothUp(icon_width + self._PageIconMargin)
else:
self.IconsEasingRight(icon_width + self._PageIconMargin)
else:
screen_icons = int(math.floor(self._Screen._Width / (icon_width + self._PageIconMargin)))
if self._IconNumbers > screen_icons:
self.IconsEasingLeft((icon_width + self._PageIconMargin) * (self._IconNumbers - screen_icons))
elif self._IconNumbers > 0:
self.IconSmoothUp(icon_width+ self._PageIconMargin)
self._PsIndex = self._IconIndex
self._Screen.Draw()
self._Screen.SwapAndShow()
if IsKeyStartOrA(event.key):
self.IconClick()
self._Screen.Draw()
self._Screen.SwapAndShow()
def Draw(self):
self.ClearCanvas()
self.DrawIcons()
self.DrawPageSelector()