tomboy-ng_0.34-1/ 0000755 0001750 0001750 00000000000 14145033543 013415 5 ustar dbannon dbannon tomboy-ng_0.34-1/kcontrols/ 0000755 0001750 0001750 00000000000 14145033543 015433 5 ustar dbannon dbannon tomboy-ng_0.34-1/kcontrols/source/ 0000755 0001750 0001750 00000000000 14145033543 016733 5 ustar dbannon dbannon tomboy-ng_0.34-1/kcontrols/source/kfunctions.pas 0000644 0001750 0001750 00000237716 14125207534 021644 0 ustar dbannon dbannon { @abstract(This file is part of the KControls component suite for Delphi and Lazarus.)
@author(Tomas Krysl)
Copyright (c) 2020 Tomas Krysl
License:
This code is licensed under BSD 3-Clause Clear License, see file License.txt or https://spdx.org/licenses/BSD-3-Clause-Clear.html.
}
unit kfunctions; // lowercase name because of Lazarus/Linux
{$include kcontrols.inc}
{$WEAKPACKAGEUNIT ON}
interface
uses
{$IFDEF FPC}
{$IFDEF MSWINDOWS}
Windows,
{$ELSE}
{$IF DEFINED(UNIX) and (FPC_FULLVERSION>=20701)}
UnixCP,
{$IFEND}
{$ENDIF}
LazUTF8,
{$ELSE}
Windows, Messages,
{$ENDIF}
Classes, Contnrs, SysUtils;
const
{ Carriage return character. }
cCR = #13;
{ Line feed character. }
cLF = #10;
{ TAB character. }
cTAB = #9;
{ SPACE character. }
cSPACE = #32;
{ String terminator. }
cNULL = #0;
{ Set of word break characters. }
cWordBreaks = [cNULL, cTAB, cSPACE];
{ Set of line break characters. }
cLineBreaks = [cCR, cLF];
{ Text ellipsis string. }
cEllipsis = '...';
{ Alphabetic letters. }
cLetters = ['a'..'z', 'A'..'Z'];
{ Number. }
cNumbers = ['0'..'9'];
{$IFnDEF FPC}
lcl_fullversion = 0;
{$ENDIF}
{$IFDEF MSWINDOWS}
{ @exclude }
SHFolderDll = 'SHFolder.dll';
{$ENDIF}
{$IFDEF UNIX}
cEOL = cLF;
cFirstEOL = cLF;
{$ELSE}
cEOL = cCR + cLF;
cFirstEOL = cCR;
{$ENDIF}
{$IFDEF MSWINDOWS}
cDirectoryDelimiter = '\';
{$ELSE}
cDirectoryDelimiter = '/';
{$ENDIF}
cUTF16FirstSurrogateBegin = $D800;
cUTF16FirstSurrogateEnd = $DBFF;
cUTF16SecondSurrogateBegin = $DC00;
cUTF16SecondSurrogateEnd = $DFFF;
cHexFmtText = '%.2x';
cHexBase = 16;
cHexDigitCount = 2;
type
//PInteger = ^Integer; defined by System.pas
{ Static array for Integer. }
TIntegers = array[0..MaxInt div SizeOf(Integer) - 1] of Integer;
{ Pointer for TIntegers. }
PIntegers = ^TIntegers;
{ Dynamic array for Integer. }
TDynIntegers = array of Integer;
//PCardinal = ^Cardinal; defined by System.pas
{ Static array for Cardinal. }
TCardinals = array[0..MaxInt div SizeOf(Cardinal) - 1] of Cardinal;
{ Pointer for TCardinals. }
PCardinals = ^TCardinals;
{ Dynamic array for Cardinal. }
TDynCardinals = array of Cardinal;
//PShortInt = ^ShortInt; defined by System.pas
{ Static array for ShortInt. }
TShortInts = array[0..MaxInt div SizeOf(ShortInt) - 1] of ShortInt;
{ Pointer for TShortInts. }
PShortInts = ^TShortInts;
{ Dynamic array for ShortInt. }
TDynShortInts = array of ShortInt;
//PSmallInt = ^SmallInt; defined by System.pas
{ Static array for SmallInt. }
TSmallInts = array[0..MaxInt div SizeOf(SmallInt) - 1] of SmallInt;
{ Pointer for TSmallInts. }
PSmallInts = ^TSmallInts;
{ Dynamic array for SmallInt. }
TDynSmallInts = array of SmallInt;
//PLongInt = ^LongInt; defined by System.pas
{ Static array for LongInt. }
TLongInts = array[0..MaxInt div SizeOf(LongInt) - 1] of LongInt;
{ Pointer for TLongInts. }
PLongInts = ^TLongInts;
{ Dynamic array for LongInt. }
TDynLongInts = array of LongInt;
//PInt64 = ^Int64; defined by System.pas
{ Static array for Int64. }
TInt64s = array[0..MaxInt div SizeOf(Int64) - 1] of Int64;
{ Pointer for TInt64s. }
PInt64s = ^TInt64s;
{ Dynamic array for Int64. }
TDynInt64s = array of Int64;
//PByte = ^Byte; defined by System.pas
{ Static array for Byte. }
TBytes = array[0..MaxInt div SizeOf(Byte) - 1] of Byte;
{ Pointer for TBytes. }
PBytes = ^TBytes;
{ Dynamic array for Byte. }
TDynBytes = array of Byte;
//PWord = ^Word; defined by System.pas
{ Static array for Word. }
TWords = array[0..MaxInt div SizeOf(Word) - 1] of Word;
{ Pointer for TWords. }
PWords = ^TWords;
{ Dynamic array for Word. }
TDynWords = array of Word;
//PLongWord = ^LongWord; defined by System.pas
{ Static array for LongWord. }
TLongWords = array[0..MaxInt div SizeOf(LongWord) - 1] of LongWord;
{ Pointer for TLongWords. }
PLongWords = ^TLongWords;
{ Dynamic array for LongWord. }
TDynLongWords = array of LongWord;
{$IF DEFINED(COMPILER10_UP) OR DEFINED(FPC)}
{$IFDEF FPC}
PUInt64 = ^UInt64;
{$ELSE}
//PUInt64 = ^UInt64; defined by System.pas
{$ENDIF}
{ Static array for UInt64. }
TUInt64s = array[0..MaxInt div SizeOf(UInt64) - 1] of UInt64;
{ Pointer for TUInt64s. }
PUInt64s = ^TUInt64s;
{ Dynamic array for UInt64. }
TDynUInt64s = array of UInt64;
{$IFEND}
//PSingle = ^Single; defined by System.pas
{ Static array for Single. }
TSingles = array[0..MaxInt div SizeOf(Single) - 1] of Single;
{ Pointer for TSingles. }
PSingles = ^TSingles;
{ Dynamic array for Single. }
TDynSingles = array of Single;
//PDouble = ^Double; defined by System.pas
{ Static array for Double. }
TDoubles = array[0..MaxInt div SizeOf(Double) - 1] of Double;
{ Pointer for TDoubles. }
PDoubles = ^TDoubles;
{ Dynamic array for Double. }
TDynDoubles = array of Double;
{$IFNDEF FPC}
//PExtended = ^Extended; defined by System.pas
{ Static array for Extended. }
TExtendeds = array[0..MaxInt div SizeOf(Extended) - 1] of Extended;
{ Pointer for TExtendeds. }
PExtendeds = ^TExtendeds;
{ Dynamic array for Extended. }
TDynExtendeds = array of Extended;
{$ENDIF}
//PChar is special type
{ Static array for Char. }
TChars = array[0..MaxInt div SizeOf(Char) - 1] of Char;
{ Pointer for TChars. }
PChars = ^TChars;
{ Dynamic array for Char. }
TDynChars = array of Char;
//PAnsiChar is special type
{ Static array for AnsiChar. }
TAnsiChars = array[0..MaxInt div SizeOf(AnsiChar) - 1] of AnsiChar;
{ Pointer for TChars. }
PAnsiChars = ^TAnsiChars;
{ Dynamic array for Char. }
TDynAnsiChars = array of AnsiChar;
PBoolean = ^Boolean;
{ Static array for Double. }
TBooleans = array[0..MaxInt div SizeOf(Boolean) - 1] of Boolean;
{ Pointer for TBooleans. }
PBooleans = ^TBooleans;
{ Dynamic array for Double. }
TDynBooleans = array of Boolean;
{$IFDEF FPC}
{ TKString is UTF8 string in Lazarus. }
TKString = string;
{ TKChar is UTF8 character in Lazarus. }
TKChar = string[7]; // UTF-8 character is at most 6 bytes plus a #0
{ PKChar is pointer to UTF8 character in Lazarus. }
PKChar = ^TKChar;
{ PKText is PChar (null terminated UTF8 string) in Lazarus. }
PKText = PChar;
{$ELSE}
{$IFDEF STRING_IS_UNICODE}
{ TKString is UnicodeString (UTF16) in unicode aware Delphi. }
TKString = string;
{ TKChar is Char in unicode aware Delphi. }
TKChar = Char;
{ PKChar is pointer to Char in unicode aware Delphi. }
PKChar = ^Char;
{ PKText is PChar in unicode aware Delphi. }
PKText = PChar;
{$ELSE}
{ TKString is WideString in old non-unicode Delphi versions. }
TKString = WideString;
{ TKChar is WideChar in old non-unicode Delphi versions. }
TKChar = WideChar;
{ PKChar is pointer to WideChar in old non-unicode Delphi versions. }
PKChar = ^WideChar;
{ PKText is PWideChar in old non-unicode Delphi versions. }
PKText = PWideChar;
{$ENDIF}
{$ENDIF}
{ Useful structure to handle general data and size as a single item }
TDataSize = record
Data: Pointer;
Size: Int64;
end;
{ Pointer for TDataSize }
PDataSize = ^TDataSize;
{ Set type for @link(CharInSetEx). }
TKSysCharSet = set of AnsiChar;
{ Defines a currency format settings for @link(FormatCurrency). }
TKCurrencyFormat = record
CurrencyFormat,
CurrencyDecimals: Byte;
CurrencyString: TKString;
DecimalSep: Char;
ThousandSep: Char;
UseThousandSep: Boolean;
end;
{ @abstract(Declares a structure that holds both column and row span of a cell)
Members:
- ColSpan - column span.
- RowSpan - row span.
}
TKCellSpan = record
ColSpan: Integer;
RowSpan: Integer;
end;
{ @abstract(Declares a structure that holds point coordinates as 64-bit wide integers)
Members:
- X - X coord.
- Y - Y coord.
}
TKPoint64 = record
X, Y: Int64;
end;
{ Pointer }
PKPoint64 = ^TKPoint64;
{ @abstract(Declares a structure that holds rectangle coordinates as 64-bit wide integers)
Members:
- Left - left coord.
- Right - right coord.
- Top - top coord.
- Bottom - bottom coord.
}
TKRect64 = record
Left, Right, Top, Bottom: Int64;
end;
{ Pointer }
PKRect64 = ^TKRect64;
{ @abstract(Declares the digit position in a hex string)
Members:
- Index - byte index
- Digit - digit index
}
TKHexDigitPosition = record
Index: Int64;
Digit: Integer;
end;
TKLogType = (
lgNone,
lgError,
lgWarning,
lgNote,
lgHint,
lgInfo,
lgInputError,
lgIOError,
lgAll
);
TKObjectList = class;
TKObject = class(TObject)
private
FParent: TKObjectList;
procedure SetParent(const Value: TKObjectList);
protected
FUpdateLock: Integer;
procedure CallBeforeUpdate; virtual;
procedure CallAfterUpdate; virtual;
procedure ParentChanged; virtual;
public
constructor Create; virtual;
procedure Assign(ASource: TKObject); virtual;
function EqualProperties(AValue: TKObject): Boolean; virtual;
procedure LockUpdate; virtual;
procedure UnLockUpdate; virtual;
function UpdateUnlocked: Boolean; virtual;
property Parent: TKObjectList read FParent write SetParent;
end;
TKObjectClass = class of TKObject;
TKObjectList = class(TObjectList)
protected
FUpdateLock: Integer;
procedure CallBeforeUpdate; virtual;
procedure CallAfterUpdate; virtual;
public
constructor Create; virtual;
function Add(AObject: TObject): Integer;
procedure Assign(ASource: TKObjectList); virtual;
function EqualProperties(AValue: TKObjectList): Boolean; virtual;
procedure Insert(Index: Integer; AObject: TObject);
procedure LockUpdate; virtual;
procedure UnLockUpdate; virtual;
function UpdateUnlocked: Boolean; virtual;
end;
TKPersistent = class(TPersistent)
private
FChanged: Boolean;
FUpdateLock: Integer;
protected
{ Call in property setters to track changes to this class. }
procedure Changed;
{ Override to perform requested actions when changing properties in this class.
Update will be called either immediately when you call Changed or on next
UnlockUpdate call if Changed has been called while updating was locked. }
procedure Update; virtual; abstract;
public
{ Creates the instance. }
constructor Create; virtual;
{ Locks updating. Use this if you assign many properties at the
same time. Every LockUpdate call must have a corresponding
@link(TKPersistent.UnlockUpdate) call, please use a try-finally section. }
procedure LockUpdate;
{ Unlocks page setup updating and updates the page settings.
Each @link(TKPersistent.LockUpdate) call must be always followed
by the UnlockUpdate call. }
procedure UnlockUpdate(ACallUpdate: Boolean = True);
{ Returns True if updating is not locked, i.e. there is no open
LockUpdate and UnlockUpdate pair. }
function UpdateUnlocked: Boolean;
property UpdateLock: Integer read FUpdateLock;
end;
{ Replaces possible decimal separators in S with DecimalSeparator variable.}
function AdjustDecimalSeparator(const S: string): string;
{ Converts an AnsiString into a TKString. If CodePage is not set
the current system code page for ANSI-UTFx translations will be used. }
function AnsiStringToString(const Text: AnsiString; CodePage: Cardinal = 0): TKString;
{$IFNDEF FPC}
function AnsiStringToWideChar(const Text: AnsiString; CodePage: Cardinal = 0): PWideChar;
{$ENDIF}
type
{ Callback for binary search data item comparison. }
TBsCompareProc = function(Data: Pointer; Index: Integer; KeyPtr: Pointer): Integer;
{ Performs binary search on previously sorted data given by AData and ACount.
KeyPtr is the pointer to the key which is passed to the ACompareProc.
The items are compared by CompareProc callback. Returns the zero based index
of the matched data or -1 if no match has been found. }
function BinarySearch(AData: Pointer; ACount: Integer; KeyPtr: Pointer;
ACompareProc: TBSCompareProc; ASortedDown: Boolean): Integer;
{ Compiler independent Delphi2009-like CharInSet function for ANSI characters. }
function CharInSetEx(AChar: AnsiChar; const ASet: TKSysCharSet): Boolean; overload;
{ Compiler independent Delphi2009-like CharInSet function for Unicode characters. }
function CharInSetEx(AChar: WideChar; const ASet: TKSysCharSet): Boolean; overload;
{ Compares two Integers. Returns 1 if I1 > I2, -1 if I1 < I2 and 0 if I1 = I2. }
function CompareIntegers(I1, I2: Integer): Integer;
{ Compares two PWideChar strings. Returns 1 if W1 > W2, -1 if W1 < W2 and
0 if W1 = W2. The strings will be compared using the default user locale
unless another locale has been specified in Locale. }
function CompareWideChars(W1, W2: PWideChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer;
{$IFDEF STRING_IS_UNICODE}
{ Compares two Unicode strings (Lazarus, Delphi 2009 and better). Returns 1 if S1 > S2,
-1 if S1 < S2 and 0 if S1 = S2. The strings will be compared using the default
user locale unless another locale has been specified in Locale. }
function CompareChars(S1, S2: PChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer;
{$ENDIF}
{ Compares two WideString strings. Returns 1 if W1 > W2, -1 if W1 < W2 and
0 if W1 = W2. The strings will be compared using the default user locale
unless another locale has been specified in Locale. }
function CompareWideStrings(W1, W2: WideString{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer;
{$IFDEF STRING_IS_UNICODE}
{ Compares two Unicode strings (Lazarus, Delphi 2009 and better). Returns 1 if S1 > S2,
-1 if S1 < S2 and 0 if S1 = S2. The strings will be compared using the default
user locale unless another locale has been specified in Locale. }
function CompareStrings(S1, S2: string{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal = LOCALE_USER_DEFAULT{$ENDIF}): Integer;
{$ENDIF}
{ Converts tab characters in a string to space characters. }
procedure ConvertTabsToSpaces(var AText: TKString; ASpacesForTab: Integer);
{ Creates given directory, even if more folders have to be created. }
function CreateMultipleDir(const Dir: string): Boolean;
{ Converts hexadecimal digit to nibble. }
function DigitToNibble(Digit: AnsiChar; var Nibble: Byte): Boolean;
{ Performs integer division. If there is a nonzero remainder,
the result will be incremented. }
function DivUp(Dividend, Divisor: Integer): Integer;
{ Performs 64-bit integer division. If there is a nonzero remainder,
the result will be incremented. }
function DivUp64(Dividend, Divisor: Int64): Int64;
{ Performs integer division. If there is a nonzero remainder,
the result will be decremented. }
function DivDown(Dividend, Divisor: Integer): Integer;
{ Performs 64-bit integer division. If there is a nonzero remainder,
the result will be decremented. }
function DivDown64(Dividend, Divisor: Int64): Int64;
{ Ensures the path given by APath has slash at the end. }
procedure EnsureLastPathSlash(var APath: string);
{ Ensures the path given by APath has slash at the end. }
function EnsureLastPathSlashFnc(const APath: string): string;
{ Raises a general exception with associated message Msg. }
procedure Error(const Msg: string);
{ Swaps values of two SmallInt variables. }
procedure Exchange(var Value1, Value2: SmallInt); overload;
{ Swaps values of two ShortInt variables. }
procedure Exchange(var Value1, Value2: ShortInt); overload;
{ Swaps values of two Integer variables. }
procedure Exchange(var Value1, Value2: Integer); overload;
{ Swaps values of two Int64 variables. }
procedure Exchange(var Value1, Value2: Int64); overload;
{ Swaps values of two Byte variables. }
procedure Exchange(var Value1, Value2: Byte); overload;
{ Swaps values of two Word variables. }
procedure Exchange(var Value1, Value2: Word); overload;
{ Swaps values of two Cardinal variables. }
procedure Exchange(var Value1, Value2: Cardinal); overload;
{$IFDEF COMPILER10_UP }
{ Swaps values of two UInt64 variables. }
procedure Exchange(var Value1, Value2: UInt64); overload;
{$ENDIF}
{ Swaps values of two Single variables. }
procedure Exchange(var Value1, Value2: Single); overload;
{ Swaps values of two Double variables. }
procedure Exchange(var Value1, Value2: Double); overload;
{$IFNDEF FPC}
{ Swaps values of two Extended variables. }
procedure Exchange(var Value1, Value2: Extended); overload;
{$ENDIF}
{ Swaps values of two Char variables. }
procedure Exchange(var Value1, Value2: Char); overload;
{ Returns file name without path and extension. }
function ExtractFileRawName(const APath: string): string;
{ Formats the given currency value with to specified parameters. Not thread safe. }
function FormatCurrency(Value: Currency; const AFormat: TKCurrencyFormat): TKString;
{ Returns the module version for given module. Tested under WinX, Linux, OSX. }
function GetAppVersion(const ALibName: string; out MajorVersion, MinorVersion, BuildNumber, RevisionNumber: Word): Boolean;
{ Returns the module version string for given module. Tested under WinX, Linux, OSX. }
function GetAppVersionString(const ALibName, ACodePage, AString: string; out AValue: string): Boolean;
{ Returns number of a specific character in a string. }
function GetCharCount(const AText: TKString; AChar: TKChar): Integer;
{ Returns the standard locale dependent format settings. }
function GetFormatSettings: TFormatSettings;
{ Converts an integer into binary string with custom alignment
(given by Digits). }
function IntToAscii(Value: Int64; Digits: Integer): string;
{ Converts an integer into binary digit string with custom alignment
(given by Digits) and suffix. }
function IntToBinStr(Value: Int64; Digits: Integer; const Suffix: string): string;
{ Converts an integer value into BCD number. }
function IntToBCD(Value: Cardinal): Cardinal;
{ Converts a signed integer into decimal digit string with custom alignment
(given by Digits). }
function IntToDecStr(Value: Int64; Digits: Integer = 0): string;
{ Converts a unsigned integer into decimal digit string with custom alignment
(given by Digits). }
function UIntToDecStr(Value: UInt64; Digits: Integer = 0): string;
{ Converts an integer into hexadecimal digit string with custom alignment
(given by Digits), prefix and suffix. Digits represented by alphabetical
characters can be either in lower or upper case. }
function IntToHexStr(Value: Int64; Digits: Integer; const Prefix, Suffix: string;
UseLowerCase: Boolean): string;
{ Converts an integer into octal digit string. }
function IntToOctStr(Value: Int64): string;
{ Converts an integer into roman number. }
function IntToRoman(Value: Integer; AUpperCase: Boolean): string;
{ Converts an integer into latin alphabetic numbering. }
function IntToLatin(Value: Integer; AUpperCase: Boolean): string;
{ Calculates an integer power from an integer number. }
function IntPowerInt(Value: Int64; Exponent: Integer): Int64;
{ Converts a binary string into integer with custom alignment (given by Digits). }
function AsciiToInt(S: string; Digits: Integer): Int64;
{ Converts a BCD number into integer value. }
function BCDToInt(Value: Cardinal): Cardinal;
{ Converts a binary digit string into integer with custom alignment
(given by Digits) and sign of a value represented by the string (given by Signed).
Code returns either zero for a successful conversion or the position of
first bad character. }
function BinStrToInt(S: string; Digits: Integer; Signed: Boolean;
var Code: Integer): Int64;
{ Converts a decimal digit string into integer. Code returns either zero for
a successful conversion or the position of first bad character. Equals to Val. }
function DecStrToInt(S: string; var Code: Integer): Int64;
{ Converts a hexadecimal digit string into integer with custom alignment
(given by Digits) and sign of a value represented by the string (given by Signed).
Code returns either zero for a successful conversion or the position of
first bad character. }
function HexStrToInt(S: string; Digits: Integer; Signed: Boolean;
var Code: Integer): Int64;
{ Converts an octal digit string into integer. Code returns either zero for
a successful conversion or the position of first bad character. }
function OctStrToInt(S: string; var Code: Integer): Int64;
{ Calls SysUtils.Format. }
function KFormat(const Format: string; const Args: array of const;
const AFormatSettings: TFormatSettings): string; overload;
{ Calls SysUtils.WideFormat. }
function KFormat(const Format: WideString; const Args: array of const;
const AFormatSettings: TFormatSettings): WideString; overload;
{ Makes a @link(TKCellSpan) record from AColumns and ARows. }
function MakeCellSpan(AColumns, ARows: Integer): TKCellSpan;
{ Returns a clipped ShortInt value so that it lies between Min and Max }
function MinMax(Value, Min, Max: ShortInt): ShortInt; overload;
{ Returns a clipped SmallInt value so that it lies between Min and Max }
function MinMax(Value, Min, Max: SmallInt): SmallInt; overload;
{ Returns a clipped Integer value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Integer): Integer; overload;
{ Returns a clipped Int64 value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Int64): Int64; overload;
{ Returns a clipped Single value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Single): Single; overload;
{ Returns a clipped Double value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Double): Double; overload;
{$IFNDEF FPC}
{ Returns a clipped Extended value so that it lies between Min and Max }
function MinMax(Value, Min, Max: Extended): Extended; overload;
{$ENDIF}
{ Fill the data & size structure. }
function MakeDataSize(AData: Pointer; ASize: Integer): TDataSize;
{ Converts nibble to hexadecimal digit. }
function NibbleToDigit(Nibble: Byte; UpperCase: Boolean): AnsiChar;
type
{ Callback for quicksort data item comparison. }
TQsCompareProc = function(Data: Pointer; Index1, Index2: Integer): Integer;
{ Callback for quicksort data item exchange. }
TQsExchangeProc = procedure(Data: Pointer; Index1, Index2: Integer);
{ Sorts Count number of items by means of a non recursive quicksort algorithm.
The items are compared by CompareProc callback and sorted by
ExchangeProc callback. }
procedure QuickSortNR(AData: Pointer; ACount: Integer; ACompareProc: TQsCompareProc;
AExchangeProc: TQsExchangeProc; ASortedDown: Boolean);
{ Sorts Count number of items by means of a recursive quicksort algorithm.
The items are compared by CompareProc callback and sorted by
ExchangeProc callback. }
procedure QuickSort(AData: Pointer; ACount: Integer; ACompareProc: TQsCompareProc;
AExchangeProc: TQsExchangeProc; ASortedDown: Boolean);
{ Add AX and AY to APoint. }
procedure OffsetPoint(var APoint: TPoint; AX, AY: Integer); overload;
{ Add AOffset to APoint. }
procedure OffsetPoint(var APoint: TPoint; const AOffset: TPoint); overload;
{ Normalizes the given input rectangle. }
function NormalizeRect(const ARect: TRect): TRect;
{ Create 64-bit point structure. }
function Point64(AX, AY: Int64): TKPoint64;
{ Convert point structure to 64-bit point structure. }
function PointToPoint64(const APoint: TPoint): TKPoint64;
{ Convert point structure to 64-bit point structure. }
function Point64ToPoint(const APoint: TKPoint64): TPoint;
{ Examines if APoint lies within ARect. }
function Pt64InRect(const ARect: TRect; const APoint: TKPoint64): Boolean;
{ Create 64-bit rectangle structure. }
function Rect64(ALeft, ATop, ARight, ABottom: Int64): TKRect64;
{ Examines if some part of Rect lies within Bounds. }
function RectInRect(Bounds, Rect: TRect): Boolean;
{ Examines if Rect lies fully within Bounds. }
function RectInRectFully(Bounds, Rect: TRect): Boolean;
{ Add AX and AY to ARect. }
procedure OffsetRect(var ARect: TRect; AX, AY: Integer); overload;
{ Add AOffset to ARect. }
procedure OffsetRect(var ARect: TRect; const AOffset: TPoint); overload;
{ Ensures the path given by APath has no slash at the end. }
procedure StripLastPathSlash(var APath: string);
{ Ensures the path given by APath has no slash at the end. }
function StripLastPathSlashFnc(const APath: string): string;
{ Returns next character index for given string and character index.
Takes MBCS (UTF16 in Delphi and UTF8 in Lazarus) into account. }
function StrNextCharIndex(const AText: TKString; Index: Integer): Integer;
{ Returns previous character index for given string and character index.
Takes MBCS (UTF16 in Delphi and UTF8 in Lazarus) into account. }
function StrPreviousCharIndex(const AText: TKString; Index: Integer): Integer;
{ Converts byte index to code point index for given string and byte index.
Takes MBCS (UTF16 in Delphi and UTF8 in Lazarus) into account. }
function StrByteIndexToCPIndex(const AText: TKString; ByteIndex: Integer): Integer;
{ Converts code point index to byte index for given string and code point index.
Takes MBCS (UTF16 in Delphi and UTF8 in Lazarus) into account. }
function StrCPIndexToByteIndex(const AText: TKString; CPIndex: Integer): Integer;
{ Returns the index for given string where character at given index begins.
Takes MBCS (UTF16 in Delphi and UTF8 in Lazarus) into account. }
function StringCharBegin(const AText: TKString; Index: Integer): Integer;
{ Returns the number of characters in a string.
Takes MBCS (UTF16 in Delphi and UTF8 in Lazarus) into account. }
function StringLength(const AText: TKString): Integer;
{ Performs standard Copy operation.
Takes MBCS (UTF16 in Delphi and UTF8 in Lazarus) into account. }
function StringCopy(const ASource: TKString; At, Count: Integer): TKString;
{ Performs standard Delete operation.
Takes MBCS (UTF16 in Delphi and UTF8 in Lazarus) into account. }
procedure StringDelete(var ASource: TKString; At, Count: Integer);
{ Trims characters specified by ASet from the beginning and end of AText.
New text length is returned by ALen. }
procedure TrimWhiteSpaces(const AText: TKString; var AStart, ALen: Integer; const ASet: TKSysCharSet); overload;
{ Trims characters specified by ASet from the beginning and end of AText. }
procedure TrimWhiteSpaces(var AText: TKString; const ASet: TKSysCharSet); overload;
{$IFNDEF FPC}
{ Trims characters specified by ASet from the beginning and end of AText. }
procedure TrimWhiteSpaces(var AText: AnsiString; const ASet: TKSysCharSet); overload;
{$ENDIF}
{ Converts a TKString into AnsiString. If CodePage is not set
the current system code page for ANSI-UTFx translations will be used. }
function StringToAnsiString(const AText: TKString; CodePage: Cardinal = 0): AnsiString;
function StringToUTF8(const AText: string): AnsiString;
{ Converts specified character of TKString into TKChar. }
function StringToChar(const AText: TKString; AIndex: Integer): TKChar;
{$IFDEF MSWINDOWS}
function GetWindowsFolder(CSIDL: Cardinal; var APath: string): Boolean;
function RunExecutable(const AFileName: string; AWaitForIt: Boolean): DWORD;
{$ENDIF}
function SystemCodePage: Integer;
function NativeUTFToUnicode(const AText: TKString): WideChar;
function UnicodeUpperCase(const AText: TKString): TKString;
function UnicodeLowerCase(const AText: TKString): TKString;
function UnicodeToNativeUTF(const AParam: WideChar): TKString;
function UnicodeStringReplace(const AText, AOldPattern, ANewPattern: TKString;
AFlags: TReplaceFlags): TKString;
function UTF8ToString(const AText: AnsiString): string;
{ Creates a selection structure from given Index and Digit parameters }
function MakeHexDigitPosition(Index: Int64; Digit: Integer): TKHexDigitPosition;
{ Converts a hexadecimal digit character ('0'..'F') to binary value }
function DigitToBin(Value: AnsiChar): Integer;
{ Examines/converts hexadecimal digit string to binary value string. Returns
True if the digit string is valid.
Parameters:
- S - hexadecimal digit string (e.g. 'AF01 DC05 3'). White spaces will
be ignored. When Convert is True, the converted binary value string will be returned
via this parameter (in this exammple '#A#F#0#1#D#C#0#5#3').
- Convert - the digit string will be converted if True, otherwise it will
be examined only.
}
function DigitsToBinStr(var S: AnsiString; Convert: Boolean = True): Boolean;
{ Converts a binary value string into binary data. If the binary value string
is not divisible by 2, it will be right padded with zero. Example:
'#A#F#0#1#D#C#0#5#3' is converted into '#AF#01#DC#05#30'. }
function BinStrToBinary(const S: AnsiString): AnsiString;
{ Converts binary value (0..15) to hexadecimal digit character ('0'..'F') }
function BinToDigit(Value: Byte): AnsiChar;
{ Converts binary data into hexadecimal digit string.
Parameters:
- Buffer - binary data - intended for @link(TKCustomHexEditor.Buffer)
- SelStart, SelEnd - specifies which part of the buffer is about to be
converted. SelStart.Index must be lower or equal to SelEnd.Index - intended for
@link(TKCustomHexEditor.GetRealSelStart) and @link(TKCustomHexEditor.GetRealSelEnd).
Example: '#AF#01#DC#05#30' is converted into 'AF01DC0530'.
If AInsertSpaces is True then resulting string is 'AF 01 DC 05 30'. }
function BinaryToDigits(Buffer: PBytes; SelStart, SelEnd: TKHexDigitPosition;
AInsertSpaces: Boolean = False): AnsiString; overload;
{ Convertes binary data into hexadecimal digit string. Entire data used. }
function BinaryToDigits(Buffer: PBytes; ASize: Int64;
AInsertSpaces: Boolean = False): AnsiString; overload;
{ Convertes binary data into hexadecimal digit string. Uses AnsiString as source data. }
function BinaryToDigits(const Source: AnsiString;
AInsertSpaces: Boolean = False): AnsiString; overload;
{ Converts a binary value string into hexadecimal digit string. If the binary value string
is not divisible by 2, it will be trimmed. Example:
'#A#F#0#1#D#C#0#5#3' is converted into 'AF01DC05'.
If AInsertSpaces is True then resulting string is 'AF 01 DC 05'. }
function BinStrToDigits(const Source: AnsiString;
AInsertSpaces: Boolean = False): AnsiString;
{ Insert spaces into hexadecimal digit string.
Example: 'AF01DC05' becomes 'AF 01 DC 05'. }
function InsertSpacesToDigits(const Source: AnsiString): AnsiString;
{ Replaces a hexadecimal digit in the given binary value. Returns the original
value with a replaced digit.
Parameters:
- Value - original binary value
- Digit - digit value (0..15)
- Pos - digit position (order)
Example: Value = $A18D, Digit = $C, Pos = 3: Result = $AC8D }
function ReplaceDigit(Value, Digit, Pos: Integer): Integer;
implementation
uses
Math, TypInfo
{$IFDEF FPC}
, versionresource
{$ENDIF}
{$IFDEF USE_WIDEWINPROCS}
, KWideWinProcs
{$ENDIF}
{$IFDEF FPC}
, LConvEncoding
{$ENDIF}
;
{ TKObject }
constructor TKObject.Create;
begin
inherited;
FParent := nil;
FUpdateLock := 0;
end;
procedure TKObject.Assign(ASource: TKObject);
begin
end;
procedure TKObject.CallAfterUpdate;
begin
end;
procedure TKObject.CallBeforeUpdate;
begin
end;
function TKObject.EqualProperties(AValue: TKObject): Boolean;
begin
Result := True;
end;
procedure TKObject.LockUpdate;
begin
if FUpdateLock <= 0 then
CallBeforeUpdate;
Inc(FUpdateLock);
end;
procedure TKObject.ParentChanged;
begin
end;
procedure TKObject.SetParent(const Value: TKObjectList);
begin
if Value <> FParent then
begin
FParent := Value;
ParentChanged;
end;
end;
procedure TKObject.UnLockUpdate;
begin
if FUpdateLock > 0 then
begin
Dec(FUpdateLock);
if FUpdateLock = 0 then
CallAfterUpdate;
end;
end;
function TKObject.UpdateUnlocked: Boolean;
begin
Result := FUpdateLock <= 0;
end;
{ TKObjectList }
constructor TKObjectList.Create;
begin
inherited;
FUpdateLock := 0;
end;
function TKObjectList.Add(AObject: TObject): Integer;
begin
if AObject is TKObject then
TKObject(AObject).Parent := Self;
Result := inherited Add(AObject);
end;
procedure TKObjectList.Assign(ASource: TKObjectList);
var
I: Integer;
Cls: TKObjectClass;
SrcItem, DstItem: TKObject;
begin
if ASource <> nil then
begin
Clear;
for I := 0 to ASource.Count - 1 do
begin
SrcItem := ASource.Items[I] as TKObject;
Cls := TKObjectClass(SrcItem.ClassType);
DstItem := Cls.Create;
DstItem.Parent := Self;
DstItem.Assign(SrcItem);
Add(DstItem);
end;
end;
end;
procedure TKObjectList.CallBeforeUpdate;
begin
end;
procedure TKObjectList.CallAfterUpdate;
begin
end;
function TKObjectList.EqualProperties(AValue: TKObjectList): Boolean;
var
I: Integer;
begin
Result := False;
if AValue <> nil then
begin
Result := AValue.Count = Count;
if Result then
begin
for I := 0 to Count - 1 do
if not TKObject(Items[I]).EqualProperties(TKObject(AValue[I])) then
begin
Result := False;
Break;
end;
end;
end;
end;
procedure TKObjectList.Insert(Index: Integer; AObject: TObject);
begin
if AObject is TKObject then
TKObject(AObject).Parent := Self;
inherited Insert(Index, AObject);
end;
procedure TKObjectList.LockUpdate;
begin
if FUpdateLock <= 0 then
CallBeforeUpdate;
Inc(FUpdateLock);
end;
procedure TKObjectList.UnLockUpdate;
begin
if FUpdateLock > 0 then
begin
Dec(FUpdateLock);
if FUpdateLock = 0 then
CallAfterUpdate;
end;
end;
function TKObjectList.UpdateUnlocked: Boolean;
begin
Result := FUpdateLock <= 0;
end;
{ TKPersistent }
constructor TKPersistent.Create;
begin
inherited;
FUpdateLock := 0;
FChanged := False;
end;
procedure TKPersistent.Changed;
begin
if FUpdateLock = 0 then
Update
else
FChanged := True;
end;
procedure TKPersistent.LockUpdate;
begin
Inc(FUpdateLock);
FChanged := False;
end;
procedure TKPersistent.UnlockUpdate(ACallUpdate: Boolean);
begin
if FUpdateLock > 0 then
begin
Dec(FUpdateLock);
if (FUpdateLock = 0) and FChanged and ACallUpdate then
Update;
end;
end;
function TKPersistent.UpdateUnlocked: Boolean;
begin
Result := FUpdateLock = 0;
end;
function AdjustDecimalSeparator(const S: string): string;
var
I: Integer;
begin
Result := S;
for I := 1 to Length(Result) do
if CharInSetEx(Result[I], [',', '.']) then
Result[I] := GetFormatSettings.DecimalSeparator;
end;
function AnsiStringToString(const Text: AnsiString; CodePage: Cardinal): TKString;
var
{$IFDEF FPC}
CP: string;
{$ELSE}
Len: Integer;
{$ENDIF}
begin
{$IFDEF FPC}
if CodePage = 0 then
CP := 'ansi'
else
CP := Format('cp%d', [Codepage]);
Result := LConvEncoding.ConvertEncoding(Text, CP, 'utf8');
{$ELSE}
Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(Text), -1, nil, 0);
SetLength(Result, Len shr 1);
MultiByteToWideChar(CodePage, 0, PAnsiChar(Text), -1, PWideChar(Result), Len);
{$ENDIF}
end;
{$IFNDEF FPC}
function AnsiStringToWideChar(const Text: AnsiString; CodePage: Cardinal): PWideChar;
var
Len: Integer;
begin
Len := MultiByteToWideChar(CodePage, 0, PAnsiChar(Text), -1, nil, 0);
GetMem(Result, Len shl 1);
MultiByteToWideChar(CodePage, 0, PAnsiChar(Text), -1, Result, Len);
end;
{$ENDIF}
function BinarySearch(AData: Pointer; ACount: Integer; KeyPtr: Pointer;
ACompareProc: TBsCompareProc; ASortedDown: Boolean): Integer;
var
Lo, Hi, Index, Ret: Integer;
begin
Result := -1;
Lo := 0;
Hi := ACount - 1;
repeat
Index := (Lo + Hi) div 2;
Ret := ACompareProc(AData, Index, KeyPtr);
if ASortedDown and (Ret < 0) or not ASortedDown and (Ret > 0) then
Hi := Index - 1
else
Lo := Index + 1
until (Lo > Hi) or (Ret = 0);
if Ret = 0 then
Result := Index;
end;
function CharInSetEx(AChar: AnsiChar; const ASet: TKSysCharSet): Boolean;
begin
Result := AChar in ASet;
end;
function CharInSetEx(AChar: WideChar; const ASet: TKSysCharSet): Boolean;
begin
Result := (Ord(AChar) < $100) and
{$IFDEF COMPILER12_UP}
CharInSet(AChar, ASet);
{$ELSE}
(AnsiChar(AChar) in ASet);
{$ENDIF}
end;
function CompareIntegers(I1, I2: Integer): Integer;
begin
if I1 > I2 then Result := 1
else if I1 < I2 then Result := -1
else Result := 0;
end;
function CompareWideChars(W1, W2: PWideChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer;
begin
if (W1 = nil) or (W2 = nil) then
begin
if W1 <> nil then Result := 1
else if W2 <> nil then Result := -1
else Result := 0;
end else
begin
{$IFDEF USE_WIDEWINPROCS}
Result := WideWinProcs.CompareString(Locale, 0, W1, -1, W2, -1);
Dec(Result, 2);
{$ELSE}
Result := WideCompareStr(WideString(W1), WideString(W2));
{$ENDIF}
end;
end;
{$IFDEF STRING_IS_UNICODE}
function CompareChars(S1, S2: PChar{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer;
begin
if (S1 = nil) or (S2 = nil) then
begin
if S1 <> nil then Result := 1
else if S2 <> nil then Result := -1
else Result := 0;
end else
begin
{$IFDEF USE_WIDEWINPROCS}
Result := WideWinProcs.CompareString(Locale, 0, PWideChar(S1), -1, PWideChar(S2), -1);
Dec(Result, 2);
{$ELSE}
Result := CompareStr(string(S1), string(S2));
{$ENDIF}
end;
end;
{$ENDIF}
function CompareWideStrings(W1, W2: WideString{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer;
begin
{$IFDEF USE_WIDEWINPROCS}
Result := WideWinProcs.CompareString(Locale, 0, PWideChar(W1), -1, PWideChar(W2), -1);
Dec(Result, 2);
{$ELSE}
Result := WideCompareStr(W1, W2);
{$ENDIF}
end;
{$IFDEF STRING_IS_UNICODE}
function CompareStrings(S1, S2: string{$IFDEF USE_WIDEWINPROCS}; Locale: Cardinal{$ENDIF}): Integer;
begin
{$IFDEF USE_WIDEWINPROCS}
Result := WideWinProcs.CompareString(Locale, 0, PWideChar(S1), -1, PWideChar(S2), -1);
Dec(Result, 2);
{$ELSE}
Result := CompareStr(S1, S2);
{$ENDIF}
end;
{$ENDIF}
procedure ConvertTabsToSpaces(var AText: TKString; ASpacesForTab: Integer);
var
TabCount: Integer;
S: TKString;
I, J, K: Integer;
begin
if ASpacesForTab >= 0 then
begin
TabCount := GetCharCount(AText, cTAB);
if TabCount > 0 then
begin
SetLength(S, Length(AText) + (ASpacesForTab - 1) * TabCount);
J := 1;
for I := 1 to Length(AText) do
begin
if AText[I] = cTAB then
begin
for K := 0 to ASpacesForTab - 1 do
begin
S[J] := cSPACE;
Inc(J);
end;
end else
begin
S[J] := AText[I];
Inc(J);
end;
end;
AText := S;
end;
end;
end;
function CreateMultipleDir(const Dir: string): Boolean;
var
I: Integer;
T: string;
begin
for I := 1 to Length(Dir) do
begin
if CharInSetEx(Dir[I], ['/', '\']) then
begin
T := Copy(Dir, 1, I - 1);
if not (DirectoryExists(T) or CreateDir(T)) then Break;
end;
end;
if not DirectoryExists(Dir) then
CreateDir(Dir);
Result := DirectoryExists(Dir);
end;
function DigitToNibble(Digit: AnsiChar; var Nibble: Byte): Boolean;
begin
Result := True;
if (Digit >= '0') and (Digit <= '9') then
Nibble := Ord(Digit) - Ord('0')
else if (Digit >= 'a') and (Digit <= 'f') then
Nibble := Ord(Digit) - Ord('a') + 10
else if (Digit >= 'A') and (Digit <= 'F') then
Nibble := Ord(Digit) - Ord('A') + 10
else
Result := False;
end;
function DivUp(Dividend, Divisor: Integer): Integer;
begin
if Divisor = 0 then
Result := 0
else if Dividend mod Divisor > 0 then
Result := Dividend div Divisor + 1
else
Result := Dividend div Divisor;
end;
function DivUp64(Dividend, Divisor: Int64): Int64;
begin
if Divisor = 0 then
Result := 0
else if Dividend mod Divisor > 0 then
Result := Dividend div Divisor + 1
else
Result := Dividend div Divisor;
end;
function DivDown(Dividend, Divisor: Integer): Integer;
begin
if Divisor = 0 then
Result := 0
else if Dividend mod Divisor < 0 then
Result := Dividend div Divisor - 1
else
Result := Dividend div Divisor;
end;
function DivDown64(Dividend, Divisor: Int64): Int64;
begin
if Divisor = 0 then
Result := 0
else if Dividend mod Divisor < 0 then
Result := Dividend div Divisor - 1
else
Result := Dividend div Divisor;
end;
procedure EnsureLastPathSlash(var APath: string);
begin
if APath <> '' then
if not CharInSetEx(APath[Length(APath)], ['\', '/']) then APath := APath + cDirectoryDelimiter;
end;
function EnsureLastPathSlashFnc(const APath: string): string;
begin
Result := APath;
EnsureLastPathSlash(Result);
end;
procedure Exchange(var Value1, Value2: ShortInt);
var
Tmp: ShortInt;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: SmallInt);
var
Tmp: SmallInt;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Integer);
var
Tmp: Integer;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Int64);
var
Tmp: Int64;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Byte);
var
Tmp: Byte;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Word);
var
Tmp: Word;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Cardinal);
var
Tmp: Cardinal;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
{$IFDEF COMPILER10_UP }
procedure Exchange(var Value1, Value2: UINT64);
var
Tmp: UINT64;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
{$ENDIF}
procedure Exchange(var Value1, Value2: Single);
var
Tmp: Single;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
procedure Exchange(var Value1, Value2: Double);
var
Tmp: Double;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
{$IFNDEF FPC}
procedure Exchange(var Value1, Value2: Extended);
var
Tmp: Extended;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
{$ENDIF}
procedure Exchange(var Value1, Value2: Char);
var
Tmp: Char;
begin
Tmp := Value1;
Value1 := Value2;
Value2 := Tmp;
end;
function ExtractFileRawName(const APath: string): string;
var
I: Integer;
begin
Result := ExtractFileName(APath);
I := Length(Result);
while I > 1 do
begin
if Result[I] = '.' then
begin
SetLength(Result, I - 1);
Break;
end;
Dec(I);
end;
end;
procedure Error(const Msg: string);
begin
raise Exception.Create(Msg);
end;
function FormatCurrency(Value: Currency; const AFormat: TKCurrencyFormat): TKString;
var
Fmt: string;
FS: TFormatSettings;
begin
if AFormat.UseThousandSep then
begin
FS.ThousandSeparator := AFormat.ThousandSep;
Fmt := '%.*n';
end else
Fmt := '%.*f';
FS.DecimalSeparator := AFormat.DecimalSep;
case AFormat.CurrencyFormat of
0: Result := KFormat('%s' + Fmt, [AFormat.CurrencyString, AFormat.CurrencyDecimals, Value], FS);
1: Result := KFormat(Fmt + '%s', [AFormat.CurrencyDecimals, Value, AFormat.CurrencyString], FS);
2: Result := KFormat('%s ' + Fmt, [AFormat.CurrencyString, AFormat.CurrencyDecimals, Value], FS);
else
Result := KFormat(Fmt + ' %s', [AFormat.CurrencyDecimals, Value, AFormat.CurrencyString], FS);
end;
end;
function GetAppVersion(const ALibName: string; out MajorVersion, MinorVersion, BuildNumber, RevisionNumber: Word): Boolean;
var
{$IFDEF FPC}
Info: TVersionResource;
Stream: TResourceStream;
ResID: Integer;
Res: TFPResourceHandle;
{$ELSE}
dwHandle, dwLen: DWORD;
BufLen: Cardinal;
lpData: LPTSTR;
pFileInfo: ^VS_FIXEDFILEINFO;
{$ENDIF}
begin
Result := False;
{$IFDEF FPC}
Info := TVersionResource.Create;
try
ResID := 1;
// Defensive code to prevent failure if no resource available...
Res := FindResource(HInstance, PChar(PtrInt(ResID)), PChar(RT_VERSION));
If Res = 0 Then
Exit;
Stream := TResourceStream.CreateFromID(HInstance, ResID, {$IFDEF LCLWinCE}PWideChar{$ELSE}PChar{$ENDIF}(RT_VERSION));
Try
Info.SetCustomRawDataStream(Stream);
MajorVersion := Info.FixedInfo.FileVersion[0];
MinorVersion := Info.FixedInfo.FileVersion[1];
BuildNumber := Info.FixedInfo.FileVersion[2];
RevisionNumber := Info.FixedInfo.FileVersion[3];
Info.SetCustomRawDataStream(nil);
Finally
Stream.Free;
End;
Result := True;
finally
Info.Free;
end;
{$ELSE}
dwLen := GetFileVersionInfoSize(PChar(ALibName), dwHandle);
if dwLen <> 0 then
begin
GetMem(lpData, dwLen);
try
if GetFileVersionInfo(PChar(ALibName), dwHandle, dwLen, lpData) then
begin
if VerQueryValue(lpData, '\\', Pointer(pFileInfo), BufLen) then
begin
MajorVersion := HIWORD(pFileInfo.dwFileVersionMS);
MinorVersion := LOWORD(pFileInfo.dwFileVersionMS);
BuildNumber := HIWORD(pFileInfo.dwFileVersionLS);
RevisionNumber := LOWORD(pFileInfo.dwFileVersionLS);
Result := True;
end;
end;
finally
FreeMem(lpData);
end;
end;
{$ENDIF}
end;
function GetAppVersionString(const ALibName, ACodePage, AString: string; out AValue: string): Boolean;
{$IFnDEF FPC}
type
TTranslation = packed record
wLanguage: Word;
wCodePage: Word;
end;
{$ENDIF}
var
{$IFDEF FPC}
Info: TVersionResource;
Stream: TResourceStream;
ResID: Integer;
Res: TFPResourceHandle;
{$ELSE}
dwHandle, dwLen: DWORD;
BufLen: Cardinal;
lpData: LPTSTR;
pValue: Pointer;
Translation: ^TTranslation;
CP: string;
Tmp: WideString;
{$ENDIF}
begin
Result := False;
{$IFDEF FPC}
Info := TVersionResource.Create;
try
ResID := 1;
// Defensive code to prevent failure if no resource available...
Res := FindResource(HInstance, PChar(PtrInt(ResID)), PChar(RT_VERSION));
If Res = 0 Then
Exit;
Stream := TResourceStream.CreateFromID(HInstance, ResID, {$IFDEF LCLWinCE}PWideChar{$ELSE}PChar{$ENDIF}(RT_VERSION));
Try
Info.SetCustomRawDataStream(Stream);
if Info.StringFileInfo.Count > 0 then
begin
AValue := Info.StringFileInfo.Items[0].Values[AString];
Result := True;
end;
Info.SetCustomRawDataStream(nil);
Finally
Stream.Free;
End;
finally
Info.Free;
end;
{$ELSE}
dwLen := GetFileVersionInfoSize(PChar(ALibName), dwHandle);
if dwLen <> 0 then
begin
GetMem(lpData, dwLen);
try
if GetFileVersionInfo(PChar(ALibName), dwHandle, dwLen, lpData) then
begin
if ACodePage = '' then
begin
// retrieve first codepage available
if VerQueryValue(lpData, '\VarFileInfo\Translation', Pointer(Translation), BufLen) and (BufLen >= 4) then
CP := Format('%4.4x%4.4x', [Translation.wLanguage, Translation.wCodePage])
else
CP := ''; // error!
end else
CP := ACodePage;
if (CP <> '') and (VerQueryValue(lpData, PChar(Format('\StringFileInfo\%s\%s', [CP, AString])), pValue, BufLen)) then
begin
SetString(Tmp, PChar(pValue), BufLen);
AValue := string(Tmp);
Result := True;
end;
end;
finally
FreeMem(lpData);
end;
end;
{$ENDIF}
end;
function GetCharCount(const AText: TKString; AChar: TKChar): Integer;
var
I: Integer;
begin
Result := 0;
for I := 1 to Length(AText) do
if AText[I] = AChar then
Inc(Result);
end;
function GetFormatSettings: TFormatSettings;
begin
{$IFDEF FPC}
Result := FormatSettings;
{$ELSE}
{$IFDEF COMPILER15_UP}
Result := TFormatSettings.Create;
{$ELSE}
GetLocaleFormatSettings(GetThreadLocale, Result);
{$ENDIF}
{$ENDIF}
end;
function IntToAscii(Value: Int64; Digits: Integer): string;
var
I: Integer;
begin
Result := '';
I := 0;
while I < Digits do
begin
Result := Result + Chr(Value and $FF);
Value := Value shr 8;
Inc(I);
end;
end;
function IntToBCD(Value: Cardinal): Cardinal;
var
Exp: Cardinal;
begin
Result := 0;
Exp := 1;
while (Value > 0) and (Exp > 0) do
begin
Result := Result + Value mod 10 * Exp;
Value := Value div 10;
Exp := Exp * 16;
end;
end;
function IntToBinStr(Value: Int64; Digits: Integer; const Suffix: string): string;
var
B: Byte;
C: Char;
begin
Result := '';
if Digits <> 0 then
Digits := MinMax(Digits, 1, 64);
repeat
B := Byte(Value and $1);
Value := Value shr 1;
C := Chr(Ord('0') + B);
Result := C + Result;
until (Value = 0) or ((Digits <> 0) and (Length(Result) = Digits));
while Length(Result) < Digits do
Result := '0' + Result;
Result := Result + Suffix;
end;
function IntToDecStr(Value: Int64; Digits: Integer): string;
var
B: Byte;
C: Char;
Signum: Boolean;
begin
Result := '';
Signum := Value < 0;
{if Signum then
asm
nop
end;}
repeat
B := Byte(Value mod 10);
if Signum then
B := 256 - B;
Value := Value div 10;
C := Chr(Ord('0') + B);
Result := C + Result;
until Value = 0;
while Length(Result) < Digits do
Result := '0' + Result;
if Signum then
Result := '-' + Result;
end;
function UIntToDecStr(Value: UInt64; Digits: Integer): string;
var
B: Byte;
C: Char;
begin
Result := '';
repeat
B := Byte(Value mod 10);
Value := Value div 10;
C := Chr(Ord('0') + B);
Result := C + Result;
until Value = 0;
while Length(Result) < Digits do
Result := '0' + Result;
end;
function IntToHexStr(Value: Int64; Digits: Integer; const Prefix, Suffix: string; UseLowerCase: Boolean): string;
var
B: Byte;
begin
Result := '';
if Digits <> 0 then
Digits := MinMax(Digits, 1, 16);
repeat
B := Byte(Value and $F);
Value := Value shr 4;
Result := Char(NibbleToDigit(B, not UseLowerCase)) + Result;
until (Value = 0) or ((Digits <> 0) and (Length(Result) = Digits));
while Length(Result) < Digits do
Result := '0' + Result;
Result := Prefix + Result + Suffix;
end;
function IntToOctStr(Value: Int64): string;
var
B: Byte;
C: Char;
Signum: Boolean;
begin
if Value < 0 then
begin
Signum := True;
Value := -Value;
end else
Signum := False;
Result := '';
repeat
B := Byte(Value mod 8);
Value := Value div 8;
C := Chr(Ord('0') + B);
Result := C + Result;
until Value = 0;
Result := '0' + Result;
if Signum then
Result := '-' + Result;
end;
function IntToRoman(Value: Integer; AUpperCase: Boolean): string;
begin
Result := '';
while Value >= 1000 do begin
Result := Result + 'M';
Value := Value - 1000;
end; { while }
if Value >= 900 then begin
Result := Result + 'CM';
Value := Value - 900;
end; { if }
while Value >= 500 do begin
Result := Result + 'D';
Value := Value - 500;
end; { while }
if Value >= 400 then begin
Result := Result + 'CD';
Value := Value - 400;
end; { if }
while Value >= 100 do begin
Result := Result + 'C';
Value := Value - 100;
end; { while }
if Value >= 90 then begin
Result := Result + 'XC';
Value := Value - 90;
end; { if }
while Value >= 50 do begin
Result := Result + 'L';
Value := Value - 50;
end; { while }
if Value >= 40 then begin
Result := Result + 'XL';
Value := Value - 40;
end; { while }
while Value >= 10 do begin
Result := Result + 'X';
Value := Value - 10;
end; { while }
if Value >= 9 then begin
Result := Result + 'IX';
Value := Value - 9;
end; { if }
while Value >= 5 do begin
Result := Result + 'V';
Value := Value - 5;
end; { while }
if Value >= 4 then begin
Result := Result + 'IV';
Value := Value - 4;
end; { if }
while Value > 0 do begin
Result := Result + 'I';
Dec(Value);
end; { while }
if not AUpperCase then
Result := LowerCase(Result);
end;
function IntToLatin(Value: Integer; AUpperCase: Boolean): string;
var
OrdA: Integer;
begin
Result := '';
if AUpperCase then
OrdA := Ord('A')
else
OrdA := Ord('a');
while Value > 0 do
begin
Result := Chr(Value mod 26 + OrdA - 1) + Result;
Value := Value div 26;
end;
end;
function IntPowerInt(Value: Int64; Exponent: Integer): Int64;
begin
Result := Value;
while Exponent > 1 do
begin
Result := Result * Value;
Dec(Exponent);
end;
end;
function AsciiToInt(S: string; Digits: Integer): Int64;
var
I: Integer;
begin
Result := 0;
I := Min(Length(S), Digits);
while I > 0 do
begin
Result := Result shl 8;
Result := Ord(S[I]) + Result;
Dec(I);
end;
end;
function BCDToInt(Value: Cardinal): Cardinal;
var
Exp: Cardinal;
begin
Result := 0;
Exp := 1;
while Value > 0 do
begin
Result := Result + Min(Value and 15, 9) * Exp;
Value := Value shr 4;
Exp := Exp * 10;
end;
end;
function BinStrToInt(S: string; Digits: Integer; Signed: Boolean; var Code: Integer): Int64;
var
I, L, Len: Integer;
N: Byte;
C: Char;
M: Int64;
begin
Result := 0;
Code := 0;
L := 0;
Len := Length(S);
if (Digits = 0) or (Digits > 64) then
Digits := 64;
if (Len >= 1) and CharInSetEx(S[Len], ['b', 'B']) then
begin
Delete(S, Len, 1);
Dec(Len);
end;
I := 1;
while I <= Len do
begin
C := S[I];
N := 255;
if (C >= '0') and (C <= '1') then N := Ord(C) - Ord('0');
if N > 1 then
begin
Code := I;
Break;
end
else if (N > 0) or (Result <> 0) then
begin
if L >= Digits then
begin
Code := I;
Break;
end;
Result := Result shl 1;
Inc(Result, N);
Inc(L);
end;
Inc(I);
end;
if Signed and (Digits < 64) then
begin
M := Int64(1) shl Digits;
if Result >= M shr 1 - 1 then
Dec(Result, M);
end;
end;
function DecStrToInt(S: string; var Code: Integer): Int64;
var
I, Len: Integer;
N: Byte;
C: Char;
Minus: Boolean;
begin
Result := 0;
Code := 0;
Len := Length(S);
Minus := S[1] = '-';
if Minus then I := 2 else I := 1;
while I <= Len do
begin
C := S[I];
N := 255;
if (C >= '0') and (C <= '9') then N := Ord(C) - Ord('0');
if N > 9 then
begin
Code := I;
Break;
end
else if (N > 0) or (Result <> 0) then
begin
Result := Result * 10;
Inc(Result, N);
end;
Inc(I);
end;
if Minus then Result := -Result;
end;
function HexStrToInt(S: string; Digits: Integer; Signed: Boolean; var Code: Integer): Int64;
var
I, L, Len: Integer;
N: Byte;
C: AnsiChar;
M: Int64;
begin
Result := 0;
Code := 0;
L := 0;
Len := Length(S);
if (Digits = 0) or (Digits > 16) then
Digits := 16;
if (Len >= 2) and (AnsiChar(S[1]) = '0') and CharInSetEx(S[2], ['x', 'X']) then
I := 3
else if (Len >= 1) and CharInSetEx(S[1], ['x', 'X', '$']) then
I := 2
else
I := 1;
while I <= Len do
begin
C := AnsiChar(S[I]);
N := 255;
DigitToNibble(C, N);
if N > 15 then
begin
if CharInSetEx(C, ['h', 'H']) then
begin
if Len > I then Code := I + 1;
end else
Code := I;
Break;
end
else if (N > 0) or (Result <> 0) then
begin
if L >= Digits then
begin
Code := I;
Break;
end;
Result := Result shl 4;
Inc(Result, N);
Inc(L);
end;
Inc(I);
end;
if Signed and (Digits < 16) then
begin
M := Int64(1) shl (Digits shl 2);
if Result >= M shr 1 - 1 then
Dec(Result, M);
end;
end;
function OctStrToInt(S: string; var Code: Integer): Int64;
var
I, Len: Integer;
N: Byte;
C: Char;
Minus: Boolean;
begin
Result := 0;
Code := 0;
Len := Length(S);
Minus := S[1] = '-';
if Minus then I := 2 else I := 1;
while I <= Len do
begin
C := S[I];
N := 255;
if (C >= '0') and (C <= '7') then N := Ord(C) - Ord('0');
if N > 7 then
begin
Code := I;
Break;
end
else if (N > 0) or (Result <> 0) then
begin
Result := Result * 8;
Inc(Result, N);
end;
Inc(I);
end;
if Minus then Result := -Result;
end;
function KFormat(const Format: string; const Args: array of const; const AFormatSettings: TFormatSettings): string;
begin
Result := SysUtils.Format(Format, Args, AFormatSettings);
end;
function KFormat(const Format: WideString; const Args: array of const; const AFormatSettings: TFormatSettings): WideString;
begin
Result := SysUtils.WideFormat(Format, Args, AFormatSettings);
end;
function MakeCellSpan(AColumns, ARows: Integer): TKCellSpan;
begin
Result.ColSpan := AColumns;
Result.RowSpan := ARows;
end;
function MinMax(Value, Min, Max: ShortInt): ShortInt;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: SmallInt): SmallInt;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: Integer): Integer;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: Int64): Int64;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: Single): Single;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
function MinMax(Value, Min, Max: Double): Double;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
{$IFNDEF FPC}
function MinMax(Value, Min, Max: Extended): Extended;
begin
if Max < Min then
Exchange(Min, Max);
if Value <= Max then
if Value >= Min then
Result := Value
else
Result := Min
else
Result := Max;
end;
{$ENDIF}
function MakeDataSize(AData: Pointer; ASize: Integer): TDataSize;
begin
Result.Data := AData;
Result.Size := ASize;
end;
function NibbleToDigit(Nibble: Byte; UpperCase: Boolean): AnsiChar;
begin
if Nibble < 10 then
Result := AnsiChar(Ord('0') + Nibble)
else if UpperCase then
Result := AnsiChar(Ord('A') + Nibble - 10)
else
Result := AnsiChar(Ord('a') + Nibble - 10);
end;
procedure QuickSortNR(AData: Pointer; ACount: Integer; ACompareProc: TQsCompareProc;
AExchangeProc: TQsExchangeProc; ASortedDown: Boolean);
type
TStackItem = record
LIndex, RIndex: Integer;
end;
const
cStackGrow = 100;
var
Key, Left, Right, L, R, LBack, RBack, StackLen, StackPtr: Integer;
Stack: array of TStackItem;
begin
{ this is the non recursive quick sort algorithm to avoid stack overflows.
Right parts of divided arrays are stored into a stack-like array
in dynamic memory for later use. }
Left := 0;
Right := ACount - 1;
SetLength(Stack, cStackGrow);
StackPtr := 0;
with Stack[StackPtr] do begin LIndex := Left; RIndex := Right end;
repeat
with Stack[StackPtr] do begin Left := LIndex; Right := RIndex end;
Dec(StackPtr);
repeat
L := Left;
R := Right;
Key := (L + R) div 2;
LBack := Left - 1;
RBack := Right;
repeat
if ASortedDown then
begin
while (L < Right) and (ACompareProc(AData, L, Key) < 0) do Inc(L);
while (R > Left) and (ACompareProc(AData, R, Key) > 0) do Dec(R);
end else
begin
while (L < Right) and (ACompareProc(AData, L, Key) > 0) do Inc(L);
while (R > Left) and (ACompareProc(AData, R, Key) < 0) do Dec(R);
end;
if L <= R then
begin
if L < R then
if (L = Key) or (R = Key) then
begin
// preserve Key, exchange later
LBack := L;
RBack := R;
end else
AExchangeProc(AData, L, R);
Dec(R);
Inc(L);
end;
until L >= R;
// exchange anything with former Key
if LBack >= Left then
AExchangeProc(AData, LBack, RBack);
if L < Right then
begin
Inc(StackPtr);
StackLen := Length(Stack);
if StackPtr >= StackLen then
SetLength(Stack, StackLen + cStackGrow);
with Stack[StackPtr] do begin LIndex := L; RIndex := Right end;
end;
Right := R;
until Left >= Right;
until StackPtr < 0;
end;
procedure QuickSort(AData: Pointer; ACount: Integer; ACompareProc: TQsCompareProc;
AExchangeProc: TQsExchangeProc; ASortedDown: Boolean);
procedure Sort(const Left, Right: Integer);
var
Key, L, R, LBack, RBack: Integer;
begin
Key := (Left + Right) div 2;
L := Left;
R := Right;
LBack := Left - 1;
RBack := Right;
repeat
if ASortedDown then
begin
while (L < Right) and (ACompareProc(AData, L, Key) < 0) do Inc(L);
while (R > Left) and (ACompareProc(AData, R, Key) > 0) do Dec(R);
end else
begin
while (L < Right) and (ACompareProc(AData, L, Key) > 0) do Inc(L);
while (R > Left) and (ACompareProc(AData, R, Key) < 0) do Dec(R);
end;
if L <= R then
begin
if L < R then
if (L = Key) or (R = Key) then
begin
// preserve Key, exchange later
LBack := L;
RBack := R;
end else
AExchangeProc(AData, L, R);
Inc(L);
Dec(R);
end;
until L >= R;
// exchange anything with former Key
if LBack >= Left then
AExchangeProc(AData, LBack, RBack);
if Left < R then Sort(Left, R);
if L < Right then Sort(L, Right);
end;
begin
if ACount > 1 then
Sort(0, ACount - 1);
end;
procedure OffsetPoint(var APoint: TPoint; AX, AY: Integer);
begin
Inc(APoint.X, AX);
Inc(APoint.Y, AY);
end;
procedure OffsetPoint(var APoint: TPoint; const AOffset: TPoint);
begin
Inc(APoint.X, AOffset.X);
Inc(APoint.Y, AOffset.Y);
end;
function NormalizeRect(const ARect: TRect): TRect;
begin
Result := ARect;
if Result.Left > Result.Right then
Exchange(Result.Left, Result.Right);
if Result.Top > Result.Bottom then
Exchange(Result.Top, Result.Bottom);
end;
function Point64(AX, AY: Int64): TKPoint64;
begin
Result.X:= AX;
Result.Y:= AY;
end;
function PointToPoint64(const APoint: TPoint): TKPoint64;
begin
Result.X:= APoint.x;
Result.Y:= APoint.y;
end;
function Point64ToPoint(const APoint: TKPoint64): TPoint;
begin
Result.X:= Integer(APoint.X);
Result.Y:= Integer(APoint.Y);
end;
function Pt64InRect(const ARect: TRect; const APoint: TKPoint64): Boolean;
begin
Result :=
(APoint.X >= ARect.Left) and (APoint.X < ARect.Right) and
(APoint.Y >= ARect.Top) and (APoint.Y < ARect.Bottom);
end;
function Rect64(ALeft, ATop, ARight, ABottom: Int64): TKRect64;
begin
Result.Left:= ALeft;
Result.Top:= ATop;
Result.Right:= ARight;
Result.Bottom:= ABottom;
end;
function RectInRect(Bounds, Rect: TRect): Boolean;
begin
Result :=
(Rect.Left < Bounds.Right) and (Rect.Right >= Bounds.Left) and
(Rect.Top < Bounds.Bottom) and (Rect.Bottom >= Bounds.Top);
end;
function RectInRectFully(Bounds, Rect: TRect): Boolean;
begin
Result :=
(Rect.Left >= Bounds.Left) and (Rect.Right <= Bounds.Right) and
(Rect.Top >= Bounds.Top) and (Rect.Bottom <= Bounds.Bottom);
end;
procedure OffsetRect(var ARect: TRect; AX, AY: Integer);
begin
Inc(ARect.Left, AX);
Inc(ARect.Top, AY);
Inc(ARect.Right, AX);
Inc(ARect.Bottom, AY);
end;
procedure OffsetRect(var ARect: TRect; const AOffset: TPoint);
begin
Inc(ARect.Left, AOffset.X);
Inc(ARect.Top, AOffset.Y);
Inc(ARect.Right, AOffset.X);
Inc(ARect.Bottom, AOffset.Y);
end;
procedure StripLastPathSlash(var APath: string);
begin
if APath <> '' then
if CharInSetEx(APath[Length(APath)], ['\', '/']) then Delete(APath, Length(APath), 1);
end;
function StripLastPathSlashFnc(const APath: string): string;
begin
Result := APath;
StripLastPathSlash(Result);
end;
function StrNextCharIndex(const AText: TKString; Index: Integer): Integer;
begin
{$IFDEF FPC}
Result := Index + LazUTF8.UTF8CharacterLength(@AText[Index]);
{$ELSE}
if (Word(AText[Index]) >= cUTF16FirstSurrogateBegin) and (Word(AText[Index]) <= cUTF16FirstSurrogateEnd) then
Result := Index + 2
else
Result := Index + 1;
{$ENDIF}
end;
function StrPreviousCharIndex(const AText: TKString; Index: Integer): Integer;
begin
{$IFDEF FPC}
Result := Index - LazUTF8.UTF8CharacterLength(@AText[StringCharBegin(AText, Index - 1)]);
{$ELSE}
if (Word(AText[Index - 1]) >= cUTF16SecondSurrogateBegin) and (Word(AText[Index - 1]) <= cUTF16SecondSurrogateEnd) then
Result := Index - 2
else
Result := Index - 1;
{$ENDIF}
end;
function StrByteIndexToCPIndex(const AText: TKString; ByteIndex: Integer): Integer;
var
I: Integer;
begin
Result := 0;
I := 1;
while I < ByteIndex do
begin
{$IFDEF FPC}
Inc(I, LazUTF8.UTF8CharacterLength(@AText[I]));
{$ELSE}
if (Word(AText[I]) >= cUTF16FirstSurrogateBegin) or (Word(AText[I]) > cUTF16FirstSurrogateEnd) then
Inc(I, 2)
else
Inc(I);
{$ENDIF}
Inc(Result);
end;
end;
function StrCPIndexToByteIndex(const AText: TKString; CPIndex: Integer): Integer;
var
I: Integer;
begin
Result := 0;
for I := 1 to CPIndex do
begin
{$IFDEF FPC}
Inc(Result, LazUTF8.UTF8CharacterLength(@AText[Result]));
{$ELSE}
if (Word(AText[Result]) >= cUTF16FirstSurrogateBegin) and (Word(AText[Result]) <= cUTF16FirstSurrogateEnd) then
Inc(Result, 2)
else
Inc(Result);
{$ENDIF}
if Result > Length(AText) then
Break;
end;
end;
function StringCharBegin(const AText: TKString; Index: Integer): Integer;
begin
{$IFDEF FPC}
Result := LazUTF8.UTF8CharToByteIndex(PChar(AText), Length(AText), Index)
{$ELSE}
if (Word(AText[Index - 1]) >= cUTF16SecondSurrogateBegin) and (Word(AText[Index - 1]) <= cUTF16SecondSurrogateEnd) then
Result := Index - 1
else
Result := Index
{$ENDIF}
end;
function StringLength(const AText: TKString): Integer;
var
I: Integer;
begin
{$IFDEF FPC}
Result := LazUTF8.UTF8Length(AText)
{$ELSE}
Result := 0;
for I := 1 to Length(AText) do
if (Word(AText[I]) < cUTF16SecondSurrogateBegin) or (Word(AText[I]) > cUTF16SecondSurrogateEnd) then
Inc(Result);
{$ENDIF}
end;
function StringCopy(const ASource: TKString; At, Count: Integer): TKString;
{$IFnDEF FPC}
var
ByteFrom, ByteTo: Integer;
{$ENDIF}
begin
{$IFDEF FPC}
Result := UTF8Copy(ASource, At, Count);
{$ELSE}
ByteFrom := StrCPIndexToByteIndex(ASource, At);
ByteTo := StrCPIndexToByteIndex(ASource, At + Count);
Result := Copy(ASource, ByteFrom, ByteTo - ByteFrom);
{$ENDIF}
end;
procedure StringDelete(var ASource: TKString; At, Count: Integer);
{$IFnDEF FPC}
var
ByteFrom, ByteTo: Integer;
{$ENDIF}
begin
{$IFDEF FPC}
LazUTF8.UTF8Delete(ASource, At, Count);
{$ELSE}
ByteFrom := StrCPIndexToByteIndex(ASource, At);
ByteTo := StrCPIndexToByteIndex(ASource, At + Count);
Delete(ASource, ByteFrom, ByteTo - ByteFrom);
{$ENDIF}
end;
procedure TrimWhiteSpaces(const AText: TKString; var AStart, ALen: Integer; const ASet: TKSysCharSet);
begin
while (ALen > 0) and CharInSetEx(AText[AStart], ASet) do
begin
Inc(AStart);
Dec(ALen);
end;
while (ALen > 0) and CharInSetEx(AText[AStart + ALen - 1], ASet) do
Dec(ALen);
end;
procedure TrimWhiteSpaces(var AText: TKString; const ASet: TKSysCharSet);
begin
while (Length(AText) > 0) and CharInSetEx(AText[1], ASet) do
Delete(AText, 1, 1);
while (Length(AText) > 0) and CharInSetEx(AText[Length(AText)], ASet) do
Delete(AText, Length(AText), 1);
end;
{$IFNDEF FPC}
procedure TrimWhiteSpaces(var AText: AnsiString; const ASet: TKSysCharSet);
begin
while (Length(AText) > 0) and CharInSetEx(AText[1], ASet) do
Delete(AText, 1, 1);
while (Length(AText) > 0) and CharInSetEx(AText[Length(AText)], ASet) do
Delete(AText, Length(AText), 1);
end;
{$ENDIF}
function StringToAnsiString(const AText: TKString; CodePage: Cardinal): AnsiString;
var
{$IFDEF FPC}
CP: string;
{$ELSE}
Len: Integer;
W: WideString;
DefaultChar: AnsiChar;
{$ENDIF}
begin
{$IFDEF FPC}
if CodePage = 0 then
CP := 'ansi'
else
CP := Format('cp%d', [Codepage]);
Result := LConvEncoding.ConvertEncoding(AText, 'utf8', CP);
{$ELSE}
if AText <> '' then
begin
DefaultChar := #0;
W := WideString(AText);
Len := WideCharToMultiByte(CodePage, 0, PWideChar(W), -1, nil, 0, @DefaultChar, nil);
SetLength(Result, Len - 1);
WideCharToMultiByte(CodePage, 0, PWideChar(W), -1, PAnsiChar(Result), Len, @DefaultChar, nil);
end else
Result := '';
{$ENDIF}
end;
function StringToUTF8(const AText: string): AnsiString;
begin
{$IFDEF FPC}
Result := AText;
{$ELSE}
Result := UTF8Encode(AText);
{$ENDIF}
end;
function StringToChar(const AText: TKString; AIndex: Integer): TKChar;
begin
{$IFDEF FPC}
Result := LazUTF8.UTF8Copy(AText, AIndex, 1);
{$ELSE}
Result := AText[AIndex];
{$ENDIF}
end;
{$IFDEF MSWINDOWS}
function GetWindowsFolder(CSIDL: Cardinal; var APath: string): Boolean;
type
TSHGetFolderPathProc = function(hWnd: HWND; CSIDL: Integer; hToken: THandle;
dwFlags: DWORD; pszPath: PAnsiChar): HResult; stdcall;
var
SHFolderHandle: HMODULE;
SHGetFolderPathProc: TSHGetFolderPathProc;
Buffer: PAnsiChar;
begin
Result := False;
APath := '';
SHFolderHandle := GetModuleHandle(SHFolderDll);
if SHFolderHandle <> 0 then
begin
SHGetFolderPathProc := GetProcAddress(SHFolderHandle, 'SHGetFolderPathA');
if Assigned(SHGetFolderPathProc) then
begin
GetMem(Buffer, MAX_PATH);
try
if Succeeded(SHGetFolderPathProc(0, CSIDL, 0, 0, Buffer)) then
begin
APath := string(Buffer);
Result := True;
end
finally
FreeMem(Buffer);
end;
end;
end;
end;
function RunExecutable(const AFileName: string; AWaitForIt: Boolean): DWORD;
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
ErrMsg: PChar;
begin
Result := STILL_ACTIVE;
GetStartupInfo(StartupInfo);
if CreateProcess(nil, PChar(AFileName), nil, nil, IsConsole,
NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo) then
begin
try
if (not AWaitForIt) or (WaitForSingleObject(ProcessInfo.hProcess,INFINITE) = WAIT_OBJECT_0) then
GetExitCodeProcess(ProcessInfo.hProcess, Result);
finally
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
end;
end else
begin
if FormatMessage(Format_Message_Allocate_Buffer or Format_Message_From_System, nil,
GetLastError, 0, @errMsg, 0, nil) <> 0 then
begin
try
Error('CreateProcess failed with error "' + String (errMsg) + '".');
finally
LocalFree (HLOCAL(errMsg));
end;
end;
end;
end;
{$ENDIF}
function SystemCodePage: Integer;
begin
{$IFDEF MSWINDOWS}
Result := getACP;
{$ELSE}
{$IF DEFINED(UNIX) and (FPC_FULLVERSION>=20701)}
Result := GetSystemCodepage;
{$ELSE}
Result := 0;
{$IFEND}
{$ENDIF}
end;
function NativeUTFToUnicode(const AText: TKString): WideChar;
{$IFDEF FPC}
var
CharLen: Integer;
{$ENDIF}
begin
{$IFDEF FPC}
Result := WideChar(LazUTF8.UTF8CharacterToUnicode(PChar(AText), CharLen));
{$ELSE}
Result := AText[1];
{$ENDIF}
end;
function UnicodeUpperCase(const AText: TKString): TKString;
begin
{$IFDEF FPC}
Result := LazUTF8.UTF8UpperCase(AText);
{$ELSE}
{$IFDEF STRING_IS_UNICODE}
Result := AnsiUpperCase(AText);
{$ELSE}
Result := WideUpperCase(AText);
{$ENDIF}
{$ENDIF}
end;
function UnicodeLowerCase(const AText: TKString): TKString;
begin
{$IFDEF FPC}
Result := LazUTF8.UTF8LowerCase(AText);
{$ELSE}
{$IFDEF STRING_IS_UNICODE}
Result := AnsiLowerCase(AText);
{$ELSE}
Result := WideLowerCase(AText);
{$ENDIF}
{$ENDIF}
end;
function UnicodeToNativeUTF(const AParam: WideChar): TKString;
begin
{$IFDEF FPC}
Result := LazUTF8.UnicodeToUTF8(Cardinal(AParam));
{$ELSE}
Result := AParam;
{$ENDIF}
end;
function UnicodeStringReplace(const AText, AOldPattern, ANewPattern: TKString;
AFlags: TReplaceFlags): TKString;
var
SearchStr, Pattern, Candidate: TKString;
I, NewI, PatternLen, SearchLen: Integer;
DoInc, Found: Boolean;
begin
Result := '';
if rfIgnoreCase in AFlags then
begin
SearchStr := UnicodeUpperCase(AText);
Pattern := UnicodeUpperCase(AOldPattern);
end else
begin
SearchStr := AText;
Pattern := AOldPattern;
end;
PatternLen := Length(Pattern);
SearchLen := Length(SearchStr);
Found := False;
I := 1;
while (I <= SearchLen) do
begin
DoInc := True;
if (rfReplaceAll in AFlags) or not Found then
begin
if SearchStr[I] = Pattern[1] then
begin
Candidate := Copy(SearchStr, I, PatternLen);
if Candidate = Pattern then
begin
Result := Result + ANewPattern;
Inc(I, PatternLen);
DoInc := False;
Found := True;
end;
end;
end;
if DoInc then
begin
NewI := StrNextCharIndex(SearchStr, I);
Result := Result + Copy(SearchStr, I, NewI - I);
I := NewI;
end;
end;
end;
function UTF8ToString(const AText: AnsiString): string;
begin
{$IFDEF FPC}
Result := AText;
{$ELSE}
{$IFDEF COMPILER12_UP}
Result := System.UTF8ToString(AText);
{$ELSE}
Result := System.UTF8Decode(AText);
{$ENDIF}
{$ENDIF}
end;
function MakeHexDigitPosition(Index: Int64; Digit: Integer): TKHexDigitPosition;
begin
Result.Index := Index;
Result.Digit := Digit;
end;
function DigitToBin(Value: AnsiChar): Integer;
begin
if ((Value >= 'a') and (Value <= 'f')) then Result := Ord(Value) - Ord('a') + 10
else if ((Value >= 'A') and (Value <= 'F')) then Result := Ord(Value) - Ord('A') + 10
else if ((Value >= '0') and (Value <= '9')) then Result := Ord(Value) - Ord('0')
else Result := -1;
end;
function DigitsToBinStr(var S: AnsiString; Convert: Boolean = True): Boolean;
var
I, J, K: Integer;
T: AnsiString;
begin
// check and convert text characters to hex values 0..15
Result := True;
if Convert then
SetLength(T, Length(S));
J := 0;
for I := 1 to Length(S) do if not CharInSetEx(S[I], [cTAB, cSPACE]) then
begin
K := DigitToBin(S[I]);
if K >= 0 then
begin
if Convert then
begin
Inc(J);
T[J] := AnsiChar(K)
end;
end else
begin
Result := False;
Break;
end;
end;
if Result and Convert then
begin
SetLength(T, J);
S := T;
end;
end;
function BinStrToBinary(const S: AnsiString): AnsiString;
var
I, J, L: Integer;
B1, B2: Byte;
begin
L := Length(S);
Result := '';
if L > 0 then
begin
SetLength(Result, DivUp(L, 2));
if L = 1 then
Result := S
else
begin
J := 1;
for I := 1 to Length(Result) do
begin
B1 := Byte(S[J]); Inc(J);
if J <= L then
begin
B2 := Byte(S[J]); Inc(J);
end else
B2 := 0;
Result[I] := AnsiChar(B1 shl 4 + B2);
end;
end;
end;
end;
function BinToDigit(Value: Byte): AnsiChar;
begin
if Value >= $10 then
Result := '0'
else if Value >= $A then
Result := AnsiChar(Ord('A') + Value - 10)
else
Result := AnsiChar(Ord('0') + Value)
end;
function BinaryToDigits(Buffer: PBytes; SelStart, SelEnd: TKHexDigitPosition;
AInsertSpaces: Boolean): AnsiString;
var
I, J, SpaceCount: Integer;
begin
if AInsertSpaces then
SpaceCount := SelEnd.Index - SelStart.Index
else
SpaceCount := 0;
SetLength(Result, (SelEnd.Index - SelStart.Index) * cHexDigitCount - SelStart.Digit + SelEnd.Digit + SpaceCount);
J := 1;
for I := SelStart.Index to SelEnd.Index do
begin
if ((I > SelStart.Index) or (SelStart.Digit < 1)) and ((I < SelEnd.Index) or (SelEnd.Digit > 0)) then
begin
Result[J] := BinToDigit((Buffer[I] shr 4) and $F);
Inc(J);
end;
if ((I > SelStart.Index) or (SelStart.Digit < 2)) and ((I < SelEnd.Index) or (SelEnd.Digit > 1)) then
begin
Result[J] := BinToDigit(Buffer[I] and $F);
Inc(J);
end;
if AInsertSpaces and (I < SelEnd.Index) then
begin
Result[J] := ' ';
Inc(J);
end;
end;
end;
function BinaryToDigits(Buffer: PBytes; ASize: Int64; AInsertSpaces: Boolean = False): AnsiString;
begin
Result := BinaryToDigits(Buffer, MakeHexDigitPosition(0, 0), MakeHexDigitPosition(ASize - 1, cHexDigitCount), AInsertSpaces);
end;
function BinaryToDigits(const Source: AnsiString; AInsertSpaces: Boolean): AnsiString;
begin
Result := BinaryToDigits(PBytes(@Source[1]), MakeHexDigitPosition(0, 0), MakeHexDigitPosition(Length(Source) - 1, cHexDigitCount), AInsertSpaces);
end;
function BinStrToDigits(const Source: AnsiString; AInsertSpaces: Boolean): AnsiString;
var
I, J, CharLen, SpaceCount: Integer;
begin
CharLen := Length(Source) div 2;
if AInsertSpaces then
SpaceCount := CharLen - 1
else
SpaceCount := 0;
SetLength(Result, CharLen * 2 + SpaceCount);
J := 1;
for I := 1 to CharLen do
begin
Result[J] := BinToDigit(Ord(Source[I * 2 - 1]));
Inc(J);
Result[J] := BinToDigit(Ord(Source[I * 2]));
Inc(J);
if AInsertSpaces and (I < CharLen) then
begin
Result[J] := ' ';
Inc(J);
end;
end;
end;
function InsertSpacesToDigits(const Source: AnsiString): AnsiString;
var
I, J, CharLen, SpaceCount: Integer;
begin
CharLen := Length(Source) div 2;
SpaceCount := CharLen - 1;
SetLength(Result, CharLen * 2 + SpaceCount);
J := 1;
for I := 1 to CharLen do
begin
Result[J] := Source[I * 2 - 1];
Inc(J);
Result[J] := Source[I * 2];
Inc(J);
if I < CharLen then
begin
Result[J] := ' ';
Inc(J);
end;
end;
end;
function ReplaceDigit(Value, Digit, Pos: Integer): Integer;
var
I, Mask, O: Integer;
begin
O := 1;
for I := Pos to cHexDigitCount - 2 do
O := O * cHexBase;
Mask := cHexBase - 1;
Result := (((Value div O) and not Mask) + (Digit and Mask)) * O + Value mod O;
end;
end.
tomboy-ng_0.34-1/kcontrols/source/kprintpreview.dfm 0000644 0001750 0001750 00000143301 14125207534 022337 0 ustar dbannon dbannon object KCustomPrintPreviewForm: TKCustomPrintPreviewForm
Left = 324
Top = 212
Caption = 'Print Preview'
ClientHeight = 614
ClientWidth = 812
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
Icon.Data = {
0000010001001010000001002000680400001600000028000000100000002000
000001002000000000000004000000000000000000000000000000000000FFFF
FF005F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFF5F5E
5FFF5F5E5FFF5F5E5FFF5F5E5F9F00000000B779329FB779329F00000000FFFF
FF005F5E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFB779329FB77932FFB77932FFB779329FFFFF
FF005F5E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8D5BEFFC089
4BFFB77932FFB77932FFBB813EFFB77932FFB77932FFB77932FFB779329FFFFF
FF005F5E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8D5BEFFB77932FFBE88
49FFD5B591FFD5B591FFBE8849FFB77932FFB77932FFB779329F00000000FFFF
FF005F5E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0894BFFBE8849FFF0EA
E4FFF4F2F0FFF4F2F0FFF0EAE4FFBE8849FFB77932EF0000000000000000FFFF
FF005F5E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB77932FFD5B591FFF4F2
F0FFF4F2F0FFF4F2F0FFF4F2F0FFD5B591FFB77932FF0000000000000000FFFF
FF005F5E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB77932FFD5B591FFF4F2
F0FFF4F2F0FFF4F2F0FFF4F2F0FFD5B591FFB77932FF0000000000000000FFFF
FF005F5E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0894BFFBE8849FFF0EA
E4FFF4F2F0FFF4F2F0FFF0EAE4FFBE8849FFB77932DF0000000000000000FFFF
FF005F5E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8D5BEFFB77932FFBE88
49FFD5B591FFD5B591FFBE8849FFB77932FFB779324F0000000000000000FFFF
FF005F5E5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE8D5BEFFC089
4BFFB77932FFB77932FFC0894BFFB779324FFFFFFF00FFFFFF00FFFFFF00FFFF
FF005F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFFC3C2C3FFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFF5F5E5F9FFFFFFF00FFFFFF00FFFFFF00FFFF
FF005F5E5F9F5F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFF5F5E5FFFFFFFFF00FFFFFF00FFFFFF00FFFF
FF00000000005F5E5F9F5F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFF5F5E5FFFFFFFFF00FFFFFF00FFFFFF00FFFF
FF0000000000000000005F5E5F9F5F5E5FFF5F5E5FFF5F5E5FFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFF5F5E5FFF000000000000000000000000FFFF
FF000000000000000000000000005F5E5F9F5F5E5FFF5F5E5FFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFF5F5E5FFF000000000000000000000000FFFF
FF00000000000000000000000000000000005F5E5F9F5F5E5FFF5F5E5FFF5F5E
5FFF5F5E5FFF5F5E5FFF5F5E5FFF5F5E5FFF0000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000}
KeyPreview = True
OldCreateOrder = False
Position = poScreenCenter
OnCreate = FormCreate
OnKeyDown = FormKeyDown
OnShow = FormShow
PixelsPerInch = 96
TextHeight = 13
object ToBMain: TToolBar
Left = 0
Top = 0
Width = 812
Height = 30
AutoSize = True
ButtonHeight = 30
ButtonWidth = 31
Caption = 'TBMain'
Images = ILMain
TabOrder = 0
Wrapable = False
object TBPageFirst: TToolButton
Left = 0
Top = 0
Action = ACPageFirst
Grouped = True
ParentShowHint = False
ShowHint = True
end
object TBPagePrevious: TToolButton
Left = 31
Top = 0
Action = ACPagePrevious
Grouped = True
ParentShowHint = False
ShowHint = True
end
object TBPageNext: TToolButton
Left = 62
Top = 0
Action = ACPageNext
Grouped = True
ParentShowHint = False
ShowHint = True
end
object TBPageLast: TToolButton
Left = 93
Top = 0
Action = ACPageLast
Grouped = True
ParentShowHint = False
ShowHint = True
end
object ToolButton3: TToolButton
Left = 124
Top = 0
Width = 8
Caption = 'ToolButton3'
ImageIndex = 2
Style = tbsSeparator
end
object PNPage: TPanel
Left = 132
Top = 0
Width = 71
Height = 30
BevelOuter = bvNone
ParentBackground = False
TabOrder = 0
object EDPage: TEdit
Left = 7
Top = 4
Width = 43
Height = 21
TabOrder = 0
Text = '1'
OnExit = EDPageExit
OnKeyDown = EDPageKeyDown
end
object UDPage: TUpDown
Left = 50
Top = 4
Width = 15
Height = 21
Associate = EDPage
Min = 1
Position = 1
TabOrder = 1
OnClick = UDPageClick
end
end
object ToolButton6: TToolButton
Left = 203
Top = 0
Width = 8
Caption = 'ToolButton6'
ImageIndex = 3
Style = tbsSeparator
end
object PNScale: TPanel
Left = 211
Top = 0
Width = 112
Height = 30
BevelOuter = bvNone
ParentBackground = False
ParentColor = True
TabOrder = 1
object CoBScale: TComboBox
Left = 9
Top = 4
Width = 95
Height = 21
AutoComplete = False
DropDownCount = 16
TabOrder = 0
OnExit = CoBScaleExit
OnSelect = CoBScaleExit
Items.Strings = (
'25 %'
'50 %'
'75 %'
'100 %'
'125 %'
'150 %'
'200 %'
'500 %'
'whole page'
'page width')
end
end
object ToolButton1: TToolButton
Left = 323
Top = 0
Width = 8
Caption = 'ToolButton1'
ImageIndex = 4
Style = tbsSeparator
end
object TBPrint: TToolButton
Left = 331
Top = 0
Action = ACPrint
ParentShowHint = False
ShowHint = True
end
object ToolButton4: TToolButton
Left = 362
Top = 0
Width = 8
Caption = 'ToolButton4'
ImageIndex = 5
Style = tbsSeparator
end
object TBClose: TToolButton
Left = 370
Top = 0
Action = ACClose
ParentShowHint = False
ShowHint = True
end
end
object ILMain: TImageList
ColorDepth = cd32Bit
DrawingStyle = dsTransparent
Height = 24
Width = 24
Left = 16
Top = 54
Bitmap = {
494C010106002000340018001800FFFFFFFF2110FFFFFFFFFFFFFFFF424D3600
0000000000003600000028000000600000003000000001002000000000000048
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000E0E0E0F2424242C393939543C3B3B5A3B3B3B593B3B3B593B3B
3B593B3B3B593B3B3B593B3B3B593B3B3B593C3B3B5A3737374F1D1D1D220808
0809000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000303030404040405000000000000
0000000000000000000033333243FEEFC3FFFEE5BBFFFEE5BBFFFEE5BCFFFEE6
BDFFFEE7BEFFFEE9C2FFFEE9C2FFFEEAC4FFFEEEC9FFFCE0BEFE0B0B0B0C0000
0000000000000000000004040405030303040000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000161616191F1F1F25393939515E5E
5EB35E5E5EB6646566B979726CD1FED3A3FFFECFA2FFFED0A3FFFED0A6FFFED3
A8FFFED4ADFFFED7B0FFFED8B2FFFED9B5FFFEDEBBFFEECDB2FB62615FC25C5D
5DB45E5E5EB43B3B3B571E1E1E24161616190000000000000000000000000000
0000000000000000000055565780555657800000000000000000000000000000
0000000000000000000000000000000000005556578055565780000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000606060733333346949494E0D2D2
D2FFD6D6D6FFBABDBFFF6A5F54FFEEBE90FFE9BB90FFE9BC93FFE9BD95FFE9C0
99FFE9C29EFFE9C4A1FFE9C5A4FFE9C7A9FFECCDAFFFD4B89EFF676563FFD4D5
D6FFD1D1D1FF9F9F9FE939393952040404050000000000000000000000000000
000000000000555657804343C0FF4343C0FF5556578000000000000000000000
0000000000000000000000000000555657804343C0FF4343C0FF555657800000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000004D4D4D82D3D3D3FFD3D3
D3FFD4D4D4FFBDBFC1FF524840FFB9936FFFB59270FFB59272FFB59474FFB596
78FFB59779FFB5977BFFB6997DFFB69984FFB99E88FFA28A74FF555453FFD7D3
D6FFD1CFD0FFCFCFCFFF4D4D4D82000000000000000000000000000000000000
0000555657804343C0FF7272DAFF7171DAFF4343C0FF55565780000000000000
00000000000000000000555657804343C0FF7171DAFF7272DAFF4343C0FF5556
5780000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000057575780CACACAFFD7D7
D7FFD5D5D5FFCCCCCDFF95908FFFB6A8A2FFB5A7A1FFB5A7A1FFB5A7A1FFB4A7
A0FFB4A7A1FFB4A7A1FFB4A6A0FFB4A6A1FFB4A7A1FFAB9E99FF9D9799FF9BC0
B0FFADC5BBFFCAC6C8FF57575780000000000000000000000000000000000000
00004343C0FF7272DAFF9797FEFF8D8DFEFF6767DAFF4343C0FF555657800000
000000000000555657804343C0FF6767DAFF8D8DFEFF9797FEFF7272DAFF4343
C0FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000055555580CCCCCCFFE0DF
DFFFEAE9EAFFE2E7E5FFE9EFEDFFE3EBEAFFE3EBEAFFE3EBEAFFE3EBE9FFE3EB
E9FFE3EBE9FFE3EBE9FFE3EAE9FFE3EAE9FFE2EAE8FFE3EBE9FFEEEFEEFFCDDF
D8FFC7D3CEFFCAC8C9FF55555580000000000000000000000000000000000000
00004343C0FF7171DAFF8D8DFEFF7777FEFF7D7DFEFF6464DAFF4343C0FF5556
5780555657804343C0FF6464DAFF7D7DFEFF7777FEFF8D8DFEFF7171DAFF4343
C0FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000005454547FD5D1D3FFE6ED
EAFF6ABE9CFF2DA372FF37A878FF37A877FF37A777FF37A777FF37A677FF37A7
76FF37A776FF37A676FF38A677FF38A677FF38A677FF38A677FF2DA16FFF7AC3
A5FFECEEEDFFD0CDCEFF5454547F000000000000000000000000000000000000
0000000000004343C0FF6767DAFF7D7DFEFF7272FEFF7878FEFF5E5EDAFF4343
C0FF4343C0FF5E5EDAFF7878FEFF7272FEFF7D7DFEFF6767DAFF4343C0FF0000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000004F4F4F74E4DDE0FFBFE1
D2FF28B17CFF44C79BFF3DBF91FF3EBF91FF3EBF91FF3EBF91FF3EBF91FF3EBF
92FF3EBF92FF3EBF92FF3EBF92FF3EBF92FF3EBF92FF3DBE91FF44C89BFF29AD
7AFFC4E1D3FFE1DADDFF50505076000000000000000000000000000000000000
000000000000000000004343C0FF6464DAFF7878FEFF6D6DFEFF6B6BFEFF6F6F
FEFF6F6FFEFF6B6BFEFF6D6DFEFF7878FEFF6464DAFF4343C0FF000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000004E4E4E71EEE7EAFFBFE4
D6FF28B382FF27B180FF18AA73FF1AAC76FF1AAC76FF1AAC76FF1AAC76FF1AAC
76FF1AAC76FF1AAC76FF1AAC76FF1AAC76FF1AAC76FF18AA73FF27B180FF29AE
7CFFC8E5D9FFEDE6EAFF50505075000000000000000000000000000000000000
00000000000000000000000000004343C0FF5E5EDAFF6B6BFEFF5F5FFEFF5C5C
FEFF5C5CFEFF5F5FFEFF6B6BFEFF5E5EDAFF4343C0FF00000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000004E4E4E70F8F1F4FFBBE6
D6FF30C190FF35CA9BFF21C591FF23C794FF23C794FF23C794FF23C794FF23C7
94FF23C794FF23C794FF23C794FF23C794FF23C794FF20C491FF36CC9EFF35BE
8FFFC6E6D8FFFBF3F6FF52525276000000000000000000000000000000000000
0000000000000000000000000000000000004343C0FF6F6FFEFF5C5CFEFF5555
FEFF5555FEFF5C5CFEFF6F6FFEFF4343C0FF0000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000004D4D4D6DFAF3F5FFB0E5
D3FF37CA9CFF71F3CEFF6BF0CBFF6BF1CBFF6BF0CBFF6BF0CBFF6BF1CBFF6BF1
CBFF6BF1CBFF6BF0CBFF6BF0CBFF6BF0CBFF6BF1CBFF6CF0CBFF73F3CFFF39C7
98FFC4E6D9FFFEF5F9FF52525276000000000000000000000000000000000000
0000000000000000000000000000555657804343C0FFB4B4FEFFAAAAFEFFA7A7
FEFFA7A7FEFFAAAAFEFFB4B4FEFF4343C0FF5556578000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000049494967FAF3F5FFACE6
D3FF38CEA0FF67EEC7FF4DD6ACFF4DD4ABFF4DD5ABFF4DD5ABFF4DD4ABFF4DD4
ABFF4DD4ABFF4DD5ABFF4DD5ACFF4DD5ABFF4ED4ABFF4AD6ACFF5EEBC2FF39CA
9BFFC3E9DBFFFEF5F9FF4F4F4F71000000000000000000000000000000000000
00000000000000000000555657804343C0FF7979DAFFBEBEFEFFB8B8FEFFB7B7
FEFFB7B7FEFFB8B8FEFFBEBEFEFF7979DAFF4343C0FF55565780000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000004242425AF3EAEDFEBAEB
DBFF2ED1A0FF44D4A5FFA8B489FFB7B48BFFB4B58BFFB4B58BFFB4B58BFFB4B5
8BFFB4B58BFFB4B58BFFB4B58CFFB4B58BFFB7B48BFFA7B68BFF2FC998FF17C1
8CFFC8EEE0FFFAF0F3FF48484865000000000000000000000000000000000000
000000000000555657804343C0FF8282DAFFCECEFEFFCACAFEFFCACAFEFFCBCB
FEFFCBCBFEFFCACAFEFFCACAFEFFCECEFEFF8282DAFF4343C0FF555657800000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000060606076B68699D92BB
ADF337AE8AF153A78AEFE8C49DFEFECCA4FFF9CBA3FFF9CBA3FFF9CBA3FFF9CB
A3FFF9CBA3FFF9CBA3FFF9CBA3FFF9CBA3FFFDCCA4FFECC69EFE58A98BF233A9
85F191B0A6EB716E70A50F0F0F10000000000000000000000000000000000000
0000555657804343C0FF8686DAFFDBDBFEFFD8D8FEFFDADAFEFF8484DAFF4343
C0FF4343C0FF8484DAFFDADAFEFFD8D8FEFFDBDBFEFF8686DAFF4343C0FF5556
5780000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000001818
181B0F0F0F100F0F0F10CAB899EDFBD8B3FFF7D8B3FFF8D8B3FFF7D8B2FFF8D8
B3FFF8D8B3FFF7D8B2FFF8D8B2FFF8D8B3FFFAD9B3FFD4BCA0F01E1E1E230F0F
0F100C0C0C0D0000000000000000000000000000000000000000000000000000
00004343C0FF8B8BDAFFE8E8FEFFE5E5FEFFE6E6FEFF8989DAFF4343C0FF0000
0000000000004343C0FF8989DAFFE6E6FEFFE5E5FEFFE8E8FEFF8B8BDAFF4343
C0FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000E0E0E0FDCBB9DEFF8D9B6FFF9D9B5FFF8D8B5FFF9D9B6FFF8DA
B6FFF8DAB6FFF8D9B6FFF8D9B6FFF9D9B6FFFAD9B5FFD7BC9FEF0C0C0C0D0000
0000000000000000000000000000000000000000000000000000000000000000
00004343C0FF8E8EDAFFF2F2FEFFF1F1FEFF8D8DDAFF4343C0FF000000000000
000000000000000000004343C0FF8D8DDAFFF1F1FEFFF2F2FEFF8E8EDAFF4343
C0FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000F0F0F10D6B99CEFF9DCBAFFF9DBB9FFF9DBB9FFF9DCB9FFF8DB
B9FFF9DCB9FFF9DBBAFFF8DAB9FFF9DBB9FFF9DCB9FFD9BB9FEF0F0F0F100000
0000000000000000000000000000000000000000000000000000000000000000
0000000000004343C0FF9090DAFF9090DAFF4343C0FF00000000000000000000
00000000000000000000000000004343C0FF9090DAFF9090DAFF4343C0FF0000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000F0F0F10D4B99CEFF9DEBEFFF9DDBDFFF9DCBCFFF9DCBCFFF9DD
BDFFF9DDBDFFF9DCBCFFF9DDBCFFF9DDBDFFF9DDBEFFD6BA9FEF0F0F0F100000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000004343C0FF4343C0FF0000000000000000000000000000
0000000000000000000000000000000000004343C0FF4343C0FF000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000F0F0F10D3B79DEFFAE0C2FFF9DEC0FFF9DEC0FFFADEC0FFFADE
C0FFF9DEC1FFFADEC0FFF9DEC0FFF9DEC0FFFADFC1FFD5B99FEF0F0F0F100000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000F0F0F10D3B89DEFFCE4C7FFFAE2C6FFFBE2C5FFFAE2C5FFFAE2
C6FFFAE2C6FFFAE2C6FFFBE2C5FFFBE2C5FFFBE3C7FFD4B89FEF0F0F0F100000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000F0F0F10CBAD93EBE8C6A5FBE8C5A5FBE8C5A4FBE8C6A4FBE8C5
A5FBE8C5A5FBE8C5A5FBE8C5A4FBE8C5A4FBE8C6A5FBCBAD94EB0F0F0F100000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000555657805556578055565780555657800000000000000000000000000000
0000000000000000000000000000000000000000000055565780555657800000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000005556578055565780555657800000
0000000000000000000000000000000000000000000000000000000000000000
0000000000005556578055565780555657800000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000005556578055565780000000000000000000000000000000000000
0000000000000000000000000000000000005556578055565780555657805556
5780000000000000000000000000000000000000000000000000000000000000
000068AD93FF68AD93FF68AD93FF68AD93FF0000000000000000000000000000
0000000000000000000000000000555657805556578068AD93FF68AD93FF5556
5780000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000000000000000000555657805556578068AD93FF68AD93FF68AD93FF5556
5780000000000000000000000000000000000000000000000000000000000000
00005556578068AD93FF68AD93FF68AD93FF5556578055565780000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00005556578068AD93FF68AD93FF555657805556578000000000000000000000
00000000000000000000000000000000000068AD93FF68AD93FF68AD93FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFBEF1E4FFBEF1E4FF68AD93FF0000000000000000000000000000
000000000000555657805556578068AD93FF68AD93FF89C9B3FF8FC9B5FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000555657805556578068AD93FF68AD93FF83C7B1FFA9EDDCFF8DC9B4FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF8DC9B4FFA9EDDCFF83C7B1FF68AD93FF68AD93FF555657805556
5780000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FF8FC9B5FF89C9B3FF68AD93FF68AD93FF55565780555657800000
00000000000000000000000000000000000068AD93FFBEF1E4FFBEF1E4FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFA9EDDCFFA9EDDCFF68AD93FF0000000000000000000000005556
57805556578068AD93FF68AD93FF80C7AFFF90E8D2FF92E9D3FFA7EDDBFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000555657805556
578068AD93FF68AD93FF80C7AFFF8EE8D1FF83E6CDFF8AE7D0FFA3ECDAFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFA3ECDAFF8AE7D0FF83E6CDFF8EE8D1FF80C7AFFF68AD93FF68AD
93FF555657805556578000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FFA7EDDBFF92E9D3FF90E8D2FF80C7AFFF68AD93FF68AD93FF5556
57805556578000000000000000000000000068AD93FFA9EDDCFFA9EDDCFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF9FEBD8FF9FEBD8FF68AD93FF00000000555657805556578068AD
93FF68AD93FF80C7AFFF8DE8D1FF7DE5CBFF73E3C7FF7BE5CAFF96E9D4FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000555657805556578068AD93FF68AD
93FF80C7AFFF8DE8D1FF7DE5CBFF72E3C7FF6CE2C4FF76E4C8FF94E9D3FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF94E9D3FF76E4C8FF6CE2C4FF72E3C7FF7DE5CBFF8DE8D1FF80C7
AFFF68AD93FF68AD93FF55565780555657800000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FF96E9D4FF7BE5CAFF73E3C7FF7DE5CBFF8DE8D1FF80C7AFFF68AD
93FF68AD93FF55565780555657800000000068AD93FF9FEBD8FF9FEBD8FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF9FEBD8FF9FEBD8FF68AD93FF5556578068AD93FF68AD93FF80C7
AFFF8DE8D1FF7DE5CBFF72E3C7FF6BE1C4FF66E0C2FF73E3C7FF90E8D2FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
00000000000000000000555657805556578068AD93FF68AD93FF80C7AFFF8DE8
D1FF7DE5CBFF72E3C7FF6BE1C4FF66E0C2FF65E0C1FF72E3C7FF90E8D2FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF90E8D2FF72E3C7FF65E0C1FF66E0C2FF6BE1C4FF72E3C7FF7DE5
CBFF8DE8D1FF80C7AFFF68AD93FF68AD93FF5556578055565780000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FF90E8D2FF73E3C7FF66E0C2FF6BE1C4FF72E3C7FF7DE5CBFF8DE8
D1FF80C7AFFF68AD93FF68AD93FF5556578068AD93FF9FEBD8FF9FEBD8FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF9FEBD8FF9FEBD8FF68AD93FF68AD93FF80C7AFFF8DE8D1FF7DE5
CBFF72E3C7FF6BE1C4FF66E0C2FF65E0C1FF64E0C1FF72E3C7FF90E8D2FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
0000000000005556578068AD93FF68AD93FF80C7AFFF8DE8D1FF7DE5CBFF72E3
C7FF6BE1C4FF66E0C2FF65E0C1FF64E0C1FF64E0C1FF72E3C7FF90E8D2FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF90E8D2FF72E3C7FF64E0C1FF64E0C1FF65E0C1FF66E0C2FF6BE1
C4FF72E3C7FF7DE5CBFF8DE8D1FF80C7AFFF68AD93FF68AD93FF555657800000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FF90E8D2FF72E3C7FF64E0C1FF65E0C1FF66E0C2FF6BE1C4FF72E3
C7FF7DE5CBFF8DE8D1FF80C7AFFF68AD93FF68AD93FF9FEBD8FF9FEBD8FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF9FEBD8FF9FEBD8FF68AD93FF92E9D2FF7DE5CBFF72E3C7FF6BE1
C4FF66E0C2FF65E0C1FF64E0C1FF64E0C1FF64E0C1FF72E3C7FF90E8D2FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
00005556578068AD93FF86C8B1FF92E9D2FF7DE5CBFF72E3C7FF6BE1C4FF66E0
C2FF65E0C1FF64E0C1FF64E0C1FF64E0C1FF64E0C1FF72E3C7FF90E8D2FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF90E8D2FF72E3C7FF64E0C1FF64E0C1FF64E0C1FF64E0C1FF65E0
C1FF66E0C2FF6BE1C4FF72E3C7FF7DE5CBFF92E9D2FF86C8B1FF68AD93FF5556
5780000000000000000000000000000000000000000000000000000000000000
000068AD93FF90E8D2FF72E3C7FF64E0C1FF64E0C1FF64E0C1FF65E0C1FF66E0
C2FF6BE1C4FF72E3C7FF7DE5CBFF92E9D2FF68AD93FF9FEBD8FF9FEBD8FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF9FEBD8FF9FEBD8FF68AD93FF79E4CAFF6CE2C4FF66E0C2FF65E0
C1FF64E0C1FF64E0C1FF64E0C1FF64E0C1FF64E0C1FF72E3C7FF90E8D2FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF8BC9B4FF95E9D4FF79E4CAFF6CE2C4FF66E0C2FF65E0C1FF64E0
C1FF64E0C1FF64E0C1FF64E0C1FF64E0C1FF64E0C1FF72E3C7FF90E8D2FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF90E8D2FF72E3C7FF64E0C1FF64E0C1FF64E0C1FF64E0C1FF64E0
C1FF64E0C1FF65E0C1FF66E0C2FF6CE2C4FF79E4CAFF95E9D4FF8BC9B4FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF90E8D2FF72E3C7FF64E0C1FF64E0C1FF64E0C1FF64E0C1FF64E0
C1FF65E0C1FF66E0C2FF6CE2C4FF79E4CAFF68AD93FF9FEBD8FF9FEBD8FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFD5F0E9FFD5F0E9FF68AD93FFC5EAE1FFBFE8DEFFBDE7DDFFBCE7
DCFFBCE7DCFFBCE7DCFFBCE7DCFFBCE7DCFFBCE7DCFFC2E9DFFFCEEDE5FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF9BCAB9FFD0EEE7FFC5EAE1FFBFE8DEFFBDE7DDFFBCE7DCFFBCE7
DCFFBCE7DCFFBCE7DCFFBCE7DCFFBCE7DCFFBCE7DCFFC2E9DFFFCEEDE5FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFCEEDE5FFC2E9DFFFBCE7DCFFBCE7DCFFBCE7DCFFBCE7DCFFBCE7
DCFFBCE7DCFFBCE7DCFFBDE7DDFFBFE8DEFFC5EAE1FFD0EEE7FF9BCAB9FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFCEEDE5FFC2E9DFFFBCE7DCFFBCE7DCFFBCE7DCFFBCE7DCFFBCE7
DCFFBCE7DCFFBDE7DDFFBFE8DEFFC5EAE1FF68AD93FFD5F0E9FFD5F0E9FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFDBF1ECFFDBF1ECFF68AD93FFD7F0E9FFD0EDE6FFCCECE4FFCAEB
E2FFC8EAE1FFC7EAE1FFC7EAE1FFC7EAE1FFC7EAE1FFCCECE4FFD6F0E9FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
00000000000068AD93FF9BCAB9FFD7F0E9FFD0EDE6FFCCECE4FFCAEBE2FFC8EA
E1FFC7EAE1FFC7EAE1FFC7EAE1FFC7EAE1FFC7EAE1FFCCECE4FFD6F0E9FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFD6F0E9FFCCECE4FFC7EAE1FFC7EAE1FFC7EAE1FFC7EAE1FFC7EA
E1FFC8EAE1FFCAEBE2FFCCECE4FFD0EDE6FFD7F0E9FF9BCAB9FF68AD93FF0000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FFD6F0E9FFCCECE4FFC7EAE1FFC7EAE1FFC7EAE1FFC7EAE1FFC8EA
E1FFCAEBE2FFCCECE4FFD0EDE6FFD7F0E9FF68AD93FFDBF1ECFFDBF1ECFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFE2F4EFFFE2F4EFFF68AD93FF68AD93FF9BCAB9FFDDF2ECFFD9F1
EAFFD6F0E8FFD4EFE7FFD3EEE6FFD2EEE6FFD2EEE6FFD6F0E8FFDEF2EDFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000068AD93FF68AD93FF9BCAB9FFDDF2ECFFD9F1EAFFD6F0
E8FFD4EFE7FFD3EEE6FFD2EEE6FFD2EEE6FFD2EEE6FFD6F0E8FFDEF2EDFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFDEF2EDFFD6F0E8FFD2EEE6FFD2EEE6FFD2EEE6FFD3EEE6FFD4EF
E7FFD6F0E8FFD9F1EAFFDDF2ECFF9BCAB9FF68AD93FF68AD93FF000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FFDEF2EDFFD6F0E8FFD2EEE6FFD2EEE6FFD3EEE6FFD4EFE7FFD6F0
E8FFD9F1EAFFDDF2ECFF9BCAB9FF68AD93FF68AD93FFE2F4EFFFE2F4EFFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFE9F6F3FFE9F6F3FF68AD93FF0000000068AD93FF68AD93FF9ECB
BBFFE5F4F1FFE2F3EFFFE0F2EEFFDFF2EDFFDEF1ECFFE0F2EEFFE6F5F1FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000068AD93FF68AD93FF9ECBBBFFE5F4
F1FFE2F3EFFFE0F2EEFFDFF2EDFFDEF1ECFFDDF1ECFFE0F2EEFFE6F5F1FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFE6F5F1FFE0F2EEFFDDF1ECFFDEF1ECFFDFF2EDFFE0F2EEFFE2F3
EFFFE5F4F1FF9ECBBBFF68AD93FF68AD93FF0000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FFE6F5F1FFE0F2EEFFDEF1ECFFDFF2EDFFE0F2EEFFE2F3EFFFE5F4
F1FF9ECBBBFF68AD93FF68AD93FF0000000068AD93FFE9F6F3FFE9F6F3FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFF0F8F6FFF0F8F6FF68AD93FF00000000000000000000000068AD
93FF68AD93FFA1CCBCFFEDF7F5FFEBF6F4FFE9F6F3FFEBF6F4FFEEF8F6FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000068AD93FF68AD
93FFA1CCBCFFEDF7F5FFEBF6F4FFE9F6F3FFE8F5F3FFEAF6F3FFEEF8F6FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFEEF8F6FFEAF6F3FFE8F5F3FFE9F6F3FFEBF6F4FFEDF7F5FFA1CC
BCFF68AD93FF68AD93FF00000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FFEEF8F6FFEBF6F4FFE9F6F3FFEBF6F4FFEDF7F5FFA1CCBCFF68AD
93FF68AD93FF00000000000000000000000068AD93FFF0F8F6FFF0F8F6FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFF6FBFAFFF6FBFAFF68AD93FF0000000000000000000000000000
00000000000068AD93FF68AD93FFA3CDBDFFF4FAF9FFF4FAF9FFF6FBFAFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FF68AD93FFA3CDBDFFF4FAF9FFF3FAF8FFF3FAF9FFF6FBFAFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFF6FBFAFFF3FAF9FFF3FAF8FFF4FAF9FFA3CDBDFF68AD93FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FFF6FBFAFFF4FAF9FFF4FAF9FFA3CDBDFF68AD93FF68AD93FF0000
00000000000000000000000000000000000068AD93FFF6FBFAFFF6FBFAFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFFBFDFDFFFBFDFDFF68AD93FF0000000000000000000000000000
000000000000000000000000000068AD93FF68AD93FFA6CEBFFFA6CEBFFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000068AD93FF68AD93FFA6CEBEFFFBFDFCFFA6CEBFFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FFA6CEBFFFFBFDFCFFA6CEBEFF68AD93FF68AD93FF000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000068AD93FFA6CEBFFFA6CEBFFF68AD93FF68AD93FF00000000000000000000
00000000000000000000000000000000000068AD93FFFBFDFDFFFBFDFDFF68AD
93FF000000000000000000000000000000000000000000000000000000000000
000068AD93FF68AD93FF68AD93FF68AD93FF0000000000000000000000000000
0000000000000000000000000000000000000000000068AD93FF68AD93FF0000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000068AD93FF68AD93FF68AD93FF0000
0000000000000000000000000000000000000000000000000000000000000000
00000000000068AD93FF68AD93FF68AD93FF0000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
00000000000068AD93FF68AD93FF000000000000000000000000000000000000
00000000000000000000000000000000000068AD93FF68AD93FF68AD93FF68AD
93FF000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000424D3E000000000000003E000000
2800000060000000300000000100010000000000400200000000000000000000
000000000000000000000000FFFFFF0000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000000000000000000000000
000000000000}
end
object ALMain: TActionList
Images = ILMain
Left = 56
Top = 54
object ACPageFirst: TAction
Hint = 'First page'
ImageIndex = 0
OnExecute = ACPageFirstExecute
OnUpdate = ACPageFirstUpdate
end
object ACPagePrevious: TAction
Caption = 'Previous page'
Hint = 'Previous page'
ImageIndex = 1
OnExecute = ACPagePreviousExecute
OnUpdate = ACPageFirstUpdate
end
object ACPageNext: TAction
Caption = 'Next page'
Hint = 'Next page'
ImageIndex = 2
OnExecute = ACPageNextExecute
OnUpdate = ACPageNextUpdate
end
object ACPageLast: TAction
Caption = 'Last page'
Hint = 'Last page'
ImageIndex = 3
OnExecute = ACPageLastExecute
OnUpdate = ACPageNextUpdate
end
object ACPrint: TAction
Caption = 'Print'
Hint = 'Print'
ImageIndex = 4
OnExecute = ACPrintExecute
OnUpdate = ACPrintUpdate
end
object ACClose: TAction
Caption = 'Close'
Hint = 'Close preview'
ImageIndex = 5
OnExecute = ACCloseExecute
OnUpdate = ACCloseUpdate
end
end
end
tomboy-ng_0.34-1/kcontrols/source/kgraphics.pas 0000644 0001750 0001750 00000362415 14125207534 021427 0 ustar dbannon dbannon { @abstract(This file is part of the KControls component suite for Delphi and Lazarus.)
@author(Tomas Krysl)
Copyright (c) 2020 Tomas Krysl
License:
This code is licensed under BSD 3-Clause Clear License, see file License.txt or https://spdx.org/licenses/BSD-3-Clause-Clear.html.
}
unit kgraphics; // lowercase name because of Lazarus/Linux
{$include kcontrols.inc}
{$IFNDEF REGISTER_PICTURE_FORMATS}
{$WEAKPACKAGEUNIT ON}
{$ENDIF}
interface
uses
{$IFDEF FPC}
// use the LCL interface support whenever possible
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF}
GraphType, IntfGraphics, FPImage, LCLType, LCLIntf, LMessages, LResources,
{$ELSE}
Windows, Messages, JPeg,
{$IFDEF USE_PNG_SUPPORT}
PngImage,
{$ENDIF}
{$ENDIF}
Classes, Forms, Graphics, Controls, Types, KFunctions, KControls
{$IFDEF USE_THEMES}
, Themes
{$IFNDEF FPC}
, UxTheme
{$ENDIF}
{$ENDIF}
;
const
{ PNG Support }
PNGHeader = #137'PNG'#13#10#26#10;
MNGHeader = #138'MNG'#13#10#26#10;
{ Default value for the @link(TKSizingGrips.GripColor) property. }
cSizingGripColor = clNavy;
{ Default value for the @link(TKSizingGrips.GripSize) property. }
cSizingGripSize = 8;
{ Default value for the @link(TKSizingGrips.MidGripConstraint) property. }
cSizingMidGripConstraint = (3 * cSizingGripSize + 10);
type
{ Declares possible values for the Style parameter of the @link(BrightColor) function. }
TKBrightMode = (
{ The Color will be brightened with Percent of its entire luminosity range. }
bsAbsolute,
{ The Color will be brightened with Percent of its current luminosity value. }
bsOfBottom,
{ The Color will be brightened with Percent of the difference of its entire
luminosity range and current luminosity value. }
bsOfTop
);
{ Declares RGB + Alpha channel color description allowing both to
access single channels and the whole color item. }
TKColorRec = packed record
case Integer of
0: (R, G, B, A: Byte);
1: (Value: Cardinal);
end;
{ Pointer to TKColorRec. }
PKColorRec = ^TKColorRec;
{ Dynamic array for TKColorRec. }
TKColorRecs = array[0..MaxInt div SizeOf(TKColorRec) - 1] of TKColorRec;
{ Dynamic array for TKColorRecs. }
PKColorRecs = ^TKColorRecs;
{ Dynamic array for TKColorRec. }
TKDynColorRecs = array of TKColorRec;
{ String type for @link(ImageByType) function. }
TKImageHeaderString = string[10];
{$IFDEF USE_PNG_SUPPORT}
{$IFDEF FPC}
{ @exclude }
TKPngImage = TPortableNetworkGraphic;
{$ELSE}
{$IFDEF COMPILER12_UP}
{ @exclude }
TKPngImage = TPngImage;
{$ELSE}
{ @exclude }
TKPngImage = TPngObject;
{$ENDIF}
{$ENDIF}
{$ENDIF}
TKJpegImage = TJpegImage;
{ Declares possible values for the Attributes parameter in the @link(DrawAlignedText) function. }
TKTextAttribute = (
{ Bounding rectangle is calculated. No text is drawn. }
taCalcRect,
{ Text will be clipped within the given rectangle. }
taClip,
{ Text will be drawn with end ellipsis if it does not fit within given width. }
taEndEllipsis,
{ Given rectangle will be filled. }
taFillRect,
{ Only the text within given rectangle will be filled. }
taFillText,
{ Include padding created by aligns in the @link(TKTextBox.PointToIndex) calculation. }
taIncludePadding,
{ Text will be drawn as multi-line text if it contains carriage returns and line feeds. }
taLineBreak,
{ Text will be drawn with path ellipsis if it does not fit within given width. }
taPathEllipsis,
{ Text line(s) will be broken between words if they don't fit within given width. }
taWordBreak,
{ Text line(s) will be broken if they don't fit within col width. }
taWrapText, //JR:20091229
{ White spaces will be trimmed at the beginning or end of text lines. }
taTrimWhiteSpaces,
{ Text will be drawn with start ellipsis if it does not fit within given width. }
taStartEllipsis
);
{ Set type for @link(TKTextAttribute) enumeration. }
TKTextAttributes = set of TKTextAttribute;
{ Declares possible values for the HAlign parameter in the @link(DrawAlignedText) function. }
TKHAlign = (
{ Text is aligned to the left border of a cell rectangle. }
halLeft,
{ Text is horizontally centered within the cell rectangle. }
halCenter,
{ Text is aligned to the right border of a cell rectangle. }
halRight,
{ Text is aligned to the left and right border of a cell rectangle. }
halJustify
);
{ Declares possible values for the StretchMode parameter in the @link(ExcludeShapeFromBaseRect) function. }
TKStretchMode = (
{ Shape is not stretched. }
stmNone,
{ Shape is zoomed out. }
stmZoomOutOnly,
{ Shape is zoomed in. }
stmZoomInOnly,
{ Shape is zoomed arbitrary. }
stmZoom
);
{ For backward compatibility. }
TKTextHAlign = TKHAlign;
{ Declares possible values for the VAlign parameter in the @link(DrawAlignedText) function. }
TKVAlign = (
{ Text is aligned to the upper border of a cell rectangle. }
valTop,
{ Text is vertically centered within the cell rectangle. }
valCenter,
{ Text is aligned to the lower border of a cell rectangle. }
valBottom
);
{ For backward compatibility. }
TKTextVAlign = TKVAlign;
{ Declares possible values for the AStates parameter in the @link(DrawButtonFrame) function. }
TKButtonDrawState = (
{ Use OS themes/styles to draw button. }
bsUseThemes,
{ Draw disabled button. }
bsDisabled,
{ Draw pressed button. }
bsPressed,
{ Draw normal focused button. }
bsFocused,
{ Draw normal hot button. }
bsHot
);
{ Set of TKButtonState values. }
TKButtonDrawStates = set of TKButtonDrawState;
{ Contains common properties for all KCOntrols TGraphic descendants. }
TKGraphic = class(TGraphic)
protected
FDescription: string;
FFileFilter: string;
public
{ Creates the instance. }
constructor Create; override;
{ Gives description for design time loader. }
property Description: string read FDescription;
{ Gives file filter for design time loader. }
property FileFilter: string read FFileFilter;
end;
{ A simple platform independent encapsulation for a 32bpp bitmap with
alpha channel with the ability to modify it's pixels directly. }
{ TKAlphaBitmap }
TKAlphaBitmap = class(TKGraphic)
private
FAutoMirror: Boolean;
FCanvas: TCanvas;
FDirectCopy: Boolean;
FHandle: HBITMAP;
FHeight: Integer;
{$IFNDEF MSWINDOWS}
FImage: TLazIntfImage; // Lazarus only
FMaskHandle: HBITMAP;
{$ENDIF}
FOldBitmap: HBITMAP;
FPixels: PKColorRecs;
FPixelsChanged: Boolean;
FUpdateLock: Integer;
FWidth: Integer;
function GetScanLine(Index: Integer): PKColorRecs;
function GetHandle: HBITMAP;
function GetHasAlpha: Boolean;
function GetPixel(X, Y: Integer): TKColorRec;
procedure SetPixel(X, Y: Integer; Value: TKColorRec);
protected
{ Calls OnChanged event. }
procedure Changed(Sender: TObject); override;
{ Paints itself to ACanvas at location ARect. }
procedure Draw(ACanvas: TCanvas; const ARect: TRect); override;
{ Returns True if bitmap is empty. }
function GetEmpty: Boolean; override;
{ Returns the bitmap height. }
function GetHeight: Integer; override;
{ Returns True. Treat alpha bitmap as transparent because of the
possible alpha channel. }
function GetTransparent: Boolean; override;
{ Returns the bitmap width. }
function GetWidth: Integer; override;
{ Specifies new bitmap height. }
procedure SetHeight(Value: Integer); override;
{ Specifies new bitmap width. }
procedure SetWidth(Value: Integer); override;
{ Does nothing. Bitmap is never transparent. }
procedure SetTransparent(Value: Boolean); override;
public
{ Creates the instance. }
constructor Create; override;
{ Creates the instance from application resources. For Lazarus 'BMP' type is
taken, for Delphi RT_RCDATA is taken. }
constructor CreateFromRes(const ResName: string);
{ Destroys the instance. }
destructor Destroy; override;
{ Paints alpha bitmap onto Canvas at position given by X, Y. The alpha bitmap
is combined with the background already drawn on Canvas using alpha channel
stored in the alpha bitmap. }
procedure AlphaDrawTo(ACanvas: TCanvas; X, Y: Integer);
{ Paints alpha bitmap onto Canvas at position given by ARect. The alpha bitmap
is combined with the background already drawn on Canvas using alpha channel
stored in the alpha bitmap. }
procedure AlphaStretchDrawTo(ACanvas: TCanvas; const ARect: TRect);
{ Fills the alpha channel with Alpha. If the optional IfEmpty parameter is True,
the alpha channel won't be modified unless it has zero value for all pixels. }
procedure AlphaFill(Alpha: Byte; IfEmpty: Boolean = False); overload;
{ Fills the alpha channel according to given parameters. Currently it is used
internally by @link(TKDragWindow). }
procedure AlphaFill(Alpha: Byte; BlendColor: TColor; Gradient, Translucent: Boolean); overload;
{ Fills the alpha channel with AAlpha for pixels with AColor. }
procedure AlphaFillOnColorMatch(AColor: TColor; AAlpha: Byte);
{ Modifies the alpha channel with Percent of its current value. If the optional IfEmpty parameter is True,
the alpha channel will be set to percent of full scale if it has zero value. }
procedure AlphaFillPercent(Percent: Integer; IfEmpty: Boolean);
{ Copies shareable properties of another instance into this instance of TKAlphaBitmap. }
procedure Assign(Source: TPersistent); override;
{ Copies shareable properties of this instance into another instance of TKAlphaBitmap. }
procedure AssignTo(Dest: TPersistent); override;
{ Brightens the image by given percent and bright mode. }
procedure Brighten(APercent: Single; AMode: TKBrightMode = bsAbsolute);
{ Clears the image. }
procedure Clear; {$IFDEF FPC}override;{$ENDIF}
{ Combines the pixel at given location with the given color. }
procedure CombinePixel(X, Y: Integer; Color: TKColorRec);
{ Takes dimensions and pixels from AGraphic. }
procedure CopyFrom(AGraphic: TGraphic);
{ Takes dimensions and pixels from ABitmap. }
procedure CopyFromAlphaBitmap(ABitmap: TKAlphaBitmap);
{ Takes diemnsions and pixels from APngImage. }
procedure CopyFromJpeg(AJpegImage: TJPEGImage);
{$IFDEF USE_PNG_SUPPORT}
{ Takes diemnsions and pixels from APngImage. }
procedure CopyFromPng(APngImage: TKPngImage);
{$ENDIF}
{ Takes 90-rotated dimensions and pixels from ABitmap. }
procedure CopyFromRotated(ABitmap: TKAlphaBitmap);
{ Takes portion from AGraphic at position X and Y. }
procedure CopyFromXY(X, Y: Integer; AGraphic: TGraphic);
{ Takes portion from ABitmap at position X and Y. }
procedure CopyFromXYAlphaBitmap(X, Y: Integer; ABitmap: TKAlphaBitmap);
{ Takes portion from AJpegImage at position X and Y. }
procedure CopyFromXYJpeg(X, Y: Integer; AJpegImage: TJPEGImage);
{$IFDEF USE_PNG_SUPPORT}
{ Takes portion from APngImage at position X and Y. }
procedure CopyFromXYPng(X, Y: Integer; APngImage: TKPngImage);
{ Takes diemnsions and pixels from APngImage. }
procedure CopyToPng(APngImage: TKPngImage);
{$ENDIF}
{ Copies a location specified by ARect from ACanvas to bitmap. }
procedure DrawFrom(ACanvas: TCanvas; const ARect: TRect); overload;
{ Copies a portion of AGraphic to bitmap at position X and Y. }
procedure DrawFrom(AGraphic: TGraphic; X, Y: Integer); overload;
{ Calls @link(TKAlphaBitmap.Draw). }
procedure DrawTo(ACanvas: TCanvas; const ARect: TRect);
{ Fill with Color. }
procedure Fill(Color: TKColorRec);
{ Convert to grayscale. }
procedure GrayScale;
{$IFNDEF FPC}
{ Does nothing. }
procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle;
APalette: HPALETTE); override;
{$ENDIF}
{ Loads the bitmap from a file. Overriden to support PNG as well. }
procedure LoadFromFile(const Filename: string); override;
{ Loads the bitmap from bitmap and mask handles. }
procedure LoadFromHandles(ABitmap, AMask: HBITMAP);
{ Loads the bitmap from another TGraphic instance. }
procedure LoadFromGraphic(Image: TGraphic); virtual;
{ Loads the bitmap from a stream. }
procedure LoadFromStream(Stream: TStream); override;
{ Locks calls to @link(TKAlphaBitmap.Changed). }
procedure LockUpdate; virtual;
{ Mirrors the bitmap pixels horizontally. }
procedure MirrorHorz;
{ Mirrors the bitmap pixels vertically. }
procedure MirrorVert;
{$IFNDEF FPC}
{ Does nothing. }
procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
var APalette: HPALETTE); override;
{$ENDIF}
{ Saves the bitmap to a stream. }
procedure SaveToStream(Stream: TStream); override;
{ Specifies the bitmap size. }
procedure SetSize(AWidth, AHeight: Integer); {$IFNDEF FPC} reintroduce;{$ENDIF}
{ Unlocks calls to @link(TKAlphaBitmap.Changed). }
procedure UnlockUpdate; virtual;
{ Updates the bitmap handle from bitmap pixels. }
procedure UpdateHandle; dynamic;
{ Updates the pixels from bitmap handle. }
procedure UpdatePixels; dynamic;
{ Automatically mirrors the bitmap vertically for Linux hosts, when reading/writing from/to a stream. }
property AutoMirror: Boolean read FAutoMirror write FAutoMirror default True;
{ Returns the bitmap memory canvas. }
property Canvas: TCanvas read FCanvas;
{ Temporary flag. Use when copying data directly from another TGraphic to TKAlphaBitmap. }
property DirectCopy: Boolean read FDirectCopy write FDirectCopy;
{ Returns the bitmap handle. }
property Handle: HBITMAP read GetHandle;
{ Returns true if alpha channel is nonzero for at least one pixel. }
property HasAlpha: Boolean read GetHasAlpha;
{ Specifies the pixel color. Does range checking. }
property Pixel[X, Y: Integer]: TKColorRec read GetPixel write SetPixel;
{ Returns the pointer to bitmap pixels. }
property Pixels: PKColorRecs read FPixels;
{ Set this property to True if you have modified the bitmap pixels. }
property PixelsChanged: Boolean read FPixelsChanged write FPixelsChanged;
{ Returns the pointer to a bitmap scan line. }
property ScanLine[Index: Integer]: PKColorRecs read GetScanLine;
end;
{$IFDEF MSWINDOWS}
{ A simple encapsulation for a Windows or Enhanced metafile. It runs only under Windows and does not use shared images.
However, it is possible to release metafile handles on assigning to another TKMetafile. }
TKMetafile = class(TGraphic)
private
FCopyOnAssign: Boolean;
FEmfHandle: HENHMETAFILE;
FEnhanced: Boolean;
FWmfHandle: HMETAFILE;
procedure SetEMFHandle(const Value: HENHMETAFILE);
procedure SetEnhanced(const Value: Boolean);
procedure SetWMFHandle(const Value: HMETAFILE);
protected
FRequiredHeight,
FRequiredWidth: Integer;
procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
function GetEmpty: Boolean; override;
function GetHeight: Integer; override;
function GetTransparent: Boolean; override;
function GetWidth: Integer; override;
procedure SetHeight(Value: Integer); override;
procedure SetWidth(Value: Integer); override;
public
constructor Create; override;
destructor Destroy; override;
procedure Assign(Source: TPersistent); override;
procedure Clear; virtual;
procedure LoadFromStream(Stream: TStream); override;
procedure Release(out AWmfHandle: HMETAFILE; out AEmfHandle: HENHMETAFILE);
procedure SaveToStream(Stream: TStream); override;
property CopyOnAssign: Boolean read FCopyOnAssign write FCopyOnAssign;
property EMFHandle: HENHMETAFILE read FEMFHandle write SetEMFHandle;
property Enhanced: Boolean read FEnhanced write SetEnhanced;
property WMFHandle: HMETAFILE read FWMFHandle write SetWMFHandle;
end;
{$ENDIF}
{ Declares possible values for the AFunction parameter in the @link(TKTextBox.Process) function. }
TKTextBoxFunction = (
{ Measure text box contents. }
tbfMeasure,
{ Get text index for coordinates stored in FPoint. }
tbfGetIndex,
{ Get boundary rectangle for index stored in FIndex. }
tbfGetRect,
{ Draw text box contents. }
tbfDraw
);
{ Implements advanced text block rendering. Formerly implemented as @link(DrawAlignedText) function. }
TKTextBox = class(TObject)
private
FAttributes: TKTextAttributes;
FBackColor: TColor;
FHAlign: TKHAlign;
FHPadding: Integer;
FSelBkgnd: TColor;
FSelColor: TColor;
FSelEnd: Integer;
FSelStart: Integer;
FSpacesForTab: Integer;
FText: TKString;
FVAlign: TKVAlign;
FVPadding: Integer;
procedure SetText(const AText: TKString);
protected
FCanvas: TCanvas;
FClipRect: TRect;
FFontHeight: Integer;
FHasTabs: Boolean;
FIndex: Integer;
FCalcRect: TRect;
function GetHorzPos(ATextWidth: Integer): Integer;
function GetVertPos: Integer; virtual;
procedure Initialize(ACanvas: TCanvas; const ARect: TRect); virtual;
procedure Process(Y: Integer; AFunction: TKTextBoxFunction);
procedure TextTrim(const AText: TKString; var AStart, ALen: Integer); virtual;
public
constructor Create;
procedure Draw(ACanvas: TCanvas; const ARect: TRect); virtual;
function IndexToRect(ACanvas: TCanvas; const ARect: TRect; AIndex: Integer): TRect; virtual;
procedure Measure(ACanvas: TCanvas; const ARect: TRect; var AWidth, AHeight: Integer); virtual;
function PointToIndex(ACanvas: TCanvas; const ARect: TRect; APoint: TPoint): Integer; virtual;
class function TextExtent(ACanvas: TCanvas; const AText: TKString;
AStart, ALen: Integer; AExpandTabs: Boolean = False; ASpacesForTab: Integer = 2): TSize;
class procedure TextOutput(ACanvas: TCanvas; X, Y: Integer;
const AText: TKString; AStart, ALen: Integer;
AExpandTabs: Boolean = False; ASpacesForTab: Integer = 2);
property Attributes: TKTextAttributes read FAttributes write FAttributes;
property BackColor: TColor read FBackColor write FBackColor;
property HAlign: TKHAlign read FHAlign write FHAlign;
property HPadding: Integer read FHPadding write FHPadding;
property SelBkgnd: TColor read FSelBkgnd write FSelBkgnd;
property SelColor: TColor read FSelColor write FSelColor;
property SelEnd: Integer read FSelEnd write FSelEnd;
property SelStart: Integer read FSelStart write FSelStart;
property SpacesForTab: Integer read FSpacesForTab write FSpacesForTab;
property Text: TKString read FText write SetText;
property VAlign: TKVAlign read FVAlign write FVAlign;
property VPadding: Integer read FVPadding write FVPadding;
end;
{$IFDEF MSWINDOWS}
TUpdateLayeredWindowProc = function(Handle: THandle; hdcDest: HDC; pptDst: PPoint;
_psize: PSize; hdcSrc: HDC; pptSrc: PPoint; crKey: COLORREF; pblend: PBLENDFUNCTION;
dwFlags: DWORD): Boolean; stdcall;
{$ENDIF}
{ @abstract(Encapsulates the drag window)
Drag window is top level window used for dragging with mouse. It displays
some portion of associated control. It can be translucent under Windows. }
TKDragWindow = class(TObject)
private
FActive: Boolean;
FAlphaEffects: Boolean;
FBitmap: TKAlphaBitmap;
FBitmapFilled: Boolean;
FControl: TCustomControl;
FGradient: Boolean;
FInitialPos: TPoint;
FLayered: Boolean;
FMasterAlpha: Byte;
FRect: TRect;
{$IFDEF MSWINDOWS}
FBlend: TBlendFunction;
FUpdateLayeredWindow: TUpdateLayeredWindowProc;
FWindow: HWND;
{$ELSE}
FDragForm: TCustomForm;
{$ENDIF}
public
{ Creates the instance. }
constructor Create;
{ Destroys the instance. }
destructor Destroy; override;
{ Shows the drag window on screen. Takes a rectangular part as set by ARect from
IniCtrl's Canvas and displays it at position InitialPos. MasterAlpha and
Gradient are used to premaster the copied image with a specific fading effect. }
procedure Init(IniCtrl: TCustomControl; const ARect: TRect;
const AInitialPos: TPoint; AMasterAlpha: Byte; AGradient: Boolean);
{ Moves the drag window to a new location. }
procedure Move(ARect: PRect; const ACurrentPos: TPoint; AShowAlways: Boolean);
{ Hides the drag window. }
procedure Hide;
{ Returns True if the drag window is shown. }
property Active: Boolean read FActive;
{ Returns the pointer to the bitmap that holds the copied control image. }
property Bitmap: TKAlphaBitmap read FBitmap;
{ Returns True if the control already copied itself to the bitmap. }
property BitmapFilled: Boolean read FBitmapFilled;
end;
{ @abstract(Base class for KControls hints)
This class extends the standard THintWindow class. It adds functionality
common to all hints used in KControls. }
{ TKHintWindow }
TKHintWindow = class(THintWindow)
private
FExtent: TPoint;
procedure WMEraseBkGnd(var Msg: TLMessage); message LM_ERASEBKGND;
public
{ Creates the instance. }
constructor Create(AOwner: TComponent); override;
{ Shows the hint at given position. This is an IDE independent implementation. }
procedure ShowAt(const Origin: TPoint);
{ Hides the hint. }
procedure Hide;
{ Returns the extent of the hint. }
property Extent: TPoint read FExtent;
end;
{ @abstract(Hint window to display formatted text)
This class implements the textual hint window. The text is displayed . }
TKTextHint = class(TKHintWindow)
private
FText: TKString;
procedure SetText(const Value: TKString);
protected
{ Overriden method. Paints the hint. }
procedure Paint; override;
public
{ Creates the instance. }
constructor Create(AOwner: TComponent); override;
{ Text to show in the hint. }
property Text: TKString read FText write SetText;
end;
{ @abstract(Hint window to display graphic)
This class implements the hint window to show an image. }
TKGraphicHint = class(TKHintWindow)
private
FGraphic: TGraphic;
procedure SetGraphic(const Value: TGraphic);
protected
{ Overriden method. Paints the hint. }
procedure Paint; override;
public
{ Creates the instance. }
constructor Create(AOwner: TComponent); override;
{ Image to show in the hint. }
property Graphic: TGraphic read FGraphic write SetGraphic;
end;
TKSizingGripPosition = (
sgpNone,
sgpLeft,
sgpRight,
sgpTop,
sgpBottom,
sgpTopLeft,
sgpTopRight,
sgpBottomLeft,
sgpBottomRight
);
TKSizingGrips = class
private
FBoundsRect: TRect;
FGripColor: TColor;
FGripSize: Integer;
FMidGripConstraint: Integer;
protected
function GripRect(APosition: TKSizingGripPosition): TRect;
public
constructor Create;
class procedure ClsAffectRect(APosition: TKSizingGripPosition;
ADX, ADY: Integer; var ARect: TRect);
procedure DrawTo(ACanvas: TCanvas);
function HitTest(const APoint: TPoint): TKSizingGripPosition;
function CursorAt(const APoint: TPoint): TCursor;
function CursorFor(APosition: TKSizingGripPosition): TCursor;
property BoundsRect: TRect read FBoundsRect write FBoundsRect;
property GripColor: TColor read FGripColor write FGripColor default cSizingGripColor;
property GripSize: Integer read FGripSize write FGripSize default cSizingGripSize;
property MidGripConstraint: Integer read FMidGripConstraint write FMidGripConstraint default cSizingMidGripConstraint;
end;
{ Draws Src to Dest with per pixel weighting by alpha channel saved in Src. }
procedure BlendLine(Src, Dest: PKColorRecs; Count: Integer);
{ Calculates a brighter color of given color based on the HSL color space.
Parameters:
- Color - input color.
- Percent - percentage of luminosity to bright the color (0 to 1).
- Mode - identifies how the Percent parameter should be interpreted.
}
function BrightColor(Color: TColor; Percent: Single; Mode: TKBrightMode = bsAbsolute): TColor;
{ Returns current canvas window/wiewport scaling. }
procedure CanvasGetScale(ACanvas: TCanvas; out MulX, MulY, DivX, DivY: Integer);
{ Selects the default window/wiewport scaling to given canvas for both axes. }
procedure CanvasResetScale(ACanvas: TCanvas);
{ Returns True if the ACanvas's device context has been mapped to anything else
than MM_TEXT. }
function CanvasScaled(ACanvas: TCanvas): Boolean;
{ Selects the window/wiewport scaling to given canvas for both axes. }
procedure CanvasSetScale(ACanvas: TCanvas; MulX, MulY, DivX, DivY: Integer);
{ Selects the wiewport offset to given canvas for both axes. }
procedure CanvasSetOffset(ACanvas: TCanvas; OfsX, OfsY: Integer);
{ Converts TKColorRec to TColor. }
function ColorRecToColor(Color: TKColorRec): TColor;
{ Converts TColor to TKColorRec. }
function ColorToColorRec(Color: TColor): TKColorRec;
{$IFDEF FPC}
{ Converts TKColorRec to TFPColor. }
function ColorRecToFPColor(Color: TKColorRec): TFPColor;
{ Converts TFPColor to TKColorRec. }
function FPColorToColorRec(Color: TFPColor): TKColorRec;
{$ENDIF}
{ Makes a grayscale representation of the given color. }
function ColorToGrayScale(Color: TColor): TColor;
{ Returns True if properties of the two brushes are equal. }
function CompareBrushes(ABrush1, ABrush2: TBrush): Boolean;
{ Returns True if properties of the two fonts are equal. }
function CompareFonts(AFont1, AFont2: TFont): Boolean;
{ Calls BitBlt. }
procedure CopyBitmap(DestDC: HDC; DestRect: TRect; SrcDC: HDC; SrcX, SrcY: Integer);
{ Creates an empty point. }
function CreateEmptyPoint: TPoint;
{ Creates an empty point. }
function CreateEmptyPoint64: TKPoint64;
{ Creates an empty rectangle. }
function CreateEmptyRect: TRect;
{ Creates an empty rectangle. }
function CreateEmptyRect64: TKRect64;
{ Creates an empty rectangular region. }
function CreateEmptyRgn: HRGN;
{ Draws Text to the Canvas at location given by ARect.
This function is here for backward compatibility.
HAlign and VAlign specify horizontal resp. vertical alignment of the text
within ARect. HPadding and VPadding specify horizontal (both on left and right side)
and vertical (both on top and bottom side) padding of the Text from ARect.
BackColor specifies the fill color for brush gaps if a non solid Brush
is defined in Canvas. Attributes specift various text output attributes. }
procedure DrawAlignedText(Canvas: TCanvas; var ARect: TRect;
HAlign: TKHAlign; VAlign: TKVAlign; HPadding, VPadding: Integer;
const AText: TKString;
BackColor: TColor = clWhite; Attributes: TKTextAttributes = []);
{ Draws standard button frame }
procedure DrawButtonFrame(ACanvas: TCanvas; const ARect: TRect;
AStates: TKButtonDrawStates);
{ Simulates WinAPI DrawEdge with customizable colors. }
procedure DrawEdges(Canvas: TCanvas; const R: TRect; HighlightColor,
ShadowColor: TColor; Flags: Cardinal);
{ Draws a rectangle to Canvas. The rectangle coordinates are given by Rect.
The rectangle is filled by Brush. If Brush is not solid, its gaps are filled
with BackColor. If BackColor is clNone these gaps are not filled and the Brush
appears transparent. }
procedure DrawFilledRectangle(Canvas: TCanvas; const ARect: TRect;
BackColor: TColor);
{ Fills rectangle with linear gradient. Parameters should be self explaining. }
procedure DrawGradientRect(Canvas: TCanvas; const ARect: TRect;
AStartColor, AEndColor: TColor; AColorStep: Integer; AHorizontal: Boolean);
{ This helper function excludes a rectangular area occupied by a shape from
BaseRect and calculates the shape area rectangles Bounds and Interior.
The shape area is specified by the shape extent (ShapeWidth and ShapeHeight),
padding (HPadding and VPadding) and stretching mode (StretchMode).
The returned Bounds includes (possibly stretched) shape + padding,
and Interior includes only the (possibly stretched) shape.
HAlign specifies the horizontal alignment of shape area within BaseRect.
VAlign specifies the vertical alignment of shape area within BaseRect.
The shape area is always excluded horizontally from BaseRect, as needed by cell
data calculations in KGrid. }
procedure ExcludeShapeFromBaseRect(var BaseRect: TRect; ShapeWidth, ShapeHeight: Integer;
HAlign: TKHAlign; VAlign: TKVAlign; HPadding, VPadding: Integer;
StretchMode: TKStretchMode; out Bounds, Interior: TRect);
{ Selects ARect into device context. Returns previous clipping region. }
function ExtSelectClipRect(DC: HDC; ARect: TRect; Mode: Integer; var PrevRgn: HRGN): Boolean;
{ Selects ARect into device context. Combines with CurRgn and
returns previous clipping region. Both regions have to be created first. }
function ExtSelectClipRectEx(DC: HDC; ARect: TRect; Mode: Integer; CurRgn, PrevRgn: HRGN): Boolean;
{ Fills the area specified by the difference Boundary - Interior on ACanvas with current Brush.
If Brush is not solid, its gaps are filled with BackColor. If BackColor is
clNone these gaps are not filled and the Brush appears transparent. }
procedure FillAroundRect(ACanvas: TCanvas; const Boundary, Interior: TRect; BackColor: TColor);
{ Determine the height (ascent + descent) of the font currently selected into given DC. }
function GetFontHeight(DC: HDC): Integer;
{ Determine the ascent of the font currently selected into given DC. }
function GetFontAscent(DC: HDC): Integer;
{ Determine the descent of the font currently selected into given DC. }
function GetFontDescent(DC: HDC): Integer;
{ Determine average character size for given DC. }
function GetAveCharSize(DC: HDC): TSize;
{ Determine checkbox frame size. }
function GetCheckBoxSize: TSize;
{ Try to determine image DPI. }
function GetImageDPI(AGraphic: Tgraphic): TPoint;
{ Raises an exception if GDI resource has not been created. }
function GDICheck(Value: Integer): Integer;
{ Returns horizontal position of shape within ABoundary according to AAlignment. Shape has size defined by AShapeSize. }
function HorizontalShapePosition(AAlignment: TKHAlign; const ABoundary: TRect; const AShapeSize: TPoint): Integer;
{ Creates a TGraphic instance according to the image file header.
Currently supported images are BMP, PNG, MNG, JPG, ICO. }
function ImageByType(const Header: TKImageHeaderString): TGraphic;
{ Calls the IntersectClipRect function. }
function IntersectClipRectIndirect(DC: HDC; ARect: TRect): Boolean;
{ Determines if given color has lightness > 0.5. }
function IsBrightColor(Color: TColor): Boolean;
{ Loads a custom mouse cursor. }
procedure LoadCustomCursor(Cursor: TCursor; const ResName: string);
{ Loads graphic from resource. }
procedure LoadGraphicFromResource(Graphic: TGraphic; const ResName: string; ResType: PChar);
{ Loads picture from clipboard. Clipboard should have CF_PICTURE format. }
procedure LoadPictureFromClipboard(APicture: TPicture; APreferredFormat: TKClipboardFormat);
{ Builds a TKColorRec structure. }
function MakeColorRec(R, G, B, A: Byte): TKColorRec; overload;
{ Builds a TKColorRec structure. }
function MakeColorRec(Value: LongWord): TKColorRec; overload;
{ Returns a pixel format that matches Bpp. }
function PixelFormatFromBpp(Bpp: Cardinal): TPixelFormat;
{ In Lazarus this WinAPI function is missing. }
function RectInRegion(Rgn: HRGN; ARect: TRect): Boolean;
{ Creates the region and copies the device context's current region into it. }
function RgnCreateAndGet(DC: HDC): HRGN;
{ Selects the region into given device context and deletes the region. }
procedure RgnSelectAndDelete(DC: HDC; Rgn: HRGN);
{ Paints rectangle with rounded corners. }
procedure RoundRectangle(ACanvas: TCanvas; const ARect: TRect; AXRadius, AYRadius: Integer);
{ Paints an image so that it fits in ARect. Performs double buffering and fills
the background with current brush for mapped device contexts. }
procedure SafeStretchDraw(ACanvas: TCanvas; ARect: TRect; AGraphic: TGraphic; ABackColor: TColor = clWhite);
{ Selects ARect as new clipping region into the device context. }
procedure SelectClipRect(DC: HDC; const ARect: TRect);
{ Calls StretchBlt. }
procedure StretchBitmap(DestDC: HDC; DestRect: TRect; SrcDC: HDC; SrcRect: TRect);
{ Swaps the color format from RGB to BGR and vice versa. }
function SwitchRGBToBGR(Value: TColor): TColor;
{ Subtracts the current device context offset from ARect. }
procedure TranslateRectToDevice(DC: HDC; var ARect: TRect);
{ Returns vertical position of shape within ABoundary according to AAlignment. Shape has size defined by AShapeSize. }
function VerticalShapePosition(AAlignment: TKVAlign; const ABoundary: TRect; const AShapeSize: TPoint): Integer;
implementation
uses
ClipBrd, Math, SysUtils, KRes;
procedure BlendLine(Src, Dest: PKColorRecs; Count: Integer);
var
I: Integer;
R, G, B, A1, A2: Integer;
begin
// without assembler
for I := 0 to Count - 1 do
begin
A1 := Src[I].A;
A2 := 255 - A1;
Inc(A1);
Inc(A2);
R := Src[I].R * A1 + Dest[I].R * A2;
G := Src[I].G * A1 + Dest[I].G * A2;
B := Src[I].B * A1 + Dest[I].B * A2;
Dest[I].R := R shr 8;
Dest[I].G := G shr 8;
Dest[I].B := B shr 8;
end;
end;
function CalcLightness(Color: TColor): Single;
var
X: TKColorRec;
begin
X := ColorToColorRec(Color);
Result := (X.R + X.G + X.B) / (3 * 256);
end;
function BrightColor(Color: TColor; Percent: Single; Mode: TKBrightMode): TColor;
var
L, Tmp: Single;
function Func1(Value: Single): Single;
begin
Result := Value * (L + Percent) / L;
end;
function Func2(Value: Single): Single;
begin
Result := 1 - (0.5 - Tmp) * (1 - Value) / (1 - L);
{ this is the shorter form of
Value := 1 - 0.5 * (1 - Value) / (1 - L) ; // get color with L = 0.5
Result := 1 - (0.5 - Tmp) * (1 - Value) / 0.5; // get corresponding color
}
end;
function Rd(Value: Single): Byte;
begin
Result := Min(Integer(Round(Value * 255)), 512);
end;
var
R, G, B, Cmax, Cmin: Single;
X: TKColorRec;
begin
X := ColorToColorRec(Color);
R := X.R / 255;
G := X.G / 255;
B := X.B / 255;
Cmax := Max(R, Max(G, B));
Cmin := Min(R, Min(G, B));
L := (Cmax + Cmin) / 2;
if L < 1 then
begin
case Mode of
bsOfBottom: Percent := L * Percent;
bsOfTop: Percent := (1 - L) * Percent;
end;
Percent := Min(Percent, 1 - L);
if L = 0 then
begin
// zero length singularity
R := R + Percent; G := G + Percent; B := B + Percent;
end else
begin
Tmp := L + Percent - 0.5;
// lumination below 0.5
if L < 0.5 then
begin
// if L + Percent is >= 0.5, get color with L = 0.5
Percent := Min(Percent, 0.5 - L);
R := Func1(R); G := Func1(G); B := Func1(B);
L := 0.5;
end;
// lumination above 0.5
if Tmp > 0 then
begin
R := Func2(R); G := Func2(G); B := Func2(B);
end;
end;
X.R := Rd(R);
X.G := Rd(G);
X.B := Rd(B);
end;
Result := X.Value;
end;
procedure CanvasGetScale(ACanvas: TCanvas; out MulX, MulY, DivX, DivY: Integer);
{$IFDEF USE_DC_MAPPING}
var
WindowExt, ViewPortExt: TSize;
{$ENDIF}
begin
{$IFDEF USE_DC_MAPPING}
if Boolean(GetWindowExtEx(ACanvas.Handle, {$IFDEF FPC}@{$ENDIF}WindowExt)) and
Boolean(GetViewPortExtEx(ACanvas.Handle, {$IFDEF FPC}@{$ENDIF}ViewPortExt)) then
begin
DivX := WindowExt.cx; DivY := WindowExt.cy;
MulX := ViewPortExt.cx; MulY := ViewPortExt.cy;
end else
{$ENDIF}
begin
MulX := 1; DivX := 1;
MulY := 1; DivY := 1;
end;
end;
procedure CanvasResetScale(ACanvas: TCanvas);
begin
{$IFDEF USE_DC_MAPPING}
SetMapMode(ACanvas.Handle, MM_TEXT);
{$ENDIF}
end;
function CanvasScaled(ACanvas: TCanvas): Boolean;
begin
{$IFDEF USE_DC_MAPPING}
Result := not (GetMapMode(ACanvas.Handle) in [0, MM_TEXT]);
{$ELSE}
Result := False;
{$ENDIF}
end;
procedure CanvasSetScale(ACanvas: TCanvas; MulX, MulY, DivX, DivY: Integer);
begin
{$IFDEF USE_DC_MAPPING}
SetMapMode(ACanvas.Handle, MM_ANISOTROPIC);
SetWindowExtEx(ACanvas.Handle, DivX, DivY, nil);
SetViewPortExtEx(ACanvas.Handle, MulX, MulY, nil);
{$ELSE}
{$WARNING 'Device context window/viewport transformations not working!'}
{$ENDIF}
end;
procedure CanvasSetOffset(ACanvas: TCanvas; OfsX, OfsY: Integer);
begin
{$IFDEF USE_DC_MAPPING}
SetMapMode(ACanvas.Handle, MM_ANISOTROPIC);
SetViewPortOrgEx(ACanvas.Handle, OfsX, OfsY, nil);
{$ENDIF}
end;
function ColorToGrayScale(Color: TColor): TColor;
var
GreyValue: Integer;
X: TKColorRec;
begin
X := ColorToColorRec(Color);
GreyValue := (Integer(21) * X.R + Integer(72) * X.G + Integer(7) * X.B) div 100;
X.R := GreyValue;
X.G := GreyValue;
X.B := GreyValue;
Result := X.Value;
end;
function ColorRecToColor(Color: TKColorRec): TColor;
begin
Result := Color.Value and $FFFFFF;
end;
function ColorToColorRec(Color: TColor): TKColorRec;
begin
Result.Value := ColorToRGB(Color);
end;
{$IFDEF FPC}
function ColorRecToFPColor(Color: TKColorRec): TFPColor;
begin
Result.Red := Color.R;
Result.Red := Result.Red + (Result.Red shl 8);
Result.Green := Color.G;
Result.Green := Result.Green + (Result.Green shl 8);
Result.Blue := Color.B;
Result.Blue := Result.Blue + (Result.Blue shl 8);
Result.Alpha := Color.A;
Result.Alpha := Result.Alpha + (Result.Alpha shl 8);
end;
function FPColorToColorRec(Color: TFPColor): TKColorRec;
begin
Result.R := Color.Red shr 8;
Result.G := Color.Green shr 8;
Result.B := Color.Blue shr 8;
Result.A := Color.Alpha shr 8;
end;
{$ENDIF}
function CompareBrushes(ABrush1, ABrush2: TBrush): Boolean;
begin
Result :=
(ABrush1.Color = ABrush2.Color) and
(ABrush1.Style = ABrush2.Style);
end;
function CompareFonts(AFont1, AFont2: TFont): Boolean;
begin
Result :=
(AFont1.Charset = AFont2.Charset) and
(AFont1.Color = AFont2.Color) and
(AFont1.Name = AFont2.Name) and
(AFont1.Pitch = AFont2.Pitch) and
(AFont1.Size = AFont2.Size) and
(AFont1.Style = AFont2.Style);
end;
procedure CopyBitmap(DestDC: HDC; DestRect: TRect; SrcDC: HDC; SrcX, SrcY: Integer);
begin
{$IFDEF MSWINDOWS}Windows.{$ENDIF}BitBlt(DestDC,
DestRect.Left, DestRect.Top, DestRect.Right - DestRect.Left, DestRect.Bottom - DestRect.Top,
SrcDC, 0, 0, SRCCOPY);
end;
function CreateEmptyPoint: TPoint;
begin
Result := Point(0,0);
end;
function CreateEmptyPoint64: TKPoint64;
begin
Result := Point64(0,0);
end;
function CreateEmptyRect: TRect;
begin
Result := Rect(0,0,0,0);
end;
function CreateEmptyRect64: TKRect64;
begin
Result := Rect64(0,0,0,0);
end;
function CreateEmptyRgn: HRGN;
begin
Result := CreateRectRgn(0,0,0,0);
end;
procedure DrawAlignedText(Canvas: TCanvas; var ARect: TRect;
HAlign: TKHAlign; VAlign: TKVAlign; HPadding, VPadding: Integer;
const AText: TKString;
BackColor: TColor; Attributes: TKTextAttributes);
var
TextBox: TKTextBox;
Width, Height: Integer;
begin
TextBox := TKTextBox.Create;
try
TextBox.Attributes := Attributes;
TextBox.BackColor := BackColor;
TextBox.HAlign := HAlign;
TextBox.HPadding := HPadding;
TextBox.Text := AText;
TextBox.VAlign := VAlign;
TextBox.VPadding := VPadding;
if taCalcRect in Attributes then
begin
TextBox.Measure(Canvas, ARect, Width, Height);
ARect.Right := ARect.Left + Width;
ARect.Bottom := ARect.Top + Height;
end else
TextBox.Draw(Canvas, ARect);
finally
TextBox.Free;
end;
end;
procedure DrawButtonFrame(ACanvas: TCanvas; const ARect: TRect;
AStates: TKButtonDrawStates);
var
BM: TBitmap;
TmpCanvas: TCanvas;
TmpRect: TRect;
ButtonState: Integer;
{$IFDEF USE_THEMES}
ButtonTheme: TThemedButton;
{$ENDIF}
begin
// a LOT of tweaking here...
{$IF DEFINED(MSWINDOWS) OR DEFINED(LCLQT) } // GTK2 cannot strech and paint on bitmap canvas, grrr..
if CanvasScaled(ACanvas) {$IFDEF MSWINDOWS}and (bsUseThemes in AStates){$ENDIF} then
begin
BM := TBitmap.Create;
BM.Width := ARect.Right - ARect.Left;
BM.Height := ARect.Bottom - ARect.Top;
BM.Canvas.Brush.Assign(ACanvas.Brush);
TmpRect := Rect(0, 0, BM.Width, BM.Height);
BM.Canvas.FillRect(TmpRect);
TmpCanvas := BM.Canvas;
end else
{$IFEND}
begin
BM := nil;
TmpRect := ARect;
TmpCanvas := ACanvas;
end;
try
{$IFDEF USE_THEMES}
if bsUseThemes in AStates then
begin
if bsDisabled in AStates then
ButtonTheme := tbPushButtonDisabled
else if bsPressed in AStates then
ButtonTheme := tbPushButtonPressed
else if bsHot in AStates then
ButtonTheme := tbPushButtonHot
else if bsFocused in AStates then
ButtonTheme := tbPushButtonDefaulted
else
ButtonTheme := tbPushButtonNormal;
ThemeServices.DrawElement(TmpCanvas.Handle, ThemeServices.GetElementDetails(ButtonTheme), TmpRect);
end else
{$ENDIF}
begin
ButtonState := DFCS_BUTTONPUSH;
if bsDisabled in AStates then
ButtonState := ButtonState or DFCS_INACTIVE
else if bsPressed in AStates then
ButtonState := ButtonState or DFCS_PUSHED
else if bsHot in AStates then
ButtonState := ButtonState or DFCS_HOT;
DrawFrameControl(TmpCanvas.Handle, TmpRect, DFC_BUTTON, ButtonState);
end;
if BM <> nil then
ACanvas.Draw(ARect.Left, ARect.Top, BM);
finally
BM.Free;
end;
end;
procedure DrawEdges(Canvas: TCanvas; const R: TRect; HighlightColor,
ShadowColor: TColor; Flags: Cardinal);
begin
with Canvas do
begin
Brush.Style := bsSolid;
Brush.Color := HighlightColor;
if Flags and BF_LEFT <> 0 then
FillRect(Rect(R.Left, R.Top + 1, R.Left + 1, R.Bottom));
if Flags and BF_TOP <> 0 then
FillRect(Rect(R.Left, R.Top, R.Right, R.Top + 1));
Brush.Color := ShadowColor;
if Flags and BF_RIGHT <> 0 then
FillRect(Rect(R.Right - 1, R.Top + 1, R.Right, R.Bottom));
if Flags and BF_BOTTOM <> 0 then
FillRect(Rect(R.Left + 1, R.Bottom - 1, R.Right - 1, R.Bottom));
end;
end;
procedure DrawFilledRectangle(Canvas: TCanvas; const ARect: TRect; BackColor: TColor);
var
DC: HDC;
begin
DC := Canvas.Handle;
if BackColor <> clNone then
begin
SetBkMode(DC, OPAQUE);
SetBkColor(DC, ColorToRGB(BackColor));
end;
FillRect(DC, ARect, Canvas.Brush.Handle);
end;
procedure DrawGradientRect(Canvas: TCanvas; const ARect: TRect;
AStartColor, AEndColor: TColor; AColorStep: Integer; AHorizontal: Boolean);
var
J, OldJ, Extent, Num: Integer;
L: Byte;
CS, CE: TKColorRec;
RCnt, GCnt, BCnt: Longint;
RInc, GInc, BInc: Longint;
B: Boolean;
R: TRect;
function NumToRGB(Num: Cardinal): TKColorRec;
begin
Result.R := Byte(Num shr 16);
Result.G := Byte(Num shr 8);
Result.B := Byte(Num);
end;
function RGBToNum(Col: TKColorRec): Cardinal;
begin
Result := Cardinal(Col.R) shl 16 + Cardinal(Col.G) shl 8 + Col.B;
end;
begin
with Canvas do
begin
if AHorizontal then
Extent := ARect.Right - ARect.Left - 1
else
Extent := ARect.Bottom - ARect.Top - 1;
Num := Max(Extent div AColorStep, 1);
CS := NumToRGB(AStartColor);
CE := NumToRGB(AEndColor);
// colors per pixel
RInc := (Integer(CE.R - CS.R) shl 16) div Extent;
GInc := (Integer(CE.G - CS.G) shl 16) div Extent;
Binc := (Integer(CE.B - CS.B) shl 16) div Extent;
// start colors
RCnt := CS.R shl 16;
GCnt := CS.G shl 16;
BCnt := CS.B shl 16;
// drawing bar
Brush.Color := RGBToNum(CS);
OldJ := 0;
B := False;
for J := 0 to Extent do
begin
Inc(RCnt, RInc);
L := Byte(RCnt shr 16);
if L <> CS.R then
begin
CS.R := L;
B := True;
end;
Inc(GCnt, GInc);
L := Byte(GCnt shr 16);
if L <> CS.G then
begin
CS.G := L;
B := True;
end;
Inc(BCnt, BInc);
L := Byte(BCnt shr 16);
if L <> CS.B then
begin
CS.B := L;
B := True;
end;
if B and (J mod Num = 0) then
begin
if AHorizontal then
R := Rect(ARect.Left + OldJ, ARect.Top, ARect.Left + J, ARect.Bottom)
else
R := Rect(ARect.Left, ARect.Top + OldJ, ARect.Right, ARect.Top + J);
FillRect(R);
Brush.Color := RGBToNum(CS);
OldJ := J;
B := False;
end;
end;
end;
end;
procedure ExcludeShapeFromBaseRect(var BaseRect: TRect; ShapeWidth, ShapeHeight: Integer;
HAlign: TKHAlign; VAlign: TKVAlign; HPadding, VPadding: Integer;
StretchMode: TKStretchMode; out Bounds, Interior: TRect);
var
MaxHeight, MaxWidth, StretchHeight, StretchWidth: Integer;
RatioX, RatioY: Single;
begin
MaxHeight := BaseRect.Bottom - BaseRect.Top - 2 * VPadding;
MaxWidth := BaseRect.Right - BaseRect.Left - HPadding;
if ((MaxWidth <> ShapeWidth) or (MaxHeight <> ShapeHeight)) and (
(StretchMode = stmZoom) or
(StretchMode = stmZoomInOnly) and (MaxWidth >= ShapeWidth) and (MaxHeight >= ShapeHeight) or
(StretchMode = stmZoomOutOnly) and ((MaxWidth < ShapeWidth) or (MaxHeight < ShapeHeight))
) then
begin
RatioX := MaxWidth / ShapeWidth;
RatioY := MaxHeight / ShapeHeight;
if RatioY >= RatioX then
begin
StretchWidth := MaxWidth;
StretchHeight := ShapeHeight * StretchWidth div ShapeWidth;
end else
begin
StretchHeight := MaxHeight;
StretchWidth := ShapeWidth * StretchHeight div ShapeHeight;
end;
end else
begin
StretchHeight := ShapeHeight;
StretchWidth := ShapeWidth;
end;
Bounds := BaseRect;
Interior := BaseRect;
case HAlign of
halCenter:
begin
BaseRect.Right := BaseRect.Left; // BaseRect empty, no space for next item!
// Bounds remains unchanged
Inc(Interior.Left, HPadding + (MaxWidth - StretchWidth) div 2);
end;
halRight:
begin
Dec(BaseRect.Right, StretchWidth + HPadding);
Bounds.Left := BaseRect.Right;
// Bounds.Right remains unchanged
Interior.Left := BaseRect.Right;
end;
else
Inc(BaseRect.Left, StretchWidth + HPadding);
// Bounds.Left remains unchanged
Bounds.Right := BaseRect.Left;
Inc(Interior.Left, HPadding);
end;
Interior.Right := Interior.Left + StretchWidth;
case VAlign of
valCenter: Inc(Interior.Top, VPadding + (MaxHeight - StretchHeight) div 2);
valBottom: Interior.Top := BaseRect.Bottom - VPadding - StretchHeight;
else
Inc(Interior.Top, VPadding);
end;
Interior.Bottom := Interior.Top + StretchHeight;
end;
function ExtSelectClipRect(DC: HDC; ARect: TRect; Mode: Integer; var PrevRgn: HRGN): Boolean;
var
TmpRgn: HRGN;
begin
TmpRgn := CreateEmptyRgn;
try
Result := ExtSelectClipRectEx(DC, ARect, Mode, TmpRgn, PrevRgn)
finally
DeleteObject(TmpRgn);
end;
end;
function ExtSelectClipRectEx(DC: HDC; ARect: TRect; Mode: Integer; CurRgn, PrevRgn: HRGN): Boolean;
var
RectRgn: HRGN;
// R1, R2: TRect;
begin
RectRgn := CreateRectRgnIndirect(ARect);
try
// GetRgnBox(PrevRgn, R1); // debug line
// GetRgnBox(RectRgn, R2); // debug line
Result := CombineRgn(CurRgn, PrevRgn, RectRgn, Mode) <> NULLREGION;
if Result then
SelectClipRgn(DC, CurRgn)
finally
DeleteObject(RectRgn);
end;
end;
procedure FillAroundRect(ACanvas: TCanvas; const Boundary, Interior: TRect; BackColor: TColor);
var
R: TRect;
begin
R := Rect(Boundary.Left, Boundary.Top, Boundary.Right, Interior.Top);
if not IsRectEmpty(R) then DrawFilledRectangle(ACanvas, R, BackColor);
R := Rect(Boundary.Left, Interior.Top, Interior.Left, Interior.Bottom);
if not IsRectEmpty(R) then DrawFilledRectangle(ACanvas, R, BackColor);
R := Rect(Interior.Right, Interior.Top, Boundary.Right, Interior.Bottom);
if not IsRectEmpty(R) then DrawFilledRectangle(ACanvas, R, BackColor);
R := Rect(Boundary.Left, Interior.Bottom, Boundary.Right, Boundary.Bottom);
if not IsRectEmpty(R) then DrawFilledRectangle(ACanvas, R, BackColor);
end;
function GetFontHeight(DC: HDC): Integer;
var
TM: TTextMetric;
begin
FillChar(TM, SizeOf(TTextMetric), 0);
GetTextMetrics(DC, TM);
Result := TM.tmHeight;
end;
function GetFontAscent(DC: HDC): Integer;
var
TM: TTextMetric;
begin
FillChar(TM, SizeOf(TTextMetric), 0);
GetTextMetrics(DC, TM);
Result := TM.tmAscent;
end;
function GetFontDescent(DC: HDC): Integer;
var
TM: TTextMetric;
begin
FillChar(TM, SizeOf(TTextMetric), 0);
GetTextMetrics(DC, TM);
Result := TM.tmDescent;
end;
function GetAveCharSize(DC: HDC): TSize;
var
TM: TTextMetric;
const
Buffer = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
begin
FillChar(TM, SizeOf(TTextMetric), 0);
GetTextMetrics(DC, TM);
GetTextExtentPoint32(DC, Buffer, 52, Result);
Result.cx := (Result.cx div 26 + 1) div 2; //div uses trunc rounding; we want arithmetic rounding
Result.cy := tm.tmHeight;
end;
function GetCheckBoxSize: TSize;
{$IFDEF MSWINDOWS}
var
Bm: HBITMAP;
BmSize: BITMAP;
{$ENDIF}
{$IFDEF FPC}
{$ELSE}
var
Theme: HTHEME;
{$ENDIF}
begin
Result.cx := 0;
Result.cy := 0;
{$IFDEF USE_THEMES}
if ThemeServices.ThemesEnabled and ThemeServices.ThemesAvailable then
begin
{$IFDEF FPC}
Result := ThemeServices.GetDetailSize(ThemeServices.GetElementDetails(tbCheckBoxCheckedNormal));
Exit;
{$ELSE}
Theme := ThemeServices.Theme[teButton];
if GetThemePartSize(Theme, 0, BP_CHECKBOX, CBS_CHECKEDNORMAL, nil, TS_TRUE, Result) = S_OK then
Exit;
{$ENDIF}
end;
{$ENDIF}
{$IFDEF MSWINDOWS}
Bm := LoadBitmap(0, PChar(OBM_CHECKBOXES));
if Bm <> 0 then
try
if GetObject(Bm, SizeOf(BmSize), @BmSize) = SizeOf(BmSize) then
begin
Result.cx := BmSize.bmWidth div 4;
Result.cy := BmSize.bmHeight div 3;
end;
finally
DeleteObject(Bm);
end;
{$ELSE}
// just guessed here
Result.cx := 13;
Result.cy := 13;
{$ENDIF}
end;
function GetImageDPI(AGraphic: Tgraphic): TPoint;
procedure GetDPIFromJPeg(AJPeg: TJPegImage);
const
cInchesPerCM = (1 / 2.54);
cBufferSize = 50;
var
MS: TMemoryStream;
Index: Integer;
Buffer: AnsiString;
resUnits: Byte;
xResolution: Word;
yResolution: Word;
begin
// seek for XDensity and YDensity fields in JPEG header
MS := TMemoryStream.Create;
try
AJPeg.SaveToStream(MS);
MS.Seek(0, soFromBeginning);
SetLength(Buffer, cBufferSize);
MS.Read(Buffer[1], cBufferSize);
Index := Pos(AnsiString('JFIF'+#$00), Buffer);
if Index > 0 then
begin
MS.Seek(Index + 6, soFromBeginning);
MS.Read(resUnits, 1);
MS.Read(xResolution, 2);
MS.Read(yResolution, 2);
xResolution := Swap(xResolution);
yResolution := Swap(yResolution);
case resUnits of
1: // dots per inch
begin
Result.X := xResolution;
Result.Y := yResolution;
end;
2: // dots per cm
begin
Result.X := Round(xResolution / cInchesPerCM);
Result.Y := Round(yResolution / cInchesPerCM);
end;
else
Result.X := 96;
Result.Y := MulDiv(96, yResolution, xResolution);
end;
end;
finally
MS.Free;
end;
end;
{$IFDEF USE_PNG_SUPPORT}
procedure GetDPIFromPng(APng: TKPngImage);
const
cInchesPerMeter = (100 / 2.54);
{$IFDEF FPC}
type
TPngChunkCode = array[0..3] of AnsiChar;
TPngChunkHdr = packed record
clength: LongWord;
ctype: TPngChunkCode;
end;
var
MS: TMemoryStream;
CLen, PPUnitX, PPUnitY: Cardinal;
CHdr: TPngChunkHdr;
CPHYsData: array[0..8] of Byte;
{$ELSE}
var
Chunk: TChunk;
{$ENDIF}
begin
{$IFDEF FPC}
MS := TMemoryStream.Create;
try
APng.SaveToStream(MS);
MS.Seek(8, soFromBeginning); // skip PNG header
while MS.Position < MS.Size do
begin
// traverse the PNG chunks until pHYs chunk is found
MS.Read(CHdr, SizeOf(CHdr));
CLen := SwapEndian(CHdr.clength); // suppose little endian
if CHdr.ctype = 'pHYs' then
begin
MS.Read(CPHYsData, 9); // pHYs chunk is always 9 bytes long
if CPHYsData[8] = 1 then // dots per meter
begin
PPUnitX := SwapEndian(PCardinal(@CPHYsData[0])^); // suppose little endian
PPUnitY := SwapEndian(PCardinal(@CPHYsData[4])^); // suppose little endian
Result.X := Round(PPUnitX / cInchesPerMeter);
Result.Y := Round(PPUnitY / cInchesPerMeter);
end;
Exit;
end else
MS.Seek(CLen + SizeOf(LongWord), soFromCurrent);
end;
finally
MS.Free;
end;
{$ELSE}
// in Delphi we have the pHYs chunk directly accessible
Chunk := APng.Chunks.FindChunk(TChunkpHYs);
if Assigned(Chunk) then
begin
if (TChunkPhys(Chunk).UnitType = utMeter) then
begin
Result.X := Round(TChunkPhys(Chunk).PPUnitX / cInchesPerMeter);
Result.Y := Round(TChunkPhys(Chunk).PPUnitY / cInchesPerMeter);
end;
end
{$ENDIF}
end;
{$ENDIF}
begin
Result := Point(96, 96); // for unimplemented image types set screen dpi
if AGraphic is TJPegImage then
GetDPIFromJPeg(TJpegImage(AGraphic))
{$IFDEF USE_PNG_SUPPORT}
else if AGraphic is TKPngImage then
GetDPIFromPng(TKPngImage(AGraphic));
{$ENDIF}
end;
function GDICheck(Value: Integer): Integer;
begin
if Value = 0 then
raise EOutOfResources.Create(sGDIError);
Result := Value;
end;
function HorizontalShapePosition(AAlignment: TKHAlign; const ABoundary: TRect; const AShapeSize: TPoint): Integer;
begin
case AAlignment of
halCenter: Result := ABoundary.Left + (ABoundary.Right - ABoundary.Left - AShapeSize.X) div 2;
halRight: Result := ABoundary.Right - AShapeSize.X;
else
Result := ABoundary.Left;
end;
end;
function ImageByType(const Header: TKImageHeaderString): TGraphic;
begin
if Pos('BM', {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1 then
Result := TBitmap.Create
{$IFDEF USE_PNG_SUPPORT }
else if (Pos(#$89'PNG', {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1) or
(Pos(#$8A'MNG', {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1) then
Result := TKPngImage.Create
{$ENDIF }
else if (Pos(#$FF#$D8, {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1) then
Result := TJPegImage.Create
else if (Pos(#$00#$00, {$IFDEF COMPILER12_UP}string{$ENDIF}(Header)) = 1) then
Result := TIcon.Create
else
Result := nil;
end;
function IntersectClipRectIndirect(DC: HDC; ARect: TRect): Boolean;
begin
with ARect do
Result := IntersectClipRect(DC, Left, Top, Right, Bottom) <> NULLREGION;
end;
function IsBrightColor(Color: TColor): Boolean;
begin
Result := CalcLightness(Color) > 0.5;
end;
function MakeColorRec(R, G, B, A: Byte): TKColorRec;
begin
Result.R := R;
Result.G := G;
Result.B := B;
Result.A := A;
end;
function MakeColorRec(Value: LongWord): TKColorRec;
begin
Result.Value := Value;
end;
procedure LoadCustomCursor(Cursor: TCursor; const ResName: string);
begin
Screen.Cursors[Cursor] :=
{$IFDEF FPC}
LoadCursorFromLazarusResource(ResName);
{$ELSE}
LoadCursor(HInstance, PChar(ResName));
{$ENDIF}
end;
procedure LoadGraphicFromResource(Graphic: TGraphic; const ResName: string; ResType: PChar);
{$IFNDEF FPC}
var
Stream: TResourceStream;
{$ENDIF}
begin
if Graphic <> nil then
try
{$IFDEF FPC}
try
Graphic.LoadFromResourceName(HInstance, ResName);
except
Graphic.LoadFromLazarusResource(ResName);
end;
{$ELSE}
Stream := TResourceStream.Create(HInstance, ResName, ResType);
try
Graphic.LoadFromStream(Stream);
finally
Stream.Free;
end;
{$ENDIF}
except
Error(sErrGraphicsLoadFromResource);
end;
end;
procedure LoadPictureFromClipboard(APicture: TPicture; APreferredFormat: TKClipboardFormat);
begin
try
{$IFDEF FPC}
APicture.LoadFromClipboardFormat(APreferredFormat);
{$ELSE}
APicture.LoadFromClipboardFormat(APreferredFormat, Clipboard.GetAsHandle(APreferredFormat), 0);
{$ENDIF}
except
APicture.Assign(ClipBoard);
end;
end;
function PixelFormatFromBpp(Bpp: Cardinal): TPixelFormat;
begin
case Bpp of
1: Result := pf1bit;
2..4: Result := pf4bit;
5..8: Result := pf8bit;
9..16: Result := pf16bit;
else
Result := pf32bit;
end;
end;
function RectInRegion(Rgn: HRGN; ARect: TRect): Boolean;
{$IFDEF FPC}
var
RectRgn, TmpRgn: HRGN;
{$ENDIF}
begin
{$IFDEF FPC}
RectRgn := CreateRectRgnIndirect(ARect);
try
TmpRgn := CreateEmptyRgn;
try
Result := CombineRgn(TmpRgn, RectRgn, Rgn, RGN_AND) <> NULLREGION;
finally
DeleteObject(TmpRgn);
end;
finally
DeleteObject(RectRgn);
end;
{$ELSE}
Result := Windows.RectInRegion(Rgn, ARect);
{$ENDIF}
end;
function RgnCreateAndGet(DC: HDC): HRGN;
//var
// R: TRect;
begin
Result := CreateEmptyRgn;
GetClipRgn(DC, Result);
// GetRgnBox(Result, R); // debug line
end;
procedure RgnSelectAndDelete(DC: HDC; Rgn: HRGN);
begin
SelectClipRgn(DC, Rgn);
DeleteObject(Rgn);
end;
procedure RoundRectangle(ACanvas: TCanvas; const ARect: TRect; AXRadius, AYRadius: Integer);
begin
{$IF DEFINED(COMPILER12_UP) OR DEFINED(FPC)}
ACanvas.RoundRect(ARect, AXRadius, AYRadius)
{$ELSE}
ACanvas.RoundRect(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom, AXRadius, AYRadius)
{$IFEND}
end;
procedure SafeStretchDraw(ACanvas: TCanvas; ARect: TRect; AGraphic: TGraphic; ABackColor: TColor);
{$IFDEF MSWINDOWS}
{var
BM: TBitmap;
W, H, MulX, MulY, DivX, DivY: Integer;
R: TRect;}
{$ENDIF}
begin
{$IFDEF MSWINDOWS}
// tk: I cannot see problem with StretchBlt anymore, perhaps it was in old Windows XP?
// Even if so, following implementation is buggy:
{if AGraphic.Transparent then
begin
// WinAPI StretchBlt function does not read properly from screen buffer
// so we have to append double buffering
CanvasGetScale(ACanvas, MulX, MulY, DivX, DivY);
W := MulDiv(ARect.Right - ARect.Left, MulX, DivX);
H := MulDiv(ARect.Bottom - ARect.Top, MulY, DivY);
BM := TBitmap.Create;
try
BM.Width := W;
BM.Height := H;
BM.Canvas.Brush := ACanvas.Brush;
R := Rect(0, 0, W, H);
DrawFilledRectangle(BM.Canvas, R, ABackColor);
BM.Canvas.StretchDraw(R, AGraphic);
ACanvas.StretchDraw(ARect, BM);
finally
BM.Free;
end;
end else}
{$ENDIF}
ACanvas.StretchDraw(ARect, AGraphic);
end;
procedure SelectClipRect(DC: HDC; const ARect: TRect);
var
Rgn: HRGN;
begin
Rgn := CreateRectRgnIndirect(ARect);
try
SelectClipRgn(DC, Rgn);
finally
DeleteObject(Rgn);
end;
end;
procedure StretchBitmap(DestDC: HDC; DestRect: TRect; SrcDC: HDC; SrcRect: TRect);
begin
{$IFDEF MSWINDOWS}
SetStretchBltMode(DestDC, HALFTONE);
{$ENDIF}
{$IFDEF MSWINDOWS}Windows.{$ENDIF}StretchBlt(DestDC,
DestRect.Left, DestRect.Top, DestRect.Right - DestRect.Left, DestRect.Bottom - DestRect.Top,
SrcDC, SrcRect.Left, SrcRect.Top, SrcRect.Right - SrcRect.Left, SrcRect.Bottom - SrcRect.Top,
SRCCOPY);
end;
procedure SwapBR(var ColorRec: TKColorRec);
var
Tmp: Byte;
begin
Tmp := ColorRec.R;
ColorRec.R := ColorRec.B;
ColorRec.B := Tmp;
end;
function SwitchRGBToBGR(Value: TColor): TColor;
var
B: Byte;
begin
Result := Value;
B := PKColorRec(@Value).B;
PKColorRec(@Result).B := PKColorRec(@Result).R;
PKColorRec(@Result).R := B;
end;
procedure TranslateRectToDevice(DC: HDC; var ARect: TRect);
var
WindowOrg, ViewportOrg: TPoint;
{$IFDEF USE_DC_MAPPING}
{$IFNDEF LCLQT}
WindowExt, ViewportExt: TSize;
{$ENDIF}
{$ENDIF}
begin
if Boolean(GetWindowOrgEx(DC, {$IFDEF FPC}@{$ENDIF}WindowOrg)) then
KFunctions.OffsetRect(ARect, -WindowOrg.X, -WindowOrg.Y);
{$IFDEF USE_DC_MAPPING}
{$IFNDEF LCLQT}
if not (GetMapMode(DC) in [0, MM_TEXT]) and
Boolean(GetWindowExtEx(DC, {$IFDEF FPC}@{$ENDIF}WindowExt)) and
Boolean(GetViewportExtEx(DC, {$IFDEF FPC}@{$ENDIF}ViewportExt)) then
begin
ARect.Left := MulDiv(ARect.Left, ViewportExt.cx, WindowExt.cx);
ARect.Right := MulDiv(ARect.Right, ViewportExt.cx, WindowExt.cx);
ARect.Top := MulDiv(ARect.Top, ViewportExt.cy, WindowExt.cy);
ARect.Bottom := MulDiv(ARect.Bottom, ViewportExt.cy, WindowExt.cy);
end;
if Boolean(GetViewPortOrgEx(DC, {$IFDEF FPC}@{$ENDIF}ViewportOrg)) then
KFunctions.OffsetRect(ARect, ViewportOrg);
{$ENDIF}
{$ENDIF}
end;
function VerticalShapePosition(AAlignment: TKVAlign; const ABoundary: TRect; const AShapeSize: TPoint): Integer;
begin
case AAlignment of
valCenter: Result := ABoundary.Top + (ABoundary.Bottom - ABoundary.Top - AShapeSize.Y) div 2;
valBottom: Result := ABoundary.Bottom - AShapeSize.Y;
else
Result := ABoundary.Top;
end;
end;
{ TKGraphic }
constructor TKGraphic.Create;
begin
inherited;
FDescription := '';
FFileFilter := '';
end;
{ TKAlphaBitmap }
constructor TKAlphaBitmap.Create;
begin
inherited;
FCanvas := TCanvas.Create;
FCanvas.Handle := CreateCompatibleDC(0);
FUpdateLock := 0;
FAutoMirror := True;
FDescription := 'KControls alpha bitmap';
FDirectCopy := False;
FFileFilter := '*.bma;*.bmp;*.png;*.jpg';
FHandle := 0;
{$IFNDEF MSWINDOWS}
FImage := TLazIntfImage.Create(0, 0);
{$ENDIF}
FHeight := 0;
FOldBitmap := 0;
FPixels := nil;
FPixelsChanged := False;
FWidth := 0;
end;
constructor TKAlphaBitmap.CreateFromRes(const ResName: string);
var
Stream: {$IFDEF FPC}TLazarusResourceStream{$ELSE}TResourceStream{$ENDIF};
begin
Create;
try
{$IFDEF FPC}
Stream := TLazarusResourceStream.Create(LowerCase(ResName), 'BMP');
{$ELSE}
Stream := TResourceStream.Create(HInstance, ResName, RT_RCDATA);
{$ENDIF}
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
except
Error(sErrGraphicsLoadFromResource);
end;
end;
destructor TKAlphaBitmap.Destroy;
var
DC: HDC;
begin
LockUpdate;
SetSize(0, 0);
{$IFNDEF MSWINDOWS}
FImage.Free;
{$ENDIF}
DC := FCanvas.Handle;
FCanvas.Handle := 0;
DeleteDC(DC);
FCanvas.Free;
inherited;
end;
procedure TKAlphaBitmap.AlphaDrawTo(ACanvas: TCanvas; X, Y: Integer);
begin
AlphaStretchDrawTo(ACanvas, Rect(X, Y, X + FWidth, Y + FHeight));
end;
procedure TKAlphaBitmap.AlphaFill(Alpha: Byte; IfEmpty: Boolean);
var
I: Integer;
LocHasAlpha: Boolean;
begin
LocHasAlpha := False;
if IfEmpty then
LocHasAlpha := HasAlpha;
if not LocHasAlpha then
begin
LockUpdate;
try
for I := 0 to FWidth * FHeight - 1 do
FPixels[I].A := Alpha;
finally
UnlockUpdate;
end;
end;
end;
procedure TKAlphaBitmap.AlphaFillOnColorMatch(AColor: TColor; AAlpha: Byte);
var
I: Integer;
CS: TKColorRec;
begin
LockUpdate;
try
CS := ColorToColorRec(AColor);
SwapBR(CS);
for I := 0 to FWidth * FHeight - 1 do
if (FPixels[I].R = CS.R) and (FPixels[I].G = CS.G) and (FPixels[I].B = CS.B) then
FPixels[I].A := AAlpha;
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.AlphaFillPercent(Percent: Integer; IfEmpty: Boolean);
var
I: Integer;
begin
LockUpdate;
try
for I := 0 to FWidth * FHeight - 1 do
if FPixels[I].A <> 0 then
FPixels[I].A := Percent * FPixels[I].A div 100
else if IfEmpty then
FPixels[I].A := Percent * 255 div 100;
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.AlphaFill(Alpha: Byte; BlendColor: TColor; Gradient, Translucent: Boolean);
var
I, J, A1, A2, AR, AG, AB, HAlpha: Integer;
HStep, HSum, VStep, VSum: Single;
Scan: PKColorRecs;
CS: TKColorRec;
begin
LockUpdate;
try
VSum := 0; VStep := 0;
HSum := 0; HStep := 0;
if Gradient then
begin
VStep := Alpha / FHeight;
VSum := Alpha;
end;
CS := ColorToColorRec(BlendColor);
{$IFNDEF MSWINDOWS}
for I := 0 to FHeight - 1 do
{$ELSE}
for I := FHeight - 1 downto 0 do
{$ENDIF}
begin
Scan := ScanLine[I];
HAlpha := Alpha;
if Gradient then
begin
HStep := HAlpha / FWidth;
HSum := HAlpha;
end;
for J := 0 to FWidth - 1 do with Scan[J] do
begin
A1 := HAlpha;
A2 := 255 - HAlpha;
AR := R * A1 + CS.R * A2;
AG := G * A1 + CS.G * A2;
AB := B * A1 + CS.B * A2;
R := AR shr 8;
G := AG shr 8;
B := AB shr 8;
if Translucent then
A := HAlpha
else
A := 255;
if Gradient then
begin
HAlpha := Round(HSum);
HSum := HSum - HStep;
end;
end;
if Gradient then
begin
Alpha := Round(VSum);
VSum := VSum - VStep;
end;
end;
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.AlphaStretchDrawTo(ACanvas: TCanvas;
const ARect: TRect);
{$IF DEFINED(MSWINDOWS) OR DEFINED(LCLGTK) OR DEFINED(LCLGTK2)}
var
I: Integer;
Tmp: TKAlphaBitmap;
Ps, Pd: PKColorRecs;
{$IFEND}
begin
{$IF DEFINED(MSWINDOWS) OR DEFINED(LCLGTK) OR DEFINED(LCLGTK2)}
Tmp := TKAlphaBitmap.Create;
try
Tmp.SetSize(FWidth, FHeight);
Tmp.Fill(MakeColorRec(255, 255, 255, 0));
Tmp.DrawFrom(ACanvas, ARect);
for I := 0 to FHeight - 1 do
begin
Ps := ScanLine[I];
Pd := Tmp.ScanLine[I];
BlendLine(Ps, Pd, FWidth);
end;
Tmp.PixelsChanged := True;
Tmp.DrawTo(ACanvas, ARect);
finally
Tmp.Free;
end;
{$ELSE}
DrawTo(ACanvas, ARect);
{$IFEND}
end;
procedure TKAlphaBitmap.Assign(Source: TPersistent);
begin
if Source = nil then
SetSize(0, 0)
else if Source is TKAlphaBitmap then
TKAlphaBitmap(Source).AssignTo(Self)
else if Source is TGraphic then
LoadFromGraphic(TGraphic(Source))
else
inherited;
end;
procedure TKAlphaBitmap.AssignTo(Dest: TPersistent);
begin
if Dest is TKAlphaBitmap then with TKAlphaBitmap(Dest) do
begin
AutoMirror := Self.AutoMirror;
DirectCopy := Self.DirectCopy;
CopyFrom(Self);
end
end;
procedure TKAlphaBitmap.Clear;
var
I: Integer;
begin
LockUpdate;
try
for I := 0 to FWidth * FHeight - 1 do
FPixels[I].Value := 0;
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.Changed(Sender: TObject);
begin
inherited;
FPixelsChanged := True;
end;
procedure TKAlphaBitmap.CombinePixel(X, Y: Integer; Color: TKColorRec);
var
Index, A1, A2, AR, AG, AB: Integer;
begin
if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then
begin
LockUpdate;
try
SwapBR(Color);
{$IFDEF MSWINDOWS}
Index := (FHeight - Y - 1) * FWidth + X;
{$ELSE}
Index := Y * FWidth + X;
{$ENDIF}
A2 := Color.A;
if A2 = 255 then
FPixels[Index] := Color
else if A2 <> 0 then
begin
A1 := 255 - Color.A;
AR := FPixels[Index].R * A1 + Color.R * A2;
AG := FPixels[Index].G * A1 + Color.G * A2;
AB := FPixels[Index].B * A1 + Color.B * A2;
FPixels[Index].R := AR shr 8;
FPixels[Index].G := AG shr 8;
FPixels[Index].B := AB shr 8;
FPixels[Index].A := 255;
end;
finally
UnlockUpdate;
end;
end;
end;
procedure TKAlphaBitmap.CopyFrom(AGraphic: TGraphic);
begin
if AGraphic is TKAlphaBitmap then
CopyFromAlphaBitmap(AGraphic as TKAlphaBitmap)
{$IFDEF USE_PNG_SUPPORT}
else if AGraphic is TKPngImage then
CopyFromPng(AGraphic as TKPngImage)
{$ENDIF}
else if AGraphic is TJpegImage then
CopyFromJpeg(AGraphic as TJpegImage)
else
DrawFrom(AGraphic, 0, 0);
end;
procedure TKAlphaBitmap.CopyFromAlphaBitmap(ABitmap: TKAlphaBitmap);
var
I, Size: Integer;
begin
LockUpdate;
try
SetSize(ABitmap.Width, ABitmap.Height);
Size := FWidth * SizeOf(TKColorRec);
for I := 0 to FHeight - 1 do
Move(ABitmap.ScanLine[I]^, ScanLine[I]^, Size);
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.CopyFromJpeg(AJpegImage: TJPEGImage);
{$IFDEF FPC}
var
I, J: Integer;
C: TKColorRec;
IM: TLazIntfImage;
FC: TFPColor;
{$ENDIF}
begin
LockUpdate;
try
SetSize(AJpegImage.Width, AJpegImage.Height);
{$IFDEF FPC}
IM := AJpegImage.CreateIntfImage;
try
for I := 0 to AJpegImage.Width - 1 do
begin
for J := 0 to AJpegImage.Height - 1 do
begin
FC := IM.Colors[I, J];
C := FPColorToColorRec(FC);
Pixel[I, J] := C;
end;
end;
finally
IM.Free;
end;
{$ELSE}
// no access to JPEG pixels under Delphi
DrawFrom(AJpegImage, 0, 0);
DirectCopy := not HasAlpha;
AlphaFill(255, True);
{$ENDIF}
finally
UnlockUpdate;
end;
end;
{$IFDEF USE_PNG_SUPPORT}
procedure TKAlphaBitmap.CopyFromPng(APngImage: TKPngImage);
var
I, J: Integer;
C: TKColorRec;
{$IFDEF FPC}
IM: TLazIntfImage;
FC: TFPColor;
{$ENDIF}
begin
LockUpdate;
try
SetSize(APngImage.Width, APngImage.Height);
{$IFDEF FPC}
IM := APngImage.CreateIntfImage;
try
{$ENDIF}
for I := 0 to APngImage.Width - 1 do
begin
for J := 0 to APngImage.Height - 1 do
begin
{$IFDEF FPC}
FC := IM.Colors[I, J];
C := FPColorToColorRec(FC);
{$ELSE}
C.Value := APngImage.Pixels[I, J];
if APngImage.AlphaScanline[J] <> nil then
C.A := APngImage.AlphaScanline[J][I]
else
C.A := 255;
{$ENDIF}
Pixel[I, J] := C;
end;
end;
{$IFDEF FPC}
finally
IM.Free;
end;
{$ENDIF}
finally
UnlockUpdate;
end;
end;
{$ENDIF}
procedure TKAlphaBitmap.CopyFromRotated(ABitmap: TKAlphaBitmap);
var
I, J: Integer;
SrcScan, DstScan: PKColorRecs;
begin
LockUpdate;
try
SetSize(ABitmap.Height, ABitmap.Width);
for J := 0 to ABitmap.Height - 1 do
begin
SrcScan := ABitmap.ScanLine[J];
for I := 0 to ABitmap.Width - 1 do
begin
DstScan := ScanLine[ABitmap.Width - I - 1];
DstScan[J] := SrcScan[I];
end;
end;
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.CopyFromXY(X, Y: Integer; AGraphic: TGraphic);
begin
if AGraphic is TKAlphaBitmap then
CopyFromXYAlphaBitmap(X, Y, AGraphic as TKAlphaBitmap)
{$IFDEF USE_PNG_SUPPORT}
else if AGraphic is TKPngImage then
CopyFromXYPng(X, Y, AGraphic as TKPngImage)
{$ENDIF}
else if AGraphic is TJpegImage then
CopyFromXYJpeg(X, Y, AGraphic as TJpegImage)
else
DrawFrom(AGraphic, X, Y);
end;
procedure TKAlphaBitmap.CopyFromXYAlphaBitmap(X, Y: Integer; ABitmap: TKAlphaBitmap);
var
I, J: Integer;
begin
LockUpdate;
try
for I := X to X + ABitmap.Width - 1 do
for J := Y to Y + ABitmap.Height - 1 do
if (I >= 0) and (I < FWidth) and (J >= 0) and (J < FHeight) then
Pixels[J * FWidth + I] := ABitmap.Pixels[(J - Y) * ABitmap.Width + (I - X)];
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.CopyFromXYJpeg(X, Y: Integer; AJpegImage: TJPEGImage);
{$IFDEF FPC}
var
I, J: Integer;
C: TKColorRec;
IM: TLazIntfImage;
FC: TFPColor;
{$ENDIF}
begin
LockUpdate;
try
{$IFDEF FPC}
IM := AJpegImage.CreateIntfImage;
try
for I := X to X + AJpegImage.Width - 1 do
begin
for J := Y to Y + AJpegImage.Height - 1 do
begin
if (I >= 0) and (I < FWidth) and (J >= 0) and (J < FHeight) then
begin
FC := IM.Colors[I - X, J - Y];
C := FPColorToColorRec(FC);
Pixel[I, J] := C;
end;
end;
end;
finally
IM.Free;
end;
{$ELSE}
// no access to JPEG pixels under Delphi
DrawFrom(AJpegImage, X, Y);
DirectCopy := not HasAlpha;
AlphaFill(255, True);
{$ENDIF}
finally
UnlockUpdate;
end;
end;
{$IFDEF USE_PNG_SUPPORT}
procedure TKAlphaBitmap.CopyFromXYPng(X, Y: Integer; APngImage: TKPngImage);
var
I, J: Integer;
C: TKColorRec;
{$IFDEF FPC}
IM: TLazIntfImage;
FC: TFPColor;
{$ENDIF}
begin
LockUpdate;
try
{$IFDEF FPC}
IM := APngImage.CreateIntfImage;
try
{$ENDIF}
for I := X to X + APngImage.Width - 1 do
begin
for J := Y to Y + APngImage.Height - 1 do
begin
if (I >= 0) and (I < FWidth) and (J >= 0) and (J < FHeight) then
begin
{$IFDEF FPC}
FC := IM.Colors[I - X, J - Y];
C := FPColorToColorRec(FC);
{$ELSE}
C.Value := APngImage.Pixels[I - X, J - Y];
if APngImage.AlphaScanline[J - Y] <> nil then
C.A := APngImage.AlphaScanline[J - Y][I - X]
else
C.A := 255;
{$ENDIF}
Pixel[I, J] := C;
end;
end;
end;
{$IFDEF FPC}
finally
IM.Free;
end;
{$ENDIF}
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.CopyToPng(APngImage: TKPngImage);
var
I, J: Integer;
C: TKColorRec;
{$IFDEF FPC}
IM: TLazIntfImage;
FC: TFPColor;
{$ELSE}
IM: TKPngImage;
{$ENDIF}
begin
UpdatePixels;
{$IFDEF FPC}
IM := TLazIntfImage.Create(0, 0, [riqfRGB, riqfAlpha]);
{$ELSE}
IM := TKPngImage.CreateBlank(COLOR_RGBALPHA, 8, FWidth, FHeight);
{$ENDIF}
try
{$IFDEF FPC}
IM.SetSize(FWidth, FHeight);
{$ENDIF}
for I := 0 to FWidth - 1 do
begin
for J := 0 to FHeight - 1 do
begin
C := Pixel[I, J];
{$IFDEF FPC}
FC := ColorRecToFPColor(C);
IM.Colors[I, J] := FC;
{$ELSE}
IM.Pixels[I, J] := C.Value;
if IM.AlphaScanline[J] <> nil then
IM.AlphaScanline[J][I] := C.A;
{$ENDIF}
end;
end;
{$IFDEF FPC}
APngImage.LoadFromIntfImage(IM);
{$ELSE}
APngImage.Assign(IM);
{$ENDIF}
finally
IM.Free;
end;
end;
{$ENDIF}
procedure TKAlphaBitmap.Draw(ACanvas: TCanvas; const ARect: TRect);
begin
if FDirectCopy then
DrawTo(ACanvas, ARect)
else
AlphaStretchDrawTo(ACanvas, ARect);
end;
procedure TKAlphaBitmap.DrawFrom(ACanvas: TCanvas; const ARect: TRect);
begin
if not Empty then
begin
if not CanvasScaled(ACanvas) then
StretchBitmap(FCanvas.Handle, Rect(0, 0, FWidth, FHeight), ACanvas.Handle, ARect)
else
begin
FCanvas.Brush := ACanvas.Brush;
DrawFilledRectangle(FCanvas, Rect(0, 0, FWidth, FHeight),
{$IFDEF MSWINDOWS}GetBkColor(ACanvas.Handle){$ELSE}clWindow{$ENDIF});
end;
UpdatePixels;
end;
end;
procedure TKAlphaBitmap.DrawFrom(AGraphic: TGraphic; X, Y: Integer);
begin
if not Empty then
begin
UpdateHandle;
FCanvas.Draw(X, Y, AGraphic);
UpdatePixels;
end;
end;
procedure TKAlphaBitmap.DrawTo(ACanvas: TCanvas; const ARect: TRect);
begin
if not Empty then
begin
UpdateHandle;
StretchBitmap(ACanvas.Handle, ARect, FCanvas.Handle, Rect(0, 0, FWidth, FHeight))
end;
end;
procedure TKAlphaBitmap.Fill(Color: TKColorRec);
var
I: Integer;
begin
LockUpdate;
try
for I := 0 to FWidth * FHeight - 1 do
FPixels[I].Value := Color.Value;
finally
UnlockUpdate;
end;
end;
function TKAlphaBitmap.GetEmpty: Boolean;
begin
Result := (FWidth = 0) and (FHeight = 0);
end;
function TKAlphaBitmap.GetHeight: Integer;
begin
Result := FHeight;
end;
function TKAlphaBitmap.GetPixel(X, Y: Integer): TKColorRec;
begin
if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then
begin
{$IFDEF MSWINDOWS}
Result := FPixels[(FHeight - Y - 1) * FWidth + X];
{$ELSE}
Result := FPixels[Y * FWidth + X];
{$ENDIF}
SwapBR(Result);
end else
Result := MakeColorRec(0,0,0,0);
end;
function TKAlphaBitmap.GetTransparent: Boolean;
begin
Result := True;
end;
function TKAlphaBitmap.GetScanLine(Index: Integer): PKColorRecs;
begin
// no checks here
Result := @FPixels[Index * FWidth];
end;
function TKAlphaBitmap.GetHandle: HBITMAP;
begin
Result := FHandle;
end;
function TKAlphaBitmap.GetHasAlpha: Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to FWidth * FHeight - 1 do
if FPixels[I].A <> 0 then
begin
Result := True;
Break;
end;
end;
function TKAlphaBitmap.GetWidth: Integer;
begin
Result := FWidth;
end;
procedure TKAlphaBitmap.GrayScale;
var
I, Average: Integer;
begin
LockUpdate;
try
for I := 0 to FWidth * FHeight - 1 do
begin
// R and B are swapped
Average := (Integer(7) * FPixels[I].R + Integer(72) * FPixels[I].G + Integer(21) * FPixels[I].B) div 100;
FPixels[I].R := Average;
FPixels[I].G := Average;
FPixels[I].B := Average;
end;
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.Brighten(APercent: Single; AMode: TKBrightMode);
var
I: Integer;
X: TKColorRec;
begin
LockUpdate;
try
for I := 0 to FWidth * FHeight - 1 do
begin
X.Value := BrightColor(ColorRecToColor(FPixels[I]), APercent, AMode);
FPixels[I].R := X.R;
FPixels[I].G := X.G;
FPixels[I].B := X.B;
end;
finally
UnlockUpdate;
end;
end;
{$IFNDEF FPC}
procedure TKAlphaBitmap.LoadFromClipboardFormat(AFormat: Word; AData: THandle;
APalette: HPALETTE);
begin
// does nothing
end;
{$ENDIF}
procedure TKAlphaBitmap.LoadFromFile(const Filename: string);
var
IM: TPicture;
begin
IM := TPicture.Create;
try
IM.LoadFromFile(FileName);
LoadFromGraphic(IM.Graphic);
finally
IM.Free;
end;
end;
procedure TKAlphaBitmap.LoadFromHandles(ABitmap, AMask: HBITMAP);
begin
// todo
end;
procedure TKAlphaBitmap.LoadFromGraphic(Image: TGraphic);
begin
LockUpdate;
try
SetSize(Image.Width, Image.Height);
{$IFDEF MSWINDOWS}
Canvas.Draw(0, 0, Image);
{$ELSE}
if Image is TRasterImage then
FImage.Assign(TRasterImage(Image).CreateIntfImage);
{$ENDIF}
// if bitmap has no alpha channel, create full opacity
AlphaFill($FF, True);
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.LoadFromStream(Stream: TStream);
var
BF: TBitmapFileHeader;
BI: TBitmapInfoHeader;
begin
Stream.Read(BF, SizeOf(TBitmapFileHeader));
if BF.bfType = $4D42 then
begin
Stream.Read(BI, SizeOf(TBitmapInfoHeader));
if BI.biBitCount = 32 then
begin
LockUpdate;
try
SetSize(BI.biWidth, BI.biHeight);
Stream.Read(FPixels^, BI.biSizeImage);
// if bitmap has no alpha channel, create full opacity
AlphaFill($FF, True);
{$IFnDEF MSWINDOWS}
if FAutoMirror then
MirrorVert;
{$ENDIF}
finally
UnlockUpdate;
end;
end;
end;
end;
procedure TKAlphaBitmap.LockUpdate;
begin
Inc(FUpdateLock);
end;
procedure TKAlphaBitmap.MirrorHorz;
var
I, J, Index: Integer;
SrcScan: PKColorRecs;
Buf: TKColorRec;
begin
LockUpdate;
try
for I := 0 to FHeight - 1 do
begin
SrcScan := ScanLine[I];
Index := FWidth - 1;
for J := 0 to (FWidth shr 1) - 1 do
begin
Buf := SrcScan[Index];
SrcScan[Index] := SrcScan[J];
SrcScan[J] := Buf;
Dec(Index);
end;
end;
finally
UnlockUpdate;
end;
end;
procedure TKAlphaBitmap.MirrorVert;
var
I, Size, Index: Integer;
SrcScan, DstScan: PKColorRecs;
Buf: PKColorRec;
begin
LockUpdate;
try
Size:= FWidth * SizeOf(TKColorRec);
Index := FHeight - 1;
GetMem(Buf, Size);
try
for I := 0 to (FHeight shr 1) - 1 do
begin
SrcScan := ScanLine[I];
DstScan := ScanLine[Index];
Move(SrcScan^, Buf^, Size);
Move(DstScan^, SrcScan^, Size);
Move(Buf^, DstScan^, Size);
Dec(Index);
end;
finally
FreeMem(Buf);
end;
finally
UnlockUpdate;
end;
end;
{$IFNDEF FPC}
procedure TKAlphaBitmap.SaveToClipboardFormat(var AFormat: Word;
var AData: THandle; var APalette: HPALETTE);
begin
// does nothing
end;
{$ENDIF}
procedure TKAlphaBitmap.SaveToStream(Stream: TStream);
var
Size: Integer;
BF: TBitmapFileHeader;
BI: TBitmapInfoHeader;
begin
{$IFnDEF MSWINDOWS}
if FAutoMirror then
MirrorVert;
{$ENDIF}
Size := FWidth * FHeight * 4;
FillChar(BF, SizeOf(TBitmapFileHeader), 0);
BF.bfType := $4D42;
BF.bfSize := SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader) + Size;
BF.bfOffBits := SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader);
Stream.Write(BF, SizeOf(TBitmapFileHeader));
FillChar(BI, SizeOf(TBitmapInfoHeader), 0);
BI.biSize := SizeOf(TBitmapInfoHeader);
BI.biWidth := FWidth;
BI.biHeight := FHeight;
BI.biPlanes := 1;
BI.biBitCount := 32;
BI.biCompression := BI_RGB;
BI.biSizeImage := Size;
Stream.Write(BI, SizeOf(TBitmapInfoHeader));
Stream.Write(FPixels^, Size);
{$IFnDEF MSWINDOWS}
if FAutoMirror then
MirrorVert;
{$ENDIF}
end;
procedure TKAlphaBitmap.SetHeight(Value: Integer);
begin
SetSize(FWidth, Value);
end;
procedure TKAlphaBitmap.SetPixel(X, Y: Integer; Value: TKColorRec);
begin
if (X >= 0) and (X < FWidth) and (Y >= 0) and (Y < FHeight) then
begin
LockUpdate;
try
SwapBR(Value);
{$IFDEF MSWINDOWS}
FPixels[(FHeight - Y - 1) * FWidth + X] := Value;
{$ELSE}
FPixels[Y * FWidth + X] := Value;
{$ENDIF}
finally
UnlockUpdate;
end;
end;
end;
procedure TKAlphaBitmap.SetSize(AWidth, AHeight: Integer);
var
{$IFNDEF MSWINDOWS}
ImgFormatDescription: TRawImageDescription;
{$ELSE}
BI: TBitmapInfoHeader;
{$ENDIF}
begin
AWidth := Max(AWidth, 0);
AHeight := Max(AHeight, 0);
if (AWidth <> FWidth) or (AHeight <> FHeight) then
begin
LockUpdate;
try
FWidth := AWidth;
FHeight := AHeight;
if FHandle <> 0 then
begin
SelectObject(FCanvas.Handle, FOldBitmap);
DeleteObject(FHandle);
FHandle := 0;
{$IFNDEF MSWINDOWS}
DeleteObject(FMaskHandle);
FMaskHandle := 0;
{$ENDIF}
end;
{$IFNDEF MSWINDOWS}
FImage.SetSize(0, 0);
{$ENDIF}
FPixels := nil;
if (FWidth <> 0) and (FHeight <> 0) then
begin
{$IFNDEF MSWINDOWS}
ImgFormatDescription.Init_BPP32_B8G8R8A8_BIO_TTB(FWidth,FHeight);
FImage.DataDescription := ImgFormatDescription;
FPixelsChanged := True;
UpdateHandle;
{$ELSE}
FillChar(BI, SizeOf(TBitmapInfoHeader), 0);
BI.biSize := SizeOf(TBitmapInfoHeader);
BI.biWidth := FWidth;
BI.biHeight := FHeight;
BI.biPlanes := 1;
BI.biBitCount := 32;
BI.biCompression := BI_RGB;
FHandle := GDICheck(CreateDIBSection(FCanvas.Handle, PBitmapInfo(@BI)^, DIB_RGB_COLORS, Pointer(FPixels), 0, 0));
FOldBitmap := SelectObject(FCanvas.Handle, FHandle);
{$ENDIF}
end;
finally
UnlockUpdate;
end;
end;
end;
procedure TKAlphaBitmap.SetWidth(Value: Integer);
begin
SetSize(Value, FWidth);
end;
procedure TKAlphaBitmap.SetTransparent(Value: Boolean);
begin
// does nothing
end;
procedure TKAlphaBitmap.UnlockUpdate;
begin
if FUpdateLock > 0 then
begin
Dec(FUpdateLock);
if FUpdateLock = 0 then
Changed(Self);
end;
end;
procedure TKAlphaBitmap.UpdateHandle;
begin
{$IFNDEF MSWINDOWS}
if FPixelsChanged then
begin
PixelsChanged := False;
if FHandle <> 0 then
begin
DeleteObject(FMaskHandle);
DeleteObject(SelectObject(FCanvas.Handle, FOldBitmap));
end;
FImage.CreateBitmaps(FHandle, FMaskHandle, False);
FOldBitmap := SelectObject(FCanvas.Handle, FHandle);
FPixels := PKColorRecs(FImage.PixelData);
end;
{$ENDIF}
end;
procedure TKAlphaBitmap.UpdatePixels;
begin
{$IFNDEF MSWINDOWS}
FImage.LoadFromDevice(FCanvas.Handle);
FPixelsChanged := True;
UpdateHandle;
{$ENDIF}
end;
{ TKMetafile }
{$IFDEF MSWINDOWS}
constructor TKMetafile.Create;
begin
inherited;
FCopyOnAssign := True;
FEmfHandle := 0;
FRequiredHeight := 0;
FRequiredWidth := 0;
FWmfHandle := 0;
end;
destructor TKMetafile.Destroy;
begin
Clear;
inherited;
end;
procedure TKMetafile.Assign(Source: TPersistent);
var
Stream: TMemoryStream;
begin
if Source is TKMetafile then
begin
Clear;
FEnhanced := TKMetafile(Source).Enhanced;
if TKMetafile(Source).CopyOnAssign then
begin
Stream := TMemoryStream.Create;
try
TKMetafile(Source).SaveToStream(Stream);
Stream.Seek(0, soFromBeginning);
LoadFromStream(Stream);
finally
Stream.Free;
end;
end else
begin
// here, the source loses the images!
TKMetafile(Source).Release(FWmfHandle, FEmfHandle);
end;
FRequiredHeight := TKMetafile(Source).Height;
FRequiredWidth := TKMetafile(Source).Width;
end;
end;
procedure TKMetafile.Clear;
begin
if FWmfHandle <> 0 then
begin
DeleteMetafile(FWmfHandle);
FWmfHandle := 0;
end;
if FEmfHandle <> 0 then
begin
DeleteEnhMetafile(FEmfHandle);
FEmfHandle := 0;
end;
end;
procedure TKMetafile.Draw(ACanvas: TCanvas; const Rect: TRect);
var
BM: TKAlphaBitmap;
begin
inherited;
if FWMfHandle <> 0 then
begin
if FRequiredWidth * FRequiredHeight > 0 then
begin
BM := TKAlphaBitmap.Create;
try
BM.DirectCopy := True;
BM.SetSize(FRequiredWidth, FRequiredHeight);
BM.Fill(MakeColorRec(255,255,255,255));
PlayMetafile(BM.Canvas.Handle, FWmfHandle);
BM.DirectCopy := False;
BM.DrawTo(ACanvas, Rect);
finally
BM.Free;
end;
end;
end
else if FEMFHandle <> 0 then
begin
PlayEnhMetafile(ACanvas.Handle, FEmfHandle, Rect);
end;
end;
function TKMetafile.GetEmpty: Boolean;
begin
Result := (FWmfHandle = 0) and (FEmfHandle = 0);
end;
function TKMetafile.GetHeight: Integer;
begin
Result := FRequiredHeight;
end;
function TKMetafile.GetTransparent: Boolean;
begin
Result := False;
end;
function TKMetafile.GetWidth: Integer;
begin
Result := FRequiredWidth;
end;
procedure TKMetafile.LoadFromStream(Stream: TStream);
var
S: AnsiString;
EHDR: TEnhMetaheader;
MFP: TMetaFilePict;
begin
SetLength(S, Stream.Size - Stream.Position);
if S <> '' then
begin
Stream.Read(EHDR, SizeOf(TEnhMetaHeader));
Stream.Seek(-SizeOf(TEnhMetaHeader), soFromCurrent);
Stream.Read(S[1], Length(S));
if FEnhanced and (EHDR.iType = EMR_HEADER) then
begin
FEmfHandle := SetEnhMetafileBits(Length(S), @S[1]);
FRequiredWidth := EHDR.rclBounds.Right - EHDR.rclBounds.Left;
FRequiredHeight := EHDR.rclBounds.Bottom - EHDR.rclBounds.Top;
end else
begin
FWmfHandle := SetMetafileBitsEx(Length(S), @S[1]);
if FWmfHandle <> 0 then
begin
// obtain width and height
with MFP do
begin
MM := MM_ANISOTROPIC;
xExt := 0;
yExt := 0;
hmf := 0;
end;
FEmfHandle := SetWinMetaFileBits(Length(S), @S[1], 0, MFP);
if FEmfHandle <> 0 then
begin
if GetEnhMetaFileHeader(FEmfHandle, SizeOf(TEnhMetaHeader), @EHDR) > 0 then
begin
FRequiredWidth := EHDR.rclBounds.Right - EHDR.rclBounds.Left;
FRequiredHeight := EHDR.rclBounds.Bottom - EHDR.rclBounds.Top;
end;
DeleteEnhMetafile(FEmfHandle);
FEmfHandle := 0;
end;
end;
end;
end;
end;
procedure TKMetafile.Release(out AWmfHandle: HMETAFILE; out AEmfHandle: HENHMETAFILE);
begin
AWmfHandle := FWmfHandle;
FWmfHandle := 0;
AEmfHandle := FEmfHandle;
FEmfHandle := 0;
end;
procedure TKMetafile.SaveToStream(Stream: TStream);
var
S: AnsiString;
Size: Integer;
begin
S := '';
if FWmfHandle <> 0 then
begin
Size := GetMetaFileBitsEx(FWmfHandle, 0, nil);
if Size > 0 then
begin
SetLength(S, Size);
GetMetafileBitsEx(FWmfHandle, Size, @S[1]);
end;
end
else if FEmfHandle <> 0 then
begin
Size := GetEnhMetaFileBits(FEmfHandle, 0, nil);
if Size > 0 then
begin
SetLength(S, Size);
GetEnhMetafileBits(FEmfHandle, Size, @S[1]);
end;
end;
if S <> '' then
Stream.Write(S[1], Length(S));
end;
procedure TKMetafile.SetEMFHandle(const Value: HENHMETAFILE);
begin
Clear;
FEMFHandle := Value;
end;
procedure TKMetafile.SetEnhanced(const Value: Boolean);
begin
FEnhanced := Value;
end;
procedure TKMetafile.SetHeight(Value: Integer);
begin
FRequiredHeight := Value;
end;
procedure TKMetafile.SetWidth(Value: Integer);
begin
FRequiredWidth := Value;
end;
procedure TKMetafile.SetWMFHandle(const Value: HMETAFILE);
begin
Clear;
FWMFHandle := Value;
end;
{$ENDIF}
{ TKTextBox }
constructor TKTextBox.Create;
begin
inherited;
FAttributes := [];
FBackColor := clWhite;
FHAlign := halLeft;
FHasTabs := False;
FHPadding := 0;
FSelBkgnd := clHighlight;
FSelColor := clHighlightText;
FSelEnd := 0;
FSelStart := 0;
FSpacesForTab := 8;
FText := '';
FVAlign := valCenter;
FVPadding := 0;
end;
procedure TKTextBox.Draw(ACanvas: TCanvas; const ARect: TRect);
var
Y: Integer;
TmpRect: TRect;
PrevRgn: HRGN;
begin
if not IsRectEmpty(ARect) then
begin
if taFillRect in Attributes then
DrawFilledRectangle(ACanvas, ARect, BackColor);
if FText <> '' then
begin
Initialize(ACanvas, ARect);
if not IsRectEmpty(FClipRect) then
begin
Y := GetVertPos;
TmpRect := FClipRect;
if taClip in Attributes then
begin
TranslateRectToDevice(ACanvas.Handle, TmpRect);
PrevRgn := RgnCreateAndGet(ACanvas.Handle);
try
if ExtSelectClipRect(ACanvas.Handle, TmpRect, RGN_AND, PrevRgn) then
begin
if not (taFillText in Attributes) then
SetBkMode(ACanvas.Handle, TRANSPARENT);
Process(Y, tbfDraw);
end;
finally
RgnSelectAndDelete(ACanvas.Handle, PrevRgn);
end;
end else
begin
if not (taFillText in Attributes) then
SetBkMode(ACanvas.Handle, TRANSPARENT);
Process(Y, tbfDraw);
end;
end;
end;
end;
end;
function TKTextBox.GetHorzPos(ATextWidth: Integer): Integer;
begin
case HAlign of
halCenter:
Result := Max(FClipRect.Left, (FClipRect.Left + FClipRect.Right - ATextWidth) div 2);
halRight:
Result := FClipRect.Right - ATextWidth;
else
Result := FClipRect.Left;
end;
end;
function TKTextBox.GetVertPos: Integer;
begin
case VAlign of
valCenter:
begin
Process(0, tbfMeasure);
Result := Max(FClipRect.Top, (FClipRect.Bottom + FClipRect.Top - FCalcRect.Top) div 2);
end;
valBottom:
begin
Process(0, tbfMeasure);
Result := FClipRect.Bottom - FCalcRect.Top;
end
else
Result := FClipRect.Top;
end;
end;
function TKTextBox.IndexToRect(ACanvas: TCanvas; const ARect: TRect; AIndex: Integer): TRect;
var
Y: Integer;
begin
Initialize(ACanvas, ARect);
Y := GetVertPos;
FIndex := AIndex;
Process(Y, tbfGetRect);
Result := FCalcRect;
end;
procedure TKTextBox.Initialize(ACanvas: TCanvas; const ARect: TRect);
begin
FCanvas := ACanvas;
FClipRect := ARect;
InflateRect(FClipRect, -HPadding, -VPadding);
FFontHeight := GetFontHeight(FCanvas.Handle);
end;
procedure TKTextBox.Measure(ACanvas: TCanvas; const ARect: TRect; var AWidth, AHeight: Integer);
begin
Initialize(ACanvas, ARect);
Process(0, tbfMeasure);
AWidth := FCalcRect.Left;
AHeight := FCalcRect.Top;
end;
procedure TKTextBox.Process(Y: Integer; AFunction: TKTextBoxFunction);
var
StartEllipsis, EndEllipsis, PathEllipsis: Boolean;
Width, EllipsisWidth: Integer;
NormalColor, NormalBkgnd: TColor;
procedure Measure(AStart, ALen: Integer);
begin
FCalcRect.Left := Max(FCalcRect.Left, TextExtent(FCanvas, FText, AStart, ALen, FHasTabs, FSpacesForTab).cx);
end;
procedure GetIndex(Y: Integer; AStart, ALen: Integer);
var
Index, NewIndex, X, Width: Integer;
begin
if FIndex < 0 then
begin
if not (taIncludePadding in Attributes) and (Y <= FCalcRect.Top) and (FCalcRect.Top < Y + FFontHeight) or
(taIncludePadding in Attributes) and (
(AStart = 1) and (FClipRect.Top <= FCalcRect.Top) and (FCalcRect.Top < Y + FFontHeight) or
(AStart + ALen = Length(FText) + 1) and (Y <= FCalcRect.Top) and (FCalcRect.Top < FClipRect.Bottom)
) then
begin
Width := TextExtent(FCanvas, FText, AStart, ALen, FHasTabs, FSpacesForTab).cx;
X := GetHorzPos(Width);
if not (taIncludePadding in Attributes) and (X <= FCalcRect.Left) and (FCalcRect.Left < X + Width) or
(taIncludePadding in Attributes) and (FClipRect.Left <= FCalcRect.Left) and (FCalcRect.Left < FClipRect.Right) then
begin
Index := AStart;
while (FIndex < 0) and (Index <= AStart + ALen - 1) do
begin
NewIndex := StrNextCharIndex(FText, Index);
Inc(X, TextExtent(FCanvas, FText, Index, NewIndex - Index, FHasTabs, FSpacesForTab).cx);
if FCalcRect.Left < X then
FIndex := Index;
Index := NewIndex;
end;
if (taIncludePadding in Attributes) and (FIndex < 0) and (FCalcRect.Left < FClipRect.Right) then
FIndex := Index;
end;
end;
end;
end;
procedure GetRect(Y: Integer; AStart, ALen: Integer);
var
Index, NewIndex, X, Width: Integer;
begin
if (FIndex >= AStart) and (FIndex <= ALen) then
begin
Index := AStart;
Width := TextExtent(FCanvas, FText, AStart, ALen, FHasTabs, FSpacesForTab).cx;
X := GetHorzPos(Width);
while Index < FIndex do
begin
NewIndex := StrNextCharIndex(FText, Index);
Inc(X, TextExtent(FCanvas, FText, Index, NewIndex - Index, FHasTabs, FSpacesForTab).cx);
Index := NewIndex;
end;
NewIndex := StrNextCharIndex(FText, Index);
FCalcRect := Rect(X, Y, X + TextExtent(FCanvas, FText, Index, NewIndex - Index, FHasTabs, FSpacesForTab).cx, Y + FFontHeight);
end
end;
procedure Draw(Y: Integer; AStart, ALen: Integer);
var
DrawEllipsis, DrawFileName, SetNormalColors, SetSelectionColors: Boolean;
AWidth, Index, NewIndex, SlashPos, FileNameLen, EllipsisMaxX, X: Integer;
S: TKString;
begin
if (Y >= FClipRect.Top - FFontHeight) and (Y <= FClipRect.Bottom) then
begin
DrawEllipsis := False;
DrawFileName := False;
SlashPos := 0;
FileNameLen := 0;
if (StartEllipsis or EndEllipsis or PathEllipsis) and (ALen > 1) then
begin
AWidth := TextExtent(FCanvas, FText, AStart, ALen, FHasTabs, FSpacesForTab).cx;
if AWidth > Width then
begin
AWidth := 0;
Index := AStart;
if EndEllipsis or StartEllipsis then
begin
EllipsisMaxX := Width - EllipsisWidth;
if EndEllipsis then
begin
while Index <= AStart + ALen - 1 do
begin
NewIndex := StrNextCharIndex(FText, Index);
Inc(AWidth, TextExtent(FCanvas, FText, Index, NewIndex - Index, FHasTabs, FSpacesForTab).cx);
if (AWidth >= EllipsisMaxX) and (Index > AStart) then
Break
else
Index := NewIndex;
end;
ALen := Index - AStart;
end else
begin
Index := AStart + ALen - 1;
while Index > AStart do
begin
NewIndex := StrPreviousCharIndex(FText, Index);
Inc(AWidth, TextExtent(FCanvas, FText, Index, Index - NewIndex, FHasTabs, FSpacesForTab).cx);
if AWidth >= EllipsisMaxX then
Break
else
Index := NewIndex;
end;
if Index = AStart + ALen - 1 then
begin
AStart := Index;
ALen := 1;
end else
begin
Dec(ALen, Index - AStart);
AStart := Index + 1;
end;
end;
DrawEllipsis := True;
end
else if PathEllipsis then
begin
SlashPos := AStart + ALen - 1;
while (SlashPos > 0) and not CharInSetEx(FText[SlashPos], ['/', '\']) do
Dec(SlashPos);
Dec(SlashPos);
if SlashPos > 0 then
begin
DrawEllipsis := True;
DrawFileName := True;
FileNameLen := AStart + ALen - SlashPos;
EllipsisMaxX := Width - TextExtent(FCanvas, FText, SlashPos, FileNameLen, FHasTabs, FSpacesForTab).cx - EllipsisWidth;
while (Index <= SlashPos) do
begin
NewIndex := StrNextCharIndex(FText, Index);
Inc(AWidth, TextExtent(FCanvas, FText, Index, NewIndex - Index, FHasTabs, FSpacesForTab).cx);
if AWidth >= EllipsisMaxX then
Break
else
Index := NewIndex;
end;
ALen := Index - AStart;
end;
end;
end;
end;
if DrawEllipsis then
begin
if DrawFileName then
S := Copy(FText, AStart, ALen) + cEllipsis + Copy(FText, AStart + SlashPos, FileNameLen)
else if EndEllipsis then
S := Copy(FText, AStart, ALen) + cEllipsis
else
S := cEllipsis + Copy(FText, AStart, ALen);
AStart := 1;
ALen := Length(S);
end else
S := FText;
X := GetHorzPos(TextExtent(FCanvas, S, AStart, ALen, FHasTabs, FSpacesForTab).cx);
if DrawEllipsis or (SelStart = SelEnd) then
TextOutput(FCanvas, X, Y, S, AStart, ALen, FHasTabs, FSpacesForTab)
else
begin
AWidth := 0;
Index := AStart;
SlashPos := Index; // reuse
while (Index <= AStart + ALen) do
begin
DrawFileName := False; // reuse
SetNormalColors := False;
SetSelectionColors := False;
if Index = SelStart then
begin
DrawFileName := True;
SetSelectionColors := True;
end
else if Index = SelEnd then
begin
DrawFileName := True;
SetNormalColors := True;
end
else if Index = AStart + ALen then
begin
DrawFileName := True;
end;
if DrawFileName then
begin
if Index > SlashPos then
begin
if SetNormalColors then
DrawFilledRectangle(FCanvas, Rect(X, Y, X + AWidth, Y + FFontHeight), FBackColor);
if not (taFillText in Attributes) then
SetBkMode(FCanvas.Handle, TRANSPARENT);
TextOutput(FCanvas, X, Y, S, SlashPos, Index - SlashPos, FHasTabs, FSpacesForTab);
end;
Inc(X, AWidth);
AWidth := 0;
SlashPos := Index;
end;
if Index < AStart + ALen then
begin
NewIndex := StrNextCharIndex(FText, Index);
Inc(AWidth, TextExtent(FCanvas, FText, Index, NewIndex - Index, FHasTabs, FSpacesForTab).cx);
Index := NewIndex;
end else
Inc(Index);
if SetNormalColors then
begin
FCanvas.Font.Color := NormalColor;
FCanvas.Brush.Color := NormalBkgnd;
end
else if SetSelectionColors then
begin
FCanvas.Font.Color := SelColor;
FCanvas.Brush.Color := SelBkgnd;
end;
end;
end;
end;
end;
var
I, Index, TextLen, LineBegin, LineBreaks, Vert, TrimStart, TrimLen: Integer;
WordBreak, LineBreak, WhiteSpace, PrevWhiteSpace, FirstWord,
WasLineBreak, WrapText: Boolean;
Size: TSize;
begin
case AFunction of
tbfMeasure: FCalcRect := CreateEmptyRect;
tbfGetIndex: FIndex := -1;
tbfGetRect: FCalcRect := CreateEmptyRect;
tbfDraw: ;
end;
Vert := Y;
if FText <> '' then
begin
LineBegin := 1;
LineBreaks := 0;
TextLen := Length(FText);
Width := FClipRect.Right - FClipRect.Left;
WordBreak := taWordBreak in Attributes;
LineBreak := taLineBreak in Attributes;
WrapText := taWrapText in Attributes; //JR:20091229
if AFunction = tbfDraw then
begin
StartEllipsis := taStartEllipsis in Attributes;
EndEllipsis := taEndEllipsis in Attributes;
PathEllipsis := taPathEllipsis in Attributes;
EllipsisWidth := TextExtent(FCanvas, cEllipsis, 1, Length(cEllipsis)).cx;
NormalColor := FCanvas.Font.Color;
NormalBkgnd := FCanvas.Brush.Color;
end;
if WordBreak or LineBreak then
begin
I := LineBegin;
Index := LineBegin;
WhiteSpace := True;
FirstWord := True;
WasLineBreak := False;
while I <= TextLen + 1 do
begin
PrevWhiteSpace := WhiteSpace;
WhiteSpace := CharInSetEx(FText[I], cWordBreaks + cLineBreaks);
if (not PrevWhiteSpace and WhiteSpace and (I > LineBegin))
or (not PrevWhiteSpace and WrapText and (I > LineBegin)) then //JR:20091229
begin
if (WordBreak or WrapText) and (LineBreaks = 0) and not FirstWord then
begin
TrimStart := LineBegin;
TrimLen := I - LineBegin;
TextTrim(FText, TrimStart, TrimLen);
Size := TextExtent(FCanvas, FText, TrimStart, TrimLen, FHasTabs, FSpacesForTab);
if Size.cx > Width then
Inc(LineBreaks);
end;
if LineBreaks > 0 then
begin
if Index > LineBegin then
begin
TrimStart := LineBegin;
TrimLen := Index - LineBegin;
TextTrim(FText, TrimStart, TrimLen);
case AFunction of
tbfMeasure: Measure(TrimStart, TrimLen);
tbfGetIndex: GetIndex(Vert, TrimStart, TrimLen);
tbfGetRect: GetRect(Vert, TrimStart, TrimLen);
tbfDraw: Draw(Vert, TrimStart, TrimLen);
end;
LineBegin := Index;
end;
Inc(Vert, FFontHeight * LineBreaks);
LineBreaks := 0;
end;
Index := I;
FirstWord := False;
end;
if LineBreak then
if CharInSetEx(FText[I], cLineBreaks) then
begin
if not WasLineBreak then
begin
Inc(LineBreaks);
WasLineBreak := True;
end;
end else
WasLineBreak := False;
Inc(I);
end;
end;
if LineBegin <= TextLen then
begin
TrimStart := LineBegin;
TrimLen := TextLen - LineBegin + 1;
TextTrim(FText, TrimStart, TrimLen);
case AFunction of
tbfMeasure: Measure(TrimStart, TrimLen);
tbfGetIndex: GetIndex(Vert, TrimStart, TrimLen);
tbfGetRect: GetRect(Vert, TrimStart, TrimLen);
tbfDraw: Draw(Vert, TrimStart, TrimLen)
end;
Inc(Vert, FFontHeight * (1 + LineBreaks));
end;
end;
case AFunction of
tbfMeasure:
begin
if FText = '' then
FCalcRect.Top := FFontHeight
else
FCalcRect.Top := Vert - Y;
end;
tbfGetIndex: ;
tbfGetRect: if FText = '' then
begin
I := GetHorzPos(0);
FCalcRect := Rect(I, Y, I, Y + FFontHeight);
end;
tbfDraw: ;
end;
end;
procedure TKTextBox.SetText(const AText: TKString);
begin
if AText <> FText then
begin
FText := AText;
FHasTabs := Pos(cTAB, FText) > 0;
end;
end;
function TKTextBox.PointToIndex(ACanvas: TCanvas; const ARect: TRect; APoint: TPoint): Integer;
var
Y: Integer;
begin
Initialize(ACanvas, ARect);
Y := GetVertPos;
FCalcRect.TopLeft := APoint;
Process(Y, tbfGetIndex);
Result := FIndex;
end;
class function TKTextBox.TextExtent(ACanvas: TCanvas; const AText: TKString;
AStart, ALen: Integer; AExpandTabs: Boolean; ASpacesForTab: Integer): TSize;
var
S: TKString;
TextPtr: PKText;
begin
S := '';
if AExpandTabs then
begin
S := Copy(AText, AStart, ALen);
ConvertTabsToSpaces(S, ASpacesForTab);
TextPtr := @S[1];
ALen := Length(S);
end else
TextPtr := @AText[AStart];
{$IFDEF STRING_IS_UNICODE}
{$IFDEF FPC}
{$IFDEF USE_CANVAS_METHODS}
if not AExpandTabs then
S := Copy(AText, AStart, ALen);
Result := ACanvas.TextExtent(S); // little slower but more secure in Lazarus
{$ELSE}
GetTextExtentPoint32(ACanvas.Handle, TextPtr, ALen, Result);
{$ENDIF}
{$ELSE}
GetTextExtentPoint32(ACanvas.Handle, TextPtr, ALen, Result);
{$ENDIF}
{$ELSE}
GetTextExtentPoint32W(ACanvas.Handle, TextPtr, ALen, Result);
{$ENDIF}
end;
class procedure TKTextBox.TextOutput(ACanvas: TCanvas; X, Y: Integer;
const AText: TKString; AStart, ALen: Integer; AExpandTabs: Boolean; ASpacesForTab: Integer);
var
S: TKString;
TextPtr: PKText;
begin
if AExpandTabs then
begin
S := Copy(AText, AStart, ALen);
ConvertTabsToSpaces(S, ASpacesForTab);
TextPtr := @S[1];
ALen := Length(S);
end else
begin
TextPtr := @AText[AStart];
S := AText;
end;
{$IFDEF STRING_IS_UNICODE}
{$IFDEF FPC}
{$IFDEF USE_CANVAS_METHODS}
if not AExpandTabs then
S := Copy(S, AStart, ALen);
ACanvas.TextOut(X, Y, S); // little slower but more secure in Lazarus
{$ELSE}
TextOut(ACanvas.Handle, X, Y, TextPtr, ALen);
{$ENDIF}
{$ELSE}
TextOut(ACanvas.Handle, X, Y, TextPtr, ALen);
{$ENDIF}
{$ELSE}
TextOutW(ACanvas.Handle, X, Y, TextPtr, ALen);
{$ENDIF}
end;
procedure TKTextBox.TextTrim(const AText: TKString; var AStart, ALen: Integer);
begin
if taLineBreak in Attributes then
TrimWhiteSpaces(AText, AStart, ALen, cLineBreaks);
if taTrimWhiteSpaces in Attributes then
TrimWhiteSpaces(AText, AStart, ALen, cWordBreaks);
end;
{ TKDragWindow }
{$IFDEF MSWINDOWS}
const
cLayeredWndClass = 'KControls drag window';
function DragWndProc(Window: HWnd; Msg, WParam, LParam: Longint): Longint; stdcall;
var
DC: HDC;
PS: TPaintStruct;
AWindow: TKDragWindow;
begin
case Msg of
WM_PAINT:
begin
AWindow := TKDragWindow(GetWindowLong(Window, GWL_USERDATA));
if (AWindow <> nil) and AWindow.BitmapFilled then
begin
if wParam = 0 then
DC := BeginPaint(Window, PS)
else
DC := wParam;
try
BitBlt(DC, 0, 0, AWindow.Bitmap.Width, AWindow.Bitmap.Height,
AWindow.Bitmap.Canvas.Handle, 0, 0, SRCCOPY);
finally
if wParam = 0 then EndPaint(Window, PS);
end;
end;
Result := 1;
end;
else
Result := DefWindowProc(Window, Msg, WParam, LParam);
end;
end;
{$ELSE}
type
{ TKDragForm }
TKDragForm = class(THintWindow)
private
FWindow: TKDragWindow;
procedure WMEraseBkGnd(var Msg: TLMessage); message LM_ERASEBKGND;
protected
procedure Paint; override;
public
constructor CreateDragForm(AWindow: TKDragWindow);
end;
{ TKDragForm }
constructor TKDragForm.CreateDragForm(AWindow: TKDragWindow);
begin
inherited Create(nil);
FWindow := AWindow;
ShowInTaskBar := stNever;
end;
procedure TKDragForm.Paint;
begin
if FWindow.Active and FWindow.BitmapFilled then
Canvas.Draw(0, 0, FWindow.FBitmap);
end;
procedure TKDragForm.WMEraseBkGnd(var Msg: TLMessage);
begin
Msg.Result := 1;
end;
{$ENDIF}
constructor TKDragWindow.Create;
{$IFDEF MSWINDOWS}
var
Cls: Windows.TWndClass;
ExStyle: Cardinal;
{$ENDIF}
begin
inherited;
FActive := False;
FBitmap := TKAlphaBitmap.Create;
FInitialPos := CreateEmptyPoint;
{$IFDEF MSWINDOWS}
FUpdateLayeredWindow := GetProcAddress(GetModuleHandle('user32.dll'), 'UpdateLayeredWindow');
FLayered := Assigned(FUpdateLayeredWindow);
Cls.style := CS_SAVEBITS;
Cls.lpfnWndProc := @DragWndProc;
Cls.cbClsExtra := 0;
Cls.cbWndExtra := 0;
Cls.hInstance := HInstance;
Cls.hIcon := 0;
Cls.hCursor := 0;
Cls.hbrBackground := 0;
Cls.lpszMenuName := nil;
Cls.lpszClassName := cLayeredWndClass;
Windows.RegisterClass(Cls);
ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST;
if FLayered then
ExStyle := ExStyle or WS_EX_LAYERED or WS_EX_TRANSPARENT;
FWindow := CreateWindowEx(ExStyle, cLayeredWndClass, '', WS_POPUP,
Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT), Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT), 0, 0, HInstance, nil);
Windows.SetWindowLong(FWindow, GWL_USERDATA, Integer(Self));
{$ELSE}
FDragForm := TKDragForm.CreateDragForm(Self);
FLayered := False;
{$ENDIF}
end;
destructor TKDragWindow.Destroy;
begin
inherited;
Hide;
{$IFDEF MSWINDOWS}
DestroyWindow(FWindow);
Windows.UnregisterClass(cLayeredWndClass, HInstance);
{$ELSE}
FDragForm.Free;
{$ENDIF}
FBitmap.Free;
end;
procedure TKDragWindow.Hide;
begin
if FActive then
begin
{$IFDEF MSWINDOWS}
ShowWindow(FWindow, SW_HIDE);
{$ELSE}
FDragForm.Hide;
{$ENDIF}
FActive := False;
end;
end;
procedure TKDragWindow.Init(IniCtrl: TCustomControl; const ARect: TRect;
const AInitialPos: TPoint; AMasterAlpha: Byte; AGradient: Boolean);
var
Org: TPoint;
W, H: Integer;
ScreenDC: HDC;
begin
if not FActive and ((IniCtrl = nil) or (IniCtrl is TKCustomControl)) then
begin
FActive := True;
FBitmapFilled := False;
FControl := IniCtrl;
FMasterAlpha := AMasterAlpha;
FGradient := AGradient;
FInitialPos := AInitialPos;
FRect := ARect;
W := ARect.Right - ARect.Left;
H := ARect.Bottom - ARect.Top;
FBitmap.SetSize(W, H);
ScreenDC := GetDC(0);
try
FAlphaEffects := GetDeviceCaps(ScreenDC, BITSPIXEL) >= 15;
// because alpha blending is not nice elsewhere
finally
ReleaseDC(0, ScreenDC);
end;
if FControl <> nil then
begin
Org := FControl.ClientToScreen(ARect.TopLeft);
// to be compatible with all LCL widgetsets we must copy the control's part
// while painting in TKCustomControl.Paint!
TKCustomControl(FControl).MemoryCanvas := FBitmap.Canvas;
TKCustomControl(FControl).MemoryCanvasRect := ARect;
TKCustomControl(FControl).Repaint;
end else
Org := ARect.TopLeft;
{$IFDEF MSWINDOWS}
if FLayered then with FBlend do
begin
BlendOp := AC_SRC_OVER;
BlendFlags := 0;
SourceConstantAlpha := 255;
if FAlphaEffects then
AlphaFormat := AC_SRC_ALPHA
else
AlphaFormat := 0;
end;
SetWindowPos(FWindow, HWND_TOP, Org.X, Org.Y, W, H, SWP_NOACTIVATE);
{$ELSE}
FDragForm.SetBounds(Org.X, Org.Y, W, H);
{$ENDIF}
end;
end;
procedure TKDragWindow.Move(ARect: PRect; const ACurrentPos: TPoint; AShowAlways: Boolean);
var
R: TRect;
DX, DY: Integer;
BlendColor: TColor;
ChangedPos: Boolean;
{$IFDEF MSWINDOWS}
ScreenDC: HDC;
CanvasOrigin: TPoint;
{$ENDIF}
begin
if FActive then
begin
ChangedPos := False;
DX := ACurrentPos.X - FInitialPos.X;
DY := ACurrentPos.Y - FInitialPos.Y;
if (DX <> 0) or (DY <> 0) then
begin
FInitialPos := ACurrentPos;
ChangedPos := True;
end;
if ARect <> nil then
ChangedPos := ChangedPos or not EqualRect(ARect^, FRect);
if ((FControl = nil) or (TKCustomControl(FControl).MemoryCanvas = nil)) and not FBitmapFilled or (ARect <> nil) then
begin
FBitmapFilled := True;
if ARect <> nil then
FBitmap.SetSize(ARect.Right - ARect.Left, ARect.Bottom - ARect.Top);
FBitmap.UpdatePixels;
if FAlphaEffects then
begin
if FLayered then
BlendColor := clBlack
else
BlendColor := clWhite;
FBitmap.AlphaFill(FMasterAlpha, BlendColor, FGradient, FLayered);
FBitmap.UpdateHandle;
end;
end;
if ChangedPos or AShowAlways then
begin
{$IFDEF MSWINDOWS}
if ARect <> nil then
R := ARect^
else
GetWindowRect(FWindow, R);
KFunctions.OffsetRect(R, DX, DY);
if FLayered then
begin
R.Right := FBitmap.Width;
R.Bottom := FBitmap.Height;
CanvasOrigin := CreateEmptyPoint;
ScreenDC := GetDC(0);
try
if FUpdateLayeredWindow(FWindow, ScreenDC, @R.TopLeft, PSize(@R.BottomRight),
FBitmap.Canvas.Handle, @CanvasOrigin, clNone, @FBlend, ULW_ALPHA) then
if FBitmapFilled then
ShowWindow(FWindow, SW_SHOWNOACTIVATE);
finally
ReleaseDC(0, ScreenDC);
end;
end
else if FBitmapFilled then
SetWindowPos(FWindow, 0, R.Left, R.Top, 0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER or SWP_SHOWWINDOW);
{$ELSE}
if ARect <> nil then
R := ARect^
else
R := FDragForm.BoundsRect;
OffsetRect(R, DX, DY);
FDragForm.BoundsRect := R;
if FBitmapFilled then
begin
FDragForm.Visible := True;
if FControl <> nil then
SetCaptureControl(FControl);
end;
{$ENDIF}
end;
end;
end;
{ TKHintWindow }
constructor TKHintWindow.Create(AOwner: TComponent);
begin
inherited;
{$IFDEF FPC}
ShowInTaskBar := stNever;
{$ENDIF}
DoubleBuffered := True;
end;
procedure TKHintWindow.ShowAt(const Origin: TPoint);
begin
ActivateHint(Rect(Origin.X, Origin.Y, Origin.X + FExtent.X + 10, Origin.Y + FExtent.Y + 10), '');
// ActivateWithBounds(Rect(Origin.X, Origin.Y, Origin.X + FExtent.X + 10, Origin.Y + FExtent.Y + 10), '');
end;
procedure TKHintWindow.Hide;
begin
{$IFDEF FPC}
inherited Hide;
{$ELSE}
Self.DestroyHandle;
{$ENDIF}
end;
procedure TKHintWindow.WMEraseBkGnd(var Msg: TLMessage);
begin
Msg.Result := 1;
end;
{ TKTextHint }
constructor TKTextHint.Create(AOwner: TComponent);
begin
inherited;
FText := '';
{$IFDEF FPC}
Font := Screen.HintFont;
{$ENDIF}
end;
procedure TKTextHint.Paint;
var
TextBox: TKTextBox;
begin
Canvas.Font := Font;
Canvas.Brush.Style := bsSolid;
Canvas.Brush.Color := clInfoBk;
Canvas.FillRect(ClientRect);
Canvas.Brush.Style := bsClear;
TextBox := TKTextBox.Create;
try
TextBox.Attributes := [taEndEllipsis, taWordBreak, taLineBreak];
TextBox.HPadding := 5;
TextBox.VPadding := 5;
TextBox.Text := FText;
TextBox.Draw(Canvas, Rect(0, 0, FExtent.X + 10, FExtent.Y + 10));
finally
TextBox.Free;
end;
end;
procedure TKTextHint.SetText(const Value: TKString);
var
R: TRect;
TextBox: TKTextBox;
begin
if Value <> FText then
begin
FText := Value;
R := Rect(0, 0, 300, 0);
TextBox := TKTextBox.Create;
try
TextBox.Attributes := [taWordBreak, taLineBreak];
TextBox.Text := FText;
TextBox.Measure(Canvas, R, FExtent.X, FExtent.Y);
finally
TextBox.Free;
end;
end;
end;
{ TKGraphicHint }
constructor TKGraphicHint.Create(AOwner: TComponent);
begin
inherited;
FGraphic := nil;
{$IFDEF FPC}
ShowInTaskBar := stNever;
{$ENDIF}
DoubleBuffered := True;
end;
procedure TKGraphicHint.Paint;
begin
Canvas.Brush.Style := bsSolid;
Canvas.Brush.Color := clInfoBk;
Canvas.FillRect(ClientRect);
if Assigned(FGraphic) then
Canvas.Draw(5, 5, FGraphic)
end;
procedure TKGraphicHint.SetGraphic(const Value: TGraphic);
begin
if Value <> FGraphic then
begin
FGraphic := Value;
FExtent.X := FGraphic.Width;
FExtent.Y := FGraphic.Height;
end;
end;
{ TKSizingGrips }
constructor TKSizingGrips.Create;
begin
FBoundsRect := CreateEmptyRect;
FGripColor := cSizingGripColor;
FGripSize := cSizingGripSize;
FMidGripConstraint := cSizingMidGripConstraint;
end;
class procedure TKSizingGrips.ClsAffectRect(APosition: TKSizingGripPosition;
ADX, ADY: Integer; var ARect: TRect);
begin
case APosition of
sgpLeft:
Inc(ARect.Left, ADX);
sgpRight:
Inc(ARect.Right, ADX);
sgpTop:
Inc(ARect.Top, ADY);
sgpBottom:
Inc(ARect.Bottom, ADY);
sgpTopLeft:
begin
Inc(ARect.Left, ADX);
Inc(ARect.Top, ADY);
end;
sgpTopRight:
begin
Inc(ARect.Right, ADX);
Inc(ARect.Top, ADY);
end;
sgpBottomLeft:
begin
Inc(ARect.Left, ADX);
Inc(ARect.Bottom, ADY);
end;
sgpBottomRight:
begin
Inc(ARect.Right, ADX);
Inc(ARect.Bottom, ADY);
end;
else
KFunctions.OffsetRect(ARect, ADX, ADY);
end;
end;
function TKSizingGrips.CursorAt(const APoint: TPoint): TCursor;
begin
Result := CursorFor(HitTest(APoint));
end;
function TKSizingGrips.CursorFor(APosition: TKSizingGripPosition): TCursor;
begin
case APosition of
sgpLeft, sgpRight: Result := crSizeWE;
sgpTop, sgpBottom: Result := crSizeNS;
sgpTopLeft, sgpBottomRight: Result := crSizeNWSE;
sgpTopRight, sgpBottomLeft: Result := crSizeNESW;
else
Result := crDefault;
end;
end;
procedure TKSizingGrips.DrawTo(ACanvas: TCanvas);
begin
with ACanvas do
begin
Brush.Style := bsSolid;
Brush.Color := FGripColor;
// take the corners first
ACanvas.FillRect(GripRect(sgpTopLeft));
ACanvas.FillRect(GripRect(sgpTopRight));
ACanvas.FillRect(GripRect(sgpBottomLeft));
ACanvas.FillRect(GripRect(sgpBottomRight));
// take middle grips
if FBoundsRect.Right - FBoundsRect.Left >= FMidGripConstraint then
begin
ACanvas.FillRect(GripRect(sgpTop));
ACanvas.FillRect(GripRect(sgpBottom));
end;
if FBoundsRect.Bottom - FBoundsRect.Top >= FMidGripConstraint then
begin
ACanvas.FillRect(GripRect(sgpLeft));
ACanvas.FillRect(GripRect(sgpRight));
end;
end;
end;
function TKSizingGrips.GripRect(APosition: TKSizingGripPosition): TRect;
begin
case APosition of
sgpLeft:
begin
Result.Left := FBoundsRect.Left;
Result.Top := FBoundsRect.Top + (FBoundsRect.Bottom - FBoundsRect.Top - FGripSize) div 2;
end;
sgpRight:
begin
Result.Left := FBoundsRect.Right - FGripSize;
Result.Top := FBoundsRect.Top + (FBoundsRect.Bottom - FBoundsRect.Top - FGripSize) div 2;
end;
sgpTop:
begin
Result.Left := FBoundsRect.Left + (FBoundsRect.Right - FBoundsRect.Left - FGripSize) div 2;
Result.Top := FBoundsRect.Top;
end;
sgpBottom:
begin
Result.Left := FBoundsRect.Left + (FBoundsRect.Right - FBoundsRect.Left - FGripSize) div 2;
Result.Top := FBoundsRect.Bottom - FGripSize;
end;
sgpTopLeft:
begin
Result.Left := FBoundsRect.Left;
Result.Top := FBoundsRect.Top;
end;
sgpTopRight:
begin
Result.Left := FBoundsRect.Right - FGripSize;
Result.Top := FBoundsRect.Top;
end;
sgpBottomLeft:
begin
Result.Left := FBoundsRect.Left;
Result.Top := FBoundsRect.Bottom - FGripSize;
end;
sgpBottomRight:
begin
Result.Left := FBoundsRect.Right - FGripSize;
Result.Top := FBoundsRect.Bottom - FGripSize;
end
else
Result := CreateEmptyRect;
end;
if APosition <> sgpNone then
begin
Result.Right := Result.Left + FGripSize;
Result.Bottom := Result.Top + FGripSize;
end;
end;
function TKSizingGrips.HitTest(const APoint: TPoint): TKSizingGripPosition;
var
I: TKSizingGripPosition;
R: TRect;
begin
Result := sgpNone;
for I := Low(TKSizingGripPosition) to High(TKSizingGripPosition) do if I <> sgpNone then
begin
R := GripRect(I);
if PtInRect(R, APoint) then
begin
Result := I;
Break;
end;
end;
end;
procedure RegisterAlphaBitmap;
begin
TPicture.RegisterFileFormat('BMA', sGrAlphaBitmap, TKAlphaBitmap);
end;
procedure UnregisterAlphaBitmap;
begin
TPicture.UnregisterGraphicClass(TKAlphaBitmap);
end;
{$IFDEF REGISTER_PICTURE_FORMATS}
initialization
RegisterAlphaBitmap;
finalization
//not necessary, but...
UnregisterAlphaBitmap;
{$ENDIF}
end.
tomboy-ng_0.34-1/kcontrols/source/kedits.res 0000644 0001750 0001750 00000001564 14125207534 020740 0 ustar dbannon dbannon ( , O P E N D I R 0 ( rpnnnnnnno}))))))))))8X~))`7o))`|)W})h)`{rh7o)[)`quvuqkd[)X})KR)``a`]YRKK:u)`e)))))))))))~))u)֤)))))֤))֡xto)))֤} n {zy q tomboy-ng_0.34-1/kcontrols/source/kcontrols.pas 0000644 0001750 0001750 00000413416 14125207534 021470 0 ustar dbannon dbannon { @abstract(This file is part of the KControls component suite for Delphi and Lazarus.)
@author(Tomas Krysl)
Copyright (c) 2020 Tomas Krysl
License:
This code is licensed under BSD 3-Clause Clear License, see file License.txt or https://spdx.org/licenses/BSD-3-Clause-Clear.html.
}
unit kcontrols; // lowercase name because of Lazarus/Linux
{$include kcontrols.inc}
{$WEAKPACKAGEUNIT ON}
interface
uses
{$IFDEF FPC}
LCLType, LCLIntf, LMessages, LCLProc, LResources,
{$ELSE}
Windows, Messages,
{$ENDIF}
SysUtils, Classes, Graphics, Controls, Contnrs, Printers, Forms, KFunctions
{$IFDEF USE_THEMES}
, Themes
{$IFNDEF FPC}
, UxTheme
{$ENDIF}
{$ENDIF}
;
type
{ This array serves as storage place for all colors. }
TKColorArray = array of TColor;
{ Declares possible indexes for colors available in @link(TKPreviewColors). }
TKPreviewColorIndex = Integer;
{ Declares print options - possible values for the @link(TKPrintPageSetup.Options) property. }
TKPrintOption = (
{ If there are more printed copies these will be collated. }
poCollate,
{ The printed shape will be scaled to fit on page. }
poFitToPage,
{ Every even page will be printed with mirrored (swapped) margins. }
poMirrorMargins,
{ Page numbers will be added to the bottom of each printed page. }
poPageNumbers,
{ Paints the selection in control's specific manner. }
poPaintSelection,
{ Title will be printed to the top of each printed page. }
poTitle,
{ Color page will be printed instead of B/W page. }
poUseColor,
{ Print line numbers if applicable. }
poLineNumbers,
{ Wrap long lines if applicable. }
poWrapLines
);
{ Print options can be arbitrary combined. }
TKPrintOptions = set of TKPrintOption;
{ Declares possible values for the @link(TKPrintPageSetup.Range) property. }
TKPrintRange = (
{ All pages will be printed. }
prAll,
{ Only selected block will be printed. }
prSelectedOnly,
{ Only given range of pages will be printed. }
prRange
);
{ Declares measurement units for KControls printing system. }
TKPrintUnits = (
{ Corresponding value is given in millimeters. }
puMM,
{ Corresponding value is given in centimeters. }
puCM,
{ Corresponding value is given in inches. }
puInch,
{ Corresponding value is given in hundredths of inches. }
puHundredthInch
);
const
{$IFNDEF FPC}
{ @exclude }
KM_MOUSELEAVE = WM_MOUSELEAVE;
{ @exclude }
LM_USER = WM_USER;
{ @exclude }
LM_CANCELMODE = WM_CANCELMODE;
{ @exclude }
LM_CHAR = WM_CHAR;
{ @exclude }
LM_CLEAR = WM_CLEAR;
{ @exclude }
LM_CLOSEQUERY = WM_CLOSE;
{ @exclude }
LM_COPY = WM_COPY;
{ @exclude }
LM_CUT = WM_CUT;
{ @exclude }
LM_DROPFILES = WM_DROPFILES;
{ @exclude }
LM_ERASEBKGND = WM_ERASEBKGND;
{ @exclude }
LM_GETDLGCODE = WM_GETDLGCODE;
{ @exclude }
LM_HSCROLL = WM_HSCROLL;
{ @exclude }
LM_KEYDOWN = WM_KEYDOWN;
{ @exclude }
LM_KILLFOCUS = WM_KILLFOCUS;
{ @exclude }
LM_LBUTTONDOWN = WM_LBUTTONDOWN;
{ @exclude }
LM_LBUTTONUP = WM_LBUTTONUP;
{ @exclude }
LM_MOUSEMOVE = WM_MOUSEMOVE;
{ @exclude }
LM_MOVE = WM_MOVE;
{ @exclude }
LM_PASTE = WM_PASTE;
{ @exclude }
LM_PAINT = WM_PAINT;
{ @exclude }
LM_SETFOCUS = WM_SETFOCUS;
{ @exclude }
LM_SIZE = WM_SIZE;
{ @exclude }
LM_VSCROLL = WM_VSCROLL;
{ @exclude }
LCL_MAJOR = 0;
{ @exclude }
LCL_MINOR = 0;
{ @exclude }
LCL_RELEASE = 0;
{$ELSE}
{ @exclude }
KM_MOUSELEAVE = LM_MOUSELEAVE; // LCL 0.9.27+, for older it was LM_LEAVE
{ @exclude }
//WM_CTLCOLORBTN = Messages.WM_CTLCOLORBTN;
{ @exclude }
//WM_CTLCOLORSTATIC = Messages.WM_CTLCOLORSTATIC;
{$ENDIF}
{ Base for custom messages used by KControls suite. }
KM_BASE = LM_USER + 1024;
{ Custom message. }
KM_LATEUPDATE = KM_BASE + 1;
{ Recalculate scroll box size and scrollbars. }
KM_SCROLL = KM_BASE + 2;
{ Constant for horizontal resize cursor. }
crHResize = TCursor(101);
{ Constant for vertical resize cursor. }
crVResize = TCursor(102);
{ Constant for uncaptured dragging cursor. }
crDragHandFree = TCursor(103);
{ Constant for captured dragging cursor. }
crDragHandGrip = TCursor(104);
{ Default value for the @link(TKCustomControl.BorderStyle) property. }
cBorderStyleDef = bsSingle;
cRectBottomDef = 0;
cRectLeftDef = 0;
cRectRightDef = 0;
cRectTopDef = 0;
{ Minimum for the @link(TKPrintPageSetup.Copies) property }
cCopiesMin = 1;
{ Maximum for the @link(TKPrintPageSetup.Copies) property }
cCopiesMax = 1000;
{ Default value for the @link(TKPrintPageSetup.Copies) property }
cCopiesDef = 1;
{ Default value for the @link(TKPrintPageSetup.UnitMarginBottom) property }
cMarginBottomDef = 2.0;
{ Default value for the @link(TKPrintPageSetup.UnitMarginLeft) property }
cMarginLeftDef = 1.5;
{ Default value for the @link(TKPrintPageSetup.UnitMarginRight) property }
cMarginRightDef = 1.5;
{ Default value for the @link(TKPrintPageSetup.UnitMarginTop) property }
cMarginTopDef = 1.8;
{ Default value for the @link(TKPrintPageSetup.Options) property. }
cOptionsDef = [poFitToPage, poPageNumbers, poUseColor];
cOptionsAll = [Low(TKPrintOption)..High(TKPrintOption)];
{ Default value for the @link(TKPrintPageSetup.Options) property. }
cRangeDef = prAll;
{ Default value for the @link(TKPrintPageSetup.Scale) property }
cScaleDef = 100;
{ Minimum for the @link(TKPrintPageSetup.Scale) property }
cScaleMin = 10;
{ Maximum for the @link(TKPrintPageSetup.Scale) property }
cScaleMax = 500;
{ Default DPI value }
cDPIDef = 96;
{ Minimum DPI value }
cDPIMin = 50;
{ Maximum DPI value }
cDPIMax = 1000;
{ Default value for the @link(TKPrintPageSetup.Units) property. }
cUnitsDef = puCM;
{ Default value for the @link(TKPreviewColors.Paper) color property. }
cPaperDef = clWhite;
{ Default value for the @link(TKPreviewColors.BkGnd) color property. }
cBkGndDef = clAppWorkSpace;
{ Default value for the @link(TKPreviewColors.Border) color property. }
cBorderDef = clBlack;
{ Default value for the @link(TKPreviewColors.SelectedBorder) color property. }
cSelectedBorderDef = clNavy;
{ Index for the @link(TKPreviewColors.Paper) property. }
ciPaper = TKPreviewColorIndex(0);
{ Index for the @link(TKPreviewColors.BkGnd) property. }
ciBkGnd = TKPreviewColorIndex(1);
{ Index for the @link(TKPreviewColors.Border) property. }
ciBorder = TKPreviewColorIndex(2);
{ Index for the @link(TKPreviewColors.SelectedBorder) property. }
ciSelectedBorder = TKPreviewColorIndex(3);
{ Maximum color array index }
ciPreviewColorsMax = ciSelectedBorder;
{ Constant for control scrollbars. It means: Leave that scrollbar untouched. }
cScrollNoAction = -1;
{ Constant for control scrollbars. It means: Use given Delta to update scrollbar. }
cScrollDelta = -2;
{ Internal flag for TKPrintPreview. }
cPF_Dragging = $00000001;
{ Internal flag for TKPrintPreview. }
cPF_UpdateRange = $00000002;
type
{$IFNDEF FPC}
{ @exclude }
TLMessage = TMessage;
{ @exclude }
TLMCopy = TWMCopy;
{ @exclude }
TLMMouse = TWMMouse;
{ @exclude }
TLMNoParams = TWMNoParams;
{ @exclude }
TLMKey = TWMKey;
{ @exclude }
TLMChar = TWMChar;
{ @exclude }
TLMEraseBkGnd = TWMEraseBkGnd;
{ @exclude }
TLMHScroll = TWMHScroll;
{ @exclude }
TLMKillFocus = TWMKillFocus;
{ @exclude }
TLMMove = TWMMove;
{ @exclude }
TLMPaint = TWMPaint;
{ @exclude }
TLMPaste = TWMPaste;
{ @exclude }
TLMSetFocus = TWMSetFocus;
{ @exclude }
TLMSize = TWMSize;
{ @exclude }
TLMVScroll = TWMVScroll;
{$IFNDEF COMPILER17_UP}
{ Support for Win64 messaging. }
LONG_PTR = Longint;
{$ENDIF}
{$ENDIF}
{$IFDEF FPC}
TKClipboardFormat = TClipboardFormat;
{$ELSE}
TKClipboardFormat = Word;
{$ENDIF}
{ Declares possible values for the @link(ScaleMode) property }
TKPreviewScaleMode = (
{ Apply scale defined by the @link(Scale) property }
smScale,
{ Scale the page so that it horizontally fits to the window client area }
smPageWidth,
{ Scale the page so that it fits to the window client area }
smWholePage);
{ @abstract(Declares @link(TKPrintPreview.OnChanged) event handler)
Parameters:
- Sender - identifies the event caller
}
TKPreviewChangedEvent = procedure(Sender: TObject) of object;
{ @abstract(Declares the information structure for the @link(TKCustomControl.MeasurePages) method)
Members:
- OutlineWidth - printed outline width (maximum of all pages) in desktop pixels
- OutlineHeight - printed outline height (maximum of all pages) in desktop pixels
- ControlHorzPageCount - number of pages to split control shape into
- ControlVertPageCount - number of pages to split control shape into
- ExtraLeftHorzPageCount - number of horizontal pages to the left of control
- ExtraLeftVertPageCount - number of vertical pages to the left of control
- ExtraRightHorzPageCount - number of horizontal pages to the right of control
- ExtraRightVertPageCount - number of vertical pages to the right of control
}
TKPrintMeasureInfo = record
OutlineWidth: Integer;
OutlineHeight: Integer;
ControlHorzPageCount: Integer;
ControlVertPageCount: Integer;
ExtraLeftHorzPageCount: Integer;
ExtraLeftVertPageCount: Integer;
ExtraRightHorzPageCount: Integer;
ExtraRightVertPageCount: Integer;
end;
{ Declares possible values for the Status parameter in the @link(TKPrintNotifyEvent) event }
TKPrintStatus = (
{ This event occurs at the beginning of the print job - you may show an Abort dialog here }
epsBegin,
{ This event occurs after each page has been printed - you may update the Page/Copy information
in the Abort dialog }
epsNewPage,
{ This event occurs at the end of the print job - you may hide the Abort dialog here }
epsEnd
);
{ @abstract(Declares @link(TKCustomControl.OnPrintNotify) event handler)
Parameters:
- Sender - identifies the event caller
- Status - specifies the event type
- Abort - set to True to abort the print job
Remark: At certain time slots, the print spooler allows the message queue
to be processed for the thread where the print job is running. This e.g. allows
the user to press a button on the Abort dialog. Because this message loop can be invoked
e.g. during a Printer.Canvas.TextRect function and any painting messages may hover in
the message queue, any functions used both to print a job and to process particular
messages should be reentrant to avoid conflicts. Perhaps should print jobs be run
in seperate threads?
}
TKPrintNotifyEvent = procedure(Sender: TObject; Status: TKPrintStatus;
var Abort: Boolean) of object;
{ @abstract(Declares @link(TKCustomControl.OnPrintPaint) event handler)
Parameters:
- Sender - identifies the event caller
}
TKPrintPaintEvent = procedure(Sender: TObject) of object;
TKPrintPageSetup = class;
TKPrintPreview = class;
TKRect = class(TPersistent)
private
FLeft, FTop, FRight, FBottom: Integer;
FOnChanged: TNotifyEvent;
procedure SetBottom(const Value: Integer);
procedure SetLeft(const Value: Integer);
procedure SetRight(const Value: Integer);
procedure SetTop(const Value: Integer);
procedure SetAll(const Value: Integer);
function GetHeight: Integer;
function GetWidth: Integer;
protected
procedure Changed;
public
constructor Create;
procedure Assign(Source: TPersistent); override;
procedure AssignFromRect(const ARect: TRect);
procedure AssignFromValues(ALeft, ATop, ARight, ABottom: Integer);
function ContainsPoint(const APoint: TPoint): Boolean;
function EqualProperties(const ARect: TKRect): Boolean;
function NonZero: Boolean;
function OffsetRect(ARect: TKRect): TRect; overload;
function OffsetRect(const ARect: TRect): TRect; overload;
property All: Integer write SetAll;
property OnChanged: TNotifyEvent read FOnChanged write FOnChanged;
published
property Left: Integer read FLeft write SetLeft default cRectLeftDef;
property Top: Integer read FTop write SetTop default cRectTopDef;
property Right: Integer read FRight write SetRight default cRectRightDef;
property Bottom: Integer read FBottom write SetBottom default cRectBottomDef;
property Width: Integer read GetWidth;
property Height: Integer read GetHeight;
end;
{ Base class for all visible controls in KControls. }
{ TKCustomControl }
TKCustomControl = class(TCustomControl)
private
{$IF DEFINED(FPC) OR NOT DEFINED(COMPILER10_UP)}
FParentBackground: Boolean;
FParentDoubleBuffered: Boolean;
{$IFEND}
{$IFNDEF FPC}
FBorderStyle: TBorderStyle;
{$ENDIF}
{$IFNDEF COMPILER10_UP}
FMouseInClient: Boolean;
{$ENDIF}
FMemoryCanvas: TCanvas;
FMemoryCanvasRect: TRect;
FPageSetup: TKPrintPageSetup;
FUpdateLock: Integer;
FOnPrintNotify: TKPrintNotifyEvent;
FOnPrintPaint: TKPrintPaintEvent;
{$IFNDEF FPC}
procedure CMCancelMode(var Msg: TMessage); message CM_CANCELMODE;
procedure CMCtl3DChanged(var Msg: TMessage); message CM_CTL3DCHANGED;
{$ENDIF}
procedure CMMouseLeave(var Msg: TLMessage); message CM_MOUSELEAVE;
function GetCanPrint: Boolean;
function GetPageSetup: TKPrintPageSetup;
function GetPageSetupAllocated: Boolean;
procedure KMLateUpdate(var Msg: TLMessage); message KM_LATEUPDATE;
{$IFNDEF FPC}
procedure SetBorderStyle(Value: TBorderStyle);
{$ENDIF}
procedure SetPageSetup(Value: TKPrintPageSetup);
{$IFNDEF FPC}
procedure WMCancelMode(var Msg: TWMCancelMode); message WM_CANCELMODE;
{$ENDIF}
{$IFNDEF COMPILER10_UP}
procedure WMMouseLeave(var Msg: TLMessage); message KM_MOUSELEAVE;
{$ENDIF}
{$IFNDEF FPC}
procedure WMNCPaint(var Msg: TWMNCPaint); message WM_NCPAINT;
procedure WMSetCursor(var Msg: TWMSetCursor); message WM_SETCURSOR;
{$ENDIF}
procedure WMSize(var Msg: TLMSize); message LM_SIZE;
{$IFNDEF FPC}
{$IFDEF USE_THEMES}
procedure WMThemeChanged(var Msg: TMessage); message WM_THEMECHANGED;
{$ENDIF}
{$ENDIF}
protected
{ Holds the mutually inexclusive state as cXF... flags. }
FFlags: Cardinal;
{ Defines the message queue for late update. }
FMessages: array of TLMessage;
{ Previous size of control client area. }
FOldClientSize: TPoint;
{ Gains access to the list of associated previews. }
FPreviewList: TList;
FResizeCalled: Boolean;
{ Adds a preview control to the internal list of associated previews. }
procedure AddPreview(APreview: TKPrintPreview);
{ Gives the descendant the possibility to adjust the associated TKPrintPageSetup
instance just before printing. }
procedure AdjustPageSetup; virtual;
{ Calls @link(TKCustomControl.UpdateSize) only when the control client area has been really modified. }
procedure CallUpdateSize; virtual;
{ Cancels any dragging or resizing operations performed by mouse. }
procedure CancelMode; virtual;
{ Overriden method. Calls @link(TKCustomControl.UpdateSize). }
procedure CreateHandle; override;
{ Defines additional styles. }
procedure CreateParams(var Params: TCreateParams); override;
{$IFDEF FPC}
{ Overriden method. Calls @link(TKCustomControl.UpdateSize). }
procedure DoOnChangeBounds; override;
{$ENDIF}
{ If Value is True, includes the flag specified by AFLag to @link(FFlags).
If Value is False, excludes the flag specified by AFLag from @link(FFlags). }
procedure FlagAssign(AFlag: Cardinal; Value: Boolean);
{ Excludes the flag specified by AFLag from @link(FFlags). }
procedure FlagClear(AFlag: Cardinal);
{ Includes the flag specified by AFLag to @link(FFlags). }
procedure FlagSet(AFlag: Cardinal);
{ If the flag specified by AFLag is included in @link(FFlags), FlagToggle
excludes it and vice versa. }
procedure FlagToggle(AFlag: Cardinal);
{ Invalidates the page setup settings. If page setup is required again,
it's UpdateSettings method is called. }
procedure InvalidatePageSetup;
{ Invalidates a rectangular part of the client area if control updating is not locked
by @link(TKCustomControl.LockUpdate). }
procedure InvalidateRectArea(const R: TRect); virtual;
{ Returns True if the control has a selection. }
function InternalGetSelAvail: Boolean; virtual;
{ Called in UnlockUpdate. Allows the changes to be reflected. }
procedure InternalUnlockUpdate; virtual;
{ Determines if control can be painted with OS themes. }
function IsThemed: Boolean; virtual;
{ Called from KM_LATEUPDATE. Performs late update. Override to adapt. }
procedure LateUpdate(var Msg: TLMessage); virtual;
{ Updates information about printed shape. }
procedure MeasurePages(var Info: TKPrintMeasureInfo); virtual;
{ Retrieves a message from message queue if there is one. Used for late update.}
function MessagePeek(out Msg: TLMessage): Boolean;
{ Puts a new message into the message queue. Used for late update.}
procedure MessagePoke(const Msg: TLMessage);
{ Searches the message queue for given message code. }
function MessageSearch(MsgCode: Cardinal): Boolean;
{ Responds to WM_MOUSELEAVE message. }
procedure MouseFormLeave; virtual;
{ Overriden method - see Delphi help. }
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
{ Notifies all associated previews about a change in the associated page setup. }
procedure NotifyPreviews;
{ Overriden method - see Delphi help. Paints the entire control client area. }
procedure Paint; override;
{ Paints a page to a printer/preview canvas. }
procedure PaintPage; virtual;
{ Paints the control to the specified canvas. Must always be overriden. }
procedure PaintToCanvas(ACanvas: TCanvas); virtual; abstract;
{ Adds a message to message queue for late update. Set IfNotExists to True to
add that message only if the specified message code does not exist in the
message queue at this moment. }
procedure PostLateUpdate(const Msg: TLMessage; IfNotExists: Boolean = False);
{ Calls the @link(TKCustomControl.OnPrintNotify) event }
procedure PrintNotify(Status: TKPrintStatus; var Abort: Boolean); virtual;
{ Calls the @link(TKCustomControl.OnPrintPaint) event }
procedure PrintPaint; virtual;
{ Allows descendant to make necessary adjustments before printing or painting to preview starts. }
procedure PrintPaintBegin; virtual;
{ Allows descendant to make necessary adjustments after printing or painting to preview ended. }
procedure PrintPaintEnd; virtual;
{ Remove a preview control to the internal list of associated previews. }
procedure RemovePreview(APreview: TKPrintPreview);
{ Respond to resize calls}
procedure Resize; override;
{ Updates mouse cursor according to the state determined from current mouse
position. Returns True if cursor has been changed. }
function SetMouseCursor(X, Y: Integer): Boolean; virtual;
{ Updates the control size. Responds to WM_SIZE under Delphi and similar
notifications under Lazarus. }
procedure UpdateSize; virtual;
public
{ Creates the instance. Assigns default values to properties, allocates
default column, row and cell data. }
constructor Create(AOwner: TComponent); override;
{ Destroys the instance along with all allocated column, row and cell data.
See TObject.Destroy in Delphi help. }
destructor Destroy; override;
{ Determines whether a flag specified by AFlag is included in @link(FFlags). }
function Flag(AFlag: Cardinal): Boolean;
{ Invalidates the entire control if control updating is not locked
by @link(TKCustomControl.LockUpdate). }
procedure Invalidate; override;
{ Locks control updating so that all possibly slow operations such as all Invalidate...
methods will not be performed. This is useful e.g. when assigning many
properties at one time. Every LockUpdate call must have
a corresponding @link(TKCustomControl.UnlockUpdate) call, please use a
try-finally section. }
procedure LockUpdate; virtual;
{ Prints the control. }
procedure PrintOut;
{ Unlocks back to normal control updating and calls InternalUnlockUpdate
to reflect (possible) multiple changes made. Each @link(LockUpdate) call must
be always followed by the UnlockUpdate call. }
procedure UnlockUpdate; virtual;
{ Returns True if control updating is not locked, i.e. there is no open
LockUpdate and UnlockUpdate pair. }
function UpdateUnlocked: Boolean; virtual;
{ Determines whether a single line border is drawn around the control.
Set BorderStyle to bsSingle to add a single line border around the control.
Set BorderStyle to bsNone to omit the border. }
{$IFDEF FPC}
property BorderStyle default cBorderStyleDef;
{$ELSE}
property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default cBorderStyleDef;
{$ENDIF}
{ Returns True if the control has anything to print and a printer is installed. }
property CanPrint: Boolean read GetCanPrint;
{$IFNDEF COMPILER10_UP}
{ This property has the same meaning as the MouseInClient property introduced
into TWinControl in BDS 2006. }
property MouseInClient: Boolean read FMouseInClient;
{$ENDIF}
{ Setting this property causes the control to be painted to MemoryCanvas in it's
Paint method. This approach replaces PaintTo as it does not work good for all
LCL widget sets. The control is painted normally on it's Canvas and then
copied only once to MemoryCanvas. MemoryCanvas is then set to nil (not freed)
to indicate the copying is complete. }
property MemoryCanvas: TCanvas read FMemoryCanvas write FMemoryCanvas;
{ Specifies what rectangular part of the control should be copied on MemoryCanvas. }
property MemoryCanvasRect: TRect read FMemoryCanvasRect write FMemoryCanvasRect;
{ This event is called at certain phases of the actually running print job. }
property OnPrintNotify: TKPrintNotifyEvent read FOnPrintNotify write FOnPrintNotify;
{ This event is called after the shape was drawn onto the printer canvas. }
property OnPrintPaint: TKPrintPaintEvent read FOnPrintPaint write FOnPrintPaint;
{ Specifies the page setup component used for this control. }
property PageSetup: TKPrintPageSetup read GetPageSetup write SetPageSetup;
{Returns True if page setup component is allocated for this control. }
property PageSetupAllocated: Boolean read GetPageSetupAllocated;
{ Just to be compatible with Delphi. }
{$IF DEFINED(FPC) OR NOT DEFINED(COMPILER10_UP)}
property ParentBackground: Boolean read FParentBackground write FParentBackground default True;
property ParentDoubleBuffered: Boolean read FParentDoubleBuffered write FParentDoubleBuffered default True;
{$IFEND}
end;
{ Declares possible values for the @link(TKCustomColors.ColorScheme) property. }
TKColorScheme = (
{ GetColor returns normal color currently defined for each item }
csNormal,
{ GetColor returns gray for text and line colors and white for background colors }
csGrayed,
{ GetColor returns brighter version of normal color }
csBright,
{ GetColor returns grayscaled color versions }
csGrayScale
);
{ Declares possible indexes e.g. for the @link(TKCustomColors.Color) property. }
TKColorIndex = Integer;
{ @abstract(Declares the color description structure returned by @link(TKCustomColors.ColorData) property)
Members:
- Index - color index
- Color - current color value
- Default - default color value
- Name - color name
}
TKColorData = record
Index: TKColorIndex;
Color: TColor;
Default: TColor;
Name: string;
end;
{ @abstract(Declares @link(TKCustomColors) color item description)
Members:
- Def - default color value
- Name - color name (can be localized)
}
TKColorSpec = record
Def: TColor;
Name: string;
end;
{ @abstract(Container for all colors used by specific control)
This container allows to group many colors into one item in object inspector.
Colors are accessible via published properties or several public Color*
properties. }
TKCustomColors = class(TPersistent)
private
function GetColorData(Index: TKColorIndex): TKColorData;
function GetColorEx(Index: TKColorIndex): TColor;
function GetColorName(Index: TKColorIndex): string;
function GetDefaultColor(Index: TKColorIndex): TColor;
procedure SetColorEx(Index: TKColorIndex; Value: TColor);
procedure SetColors(const Value: TKColorArray);
protected
FControl: TKCustomControl;
FColorScheme: TKColorScheme;
FBrightColors: TKColorArray;
FColors: TKColorArray;
{ Returns the specific color. Use for property assignments. }
function GetColor(Index: TKColorIndex): TColor;
{ Returns color specification structure for given index. }
function GetColorSpec(Index: TKColorIndex): TKColorSpec; virtual;
{ Returns maximum color index. }
function GetMaxIndex: Integer; virtual;
{ Initializes the color array. }
procedure Initialize; virtual;
{ Returns the specific color according to ColorScheme. }
function InternalGetColor(Index: TKColorIndex): TColor; virtual;
{ Replaces the specific color. }
procedure InternalSetColor(Index: TKColorIndex; Value: TColor); virtual;
{ Replaces the specific color. Use for property assignments. }
procedure SetColor(Index: TKColorIndex; Value: TColor);
public
{ Creates the instance. You can create a custom instance and pass it
e.g. to a @link(TKCustomGrid.Colors) property. The AGrid parameter has no meaning
in this case and you may set it to nil. }
constructor Create(AControl: TKCustomControl); virtual;
{ Copies the properties of another instance that inherits from
TPersistent into this TKGridColors instance. }
procedure Assign(Source: TPersistent); override;
{ Clears cached brighter colors. }
procedure ClearBrightColors; virtual;
{ Returns always normal color - regardless of the ColorScheme setting. }
property Color[Index: TKColorIndex]: TColor read GetColorEx write SetColorEx;
{ Returns always a complete color description }
property ColorData[Index: TKColorIndex]: TKColorData read GetColorData;
{ Returns (localizable) color name. }
property ColorName[Index: TKColorIndex]: string read GetColorName;
{ Returns array of normal colors. }
property Colors: TKColorArray read FColors write SetColors;
{ Specifies color scheme for reading of published properties - see GetColor in source code. }
property ColorScheme: TKColorScheme read FColorScheme write FColorScheme;
{ Returns default color. }
property DefaultColor[Index: TKColorIndex]: TColor read GetDefaultColor;
end;
{ @abstract(Declares @link(TKPrintPageSetup.OnPrintMeasure) event handler)
Parameters:
- Sender - identifies the event caller
- Info - print measure info structure already filled by the associated control
}
TKPrintMeasureEvent = procedure(Sender: TObject; var Info: TKPrintMeasureInfo) of object;
{ @abstract(Class to specify the print job parameters) }
TKPrintPageSetup = class(TKPersistent)
private
FActive: Boolean;
FCanvas: TCanvas;
FControl: TKCustomControl;
FControlHorzPageCount: Integer;
FControlPageCount: Integer;
FControlVertPageCount: Integer;
FCopies: Integer;
FCurrentCopy: Integer;
FCurrentPage: Integer;
FCurrentScale: Double;
FDesktopPixelsPerInchX: Integer;
FDesktopPixelsPerInchY: Integer;
FEndPage: Integer;
FExtraLeftHorzPageCount: Integer;
FExtraLeftPageCount: Integer;
FExtraLeftVertPageCount: Integer;
FExtraRightHorzPageCount: Integer;
FExtraRightPageCount: Integer;
FExtraRightVertPageCount: Integer;
FIsValid: Boolean;
FMappedControlPaintAreaWidth: Integer;
FMappedExtraSpaceLeft: Integer;
FMappedExtraSpaceRight: Integer;
FMappedFooterSpace: Integer;
FMappedHeaderSpace: Integer;
FMappedMarginBottom: Integer;
FMappedMarginLeft: Integer;
FMappedMarginLeftMirrored: Integer;
FMappedMarginRight: Integer;
FMappedMarginRightMirrored: Integer;
FMappedMarginTop: Integer;
FMappedOutlineHeight: Integer;
FMappedOutlineWidth: Integer;
FMappedPaintAreaHeight: Integer;
FMappedPaintAreaWidth: Integer;
FMappedPageHeight: Integer;
FMappedPageWidth: Integer;
FOptions: TKPrintOptions;
FOrientation: TPrinterOrientation;
FPageCount: Integer;
FPreviewing: Boolean;
FPrinterControlPaintAreaWidth: Integer;
FPrinterExtraSpaceLeft: Integer;
FPrinterExtraSpaceRight: Integer;
FPrinterFooterSpace: Integer;
FPrinterHeaderSpace: Integer;
FPrinterMarginBottom: Integer;
FPrinterMarginLeft: Integer;
FPrinterMarginLeftMirrored: Integer;
FPrinterMarginRight: Integer;
FPrinterMarginRightMirrored: Integer;
FPrinterMarginTop: Integer;
FPrinterName: string;
FPrinterPageHeight: Integer;
FPrinterPageWidth: Integer;
FPrinterPaintAreaHeight: Integer;
FPrinterPaintAreaWidth: Integer;
FPrinterPixelsPerInchX: Integer;
FPrinterPixelsPerInchY: Integer;
FPrintingMapped: Boolean;
FRange: TKPrintRange;
FStartPage: Integer;
FScale: Integer;
FTitle: string;
FUnitControlPaintAreaWidth: Double;
FUnitExtraSpaceLeft: Double;
FUnitExtraSpaceRight: Double;
FUnitFooterSpace: Double;
FUnitHeaderSpace: Double;
FUnitMarginBottom: Double;
FUnitMarginLeft: Double;
FUnitMarginRight: Double;
FUnitMarginTop: Double;
FUnitPaintAreaHeight: Double;
FUnitPaintAreaWidth: Double;
FUnits: TKPrintUnits;
FValidating: Boolean;
FOnPrintMeasure: TKPrintMeasureEvent;
FOnUpdateSettings: TNotifyEvent;
function GetCurrentPageControl: Integer;
function GetCurrentPageExtraLeft: Integer;
function GetCurrentPageExtraRight: Integer;
function GetIsDefaultPrinter: Boolean;
procedure SetCopies(Value: Integer);
procedure SetEndPage(Value: Integer);
procedure SetUnitExtraSpaceLeft(Value: Double);
procedure SetUnitExtraSpaceRight(Value: Double);
procedure SetUnitFooterSpace(Value: Double);
procedure SetUnitHeaderSpace(Value: Double);
procedure SetUnitMarginBottom(Value: Double);
procedure SetUnitMarginLeft(Value: Double);
procedure SetUnitMarginRight(Value: Double);
procedure SetUnitMarginTop(Value: Double);
procedure SetOptions(Value: TKPrintOptions);
procedure SetOrientation(AValue: TPrinterOrientation);
procedure SetPrinterName(const Value: string);
procedure SetPrintingMapped(Value: Boolean);
procedure SetRange(Value: TKPrintRange);
procedure SetScale(Value: Integer);
procedure SetStartPage(Value: Integer);
procedure SetUnits(Value: TKPrintUnits);
protected
function GetCanPrint: Boolean; virtual;
function GetSelAvail: Boolean; virtual;
{ Called before new Units are set. Converts the margins to inches by default. }
procedure AfterUnitsChange; virtual;
{ Called after new Units are set. Converts the margins from inches by default. }
procedure BeforeUnitsChange; virtual;
{ Paints a page to APreview.Canvas. }
procedure PaintPageToPreview(APreview: TKPrintPreview); virtual;
{ Prints the page number at the bottom of the page, horizontally centered. }
procedure PrintPageNumber(Value: Integer); virtual;
{ Prints the title at the top of the page. }
procedure PrintTitle; virtual;
{ Inherited method. Calls UpdateSettings. }
procedure Update; override;
{ Updates entire printing information. }
procedure UpdateSettings; virtual;
public
{ Creates the instance. Assigns default values to properties. }
constructor Create(AControl: TKCustomControl); reintroduce; virtual;
{ Copies shareable properties of another TKPrintPageSetup instance
to this instance. }
procedure Assign(Source: TPersistent); override;
{ Returns a value mapped from desktop horizontal units to printer horizontal units. }
function HMap(Value: Integer): Integer;
{ Invalidates the settings. }
procedure Invalidate;
{ Prints the associated control. }
procedure PrintOut;
{ Validates the settings. }
procedure Validate;
{ Returns a value mapped from desktop vertical units to printer vertical units. }
function VMap(Value: Integer): Integer;
{ Returns True if printing or previewing is active. }
property Active: Boolean read FActive;
{ Returns True if the control is associated and has anything to print. }
property CanPrint: Boolean read GetCanPrint;
{ Returns the Printer.Canvas or TkPrintPreview.Canvas. Do not access outside
print job. }
property Canvas: TCanvas read FCanvas;
{ Returns the control to which this TKPrintPageSetup instance is assigned. }
property Control: TKCustomControl read FControl;
{ Returns the maximum amount of control pages for horizontal axis. }
property ControlHorzPageCount: Integer read FControlHorzPageCount;
{ Returns the maximum amount of control pages for vertical axis. }
property ControlVertPageCount: Integer read FControlVertPageCount;
{ Specifies the number of copies to print. }
property Copies: Integer read FCopies write SetCopies;
{ Returns the currently printed copy. }
property CurrentCopy: Integer read FCurrentCopy;
{ Returns the currently printed page. }
property CurrentPage: Integer read FCurrentPage;
{ Returns the currently printed page relative to the control shape.
It must be used with associated control to print page. }
property CurrentPageControl: Integer read GetCurrentPageControl;
{ Returns the currently printed page relative to the extra left shape. }
property CurrentPageExtraLeft: Integer read GetCurrentPageExtraLeft;
{ Returns the currently printed page relative to the extra left shape. }
property CurrentPageExtraRight: Integer read GetCurrentPageExtraRight;
{ Returns the horizontal scale for the printed shape, without dimension. }
property CurrentScale: Double read FCurrentScale;
{ Returns the control paint area width on canvas in units depending on PrintingMapped. }
property MappedControlPaintAreaWidth: Integer read FMappedControlPaintAreaWidth;
{ Returns the width of extra left paint area on canvas in units depending on PrintingMapped. }
property MappedExtraSpaceLeft: Integer read FMappedExtraSpaceLeft;
{ Returns the width of extra right paint area on canvas in units depending on PrintingMapped. }
property MappedExtraSpaceRight: Integer read FMappedExtraSpaceRight;
{ Returns the footer space in units depending on PrintingMapped. }
property MappedFooterSpace: Integer read FMappedFooterSpace;
{ Returns the header space in units depending on PrintingMapped. }
property MappedHeaderSpace: Integer read FMappedHeaderSpace;
{ Returns the bottom margin in units depending on PrintingMapped. }
property MappedMarginBottom: Integer read FMappedMarginBottom;
{ Returns the left margin in units depending on PrintingMapped. }
property MappedMarginLeft: Integer read FMappedMarginLeft;
{ Returns the left margin respecting current page in units depending on PrintingMapped. }
property MappedMarginLeftMirrored: Integer read FMappedMarginLeftMirrored;
{ Returns the right margin in units depending on PrintingMapped. }
property MappedMarginRight: Integer read FMappedMarginRight;
{ Returns the left margin respecting current page in units depending on PrintingMapped. }
property MappedMarginRightMirrored: Integer read FMappedMarginRightMirrored;
{ Returns the top margin in units depending on PrintingMapped. }
property MappedMarginTop: Integer read FMappedMarginTop;
{ Returns the printed shape height (maximum of all pages) in units depending on PrintingMapped. }
property MappedOutlineHeight: Integer read FMappedOutlineHeight;
{ Returns the printed shape width (maximum of all pages) in units depending on PrintingMapped. }
property MappedOutlineWidth: Integer read FMappedOutlineWidth;
{ Returns the paint area height on canvas in units depending on PrintingMapped. }
property MappedPaintAreaHeight: Integer read FMappedPaintAreaHeight;
{ Returns the paint area width on canvas in units depending on PrintingMapped. }
property MappedPaintAreaWidth: Integer read FMappedPaintAreaWidth;
{ Returns the page height in units depending on PrintingMapped. }
property MappedPageHeight: Integer read FMappedPageHeight;
{ Returns the page width in units depending on PrintingMapped. }
property MappedPageWidth: Integer read FMappedPageWidth;
{ Returns the amount of pixels per inch for the desktop device context's horizontal axis }
property DesktopPixelsPerInchX: Integer read FDesktopPixelsPerInchX;
{ Returns the amount of pixels per inch for the desktop device context's vertical axis }
property DesktopPixelsPerInchY: Integer read FDesktopPixelsPerInchY;
{ Specifies last page printed if Range is eprRange. }
property EndPage: Integer read FEndPage write SetEndPage;
{ Returns extra horizontal pages needed to print extra left space. }
property ExtraLeftHorzPageCount: Integer read FExtraLeftHorzPageCount;
{ Returns extra vertical pages needed to print extra left space. }
property ExtraLeftVertPageCount: Integer read FExtraLeftVertPageCount;
{ Returns extra horizontal pages needed to print extra right space. }
property ExtraRightHorzPageCount: Integer read FExtraRightHorzPageCount;
{ Returns extra vertical pages needed to print extra right space. }
property ExtraRightVertPageCount: Integer read FExtraRightVertPageCount;
{ Returns True if default printer is selected otherwise Talse.
Because of VCL.Printers bug, there is no way to use any printer when False. }
property IsDefaultPrinter: Boolean read GetIsDefaultPrinter;
{ Specifies the printing options. }
property Options: TKPrintOptions read FOptions write SetOptions;
{ Specifies the paper orientation. }
property Orientation: TPrinterOrientation read FOrientation write SetOrientation;
{ Returns the amount of all pages. Includes the extra left and right areas. }
property PageCount: Integer read FPageCount;
{ Returns True if painting to a TKPrintPreview.Canvas is active. }
property Previewing: Boolean read FPreviewing;
{ Returns the control paint area width in printer device context's units. }
property PrinterControlPaintAreaWidth: Integer read FPrinterControlPaintAreaWidth;
{ Returns the left extra space in printer device context's units. }
property PrinterExtraSpaceLeft: Integer read FPrinterExtraSpaceLeft;
{ Returns the right extra space in printer device context's units. }
property PrinterExtraSpaceRight: Integer read FPrinterExtraSpaceRight;
{ Returns the footer space in printer device context's units. }
property PrinterFooterSpace: Integer read FPrinterFooterSpace;
{ Returns the header space in printer device context's units. }
property PrinterHeaderSpace: Integer read FPrinterHeaderSpace;
{ Returns the bottom margin in printer device context's units. }
property PrinterMarginBottom: Integer read FPrinterMarginBottom;
{ Returns the left margin in printer device context's units. }
property PrinterMarginLeft: Integer read FPrinterMarginLeft;
{ Returns the left margin in printer device context's units with respect to current page. }
property PrinterMarginLeftMirrored: Integer read FPrinterMarginLeftMirrored;
{ Returns the right margin in printer device context's units. }
property PrinterMarginRight: Integer read FPrinterMarginRight;
{ Returns the left margin in printer device context's units with respect to current page. }
property PrinterMarginRightMirrored: Integer read FPrinterMarginRightMirrored;
{ Returns the top margin in printer device context's units. }
property PrinterMarginTop: Integer read FPrinterMarginTop;
{ Specifies the printer name. }
property PrinterName: string read FPrinterName write SetPrinterName;
{ Returns the page height in printer device context's pixels. }
property PrinterPageHeight: Integer read FPrinterPageHeight;
{ Returns the page width in printer device context's pixels. }
property PrinterPageWidth: Integer read FPrinterPageWidth;
{ Returns the paint area height in printer device context's units. }
property PrinterPaintAreaHeight: Integer read FPrinterPaintAreaHeight;
{ Returns the paint area width in printer device context's units. }
property PrinterPaintAreaWidth: Integer read FPrinterPaintAreaWidth;
{ Returns the amount of pixels per inch for the printer device context's horizontal axis }
property PrinterPixelsPerInchX: Integer read FPrinterPixelsPerInchX;
{ Returns the amount of pixels per inch for the printer device context's vertical axis }
property PrinterPixelsPerInchY: Integer read FPrinterPixelsPerInchY;
{ Specifies the units for MappedX properties.
If True, those extents are given in printer device context's pixels,
otherwise in desktop device context's pixels. It can be adjusted by the descendant
in the AdjustPageSetup method. }
property PrintingMapped: Boolean read FPrintingMapped write SetPrintingMapped;
{ Specifies the printing range. }
property Range: TKPrintRange read FRange write SetRange;
{ Returns True if the associated control has a selection. }
property SelAvail: Boolean read GetSelAvail;
{ Specifies first page printed if Range is eprRange. }
property StartPage: Integer read FStartPage write SetStartPage;
{ Specifies the requested scale for the printed shape, in percent.
If epoFitToPage is specified in Options, this parameter is ignored. }
property Scale: Integer read FScale write SetScale;
{ Specifies the document title as it appears in printer manager. }
property Title: string read FTitle write FTitle;
{ Returns the control paint area width on canvas in Units. }
property UnitControlPaintAreaWidth: Double read FUnitControlPaintAreaWidth;
{ Specifies the horizontal space that should stay free for application
specific contents at the left side of printed control. Value is given in Units. }
property UnitExtraSpaceLeft: Double read FUnitExtraSpaceLeft write SetUnitExtraSpaceLeft;
{ Specifies the horizontal space that should stay free for application
specific contents at the right side of printed control. Value is given in Units. }
property UnitExtraSpaceRight: Double read FUnitExtraSpaceRight write SetUnitExtraSpaceRight;
{ Specifies the vertical space that should stay free for application
specific footer. Value is given in Units. }
property UnitFooterSpace: Double read FUnitFooterSpace write SetUnitFooterSpace;
{ Specifies the vertical space that should stay free for application
specific header. Value is given in Units. }
property UnitHeaderSpace: Double read FUnitHeaderSpace write SetUnitHeaderSpace;
{ Specifies the bottom margin. Value is given in Units. }
property UnitMarginBottom: Double read FUnitMarginBottom write SetUnitMarginBottom;
{ Specifies the left margin. Value is given in Units. }
property UnitMarginLeft: Double read FUnitMarginLeft write SetUnitMarginLeft;
{ Specifies the right margin. Value is given in Units. }
property UnitMarginRight: Double read FUnitMarginRight write SetUnitMarginRight;
{ Specifies the top margin. Value is given in Units. }
property UnitMarginTop: Double read FUnitMarginTop write SetUnitMarginTop;
{ Returns the paint area height on canvas in Units. }
property UnitPaintAreaHeight: Double read FUnitPaintAreaHeight;
{ Returns the paint area width on canvas in Units. }
property UnitPaintAreaWidth: Double read FUnitPaintAreaWidth;
{ Specifies the units for print margins. }
property Units: TKPrintUnits read FUnits write SetUnits;
{ Allows to customize measure info filled from associated control just before
respective calculations are performed. }
property OnPrintMeasure: TKPrintMeasureEvent read FOnPrintMeasure write FOnPrintMeasure;
{ Allows to inspect settings before printing information is updated. }
property OnUpdateSettings: TNotifyEvent read FOnUpdateSettings write FOnUpdateSettings;
end;
{ @abstract(Container for all colors used by @link(TKPrintPreview) class)
This container allows to group many colors into one item in object inspector.
Colors are accessible via published properties or several public Color*
properties. }
TKPreviewColors = class(TKCustomColors)
protected
{ Returns color specification structure for given index. }
function GetColorSpec(Index: TKColorIndex): TKColorSpec; override;
{ Returns maximum color index. }
function GetMaxIndex: Integer; override;
published
{ Specifies the paper background color. }
property Paper: TColor index ciPaper read GetColor write SetColor default cPaperDef;
{ Specifies the color of the background around paper. }
property BkGnd: TColor index ciBkGnd read GetColor write SetColor default cBkGndDef;
{ Specifies the color of the paper border. }
property Border: TColor index ciBorder read GetColor write SetColor default cBorderDef;
{ Specifies the color of the paper border when the control has input focus. }
property SelectedBorder: TColor index ciSelectedBorder read GetColor write SetColor default cSelectedBorderDef;
end;
{ @abstract(Print preview control for the TKCustomControl component) }
TKPrintPreview = class(TKCustomControl)
private
FColors: TKPreviewColors;
FControl: TKCustomControl;
FMouseWheelAccumulator: Integer;
FPage: Integer;
FPageOld: Integer;
FPageSize: TPoint;
FExtent: TPoint;
FPageOffset: TPoint;
FScale: Integer;
FScaleMode: TKPreviewScaleMode;
FScrollExtent: TPoint;
FScrollPos: TPoint;
FScrollPosOld: TPoint;
FX: Integer;
FY: Integer;
FOnChanged: TKPreviewChangedEvent;
FPixelsPerInchX: Integer;
FPixelsPerInchY: Integer;
function GetCurrentScale: Integer;
function GetEndPage: Integer;
function GetStartPage: Integer;
procedure SetColors(const Value: TKPreviewColors);
procedure SetControl(Value: TKCustomControl);
procedure SetPage(Value: Integer);
procedure SetPixelsPerInchX(Value: Integer);
procedure SetPixelsPerInchY(Value: Integer);
procedure SetScale(Value: Integer);
procedure SetScaleMode(Value: TKPreviewScaleMode);
procedure WMEraseBkgnd(var Msg: TLMessage); message LM_ERASEBKGND;
procedure WMGetDlgCode(var Msg: TLMNoParams); message LM_GETDLGCODE;
procedure WMHScroll(var Msg: TLMHScroll); message LM_HSCROLL;
procedure WMKillFocus(var Msg: TLMKillFocus); message LM_KILLFOCUS;
procedure WMSetFocus(var Msg: TLMSetFocus); message LM_SETFOCUS;
procedure WMVScroll(var Msg: TLMVScroll); message LM_VSCROLL;
protected
FCurrentCanvas: TCanvas;
{ Initializes a scroll message handling. }
procedure BeginScrollWindow;
{ Defines additional styles. }
procedure CreateParams(var Params: TCreateParams); override;
{ Overriden method - handles mouse wheel messages. }
function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint): Boolean; override;
{ Calls the ScrollWindowEx function to complete a scroll message. }
procedure EndScrollWindow;
{ Returns current page rectangle inside of the window client area. }
function GetPageRect: TRect;
{ Processes virtual key strokes. }
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
{ Processes scrollbar messages.
Parameters:
- ScrollBar - scrollbar type from OS
- ScrollCode - scrollbar action from OS
- Delta - scrollbar position change
}
procedure ModifyScrollBar(ScrollBar, ScrollCode, Delta: Integer);
{ Initializes drag&scroll functionality. }
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
{ Performs drag&scroll functionality. }
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
{ Finalizes drag&scroll functionality. }
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
{ Notifies about associated TKCustomControl control removal. }
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
{ Paints paper and control shape. }
procedure Paint; override;
{ Paints the control to given canvas. }
procedure PaintToCanvas(ACanvas: TCanvas); override;
{ Calls the @link(OnChanged) event. }
procedure Changed;
{ Grants the input focus to the control when possible and the control has had none before. }
procedure SafeSetFocus;
{ Updates mouse cursor. }
function SetMouseCursor(X, Y: Integer): Boolean; override;
{ Updates page sizes and scrollbar ranges. }
procedure UpdateScrollRange;
{ Updates the control size. }
procedure UpdateSize; override;
property CurrentCanvas: TCanvas read FCurrentCanvas;
public
{ Performs necessary initializations - default values to properties. }
constructor Create(AOwner: TComponent); override;
{ Destroy instance... }
destructor Destroy; override;
{ Shows first page for the given range. }
procedure FirstPage;
{ Shows last page for the given range. }
procedure LastPage;
{ Shows next page. }
procedure NextPage;
{ Paints the current page to another canvas, without the top and left space around paper. }
procedure PaintTo(ACanvas: TCanvas);
{ Shows previous page. }
procedure PreviousPage;
{ Updates the preview. }
procedure UpdatePreview;
{ Returns the page scaling with regard to the @link(ScaleMode) property. }
property CurrentScale: Integer read GetCurrentScale;
{ Returns the current page area rectangle in desktop pixels. }
property PageRect: TRect read GetPageRect;
{ Returns the last page for the given range. }
property EndPage: Integer read GetEndPage;
{ Returns the first page for the given range. }
property StartPage: Integer read GetStartPage;
published
{ Inherited property - see Delphi help. }
property Align;
{ Inherited property - see Delphi help. }
property Anchors;
{ See TKCustomControl.@link(TKCustomControl.BorderStyle) for details. }
property BorderStyle;
{ Inherited property - see Delphi help. }
property BorderWidth;
{ Specifies all colors used by TKPrintPreview's default painting. }
property Colors: TKPreviewColors read FColors write SetColors;
{ Inherited property - see Delphi help. }
property Constraints;
{ Specifies the associated control. }
property Control: TKCustomControl read FControl write SetControl;
{ Inherited property - see Delphi help. }
property DragCursor;
{ Inherited property - see Delphi help. }
property DragKind;
{ Inherited property - see Delphi help. }
property DragMode;
{ Specifies the currently displayed page. }
property Page: Integer read FPage write SetPage default 1;
{ Inherited property - see Delphi help. }
property ParentShowHint;
{ Inherited property - see Delphi help. }
property PopupMenu;
{ The horizontal DPI at which to show the 100% scaled page. }
property PixelsPerInchX: Integer read FPixelsPerInchX write SetPixelsPerInchX default cDPIDef;
{ The vertical DPI at which to show the 100% scaled page. }
property PixelsPerInchY: Integer read FPixelsPerInchY write SetPixelsPerInchY default cDPIDef;
{ Specifies the user defined page scale - i.e. when ScaleMode = smScale. }
property Scale: Integer read FScale write SetScale default 100;
{ Specifies the scale mode to display and scroll previewed pages. }
property ScaleMode: TKPreviewScaleMode read FScaleMode write SetScaleMode default smPageWidth;
{ Inherited property - see Delphi help. }
property ShowHint;
{ Inherited property - see Delphi help. }
property TabStop;
{ Inherited property - see Delphi help. }
property TabOrder;
{ Inherited property - see Delphi help. }
property Visible;
{ Called whenever print preview is updated. }
property OnChanged: TKPreviewChangedEvent read FOnChanged write FOnChanged;
{ Inherited property - see Delphi help. }
property OnClick;
{ Inherited property - see Delphi help. }
property OnContextPopup;
{ Inherited property - see Delphi help. }
property OnDblClick;
{ Inherited property - see Delphi help. }
property OnDockDrop;
{ Inherited property - see Delphi help. }
property OnDockOver;
{ Inherited property - see Delphi help. }
property OnDragDrop;
{ Inherited property - see Delphi help. }
property OnDragOver;
{ Inherited property - see Delphi help. }
property OnEndDock;
{ Inherited property - see Delphi help. }
property OnEndDrag;
{ Inherited property - see Delphi help. }
property OnEnter;
{ Inherited property - see Delphi help. }
property OnExit;
{ Inherited property - see Delphi help. }
property OnGetSiteInfo;
{ Inherited property - see Delphi help. }
property OnKeyDown;
{ Inherited property - see Delphi help. }
property OnKeyPress;
{ Inherited property - see Delphi help. }
property OnKeyUp;
{ Inherited property - see Delphi help. }
property OnMouseDown;
{$IFDEF COMPILER9_UP}
{ Inherited property - see Delphi help. }
property OnMouseEnter;
{ Inherited property - see Delphi help. }
property OnMouseLeave;
{$ENDIF}
{ Inherited property - see Delphi help. }
property OnMouseMove;
{ Inherited property - see Delphi help. }
property OnMouseUp;
{ Inherited property - see Delphi help. }
property OnMouseWheel;
{ Inherited property - see Delphi help. }
property OnMouseWheelDown;
{ Inherited property - see Delphi help. }
property OnMouseWheelUp;
{ Inherited property - see Delphi help. }
property OnResize;
{ Inherited property - see Delphi help. }
property OnStartDock;
{ Inherited property - see Delphi help. }
property OnStartDrag;
{ Inherited property - see Delphi help. }
property OnUnDock;
end;
{ Under Windows this function calls the WinAPI TrackMouseEvent. Under other OSes
the implementation is still missing. }
procedure CallTrackMouseEvent(Control: TWinControl; var Status: Boolean);
{ Center window identified by CenteredWnd with regard to another window BoundWnd. }
procedure CenterWindowInWindow(CenteredWnd, BoundWnd: HWnd);
{ Center window identified by CenteredWnd with regard to main screen. }
procedure CenterWindowOnScreen(CenteredWnd: HWnd);
{ Load clipboard data to AStream in a format specified by AFormat (if any).
Loads also AText if clipboard has some data in text format. }
function ClipboardLoadStreamAs(const AFormat: TKClipboardFormat; AStream: TStream; var AText: TKString): Boolean; overload;
{ Load clipboard data to AStream in a format specified by AFormat (if any).
Loads also AText if clipboard has some data in text format. }
function ClipboardLoadStreamAs(const AFormat: string; AStream: TStream; var AText: TKString): Boolean; overload;
{ Save data from AStream to clipboard in a format specified by AFormat.
Optional AText can be saved in text format. }
function ClipboardSaveStreamAs(const AFormat: string; AStream: TStream; const AText: TKString): Boolean;
{ Enables or disables all children of AParent depending on AEnabled.
If ARecursive is True then the function applies to whole tree of controls
owned by AParent. }
procedure EnableControls(AParent: TWinControl; AEnabled: Boolean; ARecursive: Boolean = True);
{ Fills the message record. }
function FillMessage(Msg: Cardinal; WParam: WPARAM; LParam: LPARAM): TLMessage;
{ Searches for a child control. Can search recursively. }
function FindChildControl(AParent: TWinControl; const AName: string; ARecursive: Boolean = True): TControl;
{ Returns the Text property of any TWinControl instance as WideString (up to Delphi 2007)
or string (Delphi 2009, Lazarus). }
function GetControlText(Value: TWinControl): TKString;
{ Returns current status of Shift, Alt and Ctrl keys. }
function GetShiftState: TShiftState;
{ Converts a value given in inches into a value given in specified units.
Parameters:
- Units - measurement units for the output value
- Value - input value to convert
}
function InchesToValue(Units: TKPrintUnits; Value: Double): Double;
{ Open URL in external browser. }
procedure OpenURLWithShell(const AText: TKString);
{ Converts value given in specified units into a value given in inches.
Parameters:
- Units - measurement units for the input value
- Value - input value to convert
}
function ValueToInches(Units: TKPrintUnits; Value: Double): Double;
{ Under Windows this function calls the WinAPI SetWindowRgn. Under other OSes
the implementation is still missing. }
procedure SetControlClipRect(AControl: TWinControl; const ARect: TRect);
{ Modifies the Text property of any TWinControl instance. The value is given as
WideString (up to Delphi 2007) or string (Delphi 2009, Lazarus). }
procedure SetControlText(Value: TWinControl; const Text: TKString);
procedure DPIScaleAllForms(FromDPI: Integer = 96);
procedure DPIScaleControl(Control: TControl; FromDPI: Integer = 96);
function DPIScaleValue(Value: Int64; FromDPI: Integer = 96): Int64;
implementation
uses
{$IFDEF FPC}
{$IFDEF MSWINDOWS}Windows,{$ENDIF}
{$ELSE}
ShlObj, ShellApi,
{$ENDIF}
ClipBrd, Math, Types, KGraphics, KMessageBox, KRes;
const
cPreviewHorzBorder = 30;
cPreviewVertBorder = 30;
cPreviewShadowSize = 3;
procedure CallTrackMouseEvent(Control: TWinControl; var Status: Boolean);
{$IFDEF MSWINDOWS}
var
TE: TTrackMouseEvent;
begin
if not Status then
begin
TE.cbSize := SizeOf(TE);
TE.dwFlags := TME_LEAVE;
TE.hwndTrack := Control.Handle;
TE.dwHoverTime := HOVER_DEFAULT;
TrackMouseEvent(TE);
Status := True;
end;
end;
{$ELSE}
begin
// This is a TODO for Lazarus team.
end;
{$ENDIF}
procedure CenterWindowOnScreen(CenteredWnd: HWnd);
var
R: TRect;
begin
GetWindowRect(CenteredWnd, R);
R.Left := Max((Screen.Width - R.Right + R.Left) div 2, 0);
R.Top := Max((Screen.Height - R.Bottom + R.Top) div 2, 0);
SetWindowPos(CenteredWnd, 0, R.Left, R.Top, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
end;
procedure CenterWindowInWindow(CenteredWnd, BoundWnd: HWnd);
var
R1, R2: TRect;
begin
GetWindowRect(CenteredWnd, R1);
GetWindowRect(BoundWnd, R2);
R1.Left := Max((R2.Right - R2.Left - R1.Right + R1.Left) div 2, 0);
R1.Top := Max((R2.Bottom - R2.Top - R1.Bottom + R1.Top) div 2, 0);
SetWindowPos(CenteredWnd, 0, R1.Left, R1.Top, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
end;
function ClipboardLoadStreamAs(const AFormat: TKClipboardFormat; AStream: TStream; var AText: TKString): Boolean;
var
Data: HGLOBAL;
begin
Result := False;
{$IFDEF FPC}
with Clipboard do
begin
if (AFormat <> 0) and HasFormat(AFormat) then
begin
Clipboard.GetFormat(AFormat, AStream);
Result := True;
end else
begin
AText := AsText;
Result := AText <> '';
end;
end;
{$ELSE}
if AFormat <> 0 then
begin
Data := 0;
try
with Clipboard do
begin
Open;
try
if HasFormat(AFormat) then
begin
Data := GetAsHandle(AFormat);
if Data <> 0 then
begin
AStream.Write(GlobalLock(Data)^, GlobalSize(Data));
GlobalUnlock(Data);
Result := True;
end;
end else
begin
AText := AsText;
Result := AText <> '';
end;
finally
Close;
end;
end;
except
GlobalFree(Data);
end;
end else
Clipboard.AsText := AText;
{$ENDIF}
end;
function ClipboardLoadStreamAs(const AFormat: string; AStream: TStream; var AText: TKString): Boolean;
begin
{$IFDEF FPC}
Result := ClipboardLoadStreamAs(RegisterClipboardFormat(AFormat), AStream, AText);
{$ELSE}
Result := ClipboardLoadStreamAs(RegisterClipboardFormat(PChar(AFormat)), AStream, AText);
{$ENDIF}
end;
function ClipboardSaveStreamAs(const AFormat: string; AStream: TStream; const AText: TKString): Boolean;
var
Fmt: TKClipboardFormat;
Data: HGLOBAL;
begin
Result := False;
{$IFDEF FPC}
with Clipboard do
begin
Clear;
AsText := AText;
Fmt := RegisterClipboardFormat(AFormat);
if Fmt <> 0 then
begin
AStream.Seek(0, soFromBeginning);
AddFormat(Fmt, AStream);
Result := True;
end;
end;
{$ELSE}
Clipboard.Clear;
Fmt := RegisterClipboardFormat(PChar(AFormat));
if Fmt <> 0 then
begin
Data := GlobalAlloc(GHND or GMEM_SHARE, AStream.Size);
if Data <> 0 then
try
AStream.Seek(0, soFromBeginning);
AStream.Read(GlobalLock(Data)^, AStream.Size);
GlobalUnlock(Data);
with Clipboard do
begin
Open;
try
Clipboard.AsText := AText;
SetAsHandle(Fmt, Data);
finally
Close;
end;
end;
Result := True;
except
GlobalFree(Data);
end;
end else
Clipboard.AsText := AText;
{$ENDIF}
end;
procedure EnableControls(AParent: TWinControl; AEnabled, ARecursive: Boolean);
procedure DoEnable(AParent: TWinControl);
var
I: Integer;
begin
if AParent <> nil then
for I := 0 to AParent.ControlCount - 1 do
begin
AParent.Controls[I].Enabled := AEnabled;
if ARecursive and (AParent.Controls[I] is TWinControl) then
DoEnable(TWinControl(AParent.Controls[I]));
end;
end;
begin
DoEnable(AParent);
end;
function FillMessage(Msg: Cardinal; WParam: WPARAM; LParam: LPARAM): TLMessage;
begin
Result.Msg := Msg;
Result.LParam := LParam;
Result.WParam := WParam;
Result.Result := 0;
end;
function FindChildControl(AParent: TWinControl; const AName: string; ARecursive: Boolean): TControl;
function DoSearch(AParent: TWinControl): TControl;
var
I: Integer;
Ctrl: TControl;
begin
Result := nil;
if AParent <> nil then
for I := 0 to AParent.ControlCount - 1 do
begin
Ctrl := AParent.Controls[I];
if Ctrl.Name = AName then
Result := Ctrl
else if ARecursive and (Ctrl is TWinControl) then
Result := DoSearch(TWinControl(Ctrl));
if Result <> nil then
Break;
end;
end;
begin
Result := DoSearch(AParent);
end;
function GetControlText(Value: TWinControl): TKString;
function GetTextBuffer(Value: TWinControl): string;
begin
SetLength(Result, Value.GetTextLen);
if Length(Result) > 0 then
Value.GetTextBuf(PChar(Result), Length(Result) + 1);
end;
begin
{$IFDEF FPC}
Result := GetTextBuffer(Value); // conversion from UTF8 forced anyway
{$ELSE}
{$IFDEF STRING_IS_UNICODE}
Result := GetTextBuffer(Value);
{$ELSE}
if Value.HandleAllocated and (Win32Platform = VER_PLATFORM_WIN32_NT) then // unicode fully supported
begin
SetLength(Result, GetWindowTextLengthW(Value.Handle));
GetWindowTextW(Value.Handle, PWideChar(Result), Length(Result) + 1);
end else
Result := GetTextBuffer(Value);
{$ENDIF}
{$ENDIF}
end;
function GetShiftState: TShiftState;
begin
Result := [];
if GetKeyState(VK_SHIFT) < 0 then Include(Result, ssShift);
if GetKeyState(VK_CONTROL) < 0 then Include(Result, ssCtrl);
if GetKeyState(VK_MENU) < 0 then Include(Result, ssAlt);
end;
function InchesToValue(Units: TKPrintUnits; Value: Double): Double;
begin
case Units of
puMM: Result := Value * 25.4;
puCM: Result := Value * 2.54;
puHundredthInch: Result := Value * 100;
else
Result := Value;
end;
end;
procedure OpenURLWithShell(const AText: TKString);
begin
{$IFDEF FPC}
OpenURL(AText);
{$ELSE}
ShellExecuteW(Application.MainForm.Handle, 'open', PWideChar(AText), nil, nil, SW_SHOWNORMAL);
{$ENDIF}
end;
procedure SetControlClipRect(AControl: TWinControl; const ARect: TRect);
begin
if AControl.HandleAllocated then
begin
{$IFDEF MSWINDOWS}
SetWindowRgn(AControl.Handle, CreateRectRgn(0, 0, ARect.Right - ARect.Left, ARect.Bottom - ARect.Top), True);
{$ELSE}
//how to do that?
{$ENDIF}
end;
end;
procedure SetControlText(Value: TWinControl; const Text: TKString);
procedure SetTextBuffer(Value: TWinControl; const Text: string);
begin
Value.SetTextBuf(PChar(Text));
end;
begin
{$IFDEF FPC}
SetTextBuffer(Value, Text); // conversion to UTF8 forced anyway
{$ELSE}
{$IFDEF STRING_IS_UNICODE}
SetTextBuffer(Value, Text);
{$ELSE}
if Value.HandleAllocated and (Win32Platform = VER_PLATFORM_WIN32_NT) then // unicode fully supported
SetWindowTextW(Value.Handle, PWideChar(Text))
else
SetTextBuffer(Value, Text);
{$ENDIF}
{$ENDIF}
end;
function ValueToInches(Units: TKPrintUnits; Value: Double): Double;
begin
case Units of
puMM: Result := Value / 25.4;
puCM: Result := Value / 2.54;
puHundredthInch: Result := Value / 100;
else
Result := Value;
end;
end;
procedure DPIScaleAllForms(FromDPI: Integer);
var
i: integer;
begin
{$IFNDEF FPC}
if Screen.PixelsPerInch = FromDPI then
exit;
for i := 0 to Screen.FormCount - 1 do
DPIScaleControl(Screen.Forms[i], FromDPI);
{$ENDIF}
end;
procedure DPIScaleControl(Control: TControl; FromDPI: Integer);
var
WinControl: TWinControl;
begin
{$IFNDEF FPC}
if Screen.PixelsPerInch = FromDPI then
exit;
if Control is TWinControl then
begin
WinControl := TWinControl(Control);
WinControl.ScaleBy(Screen.PixelsPerInch, FromDPI);
end;
{$ENDIF}
end;
function DPIScaleValue(Value: Int64; FromDPI: Integer): Int64;
begin
{$IFDEF FPC}
Result := Value;
{$ELSE}
Result := Value * Screen.PixelsPerInch div FromDPI;
{$ENDIF}
end;
{ TKRect }
constructor TKRect.Create;
begin
inherited Create;
FOnChanged := nil;
FBottom := cRectBottomDef;
FLeft := cRectLeftDef;
FRight := cRectRightDef;
FTop := cRectTopDef;
end;
procedure TKRect.Assign(Source: TPersistent);
begin
if Source is TKRect then
begin
Bottom := TKRect(Source).Bottom;
Left := TKRect(Source).Left;
Right := TKRect(Source).Right;
Top := TKRect(Source).Top;
end;
end;
procedure TKRect.AssignFromRect(const ARect: TRect);
begin
FBottom := ARect.Bottom;
FLeft := ARect.Left;
FRight := ARect.Right;
FTop := ARect.Top;
end;
procedure TKRect.AssignFromValues(ALeft, ATop, ARight, ABottom: Integer);
begin
FBottom := ABottom;
FLeft := ALeft;
FRight := ARight;
FTop := ATop;
end;
procedure TKRect.Changed;
begin
if Assigned(FOnChanged) then
FOnChanged(Self);
end;
function TKRect.ContainsPoint(const APoint: TPoint): Boolean;
begin
Result :=
(FLeft <= APoint.X) and (APoint.X < FRight) and
(FTop <= APoint.Y) and (APoint.Y < FBottom);
end;
function TKRect.EqualProperties(const ARect: TKRect): Boolean;
begin
Result := (ARect <> nil) and
(FLeft = ARect.Left) and (FRight = ARect.Right) and
(FTop = ARect.Top) and (FBottom = ARect.Bottom);
end;
function TKRect.GetHeight: Integer;
begin
Result := FBottom - FTop;
end;
function TKRect.GetWidth: Integer;
begin
Result := FRight - FLeft;
end;
function TKRect.NonZero: Boolean;
begin
Result := (FLeft <> 0) or (FTop <> 0) or (FRight <> 0) or (FBottom <> 0);
end;
function TKRect.OffsetRect(ARect: TKRect): TRect;
begin
if ARect <> nil then
Result := Rect(ARect.Left + FLeft, ARect.Top + FTop, ARect.Right - FRight, ARect.Bottom - FBottom)
else
Result := CreateEmptyRect;
end;
function TKRect.OffsetRect(const ARect: TRect): TRect;
begin
Result := Rect(ARect.Left + FLeft, ARect.Top + FTop, ARect.Right - FRight, ARect.Bottom - FBottom);
end;
procedure TKRect.SetAll(const Value: Integer);
begin
Bottom := Value;
Left := Value;
Right := Value;
Top := Value;
end;
procedure TKRect.SetBottom(const Value: Integer);
begin
if FBottom <> Value then
begin
FBottom := Value;
Changed;
end;
end;
procedure TKRect.SetLeft(const Value: Integer);
begin
if FLeft <> Value then
begin
FLeft := Value;
Changed;
end;
end;
procedure TKRect.SetRight(const Value: Integer);
begin
if FRight <> Value then
begin
FRight := Value;
Changed;
end;
end;
procedure TKRect.SetTop(const Value: Integer);
begin
if FTop <> Value then
begin
FTop := Value;
Changed;
end;
end;
{ TKCustomControl }
constructor TKCustomControl.Create(AOwner: TComponent);
begin
inherited;
BorderStyle := cBorderStyleDef;
FFlags := 0;
FMemoryCanvas := nil;
FMessages := nil;
{$IFNDEF COMPILER10_UP}
FMouseInClient := False;
{$ENDIF}
FOldClientSize.X := 0;
FOldClientSize.Y := 0;
FPageSetup := nil;
{$IF DEFINED(FPC) OR NOT DEFINED(COMPILER10_UP)}
FParentBackground := True;
FParentDoubleBuffered := True;
{$IFEND}
FPreviewList := TList.Create;
FUpdateLock := 0;
FOnPrintNotify := nil;
FOnPrintPaint := nil;
end;
destructor TKCustomControl.Destroy;
begin
inherited;
FMessages := nil;
FreeAndNil(FPreviewList);
FreeAndNil(FPageSetup);
end;
procedure TKCustomControl.AddPreview(APreview: TKPrintPreview);
begin
if Assigned(APreview) then
FPreviewList.Add(APreview);
end;
procedure TKCustomControl.AdjustPageSetup;
begin
end;
procedure TKCustomControl.CallUpdateSize;
var
W, H: Integer;
begin
if HandleAllocated then
begin
W := ClientWidth;
H := ClientHeight;
if (FOldClientSize.X <> W) or (FOldClientSize.Y <> H) then
begin
UpdateSize;
FOldClientSize.X := W;
FOldClientSize.Y := H;
end;
end;
end;
procedure TKCustomControl.CancelMode;
begin
end;
{$IFNDEF FPC}
procedure TKCustomControl.CMCancelMode(var Msg: TLMessage);
begin
inherited;
CancelMode;
end;
procedure TKCustomControl.CMCtl3DChanged(var Msg: TLMessage);
begin
inherited;
RecreateWnd;
end;
{$ENDIF}
procedure TKCustomControl.CMMouseLeave(var Msg: TLMessage);
begin
inherited;
try
MouseFormLeave;
except
end;
end;
procedure TKCustomControl.CreateHandle;
begin
inherited;
CallUpdateSize;
end;
procedure TKCustomControl.CreateParams(var Params: TCreateParams);
begin
inherited;
{$IFNDEF FPC}
with Params do
begin
WindowClass.style := CS_DBLCLKS;
if BorderStyle = bsSingle then
if NewStyleControls and Ctl3D then
begin
Style := Style and not WS_BORDER;
ExStyle := ExStyle or WS_EX_CLIENTEDGE;
end
else
Style := Style or WS_BORDER;
end;
{$ENDIF}
end;
{$IFDEF FPC}
procedure TKCustomControl.DoOnChangeBounds;
begin
inherited;
if csDesigning in ComponentState then
PostLateUpdate(FillMessage(LM_SIZE, 0, 0), True)
else
CallUpdateSize;
end;
{$ENDIF}
function TKCustomControl.Flag(AFlag: Cardinal): Boolean;
begin
Result := FFlags and AFlag <> 0;
end;
procedure TKCustomControl.FlagAssign(AFlag: Cardinal; Value: Boolean);
begin
if Value then
FlagSet(AFlag)
else
FlagClear(AFlag);
end;
procedure TKCustomControl.FlagClear(AFlag: Cardinal);
begin
FFlags := FFlags and not AFlag;
end;
procedure TKCustomControl.FlagSet(AFlag: Cardinal);
begin
FFlags := FFlags or AFlag;
end;
procedure TKCustomControl.FlagToggle(AFlag: Cardinal);
begin
FFlags := FFlags xor AFlag;
end;
function TKCustomControl.GetCanPrint: Boolean;
begin
Result := PageSetup.CanPrint;
end;
function TKCustomControl.GetPageSetup: TKPrintPageSetup;
begin
if not Assigned(FPageSetup) and not (csDestroying in ComponentState) then
begin
FPageSetup := TKPrintPageSetup.Create(Self);
AdjustPageSetup;
end;
if Assigned(FPageSetup) then
FPageSetup.Validate;
Result := FPageSetup;
end;
function TKCustomControl.GetPageSetupAllocated: Boolean;
begin
Result := Assigned(FPageSetup);
end;
function TKCustomControl.InternalGetSelAvail: Boolean;
begin
Result := False;
end;
procedure TKCustomControl.InternalUnlockUpdate;
begin
end;
procedure TKCustomControl.Invalidate;
begin
if UpdateUnlocked and HandleAllocated then
inherited;
end;
procedure TKCustomControl.InvalidatePageSetup;
begin
if Assigned(FPageSetup) then
FPageSetup.Invalidate;
end;
procedure TKCustomControl.InvalidateRectArea(const R: TRect);
begin
if UpdateUnlocked and HandleAllocated then
InvalidateRect(Handle, @R, False);
end;
function TKCustomControl.IsThemed: Boolean;
begin
Result := True;
end;
procedure TKCustomControl.KMLateUpdate(var Msg: TLMessage);
var
M: TLMessage;
begin
if MessagePeek(M) then
LateUpdate(M);
end;
procedure TKCustomControl.LateUpdate(var Msg: TLMessage);
begin
case Msg.Msg of
LM_SIZE: CallUpdateSize;
end;
end;
procedure TKCustomControl.LockUpdate;
begin
Inc(FUpdateLock);
end;
procedure TKCustomControl.MeasurePages(var Info: TKPrintMeasureInfo);
begin
end;
function TKCustomControl.MessagePeek(out Msg: TLMessage): Boolean;
var
ALen: Integer;
begin
ALen := Length(FMessages);
if ALen > 0 then
begin
Dec(ALen);
Msg := FMessages[ALen];
SetLength(FMessages, ALen);
Result := True;
end else
Result := False;
end;
procedure TKCustomControl.MessagePoke(const Msg: TLMessage);
var
ALen: Integer;
begin
ALen := Length(FMessages);
SetLength(FMessages, ALen + 1);
FMessages[ALen] := Msg;
end;
function TKCustomControl.MessageSearch(MsgCode: Cardinal): Boolean;
var
I: Integer;
begin
Result := False;
for I := 0 to Length(FMessages) - 1 do
if FMessages[I].Msg = MsgCode then
begin
Result := True;
Exit;
end;
end;
procedure TKCustomControl.MouseFormLeave;
begin
end;
procedure TKCustomControl.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
inherited;
{$IFNDEF COMPILER10_UP}
CallTrackMouseEvent(Self, FMouseInClient);
{$ENDIF}
{$IFDEF FPC}
if not MouseCapture then
SetMouseCursor(X, Y);
{$ENDIF}
end;
procedure TKCustomControl.NotifyPreviews;
var
I: Integer;
begin
for I := 0 to FPreviewList.Count - 1 do
TKPrintPreview(FPreviewList[I]).UpdatePreview;
end;
procedure TKCustomControl.Paint;
begin
PaintToCanvas(Canvas);
if Assigned(FMemoryCanvas) then
begin
{$IFDEF MSWINDOWS}
// this is the best method but does not work both on QT and GTK!
MoveWindowOrg(FMemoryCanvas.Handle, -FMemoryCanvasRect.Left, -FMemoryCanvasRect.Top);
try
PaintToCanvas(FMemoryCanvas);
finally
MoveWindowOrg(FMemoryCanvas.Handle, FMemoryCanvasRect.Left, FMemoryCanvasRect.Top);
end;
{$ELSE}
FMemoryCanvas.CopyRect(Rect(0, 0, FMemoryCanvasRect.Right - FMemoryCanvasRect.Left,
FMemoryCanvasRect.Bottom - FMemoryCanvasRect.Top), Canvas, FMemoryCanvasRect);
{$ENDIF}
FMemoryCanvas := nil;
end;
end;
procedure TKCustomControl.PostLateUpdate(const Msg: TLMessage;
IfNotExists: Boolean);
var
MessageExists: Boolean;
TmpMsg: tagMSG;
begin
if HandleAllocated then
begin
MessageExists := MessageSearch(Msg.Msg);
if not MessageExists or not IfNotExists then
begin
MessagePoke(Msg);
PostMessage(Handle, KM_LATEUPDATE, 0, 0);
end;
// resend lost message
if MessageExists and not PeekMessage(TmpMsg, Handle, KM_LATEUPDATE, KM_LATEUPDATE, PM_NOREMOVE) then
PostMessage(Handle, KM_LATEUPDATE, 0, 0);
end;
end;
procedure TKCustomControl.PrintNotify(Status: TKPrintStatus; var Abort: Boolean);
begin
if Assigned(FOnPrintNotify) then
FOnPrintNotify(Self, Status, Abort);
end;
procedure TKCustomControl.PrintPaint;
begin
if Assigned(FOnPrintPaint) then
FOnPrintPaint(Self);
end;
procedure TKCustomControl.PrintPaintBegin;
begin
end;
procedure TKCustomControl.PrintPaintEnd;
begin
end;
procedure TKCustomControl.PrintOut;
begin
GetPageSetup.PrintOut;
end;
procedure TKCustomControl.PaintPage;
begin
end;
procedure TKCustomControl.RemovePreview(APreview: TKPrintPreview);
begin
if Assigned(FPreviewList) and (FPreviewList.IndexOf(APreview) >= 0) then
FPreviewList.Remove(APreview);
end;
procedure TKCustomControl.Resize;
begin
inherited;
// Needs to be handled in Lazarus as well!
// DoOnChangeBounds is not called in LCL when eg. scrollbars change their visibility etc.
PostLateUpdate(FillMessage(LM_SIZE, 0, 0), True);
end;
{$IFNDEF FPC}
procedure TKCustomControl.SetBorderStyle(Value: TBorderStyle);
begin
if FBorderStyle <> Value then
begin
FBorderStyle := Value;
RecreateWnd;
end;
end;
{$ENDIF}
function TKCustomControl.SetMouseCursor(X, Y: Integer): Boolean;
begin
Result := False;
end;
procedure TKCustomControl.SetPageSetup(Value: TKPrintPageSetup);
begin
if Value <> FPageSetup then
GetPageSetup.Assign(Value);
end;
procedure TKCustomControl.UnlockUpdate;
begin
if FUpdateLock > 0 then
begin
Dec(FUpdateLock);
if FUpdateLock = 0 then
InternalUnlockUpdate;
end;
end;
procedure TKCustomControl.UpdateSize;
begin
end;
function TKCustomControl.UpdateUnlocked: Boolean;
begin
Result := FUpdateLock = 0;
end;
{$IFNDEF FPC}
procedure TKCustomControl.WMCancelMode(var Msg: TWMCancelMode);
begin
inherited;
CancelMode;
end;
{$ENDIF}
{$IFNDEF COMPILER10_UP}
procedure TKCustomControl.WMMouseLeave(var Msg: TLMessage);
begin
{ this is because of CM_MOUSELEAVE is not sent if mouse has left client area
and entered any of the standard control scrollbars. This behavior has been
fixed via TrackMouseEvent in BDS 2006. }
inherited;
FMouseInClient := False;
Perform(CM_MOUSELEAVE, 0, 0);
end;
{$ENDIF}
{$IFNDEF FPC}
procedure TKCustomControl.WMNCPaint(var Msg: TWMNCPaint);
{$IFDEF USE_THEMES}
var
R: TRect;
ExStyle: Integer;
TempRgn: HRGN;
BorderWidth,
BorderHeight: Integer;
{$ENDIF}
begin
{$IFDEF USE_THEMES}
with ThemeServices do if IsThemed and ThemesEnabled then
begin
// If OS themes are enabled and the client edge border is set for the window then prevent the default window proc
// from painting the old border to avoid flickering.
ExStyle := GetWindowLong(Handle, GWL_EXSTYLE);
if (ExStyle and WS_EX_CLIENTEDGE) <> 0 then
begin
GetWindowRect(Handle, R);
// Determine width of the client edge.
BorderWidth := GetSystemMetrics(SM_CXEDGE);
BorderHeight := GetSystemMetrics(SM_CYEDGE);
InflateRect(R, -BorderWidth, -BorderHeight);
TempRgn := CreateRectRgnIndirect(R);
// Exclude the border from the message region if there is one. Otherwise just use the inflated
// window area region.
if Msg.Rgn <> 1 then
CombineRgn(TempRgn, Msg.Rgn, TempRgn, RGN_AND);
DefWindowProc(Handle, Msg.Msg, Integer(TempRgn), 0);
DeleteObject(TempRgn);
PaintBorder(Self, True);
end else
inherited;
end else
{$ENDIF}
inherited;
end;
procedure TKCustomControl.WMSetCursor(var Msg: TWMSetCursor);
var
MousePt: TPoint;
begin
if (Msg.HitTest = HTCLIENT) and (Msg.CursorWnd = Handle) then
begin
MousePt := ScreenToClient(Mouse.CursorPos);
if SetMouseCursor(MousePt.X, MousePt.Y) then
Msg.Result := 1
else
inherited
end else
inherited;
end;
{$ENDIF}
procedure TKCustomControl.WMSize(var Msg: TLMSize);
begin
FResizeCalled := False;
inherited;
{$IFnDEF FPC}
if not FResizeCalled then
PostLateUpdate(FillMessage(LM_SIZE, 0, 0), True);
{$ENDIF}
end;
{$IFNDEF FPC}
{$IFDEF USE_THEMES}
procedure TKCustomControl.WMThemeChanged(var Msg: TLMessage);
begin
if IsThemed then
begin
inherited;
ThemeServices.UpdateThemes;
RedrawWindow(Handle, nil, 0, RDW_INVALIDATE or RDW_VALIDATE or RDW_FRAME);
end;
end;
{$ENDIF}
{$ENDIF}
{ TKCustomColors }
constructor TKCustomColors.Create(AControl: TKCustomControl);
begin
inherited Create;
FControl := AControl;
Initialize;
ClearBrightColors;
end;
procedure TKCustomColors.Assign(Source: TPersistent);
begin
inherited;
if Source is TKCustomColors then
begin
Colors := TKCustomColors(Source).Colors;
FControl.Invalidate;
end
end;
procedure TKCustomColors.ClearBrightColors;
var
I: TKColorIndex;
begin
for I := 0 to Length(FBrightColors) - 1 do
FBrightColors[I] := clNone;
end;
function TKCustomColors.GetColor(Index: TKColorIndex): TColor;
begin
Result := InternalGetColor(Index);
end;
function TKCustomColors.GetColorData(Index: TKColorIndex): TKColorData;
var
ColorSpec: TKColorSpec;
begin
Result.Index := Index;
Result.Color := FColors[Index];
ColorSpec := GetColorSpec(Index);
Result.Default := ColorSpec.Def;
Result.Name := ColorSpec.Name;
end;
function TKCustomColors.GetColorEx(Index: TKColorIndex): TColor;
begin
Result := FColors[Index];
end;
function TKCustomColors.GetColorName(Index: TKColorIndex): string;
begin
Result := GetColorSpec(Index).Name;
end;
function TKCustomColors.GetColorSpec(Index: TKColorIndex): TKColorSpec;
begin
Result.Def := clNone;
Result.Name := '';
end;
function TKCustomColors.GetDefaultColor(Index: TKColorIndex): TColor;
begin
Result := GetColorSpec(Index).Def;
end;
function TKCustomColors.GetMaxIndex: Integer;
begin
Result := -1;
end;
procedure TKCustomColors.Initialize;
var
I, MaxIndex: TKColorIndex;
begin
MaxIndex := GetMaxIndex;
SetLength(FColors, MaxIndex + 1);
SetLength(FBrightColors, MaxIndex + 1);
for I := 0 to Length(FColors) - 1 do
FColors[I] := GetColorSpec(I).Def;
end;
function TKCustomColors.InternalGetColor(Index: TKColorIndex): TColor;
begin
case FColorScheme of
csBright:
begin
if FBrightColors[Index] = clNone then
FBrightColors[Index] := BrightColor(FColors[Index], 0.5, bsOfTop);
Result := FBrightColors[Index];
end;
csGrayScale:
Result := ColorToGrayScale(FColors[Index]);
else
Result := FColors[Index];
end;
end;
procedure TKCustomColors.InternalSetColor(Index: TKColorIndex; Value: TColor);
begin
if FColors[Index] <> Value then
begin
FColors[Index] := Value;
FBrightColors[Index] := clNone;
if not (csLoading in FControl.ComponentState) then
FControl.Invalidate;
end;
end;
procedure TKCustomColors.SetColor(Index: TKColorIndex; Value: TColor);
begin
InternalSetColor(Index, Value);
end;
procedure TKCustomColors.SetColorEx(Index: TKColorIndex; Value: TColor);
begin
if FColors[Index] <> Value then
begin
FColors[Index] := Value;
FBrightColors[Index] := clNone;
end;
end;
procedure TKCustomColors.SetColors(const Value: TKColorArray);
var
I: Integer;
begin
for I := 0 to Min(Length(FColors), Length(Value)) - 1 do
FColors[I] := Value[I];
ClearBrightColors;
end;
{ TKPrintPageSetup }
constructor TKPrintPageSetup.Create(AControl: TKCustomControl);
begin
inherited Create;
FActive := False;
FCanvas := nil;
FControl := AControl;
FControlHorzPageCount := 0;
FControlPageCount := 0;
FControlVertPageCount := 0;
FCopies := cCopiesDef;
FCurrentCopy := 0;
FCurrentPage := 0;
FCurrentScale := 0;
FMappedOutlineHeight := 0;
FMappedOutlineWidth := 0;
FDesktopPixelsPerInchX := 0;
FDesktopPixelsPerInchY := 0;
FEndPage := 0;
FExtraLeftHorzPageCount := 0;
FExtraLeftPageCount := 0;
FExtraLeftVertPageCount := 0;
FExtraRightHorzPageCount := 0;
FExtraRightPageCount := 0;
FExtraRightVertPageCount := 0;
FIsValid := False;
FOptions := cOptionsDef;
FOrientation := poPortrait;
FPageCount := 0;
FPreviewing := False;
FPrinterExtraSpaceLeft := 0;
FPrinterExtraSpaceRight := 0;
FPrinterFooterSpace := 0;
FPrinterHeaderSpace := 0;
FPrinterMarginBottom := 0;
FPrinterMarginLeft := 0;
FPrinterMarginLeftMirrored := 0;
FPrinterMarginRight := 0;
FPrinterMarginRightMirrored := 0;
FPrinterMarginTop := 0;
FPrinterName := '';
FPrinterPageHeight := 0;
FPrinterPageWidth := 0;
FPrinterPixelsPerInchX := 0;
FPrinterPixelsPerInchY := 0;
FPrintingMapped := True;
FRange := cRangeDef;
FStartPage := 0;
FScale := cScaleDef;
FTitle := '';
FUnitExtraSpaceLeft := 0;
FUnitExtraSpaceRight := 0;
FUnitFooterSpace := 0;
FUnitHeaderSpace := 0;
FUnitMarginBottom := cMarginBottomDef;
FUnitMarginLeft := cMarginLeftDef;
FUnitMarginRight := cMarginRightDef;
FUnitMarginTop := cMarginTopDef;
FUnitPaintAreaHeight := 0;
FUnitPaintAreaWidth := 0;
FUnits := cUnitsDef;
FValidating := False;
FOnPrintMeasure := nil;
FOnUpdateSettings := nil;
end;
function TKPrintPageSetup.GetCanPrint: Boolean;
begin
Result := Assigned(FControl) and (FPageCount > 0) and (Printer.Printers.Count > 0);
end;
function TKPrintPageSetup.GetCurrentPageControl: Integer;
begin
if (FCurrentPage > FExtraLeftPageCount) and (FCurrentPage <= FExtraLeftPageCount + FControlPageCount) then
Result := FCurrentPage - FExtraLeftPageCount
else
Result := 0; // we are in extra left or right area
end;
function TKPrintPageSetup.GetCurrentPageExtraLeft: Integer;
begin
if (FCurrentPage > 0) and (FCurrentPage <= FExtraLeftPageCount) then
Result := FCurrentPage - FExtraLeftPageCount
else
Result := 0; // we are in control or extra right area
end;
function TKPrintPageSetup.GetCurrentPageExtraRight: Integer;
begin
if FCurrentPage > FExtraLeftPageCount + FControlPageCount then
Result := FCurrentPage - FExtraLeftPageCount - FControlPageCount
else
Result := 0; // we are in control or extra left area
end;
function TKPrintPageSetup.GetIsDefaultPrinter: Boolean;
begin
try
Result := Printer.PrinterIndex > -MaxInt;
except
Result := False;
end;
end;
function TKPrintPageSetup.GetSelAvail: Boolean;
begin
if Assigned(FControl) then
Result := FControl.InternalGetSelAvail
else
Result := False;
end;
procedure TKPrintPageSetup.AfterUnitsChange;
begin
FUnitExtraSpaceLeft := InchesToValue(FUnits, FUnitExtraSpaceLeft);
FUnitExtraSpaceRight := InchesToValue(FUnits, FUnitExtraSpaceRight);
FUnitFooterSpace := InchesToValue(FUnits, FUnitFooterSpace);
FUnitHeaderSpace := InchesToValue(FUnits, FUnitHeaderSpace);
FUnitMarginBottom := InchesToValue(FUnits, FUnitMarginBottom);
FUnitMarginLeft := InchesToValue(FUnits, FUnitMarginLeft);
FUnitMarginRight := InchesToValue(FUnits, FUnitMarginRight);
FUnitMarginTop := InchesToValue(FUnits, FUnitMarginTop);
end;
procedure TKPrintPageSetup.Assign(Source: TPersistent);
begin
if Source is TKPrintPageSetup then
begin
LockUpdate;
try
Copies := TKPrintPageSetup(Source).Copies;
EndPage := TKPrintPageSetup(Source).EndPage;
Options := TKPrintPageSetup(Source).Options;
PrinterName := TKPrintPageSetup(Source).PrinterName;
Range := TKPrintPageSetup(Source).Range;
StartPage := TKPrintPageSetup(Source).StartPage;
Scale := TKPrintPageSetup(Source).Scale;
Title := TKPrintPageSetup(Source).Title;
UnitExtraSpaceLeft := TKPrintPageSetup(Source).UnitExtraSpaceLeft;
UnitExtraSpaceRight := TKPrintPageSetup(Source).UnitExtraSpaceRight;
UnitFooterSpace := TKPrintPageSetup(Source).UnitFooterSpace;
UnitHeaderSpace := TKPrintPageSetup(Source).UnitHeaderSpace;
UnitMarginBottom := TKPrintPageSetup(Source).UnitMarginBottom;
UnitMarginLeft := TKPrintPageSetup(Source).UnitMarginLeft;
UnitMarginRight := TKPrintPageSetup(Source).UnitMarginRight;
UnitMarginTop := TKPrintPageSetup(Source).UnitMarginTop;
Units := TKPrintPageSetup(Source).Units;
OnUpdateSettings := TKPrintPageSetup(Source).OnUpdateSettings;
finally
UnlockUpdate;
end;
end;
end;
procedure TKPrintPageSetup.BeforeUnitsChange;
begin
FUnitExtraSpaceLeft := ValueToInches(FUnits, FUnitExtraSpaceLeft);
FUnitExtraSpaceRight := ValueToInches(FUnits, FUnitExtraSpaceRight);
FUnitFooterSpace := ValueToInches(FUnits, FUnitFooterSpace);
FUnitHeaderSpace := ValueToInches(FUnits, FUnitHeaderSpace);
FUnitMarginBottom := ValueToInches(FUnits, FUnitMarginBottom);
FUnitMarginLeft := ValueToInches(FUnits, FUnitMarginLeft);
FUnitMarginRight := ValueToInches(FUnits, FUnitMarginRight);
FUnitMarginTop := ValueToInches(FUnits, FUnitMarginTop);
end;
function TKPrintPageSetup.HMap(Value: Integer): Integer;
begin
Result := MulDiv(Value, FPrinterPixelsPerInchX, FDesktopPixelsPerInchX);
end;
procedure TKPrintPageSetup.Invalidate;
begin
FIsValid := False;
end;
procedure TKPrintPageSetup.PaintPageToPreview(APreview: TKPrintPreview);
var
PaperWidth, PaperHeight,
DesktopPageWidth, DesktopPageHeight,
SaveIndex, LeftOffset: Integer;
R, PageRect: TRect;
begin
if UpdateUnlocked and Assigned(FControl) then
begin
if FActive then
Invalidate
else
begin
FCanvas := APreview.CurrentCanvas;
FActive := True;
FPreviewing := True;
try
FControl.PrintPaintBegin;
FCurrentCopy := 1;
FCurrentPage := APreview.Page;
if (poMirrorMargins in FOptions) and (FCurrentPage and 1 <> 0) then
begin
FPrinterMarginLeftMirrored := FPrinterMarginRight;
FPrinterMarginRightMirrored := FPrinterMarginLeft;
end else
begin
FPrinterMarginLeftMirrored := FPrinterMarginLeft;
FPrinterMarginRightMirrored := FPrinterMarginRight;
end;
R := APreview.PageRect;
PaperWidth := R.Right - R.Left;
PaperHeight := R.Bottom - R.Top;
if CurrentPageControl > 0 then
begin
SaveIndex := SaveDC(FCanvas.Handle);
try
if poFitToPage in FOptions then
LeftOffset := FPrinterExtraSpaceLeft
else
LeftOffset := 0;
// change the canvas mapping mode to scale the page outline
CanvasSetOffset(FCanvas,
R.Left + MulDiv(FPrinterMarginLeftMirrored + LeftOffset, PaperWidth, FPrinterPageWidth),
R.Top + MulDiv(FPrinterMarginTop + FPrinterHeaderSpace, PaperHeight, FPrinterPageHeight));
if FPrintingMapped then
begin
DesktopPageWidth := MulDiv(FPrinterPageWidth, FDesktopPixelsPerInchX, FPrinterPixelsPerInchX);
DesktopPageHeight := MulDiv(FPrinterPageHeight, FDesktopPixelsPerInchY, FPrinterPixelsPerInchY);
CanvasSetScale(FCanvas, Round(PaperWidth * FCurrentScale), Round(PaperHeight * FCurrentScale), DesktopPageWidth, DesktopPageHeight);
end
else
CanvasSetScale(FCanvas, PaperWidth, PaperHeight, FPrinterPageWidth, FPrinterPageHeight);
FControl.PaintPage;
finally
RestoreDC(FCanvas.Handle, SaveIndex);
end;
end;
PaperWidth := R.Right - R.Left;
PaperHeight := R.Bottom - R.Top;
SaveIndex := SaveDC(FCanvas.Handle);
try
CanvasSetOffset(FCanvas, R.Left, R.Top);
CanvasSetScale(FCanvas, PaperWidth, PaperHeight, FPrinterPageWidth, FPrinterPageHeight);
PageRect := Rect(0, 0, FPrinterPageWidth, FPrinterPageHeight);
TranslateRectToDevice(FCanvas.Handle, PageRect);
SelectClipRect(FCanvas.Handle, PageRect);
FControl.PrintPaint;
finally
RestoreDC(FCanvas.Handle, SaveIndex);
end;
SaveIndex := SaveDC(FCanvas.Handle);
try
CanvasSetOffset(FCanvas, R.Left, R.Top);
CanvasSetScale(FCanvas, PaperWidth, PaperHeight, FPrinterPageWidth, FPrinterPageHeight);
PageRect := Rect(0, 0, FPrinterPageWidth, FPrinterPageHeight);
TranslateRectToDevice(FCanvas.Handle, PageRect);
SelectClipRect(FCanvas.Handle, PageRect);
PrintTitle;
PrintPageNumber(FCurrentPage);
finally
RestoreDC(FCanvas.Handle, SaveIndex);
end;
FControl.PrintPaintEnd;
finally
FActive := False;
FPreviewing := False;
FCanvas := nil;
end;
end;
end;
end;
procedure TKPrintPageSetup.PrintPageNumber(Value: Integer);
var
S: string;
begin
if poPageNumbers in FOptions then
begin
SetBkMode(FCanvas.Handle, TRANSPARENT);
FCanvas.Brush.Style := bsClear;
FCanvas.Font.Color := clBlack;
FCanvas.Font.Height := 1;
FCanvas.Font.Height := VMap(16);
FCanvas.Font.Name := 'Arial';
FCanvas.Font.Pitch := fpDefault;
FCanvas.Font.Style := [fsBold];
S := Format('- %d -', [Value]);
FCanvas.TextOut(FPrinterMarginLeftMirrored + (FPrinterPageWidth - FPrinterMarginLeft - FPrinterMarginRight - FCanvas.TextWidth(S)) div 2,
FPrinterPageHeight - FPrinterMarginBottom + VMap(5), S);
end;
end;
procedure TKPrintPageSetup.PrintTitle;
begin
if poTitle in FOptions then
begin
SetBkMode(FCanvas.Handle, TRANSPARENT);
FCanvas.Brush.Style := bsClear;
FCanvas.Font.Color := clBlack;
FCanvas.Font.Height := 1;
FCanvas.Font.Height := VMap(16);
FCanvas.Font.Name := 'Arial';
FCanvas.Font.Pitch := fpDefault;
FCanvas.Font.Style := [fsBold];
FCanvas.TextOut(FPrinterMarginLeftMirrored, FPrinterMarginTop - VMap(36), Title);
FCanvas.Brush.Style := bsSolid;
FCanvas.Brush.Color := clBlack;
FCanvas.FillRect(Rect(FPrinterMarginLeftMirrored, FPrinterMarginTop - VMap(14), FPrinterPageWidth - FPrinterMarginRight, FPrinterMarginTop - VMap(12)));
end;
end;
procedure TKPrintPageSetup.PrintOut;
function DoPrint: Boolean;
var
LeftOffset, SaveIndex: Integer;
PageRect: TRect;
begin
Result := False;
if (poMirrorMargins in FOptions) and (FCurrentPage and 1 <> 0) then
begin
FPrinterMarginLeftMirrored := FPrinterMarginRight;
FPrinterMarginRightMirrored := FPrinterMarginLeft;
end else
begin
FPrinterMarginLeftMirrored := FPrinterMarginLeft;
FPrinterMarginRightMirrored := FPrinterMarginRight;
end;
if CurrentPageControl > 0 then
begin
SaveIndex := SaveDC(FCanvas.Handle);
try
if poFitToPage in FOptions then
LeftOffset := FPrinterExtraSpaceLeft
else
LeftOffset := 0;
CanvasSetOffset(FCanvas, FPrinterMarginLeftMirrored + LeftOffset, FPrinterMarginTop + FPrinterHeaderSpace);
if FPrintingMapped then
begin
// change the canvas mapping mode to scale the page outline
CanvasSetScale(FCanvas, Round(FPrinterPageWidth * FCurrentScale), Round(FPrinterPageHeight * FCurrentScale),
MulDiv(FPrinterPageWidth, FDesktopPixelsPerInchX, FPrinterPixelsPerInchX),
MulDiv(FPrinterPageHeight, FDesktopPixelsPerInchY, FPrinterPixelsPerInchY));
end else
CanvasResetScale(FCanvas);
FControl.PaintPage;
finally
RestoreDC(FCanvas.Handle, SaveIndex);
end;
end;
SaveIndex := SaveDC(FCanvas.Handle);
try
CanvasResetScale(FCanvas);
PageRect := Rect(0, 0, FPrinterPageWidth, FPrinterPageHeight);
TranslateRectToDevice(FCanvas.Handle, PageRect);
SelectClipRect(FCanvas.Handle, PageRect);
FControl.PrintPaint;
finally
RestoreDC(FCanvas.Handle, SaveIndex);
end;
SaveIndex := SaveDC(FCanvas.Handle);
try
CanvasResetScale(FCanvas);
PageRect := Rect(0, 0, FPrinterPageWidth, FPrinterPageHeight);
TranslateRectToDevice(FCanvas.Handle, PageRect);
SelectClipRect(FCanvas.Handle, PageRect);
PrintTitle;
PrintPageNumber(FCurrentPage);
finally
RestoreDC(FCanvas.Handle, SaveIndex);
end;
FControl.PrintNotify(epsNewPage, Result);
if ((FCurrentPage < FEndPage) or (FCurrentCopy < FCopies)) and not Result then
Printer.NewPage;
end;
var
I, J, PrinterCount: Integer;
AbortPrint: Boolean;
{ Orientation: TPrinterOrientation;
PaperSize: TPaperSize;
APageWidth, ApageHeight, APaperWidth, APaperHeight: Integer;
PrinterType: TPrinterType;
APaperRect: TPaperRect;}
begin
if UpdateUnlocked and Assigned(FControl) and not FActive then
begin
UpdateSettings;
if FPageCount > 0 then
begin
if IsDefaultPrinter then
begin
PrinterCount := 0;
try
AbortPrint := False;
PrinterCount := Printer.Printers.Count;
Printer.Title := FTitle;
Printer.Copies := 1;
{ PrinterType := Printer.PrinterType;
APageWidth := Printer.PageWidth;
APageHeight := Printer.PageHeight;
APaperRect := Printer.PaperSize.PaperRect;
Orientation := Printer.Orientation;}
Printer.BeginDoc;
FActive := True;
try
FCanvas := Printer.Canvas;
FControl.PrintNotify(epsBegin, AbortPrint);
{ Printer.Canvas.Font.Name := 'Arial';
Printer.Canvas.Font.color := clBlack;
Printer.Canvas.Font.height := 100;
Printer.Canvas.TextOut(200, 200, 'hello!');}
if not AbortPrint then
begin
FControl.PrintPaintBegin;
try
if poCollate in FOptions then
for I := 1 to FCopies do
begin
FCurrentCopy := I;
for J := FStartPage to FEndPage do
begin
FCurrentPage := J;
AbortPrint := DoPrint;
if AbortPrint then Break;
end;
if AbortPrint then Break;
end
else
for J := FStartPage to FEndPage do
begin
FCurrentPage := J;
for I := 1 to FCopies do
begin
FCurrentCopy := I;
AbortPrint := DoPrint;
if AbortPrint then Break;
end;
if AbortPrint then Break;
end
finally
FControl.PrintPaintEnd;
end;
end;
FCurrentPage := 0;
FCurrentCopy := 0;
FControl.PrintNotify(epsEnd, AbortPrint);
finally
FActive := False;
Printer.EndDoc;
FCanvas := nil;
end;
except
if PrinterCount = 0 then
KMsgBox(sPSErrPrintSetup, sPSErrNoPrinterInstalled, [mbOk], miStop)
else
KMsgBox(sPSErrPrintSetup, sPSErrPrinterUnknown, [mbOk], miStop);
end;
end else
KMsgBox(sPSErrPrintSetup, sPSErrNoDefaultPrinter, [mbOk], miStop);
end;
end;
end;
procedure TKPrintPageSetup.SetCopies(Value: Integer);
begin
if FActive then Exit;
if Value <> FCopies then
begin
FCopies := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetEndPage(Value: Integer);
begin
if FActive then Exit;
if Value <> FEndPage then
begin
FEndPage := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetOptions(Value: TKPrintOptions);
begin
if FActive then Exit;
if Value <> FOptions then
begin
FOptions := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetOrientation(AValue: TPrinterOrientation);
begin
if AValue <> FOrientation then
begin
FOrientation := AValue;
Changed;
end;
end;
procedure TKPrintPageSetup.SetPrinterName(const Value: string);
begin
if FActive then Exit;
if Value <> FPrinterName then
begin
FPrinterName := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetPrintingMapped(Value: Boolean);
begin
if FActive then Exit;
if Value <> FPrintingMapped then
begin
FPrintingMapped := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetRange(Value: TKPrintRange);
begin
if FActive then Exit;
if Value <> FRange then
begin
FRange := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetScale(Value: Integer);
begin
if FActive then Exit;
if Value <> FScale then
begin
FScale := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetStartPage(Value: Integer);
begin
if FActive then Exit;
if Value <> FStartPage then
begin
FStartPage := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetUnitExtraSpaceLeft(Value: Double);
begin
if FActive then Exit;
if Value <> FUnitExtraSpaceLeft then
begin
FUnitExtraSpaceLeft := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetUnitExtraSpaceRight(Value: Double);
begin
if FActive then Exit;
if Value <> FUnitExtraSpaceRight then
begin
FUnitExtraSpaceRight := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetUnitFooterSpace(Value: Double);
begin
if FActive then Exit;
if Value <> FUnitFooterSpace then
begin
FUnitFooterSpace := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetUnitHeaderSpace(Value: Double);
begin
if FActive then Exit;
if Value <> FUnitHeaderSpace then
begin
FUnitHeaderSpace := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetUnitMarginBottom(Value: Double);
begin
if FActive then Exit;
if Value <> FUnitMarginBottom then
begin
FUnitMarginBottom := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetUnitMarginLeft(Value: Double);
begin
if FActive then Exit;
if Value <> FUnitMarginLeft then
begin
FUnitMarginLeft := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetUnitMarginRight(Value: Double);
begin
if FActive then Exit;
if Value <> FUnitMarginRight then
begin
FUnitMarginRight := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetUnitMarginTop(Value: Double);
begin
if FActive then Exit;
if Value <> FUnitMarginTop then
begin
FUnitMarginTop := Value;
Changed;
end;
end;
procedure TKPrintPageSetup.SetUnits(Value: TKPrintUnits);
begin
if FActive then Exit;
if Value <> FUnits then
begin
BeforeUnitsChange;
FUnits := Value;
AfterUnitsChange;
end;
end;
procedure TKPrintPageSetup.Update;
begin
UpdateSettings;
end;
procedure TKPrintPageSetup.UpdateSettings;
var
I, PixelsPerInchX, PixelsPerInchY: Integer;
D: Double;
DC: HDC;
Info: TKPrintMeasureInfo;
begin
if UpdateUnlocked and not FActive and not FValidating then
begin
FValidating := True;
try
if Assigned(FOnUpdateSettings) then
FOnUpdateSettings(Self);
// limit copies and Scale
FCopies := MinMax(FCopies, cCopiesMin, cCopiesMax);
FScale := MinMax(FScale, cScaleMin, cScaleMax);
// get metrics for the desktop
DC := GetDC(0);
try
FDesktopPixelsPerInchX := GetDeviceCaps(DC, LOGPIXELSX);
FDesktopPixelsPerInchY := GetDeviceCaps(DC, LOGPIXELSY);
finally
ReleaseDC(0, DC);
end;
// Printer.Refresh;
// default printer metrics if no printer is installed
FOrientation := poPortrait;
FPrinterPageWidth := 2360;
FPrinterPageHeight := 3400;
FPrinterPixelsPerInchX := 300;
FPrinterPixelsPerInchY := 300;
// get printer data
try
if IsDefaultPrinter then
begin
I := Printer.Printers.IndexOf(FPrinterName);
if I >= 0 then
Printer.PrinterIndex := I;
// set orientation in case somebody assigned it programmatically
try
Printer.Orientation := FOrientation;
except
FOrientation := Printer.Orientation;
end;
// get metrics for the printer
if Printer.Printers.Count > 0 then
begin
FPrinterPageWidth := Printer.PageWidth;
FPrinterPageHeight := Printer.PageHeight;
{$IFDEF FPC}
FPrinterPixelsPerInchX := Printer.XDPI;
FPrinterPixelsPerInchY := Printer.YDPI;
{$ELSE}
FPrinterPixelsPerInchX := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
FPrinterPixelsPerInchY := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
{$ENDIF}
end
end;
except
// silent, keep default or successfully obtained data
end;
// decide how to outline extent
if FPrintingMapped then
begin
PixelsPerInchX := FDesktopPixelsPerInchX;
PixelsPerInchY := FDesktopPixelsPerInchY;
end else
begin
PixelsPerInchX := FPrinterPixelsPerInchX;
PixelsPerInchY := FPrinterPixelsPerInchY;
end;
FMappedPageHeight := MulDiv(FPrinterPageHeight, PixelsPerInchX, FPrinterPixelsPerInchX);
FMappedPageWidth := MulDiv(FPrinterPageWidth, PixelsPerInchX, FPrinterPixelsPerInchX);
// limit and convert margins
D := FPrinterPageWidth * 0.4; // 40% of the page
FPrinterMarginLeft := Round(MinMax(ValueToInches(FUnits, FUnitMarginLeft) * FPrinterPixelsPerInchX, 0, D));
FUnitMarginLeft := InchesToValue(FUnits, FPrinterMarginLeft / FPrinterPixelsPerInchX);
FMappedMarginLeft := MulDiv(FPrinterMarginLeft, PixelsPerInchX, FPrinterPixelsPerInchX);
FPrinterMarginLeftMirrored := FPrinterMarginLeft;
FMappedMarginLeftMirrored := FMappedMarginLeft;
FPrinterMarginRight := Round(MinMax(ValueToInches(FUnits, FUnitMarginRight) * FPrinterPixelsPerInchX, 0, D));
FUnitMarginRight := InchesToValue(FUnits, FPrinterMarginRight / FPrinterPixelsPerInchX);
FMappedMarginRight := MulDiv(FPrinterMarginRight, PixelsPerInchX, FPrinterPixelsPerInchX);
FPrinterMarginRightMirrored := FPrinterMarginRight;
FMappedMarginRightMirrored := FMappedMarginRight;
D := FPrinterPageHeight * 0.4; // 40% of the page
FPrinterMarginTop := Round(MinMax(ValueToInches(FUnits, FUnitMarginTop) * FPrinterPixelsPerInchY, 0, D));
FUnitMarginTop := InchesToValue(FUnits, FPrinterMarginTop / FPrinterPixelsPerInchY);
FMappedMarginTop := MulDiv(FPrinterMarginTop, PixelsPerInchX, FPrinterPixelsPerInchX);
FPrinterMarginBottom := Round(MinMax(ValueToInches(FUnits, FUnitMarginBottom) * FPrinterPixelsPerInchY, 0, D));
FUnitMarginBottom := InchesToValue(FUnits, FPrinterMarginBottom / FPrinterPixelsPerInchY);
FMappedMarginBottom := MulDiv(FPrinterMarginBottom, PixelsPerInchX, FPrinterPixelsPerInchX);
// limit and convert header and footer space
FPrinterHeaderSpace := Round(MinMax(ValueToInches(FUnits, Max(FUnitHeaderSpace, 0)) * FPrinterPixelsPerInchY, 0, D - FPrinterMarginTop));
FUnitHeaderSpace := InchesToValue(FUnits, FPrinterHeaderSpace / FPrinterPixelsPerInchY);
FMappedHeaderSpace := MulDiv(FPrinterHeaderSpace, PixelsPerInchX, FPrinterPixelsPerInchX);
FPrinterFooterSpace := Round(MinMax(ValueToInches(FUnits, Max(FUnitFooterSpace, 0)) * FPrinterPixelsPerInchY, 0, D - FPrinterMarginBottom));
FUnitFooterSpace := InchesToValue(FUnits, FPrinterFooterSpace / FPrinterPixelsPerInchY);
FMappedFooterSpace := MulDiv(FPrinterFooterSpace, PixelsPerInchX, FPrinterPixelsPerInchX);
// limit and convert extra space
FPrinterExtraSpaceLeft := Round(ValueToInches(FUnits, Max(FUnitExtraSpaceLeft, 0)) * FPrinterPixelsPerInchX);
FUnitExtraSpaceLeft := InchesToValue(FUnits, FPrinterExtraSpaceLeft / FPrinterPixelsPerInchX);
FMappedExtraSpaceLeft := MulDiv(FPrinterExtraSpaceLeft, PixelsPerInchX, FPrinterPixelsPerInchX);
FPrinterExtraSpaceRight := Round(ValueToInches(FUnits, Max(FUnitExtraSpaceRight, 0)) * FPrinterPixelsPerInchX);
FUnitExtraSpaceRight := InchesToValue(FUnits, FPrinterExtraSpaceRight / FPrinterPixelsPerInchX);
FMappedExtraSpaceRight := MulDiv(FPrinterExtraSpaceRight, PixelsPerInchX, FPrinterPixelsPerInchX);
// paint area extent
FPrinterPaintAreaHeight := FPrinterPageHeight - FPrinterMarginTop - FPrinterMarginBottom - FPrinterHeaderSpace - FPrinterFooterSpace;
FUnitPaintAreaHeight := InchesToValue(FUnits, FPrinterPaintAreaHeight / FPrinterPixelsPerInchY);
FMappedPaintAreaHeight := MulDiv(FPrinterPaintAreaHeight, PixelsPerInchY, FPrinterPixelsPerInchY);
FPrinterPaintAreaWidth := FPrinterPageWidth - FPrinterMarginLeft - FPrinterMarginRight;
FUnitPaintAreaWidth := InchesToValue(FUnits, FPrinterPaintAreaWidth / FPrinterPixelsPerInchX);
FMappedPaintAreaWidth := MulDiv(FPrinterPaintAreaWidth, PixelsPerInchX, FPrinterPixelsPerInchX);
// control paint area extent
FPrinterControlPaintAreaWidth := FPrinterPaintAreaWidth;
if poFitToPage in FOptions then
Dec(FPrinterControlPaintAreaWidth, FPrinterExtraSpaceLeft + FPrinterExtraSpaceRight);
FUnitControlPaintAreaWidth := InchesToValue(FUnits, FPrinterControlPaintAreaWidth / FPrinterPixelsPerInchX);
FMappedControlPaintAreaWidth := MulDiv(FPrinterControlPaintAreaWidth, PixelsPerInchX, FPrinterPixelsPerInchX);
// default horizontal scaling
FCurrentScale := FScale / 100;
// default page/copy info
FCurrentCopy := 0;
FCurrentPage := 0;
// measured data
if Assigned(FControl) then
begin
FillChar(Info, SizeOf(TKPrintMeasureInfo), 0);
FControl.MeasurePages(Info);
if Assigned(FOnPrintMeasure) then
FOnPrintMeasure(Self, Info);
FMappedOutlineWidth := Info.OutlineWidth;
FMappedOutlineHeight := Info.OutlineHeight;
FExtraLeftHorzPageCount := Info.ExtraLeftHorzPageCount;
FExtraLeftVertPageCount := Info.ExtraLeftVertPageCount;
FExtraLeftPageCount := FExtraLeftHorzPageCount * FExtraLeftVertPageCount;
FExtraRightHorzPageCount := Info.ExtraRightHorzPageCount;
FExtraRightVertPageCount := Info.ExtraRightVertPageCount;
FExtraRightPageCount := FExtraRightHorzPageCount * FExtraRightVertPageCount;
FControlHorzPageCount := Info.ControlHorzPageCount;
FControlVertPageCount := Info.ControlVertPageCount;
FControlPageCount := FControlHorzPageCount * FControlVertPageCount;
FPageCount := FExtraLeftPageCount + FControlPageCount + FExtraRightPageCount;
if FPageCount > 0 then
begin
// update horizontal scaling
if (poFitToPage in FOptions) and (FMappedOutlineWidth > 0) then
FCurrentScale := FMappedControlPaintAreaWidth / FMappedOutlineWidth;
// limit start and end page
case FRange of
prAll, prSelectedOnly:
begin
FStartPage := 1;
FEndPage := FPageCount;
end;
prRange:
begin
FEndPage := MinMax(FEndPage, 1, FPageCount);
FStartPage := MinMax(FStartPage, 1, FEndPage);
end;
end;
end;
// notify all previews/ force their repainting
FControl.NotifyPreviews;
end else
begin
FMappedOutlineWidth := 0;
FMappedOutlineHeight := 0;
FExtraLeftHorzPageCount := 0;
FExtraLeftVertPageCount := 0;
FExtraRightHorzPageCount := 0;
FExtraRightVertPageCount := 0;
FControlHorzPageCount := 0;
FControlVertPageCount := 0;
FPageCount := 0;
FEndPage := 0;
FStartPage := 0;
end;
FIsValid := True;
finally
FValidating := False;
end;
end;
end;
procedure TKPrintPageSetup.Validate;
begin
if not FIsValid and not FValidating then
UpdateSettings;
end;
function TKPrintPageSetup.VMap(Value: Integer): Integer;
begin
Result := MulDiv(Value, FPrinterPixelsPerInchY, FDesktopPixelsPerInchY);
end;
{ TKPreviewColors }
function TKPreviewColors.GetColorSpec(Index: TKColorIndex): TKColorSpec;
begin
case Index of
ciPaper: begin Result.Def := cPaperDef; Result.Name := ''; end;
ciBkGnd: begin Result.Def := cBkGndDef; Result.Name := ''; end;
ciBorder: begin Result.Def := cBorderDef; Result.Name := ''; end;
ciSelectedBorder: begin Result.Def := cSelectedBorderDef; Result.Name := ''; end;
else
Result := inherited GetColorSpec(Index);
end;
end;
function TKPreviewColors.GetMaxIndex: Integer;
begin
Result := ciPreviewColorsMax;
end;
{ TKPrintPreview }
constructor TKPrintPreview.Create(AOwner: TComponent);
begin
inherited;
FColors := TKPreviewColors.Create(Self);
FControl := nil;
FCurrentCanvas := Canvas;
FMouseWheelAccumulator := 0;
FPage := 1;
FPageSize := CreateEmptyPoint;
FPixelsPerInchX := cDPIDef;
FPixelsPerInchY := cDPIDef;
FScale := 100;
FScaleMode := smPageWidth;
FOnChanged := nil;
LoadCustomCursor(crDragHandFree, 'KPREVIEW_CURSOR_HAND_FREE');
LoadCustomCursor(crDragHandGrip, 'KPREVIEW_CURSOR_HAND_GRIP');
Width := 300;
Height := 200;
end;
destructor TKPrintPreview.Destroy;
begin
if Assigned(FControl) then
FControl.RemovePreview(Self);
inherited;
FColors.Free;
end;
procedure TKPrintPreview.BeginScrollWindow;
begin
FPageOld := FPage;
FScrollPosOld := FScrollPos;
end;
procedure TKPrintPreview.CreateParams(var Params: TCreateParams);
begin
inherited;
with Params do
Style := Style or WS_HSCROLL or WS_VSCROLL;
end;
function TKPrintPreview.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer;
MousePos: TPoint): Boolean;
const
cWheelDivisor = 120;
var
Delta, WheelClicks: Integer;
begin
Result := inherited DoMouseWheel(Shift, WheelDelta, MousePos);
if not Result then
begin
if ssCtrl in Shift then
begin
if FScaleMode = smWholePage then Delta := 10 else Delta := ClientHeight;
end else
if FScaleMode = smWholePage then Delta := 1 else Delta := ClientHeight div 10;
Inc(FMouseWheelAccumulator, WheelDelta);
WheelClicks := FMouseWheelAccumulator div cWheelDivisor;
FMouseWheelAccumulator := FMouseWheelAccumulator mod cWheelDivisor;
BeginScrollWindow;
ModifyScrollBar(SB_VERT, cScrollDelta, -WheelClicks * Delta);
EndScrollWindow;
Result := True;
end;
end;
procedure TKPrintPreview.EndScrollWindow;
begin
if (FPage <> FPageOld) then
Invalidate
else if (FScrollPos.X <> FScrollPosOld.X) or (FScrollPos.Y <> FScrollPosOld.Y) then
begin
ScrollWindowEx(Handle, FScrollPosOld.X - FScrollPos.X, FScrollPosOld.Y - FScrollPos.Y,
nil, nil, 0, nil, SW_INVALIDATE);
end;
end;
procedure TKPrintPreview.FirstPage;
begin
Page := StartPage;
end;
function TKPrintPreview.GetCurrentScale: Integer;
begin
if Assigned(FControl) then
Result := MulDiv(FPageSize.X, 100, MulDiv(FControl.PageSetup.PrinterPageWidth, 300, FControl.PageSetup.PrinterPixelsPerInchX))
else
Result := FScale;
end;
function TKPrintPreview.GetEndPage: Integer;
begin
if Assigned(FControl) then
begin
Result := FControl.PageSetup.EndPage;
if Result = 0 then
begin
FControl.PageSetup.UpdateSettings;
Result := FControl.PageSetup.EndPage
end;
end else
Result := 0;
end;
function TKPrintPreview.GetPageRect: TRect;
begin
with Result do
begin
Left := FPageOffset.X - FScrollPos.X;
if FScaleMode = smWholePage then
Top := FPageOffset.Y
else
Top := FPageOffset.Y - FScrollPos.Y;
Right := Left + FPageSize.X;
Bottom := Top + FPageSize.Y;
end;
end;
function TKPrintPreview.GetStartPage: Integer;
begin
if Assigned(FControl) then
begin
Result := FControl.PageSetup.StartPage;
if Result = 0 then
begin
FControl.PageSetup.UpdateSettings;
Result := FControl.PageSetup.StartPage
end;
end else
Result := 0;
end;
procedure TKPrintPreview.KeyDown(var Key: Word; Shift: TShiftState);
var
DeltaX, DeltaY, LineX, PageY: Integer;
NoAlt, NoAltCtrl: Boolean;
begin
NoAlt := Shift * [ssAlt] = [];
NoAltCtrl := Shift * [ssAlt, ssCtrl] = [];
DeltaX := 0;
DeltaY := 0;
LineX := ClientWidth div 10;
PageY := ClientHeight;
case Key of
VK_UP:
if NoAltCtrl then
begin
if FScaleMode = smWholePage then
PreviousPage
else
DeltaY := -PageY div 10;
end;
VK_DOWN:
if NoAltCtrl then
begin
if FScaleMode = smWholePage then
NextPage
else
DeltaY := PageY div 10;
end;
VK_PRIOR:
if NoAltCtrl then
begin
if FScaleMode = smWholePage then
PreviousPage
else
DeltaY := -PageY;
end;
VK_NEXT:
if NoAltCtrl then
begin
if FScaleMode = smWholePage then
NextPage
else
DeltaY := PageY;
end;
VK_LEFT: if NoAltCtrl then DeltaX := -LineX;
VK_RIGHT: if NoAltCtrl then DeltaX := LineX;
VK_HOME:
if NoAlt then
begin
if ssCtrl in Shift then
FirstPage
else
DeltaX := -FScrollPos.X;
end;
VK_END:
if NoAlt then
begin
if ssCtrl in Shift then
LastPage
else
DeltaX := FScrollExtent.X - FScrollPos.X;
end;
end;
if (DeltaX <> 0) or (DeltaY <> 0) then
begin
BeginScrollWindow;
if DeltaX <> 0 then
ModifyScrollBar(SB_HORZ, cScrollDelta, DeltaX);
if DeltaY <> 0 then
ModifyScrollBar(SB_VERT, cScrollDelta, DeltaY);
EndScrollWindow;
end;
end;
procedure TKPrintPreview.LastPage;
begin
Page := EndPage;
end;
procedure TKPrintPreview.ModifyScrollBar(ScrollBar, ScrollCode, Delta: Integer);
var
I, AEndPage: Integer;
Divisor: Cardinal;
PPos, PExtent: PInteger;
SI: TScrollInfo;
begin
Divisor := 10;
if ScrollBar = SB_HORZ then
begin
PPos := @FScrollPos.X;
PExtent := @FScrollExtent.X;
end else
begin
if FScaleMode = smWholePage then
begin
PPos := @FPage;
AEndPage := EndPage;
PExtent := @AEndPage;
Divisor := 1;
end else
begin
PPos := @FScrollPos.Y;
PExtent := @FScrollExtent.Y;
end;
end;
if PExtent^ > 0 then
begin
SI.cbSize := SizeOf(TScrollInfo);
SI.fMask := SIF_RANGE or SIF_PAGE or SIF_TRACKPOS;
GetScrollInfo(Handle, ScrollBar, SI);
{$IFDEF UNIX}
SI.nTrackPos := Delta;
{$ENDIF}
I := PPos^;
case ScrollCode of
SB_TOP: I := SI.nMin;
SB_BOTTOM: I := SI.nMax; // will be trimmed below
SB_LINEUP: Dec(I, SI.nPage div Divisor);
SB_LINEDOWN: Inc(I, SI.nPage div Divisor);
SB_PAGEUP: Dec(I, SI.nPage);
SB_PAGEDOWN: Inc(I, SI.nPage);
SB_THUMBTRACK, SB_THUMBPOSITION: I := SI.nTrackPos;
cScrollDelta: Inc(I, Delta);
end;
if FScaleMode = smWholePage then
I := MinMax(I, 1, PExtent^)
else
I := MinMax(I, 0, PExtent^);
PPos^ := I;
SI.nPos := I;
SI.fMask := SIF_POS;
SetScrollInfo(Handle, ScrollBar, SI, True);
end;
end;
procedure TKPrintPreview.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
inherited;
if ssLeft in Shift then
begin
SafeSetFocus;
if (FScaleMode <> smWholePage) and PtInRect(GetPageRect, Point(X, Y)) then
begin
FlagSet(cPF_Dragging);
FX := X;
FY := Y;
SetMouseCursor(X, Y);
end;
end;
end;
procedure TKPrintPreview.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
inherited;
if Flag(cPF_Dragging) and MouseCapture then
begin
BeginScrollWindow;
if (X > FX) and (FScrollPos.X > 0) or (X < FX) and (FScrollPos.X < FScrollExtent.X) then
begin
ModifyScrollBar(SB_HORZ, cScrollDelta, FX - X);
FX := X;
end;
if (Y > FY) and (FScrollPos.Y > 0) or (Y < FY) and (FScrollPos.Y < FScrollExtent.Y) then
begin
ModifyScrollBar(SB_VERT, cScrollDelta, FY - Y);
FY := Y;
end;
EndScrollWindow;
end;
end;
procedure TKPrintPreview.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
inherited;
FlagClear(cPF_Dragging);
SetMouseCursor(X, Y);
end;
procedure TKPrintPreview.NextPage;
begin
Page := Page + 1;
end;
procedure TKPrintPreview.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = FControl) then
begin
FControl := nil;
UpdatePreview;
end;
end;
procedure TKPrintPreview.PaintToCanvas(ACanvas: TCanvas);
procedure DoPaint(IsBuffer: Boolean);
var
C: TColor;
R, RPaper, RPage: TRect;
RgnPaper: HRGN;
begin
ACanvas.Brush.Style := bsSolid;
ACanvas.Pen.Mode := pmCopy;
ACanvas.Pen.Style := psSolid;
ACanvas.Pen.Width := 1;
RPage := GetPageRect;
RPaper := RPage;
with RPaper do
begin
Inc(Right, cPreviewShadowSize);
Inc(Bottom, cPreviewShadowSize);
end;
if not IsBuffer then
RgnPaper := CreateRectRgnIndirect(RPaper)
else
RgnPaper := 0;
try
// paint background around paper, we don't want at least this to flicker
if IsBuffer or (ExtSelectClipRgn(ACanvas.Handle, RgnPaper, RGN_DIFF) <> NULLREGION) then
begin
ACanvas.Brush.Color := FColors.BkGnd;
ACanvas.FillRect(ClientRect);
end;
if not IsBuffer then
SelectClipRgn(ACanvas.Handle, RgnPaper);
finally
if not IsBuffer then
DeleteObject(rgnPaper);
end;
// paint paper outline
if Focused then
C := FColors.SelectedBorder
else
C := FColors.Border;
ACanvas.Pen.Color := C;
ACanvas.Brush.Color := FColors.Paper;
ACanvas.Rectangle(RPage);
ACanvas.Brush.Color := FColors.BkGnd;
R := Rect(RPage.Left, RPage.Bottom, RPage.Left + cPreviewShadowSize, RPage.Bottom + cPreviewShadowSize);
ACanvas.FillRect(R);
R := Rect(RPage.Right, RPage.Top, RPage.Right + cPreviewShadowSize, RPage.Top + cPreviewShadowSize);
ACanvas.FillRect(R);
ACanvas.Brush.Color := C;
R := Rect(RPage.Left + cPreviewShadowSize, RPage.Bottom, RPaper.Right, RPaper.Bottom);
ACanvas.FillRect(R);
R := Rect(RPage.Right, RPage.Top + cPreviewShadowSize, RPaper.Right, RPaper.Bottom);
ACanvas.FillRect(R);
// paint page outline
InflateRect(RPage, -1, -1);
FControl.PageSetup.PaintPageToPreview(Self);
end;
var
SaveIndex: Integer;
RClient: TRect;
{$IFDEF MSWINDOWS}
Org: TPoint;
MemBitmap, OldBitmap: HBITMAP;
DC: HDC;
{$ENDIF}
begin
RClient := ClientRect;
if Assigned(FControl) then
begin
SaveIndex := SaveDC(ACanvas.Handle);
try
{$IFDEF MSWINDOWS}
if DoubleBuffered then
begin
// we must paint always the entire client because of canvas scaling
MemBitmap := CreateCompatibleBitmap(ACanvas.Handle, RClient.Right - RClient.Left, RClient.Bottom - RClient.Top);
try
OldBitmap := SelectObject(ACanvas.Handle, MemBitmap);
try
SetWindowOrgEx(ACanvas.Handle, 0, 0, @Org);
SelectClipRect(ACanvas.Handle, Rect(0, 0, RClient.Right - RClient.Left, RClient.Bottom - RClient.Top));
DoPaint(True);
finally
SelectObject(ACanvas.Handle, OldBitmap);
SetWindowOrgEx(ACanvas.Handle, Org.X, Org.Y, nil);
end;
// copy MemBitmap to original canvas
DC := CreateCompatibleDC(ACanvas.Handle);
try
OldBitmap := SelectObject(DC, MemBitmap);
try
CopyBitmap(ACanvas.Handle, RClient, DC, 0, 0);
finally
SelectObject(DC, OldBitmap);
end;
finally
DeleteDC(DC);
end;
finally
DeleteObject(MemBitmap);
end;
end else
{$ENDIF}
DoPaint(False);
finally
RestoreDC(ACanvas.Handle, SaveIndex);
end;
end else
begin
ACanvas.Brush.Color := FColors.BkGnd;
ACanvas.FillRect(RClient);
end;
end;
procedure TKPrintPreview.Paint;
begin
PaintToCanvas(Canvas);
end;
procedure TKPrintPreview.PaintTo(ACanvas: TCanvas);
var
OldOffset, OldScrollPos: TPoint;
begin
// will paint the page on given canvas
FCurrentCanvas := ACanvas;
OldOffset := FPageOffset;
OldScrollPos := FScrollPos;
try
FPageOffset := Point(0, 0); // don't paint left and top space around paper
FScrollPos := Point(0, 0);
PaintToCanvas(ACanvas);
finally
FPageOffset := OldOffset;
FScrollPos := OldScrollPos;
FCurrentCanvas := Canvas;
end;
end;
procedure TKPrintPreview.Changed;
begin
if Assigned(FOnChanged) then
FOnChanged(Self);
end;
procedure TKPrintPreview.PreviousPage;
begin
Page := Page - 1;
end;
procedure TKPrintPreview.SafeSetFocus;
var
Form: TCustomForm;
begin
Form := GetParentForm(Self);
if (Form <> nil) and Form.Visible and Form.Enabled and Visible and Enabled then
Form.ActiveControl := Self;
end;
procedure TKPrintPreview.SetColors(const Value: TKPreviewColors);
begin
FColors.Assign(Value);
end;
procedure TKPrintPreview.SetControl(Value: TKCustomControl);
begin
if (Value <> FControl) and (Value <> Self) and not (Value is TKPrintPreview) then
begin
if Assigned(FControl) then
FControl.RemovePreview(Self);
FControl := Value;
if Assigned(FControl) then
FControl.AddPreview(Self);
UpdatePreview;
end;
end;
procedure TKPrintPreview.SetPage(Value: Integer);
begin
Value := MinMax(Value, StartPage, EndPage);
if Value <> FPage then
begin
BeginScrollWindow;
if FScaleMode = smWholePage then
ModifyScrollBar(SB_VERT, cScrollDelta, Value - FPage)
else
FPage := Value;
EndScrollWindow;
Changed;
end;
end;
procedure TKPrintPreview.SetPixelsPerInchX(Value: Integer);
begin
Value := MinMax(Value, cDPIMin, cDPIMax);
if Value <> FPixelsPerInchX then
begin
FPixelsPerInchX := Value;
UpdatePreview;
end;
end;
procedure TKPrintPreview.SetPixelsPerInchY(Value: Integer);
begin
Value := MinMax(Value, cDPIMin, cDPIMax);
if Value <> FPixelsPerInchY then
begin
FPixelsPerInchY := Value;
UpdatePreview;
end;
end;
procedure TKPrintPreview.SetScale(Value: Integer);
begin
Value := MinMax(Value, cScaleMin, cScaleMax);
if Value <> FScale then
begin
FScale := Value;
UpdatePreview;
end;
end;
procedure TKPrintPreview.SetScaleMode(Value: TKPreviewScaleMode);
begin
if Value <> FScaleMode then
begin
FScaleMode := Value;
UpdatePreview;
end;
end;
function TKPrintPreview.SetMouseCursor(X, Y: Integer): Boolean;
var
ACursor: TCursor;
begin
if PtInRect(GetPageRect, Point(X, Y)) and (FScaleMode <> smWholePage) then
begin
if MouseCapture then
ACursor := crDragHandGrip
else
ACursor := crDragHandFree;
end else
ACursor := crDefault;
{$IFDEF FPC}
FCursor := ACursor;
SetTempCursor(ACursor);
{$ELSE}
Windows.SetCursor(Screen.Cursors[ACursor]);
{$ENDIF}
Result := True;
end;
procedure TKPrintPreview.UpdatePreview;
begin
Page := FPage;
UpdateScrollRange;
Changed;
end;
procedure TKPrintPreview.UpdateScrollRange;
var
I: Integer;
PageWidth100Percent, PageHeight100Percent: Integer;
SI: TScrollInfo;
begin
if HandleAllocated and not Flag(cPF_UpdateRange) then
begin
FlagSet(cPF_UpdateRange);
try
if Assigned(FControl) then
begin
PageWidth100Percent := MulDiv(FControl.PageSetup.PrinterPageWidth, FPixelsPerInchX, FControl.PageSetup.PrinterPixelsPerInchX);
PageHeight100Percent := MulDiv(FControl.PageSetup.PrinterPageHeight, FPixelsPerInchY, FControl.PageSetup.PrinterPixelsPerInchY);
case FScaleMode of
smScale:
begin
FPageSize.X := MulDiv(PageWidth100Percent, FScale, 100);
FPageSize.Y := MulDiv(PageHeight100Percent, FScale, 100);
end;
smPageWidth:
begin
FPageSize.X := Max(ClientWidth - 2 * cPreviewHorzBorder - cPreviewShadowSize, 40);
FPageSize.Y := MulDiv(FPageSize.X, PageHeight100Percent, PageWidth100Percent);
end;
smWholePage:
begin
FPageSize.X := Max(ClientWidth - 2 * cPreviewHorzBorder - cPreviewShadowSize, 40);
FPageSize.Y := Max(ClientHeight - 2 * cPreviewVertBorder - cPreviewShadowSize, 40);
I := MulDiv(FPageSize.Y, PageWidth100Percent, PageHeight100Percent);
if I < FPageSize.X then
FPageSize.X := I
else
FPageSize.Y := MulDiv(FPageSize.X, PageHeight100Percent, PageWidth100Percent);
end;
end;
FExtent.X := FPageSize.X + 2 * cPreviewHorzBorder + cPreviewShadowSize;
FExtent.Y := FPageSize.Y + 2 * cPreviewVertBorder + cPreviewShadowSize;
FPageOffset.X := cPreviewHorzBorder;
if (FExtent.X < ClientWidth) then
Inc(FPageOffset.X, (ClientWidth - FExtent.X) div 2);
FPageOffset.Y := cPreviewVertBorder;
if (FExtent.Y < ClientHeight) then
Inc(FPageOffset.Y, (ClientHeight - FExtent.Y) div 2);
// adjust horizontal scroll position
I := FScrollPos.X + ClientWidth - FExtent.X - 1;
if I > 0 then
Dec(FScrollPos.X, I);
FScrollPos.X := Max(FScrollPos.X, 0);
// adjust vertical scroll position
I := FScrollPos.Y + ClientHeight - FExtent.Y - 1;
if I > 0 then
Dec(FScrollPos.Y, I);
FScrollPos.Y := Max(FScrollPos.Y, 0);
// update scroll range
FScrollExtent.X := 0;
FScrollExtent.Y := 0;
FillChar(SI, SizeOf(TScrollInfo), 0);
SI.cbSize := SizeOf(TScrollInfo);
SI.fMask := SIF_RANGE or SIF_PAGE or SIF_POS or SIF_DISABLENOSCROLL {$IFDEF UNIX}or SIF_UPDATEPOLICY{$ENDIF};
SI.nMin := 0;
{$IFDEF UNIX}
SI.ntrackPos := SB_POLICY_CONTINUOUS;
{$ENDIF}
case FScaleMode of
smScale:
begin
ShowScrollbar(Handle, SB_HORZ, True);
ShowScrollbar(Handle, SB_VERT, True);
SI.nMax := FExtent.X{$IFDEF FPC}+ 1{$ENDIF};
SI.nPage := ClientWidth;
SI.nPos := FScrollPos.X;
FScrollExtent.X := SI.nMax - Integer(SI.nPage);
SetScrollInfo(Handle, SB_HORZ, SI, True);
SI.nMax := FExtent.Y{$IFDEF FPC}+ 1{$ENDIF};
SI.nPage := ClientHeight;
SI.nPos := FScrollPos.Y;
FScrollExtent.Y := SI.nMax - Integer(SI.nPage);
SetScrollInfo(Handle, SB_VERT, SI, True);
end;
smPageWidth:
begin
ShowScrollbar(Handle, SB_HORZ, False);
ShowScrollbar(Handle, SB_VERT, True);
SI.nMax := FExtent.Y{$IFDEF FPC}+ 1{$ENDIF};
SI.nPage := ClientHeight;
SI.nPos := FScrollPos.Y;
FScrollExtent.Y := SI.nMax - Integer(SI.nPage);
SetScrollInfo(Handle, SB_VERT, SI, True);
end;
smWholePage:
begin
// another mode for vertical scrollbar - page selection
ShowScrollbar(Handle, SB_HORZ, False);
ShowScrollbar(Handle, SB_VERT, True);
SI.nMin := StartPage;
SI.nMax := EndPage{$IFDEF FPC}+ 1{$ENDIF};
SI.nPage := 1;
SI.nPos := FPage;
SetScrollInfo(Handle, SB_VERT, SI, True);
end;
end;
end else
begin
ShowScrollbar(Handle, SB_HORZ, False);
ShowScrollbar(Handle, SB_VERT, False);
end;
Invalidate;
finally
FlagClear(cPF_UpdateRange);
end;
end;
end;
procedure TKPrintPreview.UpdateSize;
begin
inherited;
UpdatePreview;
end;
procedure TKPrintPreview.WMEraseBkgnd(var Msg: TLMessage);
begin
Msg.Result := 1;
end;
procedure TKPrintPreview.WMGetDlgCode(var Msg: TLMNoParams);
begin
Msg.Result := DLGC_WANTARROWS;
end;
procedure TKPrintPreview.WMHScroll(var Msg: TLMHScroll);
begin
SafeSetFocus;
BeginScrollWindow;
ModifyScrollBar(SB_HORZ, Msg.ScrollCode, Msg.Pos);
EndScrollWindow;
end;
procedure TKPrintPreview.WMKillFocus(var Msg: TLMKillFocus);
begin
inherited;
Invalidate;
end;
procedure TKPrintPreview.WMSetFocus(var Msg: TLMSetFocus);
begin
inherited;
Invalidate;
end;
procedure TKPrintPreview.WMVScroll(var Msg: TLMVScroll);
begin
SafeSetFocus;
BeginScrollWindow;
ModifyScrollBar(SB_VERT, Msg.ScrollCode, Msg.Pos);
EndScrollWindow;
end;
{$IFDEF FPC}
initialization
{$i kcontrols.lrs}
{$ELSE}
{$R kcontrols.res}
{$ENDIF}
end.
tomboy-ng_0.34-1/kcontrols/source/kcontrols.inc 0000644 0001750 0001750 00000017400 14125207534 021447 0 ustar dbannon dbannon { @abstract(This file is part of the KControls component suite for Delphi and Lazarus.)
@author(Tomas Krysl)
Copyright (c) 2020 Tomas Krysl
License:
This code is licensed under BSD 3-Clause Clear License, see file License.txt or https://spdx.org/licenses/BSD-3-Clause-Clear.html.
}
{$IFNDEF KCONTROLS_INC}
{$DEFINE KCONTROLS_INC}
{ Default compiler directives for entire KControls Development Suite }
{$IFDEF FPC}
{$MODE DELPHI}
{$B-,H+,J+,Q-,R-,T-,X+}
{$ELSE}
{$B-,H+,J+,Q-,R-,T-,X+}
{$ENDIF}
{ Specifies if native operating system theme support should be used (Themes.pas is needed) }
{$DEFINE USE_THEMES}
{ COMPILERx, DELPHIx and BCBx directives from VERx }
{$IFDEF VER320}
{$DEFINE COMPILER25}
{$IFDEF BCB}
{$DEFINE BCB10C}
{$ELSE}
{$DEFINE DELPHI10C}
{$ENDIF}
{$ENDIF}
{$IFDEF VER310}
{$DEFINE COMPILER24}
{$IFDEF BCB}
{$DEFINE BCB10B}
{$ELSE}
{$DEFINE DELPHI10B}
{$ENDIF}
{$ENDIF}
{$IFDEF VER300}
{$DEFINE COMPILER23}
{$IFDEF BCB}
{$DEFINE BCB10S}
{$ELSE}
{$DEFINE DELPHI10S}
{$ENDIF}
{$ENDIF}
{$IFDEF VER290}
{$DEFINE COMPILER22}
{$IFDEF BCB}
{$DEFINE BCBXE8}
{$ELSE}
{$DEFINE DELPHIXE8}
{$ENDIF}
{$ENDIF}
{$IFDEF VER280}
{$DEFINE COMPILER21}
{$IFDEF BCB}
{$DEFINE BCBXE7}
{$ELSE}
{$DEFINE DELPHIXE7}
{$ENDIF}
{$ENDIF}
{$IFDEF VER270}
{$DEFINE COMPILER20}
{$IFDEF BCB}
{$DEFINE BCBXE6}
{$ELSE}
{$DEFINE DELPHIXE6}
{$ENDIF}
{$ENDIF}
{$IFDEF VER260}
{$DEFINE COMPILER19}
{$IFDEF BCB}
{$DEFINE BCBXE5}
{$ELSE}
{$DEFINE DELPHIXE5}
{$ENDIF}
{$ENDIF}
{$IFDEF VER250}
{$DEFINE COMPILER18}
{$IFDEF BCB}
{$DEFINE BCBXE4}
{$ELSE}
{$DEFINE DELPHIXE4}
{$ENDIF}
{$ENDIF}
{$IFDEF VER240}
{$DEFINE COMPILER17}
{$IFDEF BCB}
{$DEFINE BCBXE3}
{$ELSE}
{$DEFINE DELPHIXE3}
{$ENDIF}
{$ENDIF}
{$IFDEF VER230}
{$DEFINE COMPILER16}
{$IFDEF BCB}
{$DEFINE BCBXE2}
{$ELSE}
{$DEFINE DELPHIXE2}
{$ENDIF}
{$ENDIF}
{$IFDEF VER220}
{$DEFINE COMPILER15}
{$IFDEF BCB}
{$DEFINE BCBXE}
{$ELSE}
{$DEFINE DELPHIXE}
{$ENDIF}
{$ENDIF}
{$IFDEF VER210}
{$DEFINE COMPILER14}
{$IFDEF BCB}
{$DEFINE BCB2010}
{$ELSE}
{$DEFINE DELPHI2010}
{$ENDIF}
{$ENDIF}
{$IFDEF VER200}
{$DEFINE COMPILER12}
{$IFDEF BCB}
{$DEFINE BCB2009}
{$ELSE}
{$DEFINE DELPHI2009}
{$ENDIF}
{$ENDIF}
{$IFDEF VER180}
{$IFDEF VER185}
{$DEFINE COMPILER11}
{$IFDEF BCB}
{$DEFINE BCB2007}
{$ELSE}
{$DEFINE DELPHI2007}
{$ENDIF}
{$ELSE}
{$DEFINE COMPILER10}
{$IFDEF BCB}
{$DEFINE BCB2006}
{$ELSE}
{$DEFINE DELPHI2006}
{$ENDIF}
{$ENDIF}
{$ENDIF}
{$IFDEF VER170}
{$DEFINE COMPILER9}
{$DEFINE DELPHI2005}
{$ENDIF}
{$IFDEF VER160}
{$DEFINE COMPILER8}
{$DEFINE DELPHI8}
{$ENDIF}
{$IFDEF VER150}
{$DEFINE COMPILER7}
{$DEFINE DELPHI7}
{$ENDIF}
{$IFDEF VER140}
{$DEFINE COMPILER6}
{$IFDEF BCB}
{$DEFINE BCB6}
{$ELSE}
{$DEFINE DELPHI6}
{$ENDIF}
{$ENDIF}
{$IFDEF VER130}
{$DEFINE COMPILER5}
{$IFDEF BCB}
{$DEFINE BCB5}
{$ELSE}
{$DEFINE DELPHI5}
{$ENDIF}
{$ENDIF}
{$IFDEF VER125}
{$DEFINE COMPILER4}
{$DEFINE BCB}
{$DEFINE BCB4}
{$ENDIF}
{$IFDEF VER120}
{$DEFINE COMPILER4}
{$DEFINE DELPHI4}
{$ENDIF}
{$IFDEF VER110}
{$DEFINE COMPILER3}
{$DEFINE BCB}
{$DEFINE BCB3}
{$ENDIF}
{$IFDEF VER100}
{$DEFINE COMPILER3}
{$DEFINE DELPHI3}
{$ENDIF}
{$IFDEF VER93}
{$DEFINE COMPILER2}
{$DEFINE BCB}
{$DEFINE BCB1}
{$ENDIF}
{$IFDEF VER90}
{$DEFINE COMPILER2}
{$DEFINE DELPHI2}
{$ENDIF}
{ What is used: DELPHI or BCB ? (BCB is defined by C++Builder 5 and later) }
{$IFNDEF BCB}
{$DEFINE DELPHI}
{$ENDIF}
{ COMPILERx_UP directives from COMPILERx }
{$IFDEF COMPILER25} {$DEFINE COMPILER25_UP} {$ENDIF}
{$IFDEF COMPILER24} {$DEFINE COMPILER24_UP} {$ENDIF}
{$IFDEF COMPILER23} {$DEFINE COMPILER23_UP} {$ENDIF}
{$IFDEF COMPILER22} {$DEFINE COMPILER22_UP} {$ENDIF}
{$IFDEF COMPILER21} {$DEFINE COMPILER21_UP} {$ENDIF}
{$IFDEF COMPILER20} {$DEFINE COMPILER20_UP} {$ENDIF}
{$IFDEF COMPILER19} {$DEFINE COMPILER19_UP} {$ENDIF}
{$IFDEF COMPILER18} {$DEFINE COMPILER18_UP} {$ENDIF}
{$IFDEF COMPILER17} {$DEFINE COMPILER17_UP} {$ENDIF}
{$IFDEF COMPILER16} {$DEFINE COMPILER16_UP} {$ENDIF}
{$IFDEF COMPILER15} {$DEFINE COMPILER15_UP} {$ENDIF}
{$IFDEF COMPILER14} {$DEFINE COMPILER14_UP} {$ENDIF}
{$IFDEF COMPILER12} {$DEFINE COMPILER12_UP} {$ENDIF}
{$IFDEF COMPILER11} {$DEFINE COMPILER11_UP} {$ENDIF}
{$IFDEF COMPILER10} {$DEFINE COMPILER10_UP} {$ENDIF}
{$IFDEF COMPILER9} {$DEFINE COMPILER9_UP} {$ENDIF}
{$IFDEF COMPILER8} {$DEFINE COMPILER8_UP} {$ENDIF}
{$IFDEF COMPILER7} {$DEFINE COMPILER7_UP} {$ENDIF}
{$IFDEF COMPILER6} {$DEFINE COMPILER6_UP} {$ENDIF}
{$IFDEF COMPILER5} {$DEFINE COMPILER5_UP} {$ENDIF}
{$IFDEF COMPILER4} {$DEFINE COMPILER4_UP} {$ENDIF}
{$IFDEF COMPILER3} {$DEFINE COMPILER3_UP} {$ENDIF}
{$IFDEF COMPILER2} {$DEFINE COMPILER2_UP} {$ENDIF}
{$IFDEF COMPILER25_UP} {$DEFINE COMPILER24_UP} {$ENDIF}
{$IFDEF COMPILER24_UP} {$DEFINE COMPILER23_UP} {$ENDIF}
{$IFDEF COMPILER23_UP} {$DEFINE COMPILER22_UP} {$ENDIF}
{$IFDEF COMPILER22_UP} {$DEFINE COMPILER21_UP} {$ENDIF}
{$IFDEF COMPILER21_UP} {$DEFINE COMPILER20_UP} {$ENDIF}
{$IFDEF COMPILER20_UP} {$DEFINE COMPILER19_UP} {$ENDIF}
{$IFDEF COMPILER19_UP} {$DEFINE COMPILER18_UP} {$ENDIF}
{$IFDEF COMPILER18_UP} {$DEFINE COMPILER17_UP} {$ENDIF}
{$IFDEF COMPILER17_UP} {$DEFINE COMPILER16_UP} {$ENDIF}
{$IFDEF COMPILER16_UP} {$DEFINE COMPILER15_UP} {$ENDIF}
{$IFDEF COMPILER15_UP} {$DEFINE COMPILER14_UP} {$ENDIF}
{$IFDEF COMPILER14_UP} {$DEFINE COMPILER12_UP} {$ENDIF}
{$IFDEF COMPILER12_UP} {$DEFINE COMPILER11_UP} {$ENDIF}
{$IFDEF COMPILER11_UP} {$DEFINE COMPILER10_UP} {$ENDIF}
{$IFDEF COMPILER10_UP} {$DEFINE COMPILER9_UP} {$ENDIF}
{$IFDEF COMPILER9_UP} {$DEFINE COMPILER8_UP} {$ENDIF}
{$IFDEF COMPILER8_UP} {$DEFINE COMPILER7_UP} {$ENDIF}
{$IFDEF COMPILER7_UP} {$DEFINE COMPILER6_UP} {$ENDIF}
{$IFDEF COMPILER6_UP} {$DEFINE COMPILER5_UP} {$ENDIF}
{$IFDEF COMPILER5_UP} {$DEFINE COMPILER4_UP} {$ENDIF}
{$IFDEF COMPILER4_UP} {$DEFINE COMPILER3_UP} {$ENDIF}
{$IFDEF COMPILER3_UP} {$DEFINE COMPILER2_UP} {$ENDIF}
{$IFDEF COMPILER2_UP} {$DEFINE COMPILER1_UP} {$ENDIF}
{ Unicode compiler directive for string type }
// Delphi 2009+ uses UTF16, Lazarus 0.9.25+ uses UTF8
{$IF DEFINED(COMPILER12_UP) OR DEFINED(FPC)}
{$DEFINE STRING_IS_UNICODE}
{$IFEND}
{ Prefers usage of TCanvas methods instead of WinAPI mainly to avoid problems in Lazarus. }
{$DEFINE USE_CANVAS_METHODS}
{ Register new image formats into TPicture. }
{.$DEFINE REGISTER_PICTURE_FORMATS}
{ Allows to use WideWinProcs unit }
{$IFDEF MSWINDOWS}
{.$DEFINE USE_WIDEWINPROCS}
{$ENDIF}
{$DEFINE LAZARUS_HAS_DC_MAPPING}
{$IF DEFINED(USE_WINAPI) OR DEFINED(LAZARUS_HAS_DC_MAPPING)}
{$DEFINE USE_DC_MAPPING}
{$IFEND}
{ Conditional defines for unit KGrids: }
// we want TKGridObjectCell to be a descendant of TKGridAttrTextCell
{$DEFINE TKGRIDOBJECTCELL_IS_TKGRIDATTRTEXTCELL}
// we want TKGridObjectCell to be a descendant of TKGridTextCell
{.$DEFINE TKGRIDOBJECTCELL_IS_TKGRIDTEXTCELL}
// use JCLUnicode (only for TKGridAxisItem.Assign(Source: TWideStrings);)
{.$DEFINE TKGRID_USE_JCL}
{ Conditional defines for unit KDBGrids: }
// we want to use TKDBGrid
{$DEFINE TKDBGRID_USE}
// we want TKDBGridCell to be a descendant of TKGridAttrTextCell
{.$DEFINE TKDBGRIDCELL_IS_TKGRIDATTRTEXTCELL}
// PngImage can be used
{$IF DEFINED(FPC) OR DEFINED(COMPILER12_UP)}
{$DEFINE USE_PNG_SUPPORT}
{$IFEND}
{$ENDIF ~KCONTROLS_INC}
tomboy-ng_0.34-1/kcontrols/source/keditcommon.pas 0000644 0001750 0001750 00000061664 14125207534 021767 0 ustar dbannon dbannon { @abstract(This file is part of the KControls component suite for Delphi and Lazarus.)
@author(Tomas Krysl)
Copyright (c) 2020 Tomas Krysl
License:
This code is licensed under BSD 3-Clause Clear License, see file License.txt or https://spdx.org/licenses/BSD-3-Clause-Clear.html.
}
unit keditcommon; // lowercase name because of Lazarus/Linux
{$include kcontrols.inc}
{$WEAKPACKAGEUNIT ON}
interface
uses
{$IFDEF FPC}
LCLType, LCLIntf, LCLProc, LMessages, LResources, {$IFDEF MSWINDOWS}Windows,{$ENDIF}
{$ELSE}
Windows, Messages,
{$ENDIF}
SysUtils, Classes, ClipBrd, Graphics, Controls, ComCtrls, Forms, StdCtrls, KFunctions;
const
cCharMappingSize = 256;
type
{ Declares possible values for the edit control commands. }
TKEditCommand = (
{ No command }
ecNone,
{ Move caret left one char }
ecLeft,
{ Move caret right one char }
ecRight,
{ Move caret up one line }
ecUp,
{ Move caret down one line }
ecDown,
{ Move caret to beginning of line }
ecLineStart,
{ Move caret to end of line }
ecLineEnd,
{ Move caret left one word }
ecWordLeft,
{ Move caret right one word }
ecWordRight,
{ Move caret up one page }
ecPageUp,
{ Move caret down one page }
ecPageDown,
{ Move caret left one page }
ecPageLeft,
{ Move caret right one page }
ecPageRight,
{ Move caret to top of page }
ecPageTop,
{ Move caret to bottom of page }
ecPageBottom,
{ Move caret to absolute beginning }
ecEditorTop,
{ Move caret to absolute end }
ecEditorBottom,
{ Move caret to specific coordinates, Data = ^TPoint }
ecGotoXY,
{ Move caret left one char }
ecSelLeft,
{ Move caret right one char, affecting selection }
ecSelRight,
{ Move caret up one line, affecting selection }
ecSelUp,
{ Move caret down one line, affecting selection }
ecSelDown,
{ Move caret to beginning of line, affecting selection }
ecSelLineStart,
{ Move caret to end of line, affecting selection }
ecSelLineEnd,
{ Move caret left one word, affecting selection }
ecSelWordLeft,
{ Move caret right one word, affecting selection }
ecSelWordRight,
{ Move caret up one page, affecting selection }
ecSelPageUp,
{ Move caret down one page, affecting selection }
ecSelPageDown,
{ Move caret left one page, affecting selection }
ecSelPageLeft,
{ Move caret right one page, affecting selection }
ecSelPageRight,
{ Move caret to top of page, affecting selection }
ecSelPageTop,
{ Move caret to bottom of page, affecting selection }
ecSelPageBottom,
{ Move caret to absolute beginning, affecting selection }
ecSelEditorTop,
{ Move caret to absolute end, affecting selection }
ecSelEditorBottom,
{ Move caret to specific coordinates, affecting selection, Data = ^TPoint }
ecSelGotoXY,
{ Scroll up one line leaving caret position unchanged }
ecScrollUp,
{ Scroll down one line leaving caret position unchanged }
ecScrollDown,
{ Scroll left one char leaving caret position unchanged }
ecScrollLeft,
{ Scroll right one char leaving caret position unchanged }
ecScrollRight,
{ Scroll to center the caret position within client area }
ecScrollCenter,
{ Undo previous action }
ecUndo,
{ Redo last undone action }
ecRedo,
{ Copy selection to clipboard }
ecCopy,
{ Cut selection to clipboard }
ecCut,
{ Paste clipboard to current position }
ecPaste,
{ Insert character at current position, Data = ^Char }
ecInsertChar,
{ Insert digits (digit string) at current position, Data = ^string
(must contain digits only), TKCustomHexEditor only }
ecInsertDigits,
{ Insert string (multiple characters) at current position, Data = ^string }
ecInsertString,
{ Insert new line }
ecInsertNewLine,
{ Delete last character (i.e. backspace key) }
ecDeleteLastChar,
{ Delete character at caret (i.e. delete key) }
ecDeleteChar,
{ Delete from caret to beginning of line }
ecDeleteBOL,
{ Delete from caret to end of line }
ecDeleteEOL,
{ Delete current line }
ecDeleteLine,
{ Select everything }
ecSelectAll,
{ Delete everything }
ecClearAll,
{ Delete selection (no digit selection), TKCustomHexEditor only }
ecClearIndexSelection,
{ Delete selection (digit selection as well) }
ecClearSelection,
{ Search for text/digits }
ecSearch,
{ Replace text/digits }
ecReplace,
{ Set insert mode }
ecInsertMode,
{ Set overwrite mode }
ecOverwriteMode,
{ Toggle insert/overwrite mode }
ecToggleMode,
{ Adjust editor when getting input focus }
ecGotFocus,
{ Adjust editor when losing input focus }
ecLostFocus
);
{ Declares possible values for control's DisabledDrawStyle property. }
TKEditDisabledDrawStyle = (
{ The lines will be painted with brighter colors when editor is disabled. }
eddBright,
{ The lines will be painted with gray text and white background when editor is disabled. }
eddGrayed,
{ The lines will be painted normally when editor is disabled. }
eddNormal
);
{ @abstract(Declares the keystroke information structure for the Key member
of the @link(TKEditCommandAssignment) structure)
Members:
- Key - virtual key code
- Shift - shift state that belongs to that key code
}
TKEditKey = record
Key: Word;
Shift: TShiftState;
end;
{ @abstract(Declares the @link(TKEditKeyMapping) array item)
Members:
- Command - command that is about to be executed
- Key - key combination necessary to execute that command
}
TKEditCommandAssignment = record
Key: TKEditKey;
Command: TKEditCommand;
end;
TKEditCommandMap = array of TKEditCommandAssignment;
{ @abstract(Declares OnDropFiles event handler)
Parameters:
- Sender - identifies the event caller
- X, Y - mouse cursor coordinates (relative to the caller's window)
- Files - list of file names that were dropped on the caller's window)
}
TKEditDropFilesEvent = procedure(Sender: TObject; X, Y: integer;
Files: TStrings) of object;
{ Declares key mapping class for the KeyMapping property }
TKEditKeyMapping = class(TObject)
private
function GetAssignment(AIndex: Integer): TKEditCommandAssignment;
function GetKey(AIndex: TKEditCommand): TKEditKey;
procedure SetKey(AIndex: TKEditCommand; const AValue: TKEditKey);
protected
FMap: TKEditCommandMap;
procedure CreateMap; virtual;
public
constructor Create;
procedure Assign(Source: TKEditKeyMapping); virtual;
procedure AddKey(Command: TKEditCommand; Key: Word; Shift: TShiftState);
class function EmptyMap: TKEditCommandAssignment;
function FindCommand(AKey: Word; AShift: TShiftState): TKEditCommand;
property Assignment[Index: Integer]: TKEditCommandAssignment read GetAssignment;
property Key[AIndex: TKEditCommand]: TKEditKey read GetKey write SetKey;
property Map: TKEditCommandMap read FMap;
end;
{ Declares character mapping array for the edit control's CharMapping property }
TKEditCharMapping = array of AnsiChar;
{ Pointer to @link(TKEditCharMapping) }
PKEditCharMapping = ^TKEditCharMapping;
{ Declares options - possible values for the edit control's Options property }
TKEditOption = (
{ The editor will receive dropped files }
eoDropFiles,
{ The blinking caret should be disabled }
eoDisableCaret,
{ All undo/redo operations of the same kind will be grouped together }
eoGroupUndo,
{ The editor allows undo/redo operations after the edit control's Modified property
has been set to False }
eoUndoAfterSave,
{ TKMemo only: Will draw each character separately. }
eoDrawSingleChars,
{ TKMemo only: Use ScrollWindowEx to scroll the control. }
eoScrollWindow,
{ TKMemo only: show formatting markers. }
eoShowFormatting,
{ TKMemo only: acquire TAB characters. }
eoWantTab,
{ TKMemo only: Will wrap text at each character. }
eoWrapSingleChars
);
{ Options can be arbitrary combined }
TKEditOptions = set of TKEditOption;
{ Declares possible values for the Action parameter in the @link(TKEditReplaceTextEvent) event }
TKEditReplaceAction = (
{ Quit replace sequence }
eraCancel,
{ Replace this occurence }
eraYes,
{ Don't replace this occurence }
eraNo,
{ Replace all following occurences without prompting }
eraAll
);
{ @abstract(Declares OnReplaceText event handler)
Parameters:
- Sender - identifies the event caller
- TextToFind - current search string
- TextToReplace - current replace string
- Action - specifies how the replace function should continue
}
TKEditReplaceTextEvent = procedure(Sender: TObject; const TextToFind, TextToReplace:
string; var Action: TKEditReplaceAction) of object;
{ Declares possible values for the ErrorReason member of the @link(TKEditSearchData) structure }
TKEditSearchError = (
{ No error occured }
eseOk,
{ There is a character in the search string that cannot be interpreted as hexadecimal digits}
eseNoDigitsFind,
{ There is a character in the replace string that cannot be interpreted as hexadecimal digits}
eseNoDigitsReplace,
{ No other search string found }
eseNoMatch
);
{ Declares search options - possible values for the Options member of the @link(TKEditSearchData) structure }
TKEditSearchOption = (
{ Replace all occurences }
esoAll,
{ Search backwards }
esoBackwards,
{ Search entire scope instead from current caret position }
esoEntireScope,
{ Include to identify search - this element will be automatically cleared
to provide the @link(TKEditSearchData) structure for additional search }
esoFirstSearch,
{ Match case when a binary search should be executed }
esoMatchCase,
{ Prompt user before a string is about to be replaced. This assumes @link(OnReplaceText)
is assigned }
esoPrompt,
{ Search the current selection only }
esoSelectedOnly,
{ Treat the supplied search and/or replace strings as hexadecimal sequence.
When the search string contains a character that cannot be interpreted as
hexadecimal digit, the execution stops and @link(eseNoDigitsFind) error will
be returned. Similarly, @link(eseNoDigitsReplace) errors will be returned
on invalid replace string }
esoTreatAsDigits,
{ Internal option - don't modify }
esoWereDigits
);
{ Search options can be arbitrary combined }
TKEditSearchOptions = set of TKEditSearchOption;
{ @abstract(Declares the search/replace description structure for the @link(ecSearch)
and @link(ecReplace) commands)
Members:
- ErrorReason - upon @link(ExecuteCommand)(ecSearch) or
ExecuteCommand(ecReplace), inspect this member to inform user about
search/replace result
- Options - defines search/replace options
- SelStart, SelEnd - internal parameters, don't modify
- TextToFind - search string
- TextToReplace - replace string
}
TKEditSearchData = record
ErrorReason: TKEditSearchError;
Options: TKEditSearchOptions;
SelStart,
SelEnd: Int64;
TextToFind,
TextToReplace: string;
end;
{ Pointer to @link(TKEditSearchData) }
PKEditSearchData = ^TKEditSearchData;
const
{ Default value for the @link(TKCustomHexEditor.DisabledDrawStyle) property }
cEditDisabledDrawStyleDef = eddBright;
{ Returns default key mapping structure }
function CreateDefaultKeyMapping: TKEditKeyMapping;
{ Returns default char mapping structure }
function DefaultCharMapping: TKEditCharMapping;
{ Returns default search data structure }
function DefaultSearchData: TKEditSearchData;
{ Returns True if focused window is some text editing window, such as TEdit. }
function EditIsFocused(AMustAllowWrite: Boolean): Boolean;
{ Returns True if some text editing window is focused and contains a selectable text. }
function EditFocusedTextCanCopy: Boolean;
{ Returns True if some non-readonly text editing window is focused and contains a selectable text. }
function EditFocusedTextCanCut: Boolean;
{ Returns True if some non-readonly text editing window is focused. }
function EditFocusedTextCanDelete: Boolean;
{ Returns True if some non-readonly text editing window is focused and clipboard is not empty. }
function EditFocusedTextCanPaste: Boolean;
{ Returns True if the focused text editing window can perform an undo operation. }
function EditFocusedTextCanUndo: Boolean;
{ Performs an undo operation on the focused text editing window. }
procedure EditUndoFocused;
{ Performs a delete operation on the focused text editing window. }
procedure EditDeleteFocused;
{ Performs a clipboard cut operation on the focused text editing window. }
procedure EditCutFocused;
{ Performs a clipboard copy operation on the focused text editing window. }
procedure EditCopyFocused;
{ Performs a clipboard paste operation on the focused text editing window. }
procedure EditPasteFocused;
{ Performs a select all operation on the focused text editing window. }
procedure EditSelectAllFocused;
function PixelsPerInchX(AHandle: HWND): Integer;
function PixelsPerInchY(AHandle: HWND): Integer;
function TwipsPerPixelX(AHandle: HWND): Double;
function TwipsPerPixelY(AHandle: HWND): Double;
function PixelsToPoints(AValue: Integer; ADPI: Integer): Double;
function PointsToPixels(AValue: Double; ADPI: Integer): Integer;
function TwipsToPoints(AValue: Integer; ADPI: Integer): Double;
function PointsToTwips(AValue: Double; ADPI: Integer): Integer;
{ Converts binary data into text using given character mapping.
Parameters:
- Buffer - binary data - intended for @link(TKCustomHexEditor.Buffer)
- SelStart, SelEnd - specifies which part of the buffer is about to be
converted. SelStart must be lower or equal to SelEnd. These parameters are integers
since no digit selections are necessary.
- CharMapping - required character mapping scheme
}
function BinaryToText(Buffer: PBytes; SelStart, SelEnd: Int64;
CharMapping: PKEditCharMapping): AnsiString;
function ReplaceNonprintableCharacters(const AText: AnsiString; AMapping: TKEditCharMapping = nil): AnsiString;
implementation
uses
KControls, KMemo;
function PixelsPerInchX(AHandle: HWND): Integer;
var
DC: HDC;
begin
DC := GetDC(AHandle);
try
Result := GetDeviceCaps(DC, LOGPIXELSX);
finally
ReleaseDC(AHandle, DC);
end;
end;
function PixelsPerInchY(AHandle: HWND): Integer;
var
DC: HDC;
begin
DC := GetDC(AHandle);
try
Result := GetDeviceCaps(DC, LOGPIXELSY);
finally
ReleaseDC(AHandle, DC);
end;
end;
function TwipsPerPixelX(AHandle: HWND): Double;
begin
Result := 1440 / PixelsPerInchX(AHandle);
end;
function TwipsPerPixelY(AHandle: HWND): Double;
begin
Result := 1440 / PixelsPerInchY(AHandle);
end;
function PixelsToPoints(AValue, ADPI: Integer): Double;
begin
Result := AValue * 72 / ADPI;
end;
function PointsToPixels(AValue: Double; ADPI: Integer): Integer;
begin
Result := Round(AValue * ADPI / 72);
end;
function TwipsToPoints(AValue: Integer; ADPI: Integer): Double;
begin
Result := AValue * 1440 / ADPI;
end;
function PointsToTwips(AValue: Double; ADPI: Integer): Integer;
begin
Result := Round(AValue * ADPI / 1440);
end;
function BinaryToText(Buffer: PBytes; SelStart, SelEnd: Int64;
CharMapping: PKEditCharMapping): AnsiString;
var
I: Integer;
begin
if SelEnd > SelStart then
begin
SetLength(Result, SelEnd - SelStart);
System.Move(Buffer[SelStart], Result[1], SelEnd - SelStart);
if CharMapping <> nil then
for I := 1 to Length(Result) do
Result[I] := CharMapping^[Byte(Result[I])];
end else
Result := '';
end;
function ReplaceNonprintableCharacters(const AText: AnsiString; AMapping: TKEditCharMapping = nil): AnsiString;
var
I: Integer;
begin
if AMapping = nil then
AMapping := DefaultCharMapping;
SetLength(Result, Length(AText));
for I := 1 to Length(AText) do
Result[I] := AMapping[Ord(AText[I])];
end;
function CreateDefaultKeyMapping: TKEditKeyMapping;
begin
Result := TKEditKeyMapping.Create;
end;
function DefaultCharMapping: TKEditCharMapping;
var
I: Integer;
begin
SetLength(Result, cCharMappingSize);
for I := 0 to cCharMappingSize - 1 do
if (I < $20) or (I >= $80) then
Result[I] := '.'
else
Result[I] := AnsiChar(I);
end;
function DefaultSearchData: TKEditSearchData;
begin
with Result do
begin
ErrorReason := eseOk;
Options := [esoAll, esoFirstSearch, esoPrompt, esoTreatAsDigits];
SelStart := 0;
SelEnd := 0;
TextToFind := '';
TextToReplace := '';
end;
end;
{$IFDEF MSWINDOWS}
function EditFocusedHandle(AMustAllowWrite: Boolean): THandle;
var
Len: Integer;
Wnd: HWND;
S: string;
C: TWinControl;
begin
Result := 0;
Wnd := GetFocus;
C := FindControl(Wnd);
if (C <> nil) and
(C is TCustomEdit) and (not AMustAllowWrite or not TEdit(C).ReadOnly) or
(C is TCustomMemo) and (not AMustAllowWrite or not TMemo(C).ReadOnly) or
(C is TComboBox) and (TComboBox(C).Style in [csSimple, csDropDown])
{$IFnDEF FPC}
or (C is TRichEdit) and (not AMustAllowWrite or not TRichEdit(C).ReadOnly)
{$ENDIF}
or (C is TKCustomMemo) and (not AMustAllowWrite or not TKCustomMemo(C).ReadOnly)
then
Result := Wnd
else
begin
SetLength(S, 100);
Len := GetClassName(Wnd, PChar(S), 100);
if Len > 0 then
begin
SetLength(S, Len);
S := UpperCase(S);
if (S = 'EDIT') then
Result := Wnd;
end;
end;
end;
{$ENDIF}
function EditIsFocused(AMustAllowWrite: Boolean): Boolean;
{$IFDEF MSWINDOWS}
begin
Result := EditFocusedHandle(AMustAllowWrite) <> 0;
end;
{$ELSE}
begin
// can this be implemented somehow?
Result := False;
end;
{$ENDIF}
function EditFocusedTextHasSelection(AMustAllowWrite: Boolean): Boolean;
{$IFDEF MSWINDOWS}
var
A, B: Integer;
Wnd: THandle;
begin
Wnd := EditFocusedHandle(AMustAllowWrite);
if Wnd <> 0 then
begin
SendMessage(Wnd, EM_GETSEL, WParam(@A), LParam(@B));
Result := A <> B;
end else
Result := False;
end;
{$ELSE}
begin
// can this be implemented somehow?
Result := False;
end;
{$ENDIF}
function EditFocusedTextCanCopy: Boolean;
begin
Result := EditFocusedTextHasSelection(False);
end;
function EditFocusedTextCanCut: Boolean;
begin
Result := EditFocusedTextHasSelection(True);
end;
function EditFocusedTextCanDelete: Boolean;
begin
Result := EditIsFocused(True);
end;
function EditFocusedTextCanPaste: Boolean;
begin
Result := EditIsFocused(True) and ClipBoard.HasFormat(CF_TEXT);
end;
function EditFocusedTextCanUndo: Boolean;
begin
{$IFDEF MSWINDOWS}
Result := LongBool(SendMessage(GetFocus, EM_CANUNDO, 0, 0));
{$ELSE}
// can this be implemented somehow?
Result := False;
{$ENDIF}
end;
procedure EditUndoFocused;
begin
{$IFDEF MSWINDOWS}
SendMessage(GetFocus, WM_UNDO, 0, 0);
{$ENDIF}
end;
procedure EditDeleteFocused;
begin
SendMessage(GetFocus, LM_CLEAR, 0, 0);
end;
procedure EditCutFocused;
begin
SendMessage(GetFocus, LM_CUT, 0, 0);
end;
procedure EditCopyFocused;
begin
SendMessage(GetFocus, LM_COPY, 0, 0);
end;
procedure EditPasteFocused;
begin
SendMessage(GetFocus, LM_PASTE, 0, 0);
end;
procedure EditSelectAllFocused;
begin
{$IFDEF MSWINDOWS}
SendMessage(GetFocus, EM_SETSEL, 0, -1);
{$ENDIF}
end;
{ TKEditKeyMapping }
constructor TKEditKeyMapping.Create;
begin
FMap := nil;
CreateMap;
end;
procedure TKEditKeyMapping.Assign(Source: TKEditKeyMapping);
begin
FMap := Copy(Source.Map);
end;
procedure TKEditKeyMapping.CreateMap;
begin
AddKey(ecLeft, VK_LEFT, []);
AddKey(ecRight, VK_RIGHT, []);
AddKey(ecInsertNewLine, VK_RETURN, []);
AddKey(ecUp, VK_UP, []);
AddKey(ecDown, VK_DOWN, []);
AddKey(ecLineStart, VK_HOME, []);
AddKey(ecLineEnd, VK_END, []);
AddKey(ecPageUp, VK_PRIOR, []);
AddKey(ecPageDown, VK_NEXT, []);
AddKey(ecPageLeft, VK_LEFT, [ssCtrl, ssAlt]);
AddKey(ecPageRight, VK_RIGHT, [ssCtrl, ssAlt]);
AddKey(ecPageTop, VK_PRIOR, [ssCtrl]);
AddKey(ecPageBottom, VK_NEXT, [ssCtrl]);
AddKey(ecEditorTop, VK_HOME, [ssCtrl]);
AddKey(ecEditorBottom, VK_END, [ssCtrl]);
AddKey(ecSelLeft, VK_LEFT, [ssShift]);
AddKey(ecSelRight, VK_RIGHT, [ssShift]);
AddKey(ecSelUp, VK_UP, [ssShift]);
AddKey(ecSelDown, VK_DOWN, [ssShift]);
AddKey(ecSelLineStart, VK_HOME, [ssShift]);
AddKey(ecSelLineEnd, VK_END, [ssShift]);
AddKey(ecSelPageUp, VK_PRIOR, [ssShift]);
AddKey(ecSelPageDown, VK_NEXT, [ssShift]);
AddKey(ecSelPageLeft, VK_LEFT, [ssShift, ssCtrl, ssAlt]);
AddKey(ecSelPageRight, VK_RIGHT, [ssShift, ssCtrl, ssAlt]);
AddKey(ecSelPageTop, VK_PRIOR, [ssShift, ssCtrl]);
AddKey(ecSelPageBottom, VK_NEXT, [ssShift, ssCtrl]);
AddKey(ecSelEditorTop, VK_HOME, [ssShift, ssCtrl]);
AddKey(ecSelEditorBottom, VK_END, [ssShift, ssCtrl]);
AddKey(ecSelWordLeft, VK_LEFT, [ssShift, ssCtrl]);
AddKey(ecSelWordRight, VK_RIGHT, [ssShift, ssCtrl]);
AddKey(ecScrollUp, VK_UP, [ssCtrl]);
AddKey(ecScrollDown, VK_DOWN, [ssCtrl]);
AddKey(ecWordLeft, VK_LEFT, [ssCtrl]);
AddKey(ecWordRight, VK_RIGHT, [ssCtrl]);
AddKey(ecScrollLeft, VK_LEFT, [ssShift, ssAlt]);
AddKey(ecScrollRight, VK_RIGHT, [ssShift, ssAlt]);
AddKey(ecScrollCenter, VK_RETURN, [ssCtrl]);
AddKey(ecUndo, ord('Z'), [ssCtrl]);
AddKey(ecUndo, VK_BACK, [ssAlt]);
AddKey(ecRedo, ord('Z'), [ssShift, ssCtrl]);
AddKey(ecRedo, VK_BACK, [ssShift, ssAlt]);
AddKey(ecCopy, ord('C'), [ssCtrl]);
AddKey(ecCopy, VK_INSERT, [ssCtrl]);
AddKey(ecCut, ord('X'), [ssCtrl]);
AddKey(ecCut, VK_DELETE, [ssShift]);
AddKey(ecPaste, ord('V'), [ssCtrl]);
AddKey(ecPaste, VK_INSERT, [ssShift]);
AddKey(ecDeleteLastChar, VK_BACK, []);
AddKey(ecDeleteLastChar, VK_BACK, [ssShift]);
AddKey(ecDeleteChar, VK_DELETE, []);
AddKey(ecDeleteBOL, ord('X'), [ssCtrl,ssShift]);
AddKey(ecDeleteEOL, ord('Y'), [ssCtrl,ssShift]);
AddKey(ecDeleteLine, ord('Y'), [ssCtrl]);
AddKey(ecSelectAll, ord('A'), [ssCtrl]);
AddKey(ecToggleMode, VK_INSERT, []);
{$IFDEF DARWIN}
// MAC specific, what I knew or guessed and worked for me
AddKey(ecLineStart, VK_LEFT, [ssMeta]);
AddKey(ecLineEnd, VK_RIGHT, [ssMeta]);
AddKey(ecSelLineStart, VK_LEFT, [ssMeta, ssShift]);
AddKey(ecSelLineEnd, VK_RIGHT, [ssMeta, ssShift]);
AddKey(ecSelPageTop, VK_PRIOR, [ssMeta, ssShift]);
AddKey(ecSelPageBottom, VK_NEXT, [ssMeta, ssShift]);
AddKey(ecCopy, ord('C'), [ssMeta]);
AddKey(ecCut, ord('X'), [ssMeta]);
AddKey(ecPaste, ord('V'), [ssMeta]);
{$ENDIF}
end;
class function TKEditKeyMapping.EmptyMap: TKEditCommandAssignment;
begin
Result.Command := ecNone;
Result.Key.Key := 0;
Result.Key.Shift := [];
end;
procedure TKEditKeyMapping.AddKey(Command: TKEditCommand; Key: Word; Shift: TShiftState);
var
I: Integer;
begin
I := Length(FMap);
SetLength(FMap, I + 1);
FMap[I].Command := Command;
FMap[I].Key.Key := Key;
FMap[I].Key.Shift := Shift;
end;
function TKEditKeyMapping.FindCommand(AKey: Word; AShift: TShiftState): TKEditCommand;
var
I: Integer;
Key: TKEditKey;
begin
Result := ecNone;
for I := 0 to Length(FMap) - 1 do
begin
Key := FMap[I].Key;
if (Key.Key = AKey) and (Key.Shift = AShift) then
begin
Result := FMap[I].Command;
Exit;
end;
end;
end;
function TKEditKeyMapping.GetKey(AIndex: TKEditCommand): TKEditKey;
var
I: Integer;
begin
Result.Key := 0;
Result.Shift := [];
for I := 0 to Length(FMap) - 1 do
if FMap[I].Command = AIndex then
begin
Result := FMap[I].Key;
Exit;
end;
end;
function TKEditKeyMapping.GetAssignment(AIndex: Integer): TKEditCommandAssignment;
begin
if (AIndex >= 0) and (AIndex < Length(FMap)) then
Result := FMap[AIndex]
else
Result := EmptyMap;
end;
procedure TKEditKeyMapping.SetKey(AIndex: TKEditCommand; const AValue: TKEditKey);
var
I: Integer;
begin
for I := 0 to Length(FMap) - 1 do
if FMap[I].Command = AIndex then
begin
FMap[I].Key := AValue;
Exit;
end;
end;
end.
tomboy-ng_0.34-1/kcontrols/source/kres.pas 0000644 0001750 0001750 00000031166 14125207534 020414 0 ustar dbannon dbannon { @abstract(This file is part of the KControls component suite for Delphi and Lazarus.)
@author(Tomas Krysl)
Copyright (c) 2020 Tomas Krysl
License:
This code is licensed under BSD 3-Clause Clear License, see file License.txt or https://spdx.org/licenses/BSD-3-Clause-Clear.html.
}
unit kres; // lowercase name because of Lazarus/Linux
{$include kcontrols.inc}
{$WEAKPACKAGEUNIT ON}
interface
{ Because the resourcestring concept used in Delphi is not always the best way to localize an application,
I decided to implement routines which allow to modify the resourcestrings dynamically at runtime.
They allow for direct localization e.g. from XML file without the need of the standard localization scheme
for resourcestrings. Especially if you need to translate only some of the strings it is much easier approach. }
{ Standard resourcestrings localized to english by default }
resourcestring
// KGraphics texts
sGrAlphaBitmap = 'KControls alpha bitmap';
// KDialogs texts
sBrowseDirectory = 'Choose directory:';
// KEdits texts
sEDBadSubDirName = 'The invalid subdirectory "%s" has been replaced with "%s".';
sEDCurrentDirAdded = 'Current path added to path "%s".';
sEDBadDir = 'The directory "%s" can be invalid.';
sEDBadDirCorr = 'Invalid or incomplete directory "%s" has been replaced with "%s".';
sEDBadPath = 'The path or file name "%s" can be incomplete or invalid.';
sEDBadPathCorr = 'Invalid path or file name "%s" has been replaced with "%s".';
sEDMissingFileName = 'Missing file name.';
sEDNoExistingDir = 'The directory "%s" doesn''t exist.';
sEDNoExistingPath = 'The file "%s" doesn''t exist.';
sEDFormatNotAccepted = 'The text either doesn''t represent a numeral or the numeric format cannot be accepted.';
sEDBadFloatValueAsStr = 'The text is not a float value in the range from %s to %s. Value corrected to %s.';
sEDBadIntValueAsStr = 'The text is not a decimal value in the range from %s to %s. Value corrected to %s.';
sEDBadHexValueAsStr = 'The text is not a hexadecimal value in the range from %s to %s. Value corrected to %s.';
sEDClipboardFmtNotAccepted = 'The current clipboard text cannot be accepted.';
sEDBrowse = 'Browse ...';
sEDAllFiles = 'All files (*.*)|*.*';
// KGraphics texts
sGDIError = 'GDI object could not be created.';
sErrGraphicsLoadFromResource = 'Graphics could not be loaded from resource.';
// KHexEditor texts
sHEAddressText = 'Address area text';
sHEAddressBkGnd = 'Address area background';
sHEBkGnd = 'Editor background';
sHEDigitTextEven = 'Digit area even column';
sHEDigitTextOdd = 'Digit area odd column';
sHEDigitBkgnd = 'Digit area background';
sHEHorzLines = 'Horizontal lines';
sHEInactiveCaretBkGnd = 'Inactive caret background';
sHEInactiveCaretSelBkGnd = 'Selected inactive caret background';
sHEInactiveCaretSelText = 'Selected inactive caret text';
sHEInactiveCaretText = 'Inactive caret text';
sHELinesHighLight = 'Lines highlight';
sHESelBkGnd = 'Selection background';
sHESelBkGndFocused = 'Focused selection background';
sHESelText = 'Selection text';
sHESelTextFocused = 'Focused selection text';
sHESeparators = 'Area separating lines';
sHETextText = 'Text area text';
sHETextBkGnd = 'Text area background';
sHEVertLines = 'Vertical lines';
// KIcons texts
sIconIcons = 'Icons';
sIconCursors = 'Cursors';
sIconAllocationError = 'Error while allocating icon data';
sIconBitmapError = 'Invalid icon bitmap handles';
sIconFormatError = 'Invalid icon format';
sIconResourceError = 'Invalid icon resource';
sIconIndexError = 'Invalid icon resource index';
sIconInvalidModule = 'Invalid module or no icon resources';
sIconResizingError = 'Error while resizing icon';
sIconAssocResolveError = 'Error while resolving associated icon';
// KLog texts
sLogError = 'Error';
sLogWarning = 'Warning';
sLogNote = 'Note';
sLogHint = 'Hint';
sLogInfo = 'Info';
sLogInputError = 'Input error';
sLogIOError = 'IO error';
// KMessagebox texts
sMsgBoxYes = '&Yes';
sMsgBoxNo = '&No';
sMsgBoxOK = '&OK';
sMsgBoxCancel = 'Cancel';
sMsgBoxClose = '&Close';
sMsgBoxAbort = 'A&bort';
sMsgBoxRetry = '&Retry';
sMsgBoxIgnore = '&Ignore';
sMsgBoxAll = '&All';
sMsgBoxNoToAll = 'Non&e';
sMsgBoxYesToAll = 'Ye&s to all';
sMsgBoxHelp = '&Help';
// KPrinterSetup texts
sPSPrinterSetup = 'Printer setup';
sPSAllPages = 'All pages (%d)';
sPSErrPrintSetup = 'Print setup error';
sPSErrNoPrinterInstalled = 'No printer is installed on this computer.';
sPSErrNoDefaultPrinter = 'No default printer selected, cannot continue. Please select default printer.';
sPSErrPrinterUnknown = 'Unknown error in printer interface. Please restart application and try again.';
sPSErrPrinterConfiguration = 'Printer configuration not supported.';
// KControlsDesign texts
sInvalidGraphicFormat = 'Invalid graphic format.';
// KDBGrids texts
sDataSetUnidirectional = 'Cannot use KDBGrid with a unidirectional dataset.';
// KMemoRTF texts
sErrMemoLoadFromRTF = 'Error while reading RTF file.';
sErrMemoLoadImageFromRTF = 'Error while loading image from RTF file.';
sErrMemoSaveToRTF = 'Error while saving RTF file.';
// KMemoFrame texts
sAppError = 'Application error';
sAppQuery = 'Application query';
sMemoDefaultFileName = 'document';
sQueryFileSave = 'File "%s" has been changed. Do you want to save it?';
sErrMemoLoadFromFile = 'Error while loading file "%s".';
sErrMemoSaveToFile = 'Error while saving file "%s".';
sMemoSampleTextBox = 'Enter the text box contents. The textbox can be placed anywhere in the document.';
{ Localize given resourcestring directly.
Usage: ResMod(@sYourResourceString, 'New text');
Note: Text passed to NewValue must persist through the entire
application lifetime under Delphi, as only its pointer is taken! }
procedure ResMod(Res: PResStringRec; const NewValue: string);
{ Localize all resourcestrings to Czech language. }
procedure LocalizeToCzech;
implementation
{$IFnDEF FPC}
uses
Windows, KFunctions;
{$ENDIF}
{$IFDEF FPC}
type
PResModRec = ^TResModRec;
TResModRec = record
DefStr: string;
NewStr: string;
end;
function ResModIterator(Name, Value: AnsiString; Hash: Longint; arg:pointer): AnsiString;
begin
if Value = PResModRec(arg).DefStr then
Result := PResModRec(arg).NewStr
else
Result := '';
end;
procedure ResMod(Res: PResStringRec; const NewValue: string);
var
RM: TResModRec;
begin
if (Res <> nil) and (Res^ <> '') then
begin
RM.DefStr := Res^;
RM.NewStr := NewValue;
SetResourceStrings(ResModIterator, @RM);
end;
end;
{$ELSE}
procedure ResMod(Res: PResStringRec; const NewValue: string);
var
OldProtect: LongWord;
OK: Boolean;
begin
if (Res <> nil) and (Res.Module <> nil) then
begin
OK := VirtualProtect(Res, Sizeof(TResStringRec), PAGE_EXECUTE_READWRITE, @oldProtect);
if OK then
begin
{$IFDEF COMPILER16_UP} // new code for Delphi XE2 and later
Res.Identifier := NativeUInt(NewValue);
{$ELSE}
Res.Identifier := LongInt(NewValue);
{$ENDIF}
VirtualProtect(Res, SizeOf(TResStringRec), oldProtect, @oldProtect);
end;
end;
end;
{$ENDIF}
procedure LocalizeToCzech;
begin
// KGraphics texts
ResMod(@sGrAlphaBitmap, 'Alpha bitmap KControls');
// KDialogs texts
ResMod(@sBrowseDirectory, 'Vyberte sloku:');
// KEdits texts
ResMod(@sEDBadSubDirName, 'Neplatn podsloka "%s" byla nahrazena "%s".');
ResMod(@sEDCurrentDirAdded, 'Aktuln cesta byla pidna k cest "%s".');
ResMod(@sEDBadDir, 'Sloka "%s" me bt neplatn.');
ResMod(@sEDBadDirCorr, 'Neplatn nebo nekompletn sloka "%s" byla nahrazena "%s".');
ResMod(@sEDBadPath, 'Cesta nebo soubor "%s" nemus bt kompletn nebo platn.');
ResMod(@sEDBadPathCorr, 'Neplatn cesta nebo soubor "%s" byl(a) nahrazen(a) "%s".');
ResMod(@sEDMissingFileName, 'Chyb nzev souboru.');
ResMod(@sEDNoExistingDir, 'Sloka "%s" neexistuje.');
ResMod(@sEDNoExistingPath, 'Soubor "%s" neexistuje.');
ResMod(@sEDFormatNotAccepted, 'Text nen slem nebo seln formt nelze pijmout.');
ResMod(@sEDBadFloatValueAsStr, 'Text nen relnm slem v rozsahu od %s do %s. Hodnota opravena na %s.');
ResMod(@sEDBadIntValueAsStr, 'Text nen celm slem v rozsahu od %s do %s. Hodnota opravena na %s.');
ResMod(@sEDBadHexValueAsStr, 'Text nen hexadecimlnm slem od %s do %s. Hodnota opravena na %s.');
ResMod(@sEDClipboardFmtNotAccepted, 'Text ze schrnky nelze pijmout.');
ResMod(@sEDBrowse, 'Prochzet...');
ResMod(@sEDAllFiles, 'Vechny soubory (*.*)|*.*');
// KGraphics texts
ResMod(@sGDIError, 'Objekt GDI nelze vytvoit.');
// KHexEditor texts
ResMod(@sHEAddressText, 'Ps adresy - text');
ResMod(@sHEAddressBkGnd, 'Ps adresy - pozad');
ResMod(@sHEBkGnd, 'Pozad editoru');
ResMod(@sHEDigitTextEven, 'Ps slic sud sloupec - text');
ResMod(@sHEDigitTextOdd, 'Ps slic lich sloupec - text');
ResMod(@sHEDigitBkgnd, 'Ps slic - pozad');
ResMod(@sHEHorzLines, 'Vodorovn linky');
ResMod(@sHEInactiveCaretBkGnd, 'Neaktivn kurzor - pozad');
ResMod(@sHEInactiveCaretSelBkGnd, 'Neaktivn kurzor pozad vbru');
ResMod(@sHEInactiveCaretSelText, 'Neaktivn kurzor text vbru');
ResMod(@sHEInactiveCaretText, 'Neaktivn kurzor - text');
ResMod(@sHELinesHighLight, 'Zvraznn dk');
ResMod(@sHESelBkGnd, 'Pozad vbru');
ResMod(@sHESelBkGndFocused, 'Pozad aktivnho vbru');
ResMod(@sHESelText, 'Text vbru');
ResMod(@sHESelTextFocused, 'Text aktivnho vbru');
ResMod(@sHESeparators, 'Oddlovac linky ps');
ResMod(@sHETextText, 'Ps textu - text');
ResMod(@sHETextBkGnd, 'Ps textu - pozad');
ResMod(@sHEVertLines, 'Svisl linky');
// KIcons texts
ResMod(@sIconIcons, 'Ikony');
ResMod(@sIconCursors, 'Kurzory');
ResMod(@sIconAllocationError, 'Chyba pi alokovn dat ikony');
ResMod(@sIconBitmapError, 'Neplatn popisovae bitmap ikony');
ResMod(@sIconFormatError, 'Neplatn formt ikony');
ResMod(@sIconResourceError, 'Neplatn zdroj ikony');
ResMod(@sIconIndexError, 'Neplatn index zdroje ikony');
ResMod(@sIconInvalidModule, 'Neplatn modul nebo chyb zdroje ikon');
ResMod(@sIconResizingError, 'Chyba pi zmn velikosti ikony');
ResMod(@sIconAssocResolveError, 'Chyba pi nahrvn asociovan ikony');
// KLog texts
ResMod(@sLogError, 'Chyba');
ResMod(@sLogWarning, 'Varovn');
ResMod(@sLogNote, 'Poznmka');
ResMod(@sLogHint, 'Npovda');
ResMod(@sLogInfo, 'Informace');
ResMod(@sLogInputError, 'Chyba zadn');
ResMod(@sLogIOError, 'Chyba IO operace');
// KMessagebox texts
ResMod(@sMsgBoxYes, '&Ano');
ResMod(@sMsgBoxNo, '&Ne');
ResMod(@sMsgBoxOK, '&OK');
ResMod(@sMsgBoxCancel, 'Storno');
ResMod(@sMsgBoxClose, 'Za&vt');
ResMod(@sMsgBoxAbort, '&Peruit');
ResMod(@sMsgBoxRetry, '&Znovu');
ResMod(@sMsgBoxIgnore, '&Ignorovat');
ResMod(@sMsgBoxAll, 'V&e');
ResMod(@sMsgBoxNoToAll, 'Ni&c');
ResMod(@sMsgBoxYesToAll, 'Ano pro ve');
ResMod(@sMsgBoxHelp, 'Npovda');
// KPrinterSetup texts
ResMod(@sPSPrinterSetup, 'Nasteven tiskrny');
ResMod(@sPSAllPages, 'Vechny strnky (%d)');
ResMod(@sPSErrPrintSetup, 'Chybn nastaven tisku');
ResMod(@sPSErrNoPrinterInstalled, 'Na potai nen instalovna dn tiskrna.');
ResMod(@sPSErrNoDefaultPrinter, 'Nen zvolena vchoz tiskrna, nelze pokraovat. Zvolte vchoz tiskrnu.');
ResMod(@sPSErrPrinterUnknown, 'Neznm chyba v tiskovm rozhran. Prosm restartujte aplikaci a zkuste to znovu.');
ResMod(@sPSErrPrinterConfiguration, 'Konfigurace tiskrny nen podporovna.');
// KControlsDesign texts
ResMod(@sInvalidGraphicFormat, 'Neplatn grafick formt.');
// KDBGrids texts
ResMod(@sDataSetUnidirectional, 'Nelze pout KDBGrid s jednosmrnm datasetem.');
// KMemoRTF texts
ResMod(@sErrMemoLoadFromRTF, 'Chyba pi ten souboru RTF.');
ResMod(@sErrMemoLoadImageFromRTF, 'Chyba pi ten obrzku z RTF souboru.');
ResMod(@sErrMemoSaveToRTF, 'Chyba pi zpisu souboru RTF.');
// KMemoFrame texts
ResMod(@sAppError, 'Chyba aplikace');
ResMod(@sAppQuery, 'Dotaz aplikace');
ResMod(@sMemoDefaultFileName, 'dokument');
ResMod(@sQueryFileSave, 'Soubor "%s" byl zmnn. Pejete si jej uloit?');
ResMod(@sErrMemoLoadFromFile, 'Chyba pi ten souboru "%s".');
ResMod(@sErrMemoSaveToFile, 'Chyba pi zpisu souboru "%s".');
ResMod(@sMemoSampleTextBox, 'Vyplte obsah textovho pole. Pole lze umstit kdekoli v dokumentu.');
end;
end.
tomboy-ng_0.34-1/kcontrols/source/kcontrols.res 0000644 0001750 0001750 00000001620 14125207534 021464 0 ustar dbannon dbannon 4 ( @ ? w g
P K P R E V I E W _ C U R S O R _ H A N D _ F R E E 0 @ 4 4 ( @ ? ? ` P K P R E V I E W _ C U R S O R _ H A N D _ G R I P 0 @ 4 tomboy-ng_0.34-1/kcontrols/source/kmemortf.pas 0000644 0001750 0001750 00000435146 14125207534 021302 0 ustar dbannon dbannon { @abstract(This file is part of the KControls component suite for Delphi and Lazarus.)
@author(Tomas Krysl)
Copyright (c) 2020 Tomas Krysl
License:
This code is licensed under BSD 3-Clause Clear License, see file License.txt or https://spdx.org/licenses/BSD-3-Clause-Clear.html.
}
unit kmemortf; // lowercase name because of Lazarus/Linux
{$include kcontrols.inc}
{$WEAKPACKAGEUNIT ON}
interface
uses
Classes, Contnrs, Graphics, Controls, Types,
KControls, KFunctions, KGraphics, KMemo;
type
TKMemoRTFCtrlMethod = procedure(ACtrl: Integer; var AText: AnsiString; AParam: Integer) of object;
{ Specifies the RTF control word descriptor. Is only used by RTF reader. }
TKMemoRTFCtrl = class(TObject)
private
FCode: Integer;
FCtrl: AnsiString;
FMethod: TKMemoRTFCtrlMethod;
public
constructor Create;
property Code: Integer read FCode write FCode;
property Ctrl: AnsiString read FCtrl write FCtrl;
property Method: TKMemoRTFCtrlMethod read FMethod write FMethod;
end;
{ Specifies the RTF control word table. Is only used by RTF reader. Maybe using hash table would be even faster. }
TKMemoRTFCtrlTable = class(TObjectList)
private
function GetItem(Index: Integer): TKMemoRTFCtrl;
procedure SetItem(Index: Integer; const Value: TKMemoRTFCtrl);
public
procedure AddCtrl(const ACtrl: AnsiString; ACode: Integer; AMethod: TKMemoRTFCtrlMethod);
function FindByCtrl(const ACtrl: AnsiString): TKMemoRtfCtrl; virtual;
procedure SortTable; virtual;
property Items[Index: Integer]: TKMemoRTFCtrl read GetItem write SetItem; default;
end;
{ Specifies the RTF color descriptor. }
TKMemoRTFColor = class(TObject)
private
FColorRec: TKColorRec;
public
constructor Create;
property ColorRec: TKColorRec read FColorRec write FColorRec;
property Red: Byte read FColorRec.R write FColorRec.R;
property Green: Byte read FColorRec.G write FColorRec.G;
property Blue: Byte read FColorRec.B write FColorRec.B;
end;
{ Specifies the RTF color table. }
TKMemoRTFColorTable = class(TObjectList)
private
function GetItem(Index: Integer): TKMemoRTFColor;
procedure SetItem(Index: Integer; const Value: TKMemoRTFColor);
public
procedure AddColor(AColor: TColor); virtual;
function GetColor(AIndex: Integer): TColor; virtual;
function GetIndex(AColor: TColor): Integer; virtual;
property Items[Index: Integer]: TKMemoRTFColor read GetItem write SetItem; default;
end;
{ Specifies the RTF font descriptor. }
TKMemoRTFFont = class(TObject)
private
FFont: TFont;
FFontIndex: Integer;
public
constructor Create;
destructor Destroy; override;
property Font: TFont read FFont;
property FontIndex: Integer read FFontIndex write FFontIndex;
end;
{ Specifies the RTF font table. }
TKMemoRTFFontTable = class(TObjectList)
private
function GetItem(Index: Integer): TKMemoRTFFont;
procedure SetItem(Index: Integer; const Value: TKMemoRTFFont);
public
function AddFont(AFont: TFont): Integer; virtual;
function GetFont(AFontIndex: Integer): TFont; virtual;
function GetIndex(AFont: TFont): Integer; virtual;
property Items[Index: Integer]: TKMemoRTFFont read GetItem write SetItem; default;
end;
{ Specifies the RTF list level descriptor. }
TKMemoRTFListLevel = class(TObject)
private
FFirstIndent: Integer;
FJustify: Integer;
FLeftIndent: Integer;
FNumberType: Integer;
FStartAt: Integer;
FNumberingFormat: TKMemoNumberingFormat;
FFontIndex: Integer;
function GetNumberTypeAsNumbering: TKMemoParaNumbering;
procedure SetNumberTypeAsNumbering(const Value: TKMemoParaNumbering);
public
constructor Create;
destructor Destroy; override;
property FirstIndent: Integer read FFirstIndent write FFirstIndent;
property FontIndex: Integer read FFontIndex write FFontIndex;
property Justify: Integer read FJustify write FJustify;
property LeftIndent: Integer read FLeftIndent write FLeftIndent;
property NumberingFormat: TKMemoNumberingFormat read FNumberingFormat;
property NumberType: Integer read FNumberType write FNumberType;
property NumberTypeAsNumbering: TKMemoParaNumbering read GetNumberTypeAsNumbering write SetNumberTypeAsNumbering;
property StartAt: Integer read FStartAt write FStartAt;
end;
{ Specifies the RTF list levels. }
TKMemoRTFListLevels = class(TObjectList)
private
function GetItem(Index: Integer): TKMemoRTFListLevel;
procedure SetItem(Index: Integer; const Value: TKMemoRTFListLevel);
public
property Items[Index: Integer]: TKMemoRTFListLevel read GetItem write SetItem; default;
end;
TKMemoRTFListTable = class;
{ Specifies the RTF list descriptor. }
TKMemoRTFList = class(TObject)
private
FID: Integer;
FLevels: TKMemoRTFListLevels;
public
constructor Create(AParent: TKMemoRTFListTable);
destructor Destroy; override;
property ID: Integer read FID write FID;
property Levels: TKMemoRTFListLevels read FLevels;
end;
{ Specifies the RTF list table. }
TKMemoRTFListTable = class(TObjectList)
private
FOverrides: TKMemoDictionary;
function GetItem(Index: Integer): TKMemoRTFList;
procedure SetItem(Index: Integer; const Value: TKMemoRTFList);
protected
FIDCounter: Integer;
public
constructor Create;
destructor Destroy; override;
procedure AssignFromListTable(AListTable: TKMemoListTable; AFontTable: TKMemoRTFFontTable);
procedure AssignToListTable(AListTable: TKMemoListTable; AFontTable: TKMemoRTFFontTable);
function FindByID(AListID: Integer): Integer;
function FindByIndex(AIndex: Integer): Integer;
function IDByIndex(AIndex: Integer): Integer;
function NextID: Integer;
property Items[Index: Integer]: TKMemoRTFList read GetItem write SetItem; default;
property Overrides: TKMemoDictionary read FOverrides;
end;
{ Specifies the supported RTF shape object type. }
TKMemoRTFShapeContentType = (sctUnknown, sctTextBox, sctImage, sctRectangle, sctText);
{ Specifies the RTF shape object since KMemo has no generic drawing object support. }
TKMemoRTFShape = class(TObject)
private
FBackground: Boolean;
FContentPosition: TKRect;
FContentType: TKMemoRTFShapeContentType;
FCtrlName: AnsiString;
FCtrlValue: AnsiString;
FFitToShape: Boolean;
FFitToText: Boolean;
FHorzPosCode: Integer;
FBlock: TKMemoBlock;
FStyle: TKMemoBlockStyle;
FVertPosCode: Integer;
FWrap: Integer;
FWrapSide: Integer;
FFillBlip: Boolean;
procedure SetWrap(const Value: Integer);
procedure SetWrapSide(const Value: Integer);
function GetWrap: Integer;
function GetWrapSide: Integer;
protected
procedure RTFWrapToWrapMode; virtual;
procedure WrapModeToRTFWrap; virtual;
public
constructor Create;
destructor Destroy; override;
property Background: Boolean read FBackground write FBackground;
property Block: TKMemoBlock read FBlock write FBlock;
property ContentPosition: TKRect read FContentPosition;
property ContentType: TKMemoRTFShapeContentType read FContentType write FContentType;
property CtrlName: AnsiString read FCtrlName write FCtrlName;
property CtrlValue: AnsiString read FCtrlValue write FCtrlValue;
property FillBlip: Boolean read FFillBlip write FFillBlip;
property FitToShape: Boolean read FFitToShape write FFitToShape;
property FitToText: Boolean read FFitToText write FFitToText;
property HorzPosCode: Integer read FHorzPosCode write FHorzPosCode;
property Style: TKMemoBlockStyle read FStyle;
property VertPosCode: Integer read FVertPosCode write FVertPosCode;
property Wrap: Integer read GetWrap write SetWrap;
property WrapSide: Integer read GetWrapSide write SetWrapSide;
end;
TKMemoRTFGroup = (rgNone, rgUnknown, rgColorTable, rgField, rgFieldInst, rgFieldResult, rgFontTable, rgFooter, rgHeader, rgInfo,
rgListTable, rgList, rgListLevel, rgListLevelText, rgListOverrideTable, rgListOverride, rgPageBackground, rgPicture, rgPicProp,
rgShape, rgShapeInst, rgShapePict, rgStyleSheet, rgTextBox);
{ Specifies the RTF reader state. This class is used by RTF reader to store reader state on the stack. }
TKMemoRTFState = class(TObject)
private
FTextStyle: TKMemoTextStyle;
FParaStyle: TKMemoParaStyle;
FGroup: TKMemoRTFGroup;
public
constructor Create;
destructor Destroy; override;
procedure Assign(ASource: TKmemoRTFState); virtual;
property Group: TKMemoRTFGroup read FGroup write FGroup;
property ParaStyle: TKMemoParaStyle read FParaStyle write FParaStyle;
property TextStyle: TKMemoTextStyle read FTextStyle write FTextStyle;
end;
{ Specifies the stack for the RTF reader state. }
TKMemoRTFStack = class(TStack)
public
function Push(AObject: TKMemoRTFState): TKMemoRTFState;
function Pop: TKMemoRTFState;
function Peek: TKMemoRTFState;
end;
TKMemoRTFHeaderProp = (rphNone, rphRtf, rphCodePage, rphDefaultFont, rphIgnoreCharsAfterUnicode, rphFontTable, rphColorTable, rphStyleSheet);
TKMemoRTFDocumentProp = (rpdNone, rpdFooter, rpdFooterLeft, rpdFooterRight, rpdHeader, rpdHeaderLeft, rpdHeaderRight, rpdInfo);
TKMemoRTFColorProp = (rpcNone, rpcRed, rpcGreen, rpcBlue);
TKMemoRTFFieldProp = (rpfiNone, rpfiField, rpfiResult);
TKMemoRTFFontProp = (rpfNone, rpfIndex, rpfCharset, rpfPitch);
TKMemoRTFImageProp = (rpiNone, rpiPict, rpiJPeg, rpiPng, rpiEmf, rpiWmf, rpiWidth, rpiHeight, rpiCropBottom, rpiCropLeft, rpiCropRight, rpiCropTop,
rpiReqWidth, rpiReqHeight, rpiScaleX, rpiScaleY);
TKMemoRTFListProp = (rplNone, rplList, rplListOverride, rplListLevel, rplListId, rplListIndex, rplListText, rplLevelStartAt, rplLevelNumberType, rplLevelJustify, rplLevelText,
rplLevelFontIndex, rplLevelFirstIndent, rplLevelLeftIndent, rplPnText);
TKMemoRTFParaProp = (rppNone, rppParD, rppIndentFirst, rppIndentBottom, rppIndentLeft, rppIndentRight, rppIndentTop, rppAlignLeft, rppAlignCenter, rppAlignRight, rppAlignJustify,
rppBackColor, rppNoWordWrap, rppBorderBottom, rppBorderLeft, rppBorderRight, rppBorderTop, rppBorderAll, rppBorderWidth, rppBorderNone, rppBorderRadius, rppBorderColor,
rppLineSpacing, rppLineSpacingMode, rppPar, rppListIndex, rppListLevel, rppListStartAt);
TKMemoRTFShapeProp = (rpsNone, rpsShape, rpsBottom, rpsLeft, rpsRight, rpsTop, rpsXColumn, rpsYPara, rpsWrap, rpsWrapSide, rpsSn, rpsSv, rpsShapeText);
TKMemoRTFSpecialCharProp = (rpscNone, rpscTab, rpscLquote, rpscRQuote, rpscLDblQuote, rpscRDblQuote, rpscEnDash, rpscEmDash, rpscBullet, rpscNBSP, rpscEmSpace, rpscEnSpace,
rpscAnsiChar, rpscUnicodeChar);
TKMemoRTFTableProp = (rptbNone, rptbRowBegin, rptbCellEnd, rptbRowEnd, rptbLastRow, rptbRowPaddBottom, rptbRowPaddLeft, rptbRowPaddRight, rptbRowPaddTop, rptbBorderBottom, rptbBorderLeft,
rptbPaddAll, rptbBorderRight, rptbBorderTop, rptbBorderWidth, rptbBorderNone, rptbBorderColor, rptbBackColor, rptbHorzMergeBegin, rptbHorzMerge,
rptbVertMergeBegin, rptbVertMerge, rptbCellPaddBottom, rptbCellPaddLeft, rptbCellPaddRight, rptbCellPaddTop, rptbCellWidth, rptbCellX);
TKMemoRTFTextProp = (rptNone, rptPlain, rptFontIndex, rptBold, rptItalic, rptUnderline, rptStrikeout, rptCaps, rptSmallCaps, rptFontSize, rptForeColor, rptBackColor,
rptSubscript, rptSuperscript);
TKMemoRTFUnknownProp = (rpuNone, rpuUnknownSym, rpuPageBackground, rpuPicProp, rpuShapeInst, rpuShapePict, rpuNonShapePict, rpuFieldInst, rpuListTable, rpuListOverrideTable);
{ Specifies the common ancestor for RTF streaming. }
TKMemoRTFFiler = class(TObject)
private
protected
FMemo: TKCustomMemo;
FStream: TStream;
FTwipsPerPixelX,
FTwipsPerPixelY: Double;
public
constructor Create(AMemo: TKCustomMemo); virtual;
function EMUToPoints(AValue: Integer): Integer; virtual;
function PointsToEMU(AValue: Integer): Integer; virtual;
function PixelsToTwipsX(AValue: Integer): Integer; virtual;
function PixelsToTwipsY(AValue: Integer): Integer; virtual;
function TwipsToPixelsX(AValue: Integer): Integer; virtual;
function TwipsToPixelsY(AValue: Integer): Integer; virtual;
end;
{ Specifies the RTF reader. }
TKMemoRTFReader = class(TKMemoRTFFiler)
private
function GetActiveFont: TKMemoRTFFont;
function GetActiveColor: TKMemoRTFColor;
function GetActiveImage: TKMemoImageBlock;
function GetActiveShape: TKMemoRTFShape;
function GetActiveContainer: TKMemoContainer;
function GetActiveTable: TKMemoTable;
function GetActiveList: TKMemoRTFList;
function GetActiveListLevel: TKMemoRTFListLevel;
function GetActiveListOverride: TKMemoDictionaryItem;
protected
FActiveBlocks: TKMemoBlocks;
FActiveColor: TKMemoRTFColor;
FActiveContainer: TKMemoContainer;
FActiveFont: TKMemoRTFFont;
FActiveImage: TKMemoImageBlock;
FActiveImageClass: TGraphicClass;
FActiveImageIsEMF: Boolean;
FActiveList: TKMemoRTFList;
FActiveListLevel: TKMemoRTFListLevel;
FActiveListOverride: TKMemoDictionaryItem;
FActiveParaBorder: TAlign;
FActiveShape: TKMemoRTFShape;
FActiveString: TKString;
FActiveState: TKMemoRTFState;
FActiveTable: TKMemoTable;
FActiveTableBorder: TAlign;
FActiveTableCell: TKMemoTableCell;
FActiveTableCellXPos: Integer;
FActiveTableCol: Integer;
FActiveTableColCount: Integer;
FActiveTableLastRow: Boolean;
FActiveTableRow: TKMemoTableRow;
FActiveTableRowPadd: TRect;
FActiveText: TKMemoTextBlock;
FActiveURL: TKString;
FAtIndex: TKMemoBlockIndex;
FColorTable: TKMemoRTFColorTable;
FCtrlTable: TKMemoRTFCtrlTable;
FDefaultCodePage: Integer;
FDefaultFontIndex: Integer;
FFontTable: TKMemoRTFFontTable;
FIgnoreChars: Integer;
FIgnoreCharsAfterUnicode: Integer;
FIndexStack: TKMemoIndexObjectStack;
FGraphicClass: TGraphicClass;
FListTable: TKMemoRTFListTable;
FStack: TKMemoRTFStack;
procedure AddText(const APart: TKString); virtual;
procedure AddTextToNumberingFormat(const APart: TKString); virtual;
procedure ApplyFont(ATextStyle: TKMemoTextStyle; AFontIndex: Integer); virtual;
procedure ApplyHighlight(ATextStyle: TKMemoTextStyle; AHighlightCode: Integer); virtual;
procedure FillCtrlTable; virtual;
function ParamToBool(const AValue: AnsiString): Boolean; virtual;
function ParamToColor(const AValue: AnsiString): TColor; virtual;
function ParamToInt(const AValue: AnsiString): Integer; virtual;
function ParamToEMU(const AValue: AnsiString): Integer; virtual;
procedure FlushColor; virtual;
procedure FlushContainer; virtual;
procedure FlushFont; virtual;
procedure FlushHyperlink; virtual;
procedure FlushImage; virtual;
procedure FlushList; virtual;
procedure FlushListLevel; virtual;
procedure FlushListOverride; virtual;
procedure FlushParagraph; virtual;
procedure FlushShape; virtual;
procedure FlushTable; virtual;
procedure FlushText; virtual;
function HighlightCodeToColor(AValue: Integer): TColor; virtual;
procedure PopFromStack(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure PushToStack(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
function ReadNext(out ACtrl, AText: AnsiString; out AParam: Int64): Boolean; virtual;
procedure ReadColorGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadDocumentGroups(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadFieldGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadFontGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadHeaderGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadListGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadParaFormatting(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadPictureGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadShapeGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadSpecialCharacter(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadStream; virtual;
procedure ReadTableFormatting(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadTextFormatting(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
procedure ReadUnknownGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer); virtual;
property ActiveColor: TKMemoRTFColor read GetActiveColor;
property ActiveContainer: TKMemoContainer read GetActiveContainer;
property ActiveFont: TKMemoRTFFont read GetActiveFont;
property ActiveList: TKMemoRTFList read GetActiveList;
property ActiveListLevel: TKMemoRTFListLevel read GetActiveListLevel;
property ActiveListOverride: TKMemoDictionaryItem read GetActiveListOverride;
property ActiveImage: TKMemoImageBlock read GetActiveImage;
property ActiveShape: TKMemoRTFShape read GetActiveShape;
property ActiveTable: TKMemoTable read GetActiveTable;
public
constructor Create(AMemo: TKCustomMemo); override;
destructor Destroy; override;
procedure LoadFromFile(const AFileName: TKString; AActiveBlocks: TKMemoBlocks; AtIndex: TKMemoSelectionIndex); virtual;
procedure LoadFromStream(AStream: TStream; AActiveBlocks: TKMemoBlocks; AtIndex: TKMemoSelectionIndex); virtual;
end;
{ Specifies the RTF writer. }
TKMemoRTFWriter = class(TKMemoRTFFiler)
private
FReadableOutput: Boolean;
protected
FCodePage: Integer;
FColorTable: TKMemoRTFColorTable;
FFontTable: TKMemoRTFFontTable;
FGroupLevel: Integer;
FListTable: TKMemoRTFListTable;
FSelectedOnly: Boolean;
function BoolToParam(AValue: Boolean): AnsiString; virtual;
function CanSave(ABlock: TKMemoBlock): Boolean; virtual;
function ColorToHighlightCode(AValue: TColor): Integer; virtual;
function ColorToParam(AValue: TColor): AnsiString; virtual;
function EMUToParam(AValue: Integer): AnsiString; virtual;
procedure FillColorTable(ABlocks: TKMemoBlocks); virtual;
procedure FillFontTable(ABlocks: TKMemoBlocks); virtual;
procedure WriteBackground; virtual;
procedure WriteBody(ABlocks: TKMemoBlocks; AInsideOfTable: Boolean); virtual;
procedure WriteColorTable; virtual;
procedure WriteContainer(ABlock: TKMemoContainer; AInsideTable: Boolean); virtual;
procedure WriteCtrl(const ACtrl: AnsiString);
procedure WriteCtrlParam(const ACtrl: AnsiString; AParam: Integer);
procedure WriteFontTable; virtual;
procedure WriteGroupBegin;
procedure WriteGroupEnd;
procedure WriteHeader(ABlocks: TKMemoBlocks); virtual;
procedure WriteHyperlinkBegin(ABlock: TKMemoHyperlink); virtual;
procedure WriteHyperlinkEnd; virtual;
procedure WriteImage(ABlock: TKmemoImageBlock); virtual;
procedure WriteImageBlock(ABlock: TKmemoImageBlock; AInsideTable: Boolean); virtual;
procedure WriteListTable; virtual;
procedure WriteListText(ANumberBlock: TKMemoTextBlock); virtual;
procedure WriteParagraph(ABlock: TKMemoParagraph; AInsideTable: Boolean); virtual;
procedure WriteParaStyle(AParaStyle: TKMemoParaStyle); virtual;
procedure WritePicture(AImage: TGraphic); virtual;
procedure WriteSemiColon;
procedure WriteShape(AShape: TKMemoRTFShape; AInsideTable: Boolean); virtual;
procedure WriteShapeProp(const APropName, APropValue: AnsiString); virtual;
procedure WriteShapeProperties(AShape: TKMemoRTFShape); virtual;
procedure WriteShapePropName(const APropName: AnsiString);
procedure WriteShapePropValue(const APropValue: AnsiString);
procedure WriteSpace;
procedure WriteString(const AText: AnsiString);
procedure WriteTable(ABlock: TKMemoTable); virtual;
procedure WriteTableRowProperties(ATable: TKMemoTable; ARowIndex, ASavedRowIndex: Integer); virtual;
procedure WriteTextBlock(ABlock: TKMemoTextBlock; ASelectedOnly: Boolean); virtual;
procedure WriteTextStyle(ATextStyle: TKMemoTextStyle); virtual;
procedure WriteUnicodeString(const AText: TKString); virtual;
procedure WriteUnknownGroup;
public
constructor Create(AMemo: TKCustomMemo); override;
destructor Destroy; override;
procedure SaveToFile(const AFileName: TKString; ASelectedOnly: Boolean); virtual;
procedure SaveToStream(AStream: TStream; ASelectedOnly: Boolean; AActiveBlocks: TKMemoBlocks = nil); virtual;
property ReadableOutput: Boolean read FReadableOutput write FReadableOutput;
end;
function CharSetToCP(ACharSet: TFontCharSet): Integer;
function CPToCharSet(ACodePage: Integer): TFontCharSet;
implementation
uses
Math, SysUtils, KEditCommon, KHexEditor, KRes
{$IFDEF FPC}
, LCLIntf, LCLProc, LConvEncoding, LCLType, LazUTF8
{$ELSE}
, JPeg, Windows
{$ENDIF}
;
const
cRTFHyperlink = 'HYPERLINK';
function CharSetToCP(ACharSet: TFontCharSet): Integer;
begin
case ACharset of
1: Result := 0; //Default
2: Result := 42; //Symbol
77: Result := 10000; //Mac Roman
78: Result := 10001; //Mac Shift Jis
79: Result := 10003; //Mac Hangul
80: Result := 10008; //Mac GB2312
81: Result := 10002; //Mac Big5
83: Result := 10005; //Mac Hebrew
84: Result := 10004; //Mac Arabic
85: Result := 10006; //Mac Greek
86: Result := 10081; //Mac Turkish
87: Result := 10021; //Mac Thai
88: Result := 10029; //Mac East Europe
89: Result := 10007; //Mac Russian
128: Result := 932; //Shift JIS
129: Result := 949; //Hangul
130: Result := 1361; //Johab
134: Result := 936; //GB2312
136: Result := 950; //Big5
161: Result := 1253; //Greek
162: Result := 1254; //Turkish
163: Result := 1258; //Vietnamese
177: Result := 1255; //Hebrew
178: Result := 1256; //Arabic
186: Result := 1257; //Baltic
204: Result := 1251; //Russian
222: Result := 874; //Thai
238: Result := 1250; //Eastern European
254: Result := 437; //PC 437
255: Result := 850; //OEM
else
Result := SystemCodePage; //system default
end;
end;
function CPToCharSet(ACodePage: Integer): TFontCharSet;
begin
case ACodePage of
0: Result := 1; //Default
42: Result := 2; //Symbol
10000: Result := 77; //Mac Roman
10001: Result := 78; //Mac Shift Jis
10003: Result := 79; //Mac Hangul
10008: Result := 80; //Mac GB2312
10002: Result := 81; //Mac Big5
10005: Result := 83; //Mac Hebrew
10004: Result := 84; //Mac Arabic
10006: Result := 85; //Mac Greek
10081: Result := 86; //Mac Turkish
10021: Result := 87; //Mac Thai
10029: Result := 88; //Mac East Europe
10007: Result := 89; //Mac Russian
932: Result := 128; //Shift JIS
949: Result := 129; //Hangul
1361: Result := 130; //Johab
936: Result := 134; //GB2312
950: Result := 136; //Big5
1253: Result := 161; //Greek
1254: Result := 162; //Turkish
1258: Result := 163; //Vietnamese
1255: Result := 177; //Hebrew
1256: Result := 178; //Arabic
1257: Result := 186; //Baltic
1251: Result := 204; //Russian
874: Result := 222; //Thai
1250: Result := 238; //Eastern European
437: Result := 254; //PC 437
850: Result := 255; //OEM
else
Result := 0; //ANSI
end;
end;
function AdobeSymbolToUTF16(AValue: Integer): Integer;
begin
case AValue of
$20: Result := $0020; //SPACE //space
{/$20: Result := $00A0; //NO-BREAK SPACE //space }
$21: Result := $0021; //EXCLAMATION MARK //exclam
$22: Result := $2200; //FOR ALL //universal
$23: Result := $0023; //NUMBER SIGN //numbersign
$24: Result := $2203; //THERE EXISTS //existential
$25: Result := $0025; //PERCENT SIGN //percent
$26: Result := $0026; //AMPERSAND //ampersand
$27: Result := $220B; //CONTAINS AS MEMBER //suchthat
$28: Result := $0028; //LEFT PARENTHESIS //parenleft
$29: Result := $0029; //RIGHT PARENTHESIS //parenright
$2A: Result := $2217; //ASTERISK OPERATOR //asteriskmath
$2B: Result := $002B; //PLUS SIGN //plus
$2C: Result := $002C; //COMMA //comma
$2D: Result := $2212; //MINUS SIGN //minus
$2E: Result := $002E; //FULL STOP //period
$2F: Result := $002F; //SOLIDUS //slash
$30: Result := $0030; //DIGIT ZERO //zero
$31: Result := $0031; //DIGIT ONE //one
$32: Result := $0032; //DIGIT TWO //two
$33: Result := $0033; //DIGIT THREE //three
$34: Result := $0034; //DIGIT FOUR //four
$35: Result := $0035; //DIGIT FIVE //five
$36: Result := $0036; //DIGIT SIX //six
$37: Result := $0037; //DIGIT SEVEN //seven
$38: Result := $0038; //DIGIT EIGHT //eight
$39: Result := $0039; //DIGIT NINE //nine
$3A: Result := $003A; //COLON //colon
$3B: Result := $003B; //SEMICOLON //semicolon
$3C: Result := $003C; //LESS-THAN SIGN //less
$3D: Result := $003D; //EQUALS SIGN //equal
$3E: Result := $003E; //GREATER-THAN SIGN //greater
$3F: Result := $003F; //QUESTION MARK //question
$40: Result := $2245; //APPROXIMATELY EQUAL TO //congruent
$41: Result := $0391; //GREEK CAPITAL LETTER ALPHA //Alpha
$42: Result := $0392; //GREEK CAPITAL LETTER BETA //Beta
$43: Result := $03A7; //GREEK CAPITAL LETTER CHI //Chi
$44: Result := $0394; //GREEK CAPITAL LETTER DELTA //Delta
{/$44: Result := $2206; //INCREMENT //Delta}
$45: Result := $0395; //GREEK CAPITAL LETTER EPSILON //Epsilon
$46: Result := $03A6; //GREEK CAPITAL LETTER PHI //Phi
$47: Result := $0393; //GREEK CAPITAL LETTER GAMMA //Gamma
$48: Result := $0397; //GREEK CAPITAL LETTER ETA //Eta
$49: Result := $0399; //GREEK CAPITAL LETTER IOTA //Iota
$4A: Result := $03D1; //GREEK THETA SYMBOL //theta1
$4B: Result := $039A; //GREEK CAPITAL LETTER KAPPA //Kappa
$4C: Result := $039B; //GREEK CAPITAL LETTER LAMDA //Lambda
$4D: Result := $039C; //GREEK CAPITAL LETTER MU //Mu
$4E: Result := $039D; //GREEK CAPITAL LETTER NU //Nu
$4F: Result := $039F; //GREEK CAPITAL LETTER OMICRON //Omicron
$50: Result := $03A0; //GREEK CAPITAL LETTER PI //Pi
$51: Result := $0398; //GREEK CAPITAL LETTER THETA //Theta
$52: Result := $03A1; //GREEK CAPITAL LETTER RHO //Rho
$53: Result := $03A3; //GREEK CAPITAL LETTER SIGMA //Sigma
$54: Result := $03A4; //GREEK CAPITAL LETTER TAU //Tau
$55: Result := $03A5; //GREEK CAPITAL LETTER UPSILON //Upsilon
$56: Result := $03C2; //GREEK SMALL LETTER FINAL SIGMA //sigma1
$57: Result := $03A9; //GREEK CAPITAL LETTER OMEGA //Omega
{/$57: Result := $2126; //OHM SIGN //Omega}
$58: Result := $039E; //GREEK CAPITAL LETTER XI //Xi
$59: Result := $03A8; //GREEK CAPITAL LETTER PSI //Psi
$5A: Result := $0396; //GREEK CAPITAL LETTER ZETA //Zeta
$5B: Result := $005B; //LEFT SQUARE BRACKET //bracketleft
$5C: Result := $2234; //THEREFORE //therefore
$5D: Result := $005D; //RIGHT SQUARE BRACKET //bracketright
$5E: Result := $22A5; //UP TACK //perpendicular
$5F: Result := $005F; //LOW LINE //underscore
$60: Result := $F8E5; //RADICAL EXTENDER //radicalex (CUS)
$61: Result := $03B1; //GREEK SMALL LETTER ALPHA //alpha
$62: Result := $03B2; //GREEK SMALL LETTER BETA //beta
$63: Result := $03C7; //GREEK SMALL LETTER CHI //chi
$64: Result := $03B4; //GREEK SMALL LETTER DELTA //delta
$65: Result := $03B5; //GREEK SMALL LETTER EPSILON //epsilon
$66: Result := $03C6; //GREEK SMALL LETTER PHI //phi
$67: Result := $03B3; //GREEK SMALL LETTER GAMMA //gamma
$68: Result := $03B7; //GREEK SMALL LETTER ETA //eta
$69: Result := $03B9; //GREEK SMALL LETTER IOTA //iota
$6A: Result := $03D5; //GREEK PHI SYMBOL //phi1
$6B: Result := $03BA; //GREEK SMALL LETTER KAPPA //kappa
$6C: Result := $03BB; //GREEK SMALL LETTER LAMDA //lambda
$6D: Result := $00B5; //MICRO SIGN //mu
{/$6D: Result := $03BC; //GREEK SMALL LETTER MU //mu}
$6E: Result := $03BD; //GREEK SMALL LETTER NU //nu
$6F: Result := $03BF; //GREEK SMALL LETTER OMICRON //omicron
$70: Result := $03C0; //GREEK SMALL LETTER PI //pi
$71: Result := $03B8; //GREEK SMALL LETTER THETA //theta
$72: Result := $03C1; //GREEK SMALL LETTER RHO //rho
$73: Result := $03C3; //GREEK SMALL LETTER SIGMA //sigma
$74: Result := $03C4; //GREEK SMALL LETTER TAU //tau
$75: Result := $03C5; //GREEK SMALL LETTER UPSILON //upsilon
$76: Result := $03D6; //GREEK PI SYMBOL //omega1
$77: Result := $03C9; //GREEK SMALL LETTER OMEGA //omega
$78: Result := $03BE; //GREEK SMALL LETTER XI //xi
$79: Result := $03C8; //GREEK SMALL LETTER PSI //psi
$7A: Result := $03B6; //GREEK SMALL LETTER ZETA //zeta
$7B: Result := $007B; //LEFT CURLY BRACKET //braceleft
$7C: Result := $007C; //VERTICAL LINE //bar
$7D: Result := $007D; //RIGHT CURLY BRACKET //braceright
$7E: Result := $007E; //TILDE OPERATOR //similar
$A0: Result := $20AC; //EURO SIGN //Euro
$A1: Result := $03D2; //GREEK UPSILON WITH HOOK SYMBOL //Upsilon1
$A2: Result := $2032; //PRIME //minute
$A3: Result := $2264; //LESS-THAN OR EQUAL TO //lessequal
$A4: Result := $2044; //FRACTION SLASH //fraction
{/$A4: Result := $2215; //DIVISION SLASH //fraction}
$A5: Result := $221E; //INFINITY //infinity
$A6: Result := $0192; //LATIN SMALL LETTER F WITH HOOK //florin
$A7: Result := $2663; //BLACK CLUB SUIT //club
$A8: Result := $2666; //BLACK DIAMOND SUIT //diamond
$A9: Result := $2665; //BLACK HEART SUIT //heart
$AA: Result := $2660; //BLACK SPADE SUIT //spade
$AB: Result := $2194; //LEFT RIGHT ARROW //arrowboth
$AC: Result := $2190; //LEFTWARDS ARROW //arrowleft
$AD: Result := $2191; //UPWARDS ARROW //arrowup
$AE: Result := $2192; //RIGHTWARDS ARROW //arrowright
$AF: Result := $2193; //DOWNWARDS ARROW //arrowdown
$B0: Result := $00B0; //DEGREE SIGN //degree
$B1: Result := $00B1; //PLUS-MINUS SIGN //plusminus
$B2: Result := $2033; //DOUBLE PRIME //second
$B3: Result := $2265; //GREATER-THAN OR EQUAL TO //greaterequal
$B4: Result := $00D7; //MULTIPLICATION SIGN //multiply
$B5: Result := $221D; //PROPORTIONAL TO //proportional
$B6: Result := $2202; //PARTIAL DIFFERENTIAL //partialdiff
$B7: Result := $2022; //BULLET //bullet
$B8: Result := $00F7; //DIVISION SIGN //divide
$B9: Result := $2260; //NOT EQUAL TO //notequal
$BA: Result := $2261; //IDENTICAL TO //equivalence
$BB: Result := $2248; //ALMOST EQUAL TO //approxequal
$BC: Result := $2026; //HORIZONTAL ELLIPSIS //ellipsis
$BD: Result := $F8E6; //VERTICAL ARROW EXTENDER //arrowvertex (CUS)
$BE: Result := $F8E7; //HORIZONTAL ARROW EXTENDER //arrowhorizex (CUS)
$BF: Result := $21B5; //DOWNWARDS ARROW WITH CORNER LEFTWARDS //carriagereturn
$C0: Result := $2135; //ALEF SYMBOL //aleph
$C1: Result := $2111; //BLACK-LETTER CAPITAL I //Ifraktur
$C2: Result := $211C; //BLACK-LETTER CAPITAL R //Rfraktur
$C3: Result := $2118; //SCRIPT CAPITAL P //weierstrass
$C4: Result := $2297; //CIRCLED TIMES //circlemultiply
$C5: Result := $2295; //CIRCLED PLUS //circleplus
$C6: Result := $2205; //EMPTY SET //emptyset
$C7: Result := $2229; //INTERSECTION //intersection
$C8: Result := $222A; //UNION //union
$C9: Result := $2283; //SUPERSET OF //propersuperset
$CA: Result := $2287; //SUPERSET OF OR EQUAL TO //reflexsuperset
$CB: Result := $2284; //NOT A SUBSET OF //notsubset
$CC: Result := $2282; //SUBSET OF //propersubset
$CD: Result := $2286; //SUBSET OF OR EQUAL TO //reflexsubset
$CE: Result := $2208; //ELEMENT OF //element
$CF: Result := $2209; //NOT AN ELEMENT OF //notelement
$D0: Result := $2220; //ANGLE //angle
$D1: Result := $2207; //NABLA //gradient
$D2: Result := $F6DA; //REGISTERED SIGN SERIF //registerserif (CUS)
$D3: Result := $F6D9; //COPYRIGHT SIGN SERIF //copyrightserif (CUS)
$D4: Result := $F6DB; //TRADE MARK SIGN SERIF //trademarkserif (CUS)
$D5: Result := $220F; //N-ARY PRODUCT //product
$D6: Result := $221A; //SQUARE ROOT //radical
$D7: Result := $22C5; //DOT OPERATOR //dotmath
$D8: Result := $00AC; //NOT SIGN //logicalnot
$D9: Result := $2227; //LOGICAL AND //logicaland
$DA: Result := $2228; //LOGICAL OR //logicalor
$DB: Result := $21D4; //LEFT RIGHT DOUBLE ARROW //arrowdblboth
$DC: Result := $21D0; //LEFTWARDS DOUBLE ARROW //arrowdblleft
$DD: Result := $21D1; //UPWARDS DOUBLE ARROW //arrowdblup
$DE: Result := $21D2; //RIGHTWARDS DOUBLE ARROW //arrowdblright
$DF: Result := $21D3; //DOWNWARDS DOUBLE ARROW //arrowdbldown
$E0: Result := $25CA; //LOZENGE //lozenge
$E1: Result := $2329; //LEFT-POINTING ANGLE BRACKET //angleleft
$E2: Result := $F8E8; //REGISTERED SIGN SANS SERIF //registersans (CUS)
$E3: Result := $F8E9; //COPYRIGHT SIGN SANS SERIF //copyrightsans (CUS)
$E4: Result := $F8EA; //TRADE MARK SIGN SANS SERIF //trademarksans (CUS)
$E5: Result := $2211; //N-ARY SUMMATION //summation
$E6: Result := $F8EB; //LEFT PAREN TOP //parenlefttp (CUS)
$E7: Result := $F8EC; //LEFT PAREN EXTENDER //parenleftex (CUS)
$E8: Result := $F8ED; //LEFT PAREN BOTTOM //parenleftbt (CUS)
$E9: Result := $F8EE; //LEFT SQUARE BRACKET TOP //bracketlefttp (CUS)
$EA: Result := $F8EF; //LEFT SQUARE BRACKET EXTENDER //bracketleftex (CUS)
$EB: Result := $F8F0; //LEFT SQUARE BRACKET BOTTOM //bracketleftbt (CUS)
$EC: Result := $F8F1; //LEFT CURLY BRACKET TOP //bracelefttp (CUS)
$ED: Result := $F8F2; //LEFT CURLY BRACKET MID //braceleftmid (CUS)
$EE: Result := $F8F3; //LEFT CURLY BRACKET BOTTOM //braceleftbt (CUS)
$EF: Result := $F8F4; //CURLY BRACKET EXTENDER //braceex (CUS)
$F1: Result := $232A; //RIGHT-POINTING ANGLE BRACKET //angleright
$F2: Result := $222B; //INTEGRAL //integral
$F3: Result := $2320; //TOP HALF INTEGRAL //integraltp
$F4: Result := $F8F5; //INTEGRAL EXTENDER //integralex (CUS)
$F5: Result := $2321; //BOTTOM HALF INTEGRAL //integralbt
$F6: Result := $F8F6; //RIGHT PAREN TOP //parenrighttp (CUS)
$F7: Result := $F8F7; //RIGHT PAREN EXTENDER //parenrightex (CUS)
$F8: Result := $F8F8; //RIGHT PAREN BOTTOM //parenrightbt (CUS)
$F9: Result := $F8F9; //RIGHT SQUARE BRACKET TOP //bracketrighttp (CUS)
$FA: Result := $F8FA; //RIGHT SQUARE BRACKET EXTENDER //bracketrightex (CUS)
$FB: Result := $F8FB; //RIGHT SQUARE BRACKET BOTTOM //bracketrightbt (CUS)
$FC: Result := $F8FC; //RIGHT CURLY BRACKET TOP //bracerighttp (CUS)
$FD: Result := $F8FD; //RIGHT CURLY BRACKET MID //bracerightmid (CUS)
$FE: Result := $F8FE; //RIGHT CURLY BRACKET BOTTOM //bracerightbt (CUS)
else
Result := AValue;
end;
end;
{ TKMemoRTFCtrlItem }
constructor TKMemoRTFCtrl.Create;
begin
FCode := 0;
FCtrl := '';
FMethod := nil;
end;
{ TKMemoRTFCtrlTable }
function KMemoRTFSearchCompare(Data: Pointer; Index: Integer; KeyPtr: Pointer): Integer;
var
Tbl: TKMemoRTFCtrlTable;
TblCtrl, Ctrl: AnsiString;
begin
Tbl := TKMemoRTFCtrlTable(Data);
Ctrl := AnsiString(keyPtr);
TblCtrl := Tbl[Index].Ctrl;
if Ctrl > TblCtrl then
Result := 1
else if Ctrl < TblCtrl then
Result := -1
else
Result := 0;
end;
function KMemoRTFSortCompare(Data: Pointer; Index1, Index2: Integer): Integer;
var
Tbl: TKMemoRTFCtrlTable;
TblCtrl1, TblCtrl2: AnsiString;
begin
Tbl := TKMemoRTFCtrlTable(Data);
TblCtrl1 := Tbl[Index1].Ctrl;
TblCtrl2 := Tbl[Index2].Ctrl;
if TblCtrl1 > TblCtrl2 then
Result := 1
else if TblCtrl1 < TblCtrl2 then
Result := -1
else
Result := 0;
end;
procedure KMemoRTFSortExchange(Data: Pointer; Index1, Index2: Integer);
var
Tbl: TKMemoRTFCtrlTable;
begin
Tbl := TKMemoRTFCtrlTable(Data);
Tbl.Exchange(Index1, Index2);
end;
procedure TKMemoRTFCtrlTable.AddCtrl(const ACtrl: AnsiString; ACode: Integer; AMethod: TKMemoRTFCtrlMethod);
var
Item: TKMemoRTFCtrl;
begin
Item := TKMemoRTFCtrl.Create;
Item.Ctrl := ACtrl;
Item.Code := ACode;
Item.Method := AMethod;
inherited Add(Item);
end;
function TKMemoRTFCtrlTable.FindByCtrl(const ACtrl: AnsiString): TKMemoRtfCtrl;
var
Index: Integer;
begin
Index := BinarySearch(Self, Count, Pointer(ACtrl), KMemoRTFSearchCompare, True);
if Index >= 0 then
Result := Items[Index]
else
Result := nil;
end;
function TKMemoRTFCtrlTable.GetItem(Index: Integer): TKMemoRTFCtrl;
begin
Result := TKMemoRTFCtrl(inherited GetItem(Index));
end;
procedure TKMemoRTFCtrlTable.SetItem(Index: Integer; const Value: TKMemoRTFCtrl);
begin
inherited SetItem(Index, Value);
end;
procedure TKMemoRTFCtrlTable.SortTable;
begin
QuickSort(Self, Count, KMemoRTFSortCompare, KMemoRTFSortExchange, True);
end;
{ TKMemoRTFColor }
constructor TKMemoRTFColor.Create;
begin
FColorRec.Value := 0;
end;
{ TKMemoRTFColorTable }
procedure TKMemoRTFColorTable.AddColor(AColor: TColor);
var
RTFColor: TKMemoRTFColor;
begin
if AColor <> clNone then
begin
if GetIndex(AColor) < 0 then
begin
RTFColor := TKMemoRTFColor.Create;
RTFColor.ColorRec := ColorToColorRec(AColor);
Add(RTFColor);
end;
end;
end;
function TKMemoRTFColorTable.getColor(AIndex: Integer): TColor;
begin
if (AIndex >= 0) and (AIndex < Count) then
Result := ColorRecToColor(Items[AIndex].ColorRec)
else
Result := clNone;
end;
function TKMemoRTFColorTable.GetIndex(AColor: TColor): Integer;
var
I: Integer;
Color, ColorRec: TKColorRec;
begin
Color := ColorToColorRec(AColor);
Result := -1;
for I := 0 to Count - 1 do
begin
ColorRec := Items[I].ColorRec;
if ColorRec.Value = Color.Value then
begin
Result := I;
Break;
end;
end;
end;
function TKMemoRTFColorTable.GetItem(Index: Integer): TKMemoRTFColor;
begin
Result := TKMemoRTFColor(inherited GetItem(Index));
end;
procedure TKMemoRTFColorTable.SetItem(Index: Integer; const Value: TKMemoRTFColor);
begin
inherited SetItem(Index, Value);
end;
{ TKMemoRTFFont }
constructor TKMemoRTFFont.Create;
begin
FFont := TFont.Create;
end;
destructor TKMemoRTFFont.Destroy;
begin
FFont.Free;
inherited;
end;
{ TKMemoRTFFontTable }
function TKMemoRTFFontTable.AddFont(AFont: TFont): Integer;
var
RTFFont: TKMemoRTFFont;
begin
Result := GetIndex(AFont);
if Result < 0 then
begin
RTFFont := TKmemoRTFFont.Create;
RTFFont.Font.Assign(AFont);
RTFFont.FontIndex := Count;
Result := Add(RTFFont);
end;
end;
function TKMemoRTFFontTable.GetFont(AFontIndex: Integer): TFont;
var
I: Integer;
Item: TKMemoRTFFont;
begin
Result := nil;
for I := 0 to Count - 1 do
begin
Item := Items[I];
if Item.FontIndex = AFontIndex then
begin
Result := Item.Font;
Exit;
end;
end;
end;
function TKMemoRTFFontTable.GetIndex(AFont: TFont): Integer;
var
I: Integer;
Font: TFont;
begin
Result := -1;
for I := 0 to Count - 1 do
begin
Font := Items[I].Font;
if (Font.Name = AFont.Name) and (Font.Charset = AFont.Charset) and (Font.Pitch = AFont.Pitch) then
begin
Result := I;
Break;
end;
end;
end;
function TKMemoRTFFontTable.GetItem(Index: Integer): TKMemoRTFFont;
begin
Result := TKMemoRTFFont(inherited GetItem(Index));
end;
procedure TKMemoRTFFontTable.SetItem(Index: Integer;
const Value: TKMemoRTFFont);
begin
inherited SetItem(Index, Value);
end;
{ TKMemoRTFListLevel }
constructor TKMemoRTFListLevel.Create;
begin
FFirstIndent := 0;
FFontIndex := -1;
FNumberingFormat := TKMemoNumberingFormat.Create;
FJustify := 0;
FLeftIndent := 0;
FNumberType := 0;
FStartAt := 1;
end;
destructor TKMemoRTFListLevel.Destroy;
begin
FNumberingFormat.Free;
inherited;
end;
function TKMemoRTFListLevel.GetNumberTypeAsNumbering: TKMemoParaNumbering;
begin
// we support only basic types of Word numberings...
case FNumberType of
1: Result := pnuRomanHi;
2: Result := pnuRomanLo;
3: Result := pnuLetterHi;
4: Result := pnuLetterLo;
23: Result := pnuBullets;
255: Result := pnuNone;
else
Result := pnuArabic;
end;
end;
procedure TKMemoRTFListLevel.SetNumberTypeAsNumbering(const Value: TKMemoParaNumbering);
begin
case Value of
pnuBullets, pnuTriangleBullets, pnuArrowOneBullets, pnuArrowTwoBullets, pnuCircleBullets: FNumberType := 23; // maps to bullet, TODO: find out how other bullet styles are stored in RTF...
pnuArabic: FNumberType := 0;
pnuLetterLo: FNumberType := 4;
pnuLetterHi: FNumberType := 3;
pnuRomanLo: FNumberType := 2;
pnuRomanHi: FNumberType := 1;
else
FNumberType := 255; // pnuNone
end;
end;
{ TKMemoRTFListLevels }
function TKMemoRTFListLevels.GetItem(Index: Integer): TKMemoRTFListLevel;
begin
Result := TKMemoRTFListLevel(inherited GetItem(Index));
end;
procedure TKMemoRTFListLevels.SetItem(Index: Integer; const Value: TKMemoRTFListLevel);
begin
inherited SetItem(Index, Value);
end;
{ TKMemoRTFList }
constructor TKMemoRTFList.Create(AParent: TKMemoRTFListTable);
begin
if AParent <> nil then
FID := AParent.NextID
else
FID := Random(MaxInt);
FLevels := TKMemoRTFListLevels.Create;
end;
destructor TKMemoRTFList.Destroy;
begin
FLevels.Free;
inherited;
end;
{ TKMemoRTFListTable }
constructor TKMemoRTFListTable.Create;
begin
inherited;
FIdCounter := 0;
FOverrides := TKMemoDictionary.Create;
end;
destructor TKMemoRTFListTable.Destroy;
begin
FOverrides.Free;
inherited;
end;
procedure TKMemoRTFListTable.AssignFromListTable(AListTable: TKMemoListTable; AFontTable: TKMemoRTFFontTable);
var
List: TKMemoList;
ListLevel: TKMemoListLevel;
RTFList: TKMemoRTFList;
RTFListLevel: TKMemoRTFListLevel;
NFItem: TKMemoNumberingFormatItem;
I, J, K, Len: Integer;
begin
Clear;
for I := 0 to AListTable.Count - 1 do
begin
List := AListTable.Items[I];
RTFList := TKMemoRTFList.Create(Self);
RTFList.ID := List.ID;
for J := 0 to List.Levels.Count - 1 do
begin
ListLevel := List.Levels[J];
RTFListLevel := TKMemoRTFListLevel.Create;
RTFListLevel.FirstIndent := ListLevel.FirstIndent;
RTFListLevel.LeftIndent := ListLevel.LeftIndent;
if ListLevel.NumberingFontChanged then
RTFListLevel.FontIndex := AFontTable.AddFont(ListLevel.NumberingFont);
RTFListLevel.NumberTypeAsNumbering := ListLevel.Numbering;
RTFListLevel.NumberingFormat.Assign(ListLevel.NumberingFormat);
// fixup numbering format for RTF save
// add length field
Len := 0;
for K := 0 to RTFListLevel.NumberingFormat.Count - 1 do
begin
NFItem := RTFListLevel.NumberingFormat[K];
if (NFItem.Level >= 0) and (NFItem.Text = '') then
Inc(Len)
else
Inc(Len, StringLength(NFItem.Text));
end;
RTFListLevel.NumberingFormat.InsertItem(0, Len, '');
RTFListLevel.StartAt := ListLevel.NumberStartAt;
RTFList.Levels.Add(RTFListLevel);
end;
Add(RTFList);
FOverrides.AddItem(I, RTFList.ID);
end;
end;
procedure TKMemoRTFListTable.AssignToListTable(AListTable: TKMemoListTable; AFontTable: TKMemoRTFFontTable);
var
List: TKMemoList;
ListLevel: TKMemoListLevel;
RTFList: TKMemoRTFList;
RTFListLevel: TKMemoRTFListLevel;
NFItem: TKMemoNumberingFormatItem;
Font: TFont;
I, J, K, L, UnicodeValue: Integer;
S: TKString;
begin
AListTable.LockUpdate;
try
for I := 0 to Count - 1 do
begin
RTFList := Items[I];
List := AListTable.FindByID(RTFList.ID);
if List = nil then
begin
List := TKMemoList.Create;
List.Parent := AListTable;
List.ID := RTFList.ID;
AListTable.Add(List);
end;
List.Levels.Clear;
for J := 0 to RTFList.Levels.Count - 1 do
begin
RTFListLevel := RTFList.Levels[J];
ListLevel := TKMemoListLevel.Create;
ListLevel.Parent := List.Levels;
ListLevel.FirstIndent := RTFListLevel.FirstIndent;
ListLevel.LeftIndent := RTFListLevel.LeftIndent;
ListLevel.Numbering := RTFListLevel.NumberTypeAsNumbering;
ListLevel.NumberingFormat.Assign(RTFListLevel.NumberingFormat);
ListLevel.NumberStartAt := RTFListLevel.StartAt;
if RTFListLevel.FontIndex >= 0 then
begin
Font := AFontTable.GetFont(RTFListLevel.FontIndex);
if Font <> nil then
begin
ListLevel.NumberingFont.Assign(Font);
if ListLevel.NumberingFont.Name = 'Symbol' then
begin
ListLevel.NumberingFont.Name := 'Arial';
ListLevel.NumberingFont.Charset := 0;
for K := 0 to ListLevel.NumberingFormat.Count - 1 do
begin
NFItem := ListLevel.NumberingFormat[K];
S := '';
for L := 1 to StringLength(NFItem.Text) do
begin
UnicodeValue := Ord(NativeUTFToUnicode(StringCopy(NFItem.Text, L, 1)));
S := S + UnicodeToNativeUTF(WideChar(AdobeSymbolToUTF16(Byte(UnicodeValue))));
end;
NFItem.Text := S;
end;
end;
end;
end;
List.Levels.Add(ListLevel);
end;
end;
finally
AListTable.UnLockUpdate;
end;
end;
function TKMemoRTFListTable.FindByID(AListID: Integer): Integer;
var
I: Integer;
begin
Result := -1;
for I := 0 to Count - 1 do
if Items[I].ID = AListID then
begin
Result := I;
Break;
end;
end;
function TKMemoRTFListTable.FindByIndex(AIndex: Integer): Integer;
var
I: Integer;
begin
Result := -1;
for I := 0 to FOverrides.Count - 1 do
if FOverrides.Items[I].Index = AIndex then
begin
Result := FindByID(FOverrides.Items[I].Value);
Break;
end;
end;
function TKMemoRTFListTable.GetItem(Index: Integer): TKMemoRTFList;
begin
Result := TKMemoRTFList(inherited GetItem(Index));
end;
function TKMemoRTFListTable.IDByIndex(AIndex: Integer): Integer;
var
I: Integer;
begin
I := FindByIndex(AIndex);
if I >= 0 then
Result := Items[I].ID
else
Result := cInvalidListID;
end;
function TKMemoRTFListTable.NextID: Integer;
begin
Result := FIDCounter;
Inc(FIDCounter);
end;
procedure TKMemoRTFListTable.SetItem(Index: Integer; const Value: TKMemoRTFList);
begin
inherited SetItem(Index, Value);
end;
{ TKMemoRTFShape }
constructor TKMemoRTFShape.Create;
begin
FBackground := False;
FContentPosition := TKRect.Create;
FContentType := sctUnknown;
FFillBlip := False;
FFitToShape := False;
FFitToText := True;
FHorzPosCode := 0;
FBlock := nil;
FStyle := TKMemoBlockStyle.Create;
FStyle.Brush.Color := clWhite;
FStyle.ContentMargin.AssignFromValues(5, 5, 5, 5);
FVertPosCode := 0;
FWrap := 0;
FWrapSide := 0;
end;
destructor TKMemoRTFShape.Destroy;
begin
FContentPosition.Free;
FStyle.Free;
inherited;
end;
function TKMemoRTFShape.GetWrap: Integer;
begin
WrapModeToRTFWrap;
Result := FWrap;
end;
function TKMemoRTFShape.GetWrapSide: Integer;
begin
WrapModeToRTFWrap;
Result := FWrapSide;
end;
procedure TKMemoRTFShape.SetWrap(const Value: Integer);
begin
FWrap := Value;
RTFWrapToWrapMode;
end;
procedure TKMemoRTFShape.SetWrapSide(const Value: Integer);
begin
FWrapSide := Value;
RTFWrapToWrapMode;
end;
procedure TKMemoRTFShape.WrapModeToRTFWrap;
begin
FWrapSide := 0;
FWrap := 0;
case FStyle.WrapMode of
wrAround: FWrap := 2;
wrAroundLeft: begin FWrap := 2; FWrapSide := 1; end;
wrAroundRight: begin FWrap := 2; FWrapSide := 2; end;
wrTight: FWrap := 2; // FWrap should be 4, change when tight wrapping supported
wrTightLeft: begin FWrap := 2; FWrapSide := 1; end; // FWrap should be 4, change when tight wrapping supported
wrTightRight: begin FWrap := 2; FWrapSide := 2; end; // FWrap should be 4, change when tight wrapping supported
wrTopBottom: FWrap := 1;
wrNone: FWrap := 3;
end;
end;
procedure TKMemoRTFShape.RTFWrapToWrapMode;
begin
case FWrap of
1: FStyle.WrapMode := wrTopBottom;
2: case FWrapSide of
1: FStyle.WrapMode := wrAroundLeft;
2: FStyle.WrapMode := wrAroundRight;
else
FStyle.WrapMode := wrAround;
end;
3: FStyle.WrapMode := wrNone;
4: case FWrapSide of
1: FStyle.WrapMode := wrTightLeft;
2: FStyle.WrapMode := wrTightRight;
else
FStyle.WrapMode := wrTight;
end;
else
FStyle.WrapMode := wrAround;
end;
end;
{ TKMemoRTFState }
procedure TKMemoRTFState.Assign(ASource: TKmemoRTFState);
begin
if ASource <> nil then
begin
FGroup := ASource.Group;
FParaStyle.Assign(ASource.ParaStyle);
FTextStyle.Assign(ASource.TextStyle);
// don't assign the IsShape and IsPicture properties, they should not be inherited
end;
end;
constructor TKMemoRTFState.Create;
begin
FGroup := rgNone;
FParaStyle := TKMemoParaStyle.Create;
FTextStyle := TKMemoTextStyle.Create;
end;
destructor TKMemoRTFState.Destroy;
begin
FParaStyle.Free;
FTextStyle.Free;
inherited;
end;
{ TKMemoRTFStack }
function TKMemoRTFStack.Peek: TKMemoRTFState;
begin
Result := TKMemoRTFState(inherited Peek);
end;
function TKMemoRTFStack.Pop: TKMemoRTFState;
begin
Result := TKMemoRTFState(inherited Pop);
end;
function TKMemoRTFStack.Push(AObject: TKMemoRTFState): TKMemoRTFState;
begin
Result := TKMemoRTFState(inherited Push(AObject));
end;
{ TKMemoRTFFiler }
constructor TKMemoRTFFiler.Create(AMemo: TKCustomMemo);
begin
if (AMemo <> nil) and AMemo.HandleAllocated then
begin
FTwipsPerPixelX := TwipsPerPixelX(AMemo.Handle);
FTwipsPerPixelY := TwipsPerPixelY(AMemo.Handle);
end else
begin
FTwipsPerPixelX := TwipsPerPixelX(0);
FTwipsPerPixelY := TwipsPerPixelY(0);
end;
FMemo := AMemo;
FStream := nil;
end;
function TKMemoRTFFiler.EMUToPoints(AValue: Integer): Integer;
begin
Result := DivUp(AValue, 12700);
end;
function TKMemoRTFFiler.PointsToEMU(AValue: Integer): Integer;
begin
Result := AValue * 12700;
end;
function TKMemoRTFFiler.PixelsToTwipsX(AValue: Integer): Integer;
begin
Result := Round(AValue * FTwipsPerPixelX);
end;
function TKMemoRTFFiler.PixelsToTwipsY(AValue: Integer): Integer;
begin
Result := Round(AValue * FTwipsPerPixelY);
end;
function TKMemoRTFFiler.TwipsToPixelsX(AValue: Integer): Integer;
begin
Result := Round(AValue / FTwipsPerPixelX);
end;
function TKMemoRTFFiler.TwipsToPixelsY(AValue: Integer): Integer;
begin
Result := Round(AValue / FTwipsPerPixelY);
end;
{ TKMemoRTFReader }
constructor TKMemoRTFReader.Create(AMemo: TKCustomMemo);
begin
inherited;
FColorTable := TKMemoRTFColorTable.Create;
FCtrlTable := TKMemoRTFCtrlTable.Create;
FFontTable := TKMemoRTFFontTable.Create;
FIndexStack := TKMemoIndexObjectStack.Create;
FListTable := TKMemoRTFListTable.Create;
FStack := TKMemoRTFStack.Create;
FStream := nil;
FillCtrlTable;
FCtrlTable.SortTable;
end;
destructor TKMemoRTFReader.Destroy;
begin
FColorTable.Free;
FCtrlTable.Free;
FFontTable.Free;
FIndexStack.Free;
FListTable.Free;
FStack.Free;
inherited;
end;
procedure TKMemoRTFReader.FillCtrlTable;
begin
// control symbols
FCtrlTable.AddCtrl('{', 0, PushToStack);
FCtrlTable.AddCtrl('}', 0, PopFromStack);
FCtrlTable.AddCtrl('*', Integer(rpuUnknownSym), ReadUnknownGroup);
FCtrlTable.AddCtrl('shpinst', Integer(rpuShapeInst), ReadUnknownGroup);
FCtrlTable.AddCtrl('shppict', Integer(rpuShapePict), ReadUnknownGroup);
FCtrlTable.AddCtrl('nonshppict', Integer(rpuNonShapePict), ReadUnknownGroup);
FCtrlTable.AddCtrl('background', Integer(rpuPageBackground), ReadUnknownGroup);
FCtrlTable.AddCtrl('picprop', Integer(rpuPicProp), ReadUnknownGroup);
FCtrlTable.AddCtrl('fldinst', Integer(rpuFieldInst), ReadUnknownGroup);
FCtrlTable.AddCtrl('listtable', Integer(rpuListTable), ReadUnknownGroup);
FCtrlTable.AddCtrl('listoverridetable', Integer(rpuListOverrideTable), ReadUnknownGroup);
// header ctrls
FCtrlTable.AddCtrl('rtf', Integer(rphRtf), ReadHeaderGroup);
FCtrlTable.AddCtrl('ansicpg', Integer(rphCodePage), ReadHeaderGroup);
FCtrlTable.AddCtrl('deff', Integer(rphDefaultFont), ReadHeaderGroup);
FCtrlTable.AddCtrl('uc', Integer(rphIgnoreCharsAfterUnicode), ReadHeaderGroup);
FCtrlTable.AddCtrl('fonttbl', Integer(rphFontTable), ReadHeaderGroup);
FCtrlTable.AddCtrl('colortbl', Integer(rphColorTable), ReadHeaderGroup);
FCtrlTable.AddCtrl('stylesheet', Integer(rphStyleSheet), ReadHeaderGroup);
// document ctrls
FCtrlTable.AddCtrl('footer', Integer(rpdFooter), ReadDocumentGroups);
FCtrlTable.AddCtrl('footerl', Integer(rpdFooterLeft), ReadDocumentGroups);
FCtrlTable.AddCtrl('footerr', Integer(rpdFooterRight), ReadDocumentGroups);
FCtrlTable.AddCtrl('header', Integer(rpdHeader), ReadDocumentGroups);
FCtrlTable.AddCtrl('headerl', Integer(rpdHeaderLeft), ReadDocumentGroups);
FCtrlTable.AddCtrl('headerr', Integer(rpdHeaderRight), ReadDocumentGroups);
FCtrlTable.AddCtrl('info', Integer(rpdInfo), ReadDocumentGroups);
// color table ctrls
FCtrlTable.AddCtrl('red', Integer(rpcRed), ReadColorGroup);
FCtrlTable.AddCtrl('green', Integer(rpcGreen), ReadColorGroup);
FCtrlTable.AddCtrl('blue', Integer(rpcBlue), ReadColorGroup);
// field ctrls
FCtrlTable.AddCtrl('field', Integer(rpfiField), ReadFieldGroup);
FCtrlTable.AddCtrl('fldrslt', Integer(rpfiResult), ReadFieldGroup);
// font table ctrls
FCtrlTable.AddCtrl('f', Integer(rpfIndex), ReadFontGroup);
FCtrlTable.AddCtrl('fcharset', Integer(rpfCharset), ReadFontGroup);
FCtrlTable.AddCtrl('fprq', Integer(rpfPitch), ReadFontGroup);
// list (override) table ctrls
FCtrlTable.AddCtrl('list', Integer(rplList), ReadListGroup);
FCtrlTable.AddCtrl('listoverride', Integer(rplListOverride), ReadListGroup);
FCtrlTable.AddCtrl('listlevel', Integer(rplListLevel), ReadListGroup);
FCtrlTable.AddCtrl('listid', Integer(rplListId), ReadListGroup);
FCtrlTable.AddCtrl('listtext', Integer(rplListText), ReadListGroup);
FCtrlTable.AddCtrl('levelstartat', Integer(rplLevelStartAt), ReadListGroup);
FCtrlTable.AddCtrl('levelnfc', Integer(rplLevelNumberType), ReadListGroup);
FCtrlTable.AddCtrl('leveljc', Integer(rplLevelJustify), ReadListGroup);
FCtrlTable.AddCtrl('leveltext', Integer(rplLevelText), ReadListGroup);
FCtrlTable.AddCtrl('pntext', Integer(rplPnText), ReadListGroup);
// paragraph formatting ctrls
FCtrlTable.AddCtrl('pard', Integer(rppParD), ReadParaFormatting);
FCtrlTable.AddCtrl('fi', Integer(rppIndentFirst), ReadParaFormatting);
FCtrlTable.AddCtrl('li', Integer(rppIndentLeft), ReadParaFormatting);
FCtrlTable.AddCtrl('ri', Integer(rppIndentRight), ReadParaFormatting);
FCtrlTable.AddCtrl('sb', Integer(rppIndentTop), ReadParaFormatting);
FCtrlTable.AddCtrl('sa', Integer(rppIndentBottom), ReadParaFormatting);
FCtrlTable.AddCtrl('ql', Integer(rppAlignLeft), ReadParaFormatting);
FCtrlTable.AddCtrl('qc', Integer(rppAlignCenter), ReadParaFormatting);
FCtrlTable.AddCtrl('qr', Integer(rppAlignRight), ReadParaFormatting);
FCtrlTable.AddCtrl('qj', Integer(rppAlignJustify), ReadParaFormatting);
FCtrlTable.AddCtrl('cbpat', Integer(rppBackColor), ReadParaFormatting);
FCtrlTable.AddCtrl('nowwrap', Integer(rppNoWordWrap), ReadParaFormatting);
FCtrlTable.AddCtrl('brdrb', Integer(rppBorderBottom), ReadParaFormatting);
FCtrlTable.AddCtrl('brdrl', Integer(rppBorderLeft), ReadParaFormatting);
FCtrlTable.AddCtrl('brdrr', Integer(rppBorderRight), ReadParaFormatting);
FCtrlTable.AddCtrl('brdrt', Integer(rppBorderTop), ReadParaFormatting);
FCtrlTable.AddCtrl('box', Integer(rppBorderAll), ReadParaFormatting);
FCtrlTable.AddCtrl('brdrw', Integer(rppBorderWidth), ReadParaFormatting);
FCtrlTable.AddCtrl('brdrnone', Integer(rppBorderNone), ReadParaFormatting);
FCtrlTable.AddCtrl('brdrradius', Integer(rppBorderRadius), ReadParaFormatting);
FCtrlTable.AddCtrl('brdrcf', Integer(rppBorderColor), ReadParaFormatting);
FCtrlTable.AddCtrl('sl', Integer(rppLineSpacing), ReadParaFormatting);
FCtrlTable.AddCtrl('slmult', Integer(rppLineSpacingMode), ReadParaFormatting);
FCtrlTable.AddCtrl('par', Integer(rppPar), ReadParaFormatting);
FCtrlTable.AddCtrl('ls', Integer(rppListIndex), ReadParaFormatting);
FCtrlTable.AddCtrl('ilvl', Integer(rppListLevel), ReadParaFormatting);
FCtrlTable.AddCtrl('lsstartat', Integer(rppListStartAt), ReadParaFormatting);
// picture group ctrls
FCtrlTable.AddCtrl('pict', Integer(rpiPict), ReadPictureGroup);
FCtrlTable.AddCtrl('jpegblip', Integer(rpiJpeg), ReadPictureGroup);
FCtrlTable.AddCtrl('pngblip', Integer(rpiPng), ReadPictureGroup);
FCtrlTable.AddCtrl('emfblip', Integer(rpiEmf), ReadPictureGroup);
FCtrlTable.AddCtrl('wmetafile', Integer(rpiWmf), ReadPictureGroup);
FCtrlTable.AddCtrl('picw', Integer(rpiWidth), ReadPictureGroup);
FCtrlTable.AddCtrl('pich', Integer(rpiHeight), ReadPictureGroup);
FCtrlTable.AddCtrl('piccropb', Integer(rpiCropBottom), ReadPictureGroup);
FCtrlTable.AddCtrl('piccropl', Integer(rpiCropLeft), ReadPictureGroup);
FCtrlTable.AddCtrl('piccropr', Integer(rpiCropRight), ReadPictureGroup);
FCtrlTable.AddCtrl('piccropt', Integer(rpiCropTop), ReadPictureGroup);
FCtrlTable.AddCtrl('picscalex', Integer(rpiScaleX), ReadPictureGroup);
FCtrlTable.AddCtrl('picscaley', Integer(rpiScaleY), ReadPictureGroup);
FCtrlTable.AddCtrl('picwgoal', Integer(rpiReqWidth), ReadPictureGroup);
FCtrlTable.AddCtrl('pichgoal', Integer(rpiReqHeight), ReadPictureGroup);
// shape ctrls
FCtrlTable.AddCtrl('shp', Integer(rpsShape), ReadShapeGroup);
FCtrlTable.AddCtrl('shpbottom', Integer(rpsBottom), ReadShapeGroup);
FCtrlTable.AddCtrl('shpleft', Integer(rpsLeft), ReadShapeGroup);
FCtrlTable.AddCtrl('shpright', Integer(rpsRight), ReadShapeGroup);
FCtrlTable.AddCtrl('shptop', Integer(rpsTop), ReadShapeGroup);
FCtrlTable.AddCtrl('shpbxcolumn', Integer(rpsXColumn), ReadShapeGroup);
FCtrlTable.AddCtrl('shpbypara', Integer(rpsYPara), ReadShapeGroup);
FCtrlTable.AddCtrl('shpwr', Integer(rpsWrap), ReadShapeGroup);
FCtrlTable.AddCtrl('shpwrk', Integer(rpsWrapSide), ReadShapeGroup);
FCtrlTable.AddCtrl('sn', Integer(rpsSn), ReadShapeGroup);
FCtrlTable.AddCtrl('sv', Integer(rpsSv), ReadShapeGroup);
FCtrlTable.AddCtrl('shptxt', Integer(rpsShapeText), ReadShapeGroup);
// special character ctrls
FCtrlTable.AddCtrl('tab', Integer(rpscTab), ReadSpecialCharacter);
FCtrlTable.AddCtrl('lquote', Integer(rpscLQuote), ReadSpecialCharacter);
FCtrlTable.AddCtrl('rquote', Integer(rpscRQuote), ReadSpecialCharacter);
FCtrlTable.AddCtrl('ldblquote', Integer(rpscLDblQuote), ReadSpecialCharacter);
FCtrlTable.AddCtrl('rdblquote', Integer(rpscRDblQuote), ReadSpecialCharacter);
FCtrlTable.AddCtrl('endash', Integer(rpscEnDash), ReadSpecialCharacter);
FCtrlTable.AddCtrl('emdash', Integer(rpscEmDash), ReadSpecialCharacter);
FCtrlTable.AddCtrl('bullet', Integer(rpscBullet), ReadSpecialCharacter);
FCtrlTable.AddCtrl('~', Integer(rpscNBSP), ReadSpecialCharacter);
FCtrlTable.AddCtrl('emspace', Integer(rpscEmSpace), ReadSpecialCharacter);
FCtrlTable.AddCtrl('enspace', Integer(rpscEnSpace), ReadSpecialCharacter);
FCtrlTable.AddCtrl('''', Integer(rpscAnsiChar), ReadSpecialCharacter);
FCtrlTable.AddCtrl('u', Integer(rpscUnicodeChar), ReadSpecialCharacter);
// table formatting ctrls
FCtrlTable.AddCtrl('trowd', Integer(rptbRowBegin), ReadTableFormatting);
FCtrlTable.AddCtrl('intbl', Integer(rptbRowBegin), ReadTableFormatting);
FCtrlTable.AddCtrl('cell', Integer(rptbCellEnd), ReadTableFormatting);
FCtrlTable.AddCtrl('row', Integer(rptbRowEnd), ReadTableFormatting);
FCtrlTable.AddCtrl('lastrow', Integer(rptbLastRow), ReadTableFormatting);
FCtrlTable.AddCtrl('trpaddb', Integer(rptbRowPaddBottom), ReadTableFormatting);
FCtrlTable.AddCtrl('trpaddl', Integer(rptbRowPaddLeft), ReadTableFormatting);
FCtrlTable.AddCtrl('trpaddr', Integer(rptbRowPaddRight), ReadTableFormatting);
FCtrlTable.AddCtrl('trpaddt', Integer(rptbRowPaddTop), ReadTableFormatting);
FCtrlTable.AddCtrl('trgaph', Integer(rptbPaddAll), ReadTableFormatting);
FCtrlTable.AddCtrl('clbrdrb', Integer(rptbBorderBottom), ReadTableFormatting);
FCtrlTable.AddCtrl('clbrdrl', Integer(rptbBorderLeft), ReadTableFormatting);
FCtrlTable.AddCtrl('clbrdrr', Integer(rptbBorderRight), ReadTableFormatting);
FCtrlTable.AddCtrl('clbrdrt', Integer(rptbBorderTop), ReadTableFormatting);
FCtrlTable.AddCtrl('clpadb', Integer(rptbCellPaddBottom), ReadTableFormatting);
FCtrlTable.AddCtrl('clpadl', Integer(rptbCellPaddLeft), ReadTableFormatting);
FCtrlTable.AddCtrl('clpadr', Integer(rptbCellPaddRight), ReadTableFormatting);
FCtrlTable.AddCtrl('clpadt', Integer(rptbCellPaddTop), ReadTableFormatting);
// FCtrlTable.AddCtrl('brdrw', Integer(rptbBorderWidth), ReadTableFormatting); // see ReadParaFormatting
// FCtrlTable.AddCtrl('brdrnone', Integer(rptbBorderNone), ReadTableFormatting); // see ReadParaFormatting
// FCtrlTable.AddCtrl('brdrcf', Integer(rptbBorderColor), ReadParaFormatting); // see ReadParaFormatting
FCtrlTable.AddCtrl('clcbpat', Integer(rptbBackColor), ReadTableFormatting);
FCtrlTable.AddCtrl('clmgf', Integer(rptbHorzMergeBegin), ReadTableFormatting);
FCtrlTable.AddCtrl('clhmrg', Integer(rptbHorzMerge), ReadTableFormatting);
FCtrlTable.AddCtrl('clvmgf', Integer(rptbVertMergeBegin), ReadTableFormatting);
FCtrlTable.AddCtrl('clvmrg', Integer(rptbVertMerge), ReadTableFormatting);
FCtrlTable.AddCtrl('clwWidth', Integer(rptbCellWidth), ReadTableFormatting);
FCtrlTable.AddCtrl('cellx', Integer(rptbCellX), ReadTableFormatting);
// text formatting ctrls
FCtrlTable.AddCtrl('plain', Integer(rptPlain), ReadTextFormatting);
// FCtrlTable.AddCtrl('f', Integer(rptFontIndex), ReadTextFormatting); see ReadFontGroup
FCtrlTable.AddCtrl('b', Integer(rptBold), ReadTextFormatting);
FCtrlTable.AddCtrl('i', Integer(rptItalic), ReadTextFormatting);
FCtrlTable.AddCtrl('ul', Integer(rptUnderline), ReadTextFormatting);
FCtrlTable.AddCtrl('strike', Integer(rptStrikeout), ReadTextFormatting);
FCtrlTable.AddCtrl('caps', Integer(rptCaps), ReadTextFormatting);
FCtrlTable.AddCtrl('scaps', Integer(rptSmallCaps), ReadTextFormatting);
FCtrlTable.AddCtrl('fs', Integer(rptFontSize), ReadTextFormatting);
FCtrlTable.AddCtrl('cf', Integer(rptForeColor), ReadTextFormatting);
FCtrlTable.AddCtrl('cb', Integer(rptBackColor), ReadTextFormatting);
FCtrlTable.AddCtrl('highlight', Integer(rptBackColor), ReadTextFormatting);
FCtrlTable.AddCtrl('sub', Integer(rptSubscript), ReadTextFormatting);
FCtrlTable.AddCtrl('super', Integer(rptSuperscript), ReadTextFormatting);
end;
procedure TKMemoRTFReader.AddText(const APart: TKString);
var
S: TKString;
begin
S := APart;
while (FIgnoreChars > 0) and (S <> '') do
begin
Delete(S, 1, 1);
Dec(FIgnoreChars);
end;
if S <> '' then
begin
if FActiveState.TextStyle.StyleChanged then
FlushText;
if FActiveText = nil then
begin
FActiveText := TKMemoTextBlock.Create;
FActiveText.TextStyle.Assign(FActiveState.TextStyle);
end;
FActiveState.TextStyle.StyleChanged := False;
FActiveString := FActiveString + S;
end;
end;
procedure TKMemoRTFReader.AddTextToNumberingFormat(const APart: TKString);
var
S: TKString;
begin
if APart <> '' then
begin
S := APart;
while (FIgnoreChars > 0) and (S <> '') do
begin
Delete(S, 1, 1);
Dec(FIgnoreChars);
end;
if S <> '' then
begin
if Ord(S[1]) < $20 then
ActiveListLevel.NumberingFormat.AddItem(Ord(S[1]), '')
else
ActiveListLevel.NumberingFormat.AddItem(-1, S);
end;
end;
end;
procedure TKMemoRTFReader.ApplyFont(ATextStyle: TKMemoTextStyle; AFontIndex: Integer);
var
Font: TFont;
begin
Font := FFontTable.GetFont(AFontIndex);
if Font <> nil then
begin
ATextStyle.Font.Name := Font.Name;
ATextStyle.Font.Charset := Font.Charset;
ATextStyle.Font.Pitch := Font.Pitch;
end;
end;
procedure TKMemoRTFReader.ApplyHighlight(ATextStyle: TKMemoTextStyle; AHighlightCode: Integer);
var
Color: TColor;
begin
Color := HighlightCodeToColor(AHighlightCode);
if Color <> clNone then
ATextStyle.Brush.Color := Color
else
ATextStyle.Brush.Style := bsClear;
end;
procedure TKMemoRTFReader.FlushColor;
begin
if FActiveColor <> nil then
FColorTable.Add(FActiveColor)
else
FColorTable.Add(ActiveColor);
FActiveColor := nil;
end;
procedure TKMemoRTFReader.FlushContainer;
begin
if FActiveContainer <> nil then
begin
FActiveBlocks := FActiveContainer.ParentBlocks;
FAtIndex := FIndexStack.PopValue;
FActiveBlocks.AddAt(FActiveContainer, FAtIndex);
Inc(FAtIndex);
FActiveContainer := nil;
end;
end;
procedure TKMemoRTFReader.FlushFont;
begin
if FActiveFont <> nil then
begin
FFontTable.Add(FActiveFont);
FActiveFont := nil;
end;
end;
procedure TKMemoRTFReader.FlushHyperlink;
begin
FlushText;
FActiveURL := '';
end;
procedure TKMemoRTFReader.FlushImage;
begin
if FActiveImage <> nil then
begin
FActiveBlocks.AddAt(FActiveImage, FAtIndex);
Inc(FAtIndex);
FActiveImage := nil;
end;
end;
procedure TKMemoRTFReader.FlushList;
begin
if FActiveList <> nil then
begin
if FActiveList.Levels.Count > 0 then
begin
FListTable.Add(FActiveList);
FActiveList := nil;
end else
FreeAndNil(FActiveList);
end;
end;
procedure TKMemoRTFReader.FlushListLevel;
var
NFItem: TKMemoNumberingFormatItem;
S: TKString;
begin
if FActiveListLevel <> nil then
begin
// fixup numbering format
FActiveListLevel.NumberingFormat.Delete(0); // first item should be length, remove it
NFItem := FActiveListLevel.NumberingFormat[FActiveListLevel.NumberingFormat.Count - 1];
S := NFItem.Text; // last item should be string and end with a semicolon, remove it
if S[Length(S)] = ';' then
begin
System.Delete(S, Length(S), 1);
NFItem.Text := S;
end;
ActiveList.Levels.Add(FActiveListLevel);
FActiveListLevel := nil;
end;
end;
procedure TKMemoRTFReader.FlushListOverride;
begin
if FActiveListOverride <> nil then
begin
FListTable.Overrides.Add(FActiveListOverride);
FActiveListOverride := nil;
end;
end;
procedure TKMemoRTFReader.FlushParagraph;
var
PA: TKMemoParagraph;
begin
PA := FActiveBlocks.AddParagraph(FAtIndex);
PA.TextStyle.Assign(FActiveState.TextStyle);
PA.ParaStyle.Assign(FActiveState.ParaStyle);
Inc(FAtIndex);
FActiveParaBorder := alNone;
end;
procedure TKMemoRTFReader.FlushShape;
var
State: TKMemoRTFState;
begin
if FActiveShape <> nil then
begin
case FActiveShape.ContentType of
sctImage:
begin
// image was inside shape
if FActiveImage <> nil then
begin
// position always relative
FActiveImage.Position := mbpRelative;
// shape positioning tags override the image size/scale tags (MS Word behavior)
if FActiveShape.ContentPosition.Width > 0 then
FActiveImage.ScaleX := MulDiv(FActiveShape.ContentPosition.Width, 100, FActiveImage.NativeOrExplicitWidth);
if FActiveShape.ContentPosition.Height > 0 then
FActiveImage.ScaleY := MulDiv(FActiveShape.ContentPosition.Height, 100, FActiveImage.NativeOrExplicitHeight);
if FActiveShape.HorzPosCode = 2 then
FActiveImage.LeftOffset := FActiveShape.ContentPosition.Left;
if FActiveShape.VertPosCode = 2 then
FActiveImage.TopOffset := FActiveShape.ContentPosition.Top;
FActiveImage.ImageStyle.Assign(FActiveShape.Style);
FlushImage;
end;
end;
sctRectangle:
begin
// currently only document background supported, look if it is the case
State := FStack.Peek;
if (State <> nil) and (State.Group = rgPageBackground) then
begin
if FActiveShape.FillBlip then
begin
if FActiveImage <> nil then
begin
if FMemo <> nil then
FMemo.Background.Image.Assign(FActiveImage.Image);
FreeAndNil(FActiveImage);
end;
end
else if FMemo <> nil then
FMemo.Colors.BkGnd := FActiveShape.Style.Brush.Color;
end;
end;
sctTextBox:
begin
if FActiveContainer <> nil then
begin
// container was inside shape
ActiveContainer.Position := mbpRelative;
ActiveContainer.Clip := True;
ActiveContainer.FixedWidth := True;
if not FActiveShape.FitToText then
ActiveContainer.FixedHeight := True;
if FActiveShape.HorzPosCode = 2 then
ActiveContainer.LeftOffset := FActiveShape.ContentPosition.Left;
if FActiveShape.VertPosCode = 2 then
ActiveContainer.TopOffset := FActiveShape.ContentPosition.Top;
ActiveContainer.RequiredWidth := FActiveShape.ContentPosition.Right - FActiveShape.ContentPosition.Left;
ActiveContainer.RequiredHeight := FActiveShape.ContentPosition.Bottom - FActiveShape.ContentPosition.Top;
ActiveContainer.BlockStyle.Assign(FActiveShape.Style);
FlushContainer;
end;
end;
sctText:
begin
// unformatted text was inside shape
FlushText;
end;
end;
FreeAndNil(FActiveShape);
end;
end;
procedure TKMemoRTFReader.FlushTable;
begin
if FActiveTable <> nil then
begin
FActiveTable.FixupCellSpanFromRTF;
FActiveTable.FixupBorders;
FActiveBlocks := FActiveTable.ParentBlocks;
FActiveTable.Parent := nil;
FActiveTable.UnlockUpdate;
FAtIndex := FIndexStack.PopValue;
if not FActiveBlocks.InsideOfTable then // no support for nested tables yet
begin
FActiveBlocks.AddAt(FActiveTable, FAtIndex);
Inc(FAtIndex);
end else
FActiveTable.Free;
FActiveTable := nil;
FActiveTableRow := nil;
FActiveTableCell := nil;
end;
end;
procedure TKMemoRTFReader.FlushText;
var
Block: TKMemoHyperlink;
begin
if FActiveText <> nil then
begin
if FActiveString <> '' then
begin
FActiveText.InsertString(FActiveString);
FActiveString := '';
end;
if FActiveText.TextStyle.Font.Name = 'Symbol' then
begin
FActiveText.TextStyle.Font.Name := 'Arial';
FActiveText.TextStyle.Font.Charset := 0;
end;
if FActiveURL <> '' then
begin
TrimWhiteSpaces(FActiveURL, cWordBreaks);
Block := TKMemoHyperlink.Create;
Block.Assign(FActiveText);
Block.URL := FActiveURL;
FreeAndNil(FActiveText);
FActiveText := Block;
end;
FActiveBlocks.AddAt(FActiveText, FAtIndex);
Inc(FAtIndex);
FActiveText := nil;
end;
end;
function TKMemoRTFReader.GetActiveColor: TKMemoRTFColor;
begin
if FActiveColor = nil then
FActiveColor := TKMemoRTFColor.Create;
Result := FActiveColor;
end;
function TKMemoRTFReader.GetActiveContainer: TKMemoContainer;
begin
if FActiveContainer = nil then
FActiveContainer := TKMemoContainer.Create;
Result := FActiveContainer;
end;
function TKMemoRTFReader.GetActiveFont: TKMemoRTFFont;
begin
if FActiveFont = nil then
FActiveFont := TKMemoRTFFont.Create;
Result := FActiveFont;
end;
function TKMemoRTFReader.GetActiveImage: TKMemoImageBlock;
begin
if FActiveImage = nil then
FActiveImage := TKMemoImageBlock.Create;
Result := FActiveImage;
end;
function TKMemoRTFReader.GetActiveList: TKMemoRTFList;
begin
if FActiveList = nil then
FActiveList := TKMemoRTFList.Create(nil);
Result := FActiveList;
end;
function TKMemoRTFReader.GetActiveListLevel: TKMemoRTFListLevel;
begin
if FActiveListLevel = nil then
FActiveListLevel := TKMemoRTFListLevel.Create;
Result := FActiveListLevel;
end;
function TKMemoRTFReader.GetActiveListOverride: TKMemoDictionaryItem;
begin
if FActiveListOverride = nil then
FActiveListOverride := TKMemoDictionaryItem.Create;
Result := FActiveListOverride;
end;
function TKMemoRTFReader.GetActiveShape: TKMemoRTFShape;
begin
if FActiveShape = nil then
FActiveShape := TKMemoRTFShape.Create;
Result := FActiveShape;
end;
function TKMemoRTFReader.GetActiveTable: TKMemoTable;
begin
if FActiveTable = nil then
FActiveTable := TKMemoTable.Create;
Result := FActiveTable;
end;
function TKMemoRTFReader.HighlightCodeToColor(AValue: Integer): TColor;
begin
// it seems that highlight color is taken from color table, is it correct?
case AValue of
1: Result := clBlack;
2: Result := clBlue;
3: Result := clAqua; // cyan
4: Result := clLime; // green
5: Result := clFuchsia; // magenta
6: Result := clRed;
7: Result := clYellow;
9: Result := clNavy;
10: Result := clTeal; // dark cyan
11: Result := clGreen; // dark green
12: Result := clPurple; // dark magenta
13: Result := clMaroon; // dark red
14: Result := clOlive; // dark yellow
15: Result := clGray; // dark gray
16: Result := clSilver; // light gray
else
Result := clNone;
end;
end;
procedure TKMemoRTFReader.LoadFromFile(const AFileName: TKString; AActiveBlocks: TKMemoBlocks; AtIndex: TKMemoSelectionIndex);
var
Stream: TMemoryStream;
begin
if FileExists(AFileName) then
begin
Stream := TMemoryStream.Create;
try
Stream.LoadFromFile(AFileName);
LoadFromStream(Stream, AActiveBlocks, AtIndex);
finally
Stream.Free;
end;
end;
end;
procedure TKMemoRTFReader.LoadFromStream(AStream: TStream; AActiveBlocks: TKMemoBlocks; AtIndex: TKMemoSelectionIndex);
begin
try
if AActiveBlocks <> nil then
begin
FActiveBlocks := AActiveBlocks.SplitForInsert(AtIndex, FAtIndex);
FActiveBlocks.LockUpdate;
try
FActiveColor := nil;
FActiveContainer := nil;
FActiveFont := nil;
FActiveImage := nil;
FActiveImageClass := nil;
FActiveList := nil;
FActiveListLevel := nil;
FActiveListOverride := nil;
FActiveParaBorder := alNone;
FActiveShape := nil;
FActiveState := TKMemoRTFState.Create;
FActiveState.Group := rgUnknown; // we wait for file header
if FMemo <> nil then
begin
FActiveState.ParaStyle.Assign(FMemo.ParaStyle);
FActiveState.TextStyle.Assign(FMemo.TextStyle);
end;
FActiveString := '';
FActiveTable := nil;
FActiveTableBorder := alNone;
FActiveTableCell := nil;
FActiveTableCol := -1;
FActiveTableColCount := 0;
FActiveTableRow := nil;
FActiveText := nil;
FColorTable.Clear;
FDefaultFontIndex := 0;
FIgnoreChars := 0;
FStream := AStream;
try
ReadStream;
finally
FlushText;
FlushShape;
FlushImage;
FlushTable;
FActiveState.Free;
if FMemo <> nil then
FListTable.AssignToListTable(FMemo.ListTable, FFontTable);
FActiveBlocks.ConcatEqualBlocks;
FActiveBlocks.FixEmptyBlocks;
end;
finally
FActiveBlocks.UnlockUpdate;
end;
end;
except
KFunctions.Error(sErrMemoLoadFromRTF);
end;
end;
function TKMemoRTFReader.ParamToBool(const AValue: AnsiString): Boolean;
begin
Result := Boolean(StrToIntDef(string(AValue), 0));
end;
function TKMemoRTFReader.ParamToColor(const AValue: AnsiString): TColor;
begin
Result := ColorRecToColor(MakeColorRec(StrToIntDef(string(AValue), 0)));
end;
function TKMemoRTFReader.ParamToEMU(const AValue: AnsiString): Integer;
begin
Result := EMUToPoints(StrToIntDef(string(AValue), 0));
end;
function TKMemoRTFReader.ParamToInt(const AValue: AnsiString): Integer;
begin
Result := StrToIntDef(string(AValue), 0);
end;
procedure TKMemoRTFReader.PopFromStack(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
var
State: TKMemoRTFState;
begin
State := FStack.Peek;
if State <> nil then
begin
// flush shapes, images and other embedded objects to memo
if FActiveState.Group = rgShape then
begin
// standard shape group
FlushShape
end
else if FActiveState.Group = rgShapePict then
begin
// image inside of shppict group (Word 97 and newer images)
FlushText;
if FActiveImage <> nil then
begin
if FActiveShape <> nil then
FActiveImage.ImageStyle.Assign(FActiveShape.Style);
FlushImage;
end;
end
else if (FActiveState.Group = rgPicture) and (State.Group in [rgNone, rgTextBox]) then
begin
// standalone image outside of shppict and shape group (e.g. results of embedded objects)
FlushText;
FlushImage;
end
else if (FActiveState.Group = rgTextBox) and (State.Group = rgShapeInst) then
begin
// text shape inside of shpinst group
FlushText;
end
else if FActiveState.Group = rgField then
begin
// we only support hyperlinks now
FlushHyperlink;
end
else if (FActiveState.Group = rgListLevel) and (State.Group = rgList) then
begin
FlushListLevel;
end
else if (FActiveState.Group = rgList) and (State.Group = rgListTable) then
begin
FlushList;
end
else if (FActiveState.Group = rgListOverride) and (State.Group = rgListOverrideTable) then
begin
FlushListOverride;
end;
FActiveState.Free;
FActiveState := FStack.Pop;
end;
end;
procedure TKMemoRTFReader.PushToStack(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
var
State: TKMemoRTFState;
begin
FStack.Push(FActiveState);
State := TKMemoRTFState.Create;
State.Assign(FActiveState);
FActiveState := State;
end;
function TKMemoRTFReader.ReadNext(out ACtrl, AText: AnsiString; out AParam: Int64): Boolean;
procedure ReadText(var AText: AnsiString; AChar: AnsiChar);
begin
repeat
if (AChar <> cCR) and (AChar <> cLF) then
AText := AText + AChar;
Result := FStream.Read(AChar, 1) > 0;
until CharInSetEx(AChar, ['{', '}', '\']) or not Result;
if Result then
FStream.Seek(-1, soFromCurrent);
end;
var
C: AnsiChar;
ParamStr: AnsiString;
Code: Integer;
begin
AParam := MaxInt;
ACtrl := '';
AText := '';
Result := FStream.Read(C, 1) > 0;
if C = '\' then
begin
FStream.Read(C, 1);
if CharInSetEx(C, cLetters) then
begin
// control word
repeat
ACtrl := ACtrl + C;
Result := FStream.Read(C, 1) > 0;
until not (Result and CharInSetEx(C, cLetters));
if (C = '-') or CharInSetEx(C, cNumbers) then
begin
// control word parameter
ParamStr := '';
repeat
ParamStr := ParamStr + C;
Result := FStream.Read(C, 1) > 0;
until not (Result and CharInSetEx(C, cNumbers));
AParam := StrToIntDef(TKString(ParamStr), 0);
if Result and (C <> ' ') then
FStream.Seek(-1, soFromCurrent);
end
else if Result and (C <> ' ') then
FStream.Seek(-1, soFromCurrent);
end else
begin
ACtrl := C; //control symbol
if C = '''' then
begin
//hexadecimal value - special symbol
SetLength(ParamStr, 2);
Result := FStream.Read(ParamStr[1], 2) = 2;
if Result then
AParam := HexStrToInt(string(ParamStr), Length(ParamStr), False, Code);
end
else if CharInSetEx(C, ['{', '}', '\']) then
begin
AText := C; // control symbol is printable character
ACtrl := '';
end;
end;
if FStream.Read(C, 1) > 0 then
begin
if CharInSetEx(C, ['{', '}', '\']) then
FStream.Seek(-1, soFromCurrent)
else
ReadText(AText, C);
end;
end
else if CharInSetEx(C, ['{', '}', ';']) then
ACtrl := C // group
else
ReadText(AText, C);
end;
procedure TKMemoRTFReader.ReadColorGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
begin
if FActiveState.Group = rgColorTable then
begin
case TKMemoRTFColorProp(ACtrl) of
rpcRed: ActiveColor.Red := Byte(AParam);
rpcGreen: ActiveColor.Green := Byte(AParam);
rpcBlue: ActiveColor.Blue := Byte(AParam);
end;
if AText = ';' then
begin
FlushColor;
AText := ''; // we used the text as end of the color record
end;
end;
end;
procedure TKMemoRTFReader.ReadDocumentGroups(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
begin
if FActiveState.Group = rgNone then case TKMemoRTFDocumentProp(ACtrl) of
rpdFooter, rpdFooterLeft, rpdFooterRight: FActiveState.Group := rgFooter;
rpdHeader, rpdHeaderLeft, rpdHeaderRight: FActiveState.Group := rgHeader;
rpdInfo: FActiveState.Group := rgInfo;
end;
end;
procedure TKMemoRTFReader.ReadFieldGroup(ACtrl: Integer; var AText: AnsiString;
AParam: Integer);
begin
case TKMemoRTFFieldProp(ACtrl) of
rpfiField:
begin
FlushText;
FActiveState.Group := rgField;
end;
rpfiResult:
begin
FlushText;
FActiveState.Group := rgFieldResult;
end
else
case FActiveState.Group of
rgFieldInst:
begin
if AText <> '' then
begin
if Pos(cRTFHyperlink, string(AText)) = 1 then
begin
Delete(AText, 1, Length(cRTFHyperlink));
FActiveURL := TKString(AText);
end else
begin
if FActiveURL <> '' then
FActiveURL := FActiveURL + TKString(AText);
end;
AText := '';
end;
end;
end;
end;
end;
procedure TKMemoRTFReader.ReadFontGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
var
I: Integer;
S: TKString;
begin
case FActiveState.Group of
rgFontTable:
begin
case TKMemoRTFFontProp(ACtrl) of
rpfIndex: ActiveFont.FFontIndex := AParam;
rpfCharSet: ActiveFont.Font.Charset := AParam;
rpfPitch:
begin
case AParam of
1: ActiveFont.Font.Pitch := fpFixed;
2: ActiveFont.Font.Pitch := fpVariable;
else
ActiveFont.Font.Pitch := fpDefault;
end;
end;
end;
if AText <> '' then
begin
S := TKString(AText);
I := Pos(';', S);
if I > 0 then
Delete(S, I, 1);
ActiveFont.Font.Name := S;
FlushFont;
AText := ''; // we used the text as font name
end
end;
rgNone, rgTextBox, rgFieldResult:
begin
case TKMemoRTFFontProp(ACtrl) of
rpfIndex: ReadTextFormatting(Integer(rptFontIndex), AText, AParam);
end;
end;
rgListLevel:
begin
case TKMemoRTFFontProp(ACtrl) of
rpfIndex: ReadListGroup(Integer(rplLevelFontIndex), AText, AParam);
end;
end;
end;
end;
procedure TKMemoRTFReader.ReadHeaderGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
begin
if FActiveState.Group = rgUnknown then
begin
case TKMemoRTFheaderProp(ACtrl) of
rphRtf: FActiveState.Group := rgNone;
end;
end
else if FActiveState.Group = rgNone then case TKMemoRTFheaderProp(ACtrl) of
rphCodePage: FDefaultCodePage := AParam;
rphDefaultFont: FDefaultFontIndex := AParam;
rphIgnoreCharsAfterUnicode: FIgnoreCharsAfterUnicode := AParam;
rphFontTable: FActiveState.Group := rgFontTable;
rphColorTable: FActiveState.Group := rgColorTable;
rphStyleSheet: FActiveState.Group := rgStyleSheet;
end;
end;
procedure TKMemoRTFReader.ReadListGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
begin
case FActiveState.Group of
rgListTable: case TKMemoRTFListProp(ACtrl) of
rplList: FActiveState.Group := rgList;
end;
rgList: case TKMemoRTFListProp(ACtrl) of
rplListLevel: FActiveState.Group := rgListLevel;
rplListId: ActiveList.ID := AParam;
end;
rgListLevel: case TKMemoRTFListProp(ACtrl) of
rplLevelText: FActiveState.Group := rgListLevelText;
rplLevelStartAt: ActiveListLevel.StartAt := AParam;
rplLevelNumberType: ActiveListLevel.NumberType := AParam;
rplLevelJustify: ActiveListLevel.Justify := AParam;
rplLevelFontIndex: ActiveListLevel.FontIndex := AParam;
rplLevelFirstIndent: ActiveListLevel.FirstIndent := TwipsToPixelsX(AParam);
rplLevelLeftIndent: ActiveListLevel.LeftIndent := TwipsToPixelsX(AParam);
end;
rgListOverrideTable: case TKMemoRTFListProp(ACtrl) of
rplListOverride: FActiveState.Group := rgListOverride;
end;
rgListOverride: case TKMemoRTFListProp(ACtrl) of
rplListId: ActiveListOverride.Value := AParam;
rplListIndex: ActiveListOverride.Index := AParam;
end;
rgListLevelText: AddTextToNumberingFormat(string(AText));
else
case TKMemoRTFListProp(ACtrl) of
rplListText, rplPnText: FActiveState.Group := rgUnknown; // ignore text
// Note: ignore old Word 95 'pntext' tag as well. We do not support
// old Word 95 numbering style (so IMO it should not be ignored)
// but some documents mix '\pntext' with '\lsN' control words.
// This has the effect that the numbering is displayed twice if '\pntext'
// is not ignored.
end;
end;
end;
procedure TKMemoRTFReader.ReadParaFormatting(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
begin
case FActiveState.Group of
rgNone, rgTextBox, rgFieldResult: case TKMemoRTFParaProp(ACtrl) of
rppParD: if FMemo <> nil then FActiveState.ParaStyle.Assign(FMemo.ParaStyle);
rppIndentFirst: FActiveState.ParaStyle.FirstIndent := TwipsToPixelsX(AParam);
rppIndentBottom: FActiveState.ParaStyle.BottomPadding := TwipsToPixelsY(AParam);
rppIndentLeft: FActiveState.ParaStyle.LeftPadding := TwipsToPixelsX(AParam);
rppIndentRight: FActiveState.ParaStyle.RightPadding := TwipsToPixelsX(AParam);
rppIndentTop: FActiveState.ParaStyle.TopPadding := TwipsToPixelsY(AParam);
rppAlignLeft: FActiveState.ParaStyle.HAlign := halLeft;
rppAlignCenter: FActiveState.ParaStyle.HAlign := halCenter;
rppAlignRight: FActiveState.ParaStyle.HAlign := halRight;
rppAlignJustify: FActiveState.ParaStyle.HAlign := halJustify;
rppBackColor: FActiveState.ParaStyle.Brush.Color := FColorTable.GetColor(AParam);
rppNoWordWrap: FActiveState.ParaStyle.WordWrap := False;
rppBorderBottom: FActiveParaBorder := alBottom;
rppBorderLeft: FActiveParaBorder := alLeft;
rppBorderRight: FActiveParaBorder := alRight;
rppBorderTop: FActiveParaBorder := alTop;
rppBorderAll: FActiveParaBorder := alClient;
rppBorderWidth:
case FActiveParaBorder of
alBottom: FActiveState.ParaStyle.BorderWidths.Bottom := TwipsToPixelsY(AParam);
alLeft: FActiveState.ParaStyle.BorderWidths.Left := TwipsToPixelsX(AParam);
alRight: FActiveState.ParaStyle.BorderWidths.Right := TwipsToPixelsX(AParam);
alTop: FActiveState.ParaStyle.BorderWidths.Top := TwipsToPixelsY(AParam);
alClient: FActiveState.ParaStyle.BorderWidth := TwipsToPixelsX(AParam);
else
if FActiveTableBorder <> alNone then
ReadTableFormatting(Integer(rptbBorderWidth), AText, AParam)
end;
rppBorderNone:
case FActiveParaBorder of
alBottom: FActiveState.ParaStyle.BorderWidths.Bottom := 0;
alLeft: FActiveState.ParaStyle.BorderWidths.Left := 0;
alRight: FActiveState.ParaStyle.BorderWidths.Right := 0;
alTop: FActiveState.ParaStyle.BorderWidths.Top := 0;
alClient: FActiveState.ParaStyle.BorderWidth := 0;
else
if FActiveTableBorder <> alNone then
ReadTableFormatting(Integer(rptbBorderNone), AText, AParam)
end;
rppBorderRadius: FActiveState.ParaStyle.BorderRadius := TwipsToPixelsX(AParam);
rppBorderColor:
begin
if FActiveParaBorder <> alNone then
FActiveState.ParaStyle.BorderColor := FColorTable.GetColor(AParam)
else if FActiveTableBorder <> alNone then
ReadTableFormatting(Integer(rptbBorderColor), AText, AParam)
end;
rppLineSpacing:
begin
FActiveState.ParaStyle.LineSpacingValue := TwipsToPixelsY(AParam);
FActiveState.ParaStyle.LineSpacingFactor := AParam / 240;
end;
rppLineSpacingMode:
begin
if AParam = 0 then
FActiveState.ParaStyle.LineSpacingMode := lsmValue
else
FActiveState.ParaStyle.LineSpacingMode := lsmFactor
end;
rppPar:
begin
FlushText;
FlushParagraph;
end;
rppListIndex: FActiveState.ParaStyle.NumberingList := FListTable.IDByIndex(AParam);
rppListLevel: FActiveState.ParaStyle.NumberingListLevel := AParam;
rppListStartAt: FActiveState.ParaStyle.NumberStartAt := AParam;
end;
rgListLevel: case TKMemoRTFParaProp(ACtrl) of
rppIndentFirst: ReadListgroup(Integer(rplLevelFirstIndent), AText, AParam);
rppIndentLeft: ReadListgroup(Integer(rplLevelLeftIndent), AText, AParam);
end;
rgListOverride: case TKMemoRTFParaProp(ACtrl) of
rppListIndex: ReadListgroup(Integer(rplListIndex), AText, AParam);
end;
end;
end;
procedure TKMemoRTFReader.ReadPictureGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
var
S: AnsiString;
MS: TMemoryStream;
Image: TGraphic;
Tmp: Integer;
begin
if FActiveState.Group in [rgShapeInst, rgShapePict, rgNone, rgTextBox] then
begin
case TKMemoRTFImageProp(ACtrl) of
rpiPict:
begin
FActiveState.Group := rgPicture;
end;
end;
end
else if FActiveState.Group in [rgPicture] then
begin
case TKMemoRTFImageProp(ACtrl) of
rpiJPeg: FActiveImageClass := TJpegImage;
{$IFDEF USE_PNG_SUPPORT}
rpiPng: FActiveImageClass := TKPngImage;
{$ENDIF}
{$IFDEF MSWINDOWS}
rpiEmf:
begin
FActiveImageClass := TKMetafile;
FActiveImageIsEMF := True;
end;
rpiWmf:
begin
FActiveImageClass := TKMetafile;
FActiveImageIsEMF := False;
end;
{$ENDIF}
rpiWidth: ActiveImage.ExplicitWidth := TwipsToPixelsX(AParam);
rpiHeight: ActiveImage.ExplicitHeight := TwipsToPixelsY(AParam);
rpiCropBottom: ActiveImage.Crop.Bottom := TwipsToPixelsY(AParam);
rpiCropLeft: ActiveImage.Crop.Left := TwipsToPixelsX(AParam);
rpiCropRight: ActiveImage.Crop.Right := TwipsToPixelsX(AParam);
rpiCropTop: ActiveImage.Crop.Top := TwipsToPixelsY(AParam);
rpiScaleX:
begin
if AParam > 0 then
ActiveImage.ScaleX := AParam;
end;
rpiScaleY:
begin
if AParam > 0 then
ActiveImage.ScaleY := AParam;
end;
rpiReqWidth: if ActiveImage.ExplicitWidth > 0 then
begin
Tmp := MulDiv(TwipsToPixelsX(AParam), 100, ActiveImage.ExplicitWidth);
if Tmp < ActiveImage.ScaleX then
ActiveImage.ScaleX := Tmp;
end;
rpiReqHeight: if ActiveImage.ExplicitHeight > 0 then
begin
Tmp := MulDiv(TwipsToPixelsY(AParam), 100, ActiveImage.ExplicitHeight);
if Tmp < ActiveImage.ScaleY then
ActiveImage.ScaleY := Tmp;
end;
end;
if AText <> '' then
begin
if FActiveImageClass <> nil then
begin
S := AText;
if DigitsToBinStr(S) then
begin
S := BinStrToBinary(S);
try
MS := TMemoryStream.Create;
try
MS.Write(S[1], Length(S));
MS.Seek(0, soFromBeginning);
Image := FActiveImageClass.Create;
try
{$IFDEF MSWINDOWS}
if Image is TKMetafile then
begin
//if not FActiveImageIsEMF then MS.SaveToFile('test.wmf');
TKMetafile(Image).CopyOnAssign := False; // we will destroy this instance anyway...
TKMetafile(Image).Enhanced := FActiveImageIsEMF;
TKmetafile(Image).LoadFromStream(MS);
if not FActiveImageIsEMF then
begin
// WMF extent could be incorrect here, so use RTF info
TKMetafile(Image).Width := PixelsToTwipsX(ActiveImage.ExplicitWidth);
TKMetafile(Image).Height := PixelsToTwipsY(ActiveImage.ExplicitHeight);
end;
end else
{$ENDIF}
Image.LoadFromStream(MS);
ActiveImage.Image := Image;
finally
Image.Free;
end;
finally
MS.Free;
end;
except
KFunctions.Error(sErrMemoLoadImageFromRTF);
end;
end;
FActiveImageClass := nil;
end;
AText := ''; // we used the text as image data
end;
end;
end;
procedure TKMemoRTFReader.ReadShapeGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
begin
case TKMemoRTFShapeProp(ACtrl) of
rpsShape: FActiveState.Group := rgShape;
end;
if FActiveState.Group in [rgShapeInst, rgShapePict, rgPicProp] then case TKMemoRTFShapeProp(ACtrl) of
rpsBottom: ActiveShape.ContentPosition.Bottom := TwipsToPixelsY(AParam);
rpsLeft: ActiveShape.ContentPosition.Left := TwipsToPixelsX(AParam);
rpsRight: ActiveShape.ContentPosition.Right := TwipsToPixelsX(AParam);
rpsTop: ActiveShape.ContentPosition.Top := TwipsToPixelsY(AParam);
rpsXColumn: ActiveShape.HorzPosCode := 2; // we silently assume posrelh always comes later
rpsYPara: ActiveShape.VertPosCode := 2; // we silently assume posrelv always comes later
rpsWrap: ActiveShape.Wrap := AParam;
rpsWrapSide: ActiveShape.WrapSide := AParam;
rpsSn: ActiveShape.CtrlName := AText;
rpsSv:
begin
ActiveShape.CtrlValue := AText;
// do different things according to CtrlName property
if ActiveShape.CtrlName = 'posrelh' then
begin
ActiveShape.HorzPosCode := ParamToInt(AText);
end
else if ActiveShape.CtrlName = 'posrelv' then
begin
ActiveShape.VertPosCode := ParamToInt(AText);
end
else if ActiveShape.CtrlName = 'fFitShapeToText' then
ActiveShape.FitToText := True
else if ActiveShape.CtrlName = 'fFitTextToShape' then
ActiveShape.FitToShape := True
else if ActiveShape.CtrlName = 'fFilled' then
begin
if not ParamToBool(AText) then
ActiveShape.Style.Brush.Style := bsClear;
end
else if ActiveShape.CtrlName = 'fillColor' then
ActiveShape.Style.Brush.Color := ParamToColor(AText)
else if ActiveShape.CtrlName = 'fillBlip' then
ActiveShape.FillBlip := True
else if ActiveShape.CtrlName = 'fLine' then
begin
if not ParamToBool(AText) then
ActiveShape.Style.BorderWidth := 0;
end
else if ActiveShape.CtrlName = 'lineColor' then
ActiveShape.Style.BorderColor := ParamToColor(AText)
else if ActiveShape.CtrlName = 'lineWidth' then
ActiveShape.Style.BorderWidth := ParamToEMU(AText)
else if ActiveShape.CtrlName = 'shapeType' then
begin
// supported shape types
case StrToIntDef(string(ActiveShape.CtrlValue), 0) of
1: ActiveShape.ContentType := sctRectangle;
75: ActiveShape.ContentType := sctImage;
202:
begin
ActiveShape.ContentType := sctTextBox;
ActiveShape.Style.ContentPadding.AssignFromValues(5, 5, 5, 5); //default padding for text box
end;
end;
end;
end;
rpsShapeText:
begin
// this keyword starts the actual text box contents
FlushText;
ActiveContainer.Parent := FActiveBlocks;
FActiveBlocks := ActiveContainer.Blocks;
FIndexStack.PushValue(FAtIndex);
FAtIndex := 0;
FActiveState.Group := rgTextBox;
end;
end;
end;
procedure TKMemoRTFReader.ReadSpecialCharacter(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
var
S: TKString;
CodePage: Integer;
SetIgnoreChars: Boolean;
begin
SetIgnoreChars := False;
S := '';
// we must suppose here selected font supports these Unicode characters
case TKMemoRTFSpecialCharProp(ACtrl) of
rpscTab: S := #9; // tab is rendered with an arrow symbol
rpscLquote: S := UnicodeToNativeUTF(#$2018);
rpscRQuote: S := UnicodeToNativeUTF(#$2019);
rpscLDblQuote: S := UnicodeToNativeUTF(#$201C);
rpscRDblQuote: S := UnicodeToNativeUTF(#$201D);
rpscEnDash: S := UnicodeToNativeUTF(#$2013);
rpscEmDash: S := UnicodeToNativeUTF(#$2014);
rpscBullet: S := UnicodeToNativeUTF(#$2022);
rpscNBSP: S := ' '; // nonbreaking spaces not supported
rpscEmSpace: S := ' ';
rpscEnSpace: S := ' ';
rpscAnsiChar:
begin
if AParam < $20 then
S := Chr(AParam)
else
begin
if FActiveState.TextStyle.Font.Name = 'Symbol' then
S := UnicodeToNativeUTF(WideChar(AdobeSymbolToUTF16(AParam)))
else
begin
if FActiveState.TextStyle.Font.Charset = 0 then
CodePage := FDefaultCodePage
else
CodePage := CharSetToCP(FActiveState.TextStyle.Font.Charset);
S := AnsiStringToString(AnsiChar(AParam), CodePage);
end;
end;
end;
rpscUnicodeChar:
begin
S := UnicodeToNativeUTF(WideChar(AParam));
SetIgnoreChars := True;
end;
end;
case FActiveState.Group of
rgNone, rgTextBox, rgFieldResult: AddText(S);
rgListLevelText: AddTextToNumberingFormat(S);
end;
if SetIgnoreChars and (FActiveState.Group <> rgUnknown) then
FIgnoreChars := FIgnoreCharsAfterUnicode;
end;
procedure TKMemoRTFReader.ReadStream;
var
Ctrl: AnsiString;
Text: AnsiString;
Param: Int64;
CtrlItem: TKMemoRTFCtrl;
begin
while FStream.Position < FStream.Size do
begin
ReadNext(Ctrl, Text, Param);
if (Ctrl <> '') or (Text <> '') then
begin
if Ctrl <> '' then
begin
CtrlItem := FCtrlTable.FindByCtrl(Ctrl);
if CtrlItem <> nil then
CtrlItem.Method(CtrlItem.Code, Text, Param);
end;
if Text <> '' then
begin
// if Method did not use Text use it according to active group
case FActiveState.Group of
rgColorTable: ReadColorGroup(Integer(rpcNone), Text, 0);
rgFieldInst: ReadFieldGroup(Integer(rpfiNone), Text, 0);
rgFontTable: ReadFontGroup(Integer(rpfNone), Text, 0);
rgPicture: ReadPictureGroup(Integer(rpiNone), Text, 0);
rgListLevelText: ReadListGroup(Integer(rplNone), Text, 0);
rgNone, rgTextBox, rgFieldResult: AddText(TKString(Text));
end;
end;
end;
end;
end;
procedure TKMemoRTFReader.ReadTableFormatting(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
var
I, Value: Integer;
Cell: TKMemoTableCell;
begin
if FActiveState.Group in [rgNone, rgTextBox] then case TKMemoRTFTableProp(ACtrl) of
rptbRowBegin:
begin
if FActiveTableColCount = 0 then
begin
FlushText;
if FActiveTable = nil then
begin
ActiveTable.LockUpdate;
ActiveTable.Parent := FActiveBlocks; // needs a parent to correctly update
ActiveTable.RowCount := 1;
ActiveTable.ColCount := 1;
FActiveTableColCount := 1;
FActiveTableRow := ActiveTable.Rows[ActiveTable.RowCount - 1];
FActiveBlocks := FActiveTableRow.Cells[FActiveTableColCount - 1].Blocks; // starting new cell
FIndexStack.PushValue(FAtIndex);
FAtIndex := 0;
FActiveTableCellXPos := 0;
FActiveTableLastRow := False;
end;
end
else if (FActiveTableRow <> nil) and (FActiveTableRow.CellCount > 1) then
begin
// this block comes again after definition of the row and is used to read row/cell properties (at least Word saves this)
// we don't support reading cell properties before entire row is defined with /cell control words
FActiveTableCol := 0;
FActiveTableCell := FActiveTableRow.Cells[FActiveTableCol];
end
end;
rptbCellEnd: if FActiveTableRow <> nil then
begin
FlushText;
Cell := FActiveTableRow.Cells[FActiveTableColCount - 1];
Cell.ParaStyle.Assign(FActiveState.ParaStyle);
Inc(FActiveTableColCount);
FActiveTableRow.CellCount := FActiveTableColCount;
FActiveBlocks := FActiveTableRow.Cells[FActiveTableColCount - 1].Blocks; // starting new cell
FAtIndex := 0;
end;
rptbRowEnd: if FActiveTableRow <> nil then
begin
// delete previously started cell if empty
if FActiveTableRow.Cells[FActiveTableColCount - 1].Blocks.Count = 0 then
FActiveTableRow.CellCount := FActiveTableRow.CellCount - 1;
if FActiveTableLastRow then
begin
FlushTable;
FActiveTableLastRow := False;
FActiveTableColCount := 0;
end else
begin
ActiveTable.RowCount := ActiveTable.RowCount + 1;
ActiveTable.ColCount := Max(ActiveTable.ColCount, FActiveTableRow.CellCount);
FActiveTableRow := ActiveTable.Rows[ActiveTable.RowCount - 1];
FActiveTableColCount := 1;
FActiveTableRow.CellCount := FActiveTableColCount;
FActiveBlocks := FActiveTableRow.Cells[FActiveTableColCount - 1].Blocks; // starting new cell
FAtIndex := 0;
FActiveTableCellXPos := 0;
end;
FActiveTableCol := -1;
FActiveTableCell := nil;
FActiveTableBorder := alNone;
end;
rptbLastRow: FActiveTableLastRow := True;
end;
// read row/cell formatting (if any)
if (FActiveTableRow <> nil) and (FActiveTableCell <> nil) then case TKMemoRTFTableProp(ACtrl) of
rptbPaddAll:
begin
// we silently assume this will come before other rptbRowPaddxx ctrls
Value := TwipsToPixelsX(AParam);
for I := 0 to FActiveTableRow.CellCount - 1 do
FActiveTableRow.Cells[I].BlockStyle.ContentPadding.AssignFromValues(Value, Value, Value, Value);
end;
rptbRowPaddBottom:
begin
FActiveTableRowPadd.Bottom := TwipsToPixelsY(AParam);
for I := 0 to FActiveTableRow.CellCount - 1 do
FActiveTableRow.Cells[I].BlockStyle.BottomPadding := FActiveTableRowPadd.Bottom;
end;
rptbRowPaddLeft:
begin
FActiveTableRowPadd.Left := TwipsToPixelsX(AParam);
for I := 0 to FActiveTableRow.CellCount - 1 do
FActiveTableRow.Cells[I].BlockStyle.LeftPadding := FActiveTableRowPadd.Left;
end;
rptbRowPaddRight:
begin
FActiveTableRowPadd.Right := TwipsToPixelsX(AParam);
for I := 0 to FActiveTableRow.CellCount - 1 do
FActiveTableRow.Cells[I].BlockStyle.RightPadding := FActiveTableRowPadd.Right;
end;
rptbRowPaddTop:
begin
FActiveTableRowPadd.Top := TwipsToPixelsY(AParam);
for I := 0 to FActiveTableRow.CellCount - 1 do
FActiveTableRow.Cells[I].BlockStyle.TopPadding := FActiveTableRowPadd.Top;
end;
rptbBorderBottom: FActiveTableBorder := alBottom;
rptbBorderLeft: FActiveTableBorder := alLeft;
rptbBorderRight: FActiveTableBorder := alRight;
rptbBorderTop: FActiveTableBorder := alTop;
rptbBorderWidth:
begin
case FActiveTableBorder of
alBottom: FActiveTableCell.RequiredBorderWidths.Bottom := TwipsToPixelsY(AParam);
alLeft: FActiveTableCell.RequiredBorderWidths.Left := TwipsToPixelsX(AParam);
alRight: FActiveTableCell.RequiredBorderWidths.Right := TwipsToPixelsX(AParam);
alTop: FActiveTableCell.RequiredBorderWidths.Top := TwipsToPixelsY(AParam);
end;
end;
rptbBorderNone:
begin
case FActiveTableBorder of
alBottom: FActiveTableCell.RequiredBorderWidths.Bottom := 0;
alLeft: FActiveTableCell.RequiredBorderWidths.Left := 0;
alRight: FActiveTableCell.RequiredBorderWidths.Right := 0;
alTop: FActiveTableCell.RequiredBorderWidths.Top := 0;
end;
end;
rptbBorderColor: FActiveTableCell.BlockStyle.BorderColor := FColorTable.GetColor(AParam); // no support for different colors for different borders
rptbBackColor: FActiveTableCell.BlockStyle.Brush.Color := FColorTable.GetColor(AParam);
rptbHorzMerge: FActiveTableCell.ColSpan := 0; // indicate for later fixup
rptbVertMerge: FActiveTableCell.RowSpan := 0; // indicate for later fixup
rptbCellPaddBottom: FActiveTableCell.BlockStyle.BottomPadding := TwipsToPixelsY(AParam);
rptbCellPaddLeft: FActiveTableCell.BlockStyle.LeftPadding := TwipsToPixelsX(AParam);
rptbCellPaddRight: FActiveTableCell.BlockStyle.RightPadding := TwipsToPixelsX(AParam);
rptbCellPaddTop: FActiveTableCell.BlockStyle.TopPadding := TwipsToPixelsY(AParam);
rptbCellWidth:
begin
FActiveTableCell.FixedWidth := True;
FActiveTableCell.RequiredWidth := TwipsToPixelsX(AParam);
end;
rptbCellX:
begin
// this command comes as the last for current cell
Value := FActiveTableCellXPos;
FActiveTableCellXPos := TwipsToPixelsX(AParam);
FActiveTableCell.RequiredWidth := FActiveTableCellXPos - Value;
Inc(FActiveTableCol);
if FActiveTableCol < FActiveTableRow.CellCount then
FActiveTableCell := FActiveTableRow.Cells[FActiveTableCol]
else
FActiveTableCell := nil; // error in RTF, ignore next properties
end;
end;
end;
procedure TKMemoRTFReader.ReadTextFormatting(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
begin
if FActiveState.Group in [rgNone, rgTextBox, rgFieldResult] then case TKMemoRTFTextProp(ACtrl) of
rptPlain:
begin
if FMemo <> nil then
FActiveState.TextStyle.Assign(FMemo.TextStyle);
end;
rptFontIndex: ApplyFont(FActiveState.TextStyle, AParam);
rptBold:
begin
if AParam = 0 then
FActiveState.TextStyle.Font.Style := FActiveState.TextStyle.Font.Style - [fsBold]
else
FActiveState.TextStyle.Font.Style := FActiveState.TextStyle.Font.Style + [fsBold];
end;
rptItalic:
begin
if AParam = 0 then
FActiveState.TextStyle.Font.Style := FActiveState.TextStyle.Font.Style - [fsItalic]
else
FActiveState.TextStyle.Font.Style := FActiveState.TextStyle.Font.Style + [fsItalic];
end;
rptUnderline:
begin
if AParam = 0 then
FActiveState.TextStyle.Font.Style := FActiveState.TextStyle.Font.Style - [fsUnderline]
else
FActiveState.TextStyle.Font.Style := FActiveState.TextStyle.Font.Style + [fsUnderline];
end;
rptStrikeout:
begin
if AParam = 0 then
FActiveState.TextStyle.Font.Style := FActiveState.TextStyle.Font.Style - [fsStrikeout]
else
FActiveState.TextStyle.Font.Style := FActiveState.TextStyle.Font.Style + [fsStrikeout];
end;
rptCaps: FActiveState.TextStyle.Capitals := tcaNormal;
rptSmallCaps: FActiveState.TextStyle.Capitals := tcaSmall;
rptFontSize: FActiveState.TextStyle.Font.Size := DivUp(AParam, 2);
rptForeColor: FActiveState.TextStyle.Font.Color := FColorTable.GetColor(AParam);
rptBackColor: FActiveState.TextStyle.Brush.Color := FColorTable.GetColor(AParam);
rptSubscript: FActiveState.TextStyle.ScriptPosition := tpoSubscript;
rptSuperscript: FActiveState.TextStyle.ScriptPosition := tpoSuperscript;
end;
end;
procedure TKMemoRTFReader.ReadUnknownGroup(ACtrl: Integer; var AText: AnsiString; AParam: Integer);
begin
if not (FActiveState.Group in [rgInfo, rgHeader, rgFooter]) then case TKMemoRTFUnknownProp(ACtrl) of
rpuUnknownSym: FActiveState.Group := rgUnknown;
rpuNonShapePict: FActiveState.Group := rgUnknown; // we ignore this picture
end;
if FActiveState.Group = rgUnknown then case TKMemoRTFUnknownProp(ACtrl) of
rpuFieldInst: FActiveState.Group := rgFieldInst; // field inside text
rpuShapeInst: FActiveState.Group := rgShapeInst; // picture inside text
rpuShapePict: FActiveState.Group := rgShapePict; // picture inside text
rpuPageBackground: FActiveState.Group := rgPageBackground; // this is the page background, read it
rpuPicProp: FActiveState.Group := rgPicProp; // non shape picture has some shape properties, read them
rpuListTable: FActiveState.Group := rgListTable;
rpuListOverrideTable: FActiveState.Group := rgListOverrideTable;
end;
end;
{ TKMemoRTFWriter }
constructor TKMemoRTFWriter.Create(AMemo: TKCustomMemo);
begin
inherited;
FGroupLevel := 0;
FReadableOutput := False;
FColorTable := TKMemoRTFColorTable.Create;
FFontTable := TKMemoRTFFontTable.Create;
FListTable := TKMemoRTFListTable.Create;
FSelectedOnly := False;
FStream := nil;
end;
destructor TKMemoRTFWriter.Destroy;
begin
FColorTable.Free;
FFontTable.Free;
FListTable.Free;
inherited;
end;
function TKMemoRTFWriter.BoolToParam(AValue: Boolean): AnsiString;
begin
Result := AnsiString(IntToStr(Integer(AValue)));
end;
function TKMemoRTFWriter.CanSave(ABlock: TKMemoBlock): Boolean;
begin
Result := not FSelectedOnly or (ABlock <> nil) and (ABlock.SelLength > 0);
end;
function TKMemoRTFWriter.ColorToHighlightCode(AValue: TColor): Integer;
begin
// we save highlight color as reference to color table, is it correct?
case AValue of
clBlack: Result := 1;
clBlue: Result := 2;
clAqua: Result := 3; // cyan
clLime: Result := 4; // green
clFuchsia: Result := 5; // magenta
clRed: Result := 6;
clYellow: Result := 7;
clNavy: Result := 9;
clTeal: Result := 10; // dark cyan
clGreen: Result := 11; // dark green
clPurple: Result := 12; // dark magenta
clMaroon: Result := 13; // dark red
clOlive: Result := 14; // dark yellow
clGray: Result := 15; // dark gray
clSilver: Result := 16; // light gray
else
Result := 0;
end;
end;
function TKMemoRTFWriter.ColorToParam(AValue: TColor): AnsiString;
begin
Result := AnsiString(IntToStr(ColorToColorRec(Avalue).Value));
end;
function TKMemoRTFWriter.EMUToParam(AValue: Integer): AnsiString;
begin
Result := AnsiString(IntToStr(PointsToEMU(AValue)));
end;
procedure TKMemoRTFWriter.FillColorTable(ABlocks: TKMemoBlocks);
var
I: Integer;
Block: TKmemoBlock;
begin
if ABlocks <> nil then
begin
for I := 0 to ABlocks.Count - 1 do
begin
Block := Ablocks[I];
if CanSave(Block) then
begin
if Block is TKMemoTextBlock then
begin
FColorTable.AddColor(TKmemoTextBlock(Block).TextStyle.Brush.Color);
FColorTable.AddColor(TKmemoTextBlock(Block).TextStyle.Font.Color);
if Block is TKMemoParagraph then
begin
FColorTable.AddColor(TKMemoParagraph(Block).ParaStyle.Brush.Color);
FColorTable.AddColor(TKMemoParagraph(Block).ParaStyle.BorderColor);
end;
end
else if Block is TKMemoContainer then
begin
FColorTable.AddColor(TKmemoContainer(Block).BlockStyle.Brush.Color);
FColorTable.AddColor(TKmemoContainer(Block).BlockStyle.BorderColor);
if Block is TKMemoTable then
begin
FColorTable.AddColor(TKmemoTable(Block).CellStyle.Brush.Color);
FColorTable.AddColor(TKmemoTable(Block).CellStyle.BorderColor);
end;
FillColorTable(TKmemoContainer(Block).Blocks);
end;
end;
end;
end;
end;
procedure TKMemoRTFWriter.FillFontTable(ABlocks: TKMemoBlocks);
var
I: Integer;
Block: TKmemoBlock;
begin
if ABlocks <> nil then
begin
for I := 0 to ABlocks.Count - 1 do
begin
Block := Ablocks[I];
if CanSave(Block) then
begin
if Block is TKMemoTextBlock then
FFontTable.AddFont(TKmemoTextBlock(Block).TextStyle.Font)
else if Block is TKmemoContainer then
FillFontTable(TKmemoContainer(Block).Blocks);
end;
end;
end;
end;
procedure TKMemoRTFWriter.SaveToFile(const AFileName: TKString; ASelectedOnly: Boolean);
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
SaveToStream(Stream, ASelectedOnly);
Stream.SaveToFile(AFileName);
finally
Stream.Free;
end;
end;
procedure TKMemoRTFWriter.SaveToStream(AStream: TStream; ASelectedOnly: Boolean; AActiveBlocks: TKMemoBlocks);
var
ActiveBlocks, Blocks1, Blocks2, SavedBlocks1: TKMemoBlocks;
LocalIndex: TKMemoSelectionIndex;
begin
try
FStream := AStream;
FSelectedOnly := ASelectedOnly;
if AActiveBlocks <> nil then
ActiveBlocks := AActiveBlocks
else
ActiveBlocks := FMemo.ActiveBlocks;
if ActiveBlocks <> nil then
begin
if FSelectedOnly then
begin
// find common parent blocks for the selection and use this instead of main blocks
Blocks1 := ActiveBlocks.IndexToBlocks(ActiveBlocks.SelStart, LocalIndex);
Blocks2 := ActiveBlocks.IndexToBlocks(ActiveBlocks.SelEnd, LocalIndex);
SavedBlocks1 := Blocks1;
while Blocks1 <> Blocks2 do
begin
Blocks1 := Blocks1.ParentBlocks;
if Blocks1 = nil then
begin
Blocks2 := Blocks2.ParentBlocks;
if Blocks2 <> nil then
Blocks1 := SavedBlocks1;
end;
end;
// If the parent blocks are maintained by a container (eg. a table) which
// is placed in the text then take the outermost non-container blocks placed in the text
// or a container with relative or absolute position.
while (Blocks1.Parent is TKMemoContainer) and (Blocks1.Parent.Position = mbpText) do
Blocks1 := Blocks1.ParentBlocks;
ActiveBlocks := Blocks1;
end;
ActiveBlocks.ConcatEqualBlocks;
FCodePage := SystemCodepage;
WriteGroupBegin;
try
WriteHeader(ActiveBlocks);
WriteBackground;
WriteBody(ActiveBlocks, False);
finally
WriteGroupEnd;
end;
end;
except
KFunctions.Error(sErrMemoSaveToRTF);
end;
end;
procedure TKMemoRTFWriter.WriteBackground;
var
Shape: TKMemoRTFShape;
begin
if not FSelectedOnly and (FMemo <> nil) and ((FMemo.Colors.BkGnd <> clWindow) or (FMemo.Background.Image.Graphic <> nil)) then
begin
WriteCtrlParam('viewbksp', 1);
WriteGroupBegin;
try
WriteUnknownGroup;
WriteCtrl('background');
WriteSpace;
Shape := TKmemoRTFShape.Create;
try
Shape.ContentType := sctRectangle;
Shape.FitToShape := False;
Shape.FitToText := False;
Shape.Style.WrapMode := wrUnknown;
Shape.Style.Brush.Color := FMemo.Colors.BkGnd;
Shape.Style.FillBlip := FMemo.Background.Image.Graphic;
Shape.Background := True;
Shape.HorzPosCode := 0;
Shape.VertPosCode := 0;
WriteShape(Shape, False);
finally
Shape.Free;
end;
finally
WriteGroupEnd;
end;
end;
end;
procedure TKMemoRTFWriter.WriteBody(ABlocks: TKMemoBlocks; AInsideOfTable: Boolean);
var
I: Integer;
Block: TKMemoBlock;
PA: TKMemoParagraph;
IsParagraph: Boolean;
URL: TKString;
begin
if ABlocks <> nil then
begin
URL := '';
IsParagraph := False;
for I := 0 to ABlocks.Count - 1 do
begin
Block := ABlocks[I];
if CanSave(Block) then
begin
if Block is TKMemoHyperlink then
begin
if URL <> TKMemoHyperlink(Block).URL then
begin
if URL <> '' then
WriteHyperlinkEnd;
WriteHyperlinkBegin(TKMemoHyperlink(Block));
URL := TKMemoHyperlink(Block).URL;
end;
WriteTextBlock(TKMemoTextBlock(Block), FSelectedOnly)
end else
begin
if URL <> '' then
begin
WriteHyperlinkEnd;
URL := '';
end;
if IsParagraph then
begin
PA := ABlocks.GetNearestParagraphBlock(I);
if PA <> nil then
WriteListText(PA.NumberBlock);
IsParagraph := False;
end;
if Block is TKMemoParagraph then
begin
if not AInsideOfTable or (I < ABlocks.Count - 1) then
WriteParagraph(TKMemoParagraph(Block), AInsideOfTable);
IsParagraph := True;
end
else if Block is TKMemoTextBlock then
WriteTextBlock(TKMemoTextBlock(Block), FSelectedOnly)
else if Block is TKMemoImageBlock then
WriteImageBlock(TKMemoImageBlock(Block), AInsideOfTable)
else if Block is TKMemoContainer then
begin
if Block is TKMemoTable then
WriteTable(TKMemoTable(Block))
else if Block.Position <> mbpText then
WriteContainer(TKMemoContainer(Block), AInsideOfTable)
else
WriteBody(TKMemoContainer(Block).Blocks, AInsideOfTable) // just save the contents
end;
end;
end;
end;
if URL <> '' then
WriteHyperlinkEnd;
end;
end;
procedure TKMemoRTFWriter.WriteColorTable;
var
I: Integer;
ColorRec: TKColorRec;
begin
WriteGroupBegin;
try
WriteCtrl('colortbl');
// WriteSemicolon; // no default color, write all colors explictly
for I := 0 to FColorTable.Count - 1 do
begin
ColorRec := FColorTable[I].ColorRec;
WriteCtrlParam('red', ColorRec.R);
WriteCtrlParam('green', ColorRec.G);
WriteCtrlParam('blue', ColorRec.B);
WriteSemiColon;
end;
finally
WriteGroupEnd;
end;
end;
procedure TKMemoRTFWriter.WriteContainer(ABlock: TKMemoContainer;
AInsideTable: Boolean);
var
Shape: TKMemoRTFShape;
begin
// write generic container - write as RTF text box
Shape := TKMemoRTFShape.Create;
try
Shape.ContentType := sctTextBox;
Shape.Block := ABlock;
Shape.ContentPosition.Left := ABlock.LeftOffset;
Shape.ContentPosition.Top := ABlock.TopOffset;
Shape.ContentPosition.Right := ABlock.LeftOffset + ABlock.RequiredWidth;
Shape.ContentPosition.Bottom := ABlock.TopOffset + ABlock.RequiredHeight;
Shape.FitToText := not ABlock.FixedHeight;
Shape.HorzPosCode := 2; // position by column, we don't support any other
Shape.VertPosCode := 2; // position by paragraph, we don't support any other
Shape.Style.Assign(ABlock.BlockStyle);
WriteShape(Shape, AInsideTable);
finally
Shape.Free;
end;
end;
procedure TKMemoRTFWriter.WriteCtrl(const ACtrl: AnsiString);
begin
WriteString('\' + ACtrl);
end;
procedure TKMemoRTFWriter.WriteCtrlParam(const ACtrl: AnsiString;
AParam: Integer);
begin
WriteString(AnsiString(Format('\%s%d', [ACtrl, AParam])));
end;
procedure TKMemoRTFWriter.WriteFontTable;
var
I, Pitch, Charset: Integer;
begin
WriteGroupBegin;
try
WriteCtrl('fonttbl');
for I := 0 to FFontTable.Count - 1 do
begin
WriteGroupBegin;
try
WriteCtrlParam('f', I);
Charset := FFontTable[I].Font.Charset;
{if Charset = 0 then
Charset := CPToCharset(FCodePage); // don't override charset, it is still important for certain fonts!}
WriteCtrlParam('fcharset', Charset);
case FFontTable[I].Font.Pitch of
fpFixed: Pitch := 1;
fpVariable: Pitch := 2;
else
Pitch := 0;
end;
WriteCtrlParam('fprq', Pitch);
WriteSpace;
WriteString(AnsiString(FFontTable[I].Font.Name));
WriteSemiColon;
finally
WriteGroupEnd;
end;
end;
finally
WriteGroupEnd;
end;
end;
procedure TKMemoRTFWriter.WriteGroupBegin;
begin
if FReadableOutput and (FStream.Size > 0) then
WriteString(cCR+cLF);
WriteString('{');
Inc(FGroupLevel);
end;
procedure TKMemoRTFWriter.WriteGroupEnd;
begin
Dec(FGroupLevel);
WriteString('}');
end;
procedure TKMemoRTFWriter.WriteHeader(ABlocks: TKMemoBlocks);
begin
if FMemo <> nil then
begin
FFontTable.AddFont(FMemo.TextStyle.Font);
FListTable.AssignFromListTable(FMemo.ListTable, FFontTable);
end;
FillFontTable(ABlocks);
FillColorTable(ABlocks);
WriteCtrl('rtf1');
WriteCtrl('ansi');
WriteCtrlParam('ansicpg', FCodePage);
if FFontTable.Count > 0 then
WriteCtrlParam('deff', 0);
WriteCtrlParam('uc', 1);
WriteFontTable;
WriteColorTable;
WriteListTable;
end;
procedure TKMemoRTFWriter.WriteHyperlinkBegin(ABlock: TKMemoHyperlink);
begin
WriteGroupBegin;
WriteCtrl('field');
WriteGroupBegin;
try
WriteUnknownGroup;
WriteCtrl('fldinst');
WriteSpace;
WriteString(cRTFHyperlink);
WriteSpace;
WriteUnicodeString(TKMemoHyperLink(ABlock).URL);
finally
WriteGroupEnd;
end;
WriteGroupBegin;
WriteCtrl('fldrslt');
end;
procedure TKMemoRTFWriter.WriteHyperlinkEnd;
begin
WriteGroupEnd;
WriteGroupEnd;
end;
procedure TKMemoRTFWriter.WriteImage(ABlock: TKmemoImageBlock);
begin
WriteCtrlParam('picw', PixelsToTwipsX(ABlock.NativeOrExplicitWidth));
WriteCtrlParam('pich', PixelsToTwipsY(ABlock.NativeOrExplicitHeight));
WriteCtrlParam('picscalex', MulDiv(ABlock.ScaleWidth, 100, ABlock.NativeOrExplicitWidth));
WriteCtrlParam('picscaley', MulDiv(ABlock.ScaleHeight, 100, ABlock.NativeOrExplicitHeight));
WriteCtrlParam('picwgoal', PixelsToTwipsX(ABlock.ScaleWidth));
WriteCtrlParam('pichgoal', PixelsToTwipsY(ABlock.ScaleHeight));
WriteCtrlParam('piccropb', PixelsToTwipsY(ABlock.Crop.Bottom));
WriteCtrlParam('piccropl', PixelsToTwipsX(ABlock.Crop.Left));
WriteCtrlParam('piccropr', PixelsToTwipsX(ABlock.Crop.Right));
WriteCtrlParam('piccropt', PixelsToTwipsY(ABlock.Crop.Top));
WritePicture(ABlock.Image);
end;
procedure TKMemoRTFWriter.WriteImageBlock(ABlock: TKmemoImageBlock; AInsideTable: Boolean);
var
Shape: TKMemoRTFShape;
begin
// write generic container - write as RTF text box
Shape := TKMemoRTFShape.Create;
try
Shape.ContentType := sctImage;
Shape.FitToShape := False;
Shape.FitToText := False;
Shape.Style.Assign(ABlock.ImageStyle);
if ABlock.Position = mbpText then
begin
WriteGroupBegin;
try
WriteUnknownGroup;
WriteCtrl('shppict');
WriteGroupBegin;
try
WriteCtrl('pict');
WriteGroupBegin;
try
WriteUnknownGroup;
WriteCtrl('picprop');
WriteShapeProperties(Shape);
finally
WriteGroupEnd;
end;
WriteImage(ABlock);
finally
WriteGroupEnd;
end;
finally
WriteGroupEnd;
end;
end else
begin
Shape.Block := ABlock;
Shape.ContentPosition.Left := ABlock.LeftOffset;
Shape.ContentPosition.Top := ABlock.TopOffset;
Shape.ContentPosition.Right := ABlock.LeftOffset + ABlock.ScaleWidth + ABlock.ImageStyle.LeftPadding + ABlock.ImageStyle.RightPadding;
Shape.ContentPosition.Bottom := ABlock.TopOffset + ABlock.ScaleHeight + ABlock.ImageStyle.TopPadding + ABlock.ImageStyle.BottomPadding;
Shape.HorzPosCode := 2; // we don't support any other
Shape.VertPosCode := 2; // we don't support any other
WriteShape(Shape, AInsideTable);
end;
finally
Shape.Free;
end;
end;
procedure TKMemoRTFWriter.WriteListTable;
var
I, J, K, Len: Integer;
Item: TKMemoRTFList;
Level: TKMemoRTFListLevel;
NFItem: TKMemoNumberingFormatItem;
OverrideItem: TKMemoDictionaryItem;
begin
// first write list table
WriteGroupBegin;
try
WriteUnknownGroup;
WriteCtrl('listtable');
for I := 0 to FListTable.Count - 1 do
begin
Item := FListTable[I];
WriteGroupBegin;
try
WriteCtrl('list');
for J := 0 to Item.Levels.Count - 1 do
begin
Level := Item.Levels[J];
WriteGroupBegin;
try
WriteCtrl('listlevel');
WriteCtrlParam('levelnfc', Level.NumberType);
WriteCtrlParam('levelstartat', Level.StartAt);
WriteGroupBegin;
try
WriteCtrl('leveltext');
for K := 0 to Level.NumberingFormat.Count - 1 do
begin
NFItem := Level.NumberingFormat[K];
if (NFItem.Level >= 0) and (NFItem.Text = '') then
WriteString(AnsiString(Format('\''%.2x', [NFItem.Level])))
else
WriteUnicodeString(NFItem.Text)
end;
WriteSemiColon;
finally
WriteGroupEnd;
end;
WriteGroupBegin;
try
WriteCtrl('levelnumbers');
Len := 1;
for K := 1 to Level.NumberingFormat.Count - 1 do
begin
NFItem := Level.NumberingFormat[K];
if (NFItem.Level >= 0) and (NFItem.Text = '') then
begin
WriteString(AnsiString(Format('\''%.2x', [Len])));
Inc(Len);
end else
Inc(Len, StringLength(NFItem.Text));
end;
WriteSemiColon;
finally
WriteGroupEnd;
end;
if Level.FontIndex >= 0 then
WriteCtrlParam('f', Level.FontIndex);
WriteCtrlParam('fi', PixelsToTwipsX(Level.FirstIndent));
WriteCtrlParam('li', PixelsToTwipsX(Level.LeftIndent));
finally
WriteGroupEnd;
end;
end;
WriteCtrlParam('listid', Item.ID);
finally
WriteGroupEnd;
end;
end;
finally
WriteGroupEnd;
end;
// next write list override table
WriteGroupBegin;
try
WriteUnknownGroup;
WriteCtrl('listoverridetable');
for I := 0 to FListTable.Overrides.Count - 1 do
begin
OverrideItem := FListTable.Overrides[I];
WriteGroupBegin;
try
WriteCtrl('listoverride');
WriteCtrlParam('listid', OverrideItem.Value);
WriteCtrlParam('ls', OverrideItem.Index);
finally
WriteGroupEnd;
end;
end;
finally
WriteGroupEnd;
end;
end;
procedure TKMemoRTFWriter.WriteListText(ANumberBlock: TKMemoTextBlock);
begin
if ANumberBlock <> nil then
begin
WriteGroupBegin;
try
WriteCtrl('listtext');
WriteTextBlock(ANumberBlock, False);
finally
WriteGroupEnd;
end;
end;
end;
procedure TKMemoRTFWriter.WriteParagraph(ABlock: TKMemoParagraph; AInsideTable: Boolean);
begin
WriteGroupBegin;
try
WriteParaStyle(ABlock.ParaStyle);
WriteTextStyle(ABlock.TextStyle);
if AinsideTable then
WriteCtrl('intbl');
WriteCtrl('par');
finally
WriteGroupEnd;
end;
end;
procedure TKMemoRTFWriter.WriteParaStyle(AParaStyle: TKMemoParaStyle);
begin
WriteCtrl('pard'); // always store complete paragraph properties
if AParaStyle.FirstIndent <> 0 then
WriteCtrlParam('fi', PixelsToTwipsX(AParaStyle.FirstIndent));
if AParaStyle.LeftPadding <> 0 then
WriteCtrlParam('li', PixelsToTwipsX(AParaStyle.LeftPadding));
if AParaStyle.RightPadding <> 0 then
WriteCtrlParam('ri', PixelsToTwipsX(AParaStyle.RightPadding));
if AParaStyle.TopPadding <> 0 then
WriteCtrlParam('sb', PixelsToTwipsY(AParaStyle.TopPadding));
if AParaStyle.BottomPadding <> 0 then
WriteCtrlParam('sa', PixelsToTwipsY(AParaStyle.BottomPadding));
case AParaStyle.HAlign of
halLeft: WriteCtrl('ql');
halCenter: WriteCtrl('qc');
halRight: WriteCtrl('qr');
halJustify: WriteCtrl('qj');
end;
if AParaStyle.Brush.Style <> bsClear then
WriteCtrlParam('cbpat', FColorTable.GetIndex(AParaStyle.Brush.Color));
if not AParaStyle.WordWrap then
WriteCtrl('nowwrap');
if AParaStyle.BorderWidths.NonZero then
begin
if AParaStyle.BorderWidths.Bottom > 0 then
begin
WriteCtrl('brdrb');
WriteCtrlParam('brdrw', PixelsToTwipsY(AParaStyle.BorderWidths.Bottom))
end;
if AParaStyle.BorderWidths.Left > 0 then
begin
WriteCtrl('brdrl');
WriteCtrlParam('brdrw', PixelsToTwipsX(AParaStyle.BorderWidths.Left))
end;
if AParaStyle.BorderWidths.Right > 0 then
begin
WriteCtrl('brdrr');
WriteCtrlParam('brdrw', PixelsToTwipsX(AParaStyle.BorderWidths.Right))
end;
if AParaStyle.BorderWidths.Top > 0 then
begin
WriteCtrl('brdrt');
WriteCtrlParam('brdrw', PixelsToTwipsY(AParaStyle.BorderWidths.Top))
end;
end else
begin
if AParaStyle.BorderWidth > 0 then
begin
WriteCtrl('box');
WriteCtrlParam('brdrw', PixelsToTwipsX(AParaStyle.BorderWidth))
end;
if AParaStyle.BorderRadius > 0 then
WriteCtrlParam('brdrradius', PixelsToTwipsX(AParaStyle.BorderRadius))
end;
if AParaStyle.BorderColor <> clNone then
WriteCtrlParam('brdrcf', FColorTable.GetIndex(AParaStyle.BorderColor));
if AParaStyle.LineSpacingValue <> 0 then
begin
if AParaStyle.LineSpacingMode = lsmValue then
begin
WriteCtrlParam('sl', PixelsToTwipsY(AParaStyle.LineSpacingValue));
WriteCtrlParam('slmult', 0)
end else
begin
WriteCtrlParam('sl', Round(AParaStyle.LineSpacingFactor * 240));
WriteCtrlParam('slmult', 1)
end;
end;
if AParaStyle.NumberingList <> cInvalidListID then
WriteCtrlParam('ls', FListTable.FindByID(AParaStyle.NumberingList));
if AParaStyle.NumberingListLevel >= 0 then
WriteCtrlParam('ilvl', AParaStyle.NumberingListLevel);
if AParaStyle.NumberStartAt > 0 then
WriteCtrlParam('lsstartat', AParaStyle.NumberStartAt);
end;
procedure TKMemoRTFWriter.WritePicture(AImage: TGraphic);
var
MS: TMemoryStream;
S, ImgData: AnsiString;
begin
if AImage <> nil then
begin
if AImage is TJPegImage then
WriteCtrl('jpegblip')
{$IFDEF USE_PNG_SUPPORT}
else if AImage is TKPngImage then
WriteCtrl('pngblip')
{$ENDIF}
{$IFDEF MSWINDOWS}
else if AImage is TKMetafile then
begin
if TKMetafile(AImage).Enhanced then
WriteCtrl('emfblip')
else
WriteCtrlParam('wmetafile', 8);
end
{$ENDIF}
;
MS := TMemoryStream.Create;
try
AImage.SaveToStream(MS);
MS.Seek(0, soFromBeginning);
SetLength(S, MS.Size);
MS.Read(S[1], MS.Size);
finally
MS.Free;
end;
WriteSpace;
ImgData := BinaryToDigits(S);
WriteString(ImgData);
end;
end;
procedure TKMemoRTFWriter.WriteSemiColon;
begin
WriteString(';');
end;
procedure TKMemoRTFWriter.WriteShape(AShape: TKMemoRTFShape; AInsideTable: Boolean);
begin
WriteGroupBegin;
try
WriteCtrl('shp');
WriteGroupBegin;
try
WriteUnknownGroup;
WriteCtrl('shpinst');
WriteCtrlParam('shpbottom', PixelsToTwipsY(Ashape.ContentPosition.Bottom));
WriteCtrlParam('shpleft', PixelsToTwipsX(Ashape.ContentPosition.Left));
WriteCtrlParam('shpright', PixelsToTwipsX(Ashape.ContentPosition.Right));
WriteCtrlParam('shptop', PixelsToTwipsY(Ashape.ContentPosition.Top));
case AShape.HorzPosCode of
1: WriteCtrl('shpbxpage');
2: WriteCtrl('shpbxcolumn');
else
WriteCtrl('shpbxmargin');
end;
case AShape.VertPosCode of
1: WriteCtrl('shpbypage');
2: WriteCtrl('shpbypara');
else
WriteCtrl('shpbymargin');
end;
WriteCtrlParam('shpfhdr', 0);
WriteCtrlParam('shpwr', AShape.Wrap);
WriteCtrlParam('shpwrk', AShape.WrapSide);
WriteShapeProperties(AShape);
case AShape.ContentType of
sctImage: if AShape.Block <> nil then
begin
WriteGroupBegin;
try
WriteCtrl('sp');
WriteShapePropName('pib');
WriteGroupBegin;
try
WriteCtrl('sv');
WriteSpace;
WriteGroupBegin;
try
WriteCtrl('pict');
WriteImage(AShape.Block as TKMemoImageBlock);
finally
WriteGroupEnd;
end;
finally
WriteGroupEnd;
end;
finally
WriteGroupEnd;
end;
end;
sctRectangle: if AShape.Style.FillBlip <> nil then
begin
WriteShapeProp('fillType', '3');
WriteGroupBegin;
try
WriteCtrl('sp');
WriteShapePropName('fillBlip');
WriteGroupBegin;
try
WriteCtrl('sv');
WriteSpace;
WriteGroupBegin;
try
WriteCtrl('pict');
WritePicture(AShape.Style.FillBlip);
finally
WriteGroupEnd;
end;
finally
WriteGroupEnd;
end;
finally
WriteGroupEnd;
end;
end;
sctTextbox: if AShape.Block <> nil then
begin
WriteGroupBegin;
try
WriteCtrl('shptxt');
WriteBody((AShape.Block as TKMemoContainer).Blocks, AInsideTable);
finally
WriteGroupEnd;
end;
end;
end;
finally
WriteGroupEnd;
end;
finally
WriteGroupEnd;
end;
end;
procedure TKMemoRTFWriter.WriteShapeProp(const APropName,
APropValue: AnsiString);
begin
WriteGroupBegin;
try
WriteCtrl('sp');
WriteShapePropName(APropName);
WriteShapePropValue(APropValue);
finally
WriteGroupEnd;
end;
end;
procedure TKMemoRTFWriter.WriteShapeProperties(AShape: TKMemoRTFShape);
var
B: Boolean;
begin
B := AShape.Style.Brush.Style <> bsClear;
case AShape.ContentType of
sctImage: WriteShapeProp('shapeType', '75');
sctRectangle: WriteShapeProp('shapeType', '1');
sctTextbox: WriteShapeProp('shapeType', '202');
end;
if AShape.FitToShape then
WriteShapeProp('fFitTextToShape', BoolToParam(True));
if AShape.FitToText then
WriteShapeProp('fFitShapeToText', BoolToParam(True));
WriteShapeProp('fFilled', BoolToParam(B));
if B then
WriteShapeProp('fillColor', ColorToParam(AShape.Style.Brush.Color));
B := AShape.Style.BorderWidth > 0;
WriteShapeProp('fLine', BoolToParam(B));
if B then
begin
WriteShapeProp('lineColor', ColorToParam(AShape.Style.BorderColor));
WriteShapeProp('lineWidth', EMUToParam(AShape.Style.BorderWidth));
end;
if AShape.Background then
WriteShapeProp('fBackground', BoolToParam(True));
end;
procedure TKMemoRTFWriter.WriteShapePropName(const APropName: AnsiString);
begin
WriteGroupBegin;
try
WriteCtrl('sn');
WriteSpace;
WriteString(APropName);
finally
WriteGroupEnd;
end;
end;
procedure TKMemoRTFWriter.WriteShapePropValue(const APropValue: AnsiString);
begin
WriteGroupBegin;
try
WriteCtrl('sv');
WriteSpace;
WriteString(APropValue);
finally
WriteGroupEnd;
end;
end;
procedure TKMemoRTFWriter.WriteSpace;
begin
WriteString(' ');
end;
procedure TKMemoRTFWriter.WriteString(const AText: AnsiString);
begin
FStream.Write(AText[1], Length(AText));
end;
procedure TKMemoRTFWriter.WriteTable(ABlock: TKMemoTable);
var
I, J, SavedRow, SavedRowCount: Integer;
Row: TKMemoTableRow;
Cell: TKMemoTableCell;
begin
SavedRowCount := 0;
for I := 0 to ABlock.RowCount - 1 do
begin
Row := ABlock.Rows[I];
if CanSave(Row) then
Inc(SavedRowCount);
end;
SavedRow := 0;
for I := 0 to ABlock.RowCount - 1 do
begin
Row := ABlock.Rows[I];
if CanSave(Row) then
begin
WriteCtrl('trowd');
WriteTableRowProperties(ABlock, I, SavedRow);
for J := 0 to Row.CellCount - 1 do
begin
Cell := Row.Cells[J];
if Cell.ColSpan >= 0 then
begin
WriteParaStyle(Cell.ParaStyle);
if (Cell.Blocks.Count > 0) and ((Cell.Blocks.Count > 1) or not(Cell.Blocks[0] is TKmemoParagraph)) then
begin
WriteGroupBegin;
try
WriteBody(Cell.Blocks, True);
finally
WriteGroupEnd;
end;
end;
WriteCtrl('cell');
end;
end;
WriteGroupBegin;
try
WriteCtrl('trowd');
WriteTableRowProperties(ABlock, I, SavedRow);
if SavedRow = SavedRowCount - 1 then
WriteCtrl('lastrow');
WriteCtrl('row');
finally
WriteGroupEnd;
end;
Inc(SavedRow);
end;
end;
end;
procedure TKMemoRTFWriter.WriteTableRowProperties(ATable: TKMemoTable; ARowIndex, ASavedRowIndex: Integer);
procedure WriteBorderWidth(AWidth: Integer);
begin
if AWidth <> 0 then
begin
WriteCtrl('brdrs');
WriteCtrlParam('brdrw', PixelsToTwipsX(AWidth))
end else
WriteCtrl('brdrnone');
end;
var
Cell: TKMemoTableCell;
Row: TKMemoTableRow;
I, W, XPos: Integer;
RowPadd: TRect;
begin
WriteCtrlParam('irow', ASavedRowIndex);
Xpos := 0;
Row := ATable.Rows[ARowIndex];
RowPadd := CreateEmptyRect;
for I := 0 to Row.CellCount - 1 do
begin
Cell := Row.Cells[I];
RowPadd.Bottom := Max(RowPadd.Bottom, Cell.BlockStyle.BottomPadding);
RowPadd.Left := Max(RowPadd.Left, Cell.BlockStyle.LeftPadding);
RowPadd.Right := Max(RowPadd.Right, Cell.BlockStyle.RightPadding);
RowPadd.Top := Max(RowPadd.Top, Cell.BlockStyle.TopPadding);
end;
WriteCtrlParam('trpaddb', PixelsToTwipsY(RowPadd.Bottom));
WriteCtrlParam('trpaddl', PixelsToTwipsX(RowPadd.Left));
WriteCtrlParam('trpaddr', PixelsToTwipsX(RowPadd.Right));
WriteCtrlParam('trpaddt', PixelsToTwipsY(RowPadd.Top));
for I := 0 to Row.CellCount - 1 do
begin
Cell := Row.Cells[I];
if Cell.ColSpan >= 0 then
begin
if Cell.BlockStyle.BottomPadding <> RowPadd.Bottom then
WriteCtrlParam('clpadb', PixelsToTwipsY(RowPadd.Bottom));
if Cell.BlockStyle.LeftPadding <> RowPadd.Left then
WriteCtrlParam('clpadl', PixelsToTwipsX(RowPadd.Left));
if Cell.BlockStyle.RightPadding <> RowPadd.Right then
WriteCtrlParam('clpadr', PixelsToTwipsX(RowPadd.Right));
if Cell.BlockStyle.TopPadding <> RowPadd.Top then
WriteCtrlParam('clpadt', PixelsToTwipsY(RowPadd.Top));
if Cell.RowSpan > 1 then
WriteCtrl('clvmgf')
else if Cell.RowSpan <= 0 then
WriteCtrl('clvmrg');
WriteCtrl('clbrdrb');
WriteBorderWidth(Cell.RequiredBorderWidths.Bottom);
WriteCtrlParam('brdrcf', FColorTable.GetIndex(Cell.BlockStyle.BorderColor));
WriteCtrl('clbrdrl');
WriteBorderWidth(Cell.RequiredBorderWidths.Left);
WriteCtrlParam('brdrcf', FColorTable.GetIndex(Cell.BlockStyle.BorderColor));
WriteCtrl('clbrdrr');
WriteBorderWidth(Cell.RequiredBorderWidths.Right);
WriteCtrlParam('brdrcf', FColorTable.GetIndex(Cell.BlockStyle.BorderColor));
WriteCtrl('clbrdrt');
WriteBorderWidth(Cell.RequiredBorderWidths.Top);
WriteCtrlParam('brdrcf', FColorTable.GetIndex(Cell.BlockStyle.BorderColor));
if Cell.BlockStyle.Brush.Style <> bsClear then
WriteCtrlParam('clcbpat', FColorTable.GetIndex(Cell.BlockStyle.Brush.Color));
W := Max(ATable.CalcTotalCellWidth(I, ARowIndex), 5);
WriteCtrlParam('clwWidth', PixelsToTwipsX(W));
Inc(Xpos, W);
WriteCtrlParam('cellx', PixelsToTwipsX(XPos));
end;
end;
end;
procedure TKMemoRTFWriter.WriteTextBlock(ABlock: TKMemoTextBlock; ASelectedOnly: Boolean);
var
S: TKString;
begin
WriteGroupBegin;
try
if ASelectedOnly then
S := ABlock.SelText
else
S := ABlock.Text;
WriteTextStyle(ABlock.TextStyle);
WriteSpace;
WriteUnicodeString(S);
finally
WriteGroupEnd;
end;
end;
procedure TKMemoRTFWriter.WriteTextStyle(ATextStyle: TKMemoTextStyle);
begin
WriteCtrlParam('f', FFontTable.GetIndex(ATextStyle.Font));
if fsBold in ATextStyle.Font.Style then
WriteCtrl('b');
if fsItalic in ATextStyle.Font.Style then
WriteCtrl('i');
if fsUnderline in ATextStyle.Font.Style then
WriteCtrl('ul');
if fsStrikeout in ATextStyle.Font.Style then
WriteCtrl('strike');
case ATextStyle.Capitals of
tcaNormal: WriteCtrl('caps');
tcaSmall: WriteCtrl('scaps');
end;
WriteCtrlParam('fs', ATextStyle.Font.Size * 2);
if ATextStyle.Font.Color <> clNone then
WriteCtrlParam('cf', FColorTable.GetIndex(ATextStyle.Font.Color));
if ATextStyle.Brush.Style <> bsClear then
WriteCtrlParam('highlight', FColorTable.GetIndex(ATextStyle.Brush.Color));
case ATextStyle.ScriptPosition of
tpoSuperscript: WriteCtrl('super');
tpoSubscript: WriteCtrl('sub');
end;
end;
procedure TKMemoRTFWriter.WriteUnicodeString(const AText: TKString);
var
I: Integer;
UnicodeValue: SmallInt;
WasAnsi: Boolean;
S, Ansi: AnsiString;
C: TKChar;
begin
S := '';
for I := 1 to StringLength(AText) do
begin
{$IFDEF FPC}
C := LazUTF8.UTF8Copy(AText, I, 1);
if Length(C) = 1 then
{$ELSE}
C := AText[I];
if Ord(C) < $80 then
{$ENDIF}
begin
if C = #9 then
S := AnsiString(Format('%s\tab ', [S]))
else if (C = '\') or (C = '{') or (C = '}') then
S := AnsiString(Format('%s\%s', [S, TKString(C)]))
else
S := S + AnsiString(C)
end else
begin
WasAnsi := False;
if FCodePage <> 0 then
begin
// first try Ansi codepage conversion for better backward compatibility
Ansi := StringToAnsiString(C, FCodePage);
if (Length(Ansi) = 1) and (Ansi <> #0) then
begin
S := AnsiString(Format('%s\''%.2x', [S, Ord(Ansi[1])]));
WasAnsi := True;
end;
end;
if not WasAnsi then
begin
// next store as Unicode character
UnicodeValue := Ord(NativeUTFToUnicode(C));
S := AnsiString(Format('%s\u%d\''3F', [S, UnicodeValue]));
end;
end;
end;
if S <> '' then
WriteString(S);
end;
procedure TKMemoRTFWriter.WriteUnknownGroup;
begin
WriteCtrl('*');
end;
end.
tomboy-ng_0.34-1/kcontrols/source/kdialogs.pas 0000644 0001750 0001750 00000035165 14125207534 021250 0 ustar dbannon dbannon { @abstract(This file is part of the KControls component suite for Delphi and Lazarus.)
@author(Tomas Krysl)
Copyright (c) 2020 Tomas Krysl
License:
This code is licensed under BSD 3-Clause Clear License, see file License.txt or https://spdx.org/licenses/BSD-3-Clause-Clear.html.
}
unit kdialogs; // lowercase name because of Lazarus/Linux
{$include kcontrols.inc}
{$WEAKPACKAGEUNIT ON}
interface
uses
Classes, Controls, Forms, SysUtils, KFunctions, KControls, KPrintPreview, KPrintSetup;
type
{ Specifies the root folder for TKBrowseFolderDialog dialog - RootFolder property. }
TKRootFolder = (brAdminTools, brAltStartUp, brAppData,
brBitBucket, brCommonAdminTools, brCommonAltStartUp,
brCommonAppData, brCommonDesktopDirectory, brCommonDocuments,
brCommonFavorites, brCommonPrograms, brCommonStartMenu,
brCommonStartUp, brCommonTemplates, brControls, brCookies,
brDesktop, brDesktopDirectory, brDrives, brFavorites, brFonts,
brHistory, brInternet, brInternetCache, brLocalAppData,
brMyMusic, brMyPictures, brNetHood, brNetWork, brPersonal,
brPrinters, brPrintHood, brProfile, brProgramFiles,
brProgramFilesCommon, brPrograms, brRecent, brSendTo,
brStartMenu, brStartUp, brSystem, brTemplates, brWindows,
brCustom);
TFolder = type string;
{ Specifies the folder options for TKBrowseFolderDialog dialog - Options property. }
TKBrowseFolderOption = (bfSetFolder, bfBrowseForComputer, bfBrowseForPrinter,
bfBrowseIncludeFiles, bfBrowseIncludeURLs, bfDontGoBelowDomain,
bfEditBox, bfNewDialogStyle, bfReturnFSAncestors, bfReturnOnlyFSDirs,
bfShareAble, bfStatusText, bfUseNewUI, bfValidate);
TKBrowseFolderOptions = set of TKBrowseFolderOption;
{ Specifies the initial position for TKBrowseFolderDialog dialog - Position property. }
TKBrowseFolderPosition = (poDefault, poScreenCenter, poCustom);
{ @abstract(Encapsulates the print preview dialog) }
TKPrintPreviewDialog = class(TComponent)
private
FControl: TKCustomControl;
FPrintPreviewForm: TKPrintPreviewForm;
function GetPrintPreviewForm: TKPrintPreviewForm;
public
{ Creates the instance. Assigns default values to properties. }
constructor Create(AOwner: TComponent); override;
{ Shows the dialog. }
procedure Show;
{ Shows the dialog as modal dialog. }
function Execute: Boolean;
{ Specifies the associated preview form. }
property PrintPreviewForm: TKPrintPreviewForm read GetPrintPreviewForm;
published
{ Specifies the associated control. }
property Control: TKCustomControl read FControl write FControl;
end;
{ @abstract(Encapsulates the print preview dialog) }
TKPrintSetupDialog = class(TComponent)
private
FControl: TKCustomControl;
FPreviewDialog: TKPrintPreviewDialog;
FSelAvail: Boolean;
protected
FPrintSetupForm: TKPrintSetupForm;
procedure SetupForm(AfterCreation: Boolean); virtual;
public
{ Creates the instance. Assigns default values to properties. }
constructor Create(AOwner: TComponent); override;
{ Shows the dialog as modal dialog. }
function Execute: Boolean;
published
{ Specifies the associated control. }
property Control: TKCustomControl read FControl write FControl;
{ Specifies the preview dialog for the Preview... button.
If not specified, the print setup dialog creates a new one. }
property PreviewDialog: TKPrintPreviewDialog read FPreviewDialog write FPreviewDialog;
{ If True, the Selection Only option will be checked (if selection is available
for the control). }
property SelAvail: Boolean read FSelAvail write FSelAvail default True;
end;
{ @abstract(Encapsulates the browse for folder dialog - Windows only) }
TKBrowseFolderDialog = class(TComponent)
private
FParentWindow: TWinControl;
FFolder: TFolder;
FLabelText: string;
FPosition: TKBrowseFolderPosition;
FCustomRootFolder: TFolder;
FOptions: TKBrowseFolderOptions;
FRootFolder: TKRootFolder;
FCustomLeft,
FCustomTop: Integer;
procedure SetFolder(const Value: TFolder);
public
{ Creates the instance. Assigns default values to properties. }
constructor Create(AOwner: TComponent); override;
{ Shows the dialog as modal dialog. }
function Execute: Boolean;
property LabelText: string read FLabelText write FLabelText;
published
property CustomRootFolder: TFolder read FCustomRootFolder write FCustomRootFolder;
property Folder: TFolder read FFolder write SetFolder;
property Options: TKBrowseFolderOptions read FOptions write FOptions;
property ParentWindow: TWinControl read FParentWindow write FParentWindow;
property Position: TKBrowseFolderPosition read FPosition write FPosition default poScreenCenter;
property RootFolder: TKRootFolder read FRootFolder write FRootFolder;
property CustomLeft: Integer index 1 read FCustomLeft write FCustomLeft default 100;
property CustomTop: Integer index 2 read FCustomTop write FCustomTop default 100;
end;
implementation
uses
KRes
{$IFDEF MSWINDOWS}
, ActiveX, ShlObj, Windows, Messages
{$ENDIF}
;
{$IFDEF MSWINDOWS}
const
{Common Controls version 5.O extensions}
BIF_BROWSEINCLUDEURLS = $0080;
BIF_NEWDIALOGSTYLE = $0040;
BIF_SHAREABLE = $8000;
BIF_USENEWUI = BIF_NEWDIALOGSTYLE + BIF_EDITBOX;
CSIDL_FLAG_CREATE = $8000;
CSIDL_ADMINTOOLS = $0030;
CSIDL_COMMON_ADMINTOOLS = $002F;
CSIDL_COMMON_APPDATA = $0023;
CSIDL_COMMON_DOCUMENTS = $002E;
CSIDL_LOCAL_APPDATA = $001C;
CSIDL_MYMUSIC = $0028;
CSIDL_MYPICTURES = $0027;
CSIDL_PROGRAM_FILES = $0026;
CSIDL_PROGRAM_FILES_COMMON = $002B;
CSIDL_SYSTEM = $0025;
CSIDL_WINDOWS = $0024;
{$IFDEF FPC}
// message from browser
BFFM_INITIALIZED = 1;
BFFM_SELCHANGED = 2;
BFFM_VALIDATEFAILEDA = 3; // lParam:szPath ret:1(cont),0(EndDialog)
BFFM_VALIDATEFAILEDW = 4; // lParam:wzPath ret:1(cont),0(EndDialog)
BFFM_IUNKNOWN = 5; // provides IUnknown to client. lParam: IUnknown*
// messages to browser
BFFM_SETSTATUSTEXTA = WM_USER + 100;
BFFM_ENABLEOK = WM_USER + 101;
BFFM_SETSELECTIONA = WM_USER + 102;
BFFM_SETSELECTIONW = WM_USER + 103;
BFFM_SETSTATUSTEXTW = WM_USER + 104;
BFFM_SETOKTEXT = WM_USER + 105; // Unicode only
BFFM_SETEXPANDED = WM_USER + 106; // Unicode only
{$IFDEF UNICODE}
BFFM_VALIDATEFAILED = BFFM_VALIDATEFAILEDW;
BFFM_SETSTATUSTEXT = BFFM_SETSTATUSTEXTW;
BFFM_SETSELECTION = BFFM_SETSELECTIONW;
{$ELSE}
BFFM_VALIDATEFAILED = BFFM_VALIDATEFAILEDA;
BFFM_SETSTATUSTEXT = BFFM_SETSTATUSTEXTA;
BFFM_SETSELECTION = BFFM_SETSELECTIONA;
{$ENDIF}
{$ENDIF}
{$ENDIF}
{ TKPrintPreviewDialog }
constructor TKPrintPreviewDialog.Create(AOwner: TComponent);
begin
inherited;
FPrintPreviewForm := nil;
FControl := nil;
end;
function TKPrintPreviewDialog.Execute;
begin
PrintPreviewForm.Preview.Control := FControl;
PrintPreviewForm.ShowModal;
Result := True;
end;
function TKPrintPreviewDialog.GetPrintPreviewForm: TKPrintPreviewForm;
begin
if not Assigned(FPrintPreviewForm) then
FPrintPreviewForm := TKPrintPreviewForm.Create(Self);
Result := FPrintPreviewForm;
end;
procedure TKPrintPreviewDialog.Show;
begin
PrintPreviewForm.Preview.Control := FControl;
PrintPreviewForm.Show;
end;
{ TKPrintSetupDialog }
constructor TKPrintSetupDialog.Create(AOwner: TComponent);
begin
inherited;
FControl := nil;
FPrintSetupForm := nil;
FPreviewDialog := nil;
FSelAvail := True;
end;
function TKPrintSetupDialog.Execute: Boolean;
begin
if Assigned(FControl) then
begin
if not Assigned(FPrintSetupForm) then
begin
FPrintSetupForm := TKPrintSetupForm.Create(Self);
SetupForm(True);
end;
FPrintSetupForm.PageSetup := FControl.PageSetup;
if Assigned(FPreviewDialog) then
FPrintSetupForm.PreviewForm := FPreviewDialog.PrintPreviewForm;
SetupForm(False);
Result := FPrintSetupForm.ShowModal = mrOk;
end else
Result := False;
end;
procedure TKPrintSetupDialog.SetupForm(AfterCreation: Boolean);
begin
if not AfterCreation then
FPrintSetupForm.SelAvail := FSelAvail;
end;
{ TKBrowseFolderDialog }
{$IFDEF MSWINDOWS}
function BFCallBack(Wnd: HWND; uMsg: UINT; lPar, lpData: LPARAM): Integer stdcall;
var
Allocator: IMalloc;
Location: PItemIDList;
begin
with TKBrowseFolderDialog(lpData) do
try
if uMsg = BFFM_INITIALIZED then
begin
if (bfSetFolder in Options) and (Folder <> '') then
SendMessage(Wnd, BFFM_SETSELECTION, Integer(TRUE), LPARAM(PChar(Folder)))
else
begin
SHGetMAlloc(Allocator);
try
SHGetSpecialFolderLocation(Application.MainForm.Handle, CSIDL_DRIVES, Location);
SendMessage(Wnd, BFFM_SETSELECTION, Integer(FALSE), LPARAM(Location));
finally
Allocator.Free(Location);
end;
end;
case Position of
poScreenCenter: CenterWindowOnScreen(Wnd);
poCustom: SetWindowPos(Wnd, 0, CustomLeft, CustomTop, 0, 0, SWP_NOSIZE or SWP_NOZORDER);
end;
end;
except
end;
Result := 0;
end;
{$ENDIF}
constructor TKBrowseFolderDialog.Create(AOwner: TComponent);
begin
inherited;
FParentWindow := nil;
FFolder := '';
FLabelText := sBrowseDirectory;
FOptions := [bfSetFolder, bfReturnOnlyFSDirs, bfDontGoBelowDomain, bfUseNewUI];
FRootFolder := brDesktop;
FPosition := poScreenCenter;
FCustomLeft := 100;
FCustomTop := 100;
end;
function TKBrowseFolderDialog.Execute: Boolean;
{$IFDEF MSWINDOWS}
var
BI: TBrowseInfo;
Buf: PChar;
List, Root: PItemIDList;
Allocator: IMalloc;
DesktopFolder: IShellFolder;
I: Integer;
Eaten, Flags: LongWord;
{$IFDEF FPC}
DisabledList: TList;
{$ELSE}
P: Pointer;
{$ENDIF}
begin
Result := False;
SHGetMAlloc(Allocator);
if Allocator <> nil then
begin
GetMem(Buf, MAX_PATH);
{$IFDEF FPC}
DisabledList := Screen.DisableForms(nil, nil);
{$ELSE}
P := DisableTaskWindows(0);
{$ENDIF}
try
if FParentWindow <> nil then
BI.hwndOwner := FParentWindow.Handle
else
BI.hwndOwner := Application.MainForm.Handle;
case FRootFolder of
brAdminTools: I := CSIDL_ADMINTOOLS;
brAltStartUp: I := CSIDL_ALTSTARTUP;
brAppData: I := CSIDL_APPDATA;
brBitBucket: I := CSIDL_BITBUCKET;
brCommonAdminTools: I := CSIDL_COMMON_ADMINTOOLS;
brCommonAltStartUp: I := CSIDL_COMMON_ALTSTARTUP;
brCommonAppData: I := CSIDL_COMMON_APPDATA;
brCommonDesktopDirectory: I := CSIDL_COMMON_DESKTOPDIRECTORY;
brCommonDocuments: I := CSIDL_COMMON_DOCUMENTS;
brCommonFavorites: I := CSIDL_COMMON_FAVORITES;
brCommonPrograms: I := CSIDL_COMMON_PROGRAMS;
brCommonStartMenu: I := CSIDL_COMMON_STARTMENU;
brCommonStartUp: I := CSIDL_COMMON_STARTUP;
brControls: I := CSIDL_CONTROLS;
brCookies: I := CSIDL_COOKIES;
brDesktop: I := CSIDL_DESKTOP;
brDesktopDirectory: I := CSIDL_DESKTOPDIRECTORY;
brDrives: I := CSIDL_DRIVES;
brFavorites: I := CSIDL_FAVORITES;
brFonts: I := CSIDL_FONTS;
brHistory: I := CSIDL_HISTORY;
brInternet: I := CSIDL_INTERNET;
brInternetCache: I := CSIDL_INTERNET_CACHE;
brLocalAppData: I := CSIDL_LOCAL_APPDATA;
brMyMusic: I := CSIDL_MYMUSIC;
brMyPictures: I := CSIDL_MYPICTURES;
brNetHood: I := CSIDL_NETHOOD;
brNetwork: I := CSIDL_NETWORK;
brPersonal: I := CSIDL_PERSONAL;
brPrinters: I := CSIDL_PRINTERS;
brPrintHood: I := CSIDL_PRINTHOOD;
brProgramFiles: I := CSIDL_PROGRAM_FILES;
brProgramFilesCommon: I := CSIDL_PROGRAM_FILES_COMMON;
brPrograms: I := CSIDL_PROGRAMS;
brRecent: I := CSIDL_RECENT;
brSendTo: I := CSIDL_SENDTO;
brStartMenu: I := CSIDL_STARTMENU;
brStartUp: I := CSIDL_STARTUP;
brSystem: I := CSIDL_SYSTEM;
brTemplates: I := CSIDL_TEMPLATES;
brWindows: I := CSIDL_WINDOWS;
else
I := CSIDL_DESKTOP;
end;
if FRootFolder <> brCustom then
SHGetSpecialFolderLocation(Application.MainForm.Handle, I, Root)
else
begin
SHGetDesktopFolder(DesktopFolder);
try
Eaten := 0; Flags := 0;
DesktopFolder.ParseDisplayName(Application.MainForm.Handle, nil,
PWideChar(WideString(FCustomRootFolder)), Eaten, Root, Flags);
except
Root := nil;
end;
end;
BI.pidlRoot := Root;
BI.pszDisplayName := Buf;
BI.lpszTitle := PChar(FLabelText);
BI.ulFlags := 0;
if bfBrowseForComputer in FOptions then BI.ulFlags := BIF_BROWSEFORCOMPUTER;
if bfBrowseForPrinter in FOptions then BI.ulFlags := BI.ulFlags or BIF_BROWSEFORPRINTER;
if bfBrowseIncludeFiles in FOptions then BI.ulFlags := BI.ulFlags or BIF_BROWSEINCLUDEFILES;
if bfBrowseIncludeURLs in FOptions then BI.ulFlags := BI.ulFlags or BIF_BROWSEINCLUDEURLS or BIF_USENEWUI or BIF_BROWSEINCLUDEFILES;
if bfEditBox in FOptions then BI.ulFlags := BI.ulFlags or BIF_EDITBOX;
if bfNewDialogStyle in FOptions then BI.ulFlags := BI.ulFlags or BIF_NEWDIALOGSTYLE;
if bfReturnFSAncestors in FOptions then BI.ulFlags := BI.ulFlags or BIF_RETURNFSANCESTORS;
if bfReturnOnlyFSDirs in FOptions then BI.ulFlags := BIF_RETURNONLYFSDIRS;
if bfShareAble in FOptions then BI.ulFlags := BIF_SHAREABLE or BIF_USENEWUI;
if bfStatusText in FOptions then BI.ulFlags := BI.ulFlags or BIF_STATUSTEXT;
if bfUseNewUI in FOptions then BI.ulFlags := BI.ulFlags or BIF_USENEWUI;
if bfValidate in FOptions then BI.ulFlags := BI.ulFlags or BIF_VALIDATE;
BI.lpfn := BFCallBack;
BI.lParam := Integer(Self);
List := SHBrowseForFolder({$IFDEF FPC}@BI{$ELSE}BI{$ENDIF});
if List <> nil then
begin
SHGetPathFromIDList(List, Buf);
Allocator.Free(List);
FFolder := Buf;
Result := True;
end;
finally
{$IFDEF FPC}
Screen.EnableForms(DisabledList);
{$ELSE}
EnableTaskWindows(P);
{$ENDIF}
Allocator.Free(Root);
FreeMem(Buf);
end;
end;
end;
{$ELSE}
begin
Result := False;
end;
{$ENDIF}
procedure TKBrowseFolderDialog.SetFolder(const Value: TFolder);
begin
FFolder := Value;
end;
end.
tomboy-ng_0.34-1/kcontrols/source/kprintsetup.pas 0000644 0001750 0001750 00000032137 14125207534 022037 0 ustar dbannon dbannon { @abstract(This file is part of the KControls component suite for Delphi and Lazarus.)
@author(Tomas Krysl)
Copyright (c) 2020 Tomas Krysl
License:
This code is licensed under BSD 3-Clause Clear License, see file License.txt or https://spdx.org/licenses/BSD-3-Clause-Clear.html.
}
unit kprintsetup; // lowercase name because of Lazarus/Linux
{$include kcontrols.inc}
interface
uses
{$IFDEF FPC}
LCLType, LCLIntf, LResources, {$IFnDEF LCLWinCE}PrintersDlgs, {$ENDIF}
{$ELSE}
Windows, Messages, Dialogs,
{$ENDIF}
SysUtils, Variants, Classes, Graphics, Controls, Forms,
StdCtrls, ExtCtrls, KControls, KPrintPreview;
type
TPrintEvent = procedure(PageSetup: TKPrintPageSetup) of object;
TExtPrintOption = (
xpoRange,
xpoScale
);
TExtPrintOptions = set of TExtPrintOption;
{ TKPrintSetupForm }
TKPrintSetupForm = class(TForm)
BUConfigure: TButton;
CoBPrinterName: TComboBox;
EDTitle: TEdit;
GBFileToPrint: TGroupBox;
GBPrinter: TGroupBox;
GBPrintOptions: TGroupBox;
LBPrinterName: TLabel;
BUPrint: TButton;
BUCancel: TButton;
CBFitToPage: TCheckBox;
CBPageNumbers: TCheckBox;
CBUseColor: TCheckBox;
GBMargins: TGroupBox;
CoBMarginUnits: TComboBox;
LBMarginUnits: TLabel;
CBMirrorMargins: TCheckBox;
GBPageSelection: TGroupBox;
RBAll: TRadioButton;
RBRange: TRadioButton;
RBSelectedOnly: TRadioButton;
LBRangeTo: TLabel;
LBCopies: TLabel;
EDLeft: TEdit;
LBLeft: TLabel;
LBRight: TLabel;
EDRight: TEdit;
EDTop: TEdit;
LBTop: TLabel;
EDBottom: TEdit;
LBBottom: TLabel;
EDRangeFrom: TEdit;
EDRangeTo: TEdit;
EDCopies: TEdit;
Label1: TLabel;
EDPrintScale: TEdit;
LBUnitsLeft: TLabel;
LBUnitsTop: TLabel;
LBUnitsRight: TLabel;
LBUnitsBottom: TLabel;
BUPreview: TButton;
CBPaintSelection: TCheckBox;
BUOk: TButton;
CBPrintTitle: TCheckBox;
CBCollate: TCheckBox;
CBLineNumbers: TCheckBox;
CBWrapLines: TCheckBox;
procedure BUConfigureClick(Sender: TObject);
procedure CoBMarginUnitsChange(Sender: TObject);
procedure RBAllClick(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure BUPreviewClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure EDTopExit(Sender: TObject);
procedure CBPageNumbersClick(Sender: TObject);
procedure BUPrintClick(Sender: TObject);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
FPrevSetup: TKPrintPageSetup;
FPageSetup: TKPrintPageSetup;
FPreviewForm: TKCustomPrintPreviewForm;
FPreviewCreated: Boolean;
FSelAvail: Boolean;
FUpdateLock: Boolean;
FOnPrintClick: TPrintEvent;
FOptionsVisible: TKPrintOptions;
FOptionsEnabled: TKPrintOptions;
FExtOptionsEnabled: TExtPrintOptions;
{$IFnDEF LCLWinCE}
FPSD: TPrinterSetupDialog;
{$ENDIF}
procedure SetPageSetup(const Value: TKPrintPageSetup);
procedure SetPreviewForm(const Value: TKCustomPrintPreviewForm);
protected
procedure PageSetupToForm; virtual;
procedure FormToPageSetup; virtual;
procedure ValidateForm;
public
{ Public declarations }
property PageSetup: TKPrintPageSetup read FPageSetup write SetPageSetup;
property PreviewForm: TKCustomPrintPreviewForm read FPreviewForm write SetPreviewForm;
property SelAvail: Boolean read FSelAvail write FSelAvail;
property OnPrintClick: TPrintEvent read FOnPrintClick write FOnPrintClick;
property OptionsVisible: TKPrintOptions read FOptionsVisible write FOptionsVisible;
property OptionsEnabled: TKPrintOptions read FOptionsEnabled write FOptionsEnabled;
property ExtOptionsEnabled: TExtPrintOptions read FExtOptionsEnabled write FExtOptionsEnabled;
end;
implementation
{$IFDEF FPC}
{$R *.lfm}
{$ELSE}
{$R *.dfm}
{$ENDIF}
uses
Printers, KFunctions, KRes, KMessageBox;
procedure TKPrintSetupForm.FormCreate(Sender: TObject);
begin
FPageSetup := nil;
FPrevSetup := TKPrintPageSetup.Create(nil);
FPreviewForm := nil;
FPreviewCreated := False;
FOptionsVisible := [poCollate..poUseColor];
FOptionsEnabled := FOptionsVisible;
FExtOptionsEnabled := [Low(TExtPrintOption)..High(TExtPrintOption)];
{$IfnDEF LCLWinCE}
FPSD := TPrinterSetupDialog.Create(Self);
{$IFDEF FPC}
FPSD.Title := sPSPrinterSetup;
{$ENDIF}
{$ENDIF}
end;
procedure TKPrintSetupForm.FormDestroy(Sender: TObject);
begin
if FPreviewCreated then
begin
FPreviewForm.Free;
FPreviewCreated := False;
end;
FPrevSetup.Free;
end;
procedure TKPrintSetupForm.FormShow(Sender: TObject);
begin
PageSetupToForm;
end;
procedure TKPrintSetupForm.PageSetupToForm;
function FmtMargin(Value: Double): string;
const
Fmt = '%.*f';
var
Precision: Integer;
begin
case FPageSetup.Units of
puCM: Precision := 1;
puMM: Precision := 0;
puInch: Precision := 2;
else
Precision := 0;
end;
Result := Format(Fmt, [Precision, Value]);
end;
function FmtUnit: string;
begin
case FPageSetup.Units of
puMM: Result := 'mm';
puInch: Result := '"';
puHundredthInch: Result := '".100';
else
Result := 'cm';
end;
end;
procedure SetupCheckBox(CB: TCheckBox; Option: TKPrintOption);
begin
CB.Checked := Option in FPageSetup.Options;
CB.Enabled := Option in FOptionsEnabled;
CB.Visible := Option in FOptionsVisible;
end;
var
S: string;
begin
if Assigned(FPageSetup) then
begin
FUpdateLock := True;
try
SetupCheckBox(CBCollate, poCollate);
SetupCheckBox(CBFitToPage, poFitToPage);
SetupCheckBox(CBPageNumbers, poPageNumbers);
SetupCheckBox(CBUseColor, poUseColor);
SetupCheckBox(CBPaintSelection, poPaintSelection);
SetupCheckBox(CBPrintTitle, poTitle);
SetupCheckBox(CBLineNumbers, poLineNumbers);
SetupCheckBox(CBWrapLines, poWrapLines);
SetupCheckBox(CBMirrorMargins, poMirrorMargins);
try
CoBPrinterName.Text := '';
CoBPrinterName.Items.Assign(Printer.Printers);
CoBPrinterName.ItemIndex := CoBPrinterName.Items.IndexOf(FPageSetup.PrinterName);
if FPageSetup.IsDefaultPrinter then
begin
if CoBPrinterName.ItemIndex < 0 then CoBPrinterName.ItemIndex := Printer.PrinterIndex;
end else
begin
// no default printer selected!
if CoBPrinterName.Items.Count > 0 then
CoBPrinterName.ItemIndex := 0;
end;
except
// silent, keep default or successfully obtained data
end;
RBSelectedOnly.Enabled := FPageSetup.SelAvail and FSelAvail;
case FPageSetup.Range of
prRange: RBRange.Checked := True;
prAll: RBAll.Checked := True;
prSelectedOnly: RBSelectedOnly.Checked := True;
end;
RBAll.Caption := Format(sPSAllPages, [FPageSetup.PageCount]);
RBRange.Enabled := xpoRange in FExtOptionsEnabled;
EDRangeFrom.Enabled := RBRange.Checked and RBRange.Enabled;
EDRangeFrom.Text := IntToStr(FPageSetup.StartPage);
EDRangeTo.Enabled := RBRange.Checked and RBRange.Enabled;
EDRangeTo.Text := IntToStr(FPageSetup.EndPage);
EDCopies.Text := IntToStr(FPageSetup.Copies);
EDPrintScale.Enabled := not CBFitTopage.Checked and (xpoScale in FExtOptionsEnabled);
EDPrintScale.Text := IntToStr(FPageSetup.Scale);
EDTitle.Text := FPageSetup.Title;
CoBMarginUnits.ItemIndex := Integer(FPageSetup.Units);
S := FmtUnit;
EDBottom.Text := FmtMargin(FPageSetup.UnitMarginBottom); LBUnitsBottom.Caption := S;
EDLeft.Text := FmtMargin(FPageSetup.UnitMarginLeft); LBUnitsLeft.Caption := S;
EDRight.Text := FmtMargin(FPageSetup.UnitMarginRight); LBUnitsRight.Caption := S;
EDTop.Text := FmtMargin(FPageSetup.UnitMarginTop); LBUnitsTop.Caption := S;
finally
FUpdateLock := False;
end;
end;
end;
procedure TKPrintSetupForm.FormToPageSetup;
var
Options: TKPrintOptions;
begin
if Assigned(FPageSetup) and not FUpdateLock then
begin
FPageSetup.LockUpdate;
try
Options := [];
if CBCollate.Checked then Include(Options, poCollate);
if CBFitToPage.Checked then Include(Options, poFitToPage);
if CBPageNumbers.Checked then Include(Options, poPageNumbers);
if CBUseColor.Checked then Include(Options, poUseColor);
if CBPaintSelection.Checked then Include(Options, poPaintSelection);
if CBPrintTitle.Checked then Include(Options, poTitle);
if CBMirrorMargins.Checked then Include(Options, poMirrorMargins);
if CBLineNumbers.Checked then Include(Options, poLineNumbers);
if CBWrapLines.Checked then Include(Options, poWrapLines);
FPageSetup.PrinterName := CoBPrinterName.Text;
FPageSetup.Options := Options;
if RBSelectedOnly.Checked then FPageSetup.Range := prSelectedOnly
else if RBRange.Checked then FPageSetup.Range := prRange
else FPageSetup.Range := prAll;
FPageSetup.StartPage := StrToIntDef(EDRangeFrom.Text, FPageSetup.StartPage);
FPageSetup.EndPage := StrToIntDef(EDRangeTo.Text, FPageSetup.EndPage);
FPageSetup.Copies := StrToIntDef(EDCopies.Text, FPageSetup.Copies);
FPageSetup.Scale := StrToIntDef(EDPrintScale.Text, FPageSetup.Scale);
FPageSetup.Title := EDTitle.Text;
FPageSetup.Units := TKPrintUnits(CoBMarginUnits.ItemIndex);
FPageSetup.UnitMarginBottom := StrToFloatDef(AdjustDecimalSeparator(EDBottom.Text), FPageSetup.UnitMarginBottom);
FPageSetup.UnitMarginLeft := StrToFloatDef(AdjustDecimalSeparator(EDLeft.Text), FPageSetup.UnitMarginLeft);
FPageSetup.UnitMarginRight := StrToFloatDef(AdjustDecimalSeparator(EDRight.Text), FPageSetup.UnitMarginRight);
FPageSetup.UnitMarginTop := StrToFloatDef(AdjustDecimalSeparator(EDTop.Text), FPageSetup.UnitMarginTop);
finally
FPageSetup.UnlockUpdate;
end;
end;
end;
procedure TKPrintSetupForm.BUPrintClick(Sender: TObject);
begin
FormToPageSetup;
if Assigned(FOnPrintClick) then
FOnPrintClick(FPageSetup)
else
FPageSetup.PrintOut;
end;
procedure TKPrintSetupForm.BUConfigureClick(Sender: TObject);
var
PrinterCount: Integer;
begin
{$IFDEF LCLWinCE}
KMsgBox(sPSErrPrintSetup, sPSErrPrinterConfiguration, [mbOk], miStop)
{$ELSE}
FormToPageSetup;
if FPageSetup.IsDefaultPrinter then
begin
PrinterCount := 0;
try
PrinterCount := Printer.Printers.Count;
Printer.Orientation := FPageSetup.Orientation;
Printer.Copies := FPageSetup.Copies;
if FPSD.Execute then
begin
FPageSetup.LockUpdate;
try
FPageSetup.Orientation := Printer.Orientation;
FPageSetup.Copies := Printer.Copies;
finally
FPageSetup.UnlockUpdate;
end;
PageSetupToForm;
end;
except
if PrinterCount = 0 then
KMsgBox(sPSErrPrintSetup, sPSErrNoPrinterInstalled, [mbOk], miStop)
else
KMsgBox(sPSErrPrintSetup, sPSErrPrinterUnknown, [mbOk], miStop);
end
end else
KMsgBox(sPSErrPrintSetup, sPSErrNoDefaultPrinter, [mbOk], miStop)
{$ENDIF}
end;
procedure TKPrintSetupForm.EDTopExit(Sender: TObject);
begin
if not FUpdateLock then
ValidateForm;
end;
procedure TKPrintSetupForm.CoBMarginUnitsChange(Sender: TObject);
begin
if Assigned(FPageSetup) then
begin
FPageSetup.Units := TKPrintUnits(CoBMarginUnits.ItemIndex);
PageSetupToForm;
end;
end;
procedure TKPrintSetupForm.CBPageNumbersClick(Sender: TObject);
begin
FormToPageSetup;
end;
procedure TKPrintSetupForm.RBAllClick(Sender: TObject);
begin
if not FUpdateLock then
ValidateForm;
end;
procedure TKPrintSetupForm.SetPageSetup(const Value: TKPrintPageSetup);
begin
if Value <> FPageSetup then
begin
FPrevSetup.Assign(Value);
FPageSetup := Value;
PageSetupToForm;
end;
end;
procedure TKPrintSetupForm.SetPreviewForm(const Value: TKCustomPrintPreviewForm);
begin
if Value <> FPreviewForm then
begin
if FPreviewCreated then
begin
FPreviewForm.Free;
FPreviewCreated := False;
end;
FPreviewForm := Value;
end;
end;
procedure TKPrintSetupForm.ValidateForm;
begin
FormToPageSetup;
PageSetupToForm;
end;
procedure TKPrintSetupForm.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
begin
if FPreviewCreated then
FPreviewForm.Hide;
if ModalResult = mrOk then
FormToPageSetup
else if Assigned(FPageSetup) then
FPageSetup.Assign(FPrevSetup);
end;
procedure TKPrintSetupForm.BUPreviewClick(Sender: TObject);
begin
ValidateForm;
if FPreviewForm = nil then
begin
FPreviewForm := TKPrintPreviewForm.Create(nil);
FPreviewCreated := True;
end;
if FPreviewForm is TKPrintPreviewForm then
TKPrintPreviewForm(FPreviewForm).Preview.Control := FPageSetup.Control;
FPreviewForm.Show;
end;
end.
tomboy-ng_0.34-1/kcontrols/source/kcontrols.lrs 0000644 0001750 0001750 00000004105 14125207534 021474 0 ustar dbannon dbannon LazarusResources.Add('kpreview_cursor_hand_free','CUR',[
#0#0#2#0#1#0' '#0#0#15#0#15#0'0'#1#0#0#22#0#0#0'('#0#0#0' '#0#0#0'@'#0#0#0#1
+#0#1#0#0#0#0#0#128#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255
+#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#3#240#0
+#0#3#240#0#0#7#240#0#0#15#248#0#0#31#248#0#0#31#252#0#0'?'#252#0#0'w'#252#0#0
+'g'#254#0#0#7#246#0#0#13#182#0#0#13#178#0#0#25#176#0#0#25#176#0#0#1#128#0#0#0
+#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255
+#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255
+#255#255#255#255#255#255#255#255#255#255#255#255#248#7#255#255#248#7#255#255
+#240#7#255#255#224#3#255#255#192#3#255#255#192#1#255#255#128#1#255#255#0#1
+#255#255#0#0#255#255#144#0#255#255#224#0#255#255#224#0#255#255#192#5#255#255
+#192#7#255#255#228#15#255#255#254#127#255#255#255#255#255#255#255#255#255#255
+#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255
+#255#255#255#255
]);
LazarusResources.Add('kpreview_cursor_hand_grip','CUR',[
#0#0#2#0#1#0' '#0#0#15#0#15#0'0'#1#0#0#22#0#0#0'('#0#0#0' '#0#0#0'@'#0#0#0#1
+#0#1#0#0#0#0#0#128#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255
+#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0
+#0#0#0#0#0#0#0#0#7#224#0#0#7#224#0#0#15#224#0#0#31#240#0#0'?'#240#0#0'?'#248
+#0#0#15#248#0#0#15#248#0#0#31#232#0#0#27'`'#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0
+#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#255#255#255#255#255
+#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255
+#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255
+#255#255#240#15#255#255#240#15#255#255#224#15#255#255#192#7#255#255#128#7#255
+#255#128#3#255#255#192#3#255#255#224#3#255#255#192#3#255#255#192#7#255#255
+#228#159#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255
+#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255#255
+#255#255#255#255#255
]);
tomboy-ng_0.34-1/kcontrols/source/kmessagebox.res 0000644 0001750 0001750 00000036124 14125207534 021765 0 ustar dbannon dbannon @
K M E S S A G E B O X _ S T O P 0 PNG
IHDR 0 0 W kIDATh}?9{}a"J)Ԥ6iim-mim*hZ4Z[iS"M5%(^^Teua}sv{gws.\;ɓ9/3s>~G%͵BB!RJ Lf̘A84MLDJYy&d2y<m{GK3hnnUU4440cƌ