inplong.inc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. {
  2. This file is part of the Free Vision package
  3. A longint version of TInputline
  4. Copyright (c) 1999-2022 by Peter Vreman
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$IFNDEF FPC_DOTTEDUNITS}
  12. {$ifdef FV_UNICODE}
  13. Unit UInpLong;
  14. {$else FV_UNICODE}
  15. Unit InpLong;
  16. {$endif FV_UNICODE}
  17. {$ENDIF FPC_DOTTEDUNITS}
  18. (*--
  19. TInputLong is a derivitave of TInputline designed to accept LongInt
  20. numeric input. Since both the upper and lower limit of acceptable numeric
  21. input can be set, TInputLong may be used for SmallInt, Word, or Byte input
  22. as well. Option flag bits allow optional hex input and display. A blank
  23. field may optionally be rejected or interpreted as zero.
  24. Methods
  25. constructor Init(var R : TRect; AMaxLen : SmallInt;
  26. LowerLim, UpperLim : LongInt; Flgs : Word);
  27. Calls TInputline.Init and saves the desired limits and Flags. Flags may
  28. be a combination of:
  29. ilHex will accept hex input (preceded by '$') as well as decimal.
  30. ilBlankEqZero if set, will interpret a blank field as '0'.
  31. ilDisplayHex if set, will display numeric as hex when possible.
  32. constructor Load(var S : TStream);
  33. procedure Store(var S : TStream);
  34. The usual Load and Store routines. Be sure to call RegisterType(RInputLong)
  35. to register the type.
  36. FUNCTION DataSize : Word; virtual;
  37. PROCEDURE GetData(var Rec); virtual;
  38. PROCEDURE SetData(var Rec); virtual;
  39. The transfer methods. DataSize is Sizeof(LongInt) and Rec should be
  40. the address of a LongInt.
  41. FUNCTION RangeCheck : Boolean; virtual;
  42. Returns True if the entered string evaluates to a number >= LowerLim and
  43. <= UpperLim.
  44. PROCEDURE Error; virtual;
  45. Error is called when RangeCheck fails. It displays a messagebox indicating
  46. the label (if any) of the faulting view, as well as the allowable range.
  47. PROCEDURE HandleEvent(var Event : TEvent); virtual;
  48. HandleEvent filters out characters which are not appropriate to numeric
  49. input. Tab and Shift Tab cause a call to RangeCheck and a call to Error
  50. if RangeCheck returns false. The input must be valid to Tab from the view.
  51. There's no attempt made to stop moving to another view with the mouse.
  52. FUNCTION Valid(Cmd : Word) : Boolean; virtual;
  53. if TInputline.Valid is true and Cmd is neither cmValid or cmCancel, Valid
  54. then calls RangeCheck. If RangeCheck is false, then Error is called and
  55. Valid returns False.
  56. ----*)
  57. {$i platform.inc}
  58. {$ifdef PPC_FPC}
  59. {$H-}
  60. {$else}
  61. {$F+,O+,E+,N+}
  62. {$endif}
  63. {$X+,R-,I-,Q-,V-}
  64. {$ifndef OS_UNIX}
  65. {$S-}
  66. {$endif}
  67. Interface
  68. {$IFDEF FPC_DOTTEDUNITS}
  69. uses System.Objects,
  70. {$ifdef FV_UNICODE}
  71. FreeVision.Udrivers, FreeVision.Uviews, FreeVision.Udialogs, FreeVision.Umsgbox, FreeVision.Ufvcommon,
  72. {$else FV_UNICODE}
  73. FreeVision.Drivers, FreeVision.Views, FreeVision.Dialogs, FreeVision.Msgbox, FreeVision.Fvcommon,
  74. {$endif FV_UNICODE}
  75. FreeVision.Fvconsts;
  76. {$ELSE FPC_DOTTEDUNITS}
  77. uses objects,
  78. {$ifdef FV_UNICODE}
  79. udrivers, uviews, udialogs, umsgbox, ufvcommon,
  80. {$else FV_UNICODE}
  81. drivers, views, dialogs, msgbox, fvcommon,
  82. {$endif FV_UNICODE}
  83. fvconsts;
  84. {$ENDIF FPC_DOTTEDUNITS}
  85. {flags for TInputLong constructor}
  86. const
  87. ilHex = 1; {will enable hex input with leading '$'}
  88. ilBlankEqZero = 2; {No input (blank) will be interpreted as '0'}
  89. ilDisplayHex = 4; {Number displayed as hex when possible}
  90. Type
  91. TInputLong = Object(TInputLine)
  92. ILOptions : Word;
  93. LLim, ULim : LongInt;
  94. constructor Init(var R : TRect; AMaxLen : Sw_Integer;
  95. LowerLim, UpperLim : LongInt; Flgs : Word);
  96. constructor Load(var S : TStream);
  97. procedure Store(var S : TStream);
  98. FUNCTION DataSize : Sw_Word; virtual;
  99. PROCEDURE GetData(var Rec); virtual;
  100. PROCEDURE SetData(var Rec); virtual;
  101. FUNCTION RangeCheck : Boolean; virtual;
  102. PROCEDURE Error; virtual;
  103. PROCEDURE HandleEvent(var Event : TEvent); virtual;
  104. FUNCTION Valid(Cmd : Word) : Boolean; virtual;
  105. end;
  106. PInputLong = ^TInputLong;
  107. const
  108. RInputLong : TStreamRec = (
  109. ObjType: idInputLong;
  110. VmtLink: Ofs(Typeof(TInputLong)^);
  111. Load : @TInputLong.Load;
  112. Store : @TInputLong.Store);
  113. Implementation
  114. {-----------------TInputLong.Init}
  115. constructor TInputLong.Init(var R : TRect; AMaxLen : Sw_Integer;
  116. LowerLim, UpperLim : LongInt; Flgs : Word);
  117. begin
  118. if not TInputLine.Init(R, AMaxLen) then fail;
  119. ULim := UpperLim;
  120. LLim := LowerLim;
  121. if Flgs and ilDisplayHex <> 0 then Flgs := Flgs or ilHex;
  122. ILOptions := Flgs;
  123. if ILOptions and ilBlankEqZero <> 0 then Data Sw_PString_Deref := '0';
  124. end;
  125. {-------------------TInputLong.Load}
  126. constructor TInputLong.Load(var S : TStream);
  127. begin
  128. TInputLine.Load(S);
  129. S.Read(ILOptions, Sizeof(ILOptions));
  130. S.Read(LLim, Sizeof(LLim));
  131. S.Read(ULim, Sizeof(ULim));
  132. end;
  133. {-------------------TInputLong.Store}
  134. procedure TInputLong.Store(var S : TStream);
  135. begin
  136. TInputLine.Store(S);
  137. S.Write(ILOptions, Sizeof(ILOptions));
  138. S.Write(LLim, Sizeof(LLim));
  139. S.Write(ULim, Sizeof(ULim));
  140. end;
  141. {-------------------TInputLong.DataSize}
  142. FUNCTION TInputLong.DataSize:Sw_Word;
  143. begin
  144. DataSize := Sizeof(LongInt);
  145. end;
  146. {-------------------TInputLong.GetData}
  147. PROCEDURE TInputLong.GetData(var Rec);
  148. var code : SmallInt;
  149. begin
  150. Val(Data Sw_PString_Deref, LongInt(Rec), code);
  151. end;
  152. FUNCTION Hex2(B : Byte) : Sw_String;
  153. Const
  154. HexArray : array[0..15] of AnsiChar = '0123456789ABCDEF';
  155. begin
  156. SetLength(Hex2, 2);
  157. Hex2[1] := HexArray[B shr 4];
  158. Hex2[2] := HexArray[B and $F];
  159. end;
  160. FUNCTION Hex4(W : Word) : Sw_String;
  161. begin Hex4 := Hex2(Hi(W))+Hex2(Lo(W)); end;
  162. FUNCTION Hex8(L : LongInt) : Sw_String;
  163. begin Hex8 := Hex4(LongRec(L).Hi)+Hex4(LongRec(L).Lo); end;
  164. function FormHexStr(L : LongInt) : Sw_String;
  165. var
  166. Minus : boolean;
  167. {$ifdef FV_UNICODE}
  168. S : Sw_String;
  169. {$else FV_UNICODE}
  170. S : string[20];
  171. {$endif FV_UNICODE}
  172. begin
  173. Minus := L < 0;
  174. if Minus then L := -L;
  175. S := Hex8(L);
  176. while (Length(S) > 1) and (S[1] = '0') do Delete(S, 1, 1);
  177. S := '$' + S;
  178. if Minus then System.Insert('-', S, 2);
  179. FormHexStr := S;
  180. end;
  181. {-------------------TInputLong.SetData}
  182. PROCEDURE TInputLong.SetData(var Rec);
  183. var
  184. L : LongInt;
  185. S : Sw_String;
  186. begin
  187. L := LongInt(Rec);
  188. if L > ULim then L := ULim
  189. else if L < LLim then L := LLim;
  190. if ILOptions and ilDisplayHex <> 0 then
  191. S := FormHexStr(L)
  192. else
  193. Str(L : -1, S);
  194. if Length(S) > MaxLen then SetLength(S, MaxLen);
  195. Data Sw_PString_Deref := S;
  196. end;
  197. {-------------------TInputLong.RangeCheck}
  198. FUNCTION TInputLong.RangeCheck : Boolean;
  199. var
  200. L : LongInt;
  201. code : SmallInt;
  202. begin
  203. if (Data Sw_PString_Deref = '') and (ILOptions and ilBlankEqZero <> 0) then
  204. Data Sw_PString_Deref := '0';
  205. Val(Data Sw_PString_Deref, L, code);
  206. RangeCheck := (Code = 0) and (L >= LLim) and (L <= ULim);
  207. end;
  208. {-------------------TInputLong.Error}
  209. PROCEDURE TInputLong.Error;
  210. var
  211. {$ifdef FV_UNICODE}
  212. SU, SL : Sw_String;
  213. {$else FV_UNICODE}
  214. SU, SL : string[40];
  215. {$endif FV_UNICODE}
  216. PMyLabel : PLabel;
  217. Labl : Sw_String;
  218. I : SmallInt;
  219. function FindIt(P : PView) : boolean;{$ifdef PPC_BP}far;{$endif}
  220. begin
  221. FindIt := (Typeof(P^) = Typeof(TLabel)) and (PLabel(P)^.Link = PView(@Self));
  222. end;
  223. begin
  224. Str(LLim : -1, SL);
  225. Str(ULim : -1, SU);
  226. if ILOptions and ilHex <> 0 then
  227. begin
  228. SL := SL+'('+FormHexStr(LLim)+')';
  229. SU := SU+'('+FormHexStr(ULim)+')';
  230. end;
  231. if Owner <> Nil then
  232. PMyLabel := PLabel(Owner^.FirstThat(@FindIt))
  233. else PMyLabel := Nil;
  234. if PMyLabel <> Nil then PMyLabel^.GetText(Labl)
  235. else Labl := '';
  236. if Labl <> '' then
  237. begin
  238. I := Pos('~', Labl);
  239. while I > 0 do
  240. begin
  241. System.Delete(Labl, I, 1);
  242. I := Pos('~', Labl);
  243. end;
  244. Labl := '"'+Labl+'"';
  245. end;
  246. MessageBox(Labl + ^M^J'Value not within range '+SL+' to '+SU, Nil,
  247. mfError+mfOKButton);
  248. end;
  249. {-------------------TInputLong.HandleEvent}
  250. PROCEDURE TInputLong.HandleEvent(var Event : TEvent);
  251. begin
  252. if (Event.What = evKeyDown) then
  253. begin
  254. case Event.KeyCode of
  255. kbTab, kbShiftTab
  256. : if not RangeCheck then
  257. begin
  258. Error;
  259. SelectAll(True);
  260. ClearEvent(Event);
  261. end;
  262. end;
  263. if Event.CharCode <> #0 then {a character key}
  264. begin
  265. Event.Charcode := Upcase(Event.Charcode);
  266. case Event.Charcode of
  267. '0'..'9', #1..#$1B : ; {acceptable}
  268. '-' : if (LLim >= 0) or (CurPos <> 0) then
  269. ClearEvent(Event);
  270. '$' : if ILOptions and ilHex = 0 then ClearEvent(Event);
  271. 'A'..'F' : if Pos('$', Data Sw_PString_Deref) = 0 then ClearEvent(Event);
  272. else ClearEvent(Event);
  273. end;
  274. end;
  275. end;
  276. TInputLine.HandleEvent(Event);
  277. end;
  278. {-------------------TInputLong.Valid}
  279. FUNCTION TInputLong.Valid(Cmd : Word) : Boolean;
  280. var
  281. Rslt : boolean;
  282. begin
  283. Rslt := TInputLine.Valid(Cmd);
  284. if Rslt and (Cmd <> 0) and (Cmd <> cmCancel) then
  285. begin
  286. Rslt := RangeCheck;
  287. if not Rslt then
  288. begin
  289. Error;
  290. Select;
  291. SelectAll(True);
  292. end;
  293. end;
  294. Valid := Rslt;
  295. end;
  296. end.