This is a GUI module of EuroTool program EuroDirs for Linux.
EUROASM CPU=X64,Unicode=No,DumpWidth=36
dirsling PROGRAM Format=COFF,Width=64
%DROPMACRO *
INCLUDEHEAD1 argument.htm, dirslinc.htm
INCLUDE1 linabi.htm, cpuext64.htm, cpuext.htm, linsfile.htm, lins.htm, \
string64.htm, memory64.htm, time.htm, status32.htm
EDIT STRUC ; A structure for passing parameters for the procedure EditField.
.Address D QWORD ; Address of the field in memory. The field is in UTF-8, NUL-terminated.
.MaxSize D WORD ; Maximal possible size of the field in memory (bytes).
.ScreenSize D WORD ; Size of the visible field on the screen.
.ScreenRow D WORD ; Row of the edit field in the terminal window (1, 2, 3,,).
.ScreenCol D WORD ; Left column of the edit field in the terminal window (1, 2, 3,,).
ENDSTRUC EDIT
MinWidth EQU 150 ; Minimal number of columns of the window.
MinHeight EQU 20 ; Minimal number of rows of the main window.
[.rodata] ; Constants.
BoxV DB BYTE '│',0 ; BOX DRAWINGS LIGHT VERTICAL 2502
BoxDR DB BYTE '┌',0 ; BOX DRAWINGS LIGHT DOWN AND RIGHT 250C
BoxDL DB BYTE '┐',0 ; BOX DRAWINGS LIGHT DOWN AND LEFT 2510
BoxUR DB BYTE '└',0 ; BOX DRAWINGS LIGHT UP AND RIGHT 2514
BoxUL DB BYTE '┘',0 ; BOX DRAWINGS LIGHT UP AND LEFT 2518
Box2V DB BYTE '║',0 ; BOX DRAWINGS DOUBLE VERTICAL 2551
Box2DR DB BYTE '╔',0 ; BOX DRAWINGS DOUBLE DOWN AND LEFT 2554
Box2DL DB BYTE '╗',0 ; BOX DRAWINGS LIGHT DOWN AND LEFT 2557
Box2UR DB BYTE '╚',0 ; BOX DRAWINGS DOUBLE UP AND RIGHT 255A
Box2UL DB BYTE '╝',0 ; BOX DRAWINGS DOUBLE UP AND LEFT 2518
Boxes DB NAME_MAX*2*BYTE '─' ; BOX DRAWINGS LIGHT HORIZONTAL 2500
Boxes2 DB NAME_MAX * BYTE '═' ; BOX DRAWINGS DOUBLE HORIZONTAL 2550
Space5 DB 5 * BYTE ' ',0
Spaces DB NAME_MAX * 2 * BYTE ' '
BtnHead1 DB "Inserted ",0
BtnHead2 DB "Increased ",0
BtnHead3 DB "Unchanged ",0
BtnHead4 DB "Decreased ",0
BtnHead5 DB "Deleted ",0
BtnTail1 DB " new directories",0
BtnTail3 DB " directories",0
BtnTail5 DB " old directories",0
; Not zero-terminated sequences for detection of keyboard.
EscUp DB 27,'[A'
EscDown DB 27,'[B'
EscRight DB 27,'[C'
EscLeft DB 27,'[D'
EscHome DB 27,'[H'
EscEnd DB 27,'[F'
EscShiftTab DB 27,'[Z'
EscPgUp DB 27,'[5~'
EscPgDn DB 27,'[6~'
EscDelete DB 27,'[3~'
EscCtrlHome DB 27,'[1;5H'
EscCtrlEnd DB 27,'[1;5F'
; Zero-terminated sequences for writing to terminal.
EscDirsColor:: DB 27,'[30;47m',0
EscDefColor:: DB 27,'[39;49m',0
EscEnhColor:: DB 27,'[38;5;160m',0
EscDimColor DB 27,'[38;5;243m',0
EscFileColor DB 27,'[48;5;195m',0
EscFindColor DB 27,'[30;103m',0
EscEditColor DB 27,'[30;107m',0
EscErase:: DB 27,'[2J',0
EscEscape DB 27,0
EscEnableMouse DB 27,'[?1000;1006;1015h',0
EscDisableMouse:: DB 27,'[?1000;1006;1015l',0
EscHideCursor DB 27,'[?25l',0
EscShowCursor:: DB 27,'[?25h',0
EscTab DB 9
[.data] ; Variable data.
EscResize DB 27,'[8;'
ValResize DB 'xxxxxxxxx' ; Replaced by '24;150t',0
EscRightDiv2 DB 27,'['
ValRightDiv2 DB 'xxxxx' ; Replaced by '123C',0
EscRightEdge DB 27,'['
ValRightEdge DB 'xxxxx' ; Replaced by '123C',0
EscDivN DB 27,'['
ValDivN DB 'xxxxx' ; Replaced by '123C',0
EscLineXX DB 27,'['
ValLineXX DB 'XXH',0
EscGoto DB 27,'['
EscGotoRowColH DB 'row;colH',0
line %FOR 1..14 ; Define EscLine1, EscLine2 etc.
EscLine%line DB 27,'[%line{}H',0
%ENDFOR line
[.bss] ; Working data.
Edit DS EDIT
TtySize DS TTYSIZE
TermIO:: DS TERMIO
MainWidth DD DWORD
MainHeight DD DWORD ; Number of rows in the main window (20..99).
DirHeight DD DWORD ; Number of rows in the directory window, without borders (5..84).
MainWidthDiv2 DD DWORD
MainWidthDiv5 DD DWORD
Remainder2 DD DWORD
Remainder5 DD DWORD
LineNr DD DWORD ; Ordinal number of row in DirWindow (0,1,2,...)
LineCnt DD DWORD ; Row counter in DirWindow (DirHeight, DirHeight-1,,,0).
FindTextSize DD DWORD
TabSelected DD DWORD ; 0,5,10,15,20,25,30,35,40 selects editable field or button from TabSelTable with Tab od Shift-Tab.
SelectedLineNr DD DWORD ; Ordinal number of the row which is in the topmost row of DirWindow.
KeyBuffer DB 32 * BYTE
PreviousScanDir DB 264 * BYTE
FindText DB NAME_MAX * BYTE
[.text]
MainGui:: PROC
CALL MainWindowPaint
CALL DirWindowPaint
LEA RBX,[TermIO]
LinABI ioctl,0,TCGETS,RBX ; Load current local terminal status.
RstSt [RBX+TERMIO.c_lflag],ICANON+ECHO
LinABI ioctl,0,TCSETS,RBX ; Disable terminal echo.
StdOutput EscEnableMouse
.10:XOR EDI,EDI ; Read the keyboard in the main window.
LEA RSI,[KeyBuffer]
MOV R8,RSI
MOV [RSI],RDI
MOV EDX,SIZE# KeyBuffer
LinABI read,RDI,RSI,RDX
TEST EAX
JNA .10:
XOR ECX,ECX
MOV EBX,[SelectedLineNr::]
key %FOR EscUp,EscDown,EscCtrlHome,EscCtrlEnd,EscHome,EscEnd,EscPgUp,EscPgDn,EscShiftTab,EscTab,EscEscape
LEA RDI,[%key] ; Check if a cursor key was read and dispatch it to .%key.
MOV CL,SIZE# %key
MOV RSI,R8
REPE CMPSB
JE .%key:
%ENDFOR key
MOV RSI,R8 ; Read the mouse. Expected 1B 5B 3C 3b 3B 3r 3r 3B 3c 3c 4D 00
LODSW ; Esc [ lt btn ; col ; row M
CMP AX,0x5B1B ; Esc [
JNE .10:
LODSB
CMP AL,0x3C ; Less-than?
JNE .10:
LodD RSI ; Mouse button left=0 right=2 wheelUp=64 wheelDown=65
JC .10:
SUB EBX,3 ; SelectedLineNr for the case wheelUp.
CMP AL,64 ; Scroll wheel up?
JE .50:
ADD EBX,3+3 ; SelectedLineNr for the case wheelDown.
CMP AL,65 ; Scroll wheel down?
JE .70:
XOR EBX,EBX ; Not scrolled.
CMP AL,0 ; Left button?
JNE .10:
LODSB ; Read the column where it was clicked.
CMP AL,';'
JNE .10:
LodD ; Column.
JC .10:
MOV EBX,EAX ; X-coordinate of mouse cursor.
SHL EBX,16
LODSB ; Read the row where it was clicked.
CMP AL,';'
JNE .10:
LodD ; Row.
JC .10:
MOV BX,AX ; Y-coordinate of mouse cursor.
LODSB
OR AL,'M'^'m'
CMP AL,'m'
JNE .10:
; Mouse cursor coordinates at left button click are in EBX. Row number is in BX.
CMP BX,8
JB .40:
CMP BX,10
JA .40:
MOV EAX,1 ; At line 8..10 - one of the five buttons clicked.
SHR EBX,16 ; Get X-coordinate to EBX.
.20:SUB EBX,[MainWidthDiv5]
JB .30:
INC EAX
JMP .20:
Row9Btn1:MOV AL,1
JMP .30:
Row9Btn2:MOV AL,2
JMP .30:
Row9Btn3:MOV AL,3
JMP .30:
Row9Btn4:MOV AL,4
JMP .30:
Row9Btn5:MOV AL,5
.30:CMP EAX,5
JA .10:
MOVB [ArgViewDirs::],AL ; Change the view.
CALL MainWindowPaint
JMP .10:
.40:CMP BX,11
JB .42:
CMP BX,13
JA .42:
Row12:
LEA RSI,[Edit] ; At Row 11..13 - "FindText" clicked.
LEA RAX,[FindText]
MOV ECX,SIZE# FindText
MOV [RSI+EDIT.Address],RAX
MOV [RSI+EDIT.MaxSize],CX
MOV [RSI+EDIT.ScreenRow],12
MOV [RSI+EDIT.ScreenCol],18
MOV EAX,[MainWidth]
SUB EAX,18
MOV [RSI+EDIT.ScreenSize],AX
Clear KeyBuffer
CALL EditField
CALL MainWindowPaint
CALL DirWindowPaint
JMP .10:
.42:CMP BX,1
JB .44:
CMP BX,3
JA .44:
SHR EBX,16 ; At Row 1..3 - ScanDir selection. Get X-coordinate to BX.
CMP BX,55
JB .44: ; If outside the field.
Row2:
LEA RSI,[Edit]
LEA RAX,[ArgScanDir::]
MOV ECX,NAME_MAX
MOV [RSI+EDIT.Address],RAX
MOV [RSI+EDIT.MaxSize],CX
MOV [RSI+EDIT.ScreenRow],2
MOV [RSI+EDIT.ScreenCol],56
MOV ECX,[MainWidth]
SUB ECX,56
MOV [RSI+EDIT.ScreenSize],CX
MOV RSI,RAX ; ArgScanDir::.
GetLength$ RAX
LEA RDI,[PreviousScanDir]
REP MOVSB ; Store the last scan directory name.
CALL EditField
LEA RSI,[PreviousScanDir]
GetLength$ RSI
LEA RDI,[ArgScanDir::]
REPE CMPSB
JE .43:
XOR EAX,EAX ; ArgScanDir has been changed, invalidate I/O files.
MOV [ArgInputFile::],EAX
MOV [ArgOutputFile::],EAX
.43:CALL LoadAndCompareScans::
CALL MainWindowPaint
CALL DirWindowPaint
JMP .10:
Row6ColL:
MOV EAX,[MainWidth] ; At Row 6 - selection of scan files.
SHR EAX,1
STC
JMP .45:
Row6ColR:
MOV EAX,[MainWidth] ; At Row 6 - selection of scan files.
SHR EAX,1
XOR EBX,EBX
JMP .45:
.44:CMP BX,5
JB .49:
CMP BX,7
JA .49:
MOV EAX,[MainWidth] ; At Row 5..7 - selection of scan files.
SHR EAX,1
SHR EBX,16 ; Column to EBX.
CMP EBX,EAX ; Differenciate (to flags) between older and newer scan.
.45:LEA RBX,[Edit]
MOV [RBX+EDIT.ScreenRow],6
MOV [RBX+EDIT.ScreenSize],AX
MOV [RBX+EDIT.MaxSize],NAME_MAX
LEA RDX,[ArgInputFile::]
MOV ECX,2
JB .47:
LEA RDX,[ArgOutputFile::]
LEA ECX,[EAX+2]
.47:MOV [RBX+EDIT.Address],RDX
MOV [RBX+EDIT.ScreenCol],CX
SUB EAX,2
MOV [RBX+EDIT.ScreenSize],AX
CALL EditField
CALL LoadAndCompareScans::
.49:CALL MainWindowPaint
CALL DirWindowPaint
JMP .10:
.EscUp:
DEC EBX
.50:TEST EBX
JNS .60:
SUB EBX,EBX
.60:MOV [SelectedLineNr::],EBX
CALL DirWindowPaint
JMP .10:
.EscDown:
INC EBX
.70:MOV EAX,[MaxLineNr::]
CMP EBX,EAX
JB .60:
MOV EBX,EAX
JMP .60:
.EscPgUp:
SUB EBX,[DirHeight]
INC EBX
JMP .50:
.EscPgDn:
ADD EBX,[DirHeight]
DEC EBX
JMP .70:
.EscCtrlHome:
.EscHome:
MOV EBX,0
JMP .60:
.EscCtrlEnd:
.EscEnd:
MOV EBX,[MaxLineNr::]
; SUB EBX,[DirHeight]
; INC EBX,EBX
JMP .60:
TabSelTable: ; Each jump is encoded to 5 bytes long instruction.
JMP Row2
JMP Row6ColL
JMP Row6ColR
JMP Row9Btn1
JMP Row9Btn2
JMP Row9Btn3
JMP Row9Btn4
JMP Row9Btn5
JMP Row12
.EscShiftTab:
MOV EAX,[TabSelected]
SUB EAX,5
JNB .80:
MOV EAX,8*5
JMP .80:
.EscTab: ; Tab pressed.
MOV EAX,[TabSelected]
ADD EAX,5
CMP AL,8*5
JNA .80:
SUB EAX,EAX
.80:MOV [TabSelected],EAX ; RAX=0,5,10,15,20,25,30,35,40.
LEA RCX,[TabSelTable+RAX]
JMP RCX
.EscEscape:
StdOutput EscDisableMouse,EscErase
LEA RBX,[TermIO]
LinABI ioctl,0,TCGETS,RBX ; Get current terminal echo.
SetSt [RBX+TERMIO.c_lflag],ICANON+ECHO
LinABI ioctl,0,TCSETS,RBX ; Restore terminal echo.
TerminateProgram 0
ENDP MainGui
MainWindowPaint PROC
LinABI ioctl,0,TIOCGWINSZ,TtySize ; Check if the terminal is big enough.
MOVZXW EDX,[TtySize.ts_lines]
MOVZXW ECX,[TtySize.ts_cols]
MOV EAX,MinHeight ; Minimal acceptable rows (20..99).
CMP EDX,EAX
JB .10:
MOV EAX,EDX
.10:LEA RDI,[ValResize]
StoD RDI
MOV AL,';'
STOSB
MOV EAX,MinWidth ; Minimal acceptable columns.
CMP ECX,EAX
JB .13:
MOV EAX,ECX
.13:StoD RDI
MOV AX,'t'
STOSW
StdOutput EscResize
LinABI ioctl,0,TIOCGWINSZ,TtySize
MOVZXW EDX,[TtySize.ts_lines]
DEC EDX ; Reserve one low row for status.
MOV [MainHeight],EDX
SUB EDX,15
MOV [DirHeight],EDX
MOVZXW ECX,[TtySize.ts_cols]
MOV [MainWidth],ECX
MOV EAX,ECX
XOR EDX,EDX
SHR ECX,1
ADC EDX,EDX
MOV [Remainder2],EDX
MOV [MainWidthDiv2],ECX
MOV ECX,5
XOR EDX,EDX
DIV RCX
MOV [MainWidthDiv5],EAX
MOV [Remainder5],EDX
MOV EAX,[MainWidthDiv2]
DEC EAX
StoD ValRightDiv2 ; Prepare EscRightDiv2
MOV AX,'C'
STOSW
MOV EAX,[MainWidth]
DEC EAX
StoD ValRightEdge ; Prepare EscRightEdge
MOV AX,'C'
STOSW
MOV EAX,[ArgViewDirs::] ; 1..5.
LEA RCX,[8*RAX-8+Buffers::]
MOV [BufferSelected::],RCX
BufferRetrieve RCX ; Returns array of SCAN_INDEXes.
SHR ECX,4 ; Each is 8 bytes long.
MOV [MaxLineNr::],ECX
INC ECX
SUB ECX,[DirHeight]
JA .16:
XOR ECX,ECX
.16:INC ECX
MOV [SelectedLineNr],ECX
; Start painting.
StdOutput EscLine1,EscDirsColor ; Row 1
StdOutput Spaces,Size=54
CMPD [MainWidth],28
JNA .Row2:
StdOutput EscDimColor,BoxDR
MOV ECX,[MainWidth]
SUB ECX,56
LEA EAX,[2*ECX+ECX]
StdOutput Boxes,Size=RAX
StdOutput BoxDL,Space5
.Row2: StdOutput EscLine2,=B' ',EscEnhColor,EuroDirs::,EscDimColor,Version::, \
=B". A folder with scan files:",BoxV,EscFileColor,ArgScanDir::,EscDirsColor
CMPD [MainWidth],28 ; Row 2
JB .22:
GetLengthUTF8 ArgScanDir::
MOV EAX,[MainWidth]
SUB EAX,ECX
SUB EAX,56
JB .22:
StdOutput Spaces,Size=RAX
JMP .25:
.22:StdOutput EscLine2,EscRightEdge
JMP .Row3:
.25:StdOutput EscDimColor,BoxV,Space5
.Row3:
StdOutput EscLine3 ; Row 3
StdOutput Spaces,Size=54
CMPD [MainWidth],28
JNA .Row4:
StdOutput BoxUR
MOV ECX,[MainWidth]
SUB ECX,56
LEA EAX,[2*ECX+ECX]
StdOutput Boxes,Size=RAX
StdOutput BoxUL,Space5
.Row4:StdOutput EscLine4, =B" Select an older scan file"
MOV EAX,[MainWidthDiv2] ; Row 4
SUB EAX,23
StdOutput Spaces,Size=RAX
StdOutput =B"and compare it with a newer scan file"
StdOutput Spaces,Size=RAX
StdOutput EscLine5, BoxDR ; Row 5
MOV ECX,[MainWidthDiv2]
SUB ECX,2
LEA EAX,[2*ECX+ECX]
StdOutput Boxes,Size=RAX
StdOutput BoxDL,BoxDR
ADD ECX,[Remainder2]
LEA EAX,[2*ECX+ECX]
StdOutput Boxes,Size=RAX
StdOutput BoxDL,Space5
LEA RSI,[ArgInputFile::]
StdOutput EscLine6, BoxV, EscFileColor, RSI, EscDirsColor
GetLengthUTF8 RSI ; Row 6
MOV EAX,[MainWidthDiv2]
SUB EAX,2
SUB EAX,ECX
JA .27:
StdOutput EscLine6,EscRightDiv2
JMP .30:
.27:StdOutput Spaces,Size=RAX
.30:LEA RSI,[ArgOutputFile::]
StdOutput EscDimColor,BoxV,BoxV,EscFileColor, RSI,EscDirsColor
GetLengthUTF8 RSI
MOV EAX,[MainWidthDiv2]
ADD EAX,[Remainder2]
SUB EAX,2
SUB EAX,ECX
JA .35:
StdOutput EscLine6,EscRightEdge
JMP .41:
.35:StdOutput Spaces,Size=RAX
.41:StdOutput EscDimColor,BoxV,Space5
StdOutput EscLine7, BoxUR ; Row 7
MOV ECX,[MainWidthDiv2]
SUB ECX,2
LEA EAX,[2*ECX+ECX]
StdOutput Boxes,Size=RAX
StdOutput BoxUL,BoxUR
ADD ECX,[Remainder2]
LEA EAX,[2*ECX+ECX]
StdOutput Boxes,Size=RAX
StdOutput BoxUL,Space5
StdOutput EscLine8,EscDirsColor,Box2DR
MOV ECX,[MainWidthDiv5] ; Row 8
SUB ECX,2
LEA EAX,[2*RCX+RCX]
StdOutput Boxes2,Size=RAX
StdOutput Box2DL,Box2DR
StdOutput Boxes2,Size=RAX
StdOutput Box2DL,Box2DR
StdOutput Boxes2,Size=RAX
StdOutput Box2DL,Box2DR
StdOutput Boxes2,Size=RAX
StdOutput Box2DL,Box2DR
ADD ECX,[Remainder5]
LEA EAX,[2*RCX+RCX]
StdOutput Boxes2,Size=RAX
StdOutput Box2DL,Space5
StdOutput EscLine9,Box2V ; Row 9 Button 1 title
LEA RSI,[Numbers::+00]
GetLength$ RSI
ADD ECX,SIZE#BtnHead1 + SIZE#BtnTail1 ; Size of the button title.
MOV EDX,[MainWidthDiv5] ; Space inside the button rectangle.
CMPB [ArgViewDirs::],1
JNE .44:
StdOutput EscEditColor
.44:StdOutput BtnHead1,RSI,BtnTail1
SUB EDX,ECX
JB .47:
StdOutput Spaces,Size=RDX
JMP .50:
.47:MOV EAX,[MainWidthDiv5]
DEC EAX
StoD ValDivN
MOV AX,'C'
STOSW
StdOutput EscLine9,EscDivN
.50:StdOutput EscDirsColor,Box2V,Box2V
LEA RSI,[Numbers::+20] ; Row 9 Button 2
GetLength$ RSI
CMPB [ArgViewDirs::],2
JNE .52:
StdOutput EscEditColor
.52:ADD ECX,SIZE#BtnHead2 + SIZE#BtnTail3 ; Size of the button title.
MOV EDX,[MainWidthDiv5]
StdOutput BtnHead2,RSI,BtnTail3
SUB EDX,ECX
JB .55:
StdOutput Spaces,Size=RDX
JMP .58:
.55:MOV EAX,[MainWidthDiv5]
ADD EAX,EAX
DEC EAX
StoD ValDivN
MOV AX,'C'
STOSW
StdOutput EscLine9,EscDivN
.58:StdOutput EscDirsColor,Box2V,Box2V
LEA RSI,[Numbers::+40] ; Row 9 Button 3
GetLength$ RSI
ADD ECX,SIZE#BtnHead3 + SIZE#BtnTail3 ; Size of the button title.
MOV EDX,[MainWidthDiv5]
CMPB [ArgViewDirs::],3
JNE .61:
StdOutput EscEditColor
.61:StdOutput BtnHead3,RSI,BtnTail3
SUB EDX,ECX
JB .64:
StdOutput Spaces,Size=RDX
JMP .67:
.64:MOV EAX,[MainWidthDiv5]
LEA EAX,[2*EAX+EAX]
DEC EAX
StoD ValDivN
MOV AX,'C'
STOSW
StdOutput EscLine9,EscDivN
.67:StdOutput EscDirsColor,Box2V,Box2V
LEA RSI,[Numbers::+60] ; Row 9 Button 4
GetLength$ RSI
ADD ECX,SIZE#BtnHead4 + SIZE#BtnTail3 ; Size of the button title.
MOV EDX,[MainWidthDiv5]
CMPB [ArgViewDirs::],4
JNE .70:
StdOutput EscEditColor
.70:StdOutput BtnHead4,RSI,BtnTail3
SUB EDX,ECX
JB .72:
StdOutput Spaces,Size=RDX
JMP .75:
.72:MOV EAX,[MainWidthDiv5]
LEA EAX,[4*EAX]
DEC EAX
StoD ValDivN
MOV AX,'C'
STOSW
StdOutput EscLine9,EscDivN
.75:StdOutput EscDirsColor,Box2V,Box2V
LEA RSI,[Numbers::+80] ; Row 9 Button 5
GetLength$ RSI
ADD ECX,SIZE#BtnHead5 + SIZE#BtnTail5 ; Size of the button title.
MOV EDX,[MainWidthDiv5]
ADD EDX,[Remainder5]
CMPB [ArgViewDirs::],5
JNE .78:
StdOutput EscEditColor
.78:StdOutput BtnHead5,RSI,BtnTail5
SUB EDX,ECX
JB .81:
StdOutput Spaces,Size=RDX
JMP .84:
.81:MOV EAX,[MainWidthDiv5]
LEA EAX,[4*EAX+EAX]
DEC EAX
StoD ValDivN
MOV AX,'C'
STOSW
StdOutput EscLine9,EscDivN
.84:StdOutput EscDirsColor,Box2V,Space5
StdOutput EscLine10,Box2UR ; Row 10
MOV ECX,[MainWidthDiv5]
SUB ECX,2
LEA EAX,[2*RCX+RCX]
StdOutput Boxes2,Size=RAX
StdOutput Box2UL,Box2UR
StdOutput Boxes2,Size=RAX
StdOutput Box2UL,Box2UR
StdOutput Boxes2,Size=RAX
StdOutput Box2UL,Box2UR
StdOutput Boxes2,Size=RAX
StdOutput Box2UL,Box2UR
ADD ECX,[Remainder5]
LEA EAX,[2*RCX+RCX]
StdOutput Boxes2,Size=RAX
StdOutput Box2UL,Space5
StdOutput EscLine11,EscDimColor ; Row 11
StdOutput Spaces,Size=16
StdOutput BoxDR
MOV ECX,[MainWidth]
LEA ECX,[2*RCX+RCX-18*3]
StdOutput Boxes,Size=RCX
StdOutput BoxDL,Space5
StdOutput EscLine12,=B" Find this text:",BoxV,EscFindColor,FindText,EscDirsColor
GetLengthUTF8 FindText ; Row 12
NEG ECX
ADD ECX,[MainWidth]
SUB ECX,18
JB .87:
StdOutput Spaces,Size=RCX
JMP .90:
.87:StdOutput EscLine12,EscRightEdge
.90:StdOutput BoxV,Space5
; Row 13
StdOutput EscLine13
StdOutput Spaces,Size=16
StdOutput EscDimColor,BoxUR
MOV ECX,[MainWidth]
LEA ECX,[2*RCX+RCX-18*3]
StdOutput Boxes,Size=RCX
StdOutput BoxUL,Space5
StdOutput EscLine14,BoxDR ; Row 14
MOV ECX,[MainWidth]
LEA ECX,[2*RCX+RCX-2*3]
StdOutput Boxes,Size=RCX
StdOutput BoxDL,Space5
GetLength$ FindText ; Rows 15...
MOV [FindTextSize],ECX
CALL DirWindowPaint
MOV EAX,[MainHeight] ; The last line (20..99).
StoD ValLineXX,Size=2
StdOutput EscDimColor,EscLineXX,BoxUR
MOV ECX,[MainWidth]
LEA ECX,[2*RCX+RCX-2*3]
StdOutput Boxes,Size=RCX
StdOutput BoxUL,Space5,EscDirsColor
; MainWindow is painted; DirWindow is erased to blank.
RET
ENDP MainWindowPaint
DirWindowPaint PROC
MOV EAX,[ArgViewDirs::] ; 1..5.
LEA RBX,[8*EAX-8+Buffers::]
BufferRetrieve RBX
ADD RCX,RSI
MOV EAX,ECX
SHR EAX,4
MOV [IndexInMemory::],RSI
MOV [IndexEndInMemory::],RCX
MOV [IndexNumber::],RAX
MOV EAX,[DirHeight] ; Number of lines in DirWindow.
MOV [LineCnt],EAX ; Counter of written lines in DirWindow (0..DirHeight).
MOV [LineNr],15 ; Ordinal number of row in MainWindowPaint (15..15+DirHeight).
MOV EBX,[SelectedLineNr] ; Ordinal number of row in the topmost position of DirWindow (0..MaxLineNr::).
.10:MOV EAX,[LineNr]
StoD ValLineXX,Size=2
StdOutput EscLineXX,EscDimColor,BoxV,EscDirsColor
CALL OneLine2Dir:: ; RBX is line number (0,1,2,,). Returns Dir=RSI,RCX with the line.
TEST RCX
JZ .70:
MOV EDX,ECX
MOV RDI,RSI
MOV R8,RDI
LEA RSI,[FindText]
CMPD [FindTextSize],0
JZ .60:
LODSB
.20:REPNE SCASB
JNE .60:
PUSH RCX,RSI,RDI
MOV ECX,[FindTextSize]
DEC ECX
REPE CMPSB
POP RDI,RSI,RCX
JNE .20:
PUSH RDX,RDI
LEA RCX,[RDI-1]
SUB RCX,R8
SUB RDX,RCX
StdOutput R8,Size=RCX
StdOutput EscFindColor
ADD R8,RCX
MOV ECX,[FindTextSize]
StdOutput R8,Size=RCX
StdOutput EscDirsColor
ADD R8,RCX
SUB RDX,RCX
StdOutput R8,Size=RDX
POP RDI,RDX
JMP .65:
.60:MOV RDI,R8
StdOutput RDI,Size=RDX
.65:GetLengthUTF8 RDI,Size=RDX
MOV EAX,[MainWidth]
DEC EAX
SUB EAX,ECX
JB .70:
StdOutput Spaces,Size=RAX
JMP .80:
.70:MOV EAX,[MainWidth]
SUB EAX,2
StdOutput Spaces,Size=RAX
.80:StdOutput EscDimColor,BoxV,Space5
INC EBX
INC [LineNr]
DEC [LineCnt]
JA .10:
RET
ENDP DirWindowPaint
EditField PROC
LEA RBX,[Edit]
MOV RSI,[RBX+EDIT.Address]
GetLengthUTF8 RSI
MOV R11,RCX
.10: ; R11 is cursor position withing the visible field in characters (0,1,2,,).
PUSH R11
XOR R11,R11
CALL .CursorAtR11:
MOV RSI,[RBX+EDIT.Address]
MOV R9,RSI ; R9 points at the beginning of the edit field in memory.
MOVZX EAX,[RBX+EDIT.ScreenSize]
GetLengthUTF8 RSI ; Length goes to RCX.
SUB EAX,ECX
ADD R11,RCX
StdOutput EscShowCursor,EscEditColor,RSI
StdOutput Spaces,Size=RAX
POP R11
.20: CALL .CursorAtR11: ; Display (perhaps new) cursor position.
.40: XOR EDI,EDI ; Read the keyboard.
LEA RSI,[KeyBuffer]
MOV [RSI],RDI ; Clear the key buffer.
MOV R8,RSI ; R8 points at the beginning of the keyboard buffer.
MOV EDX,SIZE# KeyBuffer
LinABI read,RDI,RSI,RDX
TEST EAX
JNA .40:
XOR ECX,ECX
MOV RDX,RAX ; Number of read bytes.
MOV EAX,[RSI]
AND EAX,0x00FFFFFF
CMP EAX,0x3C5B1B ; Mouse ANSI sequence Esc [ lt
JE .40:
Dispatch AL,0x7F,0x09,0x08,0x0A,0x0D ; First try the control characters BS, TAB, NL.
key %FOR EscDelete,EscLeft,EscRight,EscHome,EscEnd,EscShiftTab,EscEscape ; Then try kursor keys.
LEA RDI,[%key]
MOV CL,SIZE# %key
MOV RSI,R8
REPE CMPSB
JE .%key:
%ENDFOR key
CMP AL,27 ; Other special key in ANSI sequence?
JE .40: ; Ignore other ANSI sequences.
; Ordinary key was pressed, perhaps multibyte (UTF-8). Its size is in RDX (1..4).
CALL .Cursor2Physical
; Insert RDX bytes at R8 to the current physical position represented by R12.
GetLength$ R9
LEA RSI,[R9+RCX-1]
LEA RDI,[RSI+RDX]
SUB RCX,R12
STD
REP MOVSB
CLD
LEA RDI,[R9+R12]
MOV RSI,R8
MOV ECX,EDX
REP MOVSB
INC R11 ; Finally, increment cursor position.
JMP .10:
.Cursor2Physical PROC ; Convert the cursor position R11 (0,1,2,,GetLengthUTF8)
XOR R12,R12 ; to physical position R12 (0,1,2,,GetLength$). Clobbers RAX,RCX.
XOR ECX,ECX ; Cursor position.
.50: CMP RCX,R11
JAE .60:
MOVZXB EAX,[R9+R12]
INC RCX
INC R12
CMP AL,0x80
JB .50:
NEG AL ; Scan bits 7..0 of the inverted first byte.
BSR EAX,EAX ; Returns EAX= 5, 4, 3 for 2, 3, 4 bytes long UTF-8 character.
NEG RAX ; RAX=-5,-4,-3 for 2, 3, 4 bytes long UTF-8 character.
LEA R12,[R12+RAX+6]
JMP .50:
.60: ; R12 is physical offset (0,1,2,,GetLength$) corresponding with cursor offset in R11.
RET
ENDP .Cursor2Physical
.CursorAtR11 PROC ; Place the cursor in the edit field at column R11 (0,1,2..GetLengthUTF8).
; R11 represents the visible position, not the position in strings bytes. It clobbers RAX,RDI.
LEA RDI,[EscGotoRowColH]
MOVZX EAX,[RBX+EDIT.ScreenRow]
StoD RDI
MOV AL,';'
STOSB
MOVZX EAX,[RBX+EDIT.ScreenCol]
ADD RAX,R11
StoD RDI
MOV AX,'H'
STOSW
StdOutput EscGoto
RET
ENDP .CursorAtR11
.EscHome:
XOR R11,R11
JMP .20:
.EscEnd:
GetLengthUTF8 R9
MOV R11,RCX
JMP .20:
.EscLeft:
TEST R11
JZ .20:
DEC R11
JMP .20:
.EscRight:
GetLengthUTF8 R9
CMP R11,RCX
JAE .20:
INC R11
JMP .20:
.0x08:
.0x7F: ; Move the cursor left and then perform .EscDelete.
TEST R11
JZ .20:
DEC R11
.EscDelete: ; Erase the character at cursor position R11. Move chars on the left by one position.
CALL .Cursor2Physical
MOV EDX,1 ; Size of the erased character.
MOVZXB EAX,[R9+R12]
CMP AL,0x80
JB .D2:
NEG AL ; Scan bits 7..0 of the inverted first byte.
BSR EAX,EAX ; Returns EAX= 5, 4, 3 for 2, 3, 4 bytes long UTF-8 character.
NEG RAX ; RAX=-5,-4,-3 for 2, 3, 4 bytes long UTF-8 character.
LEA RDX,[RDX+RAX+6]
.D2: LEA RDI,[R9+R12]
LEA RSI,[RDI+RDX]
GetLength$ R9
INC ECX
SUB RCX,R12
REP MOVSB
JMP .10:
.0x0D:
.0x0A:
.0x09:
.EscShiftTab:
.EscEscape:
XOR R11,R11
CALL .CursorAtR11:
MOV RSI,[RBX+EDIT.Address]
GetLengthUTF8 RSI
MOV EDX,[MainWidth]
SUB EDX,18
SUB EDX,ECX
StdOutput EscFindColor,RSI, EscDirsColor
StdOutput Spaces,Size=RDX
StdOutput EscHideCursor
RET
ENDP EditField
Construct a line from the [BufferSelected] into Dir. The line looks like
dir_size directory\name\in\UTF8, it is encoded in UTF-8 and zero terminated.
When the input line number RBX is 0, an empty line is returned (CF=1. RCX=0).
When the input line number RBX is 1, first line is returned (CF=0. RCX>0).
When the input line number RBX is 2, sedond line is returned etc.
When the input line number RBX is bigger than the [MaxLineNr], an empty line is returned (CF=1, RCX=0).
OneLine2Dir:: PROC
PUSH RBX,RDI
MOV EAX,[ArgViewDirs::]
MOV RDX,[Buffers+8*RAX-8]
BufferRetrieve RDX ; Load the buffer contents to RSI,RCX.
ADD RCX,RSI ; The end of buffer contents.
SAL EBX,4 ; Each SCAN_INDEX in the buffer contents has size=16.
JZ .10:
LEA RBX,[RBX+RSI-SIZE# SCAN_INDEX] ; Let RBX point at the selected SCAN_INDEX.
CMP RBX,RCX ; Is it out of contents?
JB .20:
.10:XOR ECX,ECX
LEA RSI,[Dir::]
STC
JMP .90: ; Abort when the requested line number exceeded the buffer and return CF=1 and empty line.
.20:MOV RDX,[NewerInMemory::]
CMP AL,ArgViewDirsDel
JNE .30:
MOV RDX,[OlderInMemory::] ; Select the mapping of File_scanOlder or File_scanNewer.
.30:MOV RAX,[RBX+SCAN_INDEX.Volume]
LEA RSI,[NumberA::]
StoD RSI,Size=20 ; Store the directory volume as a decimal ANSI
CALL AddUnderscores ; and complete it with separators.
LEA RSI,[Number_A::]
CMPB [ArgViewDirs::],ArgViewDirsDel
JNE .50:
CMPB [RSI],'0'
JE .50:
INC RSI ; Skip the minus sign when viewing deleted direcotires.
.50:LEA RDI,[Dir::]
CMPB [ArgViewDirs::],ArgViewDirsInc
JNE .60:
MOV AL,'+' ; Add a plus sign when viewing incremented directories.
JMP .70:
.60:LODSB
CMP AL,0
JE .80:
.70:STOSB
JMP .60:
.80:MOV ECX,[RBX+SCAN_INDEX.Size]
MOV EAX,[RBX+SCAN_INDEX.Ptr]
ADD RDX,RAX ; Let RDX point to the directory name.
MOV RSI,RDX
REP MOVSB
MOV RCX,RDI ; At the end of directory name.
MOVB [RDI],0 ; Zero terminate.
LEA RSI,[Dir]
SUB RCX,RSI ; CF=0, RSI,RCX is the target line.
.90:POP RDI,RBX
RET
ENDP OneLine2Dir
Complete an ASCII decadic number with underscores _ each three digits.
AddUnderscores PROC
PUSH RDX
SUB RDI,RSI
MOV ECX,3
MOV EAX,EDI
XOR EDX,EDX
LEA RDI,[Number_A::]
DIV RCX
CMP EDX,0
JNE .20:
REP MOVSB
DEC EAX
JMP .40:
.20:CMP EDX,1
JNE .30:
MOVSB
CMPB [RSI-1],'-'
JNE .40:
XCHG EAX,EDX
DEC EDX
JS .80:
JMP .60:
.30:MOVSW
.40:XCHG EAX,EDX
.50:DEC RDX
JS .80:
MOV AL,'_'
STOSB
.60:MOV CL,3
REP MOVSB
JMP .50:
.80:MOV AX,' '
STOSW
POP RDX
RET
ENDP AddUnderscores
ENDPROGRAM dirsling