Files
pyfa/gui/graphFrame.py
2017-02-07 00:33:15 -05:00

298 lines
9.7 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 os
import logging
import imp
import wx
from service.fit import Fit
import gui.display
import gui.mainFrame
import gui.globalEvents as GE
from gui.graph import Graph
from gui.bitmapLoader import BitmapLoader
from config import parsePath
# Don't actually import the thing, since it takes for fucking ever
try:
imp.find_module('matplotlib')
enabled = True
except ImportError:
enabled = False
mplImported = False
logger = logging.getLogger(__name__)
if not enabled:
logger.info("Problems importing matplotlib; continuing without graphs")
class GraphFrame(wx.Frame):
def __init__(self, parent, style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE | wx.FRAME_FLOAT_ON_PARENT):
global enabled
global mplImported
# Import here
try:
import matplotlib as mpl
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as Canvas
from matplotlib.figure import Figure
enabled = True
except ImportError:
enabled = False
self.legendFix = False
if not enabled:
return
try:
cache_dir = mpl._get_cachedir()
except:
cache_dir = os.path.expanduser(os.path.join("~", ".matplotlib"))
cache_file = parsePath(cache_dir, 'fontList.cache')
if os.access(cache_dir, os.W_OK | os.X_OK) and os.path.isfile(cache_file):
# remove matplotlib font cache, see #234
os.remove(cache_file)
if not mplImported:
mpl.use('wxagg')
enabled = True
if mpl.__version__[0] != "1":
print("pyfa: Found matplotlib version ", mpl.__version__, " - activating OVER9000 workarounds")
print("pyfa: Recommended minimum matplotlib version is 1.0.0")
self.legendFix = True
mplImported = True
wx.Frame.__init__(self, parent, title=u"pyfa: Graph Generator", style=style, size=(520, 390))
i = wx.IconFromBitmap(BitmapLoader.getBitmap("graphs_small", "gui"))
self.SetIcon(i)
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.CreateStatusBar()
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.mainSizer)
sFit = Fit.getInstance()
fit = sFit.getFit(self.mainFrame.getActiveFit())
self.fits = [fit] if fit is not None else []
self.fitList = FitList(self)
self.fitList.SetMinSize((270, -1))
self.fitList.fitList.update(self.fits)
self.graphSelection = wx.Choice(self, wx.ID_ANY, style=0)
self.mainSizer.Add(self.graphSelection, 0, wx.EXPAND)
self.figure = Figure(figsize=(4, 3))
rgbtuple = wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE).Get()
clr = [c / 255. for c in rgbtuple]
self.figure.set_facecolor(clr)
self.figure.set_edgecolor(clr)
self.canvas = Canvas(self, -1, self.figure)
self.canvas.SetBackgroundColour(wx.Colour(*rgbtuple))
self.subplot = self.figure.add_subplot(111)
self.subplot.grid(True)
self.mainSizer.Add(self.canvas, 1, wx.EXPAND)
self.mainSizer.Add(wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL), 0,
wx.EXPAND)
self.gridPanel = wx.Panel(self)
self.mainSizer.Add(self.gridPanel, 0, wx.EXPAND)
dummyBox = wx.BoxSizer(wx.VERTICAL)
self.gridPanel.SetSizer(dummyBox)
self.gridSizer = wx.FlexGridSizer(0, 4)
self.gridSizer.AddGrowableCol(1)
dummyBox.Add(self.gridSizer, 0, wx.EXPAND)
for view in Graph.views:
view = view()
self.graphSelection.Append(view.name, view)
self.graphSelection.SetSelection(0)
self.fields = {}
self.select(0)
self.sl1 = wx.StaticLine(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LI_HORIZONTAL)
self.mainSizer.Add(self.sl1, 0, wx.EXPAND)
self.mainSizer.Add(self.fitList, 0, wx.EXPAND)
self.fitList.fitList.Bind(wx.EVT_LEFT_DCLICK, self.removeItem)
self.mainFrame.Bind(GE.FIT_CHANGED, self.draw)
self.Bind(wx.EVT_CLOSE, self.close)
self.Fit()
self.SetMinSize(self.GetSize())
def handleDrag(self, type, fitID):
if type == "fit":
self.AppendFitToList(fitID)
def close(self, event):
self.fitList.fitList.Unbind(wx.EVT_LEFT_DCLICK, handler=self.removeItem)
self.mainFrame.Unbind(GE.FIT_CHANGED, handler=self.draw)
event.Skip()
def getView(self):
return self.graphSelection.GetClientData(self.graphSelection.GetSelection())
def getValues(self):
values = {}
for fieldName, field in self.fields.iteritems():
values[fieldName] = field.GetValue()
return values
def select(self, index):
view = self.getView()
icons = view.getIcons()
labels = view.getLabels()
sizer = self.gridSizer
self.gridPanel.DestroyChildren()
self.fields.clear()
# Setup textboxes
for field, defaultVal in view.getFields().iteritems():
textBox = wx.TextCtrl(self.gridPanel, wx.ID_ANY, style=0)
self.fields[field] = textBox
textBox.Bind(wx.EVT_TEXT, self.onFieldChanged)
sizer.Add(textBox, 1, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 3)
if defaultVal is not None:
if not isinstance(defaultVal, basestring):
defaultVal = ("%f" % defaultVal).rstrip("0")
if defaultVal[-1:] == ".":
defaultVal += "0"
textBox.ChangeValue(defaultVal)
imgLabelSizer = wx.BoxSizer(wx.HORIZONTAL)
if icons:
icon = icons.get(field)
if icon is not None:
static = wx.StaticBitmap(self.gridPanel)
static.SetBitmap(icon)
imgLabelSizer.Add(static, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, 1)
if labels:
label = labels.get(field)
label = label if label is not None else field
else:
label = field
imgLabelSizer.Add(wx.StaticText(self.gridPanel, wx.ID_ANY, label), 0,
wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 3)
sizer.Add(imgLabelSizer, 0, wx.ALIGN_CENTER_VERTICAL)
self.draw()
def draw(self, event=None):
values = self.getValues()
view = self.getView()
self.subplot.clear()
self.subplot.grid(True)
legend = []
for fit in self.fits:
try:
success, status = view.getPoints(fit, values)
if not success:
# TODO: Add a pwetty statys bar to report errors with
self.SetStatusText(status)
return
x, y = success, status
self.subplot.plot(x, y)
legend.append(fit.name)
except:
self.SetStatusText("Invalid values in '%s'" % fit.name)
self.canvas.draw()
return
if self.legendFix and len(legend) > 0:
leg = self.subplot.legend(tuple(legend), "upper right", shadow=False)
for t in leg.get_texts():
t.set_fontsize('small')
for l in leg.get_lines():
l.set_linewidth(1)
elif not self.legendFix and len(legend) > 0:
leg = self.subplot.legend(tuple(legend), "upper right", shadow=False, frameon=False)
for t in leg.get_texts():
t.set_fontsize('small')
for l in leg.get_lines():
l.set_linewidth(1)
self.canvas.draw()
self.SetStatusText("")
if event is not None:
event.Skip()
def onFieldChanged(self, event):
self.draw()
def AppendFitToList(self, fitID):
sFit = Fit.getInstance()
fit = sFit.getFit(fitID)
if fit not in self.fits:
self.fits.append(fit)
self.fitList.fitList.update(self.fits)
self.draw()
def removeItem(self, event):
row, _ = self.fitList.fitList.HitTest(event.Position)
if row != -1:
del self.fits[row]
self.fitList.fitList.update(self.fits)
self.draw()
class FitList(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent)
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
self.SetSizer(self.mainSizer)
self.fitList = FitDisplay(self)
self.mainSizer.Add(self.fitList, 1, wx.EXPAND)
fitToolTip = wx.ToolTip("Drag a fit into this list to graph it")
self.fitList.SetToolTip(fitToolTip)
class FitDisplay(gui.display.Display):
DEFAULT_COLS = ["Base Icon",
"Base Name"]
def __init__(self, parent):
gui.display.Display.__init__(self, parent)