]> git.saurik.com Git - wxWidgets.git/blame - wxPython/samples/StyleEditor/STCStyleEditor.py
fix text scrolling in GTK2 (patch 703988)
[wxWidgets.git] / wxPython / samples / StyleEditor / STCStyleEditor.py
CommitLineData
00b6c4e3
RD
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$
1e4a197e 9# Copyright: (c) 2001 - 2002 Riaan Booysen
00b6c4e3
RD
10# Licence: wxWindows license
11#-----------------------------------------------------------------------------
12#Boa:Dialog:STCStyleEditDlg
13
14""" Style editor for the wxStyledTextCtrl.
15
16Reads in property style definitions from a config file.
17Modified styled can be saved (and optionally applied to a given list of STCs)
18
1114f46e 19It can also maintain a Common definition dictionary of font names, colours and
00b6c4e3
RD
20sizes which can be shared across multiple language style definitions.
21This is also used to store platform spesific settings as fonts and sizes
22vary with platform.
23
24The following items are defined in the stc-styles.rc.cfg file.
25
26common.defs.msw - Common definition dictionary used on wxMSW
27common.defs.gtk - Common definition dictionary used on wxGTK
28common.styleidnames - STC styles shared by all languages
29
30Each supported language defines the following groups:
31[<language>]
32displaysrc - Example source to display in the editor
33braces - Dictionary defining the (line, column) for showing 'good' and 'bad'
34 brace matching (both keys optional)
35keywords - Space separated list of keywords
36lexer - wxSTC constant for the language lexer
37styleidnames - 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
420 or more predefined style groups or 'themes'
43[style.<language>.<predefined name>]
44
1114f46e 45Currently the following languages are supported:
00b6c4e3
RD
46 python, html, xml, cpp, text, props
47Other languages can be added by just defining the above settings for them in
48the config file (if wxSTC implements them).
49
50Use the initSTC function to initialise your wxSTC from a config file.
51"""
52
53import os, sys, string, pprint, copy
54
55from wxPython.wx import *
1e4a197e 56from wxPython.help import *
00b6c4e3
RD
57from wxPython.lib.anchors import LayoutAnchors
58from wxPython.stc import *
59
60settingsIdNames = {-1: 'Selection', -2: 'Caret', -3: 'Edge'}
61
1114f46e 62commonPropDefs = {'fore': '#888888', 'size': 8,
00b6c4e3
RD
63 'face': wxSystemSettings_GetSystemFont(wxSYS_DEFAULT_GUI_FONT).GetFaceName()}
64
65styleCategoryDescriptions = {
1e4a197e
RD
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))
00b6c4e3
RD
96
97class STCStyleEditDlg(wxDialog):
98 """ Style editor for the wxStyledTextCtrl """
99 _custom_classes = {'wxWindow' : ['wxStyledTextCtrl']}
1114f46e 100 def _init_utils(self):
1e4a197e 101 # generated method, don't edit
00b6c4e3
RD
102 pass
103
1114f46e 104 def _init_ctrls(self, prnt):
1e4a197e
RD
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)
00b6c4e3 110 self._init_utils()
1e4a197e
RD
111 self.SetClientSize(wxSize(451, 455))
112 self.SetAutoLayout(True)
00b6c4e3 113 self.SetSizeHints(425, 400, -1, -1)
1e4a197e 114 self.Center(wxBOTH)
00b6c4e3
RD
115 EVT_SIZE(self, self.OnStcstyleeditdlgSize)
116
1e4a197e
RD
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)
00b6c4e3 142
1e4a197e
RD
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)
00b6c4e3 209
1e4a197e
RD
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))
00b6c4e3 214
1e4a197e
RD
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))
00b6c4e3
RD
220 self.okBtn.SetToolTipString('Save changes to the config file')
221 EVT_BUTTON(self.okBtn, wxID_STCSTYLEEDITDLGOKBTN, self.OnOkbtnButton)
222
1e4a197e
RD
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))
00b6c4e3 228 self.cancelBtn.SetToolTipString('Close dialog without saving changes')
1e4a197e
RD
229 EVT_BUTTON(self.cancelBtn, wxID_STCSTYLEEDITDLGCANCELBTN,
230 self.OnCancelbtnButton)
00b6c4e3 231
1e4a197e
RD
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)
00b6c4e3 235
1e4a197e
RD
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)
00b6c4e3 239 self.fixedWidthChk.SetToolTipString('Check this for Fixed Width fonts')
1e4a197e
RD
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)
00b6c4e3 371
1114f46e 372 def __init__(self, parent, langTitle, lang, configFile, STCsToUpdate=()):
00b6c4e3
RD
373 self.stc_title = 'wxStyledTextCtrl Style Editor'
374 self.stc_title = 'wxStyledTextCtrl Style Editor - %s' % langTitle
1e4a197e
RD
375 if wxPlatform == '__WXMSW__':
376 self.style_font_size = 8
377 else:
378 self.style_font_size = 10
00b6c4e3 379 self._init_ctrls(parent)
00b6c4e3
RD
380 self.lang = lang
381 self.configFile = configFile
382 self.style = ''
1e4a197e 383 self.styleNum = 0
00b6c4e3
RD
384 self.names = []
385 self.values = {}
386 self.STCsToUpdate = STCsToUpdate
1e4a197e 387 self._blockUpdate = False
1114f46e 388
1e4a197e
RD
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)
1114f46e
RD
396
397 (self.config, self.commonDefs, self.styleIdNames, self.styles,
398 self.styleGroupNames, self.predefStyleGroups,
00b6c4e3
RD
399 self.otherLangStyleGroupNames, self.otherLangStyleGroups,
400 self.displaySrc, self.lexer, self.keywords, self.braceInfo) = \
1114f46e
RD
401 initFromConfig(configFile, lang)
402
00b6c4e3
RD
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)
1114f46e 407
00b6c4e3
RD
408 margin = 0
409 self.stc.SetMarginType(margin, wxSTC_MARGIN_NUMBER)
410 self.stc.SetMarginWidth(margin, 25)
1e4a197e 411 self.stc.SetMarginSensitive(margin, True)
00b6c4e3
RD
412 EVT_STC_MARGINCLICK(self.stc, wxID_STCSTYLEEDITDLGSTC, self.OnMarginClick)
413
1e4a197e 414 self.stc.SetUseTabs(False)
00b6c4e3 415 self.stc.SetTabWidth(4)
1e4a197e 416 self.stc.SetIndentationGuides(True)
00b6c4e3
RD
417 self.stc.SetEdgeMode(wxSTC_EDGE_BACKGROUND)
418 self.stc.SetEdgeColumn(44)
1114f46e 419
00b6c4e3
RD
420 self.setStyles()
421
422 self.populateStyleSelector()
423
424 self.defNames, self.defValues = parseProp(\
425 self.styleDict.get(wxSTC_STYLE_DEFAULT, ''))
00b6c4e3
RD
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
1e4a197e 434 self.allCtrls = [((self.fgColBtn, self.fgColCb, self.fgColOkBtn), self.fgColDefCb,
00b6c4e3 435 'fore', wxID_STCSTYLEEDITDLGFGCOLDEFCB),
1e4a197e 436 ((self.bgColBtn, self.bgColCb, self.bgColOkBtn), self.bgColDefCb,
00b6c4e3 437 'back', wxID_STCSTYLEEDITDLGBGCOLDEFCB),
1114f46e 438 (self.taBoldCb, self.taBoldDefCb,
00b6c4e3 439 'bold', wxID_STCSTYLEEDITDLGTABOLDDEFCB),
1114f46e
RD
440 (self.taItalicCb, self.taItalicDefCb,
441 'italic', wxID_STCSTYLEEDITDLGTAITALICDEFCB),
442 (self.taUnderlinedCb, self.taUnderlinedDefCb,
00b6c4e3 443 'underline', wxID_STCSTYLEEDITDLGTAUNDERLINEDDEFCB),
1114f46e 444 (self.taEOLfilledCb, self.taEOLfilledDefCb,
00b6c4e3 445 'eolfilled', wxID_STCSTYLEEDITDLGTAEOLFILLEDDEFCB),
1e4a197e 446 ((self.sizeCb, self.sizeOkBtn), self.taSizeDefCb,
00b6c4e3 447 'size', wxID_STCSTYLEEDITDLGTASIZEDEFCB),
1e4a197e 448 ((self.faceCb, self.faceOkBtn, self.fixedWidthChk), self.faceDefCb,
00b6c4e3
RD
449 'face', wxID_STCSTYLEEDITDLGFACEDEFCB)]
450
1e4a197e 451 self.clearCtrls(disableDefs=True)
00b6c4e3
RD
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')
1114f46e 458
00b6c4e3 459 self.Center(wxBOTH)
1114f46e 460
00b6c4e3
RD
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)
1114f46e 467
00b6c4e3
RD
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
1114f46e 479
00b6c4e3
RD
480 try:
481 self.updateStyle()
1e4a197e 482 return True
00b6c4e3
RD
483 except KeyError, errkey:
484 wxLogError('Name not found in Common definition, '\
485 'please enter valid reference. (%s)'%errkey)
486 self.restoreStyles(oldstyle)
1e4a197e 487 return False
00b6c4e3
RD
488
489#---Control population methods--------------------------------------------------
490 def setStyles(self):
1e4a197e 491 if self._blockUpdate: return
00b6c4e3 492 self.styles, self.styleDict, self.styleNumIdxMap = \
1114f46e 493 setSTCStyles(self.stc, self.styles, self.styleIdNames,
00b6c4e3 494 self.commonDefs, self.lang, self.lexer, self.keywords)
1114f46e 495
00b6c4e3
RD
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)
1114f46e 502
00b6c4e3
RD
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()
1114f46e 511
00b6c4e3
RD
512 def findInStyles(self, txt, styles):
513 for style in styles:
514 if string.find(style, txt) != -1:
1e4a197e
RD
515 return True
516 return False
00b6c4e3
RD
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
1e4a197e
RD
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
1114f46e 595
00b6c4e3
RD
596 def valIsCommonDef(self, val):
597 return len(val) >= 5 and val[:2] == '%('
1114f46e 598
00b6c4e3
RD
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:
1e4a197e 605 self.fgColDefCb.Enable(True)
00b6c4e3 606 if self.styleNum == -1:
1e4a197e 607 self.bgColDefCb.Enable(True)
1114f46e 608
00b6c4e3 609 # populate with default style
1e4a197e 610 self.populateProp(self.defValues.items(), True,
00b6c4e3
RD
611 self.styleNum != wxSTC_STYLE_DEFAULT)
612 # override with current settings
1e4a197e 613 self.populateProp(self.values.items(), False)
1114f46e 614
00b6c4e3
RD
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
1e4a197e
RD
621 def bindComboEvts(self, combo, btn, btnEvtMeth, comboEvtMeth, rdclickEvtMeth):
622 EVT_COMBOBOX(combo, combo.GetId(), comboEvtMeth)
623 EVT_BUTTON(btn, btn.GetId(), btnEvtMeth)
00b6c4e3 624 EVT_RIGHT_DCLICK(combo, rdclickEvtMeth)
1e4a197e
RD
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')
00b6c4e3
RD
628
629 def populateCombosWithCommonDefs(self, fixedWidthOnly=None):
1e4a197e
RD
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
00b6c4e3
RD
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:
1e4a197e
RD
680 self.elementLb.InsertItems([name, '----Language----'], 0)
681 self.elementLb.Append('----Standard----')
00b6c4e3
RD
682 stdStart = stdPos = self.elementLb.Number()
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
1114f46e 689 elif num >= 40:
00b6c4e3
RD
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
1e4a197e 698 self.elementLb.Append('----Settings----')
00b6c4e3
RD
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
1e4a197e 706 self.elementLb.Append('----Common----')
00b6c4e3
RD
707 self.commonDefsStartIdx = self.elementLb.Number()
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
1114f46e 712
00b6c4e3
RD
713#---Colour methods--------------------------------------------------------------
714 def getColourDlg(self, colour, title=''):
715 data = wxColourData()
716 data.SetColour(colour)
1e4a197e 717 data.SetChooseFull(True)
00b6c4e3
RD
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):
1114f46e 730 col = self.getColourDlg(colBtn.GetBackgroundColour(),
00b6c4e3 731 self.colDlgTitles[prop]+ ' colour')
1114f46e 732 if col:
00b6c4e3
RD
733 colBtn.SetForegroundColour(wxColour(0, 0, 0))
734 colBtn.SetBackgroundColour(col)
735 colStr = colToStr(col)
736 colCb.SetValue(colStr)
1e4a197e 737 self.editProp(True, prop, colStr)
00b6c4e3
RD
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
1e4a197e
RD
745 def editColTCProp(self, colCb, colBtn, prop, val=None):
746 if val is None:
747 colStr = colCb.GetValue()
748 else:
749 colStr = val
1114f46e 750 if colStr:
00b6c4e3
RD
751 col = strToCol(colStr%self.commonDefs)
752 if self.editProp(colStr!='', prop, colStr):
1114f46e 753 if colStr:
00b6c4e3
RD
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
1e4a197e
RD
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
00b6c4e3
RD
770 def OnbgColRet(self, event):
771 try: self.editColTCProp(self.bgColCb, self.bgColBtn, 'back')
772 except AssertionError: wxLogError('Not a valid colour value')
773
1e4a197e
RD
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
00b6c4e3
RD
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:
1e4a197e 797 self.elementLb.SetSelection(idx, True)
00b6c4e3
RD
798 self.OnElementlbListbox(None)
799
800 def OnfaceRet(self, event):
1e4a197e
RD
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):
00b6c4e3
RD
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):
1e4a197e
RD
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):
00b6c4e3
RD
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)
1e4a197e 835 self.clearCtrls(disableDefs=True)
00b6c4e3 836 if prop == 'fore':
1e4a197e
RD
837 self.fgColBtn.Enable(True)
838 self.fgColCb.Enable(True)
839 self.fgColOkBtn.Enable(True)
00b6c4e3 840 elif prop == 'face':
1e4a197e
RD
841 self.faceCb.Enable(True)
842 self.fixedWidthChk.Enable(True)
843 self.faceOkBtn.Enable(True)
00b6c4e3 844 elif prop == 'size':
1e4a197e
RD
845 self.sizeCb.Enable(True)
846 self.sizeOkBtn.Enable(True)
00b6c4e3
RD
847
848 commonDefVal = str(self.commonDefs[common])
849 self.styleDefST.SetLabel(commonDefVal)
1e4a197e 850 self.populateProp( [(prop, commonDefVal)], True)
00b6c4e3
RD
851
852 self.styleNum = 'common'
853 self.style = [common, prop, commonDefVal]
854 self.names, self.values = [prop], {prop: commonDefVal}
1114f46e 855
00b6c4e3
RD
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)
00b6c4e3
RD
861 if self.styleNum == wxSTC_STYLE_DEFAULT:
862 self.defNames, self.defValues = \
863 self.names, self.values
864
865 self.checkBraces(self.styleNum)
1114f46e 866
00b6c4e3 867 self.styleDefST.SetLabel(self.style)
1114f46e 868
00b6c4e3
RD
869 self.populateCtrls()
870 # separator selected
871 else:
1e4a197e 872 self.clearCtrls(disableDefs=True)
00b6c4e3
RD
873 if styleIdent:
874 self.styleDefST.SetLabel(styleCategoryDescriptions[styleIdent])
875
876 self.populateCombosWithCommonDefs()
1114f46e 877
00b6c4e3 878 def OnDefaultCheckBox(self, event):
1e4a197e
RD
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)
00b6c4e3
RD
910
911 def OnOkbtnButton(self, event):
912 # write styles and common defs to the config
1e4a197e
RD
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()
00b6c4e3
RD
925 self.EndModal(wxID_OK)
926
927 def OnCancelbtnButton(self, event):
928 self.EndModal(wxID_CANCEL)
929
930 def OnCommondefsbtnButton(self, event):
1114f46e 931 dlg = wxTextEntryDialog(self, 'Edit common definitions dictionary',
00b6c4e3
RD
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()
1114f46e 948
00b6c4e3
RD
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'))
1e4a197e 977 self.elementLb.SetSelection(self.elementLb.Number()-1, True)
00b6c4e3
RD
978 self.populateCombosWithCommonDefs()
979 self.OnElementlbListbox(None)
980 finally:
981 dlg.Destroy()
982
983 def OnRemovesharebtnButton(self, event):
984 ownGroup = 'style.%s'%self.lang
1114f46e
RD
985 comDef = self.elementLb.GetStringSelection()
986
00b6c4e3
RD
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.Number():
1008 selIdx = selIdx - 1
1e4a197e 1009 self.elementLb.SetSelection(selIdx, True)
00b6c4e3
RD
1010 self.OnElementlbListbox(None)
1011
1012#---STC events------------------------------------------------------------------
1013 def OnUpdateUI(self, event):
1e4a197e
RD
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)
00b6c4e3
RD
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):
1e4a197e 1046 self.elementLb.SetStringSelection('Line numbers', True)
00b6c4e3
RD
1047 self.OnElementlbListbox(None)
1048
1114f46e 1049
00b6c4e3
RD
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
1054class 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')
1e4a197e 1057 self.SetClientSize(wxSize(184, 200))
00b6c4e3 1058
1e4a197e 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)
00b6c4e3
RD
1060 self.propTypeRBx.SetSelection(self._propTypeIdx)
1061
1e4a197e 1062 self.staticBox1 = wxStaticBox(id = wxID_COMMONDEFDLGSTATICBOX1, label = 'Name', name = 'staticBox1', parent = self, pos = wxPoint(8, 108), size = wxSize(168, 46), style = 0)
00b6c4e3 1063
1e4a197e 1064 self.comDefNameTC = wxTextCtrl(id = wxID_COMMONDEFDLGCOMDEFNAMETC, name = 'comDefNameTC', parent = self, pos = wxPoint(16, 124), size = wxSize(152, 21), style = 0, value = '')
00b6c4e3
RD
1065 self.comDefNameTC.SetLabel(self._comDefName)
1066
1e4a197e 1067 self.okBtn = wxButton(id = wxID_COMMONDEFDLGOKBTN, label = 'OK', name = 'okBtn', parent = self, pos = wxPoint(8, 164), size = wxSize(80, 23), style = 0)
00b6c4e3
RD
1068 EVT_BUTTON(self.okBtn, wxID_COMMONDEFDLGOKBTN, self.OnOkbtnButton)
1069
1e4a197e 1070 self.cancelBtn = wxButton(id = wxID_COMMONDEFDLGCANCELBTN, label = 'Cancel', name = 'cancelBtn', parent = self, pos = wxPoint(96, 164), size = wxSize(80, 23), style = 0)
00b6c4e3
RD
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)
1114f46e
RD
1079
1080 self.propMap = {0: 'fore', 1: 'face', 2: 'size'}
00b6c4e3
RD
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)
1114f46e 1093
00b6c4e3 1094#---Functions useful outside of the editor----------------------------------
1114f46e 1095
00b6c4e3
RD
1096def setSelectionColour(stc, style):
1097 names, values = parseProp(style)
1098 if 'fore' in names:
1e4a197e 1099 stc.SetSelForeground(True, strToCol(values['fore']))
00b6c4e3 1100 if 'back' in names:
1e4a197e 1101 stc.SetSelBackground(True, strToCol(values['back']))
00b6c4e3
RD
1102
1103def setCursorColour(stc, style):
1104 names, values = parseProp(style)
1105 if 'fore' in names:
1106 stc.SetCaretForeground(strToCol(values['fore']))
1107
1108def setEdgeColour(stc, style):
1109 names, values = parseProp(style)
1110 if 'fore' in names:
1111 stc.SetEdgeColour(strToCol(values['fore']))
1112
1113def strToCol(strCol):
1114 assert len(strCol) == 7 and strCol[0] == '#', 'Not a valid colour string'
1114f46e
RD
1115 return wxColour(string.atoi('0x'+strCol[1:3], 16),
1116 string.atoi('0x'+strCol[3:5], 16),
00b6c4e3
RD
1117 string.atoi('0x'+strCol[5:7], 16))
1118def colToStr(col):
1114f46e 1119 return '#%s%s%s' % (string.zfill(string.upper(hex(col.Red())[2:]), 2),
00b6c4e3
RD
1120 string.zfill(string.upper(hex(col.Green())[2:]), 2),
1121 string.zfill(string.upper(hex(col.Blue())[2:]), 2))
1122
1123def 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
1129def 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
1136def 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
1114f46e 1148
00b6c4e3
RD
1149def parsePropLine(prop):
1150 name, value = string.split(prop, '=')
1151 return int(string.split(name, '.')[-1]), value
1152
1153def setSTCStyles(stc, styles, styleIdNames, commonDefs, lang, lexer, keywords):
1e4a197e 1154 #wxLogMessage('Set style')
00b6c4e3
RD
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
1e4a197e
RD
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
00b6c4e3 1186 # Set the styles on the wxSTC
1e4a197e 1187# stc.Show(False)
00b6c4e3
RD
1188 stc.StyleResetDefault()
1189 stc.ClearDocumentStyle()
1190 stc.SetLexer(lexer)
1191 stc.SetKeyWords(0, keywords)
1114f46e 1192 stc.StyleSetSpec(wxSTC_STYLE_DEFAULT,
00b6c4e3
RD
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())
1e4a197e 1207# stc.Show(True)
1114f46e 1208
00b6c4e3
RD
1209 return newStyles, styleDict, styleNumIdxMap
1210
1211#---Config reading and writing -------------------------------------------------
1212commonDefsFile = 'common.defs.%s'%(wxPlatform == '__WXMSW__' and 'msw' or 'gtk')
1213
1e4a197e
RD
1214def readPyValFromConfig(conf, name):
1215 return eval(string.replace(conf.Read(name), '\r\n', '\n')+'\n')
1216
00b6c4e3
RD
1217def initFromConfig(configFile, lang):
1218 cfg = wxFileConfig(localFilename=configFile, style=wxCONFIG_USE_LOCAL_FILE)
1e4a197e 1219 cfg.SetExpandEnvVars(False)
00b6c4e3
RD
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)
1114f46e 1232
00b6c4e3 1233 cont, val, idx = cfg.GetNextGroup(idx)
1114f46e 1234
00b6c4e3 1235 # read in common elements
1e4a197e 1236 commonDefs = readPyValFromConfig(cfg, commonDefsFile)
00b6c4e3
RD
1237 assert type(commonDefs) is type({}), \
1238 'Common definitions (%s) not a valid dict'%commonDefsFile
1239
1e4a197e 1240 commonStyleIdNames = readPyValFromConfig(cfg, 'common.styleidnames')
00b6c4e3
RD
1241 assert type(commonStyleIdNames) is type({}), \
1242 'Common definitions (%s) not a valid dict'%'common.styleidnames'
1243
1244 # Lang spesific settings
1114f46e 1245 cfg.SetPath(lang)
1e4a197e 1246 styleIdNames = readPyValFromConfig(cfg, 'styleidnames')
00b6c4e3
RD
1247 assert type(commonStyleIdNames) is type({}), \
1248 'Not a valid dict [%s] styleidnames)'%lang
1249 styleIdNames.update(commonStyleIdNames)
1e4a197e 1250 braceInfo = readPyValFromConfig(cfg, 'braces')
00b6c4e3
RD
1251 assert type(commonStyleIdNames) is type({}), \
1252 'Not a valid dict [%s] braces)'%lang
1114f46e 1253
00b6c4e3 1254 displaySrc = cfg.Read('displaysrc')
1e4a197e 1255 lexer = readPyValFromConfig(cfg, 'lexer')
00b6c4e3
RD
1256 keywords = cfg.Read('keywords')
1257
1258 cfg.SetPath('')
1259
1260 # read in current styles
1261 styles = readStylesFromConfig(cfg, groupPrefix)
1262
1114f46e 1263 # read in predefined styles
00b6c4e3
RD
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)
1114f46e
RD
1272
1273 return (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames,
00b6c4e3
RD
1274 predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups,
1275 displaySrc, lexer, keywords, braceInfo)
1276
1277def readStylesFromConfig(config, group):
1278 config.SetPath('')
1114f46e 1279 config.SetPath(group)
00b6c4e3
RD
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
1289def 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#-------------------------------------------------------------------------------
1301def initSTC(stc, config, lang):
1302 """ Main module entry point. Initialise a wxSTC from given config file."""
1114f46e 1303 (cfg, commonDefs, styleIdNames, styles, predefStyleGroupNames,
00b6c4e3
RD
1304 predefStyleGroups, otherLangStyleGroupNames, otherLangStyleGroups,
1305 displaySrc, lexer, keywords, braceInfo) = initFromConfig(config, lang)
1114f46e 1306
00b6c4e3
RD
1307 setSTCStyles(stc, styles, styleIdNames, commonDefs, lang, lexer, keywords)
1308
1309#-------------------------------------------------------------------------------
1310if __name__ == '__main__':
1e4a197e
RD
1311 from wxPython.help import *
1312
00b6c4e3 1313 app = wxPySimpleApp()
1114f46e 1314
1e4a197e
RD
1315 provider = wxSimpleHelpProvider()
1316 wxHelpProvider_Set(provider)
1317
1318 home = os.environ.get('HOME')
1319 if home: home = os.path.join(home, '.boa')
1320 config = os.path.abspath(os.path.join(home, 'stc-styles.rc.cfg'))
00b6c4e3
RD
1321 if 0:
1322 f = wxFrame(None, -1, 'Test frame (double click for editor)')
1323 stc = wxStyledTextCtrl(f, -1)
1324 def OnDblClick(evt, stc=stc):
1325 dlg = STCStyleEditDlg(None, 'Python', 'python', config, (stc,))
1326 try: dlg.ShowModal()
1327 finally: dlg.Destroy()
1328 stc.SetText(open('STCStyleEditor.py').read())
1329 EVT_LEFT_DCLICK(stc, OnDblClick)
1330 initSTC(stc, config, 'python')
1e4a197e 1331 f.Show(True)
00b6c4e3
RD
1332 app.MainLoop()
1333 else:
1114f46e 1334 dlg = STCStyleEditDlg(None,
00b6c4e3
RD
1335 'Python', 'python',
1336 #'HTML', 'html',
1337 #'XML', 'xml',
1114f46e
RD
1338 #'C++', 'cpp',
1339 #'Text', 'text',
1340 #'Properties', 'prop',
00b6c4e3
RD
1341 config)
1342 try: dlg.ShowModal()
1343 finally: dlg.Destroy()