Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wxGUI: Fix behaviour of top Single-Window GUI toolbars #2568

Merged
merged 7 commits into from
Oct 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading