Module params
[hide private]
[frames] | no frames]

Source Code for Module params

   1  # Name:         params.py 
   2  # Purpose:      Classes for parameter introduction 
   3  # Author:       Roman Rolinsky <rolinsky@mema.ucl.ac.be> 
   4  # Created:      22.08.2001 
   5  # RCS-ID:       $Id: params.py 48520 2007-09-03 01:15:15Z ROL $ 
   6   
   7  ''' 
   8  Visual C{Param*} classes for populating C{AtrtibutePanel} with attribute editing 
   9  blocks.  
  10  ''' 
  11   
  12  import string 
  13  import os 
  14  import wx.combo 
  15  from globals import * 
  16   
  17  WARenameDict = {'fg': 'foreground', 'bg': 'background'} 
  18   
19 -def InitParams(panel):
20 '''Set pixel common size based on parent window.''' 21 22 global Presenter 23 from presenter import Presenter 24 25 dc = wx.ClientDC(panel) 26 global textH, textB 27 textH = -1 28 if wx.Platform == '__WXMAC__': 29 textB = 3 # bigger text border needed for mac highlighting 30 else: 31 textB = 2 32 dc.Destroy() 33 34 # make a custom bitmap showing "..." 35 bw, bh = 14, 16 36 bmp = wx.EmptyBitmap(bw,bh) 37 dc = wx.MemoryDC(bmp) 38 39 # clear to a specific background colour 40 bgcolor = wx.Colour(255,254,255) 41 dc.SetBackground(wx.Brush(bgcolor)) 42 dc.Clear() 43 44 # draw the label onto the bitmap 45 label = "..." 46 font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) 47 font.SetWeight(wx.FONTWEIGHT_BOLD) 48 dc.SetFont(font) 49 tw,th = dc.GetTextExtent(label) 50 dc.DrawText(label, (bw-tw)/2, (bw-tw)/2) 51 del dc 52 53 # now apply a mask using the bgcolor 54 bmp.SetMaskColour(bgcolor) 55 global bmpEdit 56 bmpEdit = bmp 57 58 # Set known encodings 59 for i in range(wx.FontMapper.GetSupportedEncodingsCount()): 60 ParamEncoding.values.append(wx.FontMapper.GetEncodingName( 61 wx.FontMapper.GetEncoding(i))) 62 ParamEncoding.values.sort()
63 64 65 # Class that can properly disable children
66 -class PPanel(wx.Panel):
67 '''Abstract base class creating an empty C{wx.Panel}.''' 68 isCheck = False
69 - def __init__(self, parent, name):
70 wx.Panel.__init__(self, parent, -1, name=name) 71 self.freeze = False 72 self.name = name
73 - def Enable(self, value):
74 self.enabled = value 75 # Something strange is going on with enable so we make sure... 76 for w in self.GetChildren(): 77 w.Enable(value)
78 #wx.Panel.Enable(self, value) 79 # Common method to set modified state
80 - def OnChange(self, evt):
81 if self.freeze: return 82 Presenter.setApplied(False) 83 evt.Skip()
84
85 -class ParamBinaryOr(PPanel):
86 '''Editing binary flag attributes defined by a string separated by '|'.'''
87 - def __init__(self, parent, name):
88 PPanel.__init__(self, parent, name) 89 sizer = wx.BoxSizer() 90 popup = CheckListBoxComboPopup(self.values) 91 self.combo = wx.combo.ComboCtrl(self, size=(220,-1)) 92 self.combo.SetPopupControl(popup) 93 if wx.Platform == '__WXMAC__': 94 sizer.Add(self.combo, 1, wx.ALL, 0) 95 else: 96 sizer.Add(self.combo, 1, wx.ALL, 2) 97 self.SetSizerAndFit(sizer) 98 self.combo.Bind(wx.EVT_TEXT, self.OnChange)
99 - def GetValue(self):
100 return self.combo.GetValue()
101 - def SetValue(self, value):
102 self.freeze = True 103 self.combo.SetValue(value) 104 self.freeze = False
105 - def SetValues(self):
106 self.combo.InsertItems(self.values, 0)
107
108 -class ParamFlag(ParamBinaryOr):
109 '''Sizer flag editing.''' 110 values = ['wxTOP', 'wxBOTTOM', 'wxLEFT', 'wxRIGHT', 'wxALL', 111 'wxEXPAND', 'wxGROW', 'wxSHAPED', 'wxSTRETCH_NOT', 112 'wxALIGN_CENTRE', 'wxALIGN_LEFT', 'wxALIGN_RIGHT', 113 'wxALIGN_TOP', 'wxALIGN_BOTTOM', 114 'wxALIGN_CENTRE_VERTICAL', 'wxALIGN_CENTRE_HORIZONTAL', 115 'wxADJUST_MINSIZE', 'wxFIXED_MINSIZE' 116 ] 117 equal = {'wxALIGN_CENTER': 'wxALIGN_CENTRE', 118 'wxALIGN_CENTER_VERTICAL': 'wxALIGN_CENTRE_VERTICAL', 119 'wxALIGN_CENTER_HORIZONTAL': 'wxALIGN_CENTRE_HORIZONTAL', 120 'wxUP': 'wxTOP', 'wxDOWN': 'wxBOTTOM', 'wxNORTH': 'wxTOP', 121 'wxSOUTH': 'wxBOTTOM', 'wxWEST': 'wxLEFT', 'wxEAST': 'wxRIGHT'}
122 - def __init__(self, parent, name):
123 ParamBinaryOr.__init__(self, parent, name)
124
125 -class ParamColour(PPanel):
126 '''Color attribute editing.'''
127 - def __init__(self, parent, name):
128 PPanel.__init__(self, parent, name) 129 sizer = wx.BoxSizer() 130 self.text = wx.TextCtrl(self, size=(80,textH)) 131 sizer.Add(self.text, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, textB) 132 self.button = wx.Panel(self, size=(20, 20)) 133 sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 3) 134 self.SetSizer(sizer) 135 self.textModified = False 136 self.button.Bind(wx.EVT_PAINT, self.OnPaintButton) 137 self.text.Bind(wx.EVT_TEXT, self.OnChange) 138 self.button.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
139 - def GetValue(self):
140 return self.text.GetValue()
141 - def SetValue(self, value):
142 self.text.ChangeValue(value) # update text ctrl 143 self.UpdateColour(value)
144 - def UpdateColour(self, value):
145 try: 146 colour = wx.Colour(int(value[1:3], 16), int(value[3:5], 16), int(value[5:7], 16)) 147 self.button.SetBackgroundColour(colour) 148 except: # ignore errors 149 self.button.SetBackgroundColour(self.GetBackgroundColour()) 150 self.button.Refresh()
151 - def OnChange(self, evt):
152 self.UpdateColour(evt.GetString()) 153 evt.Skip()
154 - def OnPaintButton(self, evt):
155 dc = wx.PaintDC(self.button) 156 dc.SetBrush(wx.TRANSPARENT_BRUSH) 157 if self.IsEnabled(): dc.SetPen(wx.BLACK_PEN) 158 else: dc.SetPen(wx.GREY_PEN) 159 size = self.button.GetSize() 160 dc.DrawRectangle(0, 0, size.width, size.height)
161 - def OnLeftDown(self, evt):
162 data = wx.ColourData() 163 data.SetColour(self.GetValue()) 164 dlg = wx.ColourDialog(self, data) 165 if dlg.ShowModal() == wx.ID_OK: 166 self.SetValue('#%02X%02X%02X' % dlg.GetColourData().GetColour().Get()) 167 Presenter.setApplied(False) 168 dlg.Destroy()
169 170 ################################################################################ 171 172 # Mapping from wx constants to XML strings 173 fontFamiliesWx2Xml = {wx.DEFAULT: 'default', wx.DECORATIVE: 'decorative', 174 wx.ROMAN: 'roman', wx.SCRIPT: 'script', wx.SWISS: 'swiss', 175 wx.MODERN: 'modern'} 176 fontStylesWx2Xml = {wx.NORMAL: 'normal', wx.SLANT: 'slant', wx.ITALIC: 'italic'} 177 fontWeightsWx2Xml = {wx.NORMAL: 'normal', wx.LIGHT: 'light', wx.BOLD: 'bold'}
178 -def ReverseMap(m):
179 rm = {} 180 for k,v in m.items(): rm[v] = k 181 return rm
182 fontFamiliesXml2wx = ReverseMap(fontFamiliesWx2Xml) 183 fontStylesXml2wx = ReverseMap(fontStylesWx2Xml) 184 fontWeightsXml2wx = ReverseMap(fontWeightsWx2Xml) 185 186 # My font picker
187 -class FontPickerCtrl(wx.Button):
188 - def __init__(self, parent, id=-1, font=wx.NullFont, size=wx.DefaultSize, style=0):
189 wx.Button.__init__(self, parent, id)
190
191 -class ParamFont(PPanel):
192 '''Font attribute editing.'''
193 - def __init__(self, parent, name):
194 PPanel.__init__(self, parent, name) 195 sizer = wx.BoxSizer() 196 self.button = wx.FontPickerCtrl( 197 self, style=wx.FNTP_FONTDESC_AS_LABEL | wx.FNTP_USE_TEXTCTRL 198 ) 199 self.text = self.button.GetTextCtrl() 200 if wx.Platform == '__WXMAC__': 201 sizer.Add(self.button, 0, wx.LEFT, -2) 202 else: 203 sizer.Add(self.button, 0, wx.LEFT, textB) 204 self.SetSizer(sizer) 205 self.Bind(wx.EVT_FONTPICKER_CHANGED, self.OnPickFont) 206 self.text.Bind(wx.EVT_TEXT, self.OnText) 207 self.text.Bind(wx.EVT_KILL_FOCUS, self.OnTextKillFocus)
208 - def OnText(self, evt):
209 Presenter.setApplied(False) 210 if evt.GetString(): 211 evt.Skip() 212 else: 213 self.text.ChangeValue('')
214 - def OnTextKillFocus(self, evt):
215 if self.text.GetValue(): 216 evt.Skip()
217 - def GetValue(self):
218 return self.value
219 - def dict2font(self, d):
220 error = False 221 if 'size' in d: 222 try: size = int(d['size']) 223 except ValueError: error = True; wx.LogError('Invalid size specification') 224 else: 225 size = g.sysFont().GetPointSize() 226 if 'family' in d: 227 try: family = fontFamiliesXml2wx[d['family']] 228 except KeyError: error = True; wx.LogError('Invalid family specification') 229 else: 230 family = wx.DEFAULT 231 if 'style' in d: 232 try: style = fontStylesXml2wx[d['style']] 233 except KeyError: error = True; wx.LogError('Invalid style specification') 234 else: 235 style = wx.NORMAL 236 if 'weight' in d: 237 try: weight = fontWeightsXml2wx[d['weight']] 238 except KeyError: error = True; wx.LogError('Invalid weight specification') 239 else: 240 weight = wx.NORMAL 241 try: underlined = bool(d.get('underlined', 0)) 242 except ValueError: error = True; wx.LogError('Invalid underlined flag specification') 243 face = d.get('face','') 244 enc = wx.FONTENCODING_DEFAULT 245 mapper = wx.FontMapper() 246 if 'encoding' in d: enc = mapper.CharsetToEncoding(d['encoding']) 247 if error: wx.LogError('Invalid font specification') 248 if enc == wx.FONTENCODING_DEFAULT: enc = wx.FONTENCODING_SYSTEM 249 font = wx.Font(size, family, style, weight, underlined, face, enc) 250 return font
251
252 - def SetValue(self, value):
253 self.freeze = True # disable other handlers 254 if not value: 255 self.text.ChangeValue('') 256 else: 257 self.button.SetSelectedFont(self.dict2font(value)) 258 self.value = value 259 self.freeze = False
260 - def OnPickFont(self, evt):
261 font = evt.GetFont() 262 if font.GetEncoding() == wx.FONTENCODING_SYSTEM: 263 encName = '' 264 else: 265 encName = wx.FontMapper.GetEncodingName(font.GetEncoding()).encode() 266 value = {'size': str(font.GetPointSize()), 267 'family': fontFamiliesWx2Xml.get(font.GetFamily(), "default"), 268 'style': fontStylesWx2Xml.get(font.GetStyle(), "normal"), 269 'weight': fontWeightsWx2Xml.get(font.GetWeight(), "normal"), 270 'underlined': str(int(font.GetUnderlined())), 271 'face': font.GetFaceName().encode(), 272 'encoding': encName} 273 self.SetValue(value) 274 Presenter.setApplied(False)
275 276 ################################################################################ 277 278 # This is a replacement for SpinCtrl to make ParamUnit looking similar. 279 # Unfortunately there is no SpinCtrl::GetStringValue...
280 -class ParamInt(PPanel):
281 '''TextCtrl with SpinButton for integer parameters.''' 282 default = 0 283 range = (-2147483648, 2147483647)
284 - def __init__(self, parent, name):
285 PPanel.__init__(self, parent, name) 286 sizer = wx.BoxSizer(wx.HORIZONTAL) 287 self.spin = wx.SpinButton(self, style = wx.SP_VERTICAL, size=(-1,10)) 288 textW = 60 - self.spin.GetSize()[0] 289 self.text = wx.TextCtrl(self, size=(textW,textH)) 290 self.spin.SetRange(*self.range) 291 if wx.Platform == '__WXMAC__': 292 sizer.Add(self.text, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | wx.ALL, textB) 293 else: 294 sizer.Add(self.text, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND | \ 295 wx.LEFT | wx.TOP | wx.BOTTOM, textB) 296 sizer.Add(self.spin, 0, wx.ALIGN_CENTER_VERTICAL | wx.EXPAND) 297 self.SetSizer(sizer) 298 self.spin.Bind(wx.EVT_SPIN_UP, self.OnSpinUp) 299 self.spin.Bind(wx.EVT_SPIN_DOWN, self.OnSpinDown) 300 self.text.Bind(wx.EVT_TEXT, self.OnChange)
301
302 - def GetValue(self):
303 return self.text.GetValue()
304 - def SetValue(self, value):
305 self.text.ChangeValue(value) 306 self.SyncSpin(value)
307 - def SyncSpin(self, value):
308 try: 309 intValue = int(value) 310 self.spin.SetValue(intValue) 311 except: 312 self.spin.SetValue(self.default)
313 - def OnChange(self, evt):
314 self.SyncSpin(evt.GetString()) 315 Presenter.setApplied(False) 316 evt.Skip()
317 - def SyncText(self, spinValue):
318 if self.range[0] <= spinValue <= self.range[1]: 319 self.text.ChangeValue(str(spinValue)) 320 Presenter.setApplied(False)
321 - def OnSpinUp(self, evt):
322 self.SyncText(evt.GetPosition()) 323 evt.Skip()
324 - def OnSpinDown(self, evt):
325 self.SyncText(evt.GetPosition()) 326 evt.Skip()
327
328 -def MetaParamInt(**kargs):
329 '''Create ParamInt class with default value.''' 330 return type('ParamInt', (ParamInt,), kargs)
331 332 ParamIntNN = MetaParamInt(default=0, range=(0, 2147483647)) # non-negative 333 ParamIntP = MetaParamInt(default=1, range=(1, 2147483647)) # positive 334 335 # Same as ParamInt but allows dialog units (XXXd)
336 -class ParamUnit(ParamInt):
337 '''Similar to L{ParamInt}, 'd' can be appended to the value to specify 338 dialog units mode.'''
339 - def _splitValue(self, value):
340 units = '' 341 if value[-1:].upper() == 'D': 342 units = value[-1] 343 value = value[:-1] 344 return value,units
345 - def SyncSpin(self, value):
346 try: 347 value,units = self._splitValue(value) 348 intValue = int(value) 349 self.spin.SetValue(intValue) 350 except: 351 self.spin.SetValue(self.default)
352 - def SyncText(self, spinValue):
353 if self.range[0] <= spinValue <= self.range[1]: 354 value,units = self._splitValue(self.text.GetValue()) 355 self.text.ChangeValue(str(spinValue)+units) 356 Presenter.setApplied(False)
357
358 -class ParamMultilineText(PPanel):
359 '''Multiline text editing.'''
360 - def __init__(self, parent, name, textWidth=-1):
361 PPanel.__init__(self, parent, name) 362 sizer = wx.BoxSizer() 363 self.text = wx.TextCtrl(self, size=wx.Size(200,textH)) 364 sizer.Add(self.text, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, textB) 365 self.button = wx.BitmapButton(self, bitmap=bmpEdit, size=(-1,textH)) 366 sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) 367 self.SetSizer(sizer) 368 self.button.Bind(wx.EVT_BUTTON, self.OnButtonEdit) 369 self.text.Bind(wx.EVT_TEXT, self.OnChange)
370 - def GetValue(self):
371 return self.text.GetValue()
372 - def SetValue(self, value):
373 self.freeze = True # disable other handlers 374 self.text.SetValue(value) 375 self.freeze = False # disable other handlers
376 - def OnButtonEdit(self, evt):
377 dlg = g.res.LoadDialog(self, 'DIALOG_TEXT') 378 textCtrl = xrc.XRCCTRL(dlg, 'TEXT') 379 textCtrl.SetValue(self.text.GetValue()) 380 if dlg.ShowModal() == wx.ID_OK: 381 self.text.SetValue(textCtrl.GetValue()) 382 Presenter.setApplied(False) 383 dlg.Destroy()
384
385 -class ParamText(PPanel):
386 '''Text attribute.''' 387 textWidth = -1 388 proportion = 0
389 - def __init__(self, parent, name, style=0, **kargs):
390 PPanel.__init__(self, parent, name) 391 textWidth = kargs.get('textWidth', self.textWidth) 392 option = kargs.get('proportion', self.proportion) 393 if textWidth == -1: option = 1 394 # We use sizer even here to have the same size of text control 395 sizer = wx.BoxSizer() 396 self.text = wx.TextCtrl(self, size=wx.Size(textWidth,textH), style=style) 397 sizer.Add(self.text, option, wx.ALIGN_CENTER_VERTICAL | wx.ALL, textB) 398 self.SetSizer(sizer) 399 self.text.Bind(wx.EVT_TEXT, self.OnChange)
400 - def GetValue(self):
401 return self.text.GetValue()
402 - def SetValue(self, value):
403 self.freeze = True # disable other handlers 404 self.text.SetValue(value) 405 self.freeze = False # disable other handlers
406
407 -def MetaParamText(textWidth, proportion=0):
408 '''Return a L{ParamText} class with specified width and proportion.''' 409 return type('ParamText__length', (ParamText,), 410 {'textWidth': textWidth, 'proportion': proportion})
411 412 ParamLongText = MetaParamText(200, 1) 413 ParamAccel = MetaParamText(100) 414 ParamHelp = MetaParamText(200, 1) 415 ParamPosSize = MetaParamText(80) 416
417 -class ParamComment(ParamText):
418 '''Comment node editing.'''
419 - def __init__(self, parent, name):
420 ParamText.__init__(self, parent, name, 330, 421 style=wx.TE_PROCESS_ENTER)
422
423 -class ContentDialog(wx.Dialog):
424 '''Dialog for editing content attributes.'''
425 - def __init__(self, parent, value):
426 # Load from resource 427 pre = wx.PreDialog() 428 g.res.LoadOnDialog(pre, parent, 'DIALOG_CONTENT') 429 self.PostCreate(pre) 430 self.list = xrc.XRCCTRL(self, 'LIST') 431 # Set list items 432 for v in value: 433 self.list.Append(v) 434 self.SetAutoLayout(True) 435 self.GetSizer().Fit(self) 436 # Callbacks 437 self.ID_BUTTON_APPEND = xrc.XRCID('BUTTON_APPEND') 438 self.ID_BUTTON_REMOVE = xrc.XRCID('BUTTON_REMOVE') 439 self.ID_BUTTON_UP = xrc.XRCID('BUTTON_UP') 440 self.ID_BUTTON_DOWN = xrc.XRCID('BUTTON_DOWN') 441 wx.EVT_BUTTON(self, self.ID_BUTTON_UP, self.OnButtonUp) 442 wx.EVT_BUTTON(self, self.ID_BUTTON_DOWN, self.OnButtonDown) 443 wx.EVT_BUTTON(self, self.ID_BUTTON_APPEND, self.OnButtonAppend) 444 wx.EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove) 445 wx.EVT_UPDATE_UI(self, self.ID_BUTTON_UP, self.OnUpdateUI) 446 wx.EVT_UPDATE_UI(self, self.ID_BUTTON_DOWN, self.OnUpdateUI) 447 wx.EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI)
448 - def OnButtonUp(self, evt):
449 i = self.list.GetSelection() 450 str = self.list.GetString(i) 451 self.list.Delete(i) 452 self.list.InsertItems([str], i-1) 453 self.list.SetSelection(i-1)
454 - def OnButtonDown(self, evt):
455 i = self.list.GetSelection() 456 str = self.list.GetString(i) 457 self.list.Delete(i) 458 self.list.InsertItems([str], i+1) 459 self.list.SetSelection(i+1)
460 - def OnButtonAppend(self, evt):
461 str = wx.GetTextFromUser('Enter new item:', 'Append', '', self) 462 self.list.Append(str)
463 - def OnButtonRemove(self, evt):
464 self.list.Delete(self.list.GetSelection())
465 - def OnUpdateUI(self, evt):
466 if evt.GetId() == self.ID_BUTTON_REMOVE: 467 evt.Enable(self.list.GetSelection() != -1) 468 elif evt.GetId() == self.ID_BUTTON_UP: 469 evt.Enable(self.list.GetSelection() > 0) 470 elif evt.GetId() == self.ID_BUTTON_DOWN: 471 evt.Enable(self.list.GetSelection() != -1 and \ 472 self.list.GetSelection() < self.list.GetCount() - 1)
473
474 -class ContentCheckListDialog(wx.Dialog):
475 '''Dialog for editing content checklist attributes.'''
476 - def __init__(self, parent, value):
477 pre = wx.PreDialog() 478 g.res.LoadOnDialog(pre, parent, 'DIALOG_CONTENT_CHECKLIST') 479 self.PostCreate(pre) 480 self.list = xrc.XRCCTRL(self, 'CHECK_LIST') 481 # Set list items 482 i = 0 483 for v,ch in value: 484 self.list.Append(v) 485 self.list.Check(i, ch) 486 i += 1 487 self.SetAutoLayout(True) 488 self.GetSizer().Fit(self) 489 # Callbacks 490 self.ID_BUTTON_APPEND = xrc.XRCID('BUTTON_APPEND') 491 self.ID_BUTTON_REMOVE = xrc.XRCID('BUTTON_REMOVE') 492 self.ID_BUTTON_UP = xrc.XRCID('BUTTON_UP') 493 self.ID_BUTTON_DOWN = xrc.XRCID('BUTTON_DOWN') 494 wx.EVT_CHECKLISTBOX(self, self.list.GetId(), self.OnCheck) 495 wx.EVT_BUTTON(self, self.ID_BUTTON_UP, self.OnButtonUp) 496 wx.EVT_BUTTON(self, self.ID_BUTTON_DOWN, self.OnButtonDown) 497 wx.EVT_BUTTON(self, self.ID_BUTTON_APPEND, self.OnButtonAppend) 498 wx.EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove) 499 wx.EVT_UPDATE_UI(self, self.ID_BUTTON_UP, self.OnUpdateUI) 500 wx.EVT_UPDATE_UI(self, self.ID_BUTTON_DOWN, self.OnUpdateUI) 501 wx.EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI)
502 - def OnCheck(self, evt):
503 # !!! Wrong wxGTK (wxMSW?) behavior: toggling selection if checking 504 self.list.Deselect(evt.GetSelection())
505 - def OnButtonUp(self, evt):
506 i = self.list.GetSelection() 507 str, ch = self.list.GetString(i), self.list.IsChecked(i) 508 self.list.Delete(i) 509 self.list.InsertItems([str], i-1) 510 self.list.Check(i-1, ch) 511 self.list.SetSelection(i-1)
512 - def OnButtonDown(self, evt):
513 i = self.list.GetSelection() 514 str, ch = self.list.GetString(i), self.list.IsChecked(i) 515 self.list.Delete(i) 516 self.list.InsertItems([str], i+1) 517 self.list.Check(i+1, ch) 518 self.list.SetSelection(i+1)
519 - def OnButtonAppend(self, evt):
520 str = wx.GetTextFromUser('Enter new item:', 'Append', '', self) 521 self.list.Append(str)
522 - def OnButtonRemove(self, evt):
523 self.list.Delete(self.list.GetSelection())
524 - def OnUpdateUI(self, evt):
525 if evt.GetId() == self.ID_BUTTON_REMOVE: 526 evt.Enable(self.list.GetSelection() != -1) 527 elif evt.GetId() == self.ID_BUTTON_UP: 528 evt.Enable(self.list.GetSelection() > 0) 529 elif evt.GetId() == self.ID_BUTTON_DOWN: 530 evt.Enable(self.list.GetSelection() != -1 and \ 531 self.list.GetSelection() < self.list.GetCount() - 1)
532
533 -class ParamContent(PPanel):
534 '''Editing of content attribute.'''
535 - def __init__(self, parent, name):
536 PPanel.__init__(self, parent, name) 537 sizer = wx.BoxSizer() 538 self.text = wx.TextCtrl(self, size=wx.Size(200,textH)) 539 sizer.Add(self.text, 1, wx.ALL | wx.ALIGN_CENTER_VERTICAL, textB) 540 self.button = wx.BitmapButton(self, bitmap=bmpEdit, size=(-1,textH)) 541 sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) 542 self.SetSizer(sizer) 543 self.textModified = False 544 self.button.Bind(wx.EVT_BUTTON, self.OnButtonEdit) 545 self.text.Bind(wx.EVT_TEXT, self.OnChange)
546 - def OnChange(self, evt):
547 Presenter.setApplied(False) 548 self.textModified = True
549 - def GetValue(self):
550 if self.textModified: # text has newer value 551 try: 552 return self.text.GetValue().split('|') 553 except ValueError: 554 return [] 555 return self.value
556 - def SetValue(self, value):
557 if not value: value = [] 558 self.value = value 559 repr_ = '|'.join(map(str, value)) 560 self.text.ChangeValue(repr_) # update text ctrl
561 - def OnButtonEdit(self, evt):
562 if self.textModified: # text has newer value 563 self.value = self.GetValue() 564 dlg = ContentDialog(self, self.value) 565 if dlg.ShowModal() == wx.ID_OK: 566 value = [] 567 for i in range(dlg.list.GetCount()): 568 value.append(dlg.list.GetString(i)) 569 self.SetValue(value) 570 Presenter.setApplied(False) 571 self.textModified = False 572 dlg.Destroy()
573 574 # CheckList content
575 -class ParamContentCheckList(ParamContent):
576 '''Editing of content check list attribute.'''
577 - def __init__(self, parent, name):
578 ParamContent.__init__(self, parent, name)
579 - def OnButtonEdit(self, evt):
580 if self.textModified: # text has newer value 581 self.value = self.GetValue() 582 dlg = ContentCheckListDialog(self, self.value) 583 if dlg.ShowModal() == wx.ID_OK: 584 value = [] 585 for i in range(dlg.list.GetCount()): 586 value.append((dlg.list.GetString(i), int(dlg.list.IsChecked(i)))) 587 self.SetValue(value) 588 Presenter.setApplied(False) 589 self.textModified = False 590 dlg.Destroy()
591 - def SetValue(self, value):
592 self.freeze = True 593 if not value: value = [] 594 self.value = value 595 repr_ = '|'.join(map(str,value)) 596 self.text.SetValue(repr_) # update text ctrl 597 self.freeze = False
598
599 -class IntListDialog(wx.Dialog):
600 '''Dialog for editing integer lists.'''
601 - def __init__(self, parent, value):
602 pre = wx.PreDialog() 603 g.res.LoadOnDialog(pre, parent, 'DIALOG_INTLIST') 604 self.PostCreate(pre) 605 self.list = xrc.XRCCTRL(self, 'LIST') 606 # Set list items 607 value.sort() 608 for v in value: 609 self.list.Append(v) 610 self.SetAutoLayout(True) 611 self.GetSizer().Fit(self) 612 # Callbacks 613 self.spinCtrl = xrc.XRCCTRL(self, 'SPIN') 614 wx.EVT_BUTTON(self, xrc.XRCID('BUTTON_ADD'), self.OnButtonAdd) 615 self.ID_BUTTON_REMOVE = xrc.XRCID('BUTTON_REMOVE') 616 wx.EVT_BUTTON(self, self.ID_BUTTON_REMOVE, self.OnButtonRemove) 617 wx.EVT_BUTTON(self, xrc.XRCID('BUTTON_CLEAR'), self.OnButtonClear) 618 wx.EVT_UPDATE_UI(self, self.ID_BUTTON_REMOVE, self.OnUpdateUI)
619 - def OnButtonAdd(self, evt):
620 # Check that it's unique 621 try: 622 v = self.spinCtrl.GetValue() 623 s = str(v) # to be sure 624 i = self.list.FindString(s) 625 if i == -1: # ignore non-unique 626 # Find place to insert 627 found = False 628 for i in range(self.list.GetCount()): 629 if int(self.list.GetString(i)) > v: 630 found = True 631 break 632 if found: self.list.InsertItems([s], i) 633 else: self.list.Append(s) 634 except ValueError: 635 wx.LogError('List item is not an int!')
636 - def OnButtonRemove(self, evt):
637 self.list.Delete(self.list.GetSelection())
638 - def OnButtonClear(self, evt):
639 self.list.Clear()
640 - def OnUpdateUI(self, evt):
641 if evt.GetId() == self.ID_BUTTON_REMOVE: 642 evt.Enable(self.list.GetSelection() != -1)
643 644 # For growable list
645 -class ParamIntList(ParamContent):
646 '''Editing integer list attribute.'''
647 - def __init__(self, parent, name):
648 ParamContent.__init__(self, parent, name)
649 - def OnButtonEdit(self, evt):
650 if self.textModified: # text has newer value 651 try: 652 self.value = self.text.GetValue().split('|') 653 except ValueError: 654 self.value = [] 655 dlg = IntListDialog(self, self.value) 656 if dlg.ShowModal() == wx.ID_OK: 657 value = [] 658 for i in range(dlg.list.GetCount()): 659 value.append(dlg.list.GetString(i)) 660 self.SetValue(value) 661 Presenter.setApplied() 662 self.textModified = False 663 dlg.Destroy()
664 665 # Boxless radiobox
666 -class RadioBox(PPanel):
667 - def __init__(self, parent, id, choices, 668 pos=wx.DefaultPosition, name='radiobox'):
669 PPanel.__init__(self, parent, name) 670 self.choices = choices 671 topSizer = wx.BoxSizer() 672 for i in choices: 673 button = wx.RadioButton(self, -1, i, name=i) 674 topSizer.Add(button, 0, wx.RIGHT, 5) 675 wx.EVT_RADIOBUTTON(self, button.GetId(), self.OnRadioChoice) 676 self.SetSizer(topSizer)
677 - def SetStringSelection(self, value):
678 self.freeze = True 679 for i in self.choices: 680 self.FindWindowByName(i).SetValue(i == value) 681 self.value = value 682 self.freeze = False
683 - def OnRadioChoice(self, evt):
684 if self.freeze: return 685 if evt.GetSelection(): 686 self.value = evt.GetEventObject().GetName() 687 Presenter.setApplied(False)
688 - def GetStringSelection(self):
689 return self.value
690 691 # Boxless radiobox
692 -class CheckBox(PPanel):
693 isCheck = True
694 - def __init__(self, parent, name='checkbox'):
695 PPanel.__init__(self, parent, name) 696 topSizer = wx.BoxSizer() 697 self.check = wx.CheckBox(self, -1, name, size=(-1,textH)) 698 topSizer.Add(self.check, 0, wx.TOP | wx.BOTTOM, textB) 699 self.check.Bind(wx.EVT_CHECKBOX, self.OnCheck) 700 self.SetSizer(topSizer)
701 - def OnCheck(self, evt):
702 Presenter.setApplied(False) 703 if Presenter.panelIsDirty(): 704 Presenter.registerUndoEdit() 705 evt.Skip()
706
707 -class ParamBool(CheckBox):
708 '''Editing on/off attributes.''' 709 defaultString = '(default is OFF)'
710 - def GetValue(self):
711 return ('', '1')[self.check.IsChecked()]
712 - def SetValue(self, value):
713 self.check.SetValue(value == '1')
714
715 -class ParamInverseBool(CheckBox):
716 '''like L{ParamBool} but defined if unchecked''' 717 defaultString = '(default is ON)'
718 - def GetValue(self):
719 return ('0', '')[self.check.IsChecked()]
720 - def SetValue(self, value):
721 self.check.SetValue(not value or value == '1')
722
723 -class ParamOrient(RadioBox):
724 '''Orientation attribute editing for sizers.''' 725 values = {'horizontal': 'wxHORIZONTAL', 'vertical': 'wxVERTICAL'} 726 seulav = {'wxHORIZONTAL': 'horizontal', 'wxVERTICAL': 'vertical'}
727 - def __init__(self, parent, name):
728 RadioBox.__init__(self, parent, -1, choices=self.values.keys(), name=name)
729 - def GetValue(self):
730 return self.values[self.GetStringSelection()]
731 - def SetValue(self, value):
732 if not value: value = 'wxHORIZONTAL' 733 self.SetStringSelection(self.seulav[value])
734
735 -class ParamOrientation(RadioBox):
736 '''Orientaiton attribute editing for C{wx.SplitterWindow}.''' 737 values = {'horizontal': 'horizontal', 'vertical': 'vertical'} 738 seulav = {'horizontal': 'horizontal', 'vertical': 'vertical'}
739 - def __init__(self, parent, name):
740 RadioBox.__init__(self, parent, -1, choices=self.values.keys(), name=name)
741 - def GetValue(self):
742 return self.values[self.GetStringSelection()]
743 - def SetValue(self, value):
744 if not value: value = 'vertical' 745 self.SetStringSelection(self.seulav[value])
746
747 -class ParamBitmap(PPanel):
748 - def __init__(self, parent, name):
749 pre = wx.PrePanel() 750 g.res.LoadOnPanel(pre, parent, 'PANEL_BITMAP') 751 self.PostCreate(pre) 752 self.modified = self.freeze = False 753 self.radio_std = xrc.XRCCTRL(self, 'RADIO_STD') 754 self.radio_file = xrc.XRCCTRL(self, 'RADIO_FILE') 755 self.combo = xrc.XRCCTRL(self, 'COMBO_STD') 756 self.text = xrc.XRCCTRL(self, 'TEXT_FILE') 757 self.button = xrc.XRCCTRL(self, 'BUTTON_BROWSE') 758 self.textModified = False 759 wx.EVT_RADIOBUTTON(self, xrc.XRCID('RADIO_STD'), self.OnRadioStd) 760 wx.EVT_RADIOBUTTON(self, xrc.XRCID('RADIO_FILE'), self.OnRadioFile) 761 wx.EVT_BUTTON(self, xrc.XRCID('BUTTON_BROWSE'), self.OnButtonBrowse) 762 wx.EVT_COMBOBOX(self, xrc.XRCID('COMBO_STD'), self.OnCombo) 763 wx.EVT_TEXT(self, xrc.XRCID('COMBO_STD'), self.OnChange) 764 wx.EVT_TEXT(self, xrc.XRCID('TEXT_FILE'), self.OnChange)
765 - def OnRadioStd(self, evt):
766 Presenter.setApplied(False) 767 self.SetValue(['wxART_MISSING_IMAGE',''])
768 - def OnRadioFile(self, evt):
769 Presenter.setApplied(False) 770 self.SetValue(['',''])
771 - def updateRadios(self):
772 if self.value[0]: 773 self.radio_std.SetValue(True) 774 self.radio_file.SetValue(False) 775 self.text.Enable(False) 776 self.button.Enable(False) 777 self.combo.Enable(True) 778 else: 779 self.radio_std.SetValue(False) 780 self.radio_file.SetValue(True) 781 self.text.Enable(True) 782 self.button.Enable(True) 783 self.combo.Enable(False)
784 - def OnChange(self, evt):
785 if self.freeze: return 786 Presenter.setApplied(False) 787 self.textModified = True
788 - def OnCombo(self, evt):
789 if self.freeze: return 790 Presenter.setApplied(False) 791 self.value[0] = self.combo.GetValue()
792 - def GetValue(self):
793 return [self.combo.GetValue(), self.text.GetValue()]
794 - def SetValue(self, value):
795 self.freeze = True 796 if not value: 797 self.value = ['', ''] 798 else: 799 self.value = value 800 self.combo.SetValue(self.value[0]) 801 self.text.SetValue(self.value[1]) # update text ctrl 802 self.updateRadios() 803 self.freeze = False
804 - def OnButtonBrowse(self, evt):
805 if self.textModified: # text has newer value 806 self.value[1] = self.text.GetValue() 807 dlg = wx.FileDialog(self, 808 defaultDir = os.path.abspath(os.path.dirname(self.value[1])), 809 defaultFile = os.path.basename(self.value[1])) 810 if dlg.ShowModal() == wx.ID_OK: 811 # Get common part of selected path and current 812 if Presenter.path: 813 curpath = os.path.abspath(Presenter.path) 814 else: 815 curpath = os.path.join(os.getcwd(), '') 816 common = os.path.commonprefix([curpath, dlg.GetPath()]) 817 self.SetValue(['', dlg.GetPath()[len(common):]]) 818 Presenter.setApplied(False) 819 self.textModified = False 820 dlg.Destroy()
821
822 -class ParamImage(PPanel):
823 '''Image selector.'''
824 - def __init__(self, parent, name):
825 PPanel.__init__(self, parent, name) 826 sizer = wx.BoxSizer() 827 self.text = wx.TextCtrl(self, size=wx.Size(200,textH)) 828 sizer.Add(self.text, 0, wx.ALL | wx.ALIGN_CENTER_VERTICAL, textB) 829 self.button = wx.Button(self, -1, 'Browse...') 830 sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) 831 self.SetSizer(sizer) 832 self.button.Bind(wx.EVT_BUTTON, self.OnButtonBrowse) 833 self.text.Bind(wx.EVT_TEXT, self.OnChange)
834 - def OnChange(self, evt):
835 Presenter.setApplied(False)
836 - def GetValue(self):
837 return self.text.GetValue()
838 - def SetValue(self, value):
839 self.text.SetValue(value)
840 - def OnButtonBrowse(self, evt):
841 value = self.text.GetValue() 842 dlg = wx.FileDialog(self, 843 defaultDir = os.path.abspath(os.path.dirname(value)), 844 defaultFile = os.path.basename(value)) 845 if dlg.ShowModal() == wx.ID_OK: 846 # Get common part of selected path and current 847 if Presenter.path: 848 curpath = os.path.abspath(Presenter.path) 849 else: 850 curpath = os.path.join(os.getcwd(), '') 851 common = os.path.commonprefix([curpath, dlg.GetPath()]) 852 self.SetValue(dlg.GetPath()[len(common):]) 853 Presenter.setApplied(False) 854 self.textModified = False 855 dlg.Destroy()
856
857 -class ParamCombo(PPanel):
858 values = [] 859 '''Combo box.'''
860 - def __init__(self, parent, name):
861 PPanel.__init__(self, parent, name) 862 sizer = wx.BoxSizer() 863 self.combo = wx.ComboBox(self, size=(220,-1)) 864 if wx.Platform == '__WXMAC__': 865 sizer.Add(self.combo, 0, wx.ALL, 0) 866 else: 867 sizer.Add(self.combo, 0, wx.ALL, 2) 868 self.SetSizerAndFit(sizer) 869 self.combo.Bind(wx.EVT_TEXT, self.OnChange) 870 self.SetValues()
871 - def GetValue(self):
872 return self.combo.GetValue()
873 - def SetValue(self, value):
874 self.freeze = True 875 self.combo.SetValue(value) 876 self.freeze = False
877 - def SetValues(self):
878 for v in self.values: 879 self.combo.Append(v)
880
881 -class ParamEncoding(ParamCombo):
882 '''Editing encoding attribute of the XML root node.''' 883 pass
884 885 paramDict = { 886 # sizer params 887 'flag': ParamFlag, 'orient': ParamOrient, 'option': ParamInt, 888 'cellpos': ParamPosSize, 'cellspan': ParamPosSize, 889 'border': ParamUnit, 'borders': ParamUnit, 890 'cols': ParamIntP, 'rows': ParamIntP, 891 'vgap': ParamUnit, 'hgap': ParamUnit, 892 # common window params 893 'pos': ParamPosSize, 'size': ParamPosSize, 894 'checkable': ParamBool, 'checked': ParamBool, 'radio': ParamBool, 895 'accel': ParamAccel, 'help': ParamHelp, 'centered': ParamBool, 896 'label': ParamMultilineText, 'title': ParamLongText, 'value': ParamLongText, 897 'content': ParamContent, 'selection': ParamIntNN, 898 'min': ParamInt, 'max': ParamInt, 899 # window attributes 900 'fg': ParamColour, 'bg': ParamColour, 'font': ParamFont, 901 'enabled': ParamInverseBool, 'focused': ParamBool, 'hidden': ParamBool, 902 'tooltip': ParamLongText, 903 # other 904 'bitmap': ParamBitmap, 'icon': ParamBitmap, 905 'comment': ParamComment 906 } 907 '''Default classes for standard attributes.''' 908
909 -class StylePanel(wx.Panel):
910 '''Style panel.'''
911 - def __init__(self, parent, styles, genericStyles=[]):
912 wx.Panel.__init__(self, parent, -1) 913 self.SetFont(g.smallerFont()) 914 self.node = None 915 self.controls = [] 916 topSizer = wx.BoxSizer(wx.HORIZONTAL) 917 if genericStyles: 918 # Generic styles 919 sizer = wx.GridSizer(len(genericStyles), 1, 1, 5) 920 label = wx.StaticText(self, label='Generic') 921 label.SetFont(g.labelFont()) 922 sizer.Add(label, 0, wx.LEFT, 20) 923 for s in genericStyles: 924 if s[:2] == 'wx': label = s[2:] 925 else: label = s 926 control = wx.CheckBox(self, label=label) 927 sizer.Add(control) 928 self.controls.append((s, control)) 929 topSizer.Add(sizer) 930 if styles: 931 # Specific styles 932 sizer = wx.GridSizer(len(styles), 1, 1, 5) 933 if genericStyles: 934 label = wx.StaticText(self, label='Specific') 935 label.SetFont(g.labelFont()) 936 sizer.Add(label, 0, wx.LEFT, 20) 937 for s in styles: 938 if s[:2] == 'wx': label = s[2:] 939 else: label = s 940 control = wx.CheckBox(self, label=label) 941 sizer.Add(control) 942 self.controls.append((s, control)) 943 topSizer.Add(sizer) 944 self.Bind(wx.EVT_CHECKBOX, self.OnCheck) 945 self.SetSizerAndFit(topSizer)
946
947 - def GetValues(self):
948 checked = [] 949 for s,check in self.controls: 950 if check.IsChecked(): checked.append(s) 951 return [('style', '|'.join(checked))]
952
953 - def SetValues(self, values):
954 styles = values[0][1].split('|') 955 for s,check in self.controls: 956 check.SetValue(s in styles)
957
958 - def OnCheck(self, evt):
959 Presenter.setApplied(False)
960 961 ############################################################################# 962
963 -class CheckListBoxComboPopup(wx.CheckListBox, wx.combo.ComboPopup):
964
965 - def __init__(self, values):
966 self.values = values 967 self.PostCreate(wx.PreCheckListBox()) 968 wx.combo.ComboPopup.__init__(self)
969
970 - def Create(self, parent):
971 wx.CheckListBox.Create(self, parent) 972 self.InsertItems(self.values, 0) 973 return True
974
975 - def GetControl(self):
976 return self
977
978 - def OnPopup(self):
979 combo = self.GetCombo() 980 value = map(string.strip, combo.GetValue().split('|')) 981 if value == ['']: value = [] 982 self.ignored = [] 983 for i in value: 984 try: 985 self.Check(self.values.index(i)) 986 except ValueError: 987 # Try to find equal 988 if self.equal.has_key(i): 989 self.Check(self.values.index(self.equal[i])) 990 else: 991 logger.warning('unknown flag: %s: ignored.', i) 992 self.ignored.append(i) 993 994 wx.combo.ComboPopup.OnPopup(self)
995
996 - def OnDismiss(self):
997 combo = self.GetCombo() 998 value = [] 999 for i in range(self.GetCount()): 1000 if self.IsChecked(i): 1001 value.append(self.values[i]) 1002 # Add ignored flags 1003 value.extend(self.ignored) 1004 strValue = '|'.join(value) 1005 if combo.GetValue() != strValue: 1006 combo.SetValue(strValue) 1007 Presenter.setApplied(False) 1008 1009 wx.combo.ComboPopup.OnDismiss(self)
1010