]> git.saurik.com Git - wxWidgets.git/blob - wxPython/samples/StyleEditor/STCStyleEditor.py
Fix or add some DoGetBestSize's
[wxWidgets.git] / wxPython / samples / StyleEditor / STCStyleEditor.py
1 #-----------------------------------------------------------------------------
2 # Name: STCStyleEditor.py
3 # Purpose: Style editor for the wxStyledTextCtrl
4 #
5 # Author: Riaan Booysen
6 #
7 # Created: 2001/08/20
8 # RCS-ID: $Id$
9 # Copyright: (c) 2001 - 2002 Riaan Booysen
10 # Licence: wxWindows license
11 #-----------------------------------------------------------------------------
12 #Boa:Dialog:STCStyleEditDlg
13
14 """ Style editor for the wxStyledTextCtrl.
15
16 Reads in property style definitions from a config file.
17 Modified styled can be saved (and optionally applied to a given list of STCs)
18
19 It can also maintain a Common definition dictionary of font names, colours and
20 sizes which can be shared across multiple language style definitions.
21 This is also used to store platform spesific settings as fonts and sizes
22 vary with platform.
23
24 The following items are defined in the stc-styles.rc.cfg file.
25
26 common.defs.msw - Common definition dictionary used on wxMSW
27 common.defs.gtk - Common definition dictionary used on wxGTK
28 common.styleidnames - STC styles shared by all languages
29
30 Each supported language defines the following groups:
31 [<language>]
32 displaysrc - Example source to display in the editor
33 braces - Dictionary defining the (line, column) for showing 'good' and 'bad'
34 brace matching (both keys optional)
35 keywords - Space separated list of keywords
36 lexer - wxSTC constant for the language lexer
37 styleidnames - Dictionary of language spesific style numbers and names
38
39 [style.<language>] - The users current style values
40 [style.<language>.default] - Default style values (can be reverted from)
41
42 0 or more predefined style groups or 'themes'
43 [style.<language>.<predefined name>]
44
45 Currently the following languages are supported:
46 python, html, xml, cpp, text, props
47 Other languages can be added by just defining the above settings for them in
48 the config file (if wxSTC implements them).
49
50 Use the initSTC function to initialise your wxSTC from a config file.
51 """
52
53 import os, sys, string, pprint, copy
54
55 from wxPython.wx import *
56 from wxPython.help import *
57 from wxPython.lib.anchors import LayoutAnchors
58 from wxPython.stc import *
59
60 settingsIdNames = {-1: 'Selection', -2: 'Caret', -3: 'Edge'}
61
62 commonPropDefs = {'fore': '#888888', 'size': 8,
63 'face': wxSystemSettings_GetSystemFont(wxSYS_DEFAULT_GUI_FONT).GetFaceName()}
64
65 styleCategoryDescriptions = {
66 '----Language----': 'Styles spesific to the language',
67 '----Standard----': 'Styles shared by all languages',
68 '----Settings----': 'Properties set by STC methods',
69 '----Common----': 'User definable values that can be shared between languages'}
70
71 [wxID_STCSTYLEEDITDLG, wxID_STCSTYLEEDITDLGADDCOMMONITEMBTN,
72 wxID_STCSTYLEEDITDLGBGCOLBTN, wxID_STCSTYLEEDITDLGBGCOLCB,
73 wxID_STCSTYLEEDITDLGBGCOLDEFCB, wxID_STCSTYLEEDITDLGBGCOLOKBTN,
74 wxID_STCSTYLEEDITDLGCANCELBTN, wxID_STCSTYLEEDITDLGCONTEXTHELPBUTTON1,
75 wxID_STCSTYLEEDITDLGELEMENTLB, wxID_STCSTYLEEDITDLGFACECB,
76 wxID_STCSTYLEEDITDLGFACEDEFCB, wxID_STCSTYLEEDITDLGFACEOKBTN,
77 wxID_STCSTYLEEDITDLGFGCOLBTN, wxID_STCSTYLEEDITDLGFGCOLCB,
78 wxID_STCSTYLEEDITDLGFGCOLDEFCB, wxID_STCSTYLEEDITDLGFGCOLOKBTN,
79 wxID_STCSTYLEEDITDLGFIXEDWIDTHCHK, wxID_STCSTYLEEDITDLGOKBTN,
80 wxID_STCSTYLEEDITDLGPANEL1, wxID_STCSTYLEEDITDLGPANEL2,
81 wxID_STCSTYLEEDITDLGPANEL3, wxID_STCSTYLEEDITDLGPANEL4,
82 wxID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN, wxID_STCSTYLEEDITDLGSIZECB,
83 wxID_STCSTYLEEDITDLGSIZEOKBTN, wxID_STCSTYLEEDITDLGSPEEDSETTINGCH,
84 wxID_STCSTYLEEDITDLGSTATICBOX1, wxID_STCSTYLEEDITDLGSTATICBOX2,
85 wxID_STCSTYLEEDITDLGSTATICLINE1, wxID_STCSTYLEEDITDLGSTATICTEXT2,
86 wxID_STCSTYLEEDITDLGSTATICTEXT3, wxID_STCSTYLEEDITDLGSTATICTEXT4,
87 wxID_STCSTYLEEDITDLGSTATICTEXT6, wxID_STCSTYLEEDITDLGSTATICTEXT7,
88 wxID_STCSTYLEEDITDLGSTATICTEXT8, wxID_STCSTYLEEDITDLGSTATICTEXT9,
89 wxID_STCSTYLEEDITDLGSTC, wxID_STCSTYLEEDITDLGSTYLEDEFST,
90 wxID_STCSTYLEEDITDLGTABOLDCB, wxID_STCSTYLEEDITDLGTABOLDDEFCB,
91 wxID_STCSTYLEEDITDLGTAEOLFILLEDCB, wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB,
92 wxID_STCSTYLEEDITDLGTAITALICCB, wxID_STCSTYLEEDITDLGTAITALICDEFCB,
93 wxID_STCSTYLEEDITDLGTASIZEDEFCB, wxID_STCSTYLEEDITDLGTAUNDERLINEDCB,
94 wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB,
95 ] = map(lambda _init_ctrls: wxNewId(), range(47))
96
97 class STCStyleEditDlg(wxDialog):
98 """ Style editor for the wxStyledTextCtrl """
99 _custom_classes = {'wxWindow' : ['wxStyledTextCtrl']}
100 def _init_utils(self):
101 # generated method, don't edit
102 pass
103
104 def _init_ctrls(self, prnt):
105 # generated method, don't edit
106 wxDialog.__init__(self, id=wxID_STCSTYLEEDITDLG, name='STCStyleEditDlg',
107 parent=prnt, pos=wxPoint(583, 291), size=wxSize(459, 482),
108 style=wxWANTS_CHARS | wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER,
109 title=self.stc_title)
110 self._init_utils()
111 self.SetClientSize(wxSize(451, 455))
112 self.SetAutoLayout(True)
113 self.SetSizeHints(425, 400, -1, -1)
114 self.Center(wxBOTH)
115 EVT_SIZE(self, self.OnStcstyleeditdlgSize)
116
117 self.speedsettingCh = wxChoice(choices=[],
118 id=wxID_STCSTYLEEDITDLGSPEEDSETTINGCH, name='speedsettingCh',
119 parent=self, pos=wxPoint(96, 28), size=wxSize(346, 21), style=0,
120 validator=wxDefaultValidator)
121 self.speedsettingCh.SetConstraints(LayoutAnchors(self.speedsettingCh,
122 True, True, True, False))
123 self.speedsettingCh.SetHelpText('The speed setting allows you to revert to one of the predefined style sets. This will overwrite your current settings when tha dialog is posted.')
124 EVT_CHOICE(self.speedsettingCh, wxID_STCSTYLEEDITDLGSPEEDSETTINGCH,
125 self.OnSpeedsettingchChoice)
126
127 self.elementLb = wxListBox(choices=[], id=wxID_STCSTYLEEDITDLGELEMENTLB,
128 name='elementLb', parent=self, pos=wxPoint(8, 72),
129 size=wxSize(160, 112), style=0, validator=wxDefaultValidator)
130 self.elementLb.SetConstraints(LayoutAnchors(self.elementLb, True, True,
131 True, False))
132 self.elementLb.SetHelpText('Select a style here to edit it. Common definitions can be added and maintained here. A common definition is a property that can be shared between styles and special cased per platform.')
133 EVT_LISTBOX(self.elementLb, wxID_STCSTYLEEDITDLGELEMENTLB,
134 self.OnElementlbListbox)
135
136 self.addCommonItemBtn = wxButton(id=wxID_STCSTYLEEDITDLGADDCOMMONITEMBTN,
137 label='Add', name='addCommonItemBtn', parent=self, pos=wxPoint(8,
138 184), size=wxSize(80, 17), style=0)
139 self.addCommonItemBtn.SetToolTipString('Add new Common definition')
140 EVT_BUTTON(self.addCommonItemBtn, wxID_STCSTYLEEDITDLGADDCOMMONITEMBTN,
141 self.OnAddsharebtnButton)
142
143 self.removeCommonItemBtn = wxButton(id=wxID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN,
144 label='Remove', name='removeCommonItemBtn', parent=self,
145 pos=wxPoint(88, 184), size=wxSize(80, 17), style=0)
146 self.removeCommonItemBtn.SetToolTipString('Remove the selected Common definition')
147 EVT_BUTTON(self.removeCommonItemBtn,
148 wxID_STCSTYLEEDITDLGREMOVECOMMONITEMBTN,
149 self.OnRemovesharebtnButton)
150
151 self.styleDefST = wxStaticText(id=wxID_STCSTYLEEDITDLGSTYLEDEFST,
152 label='(nothing selected)', name='styleDefST', parent=self,
153 pos=wxPoint(96, 8), size=wxSize(366, 16),
154 style=wxST_NO_AUTORESIZE)
155 self.styleDefST.SetFont(wxFont(self.style_font_size, wxSWISS, wxNORMAL,
156 wxBOLD, False, ''))
157 self.styleDefST.SetConstraints(LayoutAnchors(self.styleDefST, True,
158 True, True, False))
159
160 self.staticLine1 = wxStaticLine(id=wxID_STCSTYLEEDITDLGSTATICLINE1,
161 name='staticLine1', parent=self, pos=wxPoint(48, 62),
162 size=wxSize(120, 2), style=wxLI_HORIZONTAL)
163 self.staticLine1.SetConstraints(LayoutAnchors(self.staticLine1, True,
164 True, True, False))
165
166 self.staticText6 = wxStaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT6,
167 label='Style', name='staticText6', parent=self, pos=wxPoint(8,
168 56), size=wxSize(40, 13), style=0)
169
170 self.staticText8 = wxStaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT8,
171 label='Style def:', name='staticText8', parent=self,
172 pos=wxPoint(8, 8), size=wxSize(88, 13), style=0)
173
174 self.staticText9 = wxStaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT9,
175 label='SpeedSetting:', name='staticText9', parent=self,
176 pos=wxPoint(8, 32), size=wxSize(88, 13), style=0)
177
178 self.panel3 = wxPanel(id=wxID_STCSTYLEEDITDLGPANEL3, name='panel3',
179 parent=self, pos=wxPoint(176, 56), size=wxSize(146, 104),
180 style=wxTAB_TRAVERSAL)
181 self.panel3.SetConstraints(LayoutAnchors(self.panel3, False, True, True,
182 False))
183
184 self.panel4 = wxPanel(id=wxID_STCSTYLEEDITDLGPANEL4, name='panel4',
185 parent=self, pos=wxPoint(330, 56), size=wxSize(114, 104),
186 style=wxTAB_TRAVERSAL)
187 self.panel4.SetConstraints(LayoutAnchors(self.panel4, False, True, True,
188 False))
189
190 self.panel1 = wxPanel(id=wxID_STCSTYLEEDITDLGPANEL1, name='panel1',
191 parent=self, pos=wxPoint(176, 161), size=wxSize(143, 40),
192 style=wxTAB_TRAVERSAL)
193 self.panel1.SetConstraints(LayoutAnchors(self.panel1, False, True, True,
194 False))
195
196 self.panel2 = wxPanel(id=wxID_STCSTYLEEDITDLGPANEL2, name='panel2',
197 parent=self, pos=wxPoint(330, 162), size=wxSize(112, 40),
198 style=wxTAB_TRAVERSAL)
199 self.panel2.SetConstraints(LayoutAnchors(self.panel2, False, True, True,
200 False))
201
202 self.stc = wxStyledTextCtrl(id=wxID_STCSTYLEEDITDLGSTC, name='stc',
203 parent=self, pos=wxPoint(8, 208), size=wxSize(435, 207),
204 style=wxSUNKEN_BORDER)
205 self.stc.SetConstraints(LayoutAnchors(self.stc, True, True, True, True))
206 self.stc.SetHelpText('The style preview window. Click or move the cursor over a spesific style to select the style for editing in the editors above.')
207 EVT_LEFT_UP(self.stc, self.OnUpdateUI)
208 EVT_KEY_UP(self.stc, self.OnUpdateUI)
209
210 self.contextHelpButton1 = wxContextHelpButton(parent=self,
211 pos=wxPoint(8, 423), size=wxSize(24, 24), style=wxBU_AUTODRAW)
212 self.contextHelpButton1.SetConstraints(LayoutAnchors(self.contextHelpButton1,
213 True, False, False, True))
214
215 self.okBtn = wxButton(id=wxID_STCSTYLEEDITDLGOKBTN, label='OK',
216 name='okBtn', parent=self, pos=wxPoint(282, 423), size=wxSize(75,
217 23), style=0)
218 self.okBtn.SetConstraints(LayoutAnchors(self.okBtn, False, False, True,
219 True))
220 self.okBtn.SetToolTipString('Save changes to the config file')
221 EVT_BUTTON(self.okBtn, wxID_STCSTYLEEDITDLGOKBTN, self.OnOkbtnButton)
222
223 self.cancelBtn = wxButton(id=wxID_STCSTYLEEDITDLGCANCELBTN,
224 label='Cancel', name='cancelBtn', parent=self, pos=wxPoint(366,
225 423), size=wxSize(75, 23), style=0)
226 self.cancelBtn.SetConstraints(LayoutAnchors(self.cancelBtn, False,
227 False, True, True))
228 self.cancelBtn.SetToolTipString('Close dialog without saving changes')
229 EVT_BUTTON(self.cancelBtn, wxID_STCSTYLEEDITDLGCANCELBTN,
230 self.OnCancelbtnButton)
231
232 self.staticText4 = wxStaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT4,
233 label='Face:', name='staticText4', parent=self.panel1,
234 pos=wxPoint(0, 0), size=wxSize(48, 13), style=0)
235
236 self.fixedWidthChk = wxCheckBox(id=wxID_STCSTYLEEDITDLGFIXEDWIDTHCHK,
237 label='', name='fixedWidthChk', parent=self.panel1, pos=wxPoint(0,
238 23), size=wxSize(13, 19), style=0)
239 self.fixedWidthChk.SetToolTipString('Check this for Fixed Width fonts')
240 EVT_CHECKBOX(self.fixedWidthChk, wxID_STCSTYLEEDITDLGFIXEDWIDTHCHK,
241 self.OnFixedwidthchkCheckbox)
242
243 self.faceCb = wxComboBox(choices=[], id=wxID_STCSTYLEEDITDLGFACECB,
244 name='faceCb', parent=self.panel1, pos=wxPoint(17, 18),
245 size=wxSize(105, 21), style=0, validator=wxDefaultValidator,
246 value='')
247
248 self.staticText7 = wxStaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT7,
249 label='Size:', name='staticText7', parent=self.panel2,
250 pos=wxPoint(0, 0), size=wxSize(40, 13), style=0)
251
252 self.sizeCb = wxComboBox(choices=[], id=wxID_STCSTYLEEDITDLGSIZECB,
253 name='sizeCb', parent=self.panel2, pos=wxPoint(0, 17),
254 size=wxSize(91, 21), style=0, validator=wxDefaultValidator,
255 value='')
256
257 self.sizeOkBtn = wxButton(id=wxID_STCSTYLEEDITDLGSIZEOKBTN, label='ok',
258 name='sizeOkBtn', parent=self.panel2, pos=wxPoint(90, 17),
259 size=wxSize(21, 21), style=0)
260
261 self.faceOkBtn = wxButton(id=wxID_STCSTYLEEDITDLGFACEOKBTN, label='ok',
262 name='faceOkBtn', parent=self.panel1, pos=wxPoint(122, 18),
263 size=wxSize(21, 21), style=0)
264
265 self.fgColBtn = wxButton(id=wxID_STCSTYLEEDITDLGFGCOLBTN,
266 label='Foreground', name='fgColBtn', parent=self.panel3,
267 pos=wxPoint(8, 16), size=wxSize(72, 16), style=0)
268 EVT_BUTTON(self.fgColBtn, wxID_STCSTYLEEDITDLGFGCOLBTN,
269 self.OnFgcolbtnButton)
270
271 self.fgColCb = wxComboBox(choices=[], id=wxID_STCSTYLEEDITDLGFGCOLCB,
272 name='fgColCb', parent=self.panel3, pos=wxPoint(8, 32),
273 size=wxSize(89, 21), style=0, validator=wxDefaultValidator,
274 value='')
275
276 self.fgColOkBtn = wxButton(id=wxID_STCSTYLEEDITDLGFGCOLOKBTN,
277 label='ok', name='fgColOkBtn', parent=self.panel3, pos=wxPoint(96,
278 32), size=wxSize(21, 21), style=0)
279
280 self.staticText3 = wxStaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT3,
281 label='default', name='staticText3', parent=self.panel3,
282 pos=wxPoint(100, 16), size=wxSize(37, 16), style=0)
283
284 self.fgColDefCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGFGCOLDEFCB,
285 label='checkBox1', name='fgColDefCb', parent=self.panel3,
286 pos=wxPoint(120, 31), size=wxSize(16, 16), style=0)
287
288 self.bgColBtn = wxButton(id=wxID_STCSTYLEEDITDLGBGCOLBTN,
289 label='Background', name='bgColBtn', parent=self.panel3,
290 pos=wxPoint(8, 56), size=wxSize(72, 16), style=0)
291 EVT_BUTTON(self.bgColBtn, wxID_STCSTYLEEDITDLGBGCOLBTN,
292 self.OnBgcolbtnButton)
293
294 self.bgColCb = wxComboBox(choices=[], id=wxID_STCSTYLEEDITDLGBGCOLCB,
295 name='bgColCb', parent=self.panel3, pos=wxPoint(8, 72),
296 size=wxSize(89, 21), style=0, validator=wxDefaultValidator,
297 value='')
298
299 self.bgColOkBtn = wxButton(id=wxID_STCSTYLEEDITDLGBGCOLOKBTN,
300 label='ok', name='bgColOkBtn', parent=self.panel3, pos=wxPoint(96,
301 72), size=wxSize(21, 21), style=0)
302
303 self.staticBox2 = wxStaticBox(id=wxID_STCSTYLEEDITDLGSTATICBOX2,
304 label='Text attributes', name='staticBox2', parent=self.panel4,
305 pos=wxPoint(0, 0), size=wxSize(112, 99), style=0)
306 self.staticBox2.SetConstraints(LayoutAnchors(self.staticBox2, False,
307 True, True, False))
308 self.staticBox2.SetHelpText('Text attribute flags.')
309
310 self.staticText2 = wxStaticText(id=wxID_STCSTYLEEDITDLGSTATICTEXT2,
311 label='default', name='staticText2', parent=self.panel4,
312 pos=wxPoint(68, 11), size=wxSize(37, 16), style=0)
313
314 self.taBoldDefCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGTABOLDDEFCB,
315 label='checkBox1', name='taBoldDefCb', parent=self.panel4,
316 pos=wxPoint(88, 27), size=wxSize(16, 16), style=0)
317
318 self.taItalicDefCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGTAITALICDEFCB,
319 label='checkBox1', name='taItalicDefCb', parent=self.panel4,
320 pos=wxPoint(88, 43), size=wxSize(16, 16), style=0)
321
322 self.taUnderlinedDefCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB,
323 label='checkBox1', name='taUnderlinedDefCb', parent=self.panel4,
324 pos=wxPoint(88, 59), size=wxSize(16, 16), style=0)
325
326 self.taEOLfilledDefCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB,
327 label='checkBox1', name='taEOLfilledDefCb', parent=self.panel4,
328 pos=wxPoint(88, 75), size=wxSize(16, 16), style=0)
329
330 self.taEOLfilledCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGTAEOLFILLEDCB,
331 label='EOL filled', name='taEOLfilledCb', parent=self.panel4,
332 pos=wxPoint(8, 75), size=wxSize(72, 16), style=0)
333 EVT_CHECKBOX(self.taEOLfilledCb, wxID_STCSTYLEEDITDLGTAEOLFILLEDCB,
334 self.OnTaeoffilledcbCheckbox)
335
336 self.taUnderlinedCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGTAUNDERLINEDCB,
337 label='Underlined', name='taUnderlinedCb', parent=self.panel4,
338 pos=wxPoint(8, 59), size=wxSize(72, 16), style=0)
339 EVT_CHECKBOX(self.taUnderlinedCb, wxID_STCSTYLEEDITDLGTAUNDERLINEDCB,
340 self.OnTaunderlinedcbCheckbox)
341
342 self.taItalicCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGTAITALICCB,
343 label='Italic', name='taItalicCb', parent=self.panel4,
344 pos=wxPoint(8, 43), size=wxSize(72, 16), style=0)
345 EVT_CHECKBOX(self.taItalicCb, wxID_STCSTYLEEDITDLGTAITALICCB,
346 self.OnTaitaliccbCheckbox)
347
348 self.taBoldCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGTABOLDCB,
349 label='Bold', name='taBoldCb', parent=self.panel4, pos=wxPoint(8,
350 27), size=wxSize(72, 16), style=0)
351 EVT_CHECKBOX(self.taBoldCb, wxID_STCSTYLEEDITDLGTABOLDCB,
352 self.OnTaboldcbCheckbox)
353
354 self.bgColDefCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGBGCOLDEFCB,
355 label='checkBox1', name='bgColDefCb', parent=self.panel3,
356 pos=wxPoint(120, 71), size=wxSize(16, 16), style=0)
357
358 self.staticBox1 = wxStaticBox(id=wxID_STCSTYLEEDITDLGSTATICBOX1,
359 label='Colour', name='staticBox1', parent=self.panel3,
360 pos=wxPoint(0, 0), size=wxSize(142, 99), style=0)
361 self.staticBox1.SetConstraints(LayoutAnchors(self.staticBox1, False,
362 True, True, False))
363
364 self.faceDefCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGFACEDEFCB,
365 label='checkBox1', name='faceDefCb', parent=self.panel1,
366 pos=wxPoint(120, 0), size=wxSize(16, 16), style=0)
367
368 self.taSizeDefCb = wxCheckBox(id=wxID_STCSTYLEEDITDLGTASIZEDEFCB,
369 label='checkBox1', name='taSizeDefCb', parent=self.panel2,
370 pos=wxPoint(88, 0), size=wxSize(16, 16), style=0)
371
372 def __init__(self, parent, langTitle, lang, configFile, STCsToUpdate=()):
373 self.stc_title = 'wxStyledTextCtrl Style Editor'
374 self.stc_title = 'wxStyledTextCtrl Style Editor - %s' % langTitle
375 if wxPlatform == '__WXMSW__':
376 self.style_font_size = 8
377 else:
378 self.style_font_size = 10
379 self._init_ctrls(parent)
380 self.lang = lang
381 self.configFile = configFile
382 self.style = ''
383 self.styleNum = 0
384 self.names = []
385 self.values = {}
386 self.STCsToUpdate = STCsToUpdate
387 self._blockUpdate = False
388
389
390 for combo, okBtn, evtRet, evtCB, evtRDC in (
391 (self.fgColCb, self.fgColOkBtn, self.OnfgColRet, self.OnfgColCombobox, self.OnGotoCommonDef),
392 (self.bgColCb, self.bgColOkBtn, self.OnbgColRet, self.OnbgColCombobox, self.OnGotoCommonDef),
393 (self.faceCb, self.faceOkBtn, self.OnfaceRet, self.OnfaceCombobox, self.OnGotoCommonDef),
394 (self.sizeCb, self.sizeOkBtn, self.OnsizeRet, self.OnsizeCombobox, self.OnGotoCommonDef)):
395 self.bindComboEvts(combo, okBtn, evtRet, evtCB, evtRDC)
396
397 (self.config, self.commonDefs, self.styleIdNames, self.styles,
398 self.styleGroupNames, self.predefStyleGroups,
399 self.otherLangStyleGroupNames, self.otherLangStyleGroups,
400 self.displaySrc, self.lexer, self.keywords, self.braceInfo) = \
401 initFromConfig(configFile, lang)
402
403 self.currSpeedSetting = 'style.%s'%self.lang
404 for grp in [self.currSpeedSetting]+self.styleGroupNames:
405 self.speedsettingCh.Append(grp)
406 self.speedsettingCh.SetSelection(0)
407
408 margin = 0
409 self.stc.SetMarginType(margin, wxSTC_MARGIN_NUMBER)
410 self.stc.SetMarginWidth(margin, 25)
411 self.stc.SetMarginSensitive(margin, True)
412 EVT_STC_MARGINCLICK(self.stc, wxID_STCSTYLEEDITDLGSTC, self.OnMarginClick)
413
414 self.stc.SetUseTabs(False)
415 self.stc.SetTabWidth(4)
416 self.stc.SetIndentationGuides(True)
417 self.stc.SetEdgeMode(wxSTC_EDGE_BACKGROUND)
418 self.stc.SetEdgeColumn(44)
419
420 self.setStyles()
421
422 self.populateStyleSelector()
423
424 self.defNames, self.defValues = parseProp(\
425 self.styleDict.get(wxSTC_STYLE_DEFAULT, ''))
426 self.stc.SetText(self.displaySrc)
427 self.stc.EmptyUndoBuffer()
428 self.stc.SetCurrentPos(self.stc.GetTextLength())
429 self.stc.SetAnchor(self.stc.GetTextLength())
430
431 self.populateCombosWithCommonDefs()
432
433 # Logical grouping of controls and the property they edit
434 self.allCtrls = [((self.fgColBtn, self.fgColCb, self.fgColOkBtn), self.fgColDefCb,
435 'fore', wxID_STCSTYLEEDITDLGFGCOLDEFCB),
436 ((self.bgColBtn, self.bgColCb, self.bgColOkBtn), self.bgColDefCb,
437 'back', wxID_STCSTYLEEDITDLGBGCOLDEFCB),
438 (self.taBoldCb, self.taBoldDefCb,
439 'bold', wxID_STCSTYLEEDITDLGTABOLDDEFCB),
440 (self.taItalicCb, self.taItalicDefCb,
441 'italic', wxID_STCSTYLEEDITDLGTAITALICDEFCB),
442 (self.taUnderlinedCb, self.taUnderlinedDefCb,
443 'underline', wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB),
444 (self.taEOLfilledCb, self.taEOLfilledDefCb,
445 'eolfilled', wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB),
446 ((self.sizeCb, self.sizeOkBtn), self.taSizeDefCb,
447 'size', wxID_STCSTYLEEDITDLGTASIZEDEFCB),
448 ((self.faceCb, self.faceOkBtn, self.fixedWidthChk), self.faceDefCb,
449 'face', wxID_STCSTYLEEDITDLGFACEDEFCB)]
450
451 self.clearCtrls(disableDefs=True)
452 # centralised default checkbox event handler
453 self.chbIdMap = {}
454 for ctrl, chb, prop, wid in self.allCtrls:
455 self.chbIdMap[wid] = ctrl, chb, prop, wid
456 EVT_CHECKBOX(chb, wid, self.OnDefaultCheckBox)
457 chb.SetToolTipString('Toggle defaults')
458
459 self.Center(wxBOTH)
460
461 #---Property methods------------------------------------------------------------
462 def getCtrlForProp(self, findprop):
463 for ctrl, chb, prop, wid in self.allCtrls:
464 if findprop == prop:
465 return ctrl, chb
466 raise Exception('PropNotFound', findprop)
467
468 def editProp(self, on, prop, val=''):
469 oldstyle = self.rememberStyles()
470 if on:
471 if not self.names.count(prop):
472 self.names.append(prop)
473 self.values[prop] = val
474 else:
475 try: self.names.remove(prop)
476 except ValueError: pass
477 try: del self.values[prop]
478 except KeyError: pass
479
480 try:
481 self.updateStyle()
482 return True
483 except KeyError, errkey:
484 wxLogError('Name not found in Common definition, '\
485 'please enter valid reference. (%s)'%errkey)
486 self.restoreStyles(oldstyle)
487 return False
488
489 #---Control population methods--------------------------------------------------
490 def setStyles(self):
491 if self._blockUpdate: return
492 self.styles, self.styleDict, self.styleNumIdxMap = \
493 setSTCStyles(self.stc, self.styles, self.styleIdNames,
494 self.commonDefs, self.lang, self.lexer, self.keywords)
495
496 def updateStyle(self):
497 # called after a control edited self.names, self.values
498 # Special case for saving common defs settings
499 if self.styleNum == 'common':
500 strVal = self.style[2] = self.values.values()[0]
501 if self.style[1] == 'size': self.style[2] = int(strVal)
502
503 self.commonDefs[self.style[0]] = self.style[2]
504 self.styleDefST.SetLabel(strVal)
505 else:
506 self.style = writePropVal(self.names, self.values)
507 styleDecl = writeProp(self.styleNum, self.style, self.lang)
508 self.styles[self.styleNumIdxMap[self.styleNum]] = styleDecl
509 self.styleDefST.SetLabel(self.style)
510 self.setStyles()
511
512 def findInStyles(self, txt, styles):
513 for style in styles:
514 if string.find(style, txt) != -1:
515 return True
516 return False
517
518 def rememberStyles(self):
519 return self.names[:], copy.copy(self.values)
520
521 def restoreStyles(self, style):
522 self.names, self.values = style
523 self.updateStyle()
524
525 def clearCtrls(self, isDefault=False, disableDefs=False):
526 self._blockUpdate = True
527 try:
528 for ctrl, chb, prop, wid in self.allCtrls:
529 if prop in ('fore', 'back'):
530 cbtn, txt, btn = ctrl
531 cbtn.SetBackgroundColour(\
532 wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNFACE))
533 cbtn.SetForegroundColour(wxColour(255, 255, 255))
534 cbtn.Enable(isDefault)
535 txt.SetValue('')
536 txt.Enable(isDefault)
537 btn.Enable(isDefault)
538 elif prop == 'size':
539 cmb, btn = ctrl
540 cmb.SetValue('')
541 cmb.Enable(isDefault)
542 btn.Enable(isDefault)
543 elif prop == 'face':
544 cmb, btn, chk = ctrl
545 cmb.SetValue('')
546 cmb.Enable(isDefault)
547 btn.Enable(isDefault)
548 chk.Enable(isDefault)
549 chk.SetValue(False)
550 elif prop in ('bold', 'italic', 'underline', 'eolfilled'):
551 ctrl.SetValue(False)
552 ctrl.Enable(isDefault)
553
554 chb.Enable(not isDefault and not disableDefs)
555 chb.SetValue(True)
556 finally:
557 self._blockUpdate = False
558
559 def populateProp(self, items, default, forceDisable=False):
560 self._blockUpdate = True
561 try:
562 for name, val in items:
563 if name:
564 ctrl, chb = self.getCtrlForProp(name)
565
566 if name in ('fore', 'back'):
567 cbtn, txt, btn = ctrl
568 repval = val%self.commonDefs
569 cbtn.SetBackgroundColour(strToCol(repval))
570 cbtn.SetForegroundColour(wxColour(0, 0, 0))
571 cbtn.Enable(not forceDisable)
572 txt.SetValue(val)
573 txt.Enable(not forceDisable)
574 btn.Enable(not forceDisable)
575 chb.SetValue(default)
576 elif name == 'size':
577 cmb, btn = ctrl
578 cmb.SetValue(val)
579 cmb.Enable(not forceDisable)
580 btn.Enable(not forceDisable)
581 chb.SetValue(default)
582 elif name == 'face':
583 cmb, btn, chk = ctrl
584 cmb.SetValue(val)
585 cmb.Enable(not forceDisable)
586 btn.Enable(not forceDisable)
587 chk.Enable(not forceDisable)
588 chb.SetValue(default)
589 elif name in ('bold', 'italic', 'underline', 'eolfilled'):
590 ctrl.Enable(not forceDisable)
591 ctrl.SetValue(True)
592 chb.SetValue(default)
593 finally:
594 self._blockUpdate = False
595
596 def valIsCommonDef(self, val):
597 return len(val) >= 5 and val[:2] == '%('
598
599 def populateCtrls(self):
600 self.clearCtrls(self.styleNum == wxSTC_STYLE_DEFAULT,
601 disableDefs=self.styleNum < 0)
602
603 # handle colour controls for settings
604 if self.styleNum < 0:
605 self.fgColDefCb.Enable(True)
606 if self.styleNum == -1:
607 self.bgColDefCb.Enable(True)
608
609 # populate with default style
610 self.populateProp(self.defValues.items(), True,
611 self.styleNum != wxSTC_STYLE_DEFAULT)
612 # override with current settings
613 self.populateProp(self.values.items(), False)
614
615 def getCommonDefPropType(self, commonDefName):
616 val = self.commonDefs[commonDefName]
617 if type(val) == type(0): return 'size'
618 if len(val) == 7 and val[0] == '#': return 'fore'
619 return 'face'
620
621 def bindComboEvts(self, combo, btn, btnEvtMeth, comboEvtMeth, rdclickEvtMeth):
622 EVT_COMBOBOX(combo, combo.GetId(), comboEvtMeth)
623 EVT_BUTTON(btn, btn.GetId(), btnEvtMeth)
624 EVT_RIGHT_DCLICK(combo, rdclickEvtMeth)
625 combo.SetToolTipString('Select from list or click "ok" button on the right to change a manual entry, right double-click \n'\
626 'the drop down button to select Common definition in the Style Editor (if applicable)')
627 btn.SetToolTipString('Accept value')
628
629 def populateCombosWithCommonDefs(self, fixedWidthOnly=None):
630 self._blockUpdate = True
631 try:
632 commonDefs = {'fore': [], 'face': [], 'size': []}
633
634 if self.elementLb.GetSelection() < self.commonDefsStartIdx:
635 for common in self.commonDefs.keys():
636 prop = self.getCommonDefPropType(common)
637 commonDefs[prop].append('%%(%s)%s'%(common,
638 prop=='size' and 'd' or 's'))
639
640 # Colours
641 currFg, currBg = self.fgColCb.GetValue(), self.bgColCb.GetValue()
642 self.fgColCb.Clear(); self.bgColCb.Clear()
643 for colCommonDef in commonDefs['fore']:
644 self.fgColCb.Append(colCommonDef)
645 self.bgColCb.Append(colCommonDef)
646 self.fgColCb.SetValue(currFg); self.bgColCb.SetValue(currBg)
647
648 # Font
649 if fixedWidthOnly is None:
650 fixedWidthOnly = self.fixedWidthChk.GetValue()
651 fontEnum = wxFontEnumerator()
652 fontEnum.EnumerateFacenames(fixedWidthOnly=fixedWidthOnly)
653 fontNameList = fontEnum.GetFacenames()
654
655 currFace = self.faceCb.GetValue()
656 self.faceCb.Clear()
657 for colCommonDef in ['']+fontNameList+commonDefs['face']:
658 self.faceCb.Append(colCommonDef)
659 self.faceCb.SetValue(currFace)
660
661 # Size (XXX add std font sizes)
662 currSize = self.sizeCb.GetValue()
663 self.sizeCb.Clear()
664 for colCommonDef in commonDefs['size']:
665 self.sizeCb.Append(colCommonDef)
666 self.sizeCb.SetValue(currSize)
667 finally:
668 self._blockUpdate = False
669
670 def populateStyleSelector(self):
671 numStyles = self.styleIdNames.items()
672 numStyles.sort()
673 self.styleNumLookup = {}
674 stdStart = -1
675 stdOffset = 0
676 extrOffset = 0
677 # add styles
678 for num, name in numStyles:
679 if num == wxSTC_STYLE_DEFAULT:
680 self.elementLb.InsertItems([name, '----Language----'], 0)
681 self.elementLb.Append('----Standard----')
682 stdStart = stdPos = self.elementLb.GetCount()
683 else:
684 # std styles
685 if num >= 33 and num < 40:
686 self.elementLb.InsertItems([name], stdStart + stdOffset)
687 stdOffset = stdOffset + 1
688 # extra styles
689 elif num >= 40:
690 self.elementLb.InsertItems([name], stdStart + extrOffset -1)
691 extrOffset = extrOffset + 1
692 # normal lang styles
693 else:
694 self.elementLb.Append(name)
695 self.styleNumLookup[name] = num
696
697 # add settings
698 self.elementLb.Append('----Settings----')
699 settings = settingsIdNames.items()
700 settings.sort();settings.reverse()
701 for num, name in settings:
702 self.elementLb.Append(name)
703 self.styleNumLookup[name] = num
704
705 # add definitions
706 self.elementLb.Append('----Common----')
707 self.commonDefsStartIdx = self.elementLb.GetCount()
708 for common in self.commonDefs.keys():
709 tpe = type(self.commonDefs[common])
710 self.elementLb.Append('%('+common+')'+(tpe is type('') and 's' or 'd'))
711 self.styleNumLookup[common] = num
712
713 #---Colour methods--------------------------------------------------------------
714 def getColourDlg(self, colour, title=''):
715 data = wxColourData()
716 data.SetColour(colour)
717 data.SetChooseFull(True)
718 dlg = wxColourDialog(self, data)
719 try:
720 dlg.SetTitle(title)
721 if dlg.ShowModal() == wxID_OK:
722 data = dlg.GetColourData()
723 return data.GetColour()
724 finally:
725 dlg.Destroy()
726 return None
727
728 colDlgTitles = {'fore': 'Foreground', 'back': 'Background'}
729 def editColProp(self, colBtn, colCb, prop):
730 col = self.getColourDlg(colBtn.GetBackgroundColour(),
731 self.colDlgTitles[prop]+ ' colour')
732 if col:
733 colBtn.SetForegroundColour(wxColour(0, 0, 0))
734 colBtn.SetBackgroundColour(col)
735 colStr = colToStr(col)
736 colCb.SetValue(colStr)
737 self.editProp(True, prop, colStr)
738
739 def OnFgcolbtnButton(self, event):
740 self.editColProp(self.fgColBtn, self.fgColCb, 'fore')
741
742 def OnBgcolbtnButton(self, event):
743 self.editColProp(self.bgColBtn, self.bgColCb, 'back')
744
745 def editColTCProp(self, colCb, colBtn, prop, val=None):
746 if val is None:
747 colStr = colCb.GetValue()
748 else:
749 colStr = val
750 if colStr:
751 col = strToCol(colStr%self.commonDefs)
752 if self.editProp(colStr!='', prop, colStr):
753 if colStr:
754 colBtn.SetForegroundColour(wxColour(0, 0, 0))
755 colBtn.SetBackgroundColour(col)
756 else:
757 colBtn.SetForegroundColour(wxColour(255, 255, 255))
758 colBtn.SetBackgroundColour(\
759 wxSystemSettings_GetSystemColour(wxSYS_COLOUR_BTNFACE))
760
761 def OnfgColRet(self, event):
762 try: self.editColTCProp(self.fgColCb, self.fgColBtn, 'fore')
763 except AssertionError: wxLogError('Not a valid colour value')
764
765 def OnfgColCombobox(self, event):
766 if self._blockUpdate: return
767 try: self.editColTCProp(self.fgColCb, self.fgColBtn, 'fore', event.GetString())
768 except AssertionError: wxLogError('Not a valid colour value')
769
770 def OnbgColRet(self, event):
771 try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back')
772 except AssertionError: wxLogError('Not a valid colour value')
773
774 def OnbgColCombobox(self, event):
775 if self._blockUpdate: return
776 try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back', event.GetString())
777 except AssertionError: wxLogError('Not a valid colour value')
778
779 #---Text attribute events-------------------------------------------------------
780 def OnTaeoffilledcbCheckbox(self, event):
781 self.editProp(event.IsChecked(), 'eolfilled')
782
783 def OnTaitaliccbCheckbox(self, event):
784 self.editProp(event.IsChecked(), 'italic')
785
786 def OnTaboldcbCheckbox(self, event):
787 self.editProp(event.IsChecked(), 'bold')
788
789 def OnTaunderlinedcbCheckbox(self, event):
790 self.editProp(event.IsChecked(), 'underline')
791
792 def OnGotoCommonDef(self, event):
793 val = event.GetEventObject().GetValue()
794 if self.valIsCommonDef(val):
795 idx = self.elementLb.FindString(val)
796 if idx != -1:
797 self.elementLb.SetSelection(idx, True)
798 self.OnElementlbListbox(None)
799
800 def OnfaceRet(self, event):
801 self.setFace(self.faceCb.GetValue())
802
803 def OnfaceCombobox(self, event):
804 if self._blockUpdate: return
805 self.setFace(event.GetString())
806
807 def setFace(self, val):
808 try: val%self.commonDefs
809 except KeyError: wxLogError('Invalid common definition')
810 else: self.editProp(val!='', 'face', val)
811
812 def OnsizeRet(self, event):
813 self.setSize(self.sizeCb.GetValue())
814
815 def OnsizeCombobox(self, event):
816 if self._blockUpdate: return
817 self.setSize(event.GetString())
818
819 def setSize(self, val):
820 try: int(val%self.commonDefs)
821 except ValueError: wxLogError('Not a valid integer size value')
822 except KeyError: wxLogError('Invalid common definition')
823 else: self.editProp(val!='', 'size', val)
824
825 #---Main GUI events-------------------------------------------------------------
826 def OnElementlbListbox(self, event):
827 isCommon = self.elementLb.GetSelection() >= self.commonDefsStartIdx
828 self.removeCommonItemBtn.Enable(isCommon)
829
830 styleIdent = self.elementLb.GetStringSelection()
831 # common definition selected
832 if isCommon:
833 common = styleIdent[2:-2]
834 prop = self.getCommonDefPropType(common)
835 self.clearCtrls(disableDefs=True)
836 if prop == 'fore':
837 self.fgColBtn.Enable(True)
838 self.fgColCb.Enable(True)
839 self.fgColOkBtn.Enable(True)
840 elif prop == 'face':
841 self.faceCb.Enable(True)
842 self.fixedWidthChk.Enable(True)
843 self.faceOkBtn.Enable(True)
844 elif prop == 'size':
845 self.sizeCb.Enable(True)
846 self.sizeOkBtn.Enable(True)
847
848 commonDefVal = str(self.commonDefs[common])
849 self.styleDefST.SetLabel(commonDefVal)
850 self.populateProp( [(prop, commonDefVal)], True)
851
852 self.styleNum = 'common'
853 self.style = [common, prop, commonDefVal]
854 self.names, self.values = [prop], {prop: commonDefVal}
855
856 # normal style element selected
857 elif len(styleIdent) >=2 and styleIdent[:2] != '--':
858 self.styleNum = self.styleNumLookup[styleIdent]
859 self.style = self.styleDict[self.styleNum]
860 self.names, self.values = parseProp(self.style)
861 if self.styleNum == wxSTC_STYLE_DEFAULT:
862 self.defNames, self.defValues = \
863 self.names, self.values
864
865 self.checkBraces(self.styleNum)
866
867 self.styleDefST.SetLabel(self.style)
868
869 self.populateCtrls()
870 # separator selected
871 else:
872 self.clearCtrls(disableDefs=True)
873 if styleIdent:
874 self.styleDefST.SetLabel(styleCategoryDescriptions[styleIdent])
875
876 self.populateCombosWithCommonDefs()
877
878 def OnDefaultCheckBox(self, event):
879 if self.chbIdMap.has_key(event.GetId()):
880 ctrl, chb, prop, wid = self.chbIdMap[event.GetId()]
881 restore = not event.IsChecked()
882 if prop in ('fore', 'back'):
883 cbtn, cmb, btn = ctrl
884 cbtn.Enable(restore)
885 cmb.Enable(restore)
886 btn.Enable(restore)
887 if restore:
888 colStr = cmb.GetValue()
889 #if prop == 'fore': colStr = self.fgColCb.GetValue()
890 #else: colStr = self.bgColCb.GetValue()
891 if colStr: self.editProp(True, prop, colStr)
892 else:
893 self.editProp(False, prop)
894 elif prop == 'size':
895 cmb, btn = ctrl
896 val = cmb.GetValue()
897 if val: self.editProp(restore, prop, val)
898 cmb.Enable(restore)
899 btn.Enable(restore)
900 elif prop == 'face':
901 cmb, btn, chk = ctrl
902 val = cmb.GetStringSelection()
903 if val: self.editProp(restore, prop, val)
904 cmb.Enable(restore)
905 btn.Enable(restore)
906 chk.Enable(restore)
907 elif prop in ('bold', 'italic', 'underline', 'eolfilled'):
908 ctrl.Enable(restore)
909 if ctrl.GetValue(): self.editProp(restore, prop)
910
911 def OnOkbtnButton(self, event):
912 # write styles and common defs to the config
913 wxBeginBusyCursor()
914 try:
915 writeStylesToConfig(self.config, 'style.%s'%self.lang, self.styles)
916 self.config.SetPath('')
917 self.config.Write(commonDefsFile, `self.commonDefs`)
918 self.config.Flush()
919
920 for stc in self.STCsToUpdate:
921 setSTCStyles(stc, self.styles, self.styleIdNames, self.commonDefs,
922 self.lang, self.lexer, self.keywords)
923 finally:
924 wxEndBusyCursor()
925 self.EndModal(wxID_OK)
926
927 def OnCancelbtnButton(self, event):
928 self.EndModal(wxID_CANCEL)
929
930 def OnCommondefsbtnButton(self, event):
931 dlg = wxTextEntryDialog(self, 'Edit common definitions dictionary',
932 'Common definitions', pprint.pformat(self.commonDefs),
933 style=wxTE_MULTILINE | wxOK | wxCANCEL | wxCENTRE)
934 try:
935 if dlg.ShowModal() == wxID_OK:
936 answer = eval(dlg.GetValue())
937 assert type(answer) is type({}), 'Not a valid dictionary'
938 oldDefs = self.commonDefs
939 self.commonDefs = answer
940 try:
941 self.setStyles()
942 except KeyError, badkey:
943 wxLogError(str(badkey)+' not defined but required, \n'\
944 'reverting to previous common definition')
945 self.commonDefs = oldDefs
946 self.setStyles()
947 self.populateCombosWithCommonDefs()
948
949 finally:
950 dlg.Destroy()
951
952 def OnSpeedsettingchChoice(self, event):
953 group = event.GetString()
954 if group:
955 userStyles = 'style.%s'%self.lang
956 if self.currSpeedSetting == userStyles:
957 self.predefStyleGroups[userStyles] = self.styles
958 self.styles = self.predefStyleGroups[group]
959 self.setStyles()
960 self.defNames, self.defValues = parseProp(\
961 self.styleDict.get(wxSTC_STYLE_DEFAULT, ''))
962 self.OnElementlbListbox(None)
963 self.currSpeedSetting = group
964
965 def OnFixedwidthchkCheckbox(self, event):
966 self.populateCombosWithCommonDefs(event.Checked())
967
968 def OnAddsharebtnButton(self, event):
969 dlg = CommonDefDlg(self)
970 try:
971 if dlg.ShowModal() == wxID_OK:
972 prop, name = dlg.result
973 if not self.commonDefs.has_key(name):
974 self.commonDefs[name] = commonPropDefs[prop]
975 self.elementLb.Append('%('+name+')'+\
976 (type(commonPropDefs[prop]) is type('') and 's' or 'd'))
977 self.elementLb.SetSelection(self.elementLb.GetCount()-1, True)
978 self.populateCombosWithCommonDefs()
979 self.OnElementlbListbox(None)
980 finally:
981 dlg.Destroy()
982
983 def OnRemovesharebtnButton(self, event):
984 ownGroup = 'style.%s'%self.lang
985 comDef = self.elementLb.GetStringSelection()
986
987 # Search ALL styles before removing
988 srchDct = {ownGroup: self.styles}
989 srchDct.update(self.predefStyleGroups)
990 srchDct.update(self.otherLangStyleGroups)
991
992 matchList = []
993 for grpName, styles in srchDct.items():
994 if self.findInStyles(comDef, styles):
995 matchList.append(grpName)
996
997 if matchList:
998 wxLogError('Aborted: '+comDef+' is still used in the styles of the \n'\
999 'following groups in the config file (stc-styles.rc.cfg):\n'+ \
1000 string.join(matchList, '\n'))
1001 else:
1002 del self.commonDefs[comDef[2:-2]]
1003 self.setStyles()
1004 self.populateCombosWithCommonDefs()
1005 selIdx = self.elementLb.GetSelection()
1006 self.elementLb.Delete(selIdx)
1007 if selIdx == self.elementLb.GetCount():
1008 selIdx = selIdx - 1
1009 self.elementLb.SetSelection(selIdx, True)
1010 self.OnElementlbListbox(None)
1011
1012 #---STC events------------------------------------------------------------------
1013 def OnUpdateUI(self, event):
1014 styleBefore = self.stc.GetStyleAt(self.stc.GetCurrentPos())
1015 if self.styleIdNames.has_key(styleBefore):
1016 self.elementLb.SetStringSelection(self.styleIdNames[styleBefore],
1017 True)
1018 else:
1019 self.elementLb.SetSelection(0, False)
1020 self.styleDefST.SetLabel('Style %d not defined, sorry.'%styleBefore)
1021 self.OnElementlbListbox(None)
1022 event.Skip()
1023
1024 def checkBraces(self, style):
1025 if style == wxSTC_STYLE_BRACELIGHT and self.braceInfo.has_key('good'):
1026 line, col = self.braceInfo['good']
1027 pos = self.stc.PositionFromLine(line-1) + col
1028 braceOpposite = self.stc.BraceMatch(pos)
1029 if braceOpposite != -1:
1030 self.stc.BraceHighlight(pos, braceOpposite)
1031 elif style == wxSTC_STYLE_BRACEBAD and self.braceInfo.has_key('bad'):
1032 line, col = self.braceInfo['bad']
1033 pos = self.stc.PositionFromLine(line-1) + col
1034 self.stc.BraceBadLight(pos)
1035 else:
1036 self.stc.BraceBadLight(-1)
1037 return
1038
1039 def OnStcstyleeditdlgSize(self, event):
1040 self.Layout()
1041 # Without this refresh, resizing leaves artifacts
1042 self.Refresh(1)
1043 event.Skip()
1044
1045 def OnMarginClick(self, event):
1046 self.elementLb.SetStringSelection('Line numbers', True)
1047 self.OnElementlbListbox(None)
1048
1049
1050 #---Common definition dialog----------------------------------------------------
1051
1052 [wxID_COMMONDEFDLG, wxID_COMMONDEFDLGCANCELBTN, wxID_COMMONDEFDLGCOMDEFNAMETC, wxID_COMMONDEFDLGOKBTN, wxID_COMMONDEFDLGPROPTYPERBX, wxID_COMMONDEFDLGSTATICBOX1] = map(lambda _init_ctrls: wxNewId(), range(6))
1053
1054 class CommonDefDlg(wxDialog):
1055 def _init_ctrls(self, prnt):
1056 wxDialog.__init__(self, id = wxID_COMMONDEFDLG, name = 'CommonDefDlg', parent = prnt, pos = wxPoint(398, 249), size = wxSize(192, 220), style = wxDEFAULT_DIALOG_STYLE, title = 'Common definition')
1057 self.SetClientSize(wxSize(184, 200))
1058
1059 self.propTypeRBx = wxRadioBox(choices = ['Colour value', 'Font face', 'Size value'], id = wxID_COMMONDEFDLGPROPTYPERBX, label = 'Property type', majorDimension = 1, name = 'propTypeRBx', parent = self, point = wxPoint(8, 8), size = wxSize(168, 92), style = wxRA_SPECIFY_COLS, validator = wxDefaultValidator)
1060 self.propTypeRBx.SetSelection(self._propTypeIdx)
1061
1062 self.staticBox1 = wxStaticBox(id = wxID_COMMONDEFDLGSTATICBOX1, label = 'Name', name = 'staticBox1', parent = self, pos = wxPoint(8, 108), size = wxSize(168, 46), style = 0)
1063
1064 self.comDefNameTC = wxTextCtrl(id = wxID_COMMONDEFDLGCOMDEFNAMETC, name = 'comDefNameTC', parent = self, pos = wxPoint(16, 124), size = wxSize(152, 21), style = 0, value = '')
1065 self.comDefNameTC.SetLabel(self._comDefName)
1066
1067 self.okBtn = wxButton(id = wxID_COMMONDEFDLGOKBTN, label = 'OK', name = 'okBtn', parent = self, pos = wxPoint(8, 164), size = wxSize(80, 23), style = 0)
1068 EVT_BUTTON(self.okBtn, wxID_COMMONDEFDLGOKBTN, self.OnOkbtnButton)
1069
1070 self.cancelBtn = wxButton(id = wxID_COMMONDEFDLGCANCELBTN, label = 'Cancel', name = 'cancelBtn', parent = self, pos = wxPoint(96, 164), size = wxSize(80, 23), style = 0)
1071 EVT_BUTTON(self.cancelBtn, wxID_COMMONDEFDLGCANCELBTN, self.OnCancelbtnButton)
1072
1073 def __init__(self, parent, name='', propIdx=0):
1074 self._comDefName = ''
1075 self._comDefName = name
1076 self._propTypeIdx = 0
1077 self._propTypeIdx = propIdx
1078 self._init_ctrls(parent)
1079
1080 self.propMap = {0: 'fore', 1: 'face', 2: 'size'}
1081 self.result = ( '', '' )
1082
1083 self.Center(wxBOTH)
1084
1085 def OnOkbtnButton(self, event):
1086 self.result = ( self.propMap[self.propTypeRBx.GetSelection()],
1087 self.comDefNameTC.GetValue() )
1088 self.EndModal(wxID_OK)
1089
1090 def OnCancelbtnButton(self, event):
1091 self.result = ( '', '' )
1092 self.EndModal(wxID_CANCEL)
1093
1094 #---Functions useful outside of the editor----------------------------------
1095
1096 def setSelectionColour(stc, style):
1097 names, values = parseProp(style)
1098 if 'fore' in names:
1099 stc.SetSelForeground(True, strToCol(values['fore']))
1100 if 'back' in names:
1101 stc.SetSelBackground(True, strToCol(values['back']))
1102
1103 def setCursorColour(stc, style):
1104 names, values = parseProp(style)
1105 if 'fore' in names:
1106 stc.SetCaretForeground(strToCol(values['fore']))
1107
1108 def setEdgeColour(stc, style):
1109 names, values = parseProp(style)
1110 if 'fore' in names:
1111 stc.SetEdgeColour(strToCol(values['fore']))
1112
1113 def strToCol(strCol):
1114 assert len(strCol) == 7 and strCol[0] == '#', 'Not a valid colour string'
1115 return wxColour(string.atoi('0x'+strCol[1:3], 16),
1116 string.atoi('0x'+strCol[3:5], 16),
1117 string.atoi('0x'+strCol[5:7], 16))
1118 def colToStr(col):
1119 return '#%s%s%s' % (string.zfill(string.upper(hex(col.Red())[2:]), 2),
1120 string.zfill(string.upper(hex(col.Green())[2:]), 2),
1121 string.zfill(string.upper(hex(col.Blue())[2:]), 2))
1122
1123 def writeProp(num, style, lang):
1124 if num >= 0:
1125 return 'style.%s.%s='%(lang, string.zfill(`num`, 3)) + style
1126 else:
1127 return 'setting.%s.%d='%(lang, num) + style
1128
1129 def writePropVal(names, values):
1130 res = []
1131 for name in names:
1132 if name:
1133 res.append(values[name] and name+':'+values[name] or name)
1134 return string.join(res, ',')
1135
1136 def parseProp(prop):
1137 items = string.split(prop, ',')
1138 names = []
1139 values = {}
1140 for item in items:
1141 nameVal = string.split(item, ':')
1142 names.append(string.strip(nameVal[0]))
1143 if len(nameVal) == 1:
1144 values[nameVal[0]] = ''
1145 else:
1146 values[nameVal[0]] = string.strip(nameVal[1])
1147 return names, values
1148
1149 def parsePropLine(prop):
1150 name, value = string.split(prop, '=')
1151 return int(string.split(name, '.')[-1]), value
1152
1153 def setSTCStyles(stc, styles, styleIdNames, commonDefs, lang, lexer, keywords):
1154 #wxLogMessage('Set style')
1155 styleDict = {}
1156 styleNumIdxMap = {}
1157
1158 # build style dict based on given styles
1159 for numStyle in styles:
1160 num, style = parsePropLine(numStyle)
1161 styleDict[num] = style
1162
1163 # Add blank style entries for undefined styles
1164 newStyles = []
1165 styleItems = styleIdNames.items() + settingsIdNames.items()
1166 styleItems.sort()
1167 idx = 0
1168 for num, name in styleItems:
1169 styleNumIdxMap[num] = idx
1170 if not styleDict.has_key(num):
1171 styleDict[num] = ''
1172 newStyles.append(writeProp(num, styleDict[num], lang))
1173 idx = idx + 1
1174
1175 # Set background colour to reduce flashing effect on refresh or page switch
1176 bkCol = None
1177 if styleDict.has_key(0): prop = styleDict[0]
1178 else: prop = styleDict[wxSTC_STYLE_DEFAULT]
1179 names, vals = parseProp(prop)
1180 if 'back' in names:
1181 bkCol = strToCol(vals['back'])
1182 if bkCol is None:
1183 bkCol = wxWHITE
1184 stc.SetBackgroundColour(bkCol)
1185
1186 # Set the styles on the wxSTC
1187 # stc.Show(False)
1188 stc.StyleResetDefault()
1189 stc.ClearDocumentStyle()
1190 stc.SetLexer(lexer)
1191 stc.SetKeyWords(0, keywords)
1192 stc.StyleSetSpec(wxSTC_STYLE_DEFAULT,
1193 styleDict[wxSTC_STYLE_DEFAULT] % commonDefs)
1194 stc.StyleClearAll()
1195
1196 for num, style in styleDict.items():
1197 if num >= 0:
1198 stc.StyleSetSpec(num, style % commonDefs)
1199 elif num == -1:
1200 setSelectionColour(stc, style % commonDefs)
1201 elif num == -2:
1202 setCursorColour(stc, style % commonDefs)
1203 elif num == -3:
1204 setEdgeColour(stc, style % commonDefs)
1205
1206 stc.Colourise(0, stc.GetTextLength())
1207 # stc.Show(True)
1208
1209 return newStyles, styleDict, styleNumIdxMap
1210
1211 #---Config reading and writing -------------------------------------------------
1212 commonDefsFile = 'common.defs.%s'%(wxPlatform == '__WXMSW__' and 'msw' or 'gtk')
1213
1214 def readPyValFromConfig(conf, name):
1215 return eval(string.replace(conf.Read(name), '\r\n', '\n')+'\n')
1216
1217 def initFromConfig(configFile, lang):
1218 cfg = wxFileConfig(localFilename=configFile, style=wxCONFIG_USE_LOCAL_FILE)
1219 cfg.SetExpandEnvVars(False)
1220
1221 # read in all group names for this language
1222 groupPrefix = 'style.%s'%lang
1223 gpLen = len(groupPrefix)
1224 predefStyleGroupNames, otherLangStyleGroupNames = [], []
1225 cont, val, idx = cfg.GetFirstGroup()
1226 while cont:
1227 if val != groupPrefix and len(val) >= 5 and val[:5] == 'style':
1228 if len(val) > gpLen and val[:gpLen] == groupPrefix:
1229 predefStyleGroupNames.append(val)
1230 else:
1231 otherLangStyleGroupNames.append(val)
1232
1233 cont, val, idx = cfg.GetNextGroup(idx)
1234
1235 # read in common elements
1236 commonDefs = readPyValFromConfig(cfg, commonDefsFile)
1237 assert type(commonDefs) is type({}), \
1238 'Common definitions (%s) not a valid dict'%commonDefsFile
1239
1240 commonStyleIdNames = readPyValFromConfig(cfg, 'common.styleidnames')
1241 assert type(commonStyleIdNames) is type({}), \
1242 'Common definitions (%s) not a valid dict'%'common.styleidnames'
1243
1244 # Lang spesific settings
1245 cfg.SetPath(lang)
1246 styleIdNames = readPyValFromConfig(cfg, 'styleidnames')
1247 assert type(commonStyleIdNames) is type({}), \
1248 'Not a valid dict [%s] styleidnames)'%lang
1249 styleIdNames.update(commonStyleIdNames)
1250 braceInfo = readPyValFromConfig(cfg, 'braces')
1251 assert type(commonStyleIdNames) is type({}), \
1252 'Not a valid dict [%s] braces)'%lang
1253
1254 displaySrc = cfg.Read('displaysrc')
1255 lexer = readPyValFromConfig(cfg, 'lexer')
1256 keywords = cfg.Read('keywords')
1257
1258 cfg.SetPath('')
1259
1260 # read in current styles
1261 styles = readStylesFromConfig(cfg, groupPrefix)
1262
1263 # read in predefined styles
1264 predefStyleGroups = {}
1265 for group in predefStyleGroupNames:
1266 predefStyleGroups[group] = readStylesFromConfig(cfg, group)
1267
1268 # read in all other style sections
1269 otherLangStyleGroups = {}
1270 for group in otherLangStyleGroupNames:
1271 otherLangStyleGroups[group] = readStylesFromConfig(cfg, group)
1272
1273 return (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames,
1274 predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups,
1275 displaySrc, lexer, keywords, braceInfo)
1276
1277 def readStylesFromConfig(config, group):
1278 config.SetPath('')
1279 config.SetPath(group)
1280 styles = []
1281 cont, val, idx = config.GetFirstEntry()
1282 while cont:
1283 styles.append(val+'='+config.Read(val))
1284 cont, val, idx = config.GetNextEntry(idx)
1285 config.SetPath('')
1286
1287 return styles
1288
1289 def writeStylesToConfig(config, group, styles):
1290 config.SetPath('')
1291 config.DeleteGroup(group)
1292 config.SetPath(group)
1293
1294 for style in styles:
1295 name, value = string.split(style, '=')
1296 config.Write(name, string.strip(value))
1297
1298 config.SetPath('')
1299
1300 #-------------------------------------------------------------------------------
1301 def initSTC(stc, config, lang):
1302 """ Main module entry point. Initialise a wxSTC from given config file."""
1303 (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames,
1304 predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups,
1305 displaySrc, lexer, keywords, braceInfo) = initFromConfig(config, lang)
1306
1307 setSTCStyles(stc, styles, styleIdNames, commonDefs, lang, lexer, keywords)
1308
1309 #-------------------------------------------------------------------------------
1310 if __name__ == '__main__':
1311 from wxPython.help import *
1312
1313 app = wxPySimpleApp()
1314
1315 provider = wxSimpleHelpProvider()
1316 wxHelpProvider_Set(provider)
1317
1318 base = os.path.split(__file__)[0]
1319 config = os.path.abspath(os.path.join(base, 'stc-styles.rc.cfg'))
1320 if 0:
1321 f = wxFrame(None, -1, 'Test frame (double click for editor)')
1322 stc = wxStyledTextCtrl(f, -1)
1323 def OnDblClick(evt, stc=stc):
1324 dlg = STCStyleEditDlg(None, 'Python', 'python', config, (stc,))
1325 try: dlg.ShowModal()
1326 finally: dlg.Destroy()
1327 stc.SetText(open('STCStyleEditor.py').read())
1328 EVT_LEFT_DCLICK(stc, OnDblClick)
1329 initSTC(stc, config, 'python')
1330 f.Show(True)
1331 app.MainLoop()
1332 else:
1333 dlg = STCStyleEditDlg(None,
1334 'Python', 'python',
1335 #'HTML', 'html',
1336 #'XML', 'xml',
1337 #'C++', 'cpp',
1338 #'Text', 'text',
1339 #'Properties', 'prop',
1340 config)
1341 try: dlg.ShowModal()
1342 finally: dlg.Destroy()