STRINPUT.MOD 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. IMPLEMENTATION MODULE StrInput;
  2. (*
  3. * REPERTOIRE
  4. * Release 1.6
  5. * By Charles Bradford and Cole Brecheen
  6. * (c) Copyright 1985-1992 PMI
  7. * Green Bay, Wisconsin
  8. * All rights reserved
  9. * (414) 468-6040
  10. *
  11. * $Header: D:/logfiles/mods/strinput.mov 1.7 10 Mar 1991 15:33:36 coleb $
  12. *
  13. *)
  14. (*EntryDiag:
  15. IMPORT Diagnostics;
  16. :EntryDiag*)
  17. IMPORT BigSets;
  18. IMPORT ErrorManager;
  19. IMPORT KbdInput;
  20. IMPORT Key;
  21. IMPORT LowLevel;
  22. IMPORT M2Strings;
  23. IMPORT Numbers;
  24. IMPORT PosUtils;
  25. IMPORT Spkr;
  26. IMPORT StrConv;
  27. IMPORT StrEdit;
  28. IMPORT SYSTEM;
  29. IMPORT VWindows;
  30. VAR
  31. Initialized : BOOLEAN;
  32. PROCEDURE Init();
  33. BEGIN
  34. IF Initialized THEN
  35. RETURN;
  36. ELSE
  37. Initialized := TRUE;
  38. END;
  39. (*EntryDiag:
  40. Diagnostics.Init();
  41. :EntryDiag*)
  42. BigSets.Init();
  43. ErrorManager.Init();
  44. KbdInput.Init();
  45. Key.Init();
  46. LowLevel.Init();
  47. M2Strings.Init();
  48. Numbers.Init();
  49. PosUtils.Init();
  50. Spkr.Init();
  51. StrConv.Init();
  52. StrEdit.Init();
  53. VWindows.Init();
  54. (*EntryDiag:
  55. Diagnostics.diagS( 'Entering StrInput', '' );
  56. :EntryDiag*)
  57. BeepAtNumbers := TRUE;
  58. (*EntryDiag:
  59. Diagnostics.diagS( 'Exiting StrInput', '' );
  60. :EntryDiag*)
  61. END Init;
  62. CONST
  63. Minus = 45; (* ORD('-') *)
  64. DecimalKey = 46; (* ORD('.') *)
  65. CurrencySymbol = '$';
  66. blank = ' ';
  67. PROCEDURE ReadWithEdits( WindowHandle: VWindows.AWindowHandle;
  68. VAR TheStr : ARRAY OF CHAR; col1, row1, FieldWidth:
  69. CARDINAL; VAR CursorPos: CARDINAL; VAR InsertMode: BOOLEAN;
  70. scrolling: BOOLEAN; VAR LastKey : CARDINAL; VAR LegalKeys,
  71. ExitKeys : KbdInput.KeyNumSet );
  72. VAR
  73. bufch : CHAR;
  74. done, RedrawNeeded : BOOLEAN;
  75. SavedHeight, StrNdx, CharsScrolled, TheStrLen : CARDINAL;
  76. AllOkKeys: KbdInput.KeyNumSet;
  77. (* CursorPos = current offset of cursor from start of field *)
  78. PROCEDURE redraw( BeginningAt: CARDINAL );
  79. VAR
  80. TmpStr: ARRAY [0..79] OF CHAR;
  81. BEGIN
  82. IF (BeginningAt < CharsScrolled) THEN
  83. HALT();
  84. END;
  85. M2Strings.Copy( TheStr, BeginningAt,
  86. M2Strings.Length(TheStr) - BeginningAt, TmpStr );
  87. BeginningAt := BeginningAt - CharsScrolled;
  88. StrEdit.SetLength( TmpStr, FieldWidth - BeginningAt );
  89. IF (BeginningAt < FieldWidth) THEN
  90. VWindows.DrawStr( WindowHandle, col1 + BeginningAt,
  91. row1, SYSTEM.ADR(TmpStr), FieldWidth - BeginningAt );
  92. RedrawNeeded := FALSE;
  93. END;
  94. END redraw;
  95. PROCEDURE MoveToPos( StrOffset: CARDINAL );
  96. BEGIN
  97. WHILE (CursorPos + CharsScrolled) > StrOffset DO
  98. (* we are moving backwards *)
  99. IF CursorPos > 0 THEN
  100. DEC( CursorPos );
  101. ELSE
  102. RedrawNeeded := TRUE;
  103. DEC( CharsScrolled );
  104. END;
  105. DEC( StrNdx );
  106. END;
  107. WHILE (CursorPos + CharsScrolled) < StrOffset DO
  108. (* we are moving forewards *)
  109. IF CursorPos < FieldWidth THEN
  110. INC( CursorPos );
  111. ELSE
  112. RedrawNeeded := TRUE;
  113. INC( CharsScrolled );
  114. END;
  115. INC( StrNdx );
  116. END;
  117. END MoveToPos;
  118. PROCEDURE LeftToChar( TheChar: CHAR );
  119. BEGIN
  120. WHILE (StrNdx > 0) AND (TheStr[ StrNdx ] # TheChar) DO
  121. MoveToPos( StrNdx - 1 );
  122. END;
  123. END LeftToChar;
  124. PROCEDURE RightToChar( TheChar: CHAR );
  125. BEGIN
  126. WHILE (StrNdx < TheStrLen) AND (TheStr[ StrNdx ] # TheChar) DO
  127. MoveToPos( StrNdx + 1 );
  128. END;
  129. END RightToChar;
  130. PROCEDURE SkipLeftOver( TheChar: CHAR );
  131. BEGIN
  132. WHILE (StrNdx > 0) AND (TheStr[ StrNdx ] = TheChar) DO
  133. MoveToPos( StrNdx - 1 );
  134. END;
  135. END SkipLeftOver;
  136. PROCEDURE SkipRightOver( TheChar: CHAR );
  137. BEGIN
  138. WHILE (StrNdx < TheStrLen) AND (TheStr[ StrNdx ] = TheChar) DO
  139. MoveToPos( StrNdx + 1 );
  140. END;
  141. END SkipRightOver;
  142. BEGIN
  143. (* ReadWithEdits *)
  144. SavedHeight := VWindows.GetCursorHeight(WindowHandle);
  145. TheStrLen := M2Strings.Length( TheStr );
  146. BigSets.SetUnion( LegalKeys, ExitKeys, AllOkKeys);
  147. FieldWidth := Numbers.Min( HIGH(TheStr) + 1, FieldWidth );
  148. IF FieldWidth = 0 THEN
  149. (* This means you can pass 0 to FieldWidth if your only
  150. width concern is preventing overflow of TheStr. *)
  151. FieldWidth := HIGH( TheStr ) + 1;
  152. IF FieldWidth > (VWindows.EndCol(WindowHandle) - col1) THEN
  153. FieldWidth := VWindows.EndCol(WindowHandle) - col1;
  154. END;
  155. END;
  156. WHILE TheStrLen < FieldWidth DO
  157. StrEdit.Append( TheStr, blank );
  158. INC( TheStrLen );
  159. END;
  160. IF (NOT scrolling) AND (TheStrLen > FieldWidth) THEN
  161. StrEdit.SetLength( TheStr, FieldWidth );
  162. TheStrLen := FieldWidth;
  163. END;
  164. CharsScrolled := 0;
  165. StrNdx := CursorPos;
  166. VWindows.GotoXY( WindowHandle, col1 + CursorPos, row1);
  167. IF InsertMode THEN
  168. VWindows.SetCursorHeight( WindowHandle, 6 )
  169. ELSE
  170. VWindows.SetCursorHeight( WindowHandle, 2);
  171. END;
  172. (*turns on cursor*)
  173. done := FALSE;
  174. RedrawNeeded := TRUE;
  175. REPEAT
  176. IF RedrawNeeded THEN
  177. redraw( CharsScrolled );
  178. END;
  179. VWindows.GotoXY( WindowHandle, col1 + CursorPos, row1);
  180. LastKey := KbdInput.KeyHit( AllOkKeys);
  181. CASE LastKey OF
  182. Key.Left : (* move to prior character position *)
  183. IF StrNdx > 0 THEN
  184. MoveToPos( StrNdx - 1 );
  185. ELSE
  186. IF BigSets.InSet( ExitKeys, LastKey ) THEN
  187. (* left arrow at start moves to prior field if
  188. Key.Left in ExitKeys *)
  189. done := TRUE;
  190. END;
  191. END;
  192. | Key.Right : (* move to next character position *)
  193. IF StrNdx + 1 < TheStrLen THEN
  194. MoveToPos( StrNdx + 1 );
  195. ELSE
  196. IF BigSets.InSet( ExitKeys, LastKey ) THEN
  197. (* left arrow at end moves to next field if
  198. Key.Right in ExitKeys *)
  199. done := TRUE;
  200. END;
  201. END;
  202. | Key.Del : (* Delete char under cursor *)
  203. M2Strings.Delete( TheStr, StrNdx, 1 );
  204. StrEdit.Append( TheStr, blank );
  205. redraw( StrNdx );
  206. | Key.Home : (* Go to beginning of field *)
  207. IF BigSets.InSet( ExitKeys, LastKey ) THEN
  208. done := TRUE;
  209. ELSE
  210. MoveToPos( 0 );
  211. END;
  212. | Key.End : (* Go past last character written *)
  213. IF BigSets.InSet( ExitKeys, LastKey ) THEN
  214. done := TRUE;
  215. ELSE
  216. MoveToPos( TheStrLen - 1 );
  217. SkipLeftOver( blank );
  218. RightToChar( blank );
  219. END;
  220. | Key.CtrlRight, Key.Tab : (* Go to next word *)
  221. IF ((StrNdx = TheStrLen) OR (LastKey = Key.Tab)) AND
  222. BigSets.InSet( ExitKeys, LastKey ) THEN
  223. (* Tab or no next word found, so exit *)
  224. done := TRUE;
  225. ELSE
  226. IF TheStr[ StrNdx ] = blank THEN
  227. SkipRightOver( blank );
  228. ELSE
  229. RightToChar( blank );
  230. SkipRightOver( blank );
  231. END;
  232. END;
  233. | Key.CtrlLeft, Key.BackTab : (* Go to previous word *)
  234. IF ((StrNdx = 0) OR (LastKey = Key.BackTab)) AND BigSets.InSet(
  235. ExitKeys, LastKey ) THEN
  236. (* BackTab or no previous word, so exit *)
  237. done := TRUE;
  238. ELSE
  239. IF TheStr[ StrNdx ] # blank THEN
  240. LeftToChar( blank );
  241. END;
  242. SkipLeftOver( blank );
  243. LeftToChar( blank );
  244. SkipRightOver( blank );
  245. END;
  246. | Key.AltD : (* Erase the entire entry *)
  247. LowLevel.Fill( SYSTEM.ADR( TheStr ), TheStrLen, blank );
  248. MoveToPos( 0 );
  249. RedrawNeeded := TRUE;
  250. | Key.AltE : (* Erase to the end of the field *)
  251. LowLevel.Fill( LowLevel.AddAddr( SYSTEM.ADR(TheStr),
  252. StrNdx), TheStrLen - StrNdx, blank );
  253. redraw( StrNdx );
  254. | Key.Ins : (* Toggle insert mode on and off *)
  255. InsertMode := NOT InsertMode;
  256. IF InsertMode THEN
  257. VWindows.SetCursorHeight( WindowHandle, 6 )
  258. ELSE
  259. VWindows.SetCursorHeight(WindowHandle, 2);
  260. END;
  261. | Key.Escape :
  262. done := TRUE;
  263. (* Unconditionally exit if the user presses ESC. *)
  264. | Key.BackSpace :
  265. IF (StrNdx > 0) THEN
  266. MoveToPos( StrNdx - 1 );
  267. IF InsertMode THEN
  268. M2Strings.Delete( TheStr, StrNdx, 1 );
  269. StrEdit.Append( TheStr, blank );
  270. ELSE
  271. TheStr[ StrNdx ] := blank;
  272. END;
  273. redraw( StrNdx );
  274. ELSIF BigSets.InSet( ExitKeys, LastKey ) THEN
  275. done := TRUE;
  276. END;
  277. ELSE
  278. IF BigSets.InSet( ExitKeys, LastKey ) THEN
  279. done := TRUE;
  280. ELSIF (StrNdx < TheStrLen) AND (LastKey <
  281. KbdInput.Extended) THEN
  282. (* normal key pressed and cursor is not past end *)
  283. IF InsertMode THEN
  284. IF NOT scrolling THEN
  285. M2Strings.Delete( TheStr, TheStrLen - 1, 1 );
  286. END;
  287. bufch := CHR( LastKey );
  288. M2Strings.Insert( bufch, TheStr, StrNdx );
  289. ELSE
  290. TheStr[ StrNdx ] := CHR( LastKey );
  291. END;
  292. redraw( StrNdx );
  293. MoveToPos( StrNdx + 1 );
  294. ELSE
  295. Spkr.Noise( Spkr.Warble, Spkr.Normal,
  296. Spkr.Short);
  297. END;
  298. END;
  299. UNTIL done;
  300. StrEdit.SetLength( TheStr, FieldWidth );
  301. (*We do this because TheStr may have gotten longer if
  302. we've been scrolling.*)
  303. VWindows.SetCursorHeight( WindowHandle, SavedHeight );
  304. END ReadWithEdits;
  305. PROCEDURE ReadNumeric( WindowHandle:
  306. VWindows.AWindowHandle; VAR TheStr : ARRAY OF
  307. CHAR; col1, row1, FieldWidth: CARDINAL;
  308. DecimalPlaces: CARDINAL; FloatingPoint: BOOLEAN;
  309. VAR InDecimals: BOOLEAN; VAR LastKey : CARDINAL;
  310. VAR ExitKeys : KbdInput.KeyNumSet );
  311. VAR
  312. SavedHeight, cnt, DecimalSpot, InsertionPoint,
  313. NonBlankLength: CARDINAL;
  314. AtLeadingZero: BOOLEAN;
  315. LegalKeys, AllOkKeys: KbdInput.KeyNumSet;
  316. DumStr: ARRAY [0..0] OF CHAR;
  317. BEGIN
  318. (* First we make sure the FieldWidth is okay. *)
  319. IF FieldWidth = 0 THEN
  320. FieldWidth := HIGH( TheStr ) + 1;
  321. ELSE
  322. FieldWidth := Numbers.Min( HIGH(TheStr) + 1, FieldWidth );
  323. END;
  324. FieldWidth := Numbers.Min( VWindows.EndCol(WindowHandle) - col1,
  325. FieldWidth );
  326. StrEdit.RightJustify( TheStr, FieldWidth );
  327. SavedHeight := VWindows.GetCursorHeight(WindowHandle);
  328. VWindows.SetCursorHeight( WindowHandle, 2 );
  329. (* Now we make sure DecimalPlaces is consistent with
  330. TheStr; if it's not, the number of DecimalPlaces in
  331. TheStr overrides. If there's no decimal point in TheStr
  332. at all, however, we'll make it consistent with
  333. DecimalPlaces. *)
  334. IF PosUtils.PresentPos( CHR(DecimalKey), TheStr, DecimalSpot ) THEN
  335. IF (DecimalSpot + 1) # (FieldWidth - DecimalPlaces) THEN
  336. DecimalPlaces := (FieldWidth - DecimalSpot) - 1;
  337. END;
  338. ELSIF (DecimalPlaces > 0) OR FloatingPoint THEN
  339. IF DecimalPlaces = 0 THEN
  340. (*We're here because FloatingPoint was true.*)
  341. DecimalPlaces := 1;
  342. (*Makes sure that we've at least got 0.0 in TheStr if
  343. FloatingPoint is true; prevents InsertionPoint from
  344. incrementing beyond FieldWidth, below.*)
  345. END;
  346. IF PosUtils.IsBlank( TheStr ) THEN
  347. StrEdit.InsertRightJustified( '0', TheStr, FieldWidth );
  348. END;
  349. StrEdit.InsertRightJustified( '.', TheStr, FieldWidth );
  350. FOR cnt := 1 TO DecimalPlaces DO
  351. StrEdit.InsertRightJustified( '0', TheStr, FieldWidth );
  352. END;
  353. DecimalSpot := PosUtils.Pos( CHR(DecimalKey), TheStr );
  354. ELSE
  355. DecimalSpot := M2Strings.Length( TheStr );
  356. IF PosUtils.IsBlank( TheStr ) THEN
  357. (* Mike McCarthy's bug fix. *)
  358. StrEdit.InsertRightJustified( '0', TheStr, FieldWidth );
  359. END;
  360. END;
  361. (* Now force FloatingPoint to false if CurrencySymbol is in
  362. TheStr. *)
  363. IF PosUtils.Present( CurrencySymbol, TheStr ) THEN
  364. FloatingPoint := FALSE;
  365. END;
  366. (* Now we find the insertion point. *)
  367. InsertionPoint := DecimalSpot;
  368. IF InDecimals THEN
  369. REPEAT
  370. INC( InsertionPoint );
  371. UNTIL (InsertionPoint >= FieldWidth) OR
  372. (TheStr[InsertionPoint] = '0');
  373. ELSE
  374. IF (TheStr[ InsertionPoint - 1 ] = '0') AND ( (InsertionPoint <=
  375. 1) OR (NOT PosUtils.Present(TheStr[InsertionPoint - 2],
  376. '0123456789'))) THEN
  377. AtLeadingZero := TRUE;
  378. ELSE
  379. AtLeadingZero := FALSE;
  380. END;
  381. END;
  382. BigSets.InitSet( LegalKeys );
  383. BigSets.AppendSet( LegalKeys, "{8, 331, '.', '-', '0'..'9'}" );
  384. BigSets.SetUnion( LegalKeys, ExitKeys, AllOkKeys);
  385. REPEAT
  386. VWindows.DrawStr( WindowHandle, col1, row1, SYSTEM.ADR(TheStr), 0 );
  387. VWindows.GotoXY( WindowHandle, col1 + InsertionPoint, row1 );
  388. LastKey := KbdInput.KeyHit( AllOkKeys);
  389. CASE LastKey OF
  390. 48..57: (* ASCII values of '0' to '9' *)
  391. IF InDecimals THEN
  392. IF (InsertionPoint = FieldWidth) THEN
  393. IF FloatingPoint AND (TheStr[0] = blank) THEN
  394. DumStr[0] := CHR(LastKey);
  395. IF BeepAtNumbers THEN
  396. Spkr.TimedNoise( (LastKey * 100) - 4400, 2 );
  397. END;
  398. StrEdit.InsertRightJustified( DumStr, TheStr,
  399. InsertionPoint );
  400. DEC( DecimalSpot );
  401. ELSE
  402. Spkr.Noise( Spkr.Warble, Spkr.Normal,
  403. Spkr.Short);
  404. END;
  405. ELSE
  406. IF BeepAtNumbers THEN
  407. Spkr.TimedNoise( (LastKey * 100) - 4400, 2 );
  408. END;
  409. TheStr[ InsertionPoint ] := CHR( LastKey );
  410. INC( InsertionPoint );
  411. END;
  412. ELSE
  413. IF AtLeadingZero THEN
  414. IF CHR(LastKey) # '0' THEN
  415. IF BeepAtNumbers THEN
  416. Spkr.TimedNoise( (LastKey * 100) - 4400, 2 );
  417. END;
  418. TheStr[ InsertionPoint - 1 ] := CHR( LastKey );
  419. AtLeadingZero := FALSE;
  420. END
  421. ELSE
  422. IF TheStr[0] = blank THEN
  423. DumStr[0] := CHR(LastKey);
  424. IF BeepAtNumbers THEN
  425. Spkr.TimedNoise( (LastKey * 100) - 4400, 2 );
  426. END;
  427. StrEdit.InsertRightJustified( DumStr, TheStr,
  428. InsertionPoint );
  429. ELSE
  430. Spkr.Noise( Spkr.Warble, Spkr.Normal,
  431. Spkr.Short);
  432. END;
  433. END;
  434. END;
  435. | Minus: (* '-' *)
  436. IF AtLeadingZero AND (InsertionPoint > 1) THEN
  437. IF (TheStr[InsertionPoint - 2] # '-') THEN
  438. TheStr[ InsertionPoint - 1 ] := CHR( LastKey );
  439. StrEdit.InsertRightJustified( '0', TheStr,
  440. InsertionPoint );
  441. (* Note that we're still AtLeadingZero here. *)
  442. END;
  443. END;
  444. | DecimalKey:
  445. IF (NOT InDecimals) AND (FloatingPoint OR (DecimalPlaces
  446. > 0)) THEN
  447. InDecimals := TRUE;
  448. INC( InsertionPoint );
  449. END;
  450. | Key.BackSpace:
  451. IF InDecimals THEN
  452. IF InsertionPoint = (DecimalSpot + 1) THEN
  453. InDecimals := FALSE;
  454. DEC( InsertionPoint );
  455. IF (NOT PosUtils.Present(TheStr[InsertionPoint - 1],
  456. '0123456789')) THEN
  457. AtLeadingZero := TRUE;
  458. StrEdit.InsertRightJustified( '0', TheStr,
  459. InsertionPoint );
  460. END;
  461. ELSE
  462. IF FloatingPoint THEN
  463. IF (InsertionPoint = FieldWidth) THEN
  464. IF (InsertionPoint > (DecimalSpot + 1) ) THEN
  465. StrEdit.DeleteRightJustified( TheStr,
  466. InsertionPoint - 1, 1 );
  467. INC( DecimalSpot );
  468. ELSE
  469. InDecimals := FALSE;
  470. DEC( InsertionPoint );
  471. END;
  472. ELSE
  473. TheStr[ InsertionPoint - 1 ] := '0';
  474. DEC( InsertionPoint );
  475. END;
  476. ELSE
  477. TheStr[ InsertionPoint - 1 ] := '0';
  478. DEC( InsertionPoint );
  479. END;
  480. END;
  481. ELSE
  482. IF NOT AtLeadingZero THEN
  483. StrEdit.DeleteRightJustified( TheStr,
  484. InsertionPoint - 1, 1 );
  485. IF (NOT PosUtils.Present(TheStr[InsertionPoint - 1],
  486. '0123456789')) THEN
  487. AtLeadingZero := TRUE;
  488. IF TheStr[InsertionPoint - 1] = '-' THEN
  489. (*Get rid of the minus sign, if it's there.*)
  490. StrEdit.DeleteRightJustified( TheStr,
  491. InsertionPoint - 1, 1 );
  492. END;
  493. StrEdit.InsertRightJustified( '0', TheStr,
  494. InsertionPoint );
  495. END;
  496. END;
  497. END;
  498. ELSE
  499. END;
  500. UNTIL BigSets.InSet( ExitKeys, LastKey );
  501. VWindows.SetCursorHeight( WindowHandle, SavedHeight );
  502. END ReadNumeric;
  503. BEGIN
  504. Initialized := FALSE;
  505. Init();
  506. END StrInput.