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