
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@44 8e941d3f-bd1b-0410-a28a-d453659cc2b4
1007 lines
28 KiB
ObjectPascal
1007 lines
28 KiB
ObjectPascal
{*********************************************************}
|
|
{* OVCPB.PAS 4.06 *}
|
|
{*********************************************************}
|
|
|
|
{* ***** BEGIN LICENSE BLOCK ***** *}
|
|
{* Version: MPL 1.1 *}
|
|
{* *}
|
|
{* The contents of this file are subject to the Mozilla Public License *}
|
|
{* Version 1.1 (the "License"); you may not use this file except in *}
|
|
{* compliance with the License. You may obtain a copy of the License at *}
|
|
{* http://www.mozilla.org/MPL/ *}
|
|
{* *}
|
|
{* Software distributed under the License is distributed on an "AS IS" basis, *}
|
|
{* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *}
|
|
{* for the specific language governing rights and limitations under the *}
|
|
{* License. *}
|
|
{* *}
|
|
{* The Original Code is TurboPower Orpheus *}
|
|
{* *}
|
|
{* The Initial Developer of the Original Code is TurboPower Software *}
|
|
{* *}
|
|
{* Portions created by TurboPower Software Inc. are Copyright (C)1995-2002 *}
|
|
{* TurboPower Software Inc. All Rights Reserved. *}
|
|
{* *}
|
|
{* Contributor(s): *}
|
|
{* *}
|
|
{* ***** END LICENSE BLOCK ***** *}
|
|
|
|
|
|
{$I OVC.INC}
|
|
|
|
{$B-} {Complete Boolean Evaluation}
|
|
{$I+} {Input/Output-Checking}
|
|
{$P+} {Open Parameters}
|
|
{$T-} {Typed @ Operator}
|
|
{.W-} {Windows Stack Frame}
|
|
{$X+} {Extended Syntax}
|
|
|
|
unit ovcpb;
|
|
{-Base picture field class, Picture and Numeric fields are derived from this}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFNDEF LCL} Windows, Messages, {$ELSE} LclIntf, LMessages, LclType, MyMisc, {$ENDIF}
|
|
Classes, Graphics, SysUtils, OvcConst,
|
|
OvcData, OvcEF, OvcStr;
|
|
|
|
type
|
|
TOvcPictureBase = class(TOvcBaseEntryField)
|
|
{.Z+}
|
|
protected {private}
|
|
pfSemiLits : Byte; {# of semi-literals in field}
|
|
pfPicFlags : TPictureFlags; {picture flags array}
|
|
pfSelPos : Integer; {current position of selection highlight}
|
|
|
|
{windows message methods}
|
|
procedure WMSetFocus(var Msg : TWMSetFocus);
|
|
message WM_SETFOCUS;
|
|
procedure WMKillFocus(var Msg : TWMKillFocus);
|
|
message WM_KILLFOCUS;
|
|
|
|
protected
|
|
procedure CreateWnd;
|
|
override;
|
|
|
|
function efCanClose(DoValidation : Boolean) : Boolean;
|
|
override;
|
|
{-return True if window can be closed}
|
|
procedure efCaretToEnd;
|
|
override;
|
|
{-move the caret to the end of the field}
|
|
procedure efCaretToStart;
|
|
override;
|
|
{-move the caret to the beginning of the field}
|
|
procedure efChangeMask(Mask : PAnsiChar);
|
|
override;
|
|
{-change the picture mask}
|
|
function efEditBegin : Word;
|
|
override;
|
|
{-return offset of first editable position in field}
|
|
function efEditEnd : Word;
|
|
{-return offset of last editable position in field}
|
|
function efFieldIsEmpty : Boolean;
|
|
override;
|
|
{-return True if the field is empty}
|
|
function efGetDisplayString(Dest : PAnsiChar; Size : Word) : PAnsiChar;
|
|
override;
|
|
{-return the display string in Dest and a pointer as the result}
|
|
procedure efRemoveBadOptions;
|
|
override;
|
|
{-remove inappropriate options for this field and data type}
|
|
procedure efSetCaretPos(Value : Integer);
|
|
override;
|
|
{-set position of caret within the field}
|
|
|
|
function pbCalcLength : Word;
|
|
{-calculate length of efEditSt}
|
|
procedure pbCalcWidthAndPlaces(var Width, Places : Word);
|
|
{-calculate width and decimal places for a numeric field}
|
|
procedure pbFixDecimalPoint(P : PAnsiChar);
|
|
{-fix decimal points for real numbers before merging}
|
|
procedure pbFixNumber(DotPos, StBgn, StEnd : Integer; FirstHalf, SecondHalf : Boolean);
|
|
{-fix the first and/or second half of a numeric field}
|
|
function pbIsLiteral(N : Word) : Boolean;
|
|
{-return True if N'th mask character is a literal. N is 0-based}
|
|
procedure pbInitPictureFlags;
|
|
{-initialize picture mask flags}
|
|
function pbIsNumber : Boolean;
|
|
{-return True if field is treated as numeric by MergePicture}
|
|
function pbIsSemiLiteral(N : Word) : Boolean;
|
|
{-return True if N'th mask character is a semi-literal. N is 0-based}
|
|
procedure pbMergePicture(const Dest, Src : PAnsiChar);
|
|
{-merge Src with efPicture and return result in Dest}
|
|
procedure pbOptimizeInitPictureFlags;
|
|
{-see if we can optimize InitPictureFlags}
|
|
procedure pbRemoveSemiLits;
|
|
virtual;
|
|
{-remove semi-literal mask characters from the edit string}
|
|
procedure pbRestoreSemiLits;
|
|
{-restore semi-literal mask characters in the edit string}
|
|
procedure pbStripLiterals(Dest, Src : PAnsiChar);
|
|
{-strip literal mask characters from source and put result in Dest}
|
|
procedure pbStripPicture(const Dest, Src : PAnsiChar);
|
|
{-strip the mask characters from Src and put result in Dest}
|
|
|
|
public
|
|
{interfaced for internal use only--to allow validation}
|
|
{helper routines access to the picture flags array}
|
|
procedure pbGetPictureFlags(var Flags : TPictureFlags);
|
|
{-return an array of the fields picture flags}
|
|
function GetStrippedEditString : string;
|
|
override;
|
|
{-return edit string stripped of literals and semi-literals}
|
|
procedure MergeWithPicture(const S : string);
|
|
override;
|
|
{-combines S with the picture mask and updates the edit string}
|
|
function ValidateContents(ReportError : Boolean) : Word;
|
|
override;
|
|
{.Z-}
|
|
end;
|
|
|
|
|
|
implementation
|
|
|
|
|
|
{*** TOvcPictureBase ***}
|
|
|
|
procedure TOvcPictureBase.CreateWnd;
|
|
begin
|
|
pbInitPictureFlags;
|
|
|
|
inherited CreateWnd;
|
|
|
|
{set flags for Real fields and clear DecimalPlaces if decimal point is in mask}
|
|
case efDataType mod fcpDivisor of
|
|
fsubReal, fsubExtended, fsubDouble, fsubSingle, fsubComp :
|
|
begin
|
|
Include(sefOptions, sefRealVar);
|
|
if StrScan(efPicture, pmDecimalPt) <> nil then
|
|
DecimalPlaces := 0;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbGetPictureFlags(var Flags : TPictureFlags);
|
|
{-return an array of the fields picture flags}
|
|
begin
|
|
Flags := pfPicFlags;
|
|
end;
|
|
|
|
function TOvcPictureBase.pbIsLiteral(N : Word) : Boolean;
|
|
{-return True if N'th mask character is a literal. N is 0-based}
|
|
begin
|
|
Result := pfPicFlags[N] = pflagLiteral;
|
|
end;
|
|
|
|
function TOvcPictureBase.pbIsSemiLiteral(N : Word) : Boolean;
|
|
{-return True if N'th mask character is a semi-literal. N is 0-based}
|
|
begin
|
|
Result := pfPicFlags[N] = pflagSemiLit;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbFixNumber(DotPos, StBgn, StEnd : Integer; FirstHalf, SecondHalf : Boolean);
|
|
{-fix the first and/or second half of a numeric field}
|
|
var
|
|
I, J, K : Integer;
|
|
SaveHP : Word;
|
|
|
|
function StartOfSubField : Word;
|
|
begin
|
|
Result := efHPos;
|
|
while (Result > StBgn) and not pbIsLiteral(Result - 1) do
|
|
Dec(Result);
|
|
end;
|
|
|
|
function EndOfSubField : Word;
|
|
begin
|
|
Result := efHPos;
|
|
while (Result < StEnd) and not pbIsLiteral(Result + 1) do
|
|
Inc(Result);
|
|
end;
|
|
|
|
begin
|
|
SaveHP := efHPos;
|
|
|
|
if FirstHalf then begin
|
|
{bring numbers to left of decimal flush right}
|
|
if DotPos = -1 then
|
|
efHPos := StEnd
|
|
else
|
|
efHPos := DotPos-1;
|
|
K := EndOfSubField;
|
|
J := StartOfSubField;
|
|
I := J;
|
|
while efEditSt[I] = ' ' do
|
|
Inc(I);
|
|
while I <= K do begin
|
|
if efEditSt[I] = ' ' then begin
|
|
StrStDeletePrim(efEditSt, I, 1);
|
|
StrChInsertPrim(efEditSt, ' ', J);
|
|
end;
|
|
Inc(I);
|
|
end;
|
|
|
|
{make sure it isn't all blanks to left of decimal}
|
|
if efEditSt[K] = ' ' then
|
|
efEditSt[K] := '0';
|
|
end;
|
|
|
|
if (DotPos <> -1) and SecondHalf then begin
|
|
efHPos := DotPos+1;
|
|
|
|
{bring numbers to right of decimal flush left}
|
|
J := EndOfSubField;
|
|
if efHPos <= J then begin
|
|
K := J;
|
|
J := StartOfSubField;
|
|
I := K;
|
|
while efEditSt[I] = ' ' do begin
|
|
efEditSt[I] := '0';
|
|
Dec(I);
|
|
end;
|
|
while I >= J do begin
|
|
if efEditSt[I] = ' ' then begin
|
|
StrStDeletePrim(efEditSt, I, 1);
|
|
StrChInsertPrim(efEditSt, '0', K);
|
|
end;
|
|
Dec(I);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
efHPos := SaveHP;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbStripLiterals(Dest, Src : PAnsiChar);
|
|
{-strip literal mask characters from source and put result in Dest}
|
|
var
|
|
I : Word;
|
|
begin
|
|
for I := 0 to MaxLength-1 do begin
|
|
if not pbIsLiteral(I) then begin
|
|
Dest^ := Src^;
|
|
Inc(Dest);
|
|
end;
|
|
Inc(Src);
|
|
end;
|
|
Dest^ := #0;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbFixDecimalPoint(P : PAnsiChar);
|
|
{-fix decimal points for real numbers before merging}
|
|
var
|
|
PT : PAnsiChar;
|
|
begin
|
|
PT := StrScan(P, pmDecimalPt);
|
|
if PT <> nil then
|
|
PT^ := IntlSupport.DecimalChar;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbRestoreSemiLits;
|
|
{-restore semi-literal mask characters in the edit string}
|
|
var
|
|
P : PChar;
|
|
begin
|
|
if not (sefFixSemiLits in sefOptions) then
|
|
Exit;
|
|
|
|
Exclude(sefOptions, sefFixSemiLits);
|
|
pbStripPicture(efEditSt, efEditSt);
|
|
P := StrScan(efEditSt, IntlSupport.DecimalChar);
|
|
if P <> nil then
|
|
P^ := pmDecimalPt;
|
|
pbMergePicture(efEditSt, efEditSt);
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbInitPictureFlags;
|
|
var
|
|
I : Word;
|
|
begin
|
|
if sefNoLiterals in sefOptions then begin
|
|
FillChar(pfPicFlags, MaxLength, pflagFormat);
|
|
pfPicFlags[MaxLength] := pflagLiteral;
|
|
end else begin
|
|
FillChar(pfPicFlags, MaxLength+1, pflagLiteral);
|
|
for I := 0 to MaxLength-1 do
|
|
if efNthMaskChar(I) in PictureChars then
|
|
pfPicFlags[I] := pflagFormat
|
|
else
|
|
case efNthMaskChar(I) of
|
|
pmFloatDollar, pmComma :
|
|
pfPicFlags[I] := pflagSemiLit;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TOvcPictureBase.pbIsNumber : Boolean;
|
|
{-return True if field is treated as numeric by MergePicture}
|
|
begin
|
|
Result :=
|
|
(pfSemiLits <> 0) or
|
|
(sefNumeric in sefOptions) or
|
|
(sefHexadecimal in sefOptions) or
|
|
(sefOctal in sefOptions) or
|
|
(sefBinary in sefOptions) or
|
|
(StrScan(efPicture, pmDecimalPt) <> nil) or
|
|
(StrScan(efPicture, pmCurrencyLt) <> nil) or
|
|
(StrScan(efPicture, pmCurrencyRt) <> nil);
|
|
end;
|
|
|
|
function TOvcPictureBase.pbCalcLength : Word;
|
|
{-calculate length of efEditSt}
|
|
var
|
|
I : Integer;
|
|
begin
|
|
I := efEditEnd;
|
|
while (I >= 0) and ((efEditSt[I] = ' ') or pbIsLiteral(I)) do
|
|
Dec(I);
|
|
Result := I + 1;
|
|
end;
|
|
|
|
function TOvcPictureBase.efGetDisplayString(Dest : PAnsiChar; Size : Word) : PAnsiChar;
|
|
{-return the display string in Dest}
|
|
var
|
|
I : Integer;
|
|
begin
|
|
Result := inherited efGetDisplayString(Dest, Size);
|
|
|
|
if Uninitialized and not (sefHaveFocus in sefOptions) then begin
|
|
FillChar(Dest[0], MaxLength, ' ');
|
|
Dest[MaxLength] := #0;
|
|
Exit;
|
|
end;
|
|
|
|
if (efoPasswordMode in Options) or (PadChar <> ' ') then begin
|
|
I := MaxLength-1;
|
|
while I >= 0 do begin
|
|
while (I >= 0) and pbIsLiteral(I) do
|
|
Dec(I);
|
|
|
|
if efFieldClass <> fcNumeric then
|
|
while (I >= 0) and (not pbIsLiteral(I)) and (Dest[I] = ' ') do begin
|
|
Dest[I] := PadChar;
|
|
Dec(I);
|
|
end;
|
|
|
|
while (I >= 0) and (not pbIsLiteral(I)) and (Dest[I] <> ' ') do begin
|
|
if (efoPasswordMode in Options) then
|
|
Dest[I] := PasswordChar;
|
|
Dec(I);
|
|
end;
|
|
|
|
if efFieldClass = fcNumeric then
|
|
while (I >= 0) and (not pbIsLiteral(I)) and (Dest[I] = ' ') do begin
|
|
Dest[I] := PadChar;
|
|
Dec(I);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TOvcPictureBase.efFieldIsEmpty : Boolean;
|
|
{-return True if the field is empty}
|
|
var
|
|
I : Word;
|
|
begin
|
|
I := 0;
|
|
Result := True;
|
|
while (I+1 <= MaxLength) and Result do
|
|
if (not pbIsLiteral(I)) and (efEditSt[I] <> ' ') then
|
|
Result := False
|
|
else
|
|
Inc(I);
|
|
end;
|
|
|
|
procedure TOvcPictureBase.efRemoveBadOptions;
|
|
{-remove inappropriate options for this field and data type}
|
|
begin
|
|
if csLoading in ComponentState then
|
|
Exit;
|
|
|
|
case efDataType of
|
|
fidPictureString :
|
|
if not (sefNoLiterals in sefOptions) then begin
|
|
Exclude( FOptions, efoRightJustify );
|
|
Exclude( FOptions, efoTrimBlanks );
|
|
end;
|
|
else
|
|
inherited efRemoveBadOptions;
|
|
end;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.efSetCaretPos(Value : Integer);
|
|
{-set position of caret within the field}
|
|
begin
|
|
if not (sefHaveFocus in sefOptions) then
|
|
Exit;
|
|
|
|
if Value < efEditBegin then
|
|
efHPos := efEditBegin
|
|
else if Value > efEditEnd then
|
|
efHPos := efEditEnd + 1
|
|
else begin
|
|
while pbIsLiteral(Value) do
|
|
Dec(Value);
|
|
efHPos := Value;
|
|
end;
|
|
efPositionCaret(True);
|
|
end;
|
|
|
|
procedure TOvcPictureBase.efCaretToStart;
|
|
{-move the caret to the beginning of the field}
|
|
begin
|
|
efHPos := efEditBegin;
|
|
efHOffset := 0;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.efCaretToEnd;
|
|
{-move the caret to the end of the field}
|
|
var
|
|
StEnd : Word;
|
|
begin
|
|
efHPos := pbCalcLength;
|
|
StEnd := efEditEnd;
|
|
while (efHPos < StEnd) and pbIsLiteral(efHPos) do
|
|
Inc(efHPos);
|
|
end;
|
|
|
|
function TOvcPictureBase.efEditBegin : Word;
|
|
{-return offset of first editable position in field}
|
|
var
|
|
I : Word;
|
|
begin
|
|
I := 0;
|
|
while (I < MaxLength-1) and (pfPicFlags[I] = pflagLiteral) do
|
|
Inc(I);
|
|
Result := I + pfSemiLits;
|
|
end;
|
|
|
|
function TOvcPictureBase.efEditEnd : Word;
|
|
{-return offset of last editable position in field}
|
|
begin
|
|
Result := MaxLength - 1;
|
|
while (Result > 0) and (pfPicFlags[Result] = pflagLiteral) do
|
|
Dec(Result);
|
|
end;
|
|
|
|
procedure TOvcPictureBase.efChangeMask(Mask : PAnsiChar);
|
|
{-change the picture mask}
|
|
var
|
|
I : Cardinal;
|
|
Buf : array[0..MaxEditLen] of Char;
|
|
begin
|
|
{save current value}
|
|
pbStripPicture(Buf, efEditSt);
|
|
|
|
inherited efChangeMask(Mask);
|
|
|
|
{disallow 'p' and 'g' in picture fields}
|
|
if efFieldClass <> fcNumeric then begin
|
|
if StrChPos(efPicture, pmNegParens, I) then
|
|
StrChDeletePrim(efPicture, I);
|
|
if StrChPos(efPicture, pmNegHere, I) then
|
|
StrChDeletePrim(efPicture, I);
|
|
end;
|
|
|
|
efPicLen := StrLen(efPicture);
|
|
if (MaxLength < efPicLen) or
|
|
((MaxLength <> efPicLen) and (efFieldClass = fcNumeric)) then begin
|
|
if not (csLoading in ComponentState) then
|
|
MaxLength := efPicLen;
|
|
end;
|
|
|
|
{clear the edit string}
|
|
FillChar(efEditSt, MaxEditLen, #0);
|
|
|
|
{see if we can optimize InitPictureFlags}
|
|
pbOptimizeInitPictureFlags;
|
|
|
|
{restore value}
|
|
pbMergePicture(efEditSt, Buf);
|
|
end;
|
|
|
|
function TOvcPictureBase.GetStrippedEditString : string;
|
|
{-return edit string stripped of literals and semi-literals}
|
|
var
|
|
Buf : TEditString;
|
|
begin
|
|
{get copy of edit string and limit to MaxEditLen}
|
|
StrLCopy(Buf, efEditSt, MaxEditLen);
|
|
|
|
{strip the copy of the edit string}
|
|
pbStripPicture(Buf, Buf);
|
|
Result := StrPas(Buf);
|
|
end;
|
|
|
|
procedure TOvcPictureBase.MergeWithPicture(const S : string);
|
|
{-combines S with the picture mask and updates the edit string}
|
|
var
|
|
Buf : TEditString;
|
|
begin
|
|
HandleNeeded;
|
|
StrPCopy(Buf, S);
|
|
pbMergePicture(efEditSt, Buf);
|
|
end;
|
|
|
|
function TOvcPictureBase.efCanClose(DoValidation : Boolean) : Boolean;
|
|
{-return True if window can be closed}
|
|
var
|
|
DotPos : Cardinal;
|
|
begin
|
|
if efFieldClass = fcPicture then
|
|
if ((sefModified in sefOptions) and (sefHaveFocus in sefOptions)) then
|
|
if StrChPos(efPicture, pmDecimalPt, DotPos) then
|
|
pbFixNumber(DotPos, efEditBegin, efEditEnd, True, True);
|
|
Result := inherited efCanClose(DoValidation);
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbRemoveSemiLits;
|
|
{-remove semi-literal mask characters from the edit string}
|
|
var
|
|
I : Cardinal;
|
|
B : Word;
|
|
E : Word;
|
|
P : Word;
|
|
D : Word;
|
|
Buf : array[0..255] of Char;
|
|
begin
|
|
if pfSemiLits = 0 then begin
|
|
if (sefHexadecimal in sefOptions) or (sefOctal in sefOptions) or
|
|
(sefBinary in sefOptions) then
|
|
Include(sefOptions, sefFixSemiLits);
|
|
Exit;
|
|
end;
|
|
|
|
Include(sefOptions, sefFixSemiLits);
|
|
|
|
B := efEditBegin;
|
|
E := efEditEnd;
|
|
P := B - pfSemiLits;
|
|
|
|
if StrScan(efPicture, pmFloatDollar) <> nil then begin
|
|
StrPCopy(Buf, IntlSupport.CurrencyLtStr);
|
|
if StrStPos(efEditSt, Buf, I) then begin
|
|
D := StrLen(Buf);
|
|
StrStDeletePrim(efEditSt, I, D);
|
|
StrInsertChars(efEditSt, ' ', P, D);
|
|
Inc(P, D);
|
|
end;
|
|
end;
|
|
|
|
if StrScan(efPicture, pmComma) <> nil then
|
|
for I := P{B} to E do
|
|
if (efEditSt[I] = IntlSupport.CommaChar) then begin
|
|
StrStDeletePrim(efEditSt, I, 1);
|
|
StrChInsertPrim(efEditSt, ' ', P);
|
|
Inc(P);
|
|
end;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbCalcWidthAndPlaces(var Width, Places : Word);
|
|
{-calculate width and decimal places for a numeric field}
|
|
var
|
|
I : Word;
|
|
DotPos : Cardinal;
|
|
begin
|
|
pbInitPictureFlags;
|
|
|
|
{find position of period and calculate decimal places}
|
|
if not StrChPos(efPicture, pmDecimalPt, DotPos) then
|
|
Places := DecimalPlaces
|
|
else begin
|
|
Places := 0;
|
|
I := DotPos+1;
|
|
while (pfPicFlags[I] = pflagFormat) do begin
|
|
Inc(Places);
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
|
|
{calculate width}
|
|
I := 0;
|
|
Width := 0;
|
|
while pbIsLiteral(I) or pbIsSemiLiteral(I) do
|
|
Inc(I);
|
|
while (pfPicFlags[I] = pflagFormat) or (efNthMaskChar(I) = pmComma) do begin
|
|
Inc(Width, Ord(pfPicFlags[I] = pflagFormat));
|
|
Inc(I);
|
|
end;
|
|
|
|
{add decimal places and period}
|
|
if (DotPos <> $FFFF) and (Places <> 0) then
|
|
Inc(Width, Places + 1);
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbOptimizeInitPictureFlags;
|
|
{-see if we can optimize InitPictureFlags}
|
|
var
|
|
I : Word;
|
|
begin
|
|
pfSemiLits := 0;
|
|
Exclude(sefOptions, sefNoLiterals);
|
|
pbInitPictureFlags;
|
|
Include(sefOptions, sefNoLiterals);
|
|
for I := 0 to MaxLength-1 do
|
|
case pfPicFlags[I] of
|
|
pflagLiteral :
|
|
Exclude(sefOptions, sefNoLiterals);
|
|
pflagSemiLit :
|
|
begin
|
|
Inc(pfSemiLits);
|
|
Exclude(sefOptions, sefNoLiterals);
|
|
end;
|
|
end;
|
|
|
|
{if we have literals, turn off TrimBlanks and RightJustify}
|
|
if not (sefNoLiterals in sefOptions) then begin
|
|
Exclude( FOptions, efoTrimBlanks );
|
|
Exclude( FOptions, efoRightJustify );
|
|
end;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbMergePicture(const Dest, Src : PAnsiChar);
|
|
{-merge Src with efPicture and return result in Dest}
|
|
var
|
|
SrcLen : Integer;
|
|
DestLen : Integer;
|
|
DotPosP : Cardinal;
|
|
DotPosS : Cardinal;
|
|
FloatPos : Integer;
|
|
FP : Cardinal;
|
|
I : Cardinal;
|
|
J, K, N : Integer;
|
|
PicChar : AnsiChar;
|
|
NeedFloat : Boolean;
|
|
CurLeftMax : Byte;
|
|
CurLeftLen : Byte;
|
|
IsNum : Boolean;
|
|
NeedMinus : Boolean;
|
|
FoundP : Boolean;
|
|
FoundS : Boolean;
|
|
CopyOfSrc : TEditString;
|
|
Buf : array[0..255] of Char;
|
|
|
|
procedure HandleOtherCases;
|
|
begin
|
|
if NeedFloat then begin
|
|
Dec(CurLeftLen);
|
|
Dest[I] := IntlSupport.CurrencyLtStr[CurLeftLen+1];
|
|
NeedFloat := CurLeftLen <> 0;
|
|
end else if NeedMinus then begin
|
|
Dest[I] := '-';
|
|
NeedMinus := False;
|
|
end else if (sefHexadecimal in sefOptions) or (sefOctal in sefOptions) or
|
|
(sefBinary in sefOptions) then
|
|
Dest[I] := '0'
|
|
else
|
|
Dest[I] := ' ';
|
|
end;
|
|
|
|
begin
|
|
{get initial size of Src}
|
|
SrcLen := StrLen(Src);
|
|
|
|
if SrcLen = 0 then
|
|
CopyOfSrc[0] := #0
|
|
else
|
|
StrCopy(CopyOfSrc, Src);
|
|
|
|
{copy picture mask into Dest}
|
|
StrCopy(Dest, efPicture);
|
|
|
|
{mask may be artificially short -- extend with last character of mask}
|
|
if MaxLength > efPicLen then begin
|
|
FillChar(Dest[efPicLen], MaxLength-efPicLen, Dest[efPicLen-1]);
|
|
Dest[MaxLength] := #0;
|
|
end;
|
|
DestLen := MaxLength;
|
|
|
|
{get position of decimal point}
|
|
FoundP := StrChPos(efPicture, pmDecimalPt, DotPosP);
|
|
|
|
{is it a numeric string?}
|
|
IsNum := pbIsNumber;
|
|
|
|
{take care of currency strings}
|
|
if StrChPos(efPicture, pmCurrencyLt, I) then begin
|
|
K := I;
|
|
while (K+1 < DestLen) and (efNthMaskChar(K+1) = pmCurrencyLt) do
|
|
Inc(K);
|
|
StrPCopy(Buf, IntlSupport.CurrencyLtStr);
|
|
J := StrLen(Buf);
|
|
for N := K downto I do
|
|
if J > 0 then begin
|
|
Dec(J);
|
|
Dest[N] := Buf[J];
|
|
end else
|
|
Dest[N] := ' ';
|
|
end;
|
|
|
|
if StrChPos(efPicture, pmCurrencyRt, I) then begin
|
|
J := 0;
|
|
StrPCopy(Buf, IntlSupport.CurrencyRtStr);
|
|
K := StrLen(Buf);
|
|
while (LongInt(I+1) <= DestLen) and (efNthMaskChar(I) = pmCurrencyRt) do begin
|
|
if J < K then begin
|
|
Dest[I] := Buf[J];
|
|
Inc(J);
|
|
end else
|
|
Dest[I] := ' ';
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
|
|
if IsNum then begin
|
|
{we need to fill in the FloatDollar positions too, if any}
|
|
if StrChPos(efPicture, pmFloatDollar, FP) then begin
|
|
FloatPos := FP;
|
|
CurLeftLen := Length(IntlSupport.CurrencyLtStr);
|
|
CurLeftMax := 1;
|
|
while efNthMaskChar(FloatPos+1) = pmFloatDollar do begin
|
|
Inc(FloatPos);
|
|
Inc(CurLeftMax);
|
|
end;
|
|
if CurLeftMax < CurLeftLen then
|
|
CurLeftLen := CurLeftMax;
|
|
end else begin
|
|
CurLeftLen := 0;
|
|
FloatPos := -1;
|
|
end;
|
|
|
|
{trim leading and trailing blanks}
|
|
TrimAllSpacesPChar(CopyOfSrc);
|
|
|
|
{check for a minus sign}
|
|
NeedMinus := (CopyOfSrc[0] = '-');
|
|
if NeedMinus then
|
|
StrStDeletePrim(CopyOfSrc, 0, 1);
|
|
|
|
{it's a numeric field--align the decimal points}
|
|
FoundS := StrChPos(CopyOfSrc, pmDecimalPt, DotPosS);
|
|
|
|
{see if we need a floating dollar sign}
|
|
SrcLen := StrLen(CopyOfSrc);
|
|
NeedFloat := (SrcLen <> 0) and (CurLeftLen <> 0);
|
|
|
|
{if there's no tail, pretend there's a dot beyond the end of CopyOfSrc}
|
|
if not FoundS then
|
|
K := SrcLen
|
|
else
|
|
K := DotPosS;
|
|
|
|
{copy the tail of the string}
|
|
if not FoundP then
|
|
I := DestLen
|
|
else
|
|
I := DotPosP+1;
|
|
J := K+1;
|
|
while (J+1 <= SrcLen) and (LongInt(I+1) <= DestLen) and not pbIsLiteral(I) do begin
|
|
Dest[I] := CopyOfSrc[J];
|
|
Inc(I);
|
|
Inc(J);
|
|
end;
|
|
|
|
{pad to end with 0's}
|
|
while (LongInt(I+1) <= DestLen) and not pbIsLiteral(I) do begin
|
|
Dest[I] := '0';
|
|
Inc(I);
|
|
end;
|
|
|
|
{handle trailing substitution characters}
|
|
while (LongInt(I+1) <= DestLen) and pbIsLiteral(I) do begin
|
|
PicChar := efNthMaskChar(I);
|
|
case PicChar of
|
|
Subst1..Subst8 : Dest[I] := UserData.SubstChars[PicChar];
|
|
end;
|
|
Inc(I);
|
|
end;
|
|
|
|
{merge the head of the string}
|
|
if not FoundP then
|
|
J := DestLen-1
|
|
else
|
|
J := DotPosP;
|
|
|
|
if FoundS then
|
|
SrcLen := DotPosS;
|
|
|
|
for I := J downto 0 do begin
|
|
PicChar := efNthMaskChar(I);
|
|
case pfPicFlags[I] of
|
|
pflagFormat,
|
|
pflagSemiLit :
|
|
if PicChar = pmComma then begin
|
|
if (SrcLen <> 0) then begin
|
|
if IntlSupport.CommaChar <> #0 then
|
|
Dest[I] := IntlSupport.CommaChar
|
|
else
|
|
StrStDeletePrim(Dest, I, 1);
|
|
end else
|
|
HandleOtherCases;
|
|
end else if (SrcLen > 0) and (Integer(I) > FloatPos) then begin
|
|
Dec(SrcLen);
|
|
Dest[I] := CopyOfSrc[SrcLen];
|
|
end else
|
|
HandleOtherCases;
|
|
pflagLiteral :
|
|
case PicChar of
|
|
Subst1..Subst8 :
|
|
Dest[I] := UserData.SubstChars[PicChar];
|
|
pmDecimalPt :
|
|
Dest[I] := IntlSupport.DecimalChar;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{put in a 0 before the dot if necessary}
|
|
if FoundP and (Dest[DotPosP-1] = ' ') then
|
|
Dest[DotPosP-1] := '0';
|
|
end else begin
|
|
{deal with problem w/ reals w/ variable # of places}
|
|
if (sefRealVar in sefOptions) and (SrcLen > DestLen) then
|
|
if StrScan(CopyOfSrc, pmDecimalPt) <> nil then begin
|
|
TrimTrailingZerosPChar(CopyOfSrc);
|
|
SrcLen := StrLen(CopyOfSrc);
|
|
end;
|
|
|
|
if efoRightJustify in Options then begin
|
|
{fill in the characters from CopyOfSrc}
|
|
J := SrcLen-1;
|
|
for I := DestLen-1 downto 0 do begin
|
|
PicChar := efNthMaskChar(I);
|
|
case pfPicFlags[I] of
|
|
pflagLiteral :
|
|
case PicChar of
|
|
Subst1..Subst8 :
|
|
Dest[I] := UserData.SubstChars[PicChar];
|
|
end;
|
|
else
|
|
if (J = -1) then
|
|
Dest[I] := ' '
|
|
else begin
|
|
Dest[I] := CopyOfSrc[J];
|
|
efFixCase(PicChar, AnsiChar(Dest[I]), #255);
|
|
Dec(J);
|
|
end;
|
|
end;
|
|
end;
|
|
end else begin
|
|
{fill in the characters from CopyOfSrc}
|
|
J := 0;
|
|
for I := 0 to DestLen-1 do begin
|
|
PicChar := efNthMaskChar(I);
|
|
case pfPicFlags[I] of
|
|
pflagLiteral :
|
|
case PicChar of
|
|
Subst1..Subst8 :
|
|
Dest[I] := UserData.SubstChars[PicChar];
|
|
end;
|
|
else
|
|
if (J <= SrcLen-1) then begin
|
|
Dest[I] := CopyOfSrc[J];
|
|
efFixCase(PicChar, AnsiChar(Dest[I]), #255);
|
|
Inc(J);
|
|
end else
|
|
Dest[I] := ' ';
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
if sefRealVar in sefOptions then
|
|
pbFixDecimalPoint(Dest);
|
|
end;
|
|
|
|
Dest[DestLen] := #0;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.pbStripPicture(const Dest, Src : PAnsiChar);
|
|
{-strip the mask characters from Src and put result in Dest}
|
|
var
|
|
SLen : Byte;
|
|
Found : Boolean;
|
|
P : PAnsiChar;
|
|
DotPos : Cardinal;
|
|
I : Integer;
|
|
CLT : array[0..5] of AnsiChar;
|
|
begin
|
|
{this won't work if string isn't the same length as the picture mask}
|
|
if StrLen(Src) <> MaxLength then begin
|
|
if Pointer(Dest) <> Pointer(Src) then
|
|
StrCopy(Dest, Src);
|
|
Exit;
|
|
end;
|
|
|
|
{check for fixed decimal point}
|
|
Found := StrChPos(efPicture, pmDecimalPt, DotPos);
|
|
|
|
{copy all non-literals from Src into Dest. Note: it's OK if Dest *is* Src}
|
|
SLen := 0;
|
|
for I := 0 to MaxLength-1 do
|
|
if (Found and (I = LongInt(DotPos))) or not pbIsLiteral(I) then begin
|
|
Inc(SLen);
|
|
Dest[SLen-1] := Src[I];
|
|
end;
|
|
Dest[SLen] := #0;
|
|
|
|
{remove floating dollar sign}
|
|
P := StrScan(efPicture, pmFloatDollar);
|
|
if P <> nil then begin
|
|
I := 1;
|
|
|
|
{find end of currency mask}
|
|
while P[1] = pmFloatDollar do begin
|
|
Inc(I);
|
|
Inc(P);
|
|
end;
|
|
StrPCopy(CLT, IntlSupport.CurrencyLtStr);
|
|
CLT[I] := #0;
|
|
P := StrPos(Dest, CLT);
|
|
if P <> nil then
|
|
StrStDeletePrim(P, 0, I);
|
|
end;
|
|
|
|
{remove commas}
|
|
if (StrScan(efPicture, pmComma) <> nil) and
|
|
(IntlSupport.CommaChar <> #0) then
|
|
repeat
|
|
P := StrScan(Dest, IntlSupport.CommaChar);
|
|
if P <> nil then
|
|
StrStDeletePrim(P, 0, 1);
|
|
until (P = nil);
|
|
|
|
{fix up decimal point}
|
|
if Found then begin
|
|
P := StrScan(Dest, IntlSupport.DecimalChar);
|
|
if P <> nil then
|
|
P^ := pmDecimalPt;
|
|
end;
|
|
end;
|
|
|
|
function TOvcPictureBase.ValidateContents(ReportError : Boolean) : Word;
|
|
var
|
|
DotPos : Cardinal;
|
|
begin
|
|
if efFieldClass = fcPicture then
|
|
if sefModified in sefOptions then begin
|
|
if StrChPos(efPicture, pmDecimalPt, DotPos) then
|
|
pbFixNumber(DotPos, efEditBegin, efEditEnd, True, True);
|
|
end;
|
|
|
|
Result := inherited ValidateContents(ReportError);
|
|
end;
|
|
|
|
procedure TOvcPictureBase.WMSetFocus(var Msg : TWMSetFocus);
|
|
var
|
|
B : Boolean;
|
|
begin
|
|
pbInitPictureFlags;
|
|
B := sefRetainPos in sefOptions;
|
|
inherited;
|
|
if not B then
|
|
pfSelPos := efSelEnd;
|
|
end;
|
|
|
|
procedure TOvcPictureBase.WMKillFocus(var Msg : TWMKillFocus);
|
|
var
|
|
DotPos : Cardinal;
|
|
begin
|
|
if efFieldClass = fcPicture then
|
|
if sefModified in sefOptions then begin
|
|
if StrChPos(efPicture, pmDecimalPt, DotPos) then
|
|
pbFixNumber(DotPos, efEditBegin, efEditEnd, True, True);
|
|
end;
|
|
|
|
inherited;
|
|
|
|
{are we giving up the focus?}
|
|
if not (sefRetainPos in sefOptions) then begin
|
|
{restore semi-literal characters}
|
|
pbRestoreSemiLits;
|
|
end;
|
|
end;
|
|
|
|
end.
|