Skip to content

Commit

Permalink
wxGUI: Fix behaviour of top Single-Window GUI toolbars (#2568)
Browse files Browse the repository at this point in the history
Use agw.aui toolbar as the main toolbar to avoid strange behavior. This requires restructuring Toolbar classes. 

Co-authored-by: Anna Petrasova <kratochanna@gmail.com>
  • Loading branch information
lindakarlovska and petrasovaa committed Oct 28, 2022
1 parent e417678 commit 8c2239e
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 77 deletions.
238 changes: 177 additions & 61 deletions gui/wxpython/gui_core/toolbars.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import os

import wx
import wx.lib.agw.aui as aui

from core import globalvar
from core.debug import Debug
Expand Down Expand Up @@ -85,52 +86,27 @@
}


class BaseToolbar(ToolBar):
"""Abstract toolbar class.
Following code shows how to create new basic toolbar:
class MyToolbar(BaseToolbar):
def __init__(self, parent):
BaseToolbar.__init__(self, parent)
self.InitToolbar(self._toolbarData())
self.Realize()
def _toolbarData(self):
# e.g. ("help", _("Help")) tool short label (triangle/arrow
# at the right side of the toolbar)
return self._getToolbarData(
(
("help", Icons["help"].label),
Icons["help"],
self.parent.OnHelp
),
)
"""
class ToolbarController:
"""Controller specialized for wx.ToolBar subclass."""

def __init__(
self, parent, toolSwitcher=None, style=wx.NO_BORDER | wx.TB_HORIZONTAL
):
def __init__(self, classObject, widget, parent, toolSwitcher):
"""
:param classObject: toolbar class name (object, i.e. wx.Toolbar)
:param widget: toolbar instance
"""
self.classObject = classObject
self.widget = widget
self.parent = parent
wx.ToolBar.__init__(self, parent=self.parent, id=wx.ID_ANY, style=style)

self._default = None
self.SetToolBitmapSize(globalvar.toolbarSize)

self.toolSwitcher = toolSwitcher
self.handlers = {}
self.data = None

def InitToolbar(self, toolData):
"""Initialize toolbar, add tools to the toolbar"""
for tool in toolData:
self.CreateTool(*tool)

self._data = toolData

def _toolbarData(self):
"""Toolbar data (virtual)"""
return None
self.data = toolData

def CreateTool(self, label, bitmap, kind, shortHelp, longHelp, handler, pos=-1):
"""Add tool to the toolbar
Expand All @@ -147,32 +123,47 @@ def CreateTool(self, label, bitmap, kind, shortHelp, longHelp, handler, pos=-1):
internal_label = label

if label:
tool = vars(self)[internal_label] = NewId()
tool = vars(self.widget)[internal_label] = NewId()
Debug.msg(
3, "CreateTool(): tool=%d, label=%s bitmap=%s" % (tool, label, bitmap)
)
if pos < 0:
toolWin = self.AddLabelTool(
tool, label, bitmap, bmpDisabled, kind, shortHelp, longHelp
toolWin = self.classObject.AddTool(
self.widget,
tool,
label,
bitmap,
bmpDisabled,
kind,
shortHelp,
longHelp,
)
else:
toolWin = self.InsertLabelTool(
pos, tool, label, bitmap, bmpDisabled, kind, shortHelp, longHelp
toolWin = self.classObject.InsertTool(
self.widget,
pos,
tool,
label,
bitmap,
bmpDisabled,
kind,
shortHelp,
longHelp,
)
self.handlers[tool] = handler
self.Bind(wx.EVT_TOOL, handler, toolWin)
self.Bind(wx.EVT_TOOL, self.OnTool, toolWin)
self.widget.Bind(wx.EVT_TOOL, handler, toolWin)
self.widget.Bind(wx.EVT_TOOL, self.OnTool, toolWin)
else: # separator
self.AddSeparator()
self.classObject.AddSeparator(self.widget)

return tool

def EnableLongHelp(self, enable=True):
def EnableLongHelp(self, enable):
"""Enable/disable long help
:param enable: True for enable otherwise disable
"""
for tool in self._data:
for tool in self.data:
if isinstance(tool[0], tuple):
if tool[0][0] == "": # separator
continue
Expand All @@ -183,10 +174,12 @@ def EnableLongHelp(self, enable=True):
continue
else:
internal_label = tool[0]

label = vars(self.widget)[internal_label]
if enable:
self.SetToolLongHelp(vars(self)[internal_label], tool[4])
self.classObject.SetToolLongHelp(self.widget, label, tool[4])
else:
self.SetToolLongHelp(vars(self)[internal_label], "")
self.classObject.SetToolLongHelp(self.widget, label, "")

def OnTool(self, event):
"""Tool selected"""
Expand All @@ -196,14 +189,14 @@ def OnTool(self, event):
event.Skip()

def SelectTool(self, id):
self.ToggleTool(id, True)
self.classObject.ToggleTool(self.widget, id, True)
self.toolSwitcher.ToolChanged(id)

self.handlers[id](event=None)

def SelectDefault(self):
"""Select default tool"""
self.SelectTool(self._default)
self.SelectTool(self.widget._default)

def FixSize(self, width):
"""Fix toolbar width on Windows
Expand All @@ -212,8 +205,8 @@ def FixSize(self, width):
Determine why combobox causes problems here
"""
if platform.system() == "Windows":
size = self.GetBestSize()
self.SetSize((size[0] + width, size[1]))
size = self.classObject.GetBestSize(self.widget)
self.classObject.SetSize(self.widget, (size[0] + width, size[1]))

def Enable(self, tool, enable=True):
"""Enable/Disable defined tool
Expand All @@ -223,23 +216,23 @@ def Enable(self, tool, enable=True):
"""
try:
if isinstance(tool, tuple):
id = getattr(self, tool[0])
id = getattr(self.widget, tool[0])
else:
id = getattr(self, tool)
id = getattr(self.widget, tool)
except AttributeError:
# TODO: test everything that this is not raised
# this error was ignored for a long time
raise AttributeError("Toolbar does not have a tool %s." % tool)
return

self.EnableTool(id, enable)
self.classObject.EnableTool(self.widget, id, enable)

def EnableAll(self, enable=True):
"""Enable/Disable all tools
:param enable: True to enable otherwise disable tool
"""
for item in self._toolbarData():
for item in self.widget._toolbarData():
if not item[0]:
continue
self.Enable(item[0], enable)
Expand Down Expand Up @@ -275,12 +268,12 @@ def _onMenu(self, data):
item = wx.MenuItem(menu, wx.ID_ANY, icon.GetLabel())
item.SetBitmap(icon.GetBitmap(self.parent.iconsize))
menu.AppendItem(item)
self.Bind(wx.EVT_MENU, handler, item)
self.widget.Bind(wx.EVT_MENU, handler, item)

self.PopupMenu(menu)
self.classObject.PopupMenu(self.widget, menu)
menu.Destroy()

def CreateSelectionButton(self, tooltip=_("Select graphics tool")):
def CreateSelectionButton(self, tooltip):
"""Add button to toolbar for selection of graphics drawing mode.
Button must be custom (not toolbar tool) to set smaller width.
Expand All @@ -293,9 +286,9 @@ def CreateSelectionButton(self, tooltip=_("Select graphics tool")):
id=wx.ART_MISSING_IMAGE, client=wx.ART_TOOLBAR
)
button = BitmapButton(
parent=self,
parent=self.widget,
id=wx.ID_ANY,
size=((-1, self.GetToolSize()[1])),
size=((-1, self.classObject.GetToolSize(self.widget)[1])),
bitmap=bitmap,
style=wx.NO_BORDER,
)
Expand All @@ -304,6 +297,129 @@ def CreateSelectionButton(self, tooltip=_("Select graphics tool")):
return button


class AuiToolbarController(ToolbarController):
"""Controller specialized for wx.lib.agw.aui.auibar.AuiToolBar subclass"""

def _defineTool(self, name=None, icon=None, handler=None, item=wx.ITEM_NORMAL):
"""Define tool. Position is not needed since wx.lib.agw.aui.auibar.AuiToolBar
does not have InsertTool method."""
if name:
return (
name,
icon.GetBitmap(),
item,
icon.GetLabel(),
icon.GetDesc(),
handler,
)
return ("", "", "", "", "", "") # separator

def CreateTool(self, label, bitmap, kind, shortHelp, longHelp, handler):
"""Add tool to the toolbar"""
return super().CreateTool(label, bitmap, kind, shortHelp, longHelp, handler)


class BaseToolbar(ToolBar):
"""Abstract basic toolbar class.
Following code shows how to create new basic toolbar:
class MyToolbar(BaseToolbar):
def __init__(self, parent):
BaseToolbar.__init__(self, parent)
self.InitToolbar(self._toolbarData())
self.Realize()
def _toolbarData(self):
# e.g. ("help", _("Help")) tool short label (triangle/arrow
# at the right side of the toolbar)
return self._getToolbarData(
(
("help", Icons["help"].label),
Icons["help"],
self.parent.OnHelp
),
)
"""

def __init__(
self, parent, toolSwitcher=None, style=wx.NO_BORDER | wx.TB_HORIZONTAL
):
self.parent = parent
wx.ToolBar.__init__(self, parent=self.parent, id=wx.ID_ANY, style=style)

self._default = None
self.SetToolBitmapSize(globalvar.toolbarSize)

self.toolSwitcher = toolSwitcher
self.controller = ToolbarController(
classObject=ToolBar,
widget=self,
parent=self.parent,
toolSwitcher=toolSwitcher,
)

def _toolbarData(self):
"""Toolbar data (virtual)"""
return None

def Enable(self, tool, enable=True):
"""@copydoc ToolbarController::Enable()"""
self.controller.Enable(tool, enable)

def CreateTool(self, *args, **kwargs):
"""@copydoc ToolbarController::CreateTool()"""
self.controller.CreateTool(*args, **kwargs)

def __getattr__(self, name):
return getattr(self.controller, name)


class AuiToolbar(aui.AuiToolBar):
"""Abstract AUI toolbar class.
Toolbar for integration with the AUI layout system."""

def __init__(
self,
parent,
toolSwitcher=None,
style=wx.NO_BORDER | wx.TB_HORIZONTAL,
agwStyle=aui.AUI_TB_PLAIN_BACKGROUND,
):
self.parent = parent
super().__init__(
parent=self.parent, id=wx.ID_ANY, style=style, agwStyle=agwStyle
)

self._default = None
self.SetToolBitmapSize(globalvar.toolbarSize)

self.toolSwitcher = toolSwitcher
self.controller = AuiToolbarController(
classObject=aui.AuiToolBar,
widget=self,
parent=self.parent,
toolSwitcher=toolSwitcher,
)

def _toolbarData(self):
"""Toolbar data (virtual)"""
return None

def Enable(self, tool, enable=True):
"""@copydoc ToolbarController::Enable()"""
self.controller.Enable(tool, enable)

def CreateTool(self, *args, **kwargs):
"""@copydoc ToolbarController::CreateTool()"""
self.controller.CreateTool(*args, **kwargs)

def __getattr__(self, name):
return getattr(self.controller, name)


class ToolSwitcher:
"""Class handling switching tools in toolbar and custom toggle buttons."""

Expand Down
8 changes: 4 additions & 4 deletions gui/wxpython/iscatt/toolbars.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def GetToolId(self, toolName): # TODO can be useful in base
def SetPloltsMode(self, event, tool_name):
self.scatt_mgr.modeSet.disconnect(self.ModeSet)
if event.IsChecked():
for i_tool_data in self._data:
for i_tool_data in self.controller.data:
i_tool_name = i_tool_data[0]
if not i_tool_name or i_tool_name in ["cats_mgr", "sel_pol_mode"]:
continue
Expand All @@ -159,7 +159,7 @@ def ModeSet(self, mode):
self.UnsetMode()

def UnsetMode(self):
for i_tool_data in self._data:
for i_tool_data in self.controller.data:
i_tool_name = i_tool_data[0]
if not i_tool_name or i_tool_name in ["cats_mgr", "sel_pol_mode"]:
continue
Expand Down Expand Up @@ -281,7 +281,7 @@ def _toolbarData(self):
def SetMode(self, event, tool_name):
self.scatt_mgr.modeSet.disconnect(self.ModeSet)
if event.IsChecked():
for i_tool_data in self._data:
for i_tool_data in self.controller.data:
i_tool_name = i_tool_data[0]
if not i_tool_name:
continue
Expand All @@ -300,7 +300,7 @@ def ModeSet(self, mode):
self.UnsetMode()

def UnsetMode(self):
for i_tool_data in self._data:
for i_tool_data in self.controller.data:
i_tool_name = i_tool_data[0]
if not i_tool_name:
continue
Expand Down

0 comments on commit 8c2239e

Please sign in to comment.