# coding: utf-8 import wx from logbook import Logger import gui.utils.anim_effects as animEffects import gui.utils.color as colorUtils import gui.utils.draw as drawUtils from .events import Stage2Selected from gui.bitmap_loader import BitmapLoader pyfalog = Logger(__name__) class RaceSelector(wx.Window): def __init__(self, parent, id=wx.ID_ANY, label="", pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, layout=wx.VERTICAL, animate=False): wx.Window.__init__(self, parent, id, pos=pos, size=size, style=style) self.animTimerID = wx.NewId() self.animTimer = wx.Timer(self, self.animTimerID) self.animPeriod = 25 self.animDuration = 250 self.animStep = 0 self.maxWidth = 24 self.minWidth = 5 if animate else self.maxWidth self.maxHeight = 24 self.minHeight = 10 if animate else self.maxHeight self.direction = 0 if animate else 1 self.layout = layout self.animate = animate if layout == wx.VERTICAL: self.SetSize(wx.Size(self.minWidth, -1)) self.SetMinSize(wx.Size(self.minWidth, -1)) else: self.SetSize(wx.Size(-1, self.minHeight)) self.SetMinSize(wx.Size(-1, self.minHeight)) self.checkTimerID = wx.NewId() self.checkTimer = wx.Timer(self, self.checkTimerID) self.checkPeriod = 250 self.checkMaximize = True self.shipBrowser = self.Parent self.raceBmps = [] self.raceNames = [] self.hoveredItem = None if layout == wx.VERTICAL: self.buttonsBarPos = (4, 0) else: self.buttonsBarPos = (0, 4) self.buttonsPadding = 4 if layout == wx.VERTICAL: self.bmpArrow = BitmapLoader.getBitmap("down-arrow2", "gui") else: self.bmpArrow = BitmapLoader.getBitmap("up-arrow2", "gui") # Make the bitmaps have the same color as window text sysTextColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) img = self.bmpArrow.ConvertToImage() if layout == wx.VERTICAL: img = img.Rotate90(False) img.Replace(0, 0, 0, sysTextColour[0], sysTextColour[1], sysTextColour[2]) if layout == wx.VERTICAL: img = img.Scale(round(self.minWidth), 8, wx.IMAGE_QUALITY_HIGH) self.bmpArrow = wx.Bitmap(img) self.RebuildRaces(self.shipBrowser.RACE_ORDER) self.Bind(wx.EVT_ENTER_WINDOW, self.OnWindowEnter) self.Bind(wx.EVT_LEAVE_WINDOW, self.OnWindowLeave) self.Bind(wx.EVT_TIMER, self.OnTimer) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnBackgroundErase) self.Bind(wx.EVT_PAINT, self.OnPaint) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) self.Bind(wx.EVT_MOTION, self.OnMouseMove) self.Bind(wx.EVT_SIZE, self.OnSizeUpdate) self.Layout() self.SetBackgroundStyle(wx.BG_STYLE_PAINT) def OnMouseMove(self, event): mx, my = event.GetPosition() location = self.HitTest(mx, my) if location != self.hoveredItem: self.hoveredItem = location self.Refresh() if location is not None: self.SetCursor(wx.Cursor(wx.CURSOR_HAND)) else: self.SetCursor(wx.Cursor(wx.CURSOR_ARROW)) def OnSizeUpdate(self, event): self.CalcButtonsBarPos() self.Refresh() event.Skip() def CalcButtonsBarPos(self): if self.layout == wx.HORIZONTAL: rect = self.GetRect() width = 0 height = 0 for bmp in self.raceBmps: width += bmp.GetWidth() + self.buttonsPadding height = max(bmp.GetHeight(), height) posx = (rect.width - width) / 2 posy = (rect.height - height) / 2 self.buttonsBarPos = (posx, posy) def OnLeftUp(self, event): mx, my = event.GetPosition() toggle = self.HitTest(mx, my) if toggle is not None: self.Refresh() self.shipBrowser.ToggleRacesFilter(self.raceNames[toggle]) stage = self.shipBrowser.GetActiveStage() if stage == 2: categoryID = self.shipBrowser.GetStageData(stage) wx.PostEvent(self.shipBrowser, Stage2Selected(categoryID=categoryID, back=True)) event.Skip() def HitTest(self, mx, my): x, y = self.buttonsBarPos padding = self.buttonsPadding for bmp in self.raceBmps: if (x < mx < x + bmp.GetWidth()) and (y < my < y + bmp.GetHeight()): return self.raceBmps.index(bmp) if self.layout == wx.VERTICAL: y += bmp.GetHeight() + padding else: x += bmp.GetWidth() + padding return None def RebuildRaces(self, races): self.raceBmps = [] for race in races: if race: self.raceBmps.append(BitmapLoader.getBitmap("race_%s_small" % race, "gui")) self.raceNames = races self.CalcButtonsBarPos() self.Refresh() def OnBackgroundErase(self, event): pass def OnPaint(self, event): rect = self.GetRect() windowColor = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW) # bkColor = colorUtils.GetSuitable(windowColor, 0.1) sepColor = colorUtils.GetSuitable(windowColor, 0.2) mdc = wx.AutoBufferedPaintDC(self) bkBitmap = drawUtils.RenderGradientBar(windowColor, rect.width, rect.height, 0.1, 0.1, 0.2, 2) mdc.DrawBitmap(bkBitmap, 0, 0, True) x, y = self.buttonsBarPos if self.direction == 1: for raceBmp in self.raceBmps: dropShadow = drawUtils.CreateDropShadowBitmap(raceBmp, 0.2) if self.shipBrowser.GetRaceFilterState(self.raceNames[self.raceBmps.index(raceBmp)]): bmp = raceBmp else: img = raceBmp.ConvertToImage() if self.hoveredItem == self.raceBmps.index(raceBmp): img = img.AdjustChannels(1, 1, 1, 0.7) else: img = img.AdjustChannels(1, 1, 1, 0.4) bmp = wx.Bitmap(img) if self.layout == wx.VERTICAL: mdc.DrawBitmap(dropShadow, round(rect.width - self.buttonsPadding - bmp.GetWidth() + 1), round(y + 1)) mdc.DrawBitmap(bmp, round(rect.width - self.buttonsPadding - bmp.GetWidth()), round(y)) y += raceBmp.GetHeight() + self.buttonsPadding mdc.SetPen(wx.Pen(sepColor, 1)) mdc.DrawLine(rect.width - 1, 0, rect.width - 1, rect.height) else: mdc.DrawBitmap(dropShadow, round(x + 1), round(self.buttonsPadding + 1)) mdc.DrawBitmap(bmp, round(x), round(self.buttonsPadding)) x += raceBmp.GetWidth() + self.buttonsPadding mdc.SetPen(wx.Pen(sepColor, 1)) mdc.DrawLine(0, 0, rect.width, 0) if self.direction < 1: if self.layout == wx.VERTICAL: mdc.DrawBitmap(self.bmpArrow, -2, round((rect.height - self.bmpArrow.GetHeight()) / 2)) else: mdc.SetPen(wx.Pen(sepColor, 1)) mdc.DrawLine(0, 0, rect.width, 0) mdc.DrawBitmap(self.bmpArrow, round((rect.width - self.bmpArrow.GetWidth()) / 2), -2) def OnTimer(self, event): if event.GetId() == self.animTimerID: start = 0 if self.layout == wx.VERTICAL: end = self.maxWidth - self.minWidth else: end = self.maxHeight - self.minHeight step = animEffects.OUT_CIRC(self.animStep, start, end, self.animDuration) self.animStep += self.animPeriod * self.direction self.AdjustSize((self.minWidth if self.layout == wx.VERTICAL else self.minHeight) + step) if self.animStep > self.animDuration or self.animStep < 0: self.animTimer.Stop() self.animStep = self.animDuration if self.direction == 1 else 0 self.Parent.GetBrowserContainer().RefreshList(True) if event.GetId() == self.checkTimerID: if self.checkMaximize: self.direction = 1 else: self.direction = -1 if not self.animTimer.IsRunning(): self.animTimer.Start(self.animPeriod) def AdjustSize(self, delta): self.SetMinSize(wx.Size(delta, -1) if self.layout == wx.VERTICAL else wx.Size(-1, delta)) self.Parent.Layout() self.Refresh() def OnWindowEnter(self, event): if not self.animate: return if not self.checkTimer.IsRunning(): self.checkTimer.Start(self.checkPeriod, wx.TIMER_ONE_SHOT) self.checkMaximize = True event.Skip() def OnWindowLeave(self, event): if self.hoveredItem is not None: self.hoveredItem = None self.SetCursor(wx.Cursor(wx.CURSOR_ARROW)) self.Refresh() if not self.animate: return if not self.checkTimer.IsRunning(): self.checkTimer.Start(self.checkPeriod, wx.TIMER_ONE_SHOT) self.checkMaximize = False event.Skip()