Rework target profile editor to be non-blocking window

This commit is contained in:
DarkPhoenix
2019-08-09 20:57:20 +03:00
parent 01371f227c
commit c315adf987
7 changed files with 111 additions and 93 deletions

View File

@@ -67,14 +67,17 @@ except Exception:
class GraphFrame(wx.Frame):
def __init__(self, parent, style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE | wx.FRAME_FLOAT_ON_PARENT):
def __init__(self, parent):
global graphFrame_enabled
if not graphFrame_enabled:
pyfalog.warning('Matplotlib is not enabled. Skipping initialization.')
return
wx.Frame.__init__(self, parent, title='pyfa: Graph Generator', style=style, size=(520, 390))
wx.Frame.__init__(
self, parent, title='Graphs',
style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE | wx.FRAME_FLOAT_ON_PARENT,
size=(520, 390))
self.mainFrame = gui.mainFrame.MainFrame.getInstance()
self.SetIcon(wx.Icon(BitmapLoader.getBitmap('graphs_small', 'gui')))
@@ -122,7 +125,7 @@ class GraphFrame(wx.Frame):
self.ctrlPanel.updateControls(layout=False)
# Event bindings - local events
self.Bind(wx.EVT_CLOSE, self.closeEvent)
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)
# Event bindings - external events
@@ -149,15 +152,11 @@ class GraphFrame(wx.Frame):
self.SetSize(newSize)
self.SetMinSize(newSize)
def closeEvent(self, event):
self.closeWindow()
event.Skip()
def kbEvent(self, event):
keycode = event.GetKeyCode()
mstate = wx.GetMouseState()
if keycode == wx.WXK_ESCAPE and mstate.GetModifiers() == wx.MOD_NONE:
self.closeWindow()
self.Close()
return
event.Skip()
@@ -224,7 +223,7 @@ class GraphFrame(wx.Frame):
self.draw()
event.Skip()
def closeWindow(self):
def OnClose(self, event):
self.mainFrame.Unbind(GE.FIT_RENAMED, handler=self.OnFitRenamed)
self.mainFrame.Unbind(GE.FIT_CHANGED, handler=self.OnFitChanged)
self.mainFrame.Unbind(GE.FIT_REMOVED, handler=self.OnFitRemoved)
@@ -233,7 +232,7 @@ class GraphFrame(wx.Frame):
self.mainFrame.Unbind(GE.TARGET_PROFILE_REMOVED, handler=self.OnProfileRemoved)
self.mainFrame.Unbind(RESIST_MODE_CHANGED, handler=self.OnResistModeChanged)
self.mainFrame.Unbind(GE.GRAPH_OPTION_CHANGED, handler=self.OnGraphOptionChanged)
self.Destroy()
event.Skip()
def getView(self):
return self.graphSelection.GetClientData(self.graphSelection.GetSelection())

View File

@@ -2,7 +2,7 @@ import gui.mainFrame
from eos.saveddata.targetProfile import TargetProfile
from graphs.wrapper import TargetWrapper
from gui.contextMenu import ContextMenuSingle
from gui.targetProfileEditor import TargetProfileEditorDlg
from gui.targetProfileEditor import TargetProfileEditor
class TargetProfileEditor(ContextMenuSingle):
@@ -25,8 +25,7 @@ class TargetProfileEditor(ContextMenuSingle):
return 'Edit Target Profile'
def activate(self, callingWindow, fullContext, mainItem, i):
with TargetProfileEditorDlg(parent=callingWindow, selected=mainItem.item) as dlg:
dlg.ShowModal()
self.mainFrame.ShowTargetProfileEditor(selected=mainItem.item)
TargetProfileEditor.register()

View File

@@ -97,58 +97,60 @@ class EntityEditor(wx.Panel):
raise NotImplementedError()
def OnNew(self, event):
dlg = TextEntryValidatedDialog(self, self.validator,
"Enter a name for your new {}:".format(self.entityName),
"New {}".format(self.entityName))
dlg.CenterOnParent()
with TextEntryValidatedDialog(
self, self.validator, "Enter a name for your new {}:".format(self.entityName),
"New {}".format(self.entityName)
) as dlg:
dlg.CenterOnParent()
if dlg.ShowModal() == wx.ID_OK:
# using dlg.textctrl.GetValue instead of simply dlg.GetValue because the proper way does not work in wxPython 2.8
new = self.DoNew(dlg.txtctrl.GetValue().strip())
self.refreshEntityList(new)
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
else:
return False
if dlg.ShowModal() == wx.ID_OK:
# using dlg.textctrl.GetValue instead of simply dlg.GetValue because the proper way does not work in wxPython 2.8
new = self.DoNew(dlg.txtctrl.GetValue().strip())
self.refreshEntityList(new)
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
else:
return False
def OnCopy(self, event):
dlg = TextEntryValidatedDialog(self, self.validator,
"Enter a name for your {} copy:".format(self.entityName),
"Copy {}".format(self.entityName))
active = self.getActiveEntity()
dlg.SetValue("{} Copy".format(active.name))
dlg.txtctrl.SetInsertionPointEnd()
dlg.CenterOnParent()
with TextEntryValidatedDialog(
self, self.validator, "Enter a name for your {} copy:".format(self.entityName),
"Copy {}".format(self.entityName)
) as dlg:
active = self.getActiveEntity()
dlg.SetValue("{} Copy".format(active.name))
dlg.txtctrl.SetInsertionPointEnd()
dlg.CenterOnParent()
if dlg.ShowModal() == wx.ID_OK:
copy = self.DoCopy(active, dlg.txtctrl.GetValue().strip())
self.refreshEntityList(copy)
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
if dlg.ShowModal() == wx.ID_OK:
copy = self.DoCopy(active, dlg.txtctrl.GetValue().strip())
self.refreshEntityList(copy)
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
def OnRename(self, event):
dlg = TextEntryValidatedDialog(self, self.validator,
"Enter a new name for your {}:".format(self.entityName),
"Rename {}".format(self.entityName))
active = self.getActiveEntity()
dlg.SetValue(active.name)
dlg.txtctrl.SetInsertionPointEnd()
dlg.CenterOnParent()
with TextEntryValidatedDialog(
self, self.validator, "Enter a new name for your {}:".format(self.entityName),
"Rename {}".format(self.entityName)
) as dlg:
active = self.getActiveEntity()
dlg.SetValue(active.name)
dlg.txtctrl.SetInsertionPointEnd()
dlg.CenterOnParent()
if dlg.ShowModal() == wx.ID_OK:
self.DoRename(active, dlg.txtctrl.GetValue().strip())
self.refreshEntityList(active)
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
if dlg.ShowModal() == wx.ID_OK:
self.DoRename(active, dlg.txtctrl.GetValue().strip())
self.refreshEntityList(active)
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
def OnDelete(self, event):
dlg = wx.MessageDialog(self,
"Do you really want to delete the {} {}?".format(self.getActiveEntity().name,
self.entityName),
"Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION)
dlg.CenterOnParent()
if dlg.ShowModal() == wx.ID_YES:
self.DoDelete(self.getActiveEntity())
self.refreshEntityList()
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
with wx.MessageDialog(
self, "Do you really want to delete the {} {}?".format(self.getActiveEntity().name, self.entityName),
"Confirm Delete", wx.YES | wx.NO | wx.ICON_QUESTION
) as dlg:
dlg.CenterOnParent()
if dlg.ShowModal() == wx.ID_YES:
self.DoDelete(self.getActiveEntity())
self.refreshEntityList()
wx.PostEvent(self.entityChoices, wx.CommandEvent(wx.wxEVT_COMMAND_CHOICE_SELECTED))
def refreshEntityList(self, selected=None):
self.choices = self.getEntitiesFromContext()
@@ -168,7 +170,11 @@ class EntityEditor(wx.Panel):
return self.choices[self.entityChoices.GetSelection()]
def setActiveEntity(self, entity):
self.entityChoices.SetSelection(self.choices.index(entity))
try:
idx = self.choices.index(entity)
except IndexError:
return
self.entityChoices.SetSelection(idx)
def checkEntitiesExist(self):
if len(self.choices) == 0:

View File

@@ -180,7 +180,7 @@ class CharacterSelection(wx.Panel):
if charID == -1:
# revert to previous character
self.charChoice.SetSelection(self.charCache)
self.mainFrame.showCharacterEditor(event)
self.mainFrame.OnShowCharacterEditor(event)
return
self.toggleRefreshButton()

View File

@@ -24,7 +24,7 @@ class EveFittings(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title="Browse EVE Fittings", pos=wx.DefaultPosition,
size=wx.Size(750, 450), style=wx.DEFAULT_FRAME_STYLE | wx.TAB_TRAVERSAL)
size=wx.Size(750, 450), style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT)
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNFACE))

View File

@@ -60,7 +60,7 @@ from gui.preferenceDialog import PreferenceDialog
from gui.setEditor import ImplantSetEditorDlg
from gui.shipBrowser import ShipBrowser
from gui.statsPane import StatsPane
from gui.targetProfileEditor import TargetProfileEditorDlg
from gui.targetProfileEditor import TargetProfileEditor
from gui.updateDialog import UpdateDialog
from gui.utils.clipboard import fromClipboard
from service.character import Character
@@ -213,6 +213,7 @@ class MainFrame(wx.Frame):
# Internal vars to keep track of other windows (graphing/stats)
self.graphFrame = None
self.tgtProfileEditor = None
self.statsWnds = []
self.activeStatsWnd = None
@@ -385,31 +386,39 @@ class MainFrame(wx.Frame):
# info.WebSite = (forumUrl, "pyfa thread at EVE Online forum")
wx.adv.AboutBox(info)
def showDevTools(self, event):
def OnShowDevTools(self, event):
dlg = DevTools(self)
dlg.Show()
def showCharacterEditor(self, event):
def OnShowCharacterEditor(self, event):
dlg = CharacterEditor(self)
dlg.Show()
def showAttrEditor(self, event):
def OnShowAttrEditor(self, event):
dlg = AttributeEditor(self)
dlg.Show()
def showTargetProfileEditor(self, event):
with TargetProfileEditorDlg(self) as dlg:
dlg.ShowModal()
def OnShowTargetProfileEditor(self, event):
self.ShowTargetProfileEditor()
def showDamagePatternEditor(self, event):
def ShowTargetProfileEditor(self, selected=None):
if not self.tgtProfileEditor:
self.tgtProfileEditor = TargetProfileEditor(self, selected=selected)
self.tgtProfileEditor.Show()
else:
if selected:
self.tgtProfileEditor.selectTargetProfile(selected)
self.tgtProfileEditor.SetFocus()
def OnShowDamagePatternEditor(self, event):
with DmgPatternEditorDlg(self) as dlg:
dlg.ShowModal()
def showImplantSetEditor(self, event):
def OnShowImplantSetEditor(self, event):
with ImplantSetEditorDlg(self) as dlg:
dlg.ShowModal()
def showExportDialog(self, event):
def OnShowExportDialog(self, event):
""" Export active fit """
sFit = Fit.getInstance()
fit = sFit.getFit(self.getActiveFit())
@@ -444,7 +453,7 @@ class MainFrame(wx.Frame):
except RuntimeError:
pyfalog.error("Tried to destroy an object that doesn't exist in <showExportDialog>.")
def showPreferenceDialog(self, event):
def OnShowPreferenceDialog(self, event):
with PreferenceDialog(self) as dlg:
dlg.ShowModal()
@@ -463,21 +472,21 @@ class MainFrame(wx.Frame):
# Widgets Inspector
if config.debug:
self.Bind(wx.EVT_MENU, self.openWXInspectTool, id=self.widgetInspectMenuID)
self.Bind(wx.EVT_MENU, self.showDevTools, id=menuBar.devToolsId)
self.Bind(wx.EVT_MENU, self.OnShowDevTools, id=menuBar.devToolsId)
# About
self.Bind(wx.EVT_MENU, self.ShowAboutBox, id=wx.ID_ABOUT)
# Char editor
self.Bind(wx.EVT_MENU, self.showCharacterEditor, id=menuBar.characterEditorId)
self.Bind(wx.EVT_MENU, self.OnShowCharacterEditor, id=menuBar.characterEditorId)
# Damage pattern editor
self.Bind(wx.EVT_MENU, self.showDamagePatternEditor, id=menuBar.damagePatternEditorId)
self.Bind(wx.EVT_MENU, self.OnShowDamagePatternEditor, id=menuBar.damagePatternEditorId)
# Target Profile editor
self.Bind(wx.EVT_MENU, self.showTargetProfileEditor, id=menuBar.targetProfileEditorId)
self.Bind(wx.EVT_MENU, self.OnShowTargetProfileEditor, id=menuBar.targetProfileEditorId)
# Implant Set editor
self.Bind(wx.EVT_MENU, self.showImplantSetEditor, id=menuBar.implantSetEditorId)
self.Bind(wx.EVT_MENU, self.OnShowImplantSetEditor, id=menuBar.implantSetEditorId)
# Import dialog
self.Bind(wx.EVT_MENU, self.fileImportDialog, id=wx.ID_OPEN)
# Export dialog
self.Bind(wx.EVT_MENU, self.showExportDialog, id=wx.ID_SAVEAS)
self.Bind(wx.EVT_MENU, self.OnShowExportDialog, id=wx.ID_SAVEAS)
# Import from Clipboard
self.Bind(wx.EVT_MENU, self.importFromClipboard, id=wx.ID_PASTE)
# Backup fits
@@ -489,7 +498,7 @@ class MainFrame(wx.Frame):
# Export HTML
self.Bind(wx.EVT_MENU, self.exportHtml, id=menuBar.exportHtmlId)
# Preference dialog
self.Bind(wx.EVT_MENU, self.showPreferenceDialog, id=wx.ID_PREFERENCES)
self.Bind(wx.EVT_MENU, self.OnShowPreferenceDialog, id=wx.ID_PREFERENCES)
# User guide
self.Bind(wx.EVT_MENU, self.goWiki, id=menuBar.wikiId)
@@ -515,7 +524,7 @@ class MainFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.ssoHandler, id=menuBar.ssoLoginId)
# Open attribute editor
self.Bind(wx.EVT_MENU, self.showAttrEditor, id=menuBar.attrEditorId)
self.Bind(wx.EVT_MENU, self.OnShowAttrEditor, id=menuBar.attrEditorId)
# Toggle Overrides
self.Bind(wx.EVT_MENU, self.toggleOverrides, id=menuBar.toggleOverridesId)
@@ -526,7 +535,7 @@ class MainFrame(wx.Frame):
self.Bind(wx.EVT_MENU, self.toggleIgnoreRestriction, id=menuBar.toggleIgnoreRestrictionID)
# Graphs
self.Bind(wx.EVT_MENU, self.openGraphFrame, id=menuBar.graphFrameId)
self.Bind(wx.EVT_MENU, self.OnShowGraphFrame, id=menuBar.graphFrameId)
toggleSearchBoxId = wx.NewId()
toggleShipMarketId = wx.NewId()
@@ -957,7 +966,7 @@ class MainFrame(wx.Frame):
def closeWaitDialog(self):
del self.waitDialog
def openGraphFrame(self, event):
def OnShowGraphFrame(self, event):
if not self.graphFrame:
self.graphFrame = GraphFrame(self)

View File

@@ -111,7 +111,7 @@ class TargetProfileEntityEditor(EntityEditor):
wx.PostEvent(self.mainFrame, GE.TargetProfileRemoved(profileID=entity.ID))
class TargetProfileEditorDlg(wx.Dialog):
class TargetProfileEditor(wx.Frame):
DAMAGE_TYPES = OrderedDict([
("em", "EM resistance"),
@@ -124,9 +124,9 @@ class TargetProfileEditorDlg(wx.Dialog):
('radius', ('Radius', 'm'))])
def __init__(self, parent, selected=None):
wx.Dialog.__init__(
wx.Frame.__init__(
self, parent, id=wx.ID_ANY,
title="Target Profile Editor",
title="Target Profile Editor", style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT,
# Dropdown list widget is scaled to its longest content line on GTK, adapt to that
size=wx.Size(500, 240) if "wxGTK" in wx.PlatformInfo else wx.Size(350, 240))
@@ -235,7 +235,7 @@ class TargetProfileEditorDlg(wx.Dialog):
btn.Bind(wx.EVT_BUTTON, getattr(self, "{}Patterns".format(name.lower())))
if not self.entityEditor.checkEntitiesExist():
self.Destroy()
self.Close()
return
self.Layout()
@@ -259,10 +259,15 @@ class TargetProfileEditorDlg(wx.Dialog):
def OnInputTimer(self, event):
event.Skip()
if self.block:
return
if self.validateFields():
p = self.entityEditor.getActiveEntity()
TargetProfile.getInstance().saveChanges(p)
wx.PostEvent(self.mainFrame, GE.TargetProfileChanged(profileID=p.ID))
def validateFields(self):
valid = True
try:
p = self.entityEditor.getActiveEntity()
@@ -289,22 +294,18 @@ class TargetProfileEditorDlg(wx.Dialog):
self.stNotice.SetLabel("")
self.totSizer.Layout()
if event is not None:
event.Skip()
TargetProfile.getInstance().saveChanges(p)
wx.PostEvent(self.mainFrame, GE.TargetProfileChanged(profileID=p.ID))
except ValueError as e:
self.stNotice.SetLabel(e.args[0])
valid = False
finally: # Refresh for color changes to take effect immediately
self.Refresh()
return valid
def patternChanged(self, event=None):
"""Event fired when user selects pattern. Can also be called from script"""
if not self.entityEditor.checkEntitiesExist():
self.Destroy()
self.Close()
return
p = self.entityEditor.getActiveEntity()
@@ -327,7 +328,7 @@ class TargetProfileEditorDlg(wx.Dialog):
edit.ChangeValueFloat(amount)
self.block = False
self.OnFieldChanged()
self.validateFields()
def __del__(self):
pass
@@ -372,3 +373,7 @@ class TargetProfileEditorDlg(wx.Dialog):
changedFitIDs = Fit.getInstance().processTargetProfileChange()
if changedFitIDs:
wx.PostEvent(self.mainFrame, GE.FitChanged(fitIDs=changedFitIDs))
def selectTargetProfile(self, profile):
self.entityEditor.setActiveEntity(profile)
self.patternChanged()