Menu

[r2591]: / trunk / Src / FrHiliterPrefs.pas  Maximize  Restore  History

Download this file

637 lines (571 with data), 20.5 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
{
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/
*
* Copyright (C) 2006-2012, Peter Johnson (www.delphidabbler.com).
*
* $Rev$
* $Date$
*
* Implements a frame that allows user to set syntax highlighter preferences.
* Designed for use as one of the tabs in the Preferences dialogue box.
}
unit FrHiliterPrefs;
interface
uses
// Delphi
StdCtrls, Forms, Controls, Classes, Menus, Buttons,
// Project
FrPrefsBase, FrRTFShowCase, Hiliter.UGlobals, UColorBoxEx, UColorDialogEx,
UConsts, UEncodings, UPreferences, URTFUtils;
type
{
THiliterPrefsFrame:
Frame that allows user to set syntax highlighter preferences. Can persist
preferences entered by user. Note: Designed for use in preferences dialog
box.
}
THiliterPrefsFrame = class(TPrefsBaseFrame)
btnReset: TButton;
btnStyle: TBitBtn;
cbFontName: TComboBox;
cbFontSize: TComboBox;
chkBold: TCheckBox;
chkItalics: TCheckBox;
chkUnderline: TCheckBox;
frmExample: TRTFShowCaseFrame;
gbDocFont: TGroupBox;
gbElements: TGroupBox;
gbFontStyle: TGroupBox;
lbElements: TListBox;
lblColour: TLabel;
lblExample: TLabel;
lblFontName: TLabel;
lblFontSize: TLabel;
lblElements: TLabel;
miClassic: TMenuItem;
miDelphi7: TMenuItem;
miDelphi2006: TMenuItem;
miNoHilite: TMenuItem;
miVisualStudio: TMenuItem;
miSpacer: TMenuItem;
mnuStyles: TPopupMenu;
procedure btnResetClick(Sender: TObject);
procedure btnStyleClick(Sender: TObject);
procedure cbColourChange(Sender: TObject);
procedure cbFontNameChange(Sender: TObject);
procedure cbFontSizeChange(Sender: TObject);
procedure ChkFontStyleClick(Sender: TObject);
procedure lbElementsClick(Sender: TObject);
procedure StyleMenuClick(Sender: TObject);
strict private
fColorBox: TColorBoxEx; // Custom colour combo box component
fColorDlg: TColorDialogEx; // Custom colour dialog box (use with combo)
fAttrs: IHiliteAttrs; // Loads and records user's hilite preferences
fChanged: Boolean; // Flags if any preference has changed
procedure PopulateElementsList;
{Populates list box containing customisable highlighter attribute
elements.
}
procedure PopulateFontSizeCombo;
{Populates font size combo with common font sizes.
}
procedure PopulateFontNameCombo;
{Populates font name combo with all supported monospace fonts.
}
function CurrentElementId: THiliteElement;
{Gets id of highlighter element currently selected in Elements list box.
@return Required element id.
}
function CurrentElement: IHiliteElemAttrs;
{Gets reference to highlighter element currently selected in Elements list
box.
@return Required reference to element.
}
procedure UpdateControls;
{Updates state of controls and preview to reflect currently selected
highlighter element.
}
procedure UpdatePreview;
{Updates preview of highlighting of current highlighter element.
}
function GenerateRTF: TRTF;
{Generates RTF of example of current highlighter element.
@return Required RTF code.
}
function ParentForm: TForm;
{Gets reference to form that hosts the frame.
@return Reference to host form or nil if no such host.
}
public
constructor Create(AOwner: TComponent); override;
{Class constructor. Creates custom control, populates and initialises
controls and sets up object.
@param AOwner [in] Not used.
}
destructor Destroy; override;
{Class destructor. Tears down object.
}
procedure Activate(const Prefs: IPreferences); override;
{Called when page activated. Updates controls.
@param Prefs [in] Object that provides info used to update controls.
}
procedure Deactivate(const Prefs: IPreferences); override;
{Called when page is deactivated. Stores information entered by user.
@param Prefs [in] Object used to store information.
}
/// <summary>Checks if preference changes require that main window UI is
/// updated.</summary>
/// <remarks>Called when dialog box containing frame is closing.</remarks>
function UIUpdated: Boolean; override;
procedure ArrangeControls; override;
{Arranges controls on frame. Called after frame has been sized.
}
function DisplayName: string; override;
{Caption that is displayed in the tab sheet that contains this frame when
displayed in the preference dialog box.
@return Required display name.
}
class function Index: Byte; override;
{Index number that determines the location of the tab containing this
frame when displayed in the preferences dialog box.
@return Required index number.
}
end;
implementation
uses
// Delphi
SysUtils, ExtCtrls, Windows, Graphics, Dialogs,
// Project
FmPreferencesDlg, Hiliter.UAttrs, IntfCommon, UCtrlArranger, UFontHelper,
UIStringList, UMessageBox, URTFBuilder, URTFStyles, UUtils;
{$R *.dfm}
resourcestring
// Highlighter element descriptions (appear in list box)
sCommentDesc = 'Comments';
sReservedDesc = 'Reserved words';
sIdentifierDesc = 'Identifiers';
sSymbolDesc = 'Symbols';
sStringDesc = 'String literals';
sNumberDesc = 'Whole numbers';
sFloatDesc = 'Real numbers';
sHexDesc = 'Hexadecimal numbers';
sPreProcessorDesc = 'Compiler directives';
sAssemblerDesc = 'Assembler code';
sErrorDesc = 'Errors';
// Highlighter element examples (appear in Example box)
// (lines are separated by LF)
sCommentEg = '{A comment}' + LF + '// Another comment;';
sReservedEg = 'interface' + LF + 'shl';
sIdentifierEg = 'AComponent' + LF + 'MyClass.MyMethod';
sSymbolEg = ':='+ LF + '[';
sStringEg = '''A string''' + LF + '#13#$OA';
sNumberEg = '123456';
sFloatEg = '1.234e67' + LF + '120.765';
sHexEg = '$A59E' + LF + '$a59e';
sPreProcessorEg = '{$DEFINE DEBUG}' + LF + '(*$R+*)';
sAssemblerEg = 'MOV EAX,1234H' + LF + 'MOV Number,EAX';
sErrorEg = 'An error message';
// Error messages
sErrBadFontSize = 'Invalid font size';
const
// Map of highlighter elements to descriptions
cElementDescs: array[THiliteElement] of string = (
'', // heWhitespace: not displayed in list box
sCommentDesc, // heComment
sReservedDesc, // heReserved
sIdentifierDesc, // heIdentifier
sSymbolDesc, // heSymbol
sStringDesc, // heString
sNumberDesc, // heNumber
sFloatDesc, // heFloat
sHexDesc, // heHex
sPreProcessorDesc, // hePreProcessor
sAssemblerDesc, // heAssembler
sErrorDesc // heError
);
// Map of highlighter elements to examples
cElementEgs: array[THiliteElement] of string = (
'', // heWhitespace: not displayed in list box
sCommentEg, // heComment
sReservedEg, // heReserved
sIdentifierEg, // heIdentifier
sSymbolEg, // heSymbol
sStringEg, // heString
sNumberEg, // heNumber
sFloatEg, // heFloat
sHexEg, // heHex
sPreProcessorEg, // hePreProcessor
sAssemblerEg, // heAssembler
sErrorEg // heError
);
{ THiliterPrefsFrame }
procedure THiliterPrefsFrame.Activate(const Prefs: IPreferences);
{Called when page activated. Updates controls.
@param Prefs [in] Object that provides info used to update controls.
}
begin
(fAttrs as IAssignable).Assign(Prefs.HiliteAttrs);
Prefs.CustomHiliteColours.CopyTo(fColorDlg.CustomColors, True);
UpdateControls;
end;
procedure THiliterPrefsFrame.ArrangeControls;
{Arranges controls on frame. Called after frame has been sized.
}
var
AvailWidth: Integer; // width available in element group box for controls
CtrlWidth: Integer; // width of side-by-side controls in element group box
Spacing: Integer; // spacing needed to separate controls in element gp box
begin
// We can't rely on anchors to resize this group box since we need its width
// below and anchors don't seem to update width in time to use it here
gbElements.Width := Width;
AvailWidth := gbElements.Width - lbElements.Left * 2;
CtrlWidth := lbElements.Width + gbFontStyle.Width + fColorBox.Width;
Spacing := (AvailWidth - CtrlWidth) div 2;
TCtrlArranger.MoveToRightOf(lbElements, gbFontStyle, Spacing);
fColorBox.Left := gbElements.Width - fColorBox.Width - 8;
lblColour.Left := fColorBox.Left;
frmExample.Left := gbFontStyle.Left;
frmExample.Width := fColorBox.Left + fColorBox.Width - frmExample.Left;
lblExample.Left := frmExample.Left;
lbElements.Top := TCtrlArranger.BottomOf(lblElements, 4);
lbElements.Height := gbElements.ClientHeight - lbElements.Top - 12;
frmExample.Top := TCtrlArranger.BottomOf(lblExample, 4);
frmExample.Height := gbElements.ClientHeight - frmExample.Top - 12;
fColorBox.Top := TCtrlArranger.BottomOf(lblColour, 4);
end;
procedure THiliterPrefsFrame.btnResetClick(Sender: TObject);
{Reset button click handler. Reset syntax highlighter attributes to default
values.
@param Sender [in] Not used.
}
begin
fAttrs := THiliteAttrsFactory.CreateDefaultAttrs;
UpdateControls;
fChanged := True;
end;
procedure THiliterPrefsFrame.btnStyleClick(Sender: TObject);
{Predefined styles button click event handler. Displays menu containing
available predefined styles.
@param Sender [in] Not used.
}
var
PopupPos: TPoint; // place where menu pops up
begin
PopupPos := ClientToScreen(
Point(btnStyle.Left, btnStyle.Top + btnStyle.Height)
);
mnuStyles.Popup(PopupPos.X, PopupPos.Y);
end;
procedure THiliterPrefsFrame.cbColourChange(Sender: TObject);
{Colour combo box OnChange handler. Sets foreground colour of current
highlighter element to colour value selected by user.
@param Sender [in] Not used.
}
begin
CurrentElement.ForeColor := fColorBox.Selected;
UpdatePreview;
fChanged := True;
end;
procedure THiliterPrefsFrame.cbFontNameChange(Sender: TObject);
{Font name combo box OnChange hander. Sets font name used by highlighter to
value selected by user.
@param Sender [in] Not used.
}
begin
inherited;
fAttrs.FontName := cbFontName.Text;
UpdatePreview;
fChanged := True;
end;
procedure THiliterPrefsFrame.cbFontSizeChange(Sender: TObject);
{Font size combo box OnChange handler. Sets font size used by highlighter to
value selected by user.
@param Sender [in] Not used.
}
var
Size: Integer; // font size entered by user
begin
inherited;
// Do nothing if combo box text field cleared
if cbFontSize.Text = '' then
Exit;
if TryStrToInt(cbFontSize.Text, Size) then
begin
// Combo has valid value entered: update
fAttrs.FontSize := Size;
UpdatePreview;
fChanged := True;
end
else
begin
// Combo has invalid value: say so
TMessageBox.Error(ParentForm, sErrBadFontSize);
cbFontSize.Text := IntToStr(fAttrs.FontSize);
end;
end;
procedure THiliterPrefsFrame.ChkFontStyleClick(Sender: TObject);
{Handles clicks on any of the font style check boxes. Updates current
highlighter element's font style accordingly.
@param Sender [in] Reference to check box that triggered event.
}
var
CB: TCheckBox; // check box triggering event
Elem: IHiliteElemAttrs; // currently selected highlighter element
begin
CB := Sender as TCheckBox;
Elem := CurrentElement;
// Update element's font style per font style stored in check box's tag
if CB.Checked then
Elem.FontStyle := Elem.FontStyle + [TFontStyle(CB.Tag)]
else
Elem.FontStyle := Elem.FontStyle - [TFontStyle(CB.Tag)];
UpdatePreview;
fChanged := True;
end;
constructor THiliterPrefsFrame.Create(AOwner: TComponent);
{Class constructor. Creates custom components, populates and initialises
controls and sets up object.
@param AOwner [in] Not used.
}
resourcestring
// Colour dialog style
sDlgTitle = 'Choose Element Colour'; // colour dialog title
begin
inherited;
HelpKeyword := 'HiliterPrefs';
// Create object used to store customised attributes
fAttrs := THiliteAttrsFactory.CreateDefaultAttrs;
// Create and initialise custom color dialog box
fColorDlg := TColorDialogEx.Create(ParentForm);
fColorDlg.Title := sDlgTitle;
// cdShowHelp not included in fColorDlg.Options since setting HelpKeyword
// property causes this style to be used
fColorDlg.Options := [cdFullOpen];
fColorDlg.HelpKeyword := 'ChooseElemColourDlg';
// Create and initialise custom color combo box
fColorBox := TColorBoxEx.Create(Self); // automatically freed
fColorBox.Parent := gbElements;
fColorBox.Left := 248;
fColorBox.Top := 36;
fColorBox.Width := 137;
fColorBox.Height := 22;
fColorBox.NoneColorColor := clNone;
// cbCustomColor not included in fColorBox.Style since assigning ColorDialog
// property sets this style
fColorBox.Style := [cbStandardColors, cbExtendedColors, cbSystemColors,
cbIncludeNone, cbPrettyNames];
fColorBox.ItemHeight := 16;
fColorBox.TabOrder := 2;
fColorBox.ColorDialog := fColorDlg;
fColorBox.OnChange := cbColourChange;
lblColour.FocusControl := fColorBox;
// Populate list and combo controls
PopulateElementsList;
PopulateFontNameCombo;
PopulateFontSizeCombo;
// Store font style ordinal in font style check box tags
chkBold.Tag := Ord(fsBold);
chkItalics.Tag := Ord(fsItalic);
chkUnderline.Tag := Ord(fsUnderline);
// Set up predefined style drop down menu
miClassic.Tag := Ord(hsCodeSnip);
miDelphi7.Tag := Ord(hsDelphi7);
miDelphi2006.Tag := Ord(hsDelphi2006);
miVisualStudio.Tag := Ord(hsVisualStudio);
miNoHilite.Tag := Ord(hsNul);
// Clear dirty flag
fChanged := False;
end;
function THiliterPrefsFrame.CurrentElement: IHiliteElemAttrs;
{Gets reference to highlighter element currently selected in Elements list
box.
@return Required reference to element.
}
begin
Result := fAttrs.Elements[CurrentElementId];
end;
function THiliterPrefsFrame.CurrentElementId: THiliteElement;
{Gets id of highlighter element currently selected in Elements list box.
@return Required element id.
}
begin
Result := THiliteElement(lbElements.Items.Objects[lbElements.ItemIndex]);
end;
procedure THiliterPrefsFrame.Deactivate(const Prefs: IPreferences);
{Called when page is deactivated. Stores information entered by user.
@param Prefs [in] Object used to store information.
}
begin
Prefs.HiliteAttrs := fAttrs;
Prefs.CustomHiliteColours.CopyFrom(fColorDlg.CustomColors, True);
end;
destructor THiliterPrefsFrame.Destroy;
{Class destructor. Tears down object.
}
begin
FreeAndNil(fColorDlg);
FreeAndNil(fColorBox);
inherited;
end;
function THiliterPrefsFrame.DisplayName: string;
{Caption that is displayed in the tab sheet that contains this frame when
displayed in the preference dialog box.
@return Required display name.
}
resourcestring
sDisplayName = 'Syntax Highlighter'; // display name
begin
Result := sDisplayName;
end;
function THiliterPrefsFrame.GenerateRTF: TRTF;
{Generates RTF of example of current highlighter element.
@return Required RTF code.
}
var
RTFBuilder: TRTFBuilder; // object used to create and render RTFBuilder
EgLines: IStringList; // list of lines in the example
EgLine: string; // each line of example
begin
// Create builder object to create RTFBuilder document
RTFBuilder := TRTFBuilder.Create(0); // use default code page
try
// Set up font and colour tables
RTFBuilder.DefaultFontIdx := RTFBuilder.FontTable.Add(
fAttrs.FontName, rgfModern, DEFAULT_CHARSET
);
RTFBuilder.ColourTable.Add(CurrentElement.ForeColor);
// Set character formating
RTFBuilder.SetFont(fAttrs.FontName);
RTFBuilder.SetFontSize(fAttrs.FontSize);
RTFBuilder.SetColour(CurrentElement.ForeColor);
RTFBuilder.SetFontStyle(CurrentElement.FontStyle);
// Write out each line of example
EgLines := TIStringList.Create(cElementEgs[CurrentElementId], LF, False);
for EgLine in EgLines do
begin
RTFBuilder.AddText(EgLine);
RTFBuilder.EndPara;
end;
// Create RTFBuilder source
Result := RTFBuilder.Render;
finally
RTFBuilder.Free;
end;
end;
class function THiliterPrefsFrame.Index: Byte;
{Index number that determines the location of the tab containing this frame
when displayed in the preferences dialog box.
@return Required index number.
}
begin
Result := 30;
end;
procedure THiliterPrefsFrame.lbElementsClick(Sender: TObject);
{Handles click on Elements list box. Updates controls.
@param Sender [in] Not used.
}
begin
UpdateControls;
end;
function THiliterPrefsFrame.ParentForm: TForm;
{Gets reference to form that hosts the frame.
@return Reference to host form or nil if no such host.
}
var
ParentCtrl: TWinControl; // reference to parent controls
begin
// Loop through parent controls until form found or top level parent reached
ParentCtrl := Self.Parent;
while Assigned(ParentCtrl) and not (ParentCtrl is TForm) do
ParentCtrl := ParentCtrl.Parent;
if ParentCtrl is TForm then
Result := ParentCtrl as TForm
else
Result := nil;
end;
procedure THiliterPrefsFrame.PopulateElementsList;
{Populates list box containing customisable highlighter attribute elements.
}
var
ElemId: THiliteElement; // loops thru all highlighter elements
begin
lbElements.Clear;
for ElemId := Low(THiliteElement) to High(THiliteElement) do
if ElemId <> heWhitespace then
// whitespace element ignored: don't customise since no text displayed
lbElements.Items.AddObject(cElementDescs[ElemId], TObject(ElemId));
// Select first item
lbElements.ItemIndex := 0;
end;
procedure THiliterPrefsFrame.PopulateFontNameCombo;
{Populates font name combo with all supported monospace fonts.
}
begin
TFontHelper.ListMonoSpaceFonts(cbFontName.Items);
end;
procedure THiliterPrefsFrame.PopulateFontSizeCombo;
{Populates font size combo with common font sizes.
}
begin
TFontHelper.ListCommonFontSizes(cbFontSize.Items);
end;
procedure THiliterPrefsFrame.StyleMenuClick(Sender: TObject);
{Click event handler for all predefined style menu item styles.
@param Sender [in] Menu item that triggered event.
}
begin
// Menu item's Tag property stores required style id
fAttrs := THiliteAttrsFactory.CreatePredefinedAttrs(
TPredefinedHiliteStyle((Sender as TMenuItem).Tag)
);
UpdateControls;
fChanged := True;
end;
function THiliterPrefsFrame.UIUpdated: Boolean;
begin
Result := fChanged;
end;
procedure THiliterPrefsFrame.UpdateControls;
{Updates state of controls and preview to reflect currently selected
highlighter element.
}
// Ticks or clears a check box without triggering an OnClick event. To fire
// event would mean that frame would be marked as changed when it should not
// be.
procedure SafeCheck(const CB: TCheckBox; const State: Boolean);
var
OnClickSave: TNotifyEvent;
begin
OnClickSave := CB.OnClick;
try
CB.OnClick := nil;
CB.Checked := State;
finally
CB.OnClick := OnClickSave;
end;
end;
var
Elem: IHiliteElemAttrs; // currently selected highlighter element
begin
Elem := CurrentElement;
cbFontName.ItemIndex := cbFontName.Items.IndexOf(fAttrs.FontName);
cbFontSize.Text := IntToStr(fAttrs.FontSize);
SafeCheck(chkBold, fsBold in Elem.FontStyle);
SafeCheck(chkItalics, fsItalic in Elem.FontStyle);
SafeCheck(chkUnderline, fsUnderline in Elem.FontStyle);
fColorBox.Selected := Elem.ForeColor;
UpdatePreview;
end;
procedure THiliterPrefsFrame.UpdatePreview;
{Updates preview of highlighting of current highlighter element.
}
begin
TRichEditHelper.Load(frmExample.RichEdit, GenerateRTF);
end;
initialization
// Register frame with preferences dialog box
TPreferencesDlg.RegisterPage(THiliterPrefsFrame);
end.
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.