From 2bec2e38b6ca44c0be44eaaae7742aa8b298718b Mon Sep 17 00:00:00 2001 From: HomeWorld Date: Sat, 11 Dec 2010 04:05:19 +0200 Subject: [PATCH 1/8] Made Display class 100% flicker free on wxMSW. --- gui/display.py | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/gui/display.py b/gui/display.py index c9865289e..71a367d9e 100644 --- a/gui/display.py +++ b/gui/display.py @@ -36,6 +36,9 @@ class Display(wx.ListCtrl): self.Bind(wx.EVT_LIST_COL_END_DRAG, self.resizeChecker) self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.resizeSkip) + if "wxMSW" in wx.PlatformInfo: + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBk) + self.mainFrame = gui.mainFrame.MainFrame.getInstance() i = 0 @@ -68,6 +71,42 @@ class Display(wx.ListCtrl): self.imageListBase = self.imageList.ImageCount + + def OnEraseBk(self,event): + if self.GetItemCount() >0: + width, height = self.GetClientSize() + dc = event.GetDC() + + dc.DestroyClippingRegion() + dc.SetClippingRegion(0, 0, width, height) + x,y,w,h = dc.GetClippingBox() + + topItem = self.GetTopItem() + bottomItem = topItem + self.GetCountPerPage() + + if bottomItem >= self.GetItemCount(): + bottomItem = self.GetItemCount() - 1 + + topRect = self.GetItemRect(topItem, wx.LIST_RECT_LABEL) + bottomRect = self.GetItemRect(bottomItem, wx.LIST_RECT_BOUNDS) + + + items_rect = wx.Rect(topRect.left, 0, bottomRect.right - topRect.left, bottomRect.bottom ) + + updateRegion = wx.Region(x,y,w,h) + updateRegion.SubtractRect(items_rect) + + dc.DestroyClippingRegion() + dc.SetClippingRegionAsRegion(updateRegion) + + dc.SetBackground(wx.Brush(self.GetBackgroundColour(), wx.SOLID)) + dc.Clear() + + dc.DestroyClippingRegion() + + else: + event.Skip() + def addColumn(self, i, col): self.activeColumns.append(col) info = wx.ListItem() @@ -170,7 +209,6 @@ class Display(wx.ListCtrl): self.SetItemData(item, id) - # self.Freeze() if 'wxMSW' in wx.PlatformInfo: for i,col in enumerate(self.activeColumns): From 3d264d47b7502e50950673cb66247e06b4fb17d2 Mon Sep 17 00:00:00 2001 From: HomeWorld Date: Sat, 11 Dec 2010 13:01:20 +0200 Subject: [PATCH 2/8] Optimized Display.populate to avoid wx.ListCtrl.DeleteAllItems as much as posible. The result is a smoother market search, etc --- gui/display.py | 50 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/gui/display.py b/gui/display.py index 71a367d9e..ac9573bd1 100644 --- a/gui/display.py +++ b/gui/display.py @@ -23,6 +23,7 @@ import gui.mainFrame from gui.viewColumn import ViewColumn from gui.cachingImageList import CachingImageList +from wxPython._controls import wxLIST_STATE_DONTCARE class Display(wx.ListCtrl): @@ -153,23 +154,54 @@ class Display(wx.ListCtrl): self.SetColumnWidth(column,self.columnsMinWidth[column]) colItem.resized = True + def getLastItem( self, state = wx.LIST_STATE_DONTCARE): + lastFound = -1 + while True: + index = self.GetNextItem( + lastFound, + wx.LIST_NEXT_ALL, + state, + ) + if index == -1: + break + else: + lastFound = index + + return lastFound + def populate(self, stuff): selection = [] - sel = self.GetFirstSelected() - while sel != -1: - selection.append(sel) - sel = self.GetNextSelected(sel) +# sel = self.GetFirstSelected() +# while sel != -1: +# selection.append(sel) +# sel = self.GetNextSelected(sel) - self.DeleteAllItems() +# self.DeleteAllItems() if stuff is not None: - for id, st in enumerate(stuff): - index = self.InsertStringItem(sys.maxint, "") + listItemCount = self.GetItemCount() + stuffItemCount = len(stuff) - for sel in selection: - self.Select(sel) + if listItemCount < stuffItemCount: + for i in xrange(stuffItemCount - listItemCount): + index = self.InsertStringItem(sys.maxint, "") + + if listItemCount > stuffItemCount: + if listItemCount - stuffItemCount > 20 and stuffItemCount >20: + self.DeleteAllItems() + for i in xrange(stuffItemCount): + index = self.InsertStringItem(sys.maxint, "") + else: + for i in xrange(listItemCount - stuffItemCount): + self.DeleteItem(self.getLastItem()) + self.Refresh() + + + +# for sel in selection: +# self.Select(sel) def refresh(self, stuff): if stuff == None: From abdd9498caf86c4209c8faeac8847f9788903a7c Mon Sep 17 00:00:00 2001 From: HomeWorld Date: Sat, 11 Dec 2010 13:06:15 +0200 Subject: [PATCH 3/8] Removed an useless import in gui.Display --- gui/display.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/gui/display.py b/gui/display.py index ac9573bd1..250d85022 100644 --- a/gui/display.py +++ b/gui/display.py @@ -23,8 +23,6 @@ import gui.mainFrame from gui.viewColumn import ViewColumn from gui.cachingImageList import CachingImageList -from wxPython._controls import wxLIST_STATE_DONTCARE - class Display(wx.ListCtrl): def __init__(self, parent, size = wx.DefaultSize, style = 0): From 1763619fe6c3264158be33315c352f4827b91a0a Mon Sep 17 00:00:00 2001 From: HomeWorld Date: Sat, 11 Dec 2010 13:31:00 +0200 Subject: [PATCH 4/8] Fixed a little logic oopsie in gui.Display.Populate --- gui/display.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/display.py b/gui/display.py index 250d85022..7bafe4ec0 100644 --- a/gui/display.py +++ b/gui/display.py @@ -187,7 +187,7 @@ class Display(wx.ListCtrl): index = self.InsertStringItem(sys.maxint, "") if listItemCount > stuffItemCount: - if listItemCount - stuffItemCount > 20 and stuffItemCount >20: + if listItemCount - stuffItemCount > 20 and stuffItemCount < 20: self.DeleteAllItems() for i in xrange(stuffItemCount): index = self.InsertStringItem(sys.maxint, "") From 374f91eec9d854dc3e2a5e60595770669d431309 Mon Sep 17 00:00:00 2001 From: HomeWorld Date: Sat, 11 Dec 2010 13:40:44 +0200 Subject: [PATCH 5/8] Fixed implant/booster views dblclick behaviour - added a check for remove case - we do not want our items removed if we are double clicking on state column --- gui/boosterView.py | 10 ++++++---- gui/implantView.py | 12 +++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/gui/boosterView.py b/gui/boosterView.py index 1e96af409..ffcc58e8f 100644 --- a/gui/boosterView.py +++ b/gui/boosterView.py @@ -63,10 +63,12 @@ class BoosterView(d.Display): def removeItem(self, event): row, _ = self.HitTest(event.Position) if row != -1: - fitID = self.mainFrame.getActiveFit() - cFit = service.Fit.getInstance() - cFit.removeBooster(fitID, self.GetItemData(row)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + col = self.getColumn(event.Position) + if col != self.getColIndex(State): + fitID = self.mainFrame.getActiveFit() + cFit = service.Fit.getInstance() + cFit.removeBooster(fitID, self.GetItemData(row)) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) def click(self, event): event.Skip() diff --git a/gui/implantView.py b/gui/implantView.py index d0247c884..ed9e4e91a 100644 --- a/gui/implantView.py +++ b/gui/implantView.py @@ -76,11 +76,13 @@ class ImplantView(d.Display): def removeItem(self, event): row, _ = self.HitTest(event.Position) if row != -1: - fitID = self.mainFrame.getActiveFit() - cFit = service.Fit.getInstance() - implant = self.implants[self.GetItemData(row)] - cFit.removeImplant(fitID, self.original.index(implant)) - wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) + col = self.getColumn(event.Position) + if col != self.getColIndex(State): + fitID = self.mainFrame.getActiveFit() + cFit = service.Fit.getInstance() + implant = self.implants[self.GetItemData(row)] + cFit.removeImplant(fitID, self.original.index(implant)) + wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) def click(self, event): event.Skip() From b6602bf501210126d4e8b675e59d1334fe27cd7f Mon Sep 17 00:00:00 2001 From: HomeWorld Date: Sat, 11 Dec 2010 13:50:52 +0200 Subject: [PATCH 6/8] Deselect items by default if marketBrowser itemView is repopulated --- gui/display.py | 19 ++++++------------- gui/marketBrowser.py | 1 + 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/gui/display.py b/gui/display.py index 7bafe4ec0..46c5e05b7 100644 --- a/gui/display.py +++ b/gui/display.py @@ -167,16 +167,13 @@ class Display(wx.ListCtrl): return lastFound + def deselectItems(self): + sel = self.GetFirstSelected() + while sel != -1: + self.SetItemState(sel, 0, wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED) + sel = self.GetNextSelected(sel) + def populate(self, stuff): - selection = [] - - -# sel = self.GetFirstSelected() -# while sel != -1: -# selection.append(sel) -# sel = self.GetNextSelected(sel) - -# self.DeleteAllItems() if stuff is not None: listItemCount = self.GetItemCount() @@ -197,10 +194,6 @@ class Display(wx.ListCtrl): self.Refresh() - -# for sel in selection: -# self.Select(sel) - def refresh(self, stuff): if stuff == None: return diff --git a/gui/marketBrowser.py b/gui/marketBrowser.py index 0234f8911..06e3e301a 100644 --- a/gui/marketBrowser.py +++ b/gui/marketBrowser.py @@ -332,6 +332,7 @@ class ItemView(d.Display): return (item.metaGroup.parent.name, item.metaGroup.ID , item.name) def populate(self, stuff): + self.deselectItems() stuff.sort(key=self.itemSort) self.active = stuff d.Display.populate(self, stuff) From 8660e36bad7082b63b04888e880bf7572cb895ac Mon Sep 17 00:00:00 2001 From: HomeWorld Date: Sat, 11 Dec 2010 14:09:57 +0200 Subject: [PATCH 7/8] Make sure drone view gets in sync with current fit (clear its content if there is no active fitting), also , make sure the first item is visible/all selected items deselected in case we switch to other fit --- gui/droneView.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/gui/droneView.py b/gui/droneView.py index 602a9f5bf..a401d518d 100644 --- a/gui/droneView.py +++ b/gui/droneView.py @@ -50,6 +50,9 @@ class DroneView(d.Display): def __init__(self, parent): d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) + + self.lastFitId = -1 + self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem) self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) @@ -98,14 +101,34 @@ class DroneView(d.Display): drone.item.name) def fitChanged(self, event): + + #Clear list and get out if current fitId is None + if event.fitID is None and self.lastFitId is not None: + self.DeleteAllItems() + self.lastFitId = None + event.Skip() + return + cFit = service.Fit.getInstance() fit = cFit.getFit(event.fitID) self.original = fit.drones if fit is not None else None self.drones = stuff = fit.drones[:] if fit is not None else None + if stuff is not None: stuff.sort(key=self.droneKey) + + if event.fitID != self.lastFitId: + self.lastFitId = event.fitID + + item = self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_DONTCARE) + + if item != -1: + self.EnsureVisible(item) + + self.deselectItems() + self.update(stuff) event.Skip() From 22ecdba471ed6c1fc2e347e5f866aebc452bd785 Mon Sep 17 00:00:00 2001 From: HomeWorld Date: Sat, 11 Dec 2010 14:16:57 +0200 Subject: [PATCH 8/8] Make sure implant/booster/projected view gets in sync with current fit (clear its content if there is no active fitting), also , make sure the first item is visible/all selected items deselected in case we switch to other fit --- gui/boosterView.py | 22 ++++++++++++++++++++++ gui/droneView.py | 2 +- gui/implantView.py | 21 +++++++++++++++++++++ gui/projectedView.py | 19 +++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/gui/boosterView.py b/gui/boosterView.py index ffcc58e8f..fbb4ace7b 100644 --- a/gui/boosterView.py +++ b/gui/boosterView.py @@ -32,6 +32,9 @@ class BoosterView(d.Display): def __init__(self, parent): d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) + + self.lastFitId = None + self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem) self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) @@ -42,10 +45,29 @@ class BoosterView(d.Display): self.Bind(wx.EVT_RIGHT_DOWN, self.scheduleMenu) def fitChanged(self, event): + + #Clear list and get out if current fitId is None + if event.fitID is None and self.lastFitId is not None: + self.DeleteAllItems() + self.lastFitId = None + event.Skip() + return + cFit = service.Fit.getInstance() fit = cFit.getFit(event.fitID) stuff = fit.boosters if fit is not None else None + + if event.fitID != self.lastFitId: + self.lastFitId = event.fitID + + item = self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_DONTCARE) + + if item != -1: + self.EnsureVisible(item) + + self.deselectItems() + self.populate(stuff) self.refresh(stuff) event.Skip() diff --git a/gui/droneView.py b/gui/droneView.py index a401d518d..581545769 100644 --- a/gui/droneView.py +++ b/gui/droneView.py @@ -51,7 +51,7 @@ class DroneView(d.Display): def __init__(self, parent): d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) - self.lastFitId = -1 + self.lastFitId = None self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem) diff --git a/gui/implantView.py b/gui/implantView.py index ed9e4e91a..7fcbd8562 100644 --- a/gui/implantView.py +++ b/gui/implantView.py @@ -31,6 +31,9 @@ class ImplantView(d.Display): def __init__(self, parent): d.Display.__init__(self, parent, style=wx.LC_SINGLE_SEL | wx.BORDER_NONE) + + self.lastFitId = None + self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) self.mainFrame.Bind(mb.ITEM_SELECTED, self.addItem) self.Bind(wx.EVT_LEFT_DCLICK, self.removeItem) @@ -53,12 +56,30 @@ class ImplantView(d.Display): wx.PostEvent(self.mainFrame, GE.FitChanged(fitID=fitID)) def fitChanged(self, event): + #Clear list and get out if current fitId is None + if event.fitID is None and self.lastFitId is not None: + self.DeleteAllItems() + self.lastFitId = None + event.Skip() + return + cFit = service.Fit.getInstance() fit = cFit.getFit(event.fitID) self.original = fit.implants if fit is not None else None self.implants = stuff = fit.implants if fit is not None else None if stuff is not None: stuff.sort(key=lambda implant: implant.slot) + + if event.fitID != self.lastFitId: + self.lastFitId = event.fitID + + item = self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_DONTCARE) + + if item != -1: + self.EnsureVisible(item) + + self.deselectItems() + self.populate(stuff) self.refresh(stuff) event.Skip() diff --git a/gui/projectedView.py b/gui/projectedView.py index 630a9b8d4..28e2ad3c7 100644 --- a/gui/projectedView.py +++ b/gui/projectedView.py @@ -49,6 +49,9 @@ class ProjectedView(d.Display): def __init__(self, parent): d.Display.__init__(self, parent, style = wx.LC_SINGLE_SEL | wx.BORDER_NONE) + + self.lastFitId = None + self.mainFrame.Bind(GE.FIT_CHANGED, self.fitChanged) self.Bind(wx.EVT_LEFT_DOWN, self.click) self.Bind(wx.EVT_RIGHT_DOWN, self.click) @@ -108,6 +111,13 @@ class ProjectedView(d.Display): return fit.name def fitChanged(self, event): + #Clear list and get out if current fitId is None + if event.fitID is None and self.lastFitId is not None: + self.DeleteAllItems() + self.lastFitId = None + event.Skip() + return + cFit = service.Fit.getInstance() fit = cFit.getFit(event.fitID) stuff = [] @@ -124,6 +134,15 @@ class ProjectedView(d.Display): stuff.extend(self.drones) stuff.extend(self.fits) + if event.fitID != self.lastFitId: + self.lastFitId = event.fitID + + item = self.GetNextItem(-1, wx.LIST_NEXT_ALL, wx.LIST_STATE_DONTCARE) + + if item != -1: + self.EnsureVisible(item) + + self.deselectItems() self.update(stuff) def get(self, row):