SUBROUTINE EMV_INP_FLD( THE_TEXT, META_KEY, HORIZNTL, VERTICAL, FLD_WDTH, TEXT_POS, LIMITING, OBSCURED ) ! Copyright 1994-2023 Marcus Rhodes ! This program is free software; You can redistribute it and/or ! modify it under the terms of the GNU general public license ! version 3 as published by the Free Software Foundation. ! Modified: 09/08/2021 11:01:07 by Marcus ! Platform: Any Pick; Any OS; Any emulator; Any emulation ! Function: A simple, single-line text-editor for user input. ! Syntax : CALL EMV_INP_FLD( THE_TEXT, META_KEY, HORIZNTL, VERTICAL, FLD_WDTH, TEXT_POS, AUTOEXIT ) ! Var_name IO Typ Description____________________________________________ ! THE_TEXT > Str Field contents upon entry. ! < Str Field contents upon exit. ! META_KEY < Str The ANY_KEY code which exited the field. Keys allowed ! for editing operations except exit are: K_BACKSPACE, ! K_DELETE, K_END, K_HOME, K_INSERT, K_LEFT, K_RIGHT, ! KC_A, KC_BACKSPACE, KC_C, KC_DELETE, KC_END, KC_HOME, ! KC_INSERT, KC_L, KC_LEFT, KC_RIGHT, KC_U, KC_V, KC_X, ! KC_Y, KC_Z, KS_BACKSPACE, KS_DELETE, KS_END, KS_HOME, ! KS_INSERT, KS_LEFT, KS_RIGHT, KSC_BACKSPACE, KSC_DE- ! LETE, KSC_INSERT, KSC_LEFT, KSC_RIGHT, KM_L1, KM_L2, ! KM_R1, KM_R2 (as long as the mouse click is within the ! field). ! All other navigation keys/mouse-clicks exit the field. ! HORIZNTL > Int Horizontal screen position of left edge of input field. ! VERTICAL > Int Vertical screen position of input field. ! FLD_WDTH > Int Width of input field. ! TEXT_POS >< Int Position of the cursor before/after editing the field. ! LIMITING > Int 0 Allows unlimited text to be entered. ! 1 Limits text to the width of the field. ! 2 Automatically exits the field once filled. ! OBSCURED > 0/1 Whether to obscure the text entered for, say, allowing ! a password to be entered securely. ! Examples: CALL EMV_INP_FLD( THE_TEXT, META_KEY, HORIZNTL, VERTICAL, FLD_WDTH, TEXT_POS, LIMITING, OBSCURED ) ! -HORIZNTL-| VERTICAL ! |----TEXT_POS----| | ! THE_TEXT-This is a test of the Emergency Broadcasting System!_____+ ! ---------TERM_POS----------| | | ! |---------------------TEXT_LEN---------------------| | ! |-----------------------FLD_WDTH------------------------| ! Upcoming: Escape should return whatever has been entered to the ! calling program so it can decide what to do with it rather ! than returning the original/null contents. ! Done 09/08/2021 11:01:07 by Marcus ! Allow Shift+Left/Right text highlighting. ! Change is the only constant. -- Heraclitus ! Old name: N/A ! Catalog : EMV_INP_FLD ! New name: N/A EQU IDENTITY TO 'EMV_INP_FLD' INCLUDE ANY_KEY_EQU IF UNASSIGNED( THE_TEXT ) THEN THE_TEXT = '' IF UNASSIGNED( HORIZNTL ) THEN HORIZNTL = 0 IF UNASSIGNED( VERTICAL ) THEN VERTICAL = SYSTEM( 3 ) - 1 IF UNASSIGNED( FLD_WDTH ) THEN FLD_WDTH = SYSTEM( 2 ) - 2 IF UNASSIGNED( TEXT_POS ) THEN TEXT_POS = LEN( THE_TEXT ) + 1 IF UNASSIGNED( LIMITING ) THEN LIMITING = 0 IF UNASSIGNED( OBSCURED ) THEN OBSCURED = 0 BLOK_BEG = 0 BLOK_END = 0 ESC = CHAR( 27 ) FLD_FRMT = 'L#':FLD_WDTH INSERTNG = 1 ORIGINAL = THE_TEXT POSSIBLE = 1 TERM_POS = 1 TEXT_LEN = LEN( THE_TEXT ) WRD_CHRS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890_.-"[]' LEN_REST = TEXT_LEN - TERM_POS + 1 IF TEXT_LEN GT FLD_WDTH THEN IF TERM_POS GT FLD_WDTH THEN SHOW_BEG = TERM_POS - FLD_WDTH + 1 END ELSE SHOW_BEG = 1 END SHOW_END = SHOW_BEG + FLD_WDTH - 1 END ELSE SHOW_BEG = 1 SHOW_END = FLD_WDTH END LOOP WHILE POSSIBLE DO BEGIN CASE ! With a block set, this gets more complicated, requiring ! variables to manage the visible portion of commands which may ! exceed the width of the input field along with the block begin ! and/or end. ! The rules of the variables are ... ! - The full text entered/modified here is contained in the ! variable THE_TEXT. ! - The boundaries of THE_TEXT are always described relative to ! itself by 1 and TEXT_LEN. ! - The input-field is always described relative to the terminal ! by SHOW_BEG and SHOW_END. ! - The portion of THE_TEXT visible in the input field is ! contained in the variable SHOW_TXT. ! - The x position of the cursor relative to the terminal is ! contained in TERM_POS. ! - The x position of the cursor relative to THE_TEXT is in ! CRSR_TXT. ! - The highlighted portion of THE_TEXT, if any, is described ! relative to THE_TEXT by BLK_TXT1 andB BLK_TXT0. ! - The highlighted portion of SHOW_TXT, if any, is described ! relative to the terminal by BLK_TRM1 andB BLK_TRM0. CASE BLOK_BEG AND TEXT_LEN GT FLD_WDTH AND BLOK_BEG GE SHOW_BEG AND BLOK_END LE SHOW_END ! 1 BLOK_BEG CRSR_TXT BLOK_END TEXT_LEN ! | | | | | ! >LIST FILENAME 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ! | | | ! SHOW_BEG TERM_POS SHOW_END SHOW_TXT = THE_TEXT[ SHOW_BEG, BLOK_BEG - SHOW_BEG ] : @( -13 ) : THE_TEXT[ BLOK_BEG, BLOK_WID ] : @( -14 ) : @( -58 ) : THE_TEXT[ BLOK_END + 1, SHOW_END - BLOK_END - 1 ] CASE BLOK_BEG AND TEXT_LEN GT FLD_WDTH AND BLOK_BEG GT SHOW_BEG AND BLOK_END GT TEXT_LEN ! 1 BLOK_BEG CRSR_TXT BLOK_END TEXT_LEN ! | | | | | ! >LIST FILENAME 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ! | | | ! SHOW_BEG TERM_POS SHOW_END SHOW_TXT = THE_TEXT[ SHOW_BEG, BLOK_BEG - SHOW_BEG ] : @( -13 ) : THE_TEXT[ BLOK_BEG, BLOK_END - BLOK_BEG + 1 ] : @( -14 ) : @( -58 ) : THE_TEXT[ BLOK_END + 1, TEXT_LEN ] CASE BLOK_BEG AND TEXT_LEN GT FLD_WDTH AND BLOK_BEG LT SHOW_BEG AND BLOK_END LT SHOW_END ! 1 CRSR_TXT BLOK_BEG BLOK_END TEXT_LEN ! | | | | | ! >LIST FILENAME 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ! | | | ! SHOW_BEG TERM_POS SHOW_END SHOW_TXT = THE_TEXT[ SHOW_BEG, BLOK_BEG - SHOW_BEG ] : @( -13 ) : THE_TEXT[ BLOK_BEG, BLOK_END - BLOK_BEG + 1 ] : @( -14 ) : @( -58 ) : THE_TEXT[ BLOK_END + 1, TEXT_LEN ] CASE BLOK_BEG AND TEXT_LEN GT FLD_WDTH AND BLOK_BEG GT SHOW_BEG AND BLOK_END LT SHOW_END SHOW_TXT = THE_TEXT[ SHOW_BEG, BLOK_BEG - SHOW_BEG ] : @( -13 ) : THE_TEXT[ BLOK_BEG, BLOK_END - BLOK_BEG + 1 ] : @( -14 ) : @( -58 ) : THE_TEXT[ BLOK_END + 1, TEXT_LEN ] CASE BLOK_BEG AND TEXT_LEN GT FLD_WDTH AND BLOK_BEG LE SHOW_BEG AND BLOK_END GE SHOW_END SHOW_TXT = @( -13 ) : ( THE_TEXT FLD_FRMT )[ SHOW_BEG, FLD_WDTH ] : @( -14 ) CASE BLOK_BEG AND TEXT_LEN LE FLD_WDTH ! 1 BLOK_BEG BLOK_END TEXT_LEN ! | | | | ! >LIST FILENAME 1 2 3 4 5 6 7 8 9 10 11 ! | | | ! SHOW_BEG TERM_POS SHOW_END SHOW_TXT = THE_TEXT[ 1, BLOK_BEG - 1 ] : @( -13 ) : THE_TEXT[ BLOK_BEG, BLOK_WID ] : @( -14 ) : @( -58 ) : THE_TEXT[ BLOK_END + 1, TEXT_LEN ] : SPACE( FLD_WDTH - TEXT_LEN ) CASE @TRUE ! This is the simplest (and last) case of all, having no ! block/highlight set, and no text outside the input field. ! 1 TEXT_LEN ! | | ! >LIST FILENAME 1 2 3 4 5 6 7 8 9 10 11 ! | | | ! SHOW_BEG TERM_POS SHOW_END ! SHOW_TXT = THE_TEXT[ SHOW_BEG, FLD_WDTH ] FLD_FRMT ! This is the second simplest form, having no block/highlight ! set, and is covered by the same command. ! 1 TEXT_LEN ! | | ! >LIST FILENAME 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ! | | | ! SHOW_BEG TERM_POS SHOW_END SHOW_TXT = THE_TEXT[ SHOW_BEG, FLD_WDTH ] FLD_FRMT END CASE ! IF BLOK_BEG OR BLOK_END THEN ;! This is for debugging. ! IF BLOK_BEG EQ BLOK_END THEN ! CRT @( 0, VERTICAL - 1 ) : @( -4 ) : @( HORIZNTL ) : @( BLOK_BEG ) : 'I' : ! END ELSE ! CRT @( 0, VERTICAL - 1 ) : @( -4 ) : @( HORIZNTL ) : @( BLOK_BEG ) : '[' : @( BLOK_END ) : ']' : ! END ! END ELSE ! CRT @( 0, VERTICAL - 1 ) : @( -4 ) : @( HORIZNTL - 1, VERTICAL - 1 ) : ']' : @( HORIZNTL + TEXT_LEN ) : '[' : ! END ! CRT @( 0, VERTICAL - 1 ) : @( -4 ) : HORIZNTL : ' + ' : SHOW_BEG : ' + ' : TERM_POS : ' - 2 = ' : ( HORIZNTL + SHOW_BEG + TERM_POS - 2 ) ! CRT @( HORIZNTL, VERTICAL ) : @( -58 ) : SHOW_TXT : @( HORIZNTL + SHOW_BEG + TERM_POS - 2 ) : @( -59 ) : CRT @( 200, 0 ) : 'TERM_POS=' : TERM_POS : ' HORIZNTL=' : HORIZNTL : ' VERTICAL=' : VERTICAL : CRT @( HORIZNTL, VERTICAL ) : @( -58 ) : SHOW_TXT : @( -59 ) : @( TERM_POS, VERTICAL ) : CALL ANY_KEY( TEXT_KEY, META_KEY ) BEGIN CASE CASE META_KEY EQ KC_HOME ; GOSUB REVERT CASE META_KEY EQ KC_END ; GOSUB REVERT CASE META_KEY EQ K_LEFT ; GOSUB CHAR.LEFT CASE META_KEY EQ KS_LEFT ; GOSUB BLOCK.CHR.LEFT CASE META_KEY EQ K_RIGHT ; GOSUB CHAR.RIGHT CASE META_KEY EQ KS_RIGHT ; GOSUB BLOCK.CHR.RIGHT CASE META_KEY EQ KC_LEFT ; GOSUB WORD.LEFT CASE META_KEY EQ KC_RIGHT ; GOSUB WORD.RIGHT CASE META_KEY EQ K_HOME ; GOSUB LINE.BEG CASE META_KEY EQ KS_HOME ; GOSUB BLOCK.TO.BEG CASE META_KEY EQ K_END ; GOSUB LINE.END CASE META_KEY EQ KS_END ; GOSUB BLOCK.TO.END CASE META_KEY EQ K_BACKSPACE ; GOSUB DELETE.LFT CASE META_KEY EQ KC_BACKSPACE ; GOSUB DELETE.WORD CASE META_KEY EQ KC_DELETE ; GOSUB DELETE.WORD CASE META_KEY EQ K_DELETE ; GOSUB DELETE.RGT CASE META_KEY EQ K_INSERT ; GOSUB TOGGLE.INSERT CASE META_KEY EQ K_ESCAPE ; GOSUB REVERT CASE META_KEY EQ KC_A ; GOSUB BLOCK.ALL CASE TEXT_KEY NE '' ; GOSUB ADD.TO.TEXT CASE 1 ; GOSUB ACCEPT END CASE REPEAT RETURN DELETE.WORD: BLOK_BEG = TERM_POS BLOK_END = TERM_POS LOOP IF BLOK_BEG GT 0 AND INDEX( WRD_CHRS, THE_TEXT[ BLOK_BEG, 1 ], 1 ) THEN BLOK_BEG -= 1 END ELSE EXIT END REPEAT LOOP IF BLOK_END LT TEXT_LEN AND INDEX( WRD_CHRS, THE_TEXT[ BLOK_END, 1 ], 1 ) THEN BLOK_END += 1 END ELSE BLOK_END -= 1 EXIT END REPEAT GOSUB DELETE.BLOCK RETURN BLOCK.CHR.LEFT: IF TERM_POS GT 1 THEN BEGIN CASE ! CASE NOT( BLOK_BEG ) ; ! CASE BLOK_BEG EQ BLOK_END ; BLOK_BEG -= 1 ; TERM_POS -= 1 CASE TERM_POS EQ BLOK_BEG ; BLOK_BEG -= 1 ; TERM_POS -= 1 CASE TERM_POS EQ BLOK_END ; BLOK_END -= 1 ; TERM_POS -= 1 CASE @TRUE ; TERM_POS -= 1 ; BLOK_END = TERM_POS TERM_POS -= 1 ; BLOK_BEG = TERM_POS END CASE LEN_REST += 1 BLOK_WID = BLOK_END - BLOK_BEG + 1 END RETURN BLOCK.CHR.RIGHT: IF TEXT_POS LT TEXT_LEN THEN BEGIN CASE CASE TEXT_POS EQ BLOK_END ; BLOK_END += 1 ; TEXT_POS += 1 CASE TEXT_POS EQ BLOK_BEG ; BLOK_BEG += 1 ; TEXT_POS += 1 CASE @TRUE ; BLOK_BEG = TEXT_POS ; TEXT_POS += 1 ; BLOK_END = TEXT_POS ;!TEXT_POS += 1 END CASE LEN_REST -= 1 BLOK_WID = BLOK_END - BLOK_BEG END RETURN BLOCK.TO.BEG: BLOK_BEG = 1 BLOK_END = TERM_POS - 1 BLOK_WID = BLOK_END - BLOK_BEG + 1 TERM_POS = 1 SHOW_BEG = 1 SHOW_END = FLD_WDTH RETURN BLOCK.TO.END: BLOK_BEG = TERM_POS BLOK_END = TEXT_LEN BLOK_WID = BLOK_END - BLOK_BEG + 1 TERM_POS = TEXT_LEN + 1 SHOW_BEG = TEXT_LEN - FLD_WDTH IF SHOW_BEG LT 1 THEN SHOW_BEG = 1 SHOW_END = FLD_WDTH END RETURN BLOCK.ALL: BLOK_BEG = 1 BLOK_END = TEXT_LEN BLOK_WID = BLOK_END - BLOK_BEG + 1 TERM_POS = TEXT_LEN + 1 RETURN CHAR.LEFT: IF BLOK_BEG THEN TERM_POS = BLOK_BEG BLOK_BEG = 0 BLOK_END = 0 BLOK_WID = 0 GOSUB CHECK.SHOW.LEFT END ELSE IF TERM_POS GT 1 THEN TERM_POS -= 1 LEN_REST += 1 GOSUB CHECK.SHOW.LEFT END END RETURN CHAR.RIGHT: IF BLOK_BEG THEN TERM_POS = BLOK_END BLOK_BEG = 0 BLOK_END = 0 BLOK_WID = 0 GOSUB CHECK.SHOW.RIGHT END ELSE IF LEN_REST THEN TERM_POS += 1 LEN_REST -= 1 GOSUB CHECK.SHOW.RIGHT END END RETURN WORD.LEFT: IF BLOK_BEG THEN BLOK_BEG = 0 BLOK_END = 0 BLOK_WID = 0 END ELSE LOOP WHILE TERM_POS GT 1 AND NOT( INDEX( WRD_CHRS, THE_TEXT[ TERM_POS - 1, 1 ], 1 ) ) DO TERM_POS -= 1 LEN_REST += 1 REPEAT LOOP WHILE TERM_POS GT 1 AND INDEX( WRD_CHRS, THE_TEXT[ TERM_POS - 1, 1 ], 1 ) DO TERM_POS -= 1 LEN_REST += 1 REPEAT IF TERM_POS LT SHOW_BEG THEN SHOW_BEG = TERM_POS SHOW_END = SHOW_BEG + FLD_WDTH END END RETURN WORD.RIGHT: IF BLOK_BEG THEN BLOK_BEG = 0 BLOK_END = 0 BLOK_WID = 0 END ELSE LOOP WHILE LEN_REST AND INDEX( WRD_CHRS, THE_TEXT[ TERM_POS, 1 ], 1 ) DO TERM_POS += 1 LEN_REST -= 1 REPEAT LOOP WHILE LEN_REST AND NOT( INDEX( WRD_CHRS, THE_TEXT[ TERM_POS, 1 ], 1 ) ) DO TERM_POS += 1 LEN_REST -= 1 REPEAT IF TERM_POS GT SHOW_END THEN SHOW_END = TERM_POS SHOW_BEG = SHOW_END - FLD_WDTH END END RETURN LINE.BEG: GOSUB CLEAR.BLOCK TERM_POS = 1 LEN_REST = TEXT_LEN SHOW_BEG = 1 SHOW_END = FLD_WDTH RETURN LINE.END: GOSUB CLEAR.BLOCK TERM_POS = TEXT_LEN + 1 LEN_REST = 0 SHOW_BEG = TEXT_LEN - FLD_WDTH + 1 SHOW_END = SHOW_BEG + FLD_WDTH RETURN CLEAR.BLOCK: IF BLOK_BEG THEN BLOK_BEG = 0 BLOK_END = 0 BLOK_WID = 0 TERM_POS = BLOK_END IF TERM_POS GT TEXT_LEN THEN TERM_POS = TEXT_LEN + 1 END END RETURN DELETE.LFT: IF BLOK_BEG THEN GOSUB DELETE.BLOCK END ELSE IF TERM_POS GT 1 THEN THE_TEXT = THE_TEXT[ 1, TERM_POS - 2 ] : THE_TEXT[ TERM_POS, LEN_REST ] TERM_POS -= 1 TEXT_LEN -= 1 IF SHOW_BEG GT 1 THEN IF TERM_POS GE TEXT_LEN THEN SHOW_BEG = TERM_POS - FLD_WDTH + 1 SHOW_END -= 1 END IF TERM_POS LT SHOW_BEG THEN SHOW_BEG -= 1 SHOW_END -= 1 END END END END RETURN DELETE.RGT: IF BLOK_BEG THEN GOSUB DELETE.BLOCK END ELSE IF LEN_REST THEN THE_TEXT = THE_TEXT[ 1, TERM_POS - 1 ] : THE_TEXT[ TERM_POS + 1, LEN_REST ] LEN_REST -= 1 TEXT_LEN -= 1 GOSUB CHECK.SHOW.RIGHT END END RETURN DELETE.BLOCK: THE_TEXT = THE_TEXT[ 1, BLOK_BEG - 1 ] : THE_TEXT[ BLOK_END + 1, TEXT_LEN ] TEXT_LEN -= BLOK_END - BLOK_BEG + 1 TERM_POS = BLOK_BEG BLOK_BEG = 0 BLOK_END = 0 BLOK_WID = 0 GOSUB CHECK.SHOW.RIGHT CRT @( -31 ) : RETURN TOGGLE.INSERT: INSERTNG = ABS( INSERTNG - 1 ) RETURN ADD.TO.TEXT: IF BLOK_BEG THEN GOSUB DELETE.BLOCK END IF INSERTNG THEN THE_TEXT = THE_TEXT[ 1, TERM_POS - 1 ] : TEXT_KEY : THE_TEXT[ TERM_POS, LEN_REST ] TEXT_LEN += 1 END ELSE THE_TEXT = THE_TEXT[ 1, TERM_POS ] : TEXT_KEY : THE_TEXT[ TERM_POS + 2, LEN_REST ] LEN_REST -= 1 END TERM_POS += 1 GOSUB CHECK.SHOW.RIGHT RETURN CHECK.SHOW.LEFT: IF TERM_POS AND TERM_POS LT SHOW_BEG THEN SHOW_BEG = TERM_POS SHOW_END = TERM_POS + FLD_WDTH END RETURN CHECK.SHOW.RIGHT: IF TERM_POS GT SHOW_END AND TERM_POS LT TEXT_LEN THEN SHOW_BEG = TERM_POS - FLD_WDTH SHOW_END = TERM_POS END RETURN ACCEPT: POSSIBLE = 0 GOSUB CLEAR.BLOCK RETURN REVERT: ! THE_TEXT = ORIGINAL POSSIBLE = 0 GOSUB CLEAR.BLOCK RETURN