inkstitch/lib/gui/subtitle_combo_box.py

86 wiersze
3.5 KiB
Python

import wx
import wx.adv
from wx.lib.wordwrap import wordwrap
class SubtitleComboBox(wx.adv.OwnerDrawnComboBox):
TITLE_FONT_SIZE = 12
SUBTITLE_FONT_SIZE = 10
# I'd love to make this 12 too, but if I do it seems to get drawn as 10
# initially no matter what I do.
CONTROL_FONT_SIZE = 12
MARGIN = 5
def __init__(self, *args, **kwargs):
self.titles = kwargs.get('choices', [])
subtitles = kwargs.pop('subtitles', {})
self.subtitles = [subtitles.get(title, '') for title in self.titles]
wx.adv.OwnerDrawnComboBox.__init__(self, *args, **kwargs)
self.control_font = wx.Font(pointSize=self.CONTROL_FONT_SIZE, family=wx.DEFAULT, style=wx.NORMAL, weight=wx.NORMAL)
self.title_font = wx.Font(pointSize=self.TITLE_FONT_SIZE, family=wx.DEFAULT, style=wx.NORMAL, weight=wx.NORMAL)
self.subtitle_font = wx.Font(pointSize=self.SUBTITLE_FONT_SIZE, family=wx.DEFAULT, style=wx.NORMAL, weight=wx.NORMAL)
def OnMeasureItemWidth(self, item):
# This _should_ allow us to set the width of the combobox to match the
# width of the widest title. In reality, this method is never called
# and I can't figure out why. We just use self.GetSize().GetWidth()
# instead and rely on the parent window to size us appropriately. Ugh.
title = self.titles[item]
# technique from https://stackoverflow.com/a/23529463/4249120
dc = wx.ScreenDC()
dc.SetFont(self.title_font)
return dc.GetTextExtent(title).GetWidth() + 2 * self.MARGIN
def OnMeasureItem(self, item):
title = self.titles[item]
subtitle = self.subtitles[item]
dc = wx.ScreenDC()
dc.SetFont(self.subtitle_font)
wrapped = wordwrap(subtitle, self.GetSize().GetWidth(), dc)
subtitle_height = dc.GetTextExtent(wrapped).GetHeight()
dc = wx.ScreenDC()
dc.SetFont(self.title_font)
title_height = dc.GetTextExtent(title).GetHeight()
return subtitle_height + title_height + 3 * self.MARGIN
def OnDrawBackground(self, dc, rect, item, flags):
if flags & wx.adv.ODCB_PAINTING_SELECTED:
# let the parent class draw the selected item so we don't
# hae to figure out the highlight color
wx.adv.OwnerDrawnComboBox.OnDrawBackground(self, dc, rect, item, flags)
else:
# alternate white and grey for the dropdown items, and draw the
# combo box itself as white
if flags & wx.adv.ODCB_PAINTING_CONTROL or item % 2 == 0:
background_color = wx.Colour(255, 255, 255)
else:
background_color = wx.Colour(240, 240, 240)
dc.SetBrush(wx.Brush(background_color))
dc.SetPen(wx.Pen(background_color))
dc.DrawRectangle(rect)
def OnDrawItem(self, dc, rect, item, flags):
if flags & wx.adv.ODCB_PAINTING_CONTROL:
# painting the selected item in the box
dc.SetFont(self.control_font)
dc.DrawText(self.titles[item], rect.x + self.MARGIN, rect.y + self.MARGIN)
else:
# painting the items in the popup
dc.SetFont(self.title_font)
title_height = dc.GetCharHeight()
dc.DrawText(self.titles[item], rect.x + self.MARGIN, rect.y + self.MARGIN)
dc.SetFont(self.subtitle_font)
subtitle = wordwrap(self.subtitles[item], self.GetSize().GetWidth(), dc)
dc.DrawText(subtitle, rect.x + self.MARGIN, rect.y + title_height + self.MARGIN * 2)