You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
3.7 KiB

2 years ago
  1. import wx # type: ignore
  2. from wx.lib.wordwrap import wordwrap # type: ignore
  3. class AutoWrappedStaticText(wx.StaticText):
  4. """
  5. Copy/pasta of wx.lib.agw.infobar.AutoWrapStaticText with 3 modifications:
  6. 1. Extends wx.StaticText rather than GenStaticText
  7. 2. Does not set the fore/background colors to sys defaults
  8. 3. takes an optional `target` parameter for sizing info
  9. The behavior of GenStaticText's background color is pretty buggy cross-
  10. platform. It doesn't reliably match its parent components background
  11. colors[0] (for instance when rendered inside of a Notebook) which leads to
  12. ugly 'boxing' around the text components.
  13. There is either a bug in WX, or or human error on my end, which causes
  14. EVT_SIZE events to continuously spawn from this (and AutoWrapStaticText) but
  15. with ever decreasing widths (in response to the SetLabel action in the
  16. wrap handler). The end result is a single skinny column of letters.
  17. The work around is to respond the EVT_SIZE event, but follow the size of the
  18. `target` component rather than relying on the size of the event.
  19. [0] more specifically, they'll match 1:1 on paper, but still ultimately
  20. render differently.
  21. """
  22. def __init__(self, parent, *args, **kwargs):
  23. self.target = kwargs.pop('target', None)
  24. super(AutoWrappedStaticText, self).__init__(parent, *args, **kwargs)
  25. self.label = kwargs.get('label')
  26. self.Bind(wx.EVT_SIZE, self.OnSize)
  27. self.parent = parent
  28. def OnSize(self, event):
  29. """
  30. Handles the ``wx.EVT_SIZE`` event for :class:`AutoWrapStaticText`.
  31. :param `event`: a :class:`wx.SizeEvent` event to be processed.
  32. """
  33. event.Skip()
  34. if self.target:
  35. self.Wrap(self.target.GetSize().width)
  36. else:
  37. self.Wrap(self.parent.GetSize()[0])
  38. def Wrap(self, width):
  39. """
  40. This functions wraps the controls label so that each of its lines becomes at
  41. most `width` pixels wide if possible (the lines are broken at words boundaries
  42. so it might not be the case if words are too long).
  43. If `width` is negative, no wrapping is done.
  44. :param integer `width`: the maximum available width for the text, in pixels.
  45. :note: Note that this `width` is not necessarily the total width of the control,
  46. since a few pixels for the border (depending on the controls border style) may be added.
  47. """
  48. if width < 0:
  49. return
  50. self.Freeze()
  51. dc = wx.ClientDC(self)
  52. dc.SetFont(self.GetFont())
  53. text = wordwrap(self.label, width, dc)
  54. self.SetLabel(text, wrapped=True)
  55. self.Thaw()
  56. def SetLabel(self, label, wrapped=False):
  57. """
  58. Sets the :class:`AutoWrapStaticText` label.
  59. All "&" characters in the label are special and indicate that the following character is
  60. a mnemonic for this control and can be used to activate it from the keyboard (typically
  61. by using ``Alt`` key in combination with it). To insert a literal ampersand character, you
  62. need to double it, i.e. use "&&". If this behaviour is undesirable, use :meth:`~Control.SetLabelText` instead.
  63. :param string `label`: the new :class:`AutoWrapStaticText` text label;
  64. :param bool `wrapped`: ``True`` if this method was called by the developer using :meth:`~AutoWrapStaticText.SetLabel`,
  65. ``False`` if it comes from the :meth:`~AutoWrapStaticText.OnSize` event handler.
  66. :note: Reimplemented from :class:`wx.Control`.
  67. """
  68. if not wrapped:
  69. self.label = label
  70. wx.StaticText.SetLabel(self, label)