unit SpTBXExtEditors; {============================================================================== Version 2.4.4 The contents of this file are subject to the SpTBXLib License; you may not use or distribute this file except in compliance with the SpTBXLib License. A copy of the SpTBXLib License may be found in SpTBXLib-LICENSE.txt or at: http://www.silverpointdevelopment.com/sptbxlib/SpTBXLib-LICENSE.htm Alternatively, the contents of this file may be used under the terms of the Mozilla Public License Version 1.1 (the "MPL v1.1"), in which case the provisions of the MPL v1.1 are applicable instead of those in the SpTBXLib License. A copy of the MPL v1.1 may be found in MPL-LICENSE.txt or at: http://www.mozilla.org/MPL/ If you wish to allow use of your version of this file only under the terms of the MPL v1.1 and not to allow others to use your version of this file under the SpTBXLib License, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the MPL v1.1. If you do not delete the provisions above, a recipient may use your version of this file under either the SpTBXLib License or the MPL v1.1. Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for the specific language governing rights and limitations under the License. The initial developer of this code is Robert Lee. Requirements: For Delphi/C++Builder 2009 or newer: - Jordan Russell's Toolbar 2000 http://www.jrsoftware.org For Delphi/C++Builder 7-2007: - Jordan Russell's Toolbar 2000 http://www.jrsoftware.org - Troy Wolbrink's TNT Unicode Controls http://www.tntware.com/delphicontrols/unicode/ Development notes: - All the Windows and Delphi bugs fixes are marked with '[Bugfix]'. - All the theme changes and adjustments are marked with '[Theme-Change]'. To Do: - Rotated caption painting. Known Issues: - History: 2 December 2009 - version 2.4.4 - No changes. 13 September 2009 - version 2.4.3 - Fixed incorrect TSpTBXColorEdit behavior, when the focus was changed the text wasn't validated, thanks to Stephan for reporting this. 8 May 2009 - version 2.4.2 - No changes. 15 March 2009 - version 2.4.1 - No changes. 17 January 2009 - version 2.4 - Initial release. ==============================================================================} interface {$BOOLEVAL OFF} // Unit depends on short-circuit boolean evaluation uses Windows, Messages, Classes, SysUtils, Controls, Graphics, ImgList, Forms, Menus, StdCtrls, ExtCtrls, SpTBXSkins, SpTBXItem, SpTBXEditors; type TSpTBXColorListBoxStyle = ( clbsStandardColors, // First 16 RGBI colors + 4 additional extended colors clbsSystemColors, // System colors clbsIncludeNone, // Include clNone color clbsIncludeDefault, // Include clDefault color clbsCustomColor, // First color is customizable clbsPrettyNames, // Draw text with pretty names clbsNoneAsTransparent // Draw clNone as transparent color ); TSpTBXColorListBoxStyles = set of TSpTBXColorListBoxStyle; { TSpTBXColorEditButton } TSpTBXColorEditButton = class(TSpTBXEditButton) private FSelectedColor: TColor; procedure SetSelectedColor(const Value: TColor); protected function DoDrawItem(ACanvas: TCanvas; ARect: TRect; const PaintStage: TSpTBXPaintStage): Boolean; override; function GetInternalDropDownMenu: TPopupMenu; override; public property SelectedColor: TColor read FSelectedColor write SetSelectedColor; end; { TSpTBXColorEdit } TSpTBXColorEdit = class(TSpTBXEdit) private FColorButton: TSpTBXColorEditButton; FSelectedFormat: TSpTBXColorTextType; FOnSelectedColorChanged: TNotifyEvent; function GetSelectedColor: TColor; procedure SetSelectedColor(const Value: TColor); procedure SetSelectedFormat(const Value: TSpTBXColorTextType); procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS; protected procedure KeyPress(var Key: Char); override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure DoSelectedColorChanged; virtual; procedure UpdateTextFromValue; procedure UpdateValueFromText(RevertWhenInvalid: Boolean = True); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property ColorButton: TSpTBXColorEditButton read FColorButton; published property Text stored False; property SelectedColor: TColor read GetSelectedColor write SetSelectedColor; property SelectedFormat: TSpTBXColorTextType read FSelectedFormat write SetSelectedFormat default cttIdentAndHTML; property OnSelectedColorChanged: TNotifyEvent read FOnSelectedColorChanged write FOnSelectedColorChanged; end; { TSpTBXFontComboBox } TSpTBXFontComboBoxPreview = class(TCustomControl) private FPreviewPanel: TPanel; protected procedure CreateParams(var Params: TCreateParams); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property PreviewPanel: TPanel read FPreviewPanel; end; TSpTBXFontComboBox = class(TSpTBXComboBox) private FFontPreview: Boolean; FFontNamePreview: Boolean; FMaxMRUItems: Integer; FMRUCount: Integer; FPreviewWindow: TSpTBXFontComboBoxPreview; FSelectedFont: TFontName; FOnFontPreview: TSpTBXEditGetTextEvent; procedure UpdateSelectedFont(AddMRU: Boolean); procedure SetFontNamePreview(const Value: Boolean); procedure SetSelectedFont(const Value: TFontName); procedure SetMaxMRUItems(Value: Integer); procedure SetFontPreview(const Value: Boolean); protected procedure Click; override; procedure CloseUp; override; procedure DoCalcMaxDropDownWidth; override; procedure DoDrawItem(ACanvas: TCanvas; var ARect: TRect; Index: Integer; const State: TOwnerDrawState; const PaintStage: TSpTBXPaintStage; var PaintDefault: Boolean); override; procedure DropDown; override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure MRUAdd(AFontName: TFontName); function MRUDelete(AFontName: TFontName): Boolean; property MRUCount: Integer read FMRUCount; published property Items stored False; property AutoDropDownWidth default True; property AutoItemHeight default False; property FontPreview: Boolean read FFontPreview write SetFontPreview default True; property FontNamePreview: Boolean read FFontNamePreview write SetFontNamePreview default True; property MaxMRUItems: Integer read FMaxMRUItems write SetMaxMRUItems default 5; property SelectedFont: TFontName read FSelectedFont write SetSelectedFont; property OnFontPreview: TSpTBXEditGetTextEvent read FOnFontPreview write FOnFontPreview; end; { TSpTBXColorListBox } TSpTBXColorListBox = class(TSpTBXListBox) private FItems: Boolean; FNeedToPopulate: Boolean; FSelectedColor: TColor; FStyle: TSpTBXColorListBoxStyles; procedure ColorCallBack(const AName: string); function GetColorName(Index: Integer): string; function GetColor(Index: Integer): TColor; function GetSelected: TColor; procedure SetSelected(const Value: TColor); procedure SetStyle(const Value: TSpTBXColorListBoxStyles); protected procedure CreateWnd; override; procedure Loaded; override; procedure DblClick; override; procedure KeyPress(var Key: Char); override; procedure DoDrawItem(ACanvas: TCanvas; var ARect: TRect; Index: Integer; const State: TOwnerDrawState; const PaintStage: TSpTBXPaintStage; var PaintDefault: Boolean); override; function PickCustomColor: Boolean; procedure PopulateList; public constructor Create(AOwner: TComponent); override; procedure AddColor(AColor: TColor; AColorName: string); function ColorCount: Integer; property Colors[Index: Integer]: TColor read GetColor; property ColorNames[Index: Integer]: string read GetColorName; published property Items: Boolean read FItems; // Hides inherited Items property property Selected: TColor read GetSelected write SetSelected default clBlack; property Style: TSpTBXColorListBoxStyles read FStyle write SetStyle default [clbsStandardColors, clbsSystemColors, clbsNoneAsTransparent]; // Hides inherited Style property end; { Helpers } procedure SpFillFontNames(ADest: TStrings); { Painting helpers } procedure SpDrawCheckeredBackground(ACanvas: TCanvas; ARect: TRect); procedure SpDrawColorDropDownButton(ACanvas: TCanvas; ARect: TRect; Pushed: Boolean; AColor: TColor; CheckeredBkgndWhenTransparent: Boolean = True); var FontGlyphImgList: TImageList = nil; implementation uses Dialogs, TB2Common, SpTBXFormPopupMenu, SpTBXColorPickerForm; var DefaultColorPickerDropDownMenu: TSpTBXColorEditPopupMenu = nil; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { Helpers } procedure SpFillFontNames(ADest: TStrings); // This will only work on Windows 2000 and above, more info on: // http://www.delphipraxis.net/post712587.html&sid=945c12fa9fb826d76e51c80b42109a21#712587 function EnumFontsProcWin9x(EnumLogFontEx: PEnumLogFontEx; NewTextMetric: PNewTextMetric; FontType: DWORD; LParam: LPARAM): Integer; stdcall; var S: string; GlyphIndex: Integer; L: TStrings; const NTM_PS_OPENTYPE = $00020000; NTM_TT_OPENTYPE = $00040000; begin L := TStrings(LParam); if FontType = TRUETYPE_FONTTYPE then GlyphIndex := 1 else GlyphIndex := 0; S := EnumLogFontEx.elfLogFont.lfFaceName; if (S[1] <> '@') then if (L.Count = 0) or not SameText(S, L[L.Count - 1]) then L.AddObject(S, Pointer(GlyphIndex)); Result := 1; end; function EnumFontsProc(EnumLogFontExDV: PEnumLogFontExDV; EnumTextMetric: PEnumTextMetric; FontType: DWORD; LParam: LPARAM): Integer; stdcall; var S: string; GlyphIndex: Integer; L: TStrings; const NTM_PS_OPENTYPE = $00020000; NTM_TT_OPENTYPE = $00040000; begin L := TStrings(LParam); GlyphIndex := 0; if ((EnumTextMetric.etmNewTextMetricEx.ntmTm.ntmFlags and NTM_TT_OPENTYPE) = NTM_TT_OPENTYPE) or ((EnumTextMetric.etmNewTextMetricEx.ntmTm.ntmFlags and NTM_PS_OPENTYPE) = NTM_PS_OPENTYPE) then GlyphIndex := 2 else if FontType = TRUETYPE_FONTTYPE then GlyphIndex := 1; S := EnumLogFontExDV.elfEnumLogfontEx.elfLogFont.lfFaceName; if (S[1] <> '@') then if (L.Count = 0) or not SameText(S, L[L.Count - 1]) then L.AddObject(S, Pointer(GlyphIndex)); Result := 1; end; var DC: HDC; LFont: TLogFont; L: TStringList; begin L := TStringList.Create; DC := GetDC(0); try FillChar(LFont, SizeOf(LFont), 0); LFont.lfCharset := DEFAULT_CHARSET; if Win32Platform = VER_PLATFORM_WIN32_WINDOWS then EnumFontFamiliesEx(DC, LFont, @EnumFontsProcWin9x, LongInt(L), 0) else EnumFontFamiliesEx(DC, LFont, @EnumFontsProc, LongInt(L), 0); L.Sort; ADest.Assign(L); finally ReleaseDC(0, DC); L.Free; end; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { Painting helpers } procedure SpDrawCheckeredBackground(ACanvas: TCanvas; ARect: TRect); // Draws a 2x2 white and silver checkered background var R: TRect; I, J, HCount, WCount: Integer; const Size = 2; begin WCount := (ARect.Right - ARect.Left) div Size; HCount := (ARect.Bottom - ARect.Top) div Size; for J := 0 to HCount do for I := 0 to WCount do begin R := Bounds(ARect.Left + (I * Size), ARect.Top + (J * Size), Size, Size); if R.Right > ARect.Right then R.Right := ARect.Right; if R.Bottom > ARect.Bottom then R.Bottom := ARect.Bottom; if (I + J) mod 2 = 0 then ACanvas.Brush.Color := clWhite else ACanvas.Brush.Color := clSilver; ACanvas.FillRect(R); end; end; procedure SpDrawColorDropDownButton(ACanvas: TCanvas; ARect: TRect; Pushed: Boolean; AColor: TColor; CheckeredBkgndWhenTransparent: Boolean); // Draws a button used for color editboxes var R: TRect; begin R := ARect; ACanvas.Brush.Color := clBtnFace; ACanvas.FillRect(R); if not Pushed then SpDrawRectangle(ACanvas, R, 0, clBtnHighlight, clBtnShadow); InflateRect(R, -2, -2); if (AColor = clNone) and CheckeredBkgndWhenTransparent then begin // Draw a checkered background when clNone is used SpDrawCheckeredBackground(ACanvas, R); end else begin ACanvas.Brush.Color := AColor; ACanvas.FillRect(R); end; SpDrawRectangle(ACanvas, R, 0, clBtnShadow, clBtnHighlight); R := ARect; R.Left := R.Right - 9; R.Top := R.Bottom - 7; ACanvas.Brush.Color := clBtnFace; ACanvas.FillRect(R); if Pushed then SpDrawRectangle(ACanvas, R, 0, clBtnHighlight, clBtnFace) else SpDrawRectangle(ACanvas, R, 0, clBtnHighlight, clBtnShadow); SpDrawArrow(ACanvas, R.Left + (R.Right - R.Left) div 2, R.Top + (R.Bottom - R.Top) div 2 - 1, clBlack, True, False, 2); R := ARect; InflateRect(R, -1, -1); SpDrawRectangle(ACanvas, R, 0, clBtnFace, clBtnFace); end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpTBXColorEditButton } function TSpTBXColorEditButton.DoDrawItem(ACanvas: TCanvas; ARect: TRect; const PaintStage: TSpTBXPaintStage): Boolean; begin if (PaintStage = pstPrePaint) and not BitmapValid then begin Result := True; if Assigned(OnDraw) then OnDraw(Self, ACanvas, ARect, PaintStage, Result); if Result then SpDrawColorDropDownButton(ACanvas, ARect, Pushed, FSelectedColor); end else Result := inherited DoDrawItem(ACanvas, ARect, PaintStage); end; function TSpTBXColorEditButton.GetInternalDropDownMenu: TPopupMenu; begin if Assigned(DropDownMenu) then Result := DropDownMenu else Result := DefaultColorPickerDropDownMenu; end; procedure TSpTBXColorEditButton.SetSelectedColor(const Value: TColor); begin if FSelectedColor <> Value then begin FSelectedColor := Value; Invalidate; if Owner is TSpTBXColorEdit then begin TSpTBXColorEdit(Owner).UpdateTextFromValue; TSpTBXColorEdit(Owner).DoSelectedColorChanged; end; end; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpTBXColorEdit } constructor TSpTBXColorEdit.Create(AOwner: TComponent); begin inherited; FSelectedFormat := cttIdentAndHTML; FColorButton := TSpTBXColorEditButton.Create(Self); FColorButton.Parent := Self; FColorButton.FreeNotification(Self); FColorButton.Align := alRight; FColorButton.Width := 19; UpdateEditRect; Text := 'clBlack'; end; destructor TSpTBXColorEdit.Destroy; begin FreeAndNil(FColorButton); inherited; end; procedure TSpTBXColorEdit.DoSelectedColorChanged; begin if Assigned(FOnSelectedColorChanged) then FOnSelectedColorChanged(Self); end; procedure TSpTBXColorEdit.KeyPress(var Key: Char); begin inherited; if Key = #13 then begin Key := #0; UpdateValueFromText; if FColorButton.IsDroppedDown and Assigned(ActiveFormPopupMenu) then ActiveFormPopupMenu.ClosePopup(False); end; end; procedure TSpTBXColorEdit.Notification(AComponent: TComponent; Operation: TOperation); begin inherited; if (AComponent = FColorButton) and (Operation = opRemove) then FColorButton := nil; end; function TSpTBXColorEdit.GetSelectedColor: TColor; begin Result := FColorButton.SelectedColor; end; procedure TSpTBXColorEdit.SetSelectedColor(const Value: TColor); begin FColorButton.SelectedColor := Value; end; procedure TSpTBXColorEdit.SetSelectedFormat(const Value: TSpTBXColorTextType); begin if FSelectedFormat <> Value then begin FSelectedFormat := Value; UpdateTextFromValue; end; end; procedure TSpTBXColorEdit.UpdateTextFromValue; begin if (SelectedColor = clNone) or (SelectedColor = clDefault) then Text := ColorToString(SelectedColor) else Text := SpColorToString(SelectedColor, FSelectedFormat); SelStart := Length(Text); end; procedure TSpTBXColorEdit.UpdateValueFromText(RevertWhenInvalid: Boolean = True); var WS: WideString; PrevValue, NewValue, C: TColor; begin PrevValue := SelectedColor; NewValue := SelectedColor; WS := Text; // Try to parse the text to get the value WS := Trim(WS); if SpStringToColor(WS, C) then NewValue := C; if RevertWhenInvalid or (NewValue <> PrevValue) then begin SetSelectedColor(NewValue); UpdateTextFromValue; end; end; procedure TSpTBXColorEdit.WMKillFocus(var Message: TWMKillFocus); begin inherited; UpdateValueFromText; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpTBXFontComboBoxPreview } constructor TSpTBXFontComboBoxPreview.Create(AOwner: TComponent); begin inherited; Visible := False; SetBounds(0, 0, 0, 0); Color := clWindow; FPreviewPanel := TPanel.Create(Self); FPreviewPanel.Parent := Self; FPreviewPanel.Color := clWindow; FPreviewPanel.BevelOuter := bvNone; FPreviewPanel.Align := alClient; end; procedure TSpTBXFontComboBoxPreview.CreateParams(var Params: TCreateParams); const CS_DROPSHADOW = $00020000; begin inherited; with Params do begin Style := (Style and not (WS_CHILD or WS_GROUP or WS_TABSTOP)) or WS_POPUP; ExStyle := ExStyle or WS_EX_TOPMOST or WS_EX_TOOLWINDOW; WindowClass.Style := WindowClass.Style or CS_SAVEBITS; if IsWindowsXP then WindowClass.Style := WindowClass.Style or CS_DROPSHADOW; end; end; destructor TSpTBXFontComboBoxPreview.Destroy; begin FreeAndNil(FPreviewPanel); inherited; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpTBXFontComboBox } constructor TSpTBXFontComboBox.Create(AOwner: TComponent); begin inherited Create(AOwner); FAutoDropDownWidthRightMargin := 60; FFontNamePreview := True; FFontPreview := True; FMaxMRUItems := 5; FMRUCount := 0; AutoItemHeight := False; AutoDropDownWidth := True; ItemHeight := 23; end; destructor TSpTBXFontComboBox.Destroy; begin FreeAndNil(FPreviewWindow); inherited; end; procedure TSpTBXFontComboBox.Click; begin UpdateSelectedFont(False); inherited; end; procedure TSpTBXFontComboBox.CloseUp; begin UpdateSelectedFont(True); inherited; FreeAndNil(FPreviewWindow); end; procedure TSpTBXFontComboBox.DropDown; var W: Integer; P: TPoint; Sz: TSize; WS: WideString; begin inherited; if FFontPreview then begin WS := 'AaBbYyZz'; FPreviewWindow := TSpTBXFontComboBoxPreview.Create(Self); FPreviewWindow.ParentWindow := Application.Handle; FPreviewWindow.PreviewPanel.Font.Size := 14; if Assigned(FOnFontPreview) then FOnFontPreview(Self, WS); FPreviewWindow.PreviewPanel.Caption := WS; Sz := SpGetControlTextSize(FPreviewWindow.PreviewPanel, FPreviewWindow.PreviewPanel.Font, WS); Inc(Sz.cx, 100); Inc(Sz.cy, 20); W := SendMessage(Handle, CB_GETDROPPEDWIDTH, 0, 0); P := Parent.ClientToScreen(Point(Left, Top)); if P.X + W + Sz.cx > Screen.Width then Dec(P.X, Sz.cx) else Inc(P.X, W); if P.Y + Height + Sz.cy > Screen.Height then Dec(P.Y, Sz.cy) else Inc(P.Y, Height); FPreviewWindow.SetBounds(P.X, P.Y, Sz.cx, Sz.cy); FPreviewWindow.Visible := True; ShowWindow(FPreviewWindow.Handle, SW_SHOWNA); end; end; procedure TSpTBXFontComboBox.DoCalcMaxDropDownWidth; begin if Items.Count <= 0 then begin {$IFNDEF UNICODE} SpFillFontNames(Items.AnsiStrings); {$ELSE} SpFillFontNames(Items); {$ENDIF} end; inherited; end; procedure TSpTBXFontComboBox.DoDrawItem(ACanvas: TCanvas; var ARect: TRect; Index: Integer; const State: TOwnerDrawState; const PaintStage: TSpTBXPaintStage; var PaintDefault: Boolean); var Flags, ImageIndex: Integer; R: TRect; const Spacing = 4; begin inherited DoDrawItem(ACanvas, ARect, Index, State, PaintStage, PaintDefault); if (PaintStage = pstPrePaint) and PaintDefault then begin PaintDefault := False; // Override the default painting // Draw the item glyph if the font is TrueType/OpenType R := ARect; R.Left := Spacing; R.Top := R.Top + ((R.Bottom - R.Top) - FontGlyphImgList.Height) div 2; ImageIndex := Integer(Items.Objects[Index]) - 1; if ImageIndex > -1 then FontGlyphImgList.Draw(ACanvas, R.Left, R.Top, ImageIndex); // Draw the item text R := ARect; R.Left := Spacing + FontGlyphImgList.Width + Spacing; if FFontNamePreview then ACanvas.Font.Name := Items[Index]; Flags := DrawTextBiDiModeFlags(DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX); SpDrawXPText(ACanvas, Items[Index], R, Flags); // Draw the MRU separator line if FMaxMRUItems > 0 then begin if Index = MRUCount - 1 then SpDrawLine(ACanvas, ARect.Left, ARect.Bottom - 1, ARect.Right, ARect.Bottom - 1, $C0C0C0); if Index = MRUCount then SpDrawLine(ACanvas, ARect.Left, ARect.Top, ARect.Right, ARect.Top, $C0C0C0); end; // Update the Font of the PreviewWindow if Assigned(FPreviewWindow) and (odSelected in State) then FPreviewWindow.PreviewPanel.Font.Name := Items[Index]; end; end; procedure TSpTBXFontComboBox.MRUAdd(AFontName: TFontName); var I, AFontNameIndex: Integer; begin AFontNameIndex := Items.IndexOf(AFontName); if (AFontNameIndex > -1) and (FMRUCount < Items.Count) and (FMaxMRUItems > 0) then begin // Exit if it's already on the list for I := 0 to FMRUCount - 1 do if SameText(AFontName, Items[I]) then Exit; // Add the font to the top and delete the last MRU item if necessary Items.InsertObject(0, Items[AFontNameIndex], Items.Objects[AFontNameIndex]); if FMRUCount >= FMaxMRUItems then Items.Delete(FMRUCount) else Inc(FMRUCount); end; end; function TSpTBXFontComboBox.MRUDelete(AFontName: TFontName): Boolean; var I: Integer; begin Result := False; for I := 0 to FMRUCount - 1 do if SameText(AFontName, Items[I]) then begin Items.Delete(I); Result := True; Break; end; end; procedure TSpTBXFontComboBox.SetMaxMRUItems(Value: Integer); begin if Value < 0 then Value := 0; if FMaxMRUItems <> Value then begin FMaxMRUItems := Value; while FMRUCount > FMaxMRUItems do begin Items.Delete(FMRUCount); Dec(FMRUCount); end; end; end; procedure TSpTBXFontComboBox.SetFontNamePreview(const Value: Boolean); begin if FFontNamePreview <> Value then begin FFontNamePreview := Value; Invalidate; end; end; procedure TSpTBXFontComboBox.SetFontPreview(const Value: Boolean); begin FFontPreview := Value; end; procedure TSpTBXFontComboBox.SetSelectedFont(const Value: TFontName); var I: Integer; begin I := Items.IndexOf(Value); if ItemIndex <> I then ItemIndex := I; UpdateSelectedFont(True); // If the Value is not valid clear the text and call the click events if I = -1 then begin Click; Select; end; end; procedure TSpTBXFontComboBox.UpdateSelectedFont(AddMRU: Boolean); var I: Integer; begin I := ItemIndex; if I > -1 then begin FSelectedFont := Items[I]; if AddMRU then MRUAdd(FSelectedFont); end else FSelectedFont := ''; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { TSpTBXColorListBox } constructor TSpTBXColorListBox.Create(AOwner: TComponent); begin inherited; FStyle := [clbsStandardColors, clbsSystemColors, clbsNoneAsTransparent]; FSelectedColor := clBlack; PopulateList; end; procedure TSpTBXColorListBox.CreateWnd; begin inherited CreateWnd; if FNeedToPopulate then PopulateList; end; procedure TSpTBXColorListBox.DblClick; begin inherited; if ItemIndex = 0 then PickCustomColor; end; procedure TSpTBXColorListBox.Loaded; begin inherited; Selected := FSelectedColor; if FNeedToPopulate then PopulateList; end; procedure TSpTBXColorListBox.AddColor(AColor: TColor; AColorName: string); begin (inherited Items).AddObject(AColorName, TObject(AColor)); end; procedure TSpTBXColorListBox.ColorCallBack(const AName: string); var I, LStart: Integer; LColor: TColor; LName: string; begin LColor := StringToColor(AName); if clbsPrettyNames in Style then begin if AName = 'clBtnFace' then LName := 'Button Face' else if AName = 'clBtnHighlight' then LName := 'Button Highlight' else if AName = 'clBtnShadow' then LName := 'Button Shadow' else if AName = 'clBtnText' then LName := 'Button Text' else if AName = 'clMedGray' then LName := 'Medium Gray' else if AName = 'clInfoBk' then LName := 'Info Background' else if AName = 'cl3DDkShadow' then LName := '3D Dark Shadow' else if AName = 'cl3DLight' then LName := '3D Light' else begin // Remove the 'cl' prefix and separate the words with a space if Copy(AName, 1, 2) = 'cl' then LStart := 3 else LStart := 1; LName := ''; for I := LStart to Length(AName) do begin case AName[I] of 'A'..'Z': if LName <> '' then LName := LName + ' '; end; LName := LName + AName[I]; end; end; end else LName := AName; AddColor(LColor, LName); end; function TSpTBXColorListBox.ColorCount: Integer; begin Result := (inherited Items).Count; end; procedure TSpTBXColorListBox.DoDrawItem(ACanvas: TCanvas; var ARect: TRect; Index: Integer; const State: TOwnerDrawState; const PaintStage: TSpTBXPaintStage; var PaintDefault: Boolean); var R: TRect; SavedBrushColor: TColor; begin if PaintStage = pstPrePaint then begin // Paint the color glyphs R := ARect; R.Right := R.Left + 16 + 5; ARect.Left := R.Right + 1; inherited DoDrawItem(ACanvas, ARect, Index, State, PaintStage, PaintDefault); if PaintDefault then begin SavedBrushColor := ACanvas.Brush.Color; try InflateRect(R, -1, -1); ACanvas.Brush.Color := Colors[Index]; if (ACanvas.Brush.Color = clNone) and (clbsNoneAsTransparent in Style) then SpDrawCheckeredBackground(ACanvas, R) else ACanvas.FillRect(R); if odSelected in State then ACanvas.Brush.Color := clWhite else ACanvas.Brush.Color := clBlack; ACanvas.FrameRect(R); finally ACanvas.Brush.Color := SavedBrushColor; end; end; end else inherited DoDrawItem(ACanvas, ARect, Index, State, PaintStage, PaintDefault); end; function TSpTBXColorListBox.GetColor(Index: Integer): TColor; begin Result := TColor((inherited Items).Objects[Index]); end; function TSpTBXColorListBox.GetColorName(Index: Integer): string; begin Result := (inherited Items)[Index]; end; function TSpTBXColorListBox.GetSelected: TColor; begin if HandleAllocated then if ItemIndex <> -1 then Result := Colors[ItemIndex] else Result := clNone else Result := FSelectedColor; end; procedure TSpTBXColorListBox.KeyPress(var Key: Char); begin inherited KeyPress(Key); if (clbsCustomColor in Style) and (Key = #13) and (ItemIndex = 0) then begin Key := #0; PickCustomColor; end; end; function TSpTBXColorListBox.PickCustomColor: Boolean; var LColor: TColor; CD: TColorDialog; begin Result := False; if not (clbsCustomColor in Style) then Exit; CD := TColorDialog.Create(nil); try LColor := ColorToRGB(Colors[0]); CD.Color := LColor; CD.CustomColors.Text := Format('ColorA=%.8x', [LColor]); CD.Options := CD.Options + [cdFullOpen]; Result := CD.Execute; if Result then begin (inherited Items).Objects[0] := TObject(CD.Color); Invalidate; end; finally CD.Free; end; end; procedure TSpTBXColorListBox.PopulateList; procedure DeleteRange(const AMin, AMax: Integer); var I: Integer; begin for I := AMax downto AMin do (inherited Items).Delete(I); end; procedure DeleteColor(const AColor: TColor); var I: Integer; begin I := (inherited Items).IndexOfObject(TObject(AColor)); if I <> -1 then (inherited Items).Delete(I); end; var LSelectedColor, LCustomColor: TColor; begin if HandleAllocated and not (csLoading in ComponentState) then begin (inherited Items).BeginUpdate; try // Get the custom color LCustomColor := clBlack; if (clbsCustomColor in Style) and ((inherited Items).Count > 0) then LCustomColor := TColor((inherited Items).Objects[0]); LSelectedColor := FSelectedColor; (inherited Items).Clear; GetColorValues(ColorCallBack); if not (clbsIncludeNone in Style) then DeleteColor(clNone); if not (clbsIncludeDefault in Style) then DeleteColor(clDefault); if not (clbsSystemColors in Style) then DeleteRange(StandardColorsCount + ExtendedColorsCount, (inherited Items).Count - 1); if not (clbsStandardColors in Style) then DeleteRange(0, StandardColorsCount + ExtendedColorsCount - 1); if clbsCustomColor in Style then (inherited Items).InsertObject(0, '...', TObject(LCustomColor)); Selected := LSelectedColor; finally (inherited Items).EndUpdate; FNeedToPopulate := False; end; end else FNeedToPopulate := True; end; procedure TSpTBXColorListBox.SetSelected(const Value: TColor); var I, J: Integer; begin if HandleAllocated then begin I := (inherited Items).IndexOfObject(TObject(Value)); if (I = -1) and (clbsCustomColor in Style) then begin // If the color is not on the list add it and select it (inherited Items).Objects[0] := TObject(Value); I := 0; end else if (clbsCustomColor in Style) and (I = 0) then begin // Try to find the color on the list before selecting the 1st custom color for J := 1 to (inherited Items).Count - 1 do if (inherited Items).Objects[J] = TObject(Value) then begin I := J; Break; end; end; if (ItemIndex = 0) and (I = 0) then Invalidate else ItemIndex := I; end; FSelectedColor := Value; end; procedure TSpTBXColorListBox.SetStyle(const Value: TSpTBXColorListBoxStyles); begin if Style <> Value then begin FStyle := Value; Enabled := ([clbsStandardColors, clbsSystemColors, clbsCustomColor] * FStyle) <> []; PopulateList; if (ColorCount > 0) and (ItemIndex = -1) then ItemIndex := 0; end; end; //WMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWMWM { Stock Objects } procedure InitializeStock; begin Screen.Cursors[crSpTBXEyeDropper] := LoadCursor(HInstance, 'CZEYEDROPPER'); FontGlyphImgList := TImageList.CreateSize(12, 12); FontGlyphImgList.ResInstLoad(HInstance, rtBitmap, 'SPTBXTRUETYPE', clFuchsia); FontGlyphImgList.ResInstLoad(HInstance, rtBitmap, 'SPTBXOPENTYPE', clFuchsia); DefaultColorPickerDropDownMenu := TSpTBXColorEditPopupMenu.Create(nil); end; procedure FinalizeStock; begin FreeAndNil(FontGlyphImgList); FreeAndNil(DefaultColorPickerDropDownMenu); end; initialization InitializeStock; finalization FinalizeStock; end.