Files
pyfa/gui/gangView.py
2016-12-13 21:23:01 -08:00

428 lines
16 KiB
Python

# =============================================================================
# Copyright (C) 2010 Diego Duclos
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa. If not, see <http://www.gnu.org/licenses/>.
# =============================================================================
import wx
from wx.lib.scrolledpanel import ScrolledPanel
from service.fit import Fit
from service.fleet import Fleet
from service.character import Character
from service.market import Market
import gui.mainFrame
import gui.shipBrowser
import gui.globalEvents as GE
class GangView(ScrolledPanel):
def __init__(self, parent):
ScrolledPanel.__init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.Size(100, 20),
style=wx.TAB_TRAVERSAL | wx.HSCROLL | wx.VSCROLL)
mainSizer = wx.BoxSizer(wx.VERTICAL)
self.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.draggedFitID = None
help_msg = '''Set fit as booster to display in dropdown, or drag fitting from\nship browser to this window, or right click fit and select booster role.'''
helpSizer = wx.BoxSizer(wx.HORIZONTAL)
self.helpText = wx.StaticText(self, wx.ID_ANY, help_msg, wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE)
helpSizer.Add(self.helpText, 1, wx.ALL, 5)
self.options = ["Fleet", "Wing", "Squad"]
self.fleet = {}
for id_, option in enumerate(self.options):
# set content for each commander
self.fleet[id_] = {}
self.fleet[id_]['stLabel'] = wx.StaticText(self, wx.ID_ANY, self.options[id_] + ':', wx.DefaultPosition,
wx.DefaultSize, 0)
self.fleet[id_]['stText'] = wx.StaticText(self, wx.ID_ANY, 'None', wx.DefaultPosition, wx.DefaultSize, 0)
self.fleet[id_]['chFit'] = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [])
self.fleet[id_]['chChar'] = wx.Choice(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, [])
self.fleet[id_]['fitSizer'] = wx.BoxSizer(wx.VERTICAL)
self.FitDNDPopupMenu = self.buildBoostermenu()
contentFGSizer = wx.FlexGridSizer(5, 3, 0, 0)
contentFGSizer.AddGrowableCol(1)
contentFGSizer.SetFlexibleDirection(wx.BOTH)
contentFGSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)
# Header
self.stBooster = wx.StaticText(self, wx.ID_ANY, u"Booster", wx.DefaultPosition, wx.DefaultSize, 0)
self.stBooster.Wrap(-1)
self.stBooster.SetFont(wx.Font(wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString))
contentFGSizer.Add(self.stBooster, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL, 5)
self.stFits = wx.StaticText(self, wx.ID_ANY, u"Fits", wx.DefaultPosition, wx.DefaultSize, 0)
self.stFits.Wrap(-1)
self.stFits.SetFont(wx.Font(wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString))
contentFGSizer.Add(self.stFits, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL, 5)
self.stCharacters = wx.StaticText(self, wx.ID_ANY, u"Characters", wx.DefaultPosition, wx.DefaultSize, 0)
self.stCharacters.Wrap(-1)
self.stCharacters.SetFont(wx.Font(wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString))
contentFGSizer.Add(self.stCharacters, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL, 5)
self.m_staticline2 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
contentFGSizer.Add(self.m_staticline2, 0, wx.EXPAND, 5)
self.m_staticline3 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
contentFGSizer.Add(self.m_staticline3, 0, wx.EXPAND, 5)
self.m_staticline4 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
contentFGSizer.Add(self.m_staticline4, 0, wx.EXPAND, 5)
# Content
for id_ in self.fleet:
# set various properties
self.fleet[id_]['stLabel'].Wrap(-1)
self.fleet[id_]['stLabel'].SetFont(
wx.Font(wx.NORMAL_FONT.GetPointSize(), 70, 90, 92, False, wx.EmptyString))
self.fleet[id_]['stText'].Wrap(-1)
# bind text and choice events
self.fleet[id_]['stText'].Bind(wx.EVT_LEFT_DCLICK, self.RemoveBooster)
self.fleet[id_]['stText'].Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow)
self.fleet[id_]['stText'].Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
self.fleet[id_]['stText'].SetToolTip(wx.ToolTip("Double click to remove booster"))
self.fleet[id_]['chChar'].Bind(wx.EVT_CHOICE, self.CharChanged)
self.fleet[id_]['chFit'].Bind(wx.EVT_CHOICE, self.OnFitChoiceSelected)
# add fit text and choice to the fit sizer
self.fleet[id_]['fitSizer'].Add(self.fleet[id_]['stText'], 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
self.fleet[id_]['fitSizer'].Add(self.fleet[id_]['chFit'], 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND,
1)
# add everything to the content sizer
contentFGSizer.Add(self.fleet[id_]['stLabel'], 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
contentFGSizer.Add(self.fleet[id_]['fitSizer'], 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL | wx.EXPAND, 5)
contentFGSizer.Add(self.fleet[id_]['chChar'], 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
mainSizer.Add(contentFGSizer, 1, wx.EXPAND, 0)
mainSizer.Add(helpSizer, 0, wx.EXPAND, 0)
self.SetSizer(mainSizer)
self.SetAutoLayout(True)
self.SetupScrolling()
self.mainFrame.Bind(GE.CHAR_LIST_UPDATED, self.RefreshCharacterList)
self.mainFrame.Bind(GE.FIT_CHANGED, self.fitSelected)
self.mainFrame.Bind(gui.shipBrowser.EVT_FIT_RENAMED, self.fitRenamed)
self.mainFrame.Bind(gui.shipBrowser.BOOSTER_LIST_UPDATED, self.RefreshBoosterFits)
self.RefreshBoosterFits()
self.RefreshCharacterList()
def buildBoostermenu(self):
menu = wx.Menu()
for option in self.options:
item = menu.Append(-1, option)
# We bind it to the mainFrame because it may be called from either this class or from FitItem via shipBrowser
self.mainFrame.Bind(wx.EVT_MENU, self.OnPopupItemSelected, item)
return menu
def OnEnterWindow(self, event):
obj = event.GetEventObject()
obj.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
event.Skip()
def OnLeaveWindow(self, event):
obj = event.GetEventObject()
obj.SetCursor(wx.StockCursor(wx.CURSOR_DEFAULT))
event.Skip()
def CharChanged(self, event):
''' Change booster character '''
chBooster = event.GetEventObject()
type_ = -1
for id_ in self.fleet:
if chBooster == self.fleet[id_]['chChar']:
type_ = id_
if type_ == -1:
event.Skip()
return
sFit = Fit.getInstance()
fleetSrv = Fleet.getInstance()
activeFitID = self.mainFrame.getActiveFit()
fit = sFit.getFit(activeFitID)
# sChar = Character.getInstance()
# charList = sChar.getCharacterList()
if activeFitID:
commanders = fleetSrv.loadLinearFleet(fit)
if commanders is None:
fleetCom, wingCom, squadCom = (None, None, None)
else:
fleetCom, wingCom, squadCom = commanders
if type_ == 0:
if fleetCom:
charID = chBooster.GetClientData(chBooster.GetSelection())
sFit.changeChar(fleetCom.ID, charID)
else:
chBooster.SetSelection(0)
if type_ == 1:
if wingCom:
charID = chBooster.GetClientData(chBooster.GetSelection())
sFit.changeChar(wingCom.ID, charID)
else:
chBooster.SetSelection(0)
if type_ == 2:
if squadCom:
charID = chBooster.GetClientData(chBooster.GetSelection())
sFit.changeChar(squadCom.ID, charID)
else:
chBooster.SetSelection(0)
sFit.recalc(fit, withBoosters=True)
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFitID))
else:
chBooster.SetSelection(0)
def RemoveBooster(self, event):
activeFitID = self.mainFrame.getActiveFit()
if not activeFitID:
return
location = event.GetEventObject()
for id_ in self.fleet:
if location == self.fleet[id_]['stText']:
type_ = id_
sFit = Fit.getInstance()
boostee = sFit.getFit(activeFitID)
booster = None
fleetSrv = Fleet.getInstance()
if type_ == 0:
fleetSrv.setLinearFleetCom(boostee, booster)
elif type_ == 1:
fleetSrv.setLinearWingCom(boostee, booster)
elif type_ == 2:
fleetSrv.setLinearSquadCom(boostee, booster)
# Hide stText and, default fit selection, and enable it
location.Hide()
choice = self.fleet[type_]['chFit']
choice.SetSelection(0)
choice.Show()
sFit.recalc(boostee, withBoosters=True)
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFitID))
def fitRenamed(self, event):
# fleetSrv = Fleet.getInstance()
activeFitID = self.mainFrame.getActiveFit()
if activeFitID:
ev = event
ev.fitID = activeFitID
self.fitSelected(ev)
def fitSelected(self, event):
''' Fires when active fit is selected and when booster is saved to fit. Update the UI to reflect changes '''
fleetSrv = Fleet.getInstance()
activeFitID = self.mainFrame.getActiveFit()
sFit = Fit.getInstance()
fit = sFit.getFit(event.fitID or activeFitID)
self.Parent.Parent.DisablePage(self, not fit or fit.isStructure)
commanders = (None, None, None)
if activeFitID:
commanders = fleetSrv.loadLinearFleet(fit)
for id_ in self.fleet:
# try...except here as we're trying 2 different criteria and want to fall back on the same code
try:
commander = commanders[id_]
if not activeFitID or commander is None:
raise Exception()
self.fleet[id_]['stText'].SetLabel(commander.ship.item.name + ": " + commander.name)
self.fleet[id_]['chChar'].SetStringSelection(
commander.character.name if commander.character is not None else "All 0")
self.fleet[id_]['chChar'].Enable()
self.fleet[id_]['chFit'].Hide()
self.fleet[id_]['stText'].Show()
except:
# set defaults, disable char selection, and enable fit selection
self.fleet[id_]['stText'].SetLabel("None")
self.fleet[id_]['chChar'].SetStringSelection("All 0")
self.fleet[id_]['chChar'].Disable()
self.fleet[id_]['chFit'].SetSelection(0)
self.fleet[id_]['chFit'].Show()
self.fleet[id_]['stText'].Hide()
if activeFitID:
self.Enable()
else:
self.Disable()
self.Layout()
self.SendSizeEvent()
def AddCommander(self, fitID, type=None):
''' Adds booster to a fit, then recalculates active fit '''
if type is None:
return
activeFitID = self.mainFrame.getActiveFit()
if activeFitID:
sFit = Fit.getInstance()
boostee = sFit.getFit(activeFitID)
booster = sFit.getFit(fitID)
fleetSrv = Fleet.getInstance()
if type == 0:
fleetSrv.setLinearFleetCom(boostee, booster)
elif type == 1:
fleetSrv.setLinearWingCom(boostee, booster)
elif type == 2:
fleetSrv.setLinearSquadCom(boostee, booster)
sFit.recalc(boostee)
wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=activeFitID))
def RefreshBoosterFits(self, event=None):
sFit = Fit.getInstance()
sMkt = Market.getInstance()
fitList = sFit.getBoosterFits()
for id_ in self.fleet:
choice = self.fleet[id_]['chFit']
chCurrSelection = choice.GetSelection()
chCurrData = -1
if chCurrSelection != -1:
chCurrData = choice.GetClientData(chCurrSelection)
chCurrSelString = choice.GetString(chCurrSelection)
choice.Clear()
currSelFound = False
choice.Append("None", -1)
for fit in fitList:
fit_id, name, type_ = fit
ship = sMkt.getItem(type_)
choice.Append(ship.name + ': ' + name, fit_id)
if chCurrData == fit_id:
currSelFound = True
if chCurrSelection == -1:
choice.SetSelection(0)
else:
if currSelFound:
choice.SetStringSelection(chCurrSelString)
else:
choice.SetSelection(0)
def RefreshCharacterList(self, event=None):
sChar = Character.getInstance()
charList = sChar.getCharacterList()
for id_ in self.fleet:
choice = self.fleet[id_]['chChar']
chCurrSelection = choice.GetSelection()
chCurrData = -1
if chCurrSelection != -1:
chCurrData = choice.GetClientData(chCurrSelection)
chCurrSelString = choice.GetString(chCurrSelection)
choice.Clear()
currSelFound = False
for char in charList:
choice.Append(char.name, char.ID)
if chCurrData == char.ID:
currSelFound = True
if chCurrSelection == -1:
choice.SetSelection(1)
else:
if currSelFound:
choice.SetStringSelection(chCurrSelString)
else:
choice.SetSelection(1)
def handleDrag(self, type, fitID):
''' Handle dragging of fit to fleet interface '''
# Those are drags coming from pyfa sources, NOT builtin wx drags
self.draggedFitID = None
if type == "fit":
sFit = Fit.getInstance()
fit = sFit.getFit(self.mainFrame.getActiveFit())
if fit and not fit.isStructure:
self.draggedFitID = fitID
pos = wx.GetMousePosition()
pos = self.ScreenToClient(pos)
self.PopupMenu(self.FitDNDPopupMenu, pos)
def OnPopupItemSelected(self, event):
''' Fired when booster popup item is selected '''
# Get menu selection ID via self.options
menuItem = event.EventObject.FindItemById(event.GetId())
type_ = self.options.index(menuItem.GetText())
if self.draggedFitID:
sFit = Fit.getInstance()
draggedFit = sFit.getFit(self.draggedFitID)
self.AddCommander(draggedFit.ID, type_)
self.mainFrame.additionsPane.select("Fleet")
def OnFitChoiceSelected(self, event):
''' Fired when booster choice is selected '''
sFit = Fit.getInstance()
# set type via choice box used
chFit = event.GetEventObject()
fitID = chFit.GetClientData(chFit.GetSelection())
type_ = -1
for id_ in self.fleet:
if chFit == self.fleet[id_]['chFit']:
type_ = id_
if type_ == -1 or fitID == -1:
event.Skip()
return
fit = sFit.getFit(fitID)
self.AddCommander(fit.ID, type_)
self.mainFrame.additionsPane.select("Fleet")