# Name: params.py
# Purpose: Classes for parameter introduction
# Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
# Created: 22.08.2001
# RCS-ID: $Id: params.py 64107 2010-04-22 14:05:36Z ROL $
'''
Visual C{Param*} classes for populating C{AtrtibutePanel} with attribute editing
blocks.
'''
import string
import os
import wx.combo
from globals import *
WARenameDict = {'fg': 'foreground', 'bg': 'background'}
def InitParams(panel):
'''Set pixel common size based on parent window.'''
global Presenter
from presenter import Presenter
global Listener
from listener import Listener
dc = wx.ClientDC(panel)
global textH, textB
textH = -1
if wx.Platform == '__WXMAC__':
textB = 3 # bigger text border needed for mac highlighting
else:
textB = 2
dc.Destroy()
# make a custom bitmap showing "..."
bw, bh = 14, 16
bmp = wx.EmptyBitmap(bw,bh)
dc = wx.MemoryDC(bmp)
# clear to a specific background colour
bgcolor = wx.Colour(255,254,255)
dc.SetBackground(wx.Brush(bgcolor))
dc.Clear()
# draw the label onto the bitmap
label = "..."
font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
font.SetWeight(wx.FONTWEIGHT_BOLD)
dc.SetFont(font)
tw,th = dc.GetTextExtent(label)
dc.DrawText(label, (bw-tw)/2, (bw-tw)/2)
del dc
# now apply a mask using the bgcolor
bmp.SetMaskColour(bgcolor)
global bmpEdit
bmpEdit = bmp
# Set known encodings
for i in range(wx.FontMapper.GetSupportedEncodingsCount()):
ParamEncoding.values.append(wx.FontMapper.GetEncodingName(
wx.FontMapper.GetEncoding(i)))
ParamEncoding.values.sort()
# Class that can properly disable children
class PPanel(wx.Panel):
'''Abstract base class creating an empty C{wx.Panel}.'''
isCheck = False
def __init__(self, parent, name):
wx.Panel.__init__(self, parent, -1, name=name)
self.name = name
def Enable(self, value):
self.enabled = value
# Something strange is going on with enable so we make sure...
for w in self.GetChildren():
w.Enable(value)
#wx.Panel.Enable(self, value)
# Common method to set modified state
def OnChange(self, evt):
Presenter.setApplied(False)
evt.Skip()
def OnKillFocus(self, evt):
# Refresh test window if auto refresh policy on focus
if Listener.testWin.IsShown() and g.conf.autoRefresh and \
g.conf.autoRefreshPolicy == AUTO_REFRESH_POLICY_FOCUS:
wx.CallAfter(Presenter.refreshTestWin)
evt.Skip()
class ParamBinaryOr(PPanel):
'''Editing binary flag attributes defined by a string separated by '|'.'''
def __init__(self, parent, name):
PPanel.__init__(self, parent, name)
self.freeze = False
sizer = wx.BoxSizer()
popup = CheckListBoxComboPopup(self.values)
self.combo = wx.combo.ComboCtrl(self, size=(220,-1))
self.combo.SetPopupControl(popup)
if wx.Platform == '__WXMAC__':
sizer.Add(self.combo, 1, wx.ALL, 0)
else:
sizer.Add(self.combo, 1, wx.ALL, 2)
self.SetSizerAndFit(sizer)
self.combo.Bind(wx.EVT_TEXT, self.OnChange)
self.combo.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
def GetValue(self):
return self.combo.GetValue()
def SetValue(self, value):
self.freeze = True
self.combo.SetValue(value)
self.freeze = False
def SetValues(self):
self.combo.InsertItems(self.values, 0)
def OnChange(self, evt):
# ComboCtrl still generates events in SetValue
if self.freeze: return
Presenter.setApplied(False)
evt.Skip()
class ParamFlag(ParamBinaryOr):
'''Sizer flag editing.'''
values = ['wxTOP', 'wxBOTTOM', 'wxLEFT', 'wxRIGHT', 'wxALL',
'wxEXPAND', 'wxGROW', 'wxSHAPED', 'wxSTRETCH_NOT',
'wxALIGN_CENTRE', 'wxALIGN_LEFT', 'wxALIGN_RIGHT',
'wxALIGN_TOP', 'wxALIGN_BOTTOM',
'wxALIGN_CENTRE_VERTICAL', 'wxALIGN_CENTRE_HORIZONTAL',
'wxADJUST_MINSIZE', 'wxFIXED_MINSIZE',
'wxRESERVE_SPACE_EVEN_IF_HIDDEN',
]
equal = {'wxALIGN_CENTER': 'wxALIGN_CENTRE',
'wxALIGN_CENTER_VERTICAL': 'wxALIGN_CENTRE_VERTICAL',
'wxALIGN_CENTER_HORIZONTAL': 'wxALIGN_CENTRE_HORIZONTAL',
'wxUP': 'wxTOP', 'wxDOWN': 'wxBOTTOM', 'wxNORTH': 'wxTOP',
'wxSOUTH': 'wxBOTTOM', 'wxWEST': 'wxLEFT', 'wxEAST': 'wxRIGHT'}
class ParamColour(PPanel):
'''Color attribute editing.'''
def __init__(self, parent, name):
PPanel.__init__(self, parent, name)
sizer = wx.BoxSizer()
self.text = wx.TextCtrl(self, size=(80,textH))
sizer.Add(self.text, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, textB)
self.button = wx.Panel(self, size=(20, 20))
sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 3)
self.SetSizer(sizer)
self.textModified = False
self.button.Bind(wx.EVT_PAINT, self.OnPaintButton)
self.text.Bind(wx.EVT_TEXT, self.OnChange)
self.text.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
self.button.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
def GetValue(self):
return self.text.GetValue()
def SetValue(self, value):
self.text.ChangeValue(value) # update text ctrl
self.UpdateColour(value)
def UpdateColour(self, value):
try:
colour = wx.Colour(int(value[1:3], 16), int(value[3:5], 16), int(value[5:7], 16))
self.button.SetBackgroundColour(colour)
except: # ignore errors
self.button.SetBackgroundColour(self.GetBackgroundColour())
self.button.Refresh()
def OnChange(self, evt):
Presenter.setApplied(False)
self.UpdateColour(evt.GetString())
evt.Skip()
def OnPaintButton(self, evt):
dc = wx.PaintDC(self.button)
dc.SetBrush(wx.TRANSPARENT_BRUSH)
if self.IsEnabled(): dc.SetPen(wx.BLACK_PEN)
else: dc.SetPen(wx.GREY_PEN)
size = self.button.GetSize()
dc.DrawRectangle(0, 0, size.width, size.height)
def OnLeftDown(self, evt):
data = wx.ColourData()
data.SetColour(self.GetValue())
dlg = wx.ColourDialog(self, data)
if dlg.ShowModal() == wx.ID_OK:
self.SetValue('#%02X%02X%02X' % dlg.GetColourData().GetColour().Get())
Presenter.setApplied(False)
dlg.Destroy()
################################################################################
# Mapping from wx constants to XML strings
fontFamiliesWx2Xml = {wx.DEFAULT: 'default', wx.DECORATIVE: 'decorative',
wx.ROMAN: 'roman', wx.SCRIPT: 'script', wx.SWISS: 'swiss',
wx.MODERN: 'modern'}
fontStylesWx2Xml = {wx.NORMAL: 'normal', wx.SLANT: 'slant', wx.ITALIC: 'italic'}
fontWeightsWx2Xml = {wx.NORMAL: 'normal', wx.LIGHT: 'light', wx.BOLD: 'bold'}
def ReverseMap(m):
rm = {}
for k,v in m.items(): rm[v] = k
return rm
fontFamiliesXml2wx = ReverseMap(fontFamiliesWx2Xml)
fontStylesXml2wx = ReverseMap(fontStylesWx2Xml)
fontWeightsXml2wx = ReverseMap(fontWeightsWx2Xml)
class ParamFont(PPanel):
'''Font attribute editing.'''
def __init__(self, parent, name):
PPanel.__init__(self, parent, name)
sizer = wx.BoxSizer()
self.button = wx.FontPickerCtrl(
self, style=wx.FNTP_FONTDESC_AS_LABEL | wx.FNTP_USE_TEXTCTRL
)
self.text = self.button.GetTextCtrl()
if wx.Platform == '__WXMAC__':
sizer.Add(self.button, 0, wx.LEFT, -2)
else:
sizer.Add(self.button, 0, wx.LEFT, textB)
self.SetSizer(sizer)
self.Bind(wx.EVT_FONTPICKER_CHANGED, self.OnPickFont)
self.text.Bind(wx.EVT_TEXT, self.OnText)
self.text.Bind(wx.EVT_KILL_FOCUS, self.OnTextKillFocus)
def OnText(self, evt):
Presenter.setApplied(False)
if evt.GetString():
evt.Skip()
else:
self.text.ChangeValue('')
def OnTextKillFocus(self, evt):
if self.text.GetValue():
evt.Skip()
def GetValue(self):
return self.value
def dict2font(self, d):
error = False
if 'size' in d:
try: size = int(d['size'])
except ValueError: error = True; wx.LogError('Invalid size specification')
else:
size = g.sysFont().GetPointSize()
if 'family' in d:
try: family = fontFamiliesXml2wx[d['family']]
except KeyError: error = True; wx.LogError('Invalid family specification')
else:
family = wx.DEFAULT
if 'style' in d:
try: style = fontStylesXml2wx[d['style']]
except KeyError: error = True; wx.LogError('Invalid style specification')
else:
style = wx.NORMAL
if 'weight' in d:
try: weight = fontWeightsXml2wx[d['weight']]
except KeyError: error = True; wx.LogError('Invalid weight specification')
else:
weight = wx.NORMAL
try: underlined = bool(int(d.get('underlined', '0')))
except ValueError: error = True; wx.LogError('Invalid underlined flag specification')
face = d.get('face','')
enc = wx.FONTENCODING_DEFAULT
mapper = wx.FontMapper()
if 'encoding' in d and d['encoding'] != 'default':
enc = mapper.CharsetToEncoding(d['encoding'])
if error: wx.LogError('Invalid font specification')
if enc == wx.FONTENCODING_DEFAULT: enc = wx.FONTENCODING_SYSTEM
font = wx.Font(size, family, style, weight, underlined, face, enc)
return font
def SetValue(self, value):
if not value:
self.text.ChangeValue('')
else:
self.button.SetSelectedFont(self.dict2font(value))
self.value = value
def OnPickFont(self, evt):
font = evt.GetFont()
if font.GetEncoding() == wx.FONTENCODING_SYSTEM:
encName = ''
else:
encName = wx.FontMapper.GetEncodingName(font.GetEncoding()).encode()
value = {'size': str(font.GetPointSize()),
'family': fontFamiliesWx2Xml.get(font.GetFamily(), "default"),
'style': fontStylesWx2Xml.get(font.GetStyle(), "normal"),
'weight': fontWeightsWx2Xml.get(font.GetWeight(), "normal"),
'underlined': str(int(font.GetUnderlined())),
'face': font.GetFaceName().encode(),
'encoding': encName}
self.SetValue(value)
Presenter.setApplied(False)
################################################################################
# This is a replacement for SpinCtrl to make ParamUnit looking similar.
# Unfortunately there is no SpinCtrl::GetStringValue...
class ParamInt(PPanel):
'''TextCtrl with SpinButton for integer parameters.'''
default = 0
range = (-2147483648, 2147483647)
def __init__(self, parent, name):
PPanel.__init__(self, parent, name)
sizer = wx.BoxSizer(wx.HORIZONTAL)
self.spin = wx.SpinButton(self, style = wx.SP_VERTICAL, size=(-1,10))
textW = 60 - self.spin.GetSize()[0]
self.text = wx.TextCtrl(self, size=(textW,textH))
self.spin.SetRange(*self.range)
if wx.Platform == '__WXMAC__':
sizer.Add(self.text, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL, textB)
else:
sizer.Add(self.text, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | \
wx.LEFT | wx.TOP | wx.BOTTOM, textB)
sizer.Add(self.spin, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND)
self.SetSizer(sizer)
self.spin.Bind(wx.EVT_SPIN_UP, self.OnSpinUp)
self.spin.Bind(wx.EVT_SPIN_DOWN, self.OnSpinDown)
self.text.Bind(wx.EVT_TEXT, self.OnChange)
self.text.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
def GetValue(self):
return self.text.GetValue()
def SetValue(self, value):
self.text.ChangeValue(value)
self.SyncSpin(value)
def SyncSpin(self, value):
try:
intValue = int(value)
self.spin.SetValue(intValue)
except:
self.spin.SetValue(self.default)
def OnChange(self, evt):
self.SyncSpin(evt.GetString())
Presenter.setApplied(False)
evt.Skip()
def SyncText(self, spinValue):
if self.range[0] <= spinValue <= self.range[1]:
self.text.ChangeValue(str(spinValue))
Presenter.setApplied(False)
def OnSpinUp(self, evt):
self.SyncText(evt.GetPosition())
evt.Skip()
def OnSpinDown(self, evt):
self.SyncText(evt.GetPosition())
evt.Skip()
def MetaParamInt(**kargs):
'''Create ParamInt class with default value.'''
return type('ParamInt', (ParamInt,), kargs)
ParamIntNN = MetaParamInt(default=0, range=(0, 2147483647)) # non-negative
ParamIntP = MetaParamInt(default=1, range=(1, 2147483647)) # positive
# Same as ParamInt but allows dialog units (XXXd)
class ParamUnit(ParamInt):
'''Similar to L{ParamInt}, 'd' can be appended to the value to specify
dialog units mode.'''
def _splitValue(self, value):
units = ''
if value[-1:].upper() == 'D':
units = value[-1]
value = value[:-1]
return value,units
def SyncSpin(self, value):
try:
value,units = self._splitValue(value)
intValue = int(value)
self.spin.SetValue(intValue)
except:
self.spin.SetValue(self.default)
def SyncText(self, spinValue):
if self.range[0] <= spinValue <= self.range[1]:
value,units = self._splitValue(self.text.GetValue())
self.text.ChangeValue(str(spinValue)+units)
Presenter.setApplied(False)
class ParamMultilineText(PPanel):
'''Multiline text editing.'''
def __init__(self, parent, name, textWidth=-1):
PPanel.__init__(self, parent, name)
sizer = wx.BoxSizer()
self.text = wx.TextCtrl(self, size=wx.Size(200,textH))
sizer.Add(self.text, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, textB)
self.button = wx.BitmapButton(self, bitmap=bmpEdit, size=(-1,textH))
sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL)
self.SetSizer(sizer)
self.button.Bind(wx.EVT_BUTTON, self.OnButtonEdit)
self.text.Bind(wx.EVT_TEXT, self.OnChange)
self.text.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
def GetValue(self):
return self.text.GetValue()
def SetValue(self, value):
self.text.ChangeValue(value)
def OnButtonEdit(self, evt):
dlg = g.res.LoadDialog(self, 'DIALOG_TEXT')
textCtrl = xrc.XRCCTRL(dlg, 'TEXT')
textCtrl.SetValue(self.text.GetValue())
if dlg.ShowModal() == wx.ID_OK:
self.text.ChangeValue(textCtrl.GetValue())
Presenter.setApplied(False)
dlg.Destroy()
class ParamText(PPanel):
'''Text attribute.'''
textWidth = -1
proportion = 0
def __init__(self, parent, name, **kargs):
PPanel.__init__(self, parent, name)
style = kargs.pop('style', 0)
textWidth = kargs.pop('textWidth', self.textWidth)
option = kargs.pop('proportion', self.proportion)
if textWidth == -1: option = 1
# We use sizer even here to have the same size of text control
sizer = wx.BoxSizer()
self.text = wx.TextCtrl(self, size=wx.Size(textWidth,textH), style=style)
sizer.Add(self.text, option, wx.ALIGN_CENTER_VERTICAL | wx.ALL, textB)
self.SetSizer(sizer)
self.text.Bind(wx.EVT_TEXT, self.OnChange)
self.text.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
def GetValue(self):
return self.text.GetValue()
def SetValue(self, value):
self.text.ChangeValue(value)
def MetaParamText(textWidth, proportion=0):
'''Return a L{ParamText} class with specified width and proportion.'''
return type('ParamText__length', (ParamText,),
{'textWidth': textWidth, 'proportion': proportion})
ParamLongText = MetaParamText(200, 1)
ParamAccel = MetaParamText(100)
ParamHelp = MetaParamText(200, 1)
ParamPosSize = MetaParamText(80)
class ParamComment(ParamText):
'''Comment node editing.'''
def __init__(self, parent, name):
ParamText.__init__(self, parent, name, textWidth=330,
style=wx.TE_PROCESS_ENTER)
class ContentDialog(wx.Dialog):
'''Dialog for editing content attributes.'''
def __init__(self, parent, value):
# Load from resource
pre = wx.PreDialog()
g.res.LoadOnDialog(pre, parent, 'DIALOG_CONTENT')
self.PostCreate(pre)
self.list = xrc.XRCCTRL(self, 'LIST')
# Set list items
for v in value:
self.list.Append(v)
self.SetAutoLayout(True)
self.GetSizer().Fit(self)
# Callbacks
self.ID_BUTTON_APPEND = xrc.XRCID('BUTTON_APPEND')
self.ID_BUTTON_REMOVE = xrc.XRCID('BUTTON_REMOVE')
self.ID_BUTTON_UP = xrc.XRCID('BUTTON_UP')
self.ID_BUTTON_DOWN = xrc.XRCID('BUTTON_DOWN')
wx.EVT_BUTTON(self, self.ID_BUTTON_UP, self.OnButtonUp)
wx.EVT_BUTTON(self, self.ID_BUTTON_DOWN, self.OnButtonDown)
wx.EVT_BUTTON(self, self.ID_BUTTON_APPEND, self.OnButtonAppend)
wx.EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove)
wx.EVT_UPDATE_UI(self, self.ID_BUTTON_UP, self.OnUpdateUI)
wx.EVT_UPDATE_UI(self, self.ID_BUTTON_DOWN, self.OnUpdateUI)
wx.EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI)
def OnButtonUp(self, evt):
i = self.list.GetSelection()
str = self.list.GetString(i)
self.list.Delete(i)
self.list.InsertItems([str], i-1)
self.list.SetSelection(i-1)
def OnButtonDown(self, evt):
i = self.list.GetSelection()
str = self.list.GetString(i)
self.list.Delete(i)
self.list.InsertItems([str], i+1)
self.list.SetSelection(i+1)
def OnButtonAppend(self, evt):
str = wx.GetTextFromUser('Enter new item:', 'Append', '', self)
self.list.Append(str)
def OnButtonRemove(self, evt):
self.list.Delete(self.list.GetSelection())
def OnUpdateUI(self, evt):
if evt.GetId() == self.ID_BUTTON_REMOVE:
evt.Enable(self.list.GetSelection() != -1)
elif evt.GetId() == self.ID_BUTTON_UP:
evt.Enable(self.list.GetSelection() > 0)
elif evt.GetId() == self.ID_BUTTON_DOWN:
evt.Enable(self.list.GetSelection() != -1 and \
self.list.GetSelection() < self.list.GetCount() - 1)
class ContentCheckListDialog(wx.Dialog):
'''Dialog for editing content checklist attributes.'''
def __init__(self, parent, value):
pre = wx.PreDialog()
g.res.LoadOnDialog(pre, parent, 'DIALOG_CONTENT_CHECKLIST')
self.PostCreate(pre)
self.list = xrc.XRCCTRL(self, 'CHECK_LIST')
# Set list items
i = 0
for v,ch in value:
self.list.Append(v)
self.list.Check(i, ch)
i += 1
self.SetAutoLayout(True)
self.GetSizer().Fit(self)
# Callbacks
self.ID_BUTTON_APPEND = xrc.XRCID('BUTTON_APPEND')
self.ID_BUTTON_REMOVE = xrc.XRCID('BUTTON_REMOVE')
self.ID_BUTTON_UP = xrc.XRCID('BUTTON_UP')
self.ID_BUTTON_DOWN = xrc.XRCID('BUTTON_DOWN')
wx.EVT_CHECKLISTBOX(self, self.list.GetId(), self.OnCheck)
wx.EVT_BUTTON(self, self.ID_BUTTON_UP, self.OnButtonUp)
wx.EVT_BUTTON(self, self.ID_BUTTON_DOWN, self.OnButtonDown)
wx.EVT_BUTTON(self, self.ID_BUTTON_APPEND, self.OnButtonAppend)
wx.EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove)
wx.EVT_UPDATE_UI(self, self.ID_BUTTON_UP, self.OnUpdateUI)
wx.EVT_UPDATE_UI(self, self.ID_BUTTON_DOWN, self.OnUpdateUI)
wx.EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI)
def OnCheck(self, evt):
# !!! Wrong wxGTK (wxMSW?) behavior: toggling selection if checking
self.list.Deselect(evt.GetSelection())
def OnButtonUp(self, evt):
i = self.list.GetSelection()
str, ch = self.list.GetString(i), self.list.IsChecked(i)
self.list.Delete(i)
self.list.InsertItems([str], i-1)
self.list.Check(i-1, ch)
self.list.SetSelection(i-1)
def OnButtonDown(self, evt):
i = self.list.GetSelection()
str, ch = self.list.GetString(i), self.list.IsChecked(i)
self.list.Delete(i)
self.list.InsertItems([str], i+1)
self.list.Check(i+1, ch)
self.list.SetSelection(i+1)
def OnButtonAppend(self, evt):
str = wx.GetTextFromUser('Enter new item:', 'Append', '', self)
self.list.Append(str)
def OnButtonRemove(self, evt):
self.list.Delete(self.list.GetSelection())
def OnUpdateUI(self, evt):
if evt.GetId() == self.ID_BUTTON_REMOVE:
evt.Enable(self.list.GetSelection() != -1)
elif evt.GetId() == self.ID_BUTTON_UP:
evt.Enable(self.list.GetSelection() > 0)
elif evt.GetId() == self.ID_BUTTON_DOWN:
evt.Enable(self.list.GetSelection() != -1 and \
self.list.GetSelection() < self.list.GetCount() - 1)
class ParamContent(PPanel):
'''Editing of content attribute.'''
def __init__(self, parent, name):
PPanel.__init__(self, parent, name)
sizer = wx.BoxSizer()
self.text = wx.TextCtrl(self, size=wx.Size(200,textH))
sizer.Add(self.text, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, textB)
self.button = wx.BitmapButton(self, bitmap=bmpEdit, size=(-1,textH))
sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL)
self.SetSizer(sizer)
self.textModified = False
self.button.Bind(wx.EVT_BUTTON, self.OnButtonEdit)
self.text.Bind(wx.EVT_TEXT, self.OnChange)
def OnChange(self, evt):
Presenter.setApplied(False)
self.textModified = True
evt.Skip()
def GetValue(self):
if self.textModified: # text has newer value
try:
return self.text.GetValue().split('|')
except ValueError:
return []
return self.value
def SetValue(self, value):
if not value: value = []
self.value = value
repr_ = '|'.join(map(str, value))
self.text.ChangeValue(repr_) # update text ctrl
def OnButtonEdit(self, evt):
if self.textModified: # text has newer value
self.value = self.GetValue()
dlg = ContentDialog(self, self.value)
if dlg.ShowModal() == wx.ID_OK:
value = []
for i in range(dlg.list.GetCount()):
value.append(dlg.list.GetString(i))
self.SetValue(value)
Presenter.setApplied(False)
self.textModified = False
dlg.Destroy()
# CheckList content
class ParamContentCheckList(ParamContent):
'''Editing of content check list attribute.'''
def __init__(self, parent, name):
ParamContent.__init__(self, parent, name)
def OnButtonEdit(self, evt):
if self.textModified: # text has newer value
self.value = self.GetValue()
dlg = ContentCheckListDialog(self, self.value)
if dlg.ShowModal() == wx.ID_OK:
value = []
for i in range(dlg.list.GetCount()):
value.append((dlg.list.GetString(i), int(dlg.list.IsChecked(i))))
self.SetValue(value)
Presenter.setApplied(False)
self.textModified = False
dlg.Destroy()
def SetValue(self, value):
if not value: value = []
self.value = value
repr_ = '|'.join(map(str,value))
self.text.ChangeValue(repr_) # update text ctrl
class IntListDialog(wx.Dialog):
'''Dialog for editing integer lists.'''
def __init__(self, parent, value):
pre = wx.PreDialog()
g.res.LoadOnDialog(pre, parent, 'DIALOG_INTLIST')
self.PostCreate(pre)
self.list = xrc.XRCCTRL(self, 'LIST')
# Set list items
value.sort()
for v in value:
self.list.Append(v)
self.SetAutoLayout(True)
self.GetSizer().Fit(self)
# Callbacks
self.spinCtrl = xrc.XRCCTRL(self, 'SPIN')
wx.EVT_BUTTON(self, xrc.XRCID('BUTTON_ADD'), self.OnButtonAdd)
self.ID_BUTTON_REMOVE = xrc.XRCID('BUTTON_REMOVE')
wx.EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove)
wx.EVT_BUTTON(self, xrc.XRCID('BUTTON_CLEAR'), self.OnButtonClear)
wx.EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI)
def OnButtonAdd(self, evt):
# Check that it's unique
try:
v = self.spinCtrl.GetValue()
s = str(v) # to be sure
i = self.list.FindString(s)
if i == -1: # ignore non-unique
# Find place to insert
found = False
for i in range(self.list.GetCount()):
if int(self.list.GetString(i)) > v:
found = True
break
if found: self.list.InsertItems([s], i)
else: self.list.Append(s)
except ValueError:
wx.LogError('List item is not an int!')
def OnButtonRemove(self, evt):
self.list.Delete(self.list.GetSelection())
def OnButtonClear(self, evt):
self.list.Clear()
def OnUpdateUI(self, evt):
if evt.GetId() == self.ID_BUTTON_REMOVE:
evt.Enable(self.list.GetSelection() != -1)
# For growable list
class ParamIntList(ParamContent):
'''Editing integer list attribute.'''
def __init__(self, parent, name):
ParamContent.__init__(self, parent, name)
def OnButtonEdit(self, evt):
if self.textModified: # text has newer value
try:
self.value = self.text.GetValue().split('|')
except ValueError:
self.value = []
dlg = IntListDialog(self, self.value)
if dlg.ShowModal() == wx.ID_OK:
value = []
for i in range(dlg.list.GetCount()):
value.append(dlg.list.GetString(i))
self.SetValue(value)
Presenter.setApplied()
self.textModified = False
dlg.Destroy()
# Boxless radiobox
class RadioBox(PPanel):
def __init__(self, parent, name='radiobox'):
PPanel.__init__(self, parent, name)
topSizer = wx.BoxSizer()
self.choicesInv = {}
for i,v in self.choices.items():
self.choicesInv[v] = i
button = wx.RadioButton(self, -1, i, name=i)
topSizer.Add(button, 0, wx.RIGHT, 5)
wx.EVT_RADIOBUTTON(self, button.GetId(), self.OnRadioChoice)
self.SetSizer(topSizer)
def SetStringSelection(self, value):
for i in self.choices.keys():
self.FindWindowByName(i).SetValue(i == value)
self.value = value
def OnRadioChoice(self, evt):
if evt.GetSelection():
self.value = evt.GetEventObject().GetName()
Presenter.setApplied(False)
def GetStringSelection(self):
return self.value
def GetValue(self):
return self.choices[self.GetStringSelection()]
def SetValue(self, value):
if not value: value = self.default
self.SetStringSelection(self.choicesInv[value])
# Base type for checkable parameters
class CheckBox(PPanel):
isCheck = True
def __init__(self, parent, name='checkbox'):
PPanel.__init__(self, parent, name)
topSizer = wx.BoxSizer()
self.check = wx.CheckBox(self, -1, name, size=(-1,textH))
topSizer.Add(self.check, 0, wx.TOP | wx.BOTTOM, textB)
self.check.Bind(wx.EVT_CHECKBOX, self.OnCheck)
self.SetSizer(topSizer)
def OnCheck(self, evt):
Presenter.setApplied(False)
if Presenter.panelIsDirty():
Presenter.registerUndoEdit()
if Listener.testWin.IsShown() and g.conf.autoRefresh and \
g.conf.autoRefreshPolicy == AUTO_REFRESH_POLICY_FOCUS:
Listener.testWin.isDirty = True
wx.CallAfter(Presenter.refreshTestWin)
evt.Skip()
class ParamBool(CheckBox):
'''Editing on/off attributes.'''
defaultString = '(default is OFF)'
def GetValue(self):
return ('', '1')[self.check.IsChecked()]
def SetValue(self, value):
self.check.SetValue(value == '1')
class ParamInverseBool(CheckBox):
'''like L{ParamBool} but defined if unchecked'''
defaultString = '(default is ON)'
def GetValue(self):
return ('0', '')[self.check.IsChecked()]
def SetValue(self, value):
self.check.SetValue(not value or value == '1')
class ParamOrient(RadioBox):
'''Orientation attribute editing for sizers.'''
choices = {'horizontal': 'wxHORIZONTAL', 'vertical': 'wxVERTICAL'}
default = 'wxHORIZONTAL'
class ParamOrientation(RadioBox):
'''Orientaiton attribute editing for C{wx.SplitterWindow}.'''
choices = {'horizontal': 'horizontal', 'vertical': 'vertical'}
default = 'vertical'
class ParamBitmap(PPanel):
def __init__(self, parent, name):
pre = wx.PrePanel()
g.res.LoadOnPanel(pre, parent, 'PANEL_BITMAP')
self.PostCreate(pre)
self.modified = False
self.radio_std = xrc.XRCCTRL(self, 'RADIO_STD')
self.radio_file = xrc.XRCCTRL(self, 'RADIO_FILE')
self.combo = xrc.XRCCTRL(self, 'COMBO_STD')
self.text = xrc.XRCCTRL(self, 'TEXT_FILE')
self.button = xrc.XRCCTRL(self, 'BUTTON_BROWSE')
self.textModified = False
wx.EVT_RADIOBUTTON(self, xrc.XRCID('RADIO_STD'), self.OnRadioStd)
wx.EVT_RADIOBUTTON(self, xrc.XRCID('RADIO_FILE'), self.OnRadioFile)
wx.EVT_BUTTON(self, xrc.XRCID('BUTTON_BROWSE'), self.OnButtonBrowse)
wx.EVT_COMBOBOX(self, xrc.XRCID('COMBO_STD'), self.OnCombo)
wx.EVT_TEXT(self, xrc.XRCID('COMBO_STD'), self.OnChange)
wx.EVT_TEXT(self, xrc.XRCID('TEXT_FILE'), self.OnChange)
def OnRadioStd(self, evt):
Presenter.setApplied(False)
self.SetValue(['wxART_MISSING_IMAGE',''])
def OnRadioFile(self, evt):
Presenter.setApplied(False)
self.SetValue(['',''])
def updateRadios(self):
if self.value[0]:
self.radio_std.SetValue(True)
self.radio_file.SetValue(False)
self.text.Enable(False)
self.button.Enable(False)
self.combo.Enable(True)
else:
self.radio_std.SetValue(False)
self.radio_file.SetValue(True)
self.text.Enable(True)
self.button.Enable(True)
self.combo.Enable(False)
def OnChange(self, evt):
Presenter.setApplied(False)
self.textModified = True
evt.Skip()
def OnCombo(self, evt):
Presenter.setApplied(False)
self.value[0] = self.combo.GetValue()
def GetValue(self):
return [self.combo.GetValue(), self.text.GetValue()]
def SetValue(self, value):
if not value:
self.value = ['', '']
else:
self.value = value
self.combo.SetValue(self.value[0])
self.text.ChangeValue(self.value[1]) # update text ctrl
self.updateRadios()
def OnButtonBrowse(self, evt):
if self.textModified: # text has newer value
self.value[1] = self.text.GetValue()
dlg = wx.FileDialog(self,
defaultDir = os.path.abspath(os.path.dirname(self.value[1])),
defaultFile = os.path.basename(self.value[1]))
if dlg.ShowModal() == wx.ID_OK:
# Get common part of selected path and current
if Presenter.path:
curpath = os.path.abspath(Presenter.path)
else:
curpath = os.path.join(os.getcwd(), '')
common = os.path.commonprefix([curpath, dlg.GetPath()])
self.SetValue(['', dlg.GetPath()[len(common):]])
Presenter.setApplied(False)
self.textModified = False
dlg.Destroy()
class ParamImage(PPanel):
'''Image selector.'''
def __init__(self, parent, name):
PPanel.__init__(self, parent, name)
sizer = wx.BoxSizer()
self.text = wx.TextCtrl(self, size=wx.Size(200,textH))
sizer.Add(self.text, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, textB)
self.button = wx.Button(self, -1, 'Browse...')
sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL)
self.SetSizer(sizer)
self.button.Bind(wx.EVT_BUTTON, self.OnButtonBrowse)
self.text.Bind(wx.EVT_TEXT, self.OnChange)
def OnChange(self, evt):
Presenter.setApplied(False)
evt.Skip()
def GetValue(self):
return self.text.GetValue()
def SetValue(self, value):
self.text.ChangeValue(value)
def OnButtonBrowse(self, evt):
value = self.text.GetValue()
dlg = wx.FileDialog(self,
defaultDir = os.path.abspath(os.path.dirname(value)),
defaultFile = os.path.basename(value))
if dlg.ShowModal() == wx.ID_OK:
# Get common part of selected path and current
if Presenter.path:
curpath = os.path.abspath(Presenter.path)
else:
curpath = os.path.join(os.getcwd(), '')
common = os.path.commonprefix([curpath, dlg.GetPath()])
self.SetValue(dlg.GetPath()[len(common):])
Presenter.setApplied(False)
self.textModified = False
dlg.Destroy()
class ParamCombo(PPanel):
values = []
'''Combo box.'''
def __init__(self, parent, name):
PPanel.__init__(self, parent, name)
sizer = wx.BoxSizer()
self.combo = wx.ComboBox(self, size=(220,-1))
if wx.Platform == '__WXMAC__':
sizer.Add(self.combo, 0, wx.ALL, 0)
else:
sizer.Add(self.combo, 0, wx.ALL, 2)
self.SetSizerAndFit(sizer)
self.combo.Bind(wx.EVT_TEXT, self.OnChange)
self.SetValues()
def GetValue(self):
return self.combo.GetValue()
def SetValue(self, value):
self.combo.SetValue(value)
def SetValues(self):
for v in self.values:
self.combo.Append(v)
class ParamEncoding(ParamCombo):
'''Editing encoding attribute of the XML root node.'''
pass
paramDict = {
# sizer params
'flag': ParamFlag, 'orient': ParamOrient, 'option': ParamInt,
'cellpos': ParamPosSize, 'cellspan': ParamPosSize,
'border': ParamUnit, 'borders': ParamUnit,
'cols': ParamIntP, 'rows': ParamIntP,
'vgap': ParamUnit, 'hgap': ParamUnit,
# common window params
'pos': ParamPosSize, 'size': ParamPosSize,
'checkable': ParamBool, 'checked': ParamBool, 'radio': ParamBool,
'accel': ParamAccel, 'help': ParamHelp, 'centered': ParamBool,
'label': ParamMultilineText, 'title': ParamLongText, 'value': ParamLongText,
'content': ParamContent, 'selection': ParamIntNN,
'min': ParamInt, 'max': ParamInt,
# window attributes
'fg': ParamColour, 'bg': ParamColour, 'font': ParamFont,
'enabled': ParamInverseBool, 'focused': ParamBool, 'hidden': ParamBool,
'tooltip': ParamLongText,
# other
'bitmap': ParamBitmap, 'icon': ParamBitmap,
'comment': ParamComment,
'wrap': ParamInt,
}
'''Default classes for standard attributes.'''
class StylePanel(wx.Panel):
'''Style panel.'''
def __init__(self, parent, styles, genericStyles=[], tag='style'):
wx.Panel.__init__(self, parent, -1)
self.SetFont(g.smallerFont())
self.node = None
self.controls = []
self.tag = tag
topSizer = wx.BoxSizer(wx.HORIZONTAL)
if genericStyles:
# Generic styles
sizer = wx.GridSizer(len(genericStyles), 1, 1, 5)
label = wx.StaticText(self, label='Generic')
label.SetFont(g.labelFont())
sizer.Add(label, 0, wx.LEFT, 20)
for s in genericStyles:
if s[:2] == 'wx': label = s[2:]
else: label = s
control = wx.CheckBox(self, label=label)
sizer.Add(control)
self.controls.append((s, control))
topSizer.Add(sizer)
if styles:
# Specific styles
sizer = wx.GridSizer(len(styles), 1, 1, 5)
if genericStyles:
label = wx.StaticText(self, label='Specific')
label.SetFont(g.labelFont())
sizer.Add(label, 0, wx.LEFT, 20)
for s in styles:
if s[:2] == 'wx': label = s[2:]
else: label = s
control = wx.CheckBox(self, label=label)
sizer.Add(control)
self.controls.append((s, control))
topSizer.Add(sizer)
self.Bind(wx.EVT_CHECKBOX, self.OnCheck)
self.SetSizerAndFit(topSizer)
def GetValues(self):
checked = []
for s,check in self.controls:
if check.IsChecked(): checked.append(s)
return [(self.tag, '|'.join(checked))]
def SetValues(self, values):
styles = values[0][1].split('|')
for s,check in self.controls:
check.SetValue(s in styles)
def OnCheck(self, evt):
Presenter.setApplied(False)
if Listener.testWin.IsShown() and g.conf.autoRefresh and \
g.conf.autoRefreshPolicy == AUTO_REFRESH_POLICY_FOCUS:
Listener.testWin.isDirty = True
wx.CallAfter(Presenter.refreshTestWin)
evt.Skip()
#############################################################################
class CheckListBoxComboPopup(wx.CheckListBox, wx.combo.ComboPopup):
def __init__(self, values):
self.values = values
self.PostCreate(wx.PreCheckListBox())
wx.combo.ComboPopup.__init__(self)
def Create(self, parent):
wx.CheckListBox.Create(self, parent)
self.InsertItems(self.values, 0)
return True
def GetControl(self):
return self
def OnPopup(self):
combo = self.GetCombo()
value = map(string.strip, combo.GetValue().split('|'))
if value == ['']: value = []
self.ignored = []
for i in value:
try:
self.Check(self.values.index(i))
except ValueError:
# Try to find equal
if self.equal.has_key(i):
self.Check(self.values.index(self.equal[i]))
else:
logger.warning('unknown flag: %s: ignored.', i)
self.ignored.append(i)
wx.combo.ComboPopup.OnPopup(self)
def OnDismiss(self):
combo = self.GetCombo()
value = []
for i in range(self.GetCount()):
if self.IsChecked(i):
value.append(self.values[i])
# Add ignored flags
value.extend(self.ignored)
strValue = '|'.join(value)
if combo.GetValue() != strValue:
combo.SetValue(strValue)
Presenter.setApplied(False)
wx.combo.ComboPopup.OnDismiss(self)
|