This is a GUI module of EuroTool program EuroSort for Linux.
EUROASM CPU=X64,Unicode=No
sortling PROGRAM Format=coff,Width=64
;; EXTERN LinABI@RT, StdOutputLin64@RT, StoD64@RT
%DROPMACRO *
INCLUDEHEAD1 argument.htm
INCLUDE1 linabi.htm, cpuext64.htm,cpuext.htm,linsfile.htm,lins.htm,string64.htm,time.htm,status32.htm
[.rodata]
NameArray: ; Codepage name, space-padded, justified to center.
uName %FOR ' Autodetect ',\
' ASCII ',\
' UTF-8 ',\
' UTF-16LE ',\
' UTF-16BE ',\
' UTF-32LE ',\
' UTF-32BE '
DB "%uName[2..%&-1]"
%ENDFOR uName
CP %MACRO CPid,Name,Altname,url,Table ; Redefine macro CP.
%IF "%Table" !=== ""
%uName %SET %Name[2..%&-1]
%NameSize %SETS %uName
%IF %NameSize>14
%NameSize %SETA 14
%ENDIF
%SpLeft %SETA (14-%NameSize)/2
%SpRight %SETA 14-%NameSize-%SpLeft
DB %SpLeft * BYTE ' '
DB "%uName[1..14]"
DB %SpRight * BYTE ' '
%ENDIF
%ENDMACRO CP
INCLUDE "codepage.htm" ; Expand the macro CP with each line of the table CodePages.
NameArrayEnd:
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
MinRows EQU 64 ; Minimal terminal dimensions.
MinCols EQU 48
Indentation EQU 24 ; Titles "Input file", "Encoding" etc.
[.rodata] ; Constant data.
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
Boxes DB NAME_MAX*2*BYTE '─' ; BOX DRAWINGS LIGHT HORIZONTAL 2500
Checked DB '■',0 ; BLACK SQUARE 25A0
Unchecked DB '□',0 ; WHITE SQUARE 25A1
Spaces DB NAME_MAX * 2 * BYTE ' ',0
Box3U DB '┌─┐',0
Box3D DB '└─┘',0
Box4U DB '┌──┐',0
Box4D DB '└──┘',0
Box6U DB '┌────┐',0
Box6D DB '└────┘',0
Box14U DB '╔════════════╗',0
Box14D DB '╚════════════╝',0
EscRight DB 27,'[C'
EscLeft DB 27,'[D'
EscHome DB 27,'[H'
EscEnd DB 27,'[F'
EscShiftTab DB 27,'[Z'
EscDelete DB 27,'[3~'
EscBaseColor:: DB 27,'[30;47m',0 ; Zero-terminated sequences for writing to terminal.
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
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
EscGoto DB 27,'['
EscGotoRowColH DB 'row;colH',0
line %FOR 1..21 ; Define EscLine1, EscLine2 etc.
EscLine%line DB 27,'[%line{}H',0
%ENDFOR line
Back4 DB 8
Back3 DB 8
Back2 DB 8,8,0
EuroSort DB ' EuroSort',0
Version DB ' version %^Date',0
GuiRecordSize DB '0',19*B 0 ; GUI-maintained arguments in text form.
GuiHeaderSize DB '0',19*B 0
GuiHeaderLength DB '0',19*B 0
GuiFooterSize DB '0',19*B 0
GuiFooterLength DB '0',19*B 0
GuiKeyOffset DB '0',19*B 0
GuiKeyLength DB '-1',18*B 0
GuiLocale DB '--'
[.bss] ; Working data.
Edit DS EDIT
TtySize DS TTYSIZE
TermIO DS TERMIO
MainWidth D DWORD ; The width of the window.
NrOfEncodingCol D DWORD ; How many encoding names will fit on one terminal line.
NrOfLocalesCol D DWORD ; How many locale names will fit on one terminal line.
MainHeight D DWORD ; Number of lines in the main window.
EncodingLastRow D DWORD ; Encoding buttons are between 22 and this value.
LocaleFirstRow D DWORD ; Row of the first locale button.
LocaleInterSpaces D DWORD ; Number of spaces between Locale buttons.
NumInterSpaces D DWORD ; Number of spaces between numeric buttons -RS,-HS,-HL,-FS,-FL.
BoxInterSpaces D DWORD ; Number of spaces between boxes -KO,-KS,-KR etc.
OneFifth D DWORD ; One fifth of MainWidth.
CancelSortRow D DWORD ; Row if the buttons [Cancel] and [Sort].
TabSelected D DWORD ; 0,5,10,15,20,25,30,,,index of jump.
KeyBuffer D 32*BYTE ; Buffer for reading the keyboard.
Number D 24*BYTE ; Ordinary number in decadic form.
[.text]
MainGui:: PROC
CALL Arg2Gui ; Convert numeric arguments to decimal form.
CALL PaintWindow
MOV [TabSelected],-5
MOV EAX,[MainWidth]
XOR EDX,EDX
MOV ECX,5
DIV RCX ; EAX is MainWidth/5.
MOV [OneFifth],EAX
MOV ESI,[MainWidth]
SUB ESI,5*6
SHR ESI,2 ; Number of spaces between five NumFields.
MOV [NumInterSpaces],ESI
MOV EAX,[MainWidth]
SUB EAX,2*6+5*3
MOV ECX,6
XOR EDX,EDX
DIV RCX
MOV [BoxInterSpaces],EAX
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 EscShiftTab,EscTab,EscEscape
LEA RDI,[%key]
MOV CL,SIZE# %key
MOV RSI,R8 ; KeyBuffer.
REPE CMPSB
JE .%key:
%ENDFOR key
MOV RSI,R8 ; Read the mouse.
LODSW
CMP AX,0x5B1B ; Esc [
JNE .10:
LODSB
CMP AL,0x3C ; Less-than?
JNE .10:
LodD ; Mouse button.
JC .10:
CMP AL,0
JNE .10:
LODSB
CMP AL,';'
JNE .10:
LodD
JC .10:
MOV EBX,EAX ; X-coordinate of mouse cursor.
SHL EBX,16
LODSB
CMP AL,';'
JNE .10:
LodD
JC .10:
MOV BX,AX ; Y-coordinate of mouse cursor.
LODSB
CMP AL,'m'
JNE .10:
CMP BX,3 ; Mouse cursor coordinates are in EBX. Row number is in BX.
JB .23:
CMP BX,5
JA .23:
.TabIF:
LEA RSI,[ArgInputFile::] ; Input file clicked.
MOV [Edit.Address],RSI
MOV [Edit.MaxSize],NAME_MAX
MOV EAX,[MainWidth]
SUB EAX,2
MOV [Edit.ScreenSize],AX
MOV [Edit.ScreenRow],4
MOV [Edit.ScreenCol],2
.13:CALL EditField
CALL Gui2Arg
.16:CALL PaintWindow
JMP .10:
.TabRS:
XOR EBX,EBX
JMP .20:
.TabHS:
MOV EBX,[OneFifth]
JMP .20:
.TabHL:
MOV EBX,[OneFifth]
ADD EBX,EBX
JMP .20:
.TabFS:
MOV EBX,[OneFifth]
LEA EBX,[EBX+2*EBX]
JMP .20:
.TabFL:
MOV EBX,[MainWidth]
.20:MOV ESI,[NumInterSpaces]
MOV EAX,[OneFifth]
JMP .30:
.TabKO:
SUB EBX,EBX
JMP .40:
.TabKL:
MOV EBX,[BoxInterSpaces]
ADD EBX,12
JMP .40:
.23:CMP BX,12
JB .26:
CMP BX,14
JA .26:
.TabOF:
LEA RSI,[ArgOutputFile::]; Output file clicked.
MOV [Edit.Address],RSI
MOV [Edit.MaxSize],NAME_MAX
MOV EAX,[MainWidth]
SUB EAX,2
MOV [Edit.ScreenSize],AX
MOV [Edit.ScreenRow],13
MOV [Edit.ScreenCol],2
JMP .13:
.26:CMP BX,8
JB .36:
CMP BX,10
JA .36:
SHR EBX,16 ; Numfield clicked.
MOV EAX,[OneFifth]
MOV ESI,[NumInterSpaces]
.30:MOV EDX,2
LEA RDI,[GuiRecordSize]
SUB EBX,EAX
JB .33:
LEA EDX,[EDX+ESI+6]
LEA RDI,[GuiHeaderSize]
SUB EBX,EAX
JB .33:
LEA EDX,[EDX+ESI+6]
LEA RDI,[GuiHeaderLength]
SUB EBX,EAX
JB .33:
LEA EDX,[EDX+ESI+6]
LEA RDI,[GuiFooterSize]
SUB EBX,EAX
JB .33:
LEA EDX,[EDX+ESI+6]
LEA RDI,[GuiFooterLength]
.33:MOV [Edit.Address],RDI
MOV [Edit.MaxSize],20
MOV [Edit.ScreenSize],4
MOV [Edit.ScreenRow],9
MOV [Edit.ScreenCol],DX
JMP .13:
.36:CMP BX,17
JB .50:
CMP BX,19
JA .50:
SHR EBX,16 ; Boxfield clicked. EBX is column.
.40:MOV EAX,[BoxInterSpaces]
MOV EDX,6 ; EAX is the number of spaces between elements.
LEA RDI,[GuiKeyOffset]
CMP EBX,EDX
JBE .46:
LEA RDI,[GuiKeyLength]
LEA EDX,[EDX+EAX+6]
CMP EBX,EDX
JBE .46:
arg %FOR KeyReverse,DigitFirst,PunctuationFirst,UpperFirst,MergeSpaces
MOV EDI,Arg%arg
LEA EDX,[EDX+EAX+3]
CMP EBX,EDX
JBE .43:
%ENDFOR arg
.43:XOR [Status::],EDI
JMP .16:
.46:MOV [Edit.Address],RDI
MOV [Edit.MaxSize],20
MOV [Edit.ScreenSize],4
MOV [Edit.ScreenRow],18
SUB EDX,4
MOV [Edit.ScreenCol],DX
JMP .13:
.50:CMP BX,22
JB .65:
MOV EAX,[EncodingLastRow]
CMP BX,AX
JAE .65:
SUB BX,22 ; Clicked on Encodings.
MOV EAX,[NrOfEncodingCol]
MOVZXW ECX,BX
MUL RCX
SHR EBX,16
.55:SUB EBX,14
JB .60:
INC EAX
JMP .55:
.60:LEA RSI,[CPid::]
MOVZXW EAX,[RSI-2+2*RAX]
MOV [ArgInputEncoding::],EAX
JMP .16:
.65:LEA RDI,[Locales::]
MOV ESI,[LocaleInterSpaces]
MOV EAX,[LocaleFirstRow]
CMP BX,AX
JB .85:
ADD EAX,3
CMP BX,AX
JB .70:
CMP BX,[CancelSortRow]
JAE .85:
ADD EAX,2
CMP BX,AX
JA .85:
MOV EAX,[NrOfLocalesCol]
MOV ECX,SIZE# VAL
MUL RCX
ADD RDI,RAX ; RDI points to the first button on the last row.
.70:SHR EBX,16 ; EBX is now the column.
MOV EDX,6
.75:CMP EBX,EDX
JB .80:
ADD RDI,SIZE# VAL
CMP RDI,EndLocales::
JNB .10:
LEA EDX,[EDX+ESI+4]
JMP .75:
.80:MOV EAX,[RDI+VAL.ValValue]
MOV [ArgLocale::],EAX
JMP .16:
.85:MOV EAX,[CancelSortRow]
CMP BX,AX
JB .10:
SHR EBX,16 ; Clicked on [Cancel] or [Sort].
CMP EBX,16
JA .EscEscape:
SetSt [Status::],ArgCancel
JMP .EscEscape:
TabSelTable: ; Each jump is encoded to 5 bytes long instruction.
JMP .TabIF:
JMP .TabRS:
JMP .TabHS:
JMP .TabHL:
JMP .TabFS:
JMP .TabFL:
JMP .TabOF:
JMP .TabKO:
JMP .TabKL:
TabSize EQU 9
.EscShiftTab:
MOV EAX,[TabSelected]
SUB EAX,5
JNB .90:
MOV EAX,5*(TabSize-1)
JMP .90:
.EscTab: ; Tab pressed.
MOV EAX,[TabSelected]
ADD EAX,5
CMP AL,5*TabSize
JB .90:
SUB EAX,EAX
.90:MOV [TabSelected],EAX ; RAX=0,5,10,,,
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.
RET
ENDP MainGui
PaintWindow PROC
LinABI ioctl,0,TIOCGWINSZ,TtySize
MOVZXW EDX,[TtySize.ts_lines]
MOVZXW ECX,[TtySize.ts_cols]
MOV EAX,MinRows ; Minimal acceptable lines.
CMP EDX,EAX
JB .10:
MOV EAX,EDX
.10:LEA RDI,[ValResize]
StoD RDI
MOV AL,';'
STOSB
MOV EAX,MinCols ; Minimal acceptable columns.
CMP ECX,EAX
JB .15:
MOV EAX,ECX
.15:StoD RDI
MOV AX,'t'
STOSW
StdOutput EscResize
LinABI ioctl,0,TIOCGWINSZ,TtySize
MOVZXW EDX,[TtySize.ts_lines]
DEC EDX ; Reserve one low line for status.
MOV [MainHeight],EDX
MOVZXW ECX,[TtySize.ts_cols]
MOV [MainWidth],ECX
; Start painting.
StdOutput EscLine1,EscBaseColor,=B' ',EscEnhColor,EuroSort,EscDimColor,Version,Spaces
StdOutput EscLine2,EscBaseColor ; Row 2
StdOutput Spaces,Size=Indentation
StdOutput =B'Input file',Spaces
StdOutput EscLine3,BoxDR ; Row 3
MOV ECX,[MainWidth]
SUB ECX,2
LEA EDX,[2*ECX+ECX]
StdOutput Boxes,Size=RDX
StdOutput BoxDL,EscLine4,BoxV ; Row 4
LEA RSI,[ArgInputFile::]
GetLengthUTF8 RSI
StdOutput RSI,Size=RCX
MOV EAX,[MainWidth]
SUB EAX,2
SUB EAX,ECX
JBE .25:
StdOutput Spaces,Size=RAX
.25:StdOutput BoxV,EscLine5,BoxUR ; Row 5
StdOutput Boxes,Size=RDX
StdOutput BoxUL,EscLine6 ; Row 6
MOV ESI,[MainWidth]
SUB ESI,5*6
SHR ESI,2 ; Number of spaces between five NumFields.
StdOutput =B'Record'
LEA ECX,[ESI+1]
StdOutput Spaces,Size=RCX
StdOutput =B'Head'
LEA ECX,[ESI+2]
StdOutput Spaces,Size=RCX
StdOutput =B'Head'
StdOutput Spaces,Size=RCX
StdOutput =B'Foot'
StdOutput Spaces,Size=RCX
StdOutput =B'Foot'
StdOutput Spaces,Size=RCX
StdOutput EscLine7,=B' size' ; Row 7
LEA ECX,[ESI+2]
StdOutput Spaces,Size=RCX
StdOutput =B'Size'
StdOutput Spaces,Size=RCX
StdOutput =B'Length'
SUB ECX,2
StdOutput Spaces,Size=RCX
StdOutput =B'Size'
StdOutput Spaces,Size=RCX
StdOutput =B'Length',Spaces
StdOutput EscLine8 ; Row 8
MOV ECX,5
.30:StdOutput Box6U
StdOutput Spaces,Size=RSI
LOOP .30:
StdOutput EscLine9 ; Row 9
MOV EAX,[ArgRecordSize::]
CALL .NumField:
MOV EAX,[ArgHeaderSize::]
CALL .NumField:
MOV EAX,[ArgHeaderLength::]
CALL .NumField:
MOV EAX,[ArgFooterSize::]
CALL .NumField:
MOV EAX,[ArgFooterLength::]
CALL .NumField:
StdOutput EscLine10 ; Row 10
MOV ECX,5
.35:StdOutput Box6D
StdOutput Spaces,Size=RSI
LOOP .35:
StdOutput EscLine11 ; Row 11
StdOutput Spaces,Size=Indentation
StdOutput =B'Output file',Spaces
StdOutput EscLine12,BoxDR ; Row 12
StdOutput Boxes,Size=RDX
StdOutput BoxDL,EscLine13,BoxV ; Row 13
LEA RSI,[ArgOutputFile::]
GetLengthUTF8 RSI
StdOutput RSI,Size=RCX
MOV ESI,[MainWidth]
SUB ESI,2
MOV EDI,ESI
SUB EDI,ECX
JBE .40:
StdOutput Spaces,Size=RDI
.40:StdOutput BoxV,EscLine14,BoxUR ; Row 14
StdOutput Boxes,Size=RDX
StdOutput BoxUL,EscLine15,=B' Key ' ; Row 15
MOV EAX,[MainWidth]
SUB EAX,2*6+5*3
XOR EDX,EDX
MOV ECX,6
DIV RCX
MOV ESI,EAX ; Spaces between fields.
StdOutput Spaces,Size=RSI
StdOutput =B' Key '
StdOutput Spaces,Size=RSI
StdOutput =B' Key '
StdOutput Spaces,Size=RSI
StdOutput Back3,=B'Digit'
StdOutput Spaces,Size=RSI
StdOutput Back3,=B'Punct.'
StdOutput Spaces,Size=RSI
StdOutput Back3,=B'Upper'
StdOutput Spaces,Size=RSI
StdOutput Back2,=B'Merge',Spaces
StdOutput EscLine16 ; Row 16
StdOutput =B'Offset'
StdOutput Spaces,Size=RSI
StdOutput =B'Length'
StdOutput Spaces,Size=RSI
StdOutput =B'Reverse'
StdOutput Spaces,Size=RSI
StdOutput Back4,=B'First'
StdOutput Spaces,Size=RSI
StdOutput Back3,=B'First'
StdOutput Spaces,Size=RSI
StdOutput Back2,=B'First'
StdOutput Spaces,Size=RSI
StdOutput Back3,=B'Spaces'
StdOutput Spaces,Size=RSI
StdOutput EscLine17,Box6U ; Row 17
StdOutput Spaces,Size=RSI
StdOutput Box6U
StdOutput Spaces,Size=RSI
StdOutput Box3U
StdOutput Spaces,Size=RSI
StdOutput Box3U
StdOutput Spaces,Size=RSI
StdOutput Box3U
StdOutput Spaces,Size=RSI
StdOutput Box3U
StdOutput Spaces,Size=RSI
StdOutput Box3U,Spaces,EscLine18 ; Row 18
MOV EAX,[ArgKeyOffset::]
CALL .NumField:
MOV EAX,[ArgKeyLength::]
CDQE
CALL .NumField:
arg %FOR KeyReverse,DigitFirst,PunctuationFirst,UpperFirst,MergeSpaces
LEA RDX,[Checked]
JSt [Status::],Arg%arg,.%arg:
LEA RDX,[Unchecked]
.%arg:StdOutput BoxV,RDX,BoxV
StdOutput Spaces,Size=RSI
%ENDFOR arg
StdOutput EscLine19,Box6D ; Row 19
StdOutput Spaces,Size=RSI
StdOutput Box6D
StdOutput Spaces,Size=RSI
StdOutput Box3D
StdOutput Spaces,Size=RSI
StdOutput Box3D
StdOutput Spaces,Size=RSI
StdOutput Box3D
StdOutput Spaces,Size=RSI
StdOutput Box3D
StdOutput Spaces,Size=RSI
StdOutput Box3D
StdOutput Spaces,Size=RSI
MOV EAX,[MainWidth]
SUB EAX,2
MOV ECX,14 ; Width of one "button" for encoding selection.
XOR EDX,EDX
DIV RCX
MOV [NrOfEncodingCol],EAX ; Columns of encoding buttons.
StdOutput EscLine20 ; Row 20
StdOutput Spaces,Size=Indentation
StdOutput =B'Encoding',Spaces,EscLine21,BoxDR ; Row 21
MOV ESI,[MainWidth]
LEA EDX,[ESI+2*ESI-6]
StdOutput Boxes,Size=RDX
StdOutput BoxDL
MOV R10,22 ; Start with Row 22
LEA RBX,[NameArray]
LEA R9,[CPid::-2]
.45:MOV EDX,1 ; Loop for Encoding selections.
CALL Goto:
StdOutput BoxV
.50:MOVZXW EAX,[R9]
CMP EAX,[ArgInputEncoding::]
LEA RAX,[EscFileColor]
JE .55:
LEA RAX,[EscBaseColor]
.55:StdOutput RAX
StdOutput RBX,Size=14
StdOutput EscBaseColor
ADD RBX,14
ADD EDX,14
ADD R9,2
LEA RAX,[NameArrayEnd]
CMP RBX,RAX
JNB .60:
LEA EAX,[EDX+14-1]
CMP EAX,[MainWidth]
JB .50:
.60:MOV EAX,[MainWidth]
SUB EAX,1
SUB EAX,EDX
JB .65:
StdOutput Spaces,Size=RAX
.65:StdOutput BoxV
INC R10
MOV [EncodingLastRow],R10D
LEA RAX,[NameArrayEnd]
CMP RBX,RAX
JB .45:
MOV EDX,1
CALL Goto:
StdOutput BoxUR
MOV EAX,[MainWidth]
LEA ECX,[EAX+2*EAX-6]
StdOutput Boxes,Size=RCX
StdOutput BoxUL
MOV EDX,1
INC R10
CALL Goto:
StdOutput Spaces, Size=Indentation
StdOutput =B'Locale',Spaces
INC R10
CALL Goto:
StdOutput BoxDR
MOV EAX,[MainWidth]
LEA ECX,[RAX+2*RAX-6]
StdOutput Boxes,Size=RCX
StdOutput BoxDL
INC R10
MOV [LocaleFirstRow],R10D
CALL .Frame3:
LEA RBX,[Locales::] ; Array of VAL records.
LEA RAX,[EndLocales::]
SUB RAX,RBX
MOV ECX,SIZE# VAL
XOR EDX,EDX
DIV RCX ; RAX=number of locales.
MOV R9,RAX
SHL EAX,2 ; Each button is 4 characters wide.
XOR R11,R11 ; R11 is interbutton spaces.
XOR R12,R12 ; R12=button counter.
MOV ECX,[MainWidth]
SUB ECX,2
SUB ECX,EAX
JB .70:
MOV EAX,ECX
DIV R9
MOV R11,RAX ; R11 is interbutton spaces.
MOV [LocaleInterSpaces],EAX
.70:MOV EDX,2
.73:CMP EBX,EndLocales:: ; Start painting buttons.
JNB .85:
MOV EAX,[MainWidth]
SUB EAX,5
CMP EDX,EAX
JNB .80:
CALL Goto:
StdOutput Box4U
INC R10
CALL Goto:
MOV EAX,[RBX+VAL.ValValue]
LEA RDI,[GuiLocale]
MOV [RDI],AX
CMP EAX,[ArgLocale::]
LEA RCX,[EscBaseColor]
JNE .77:
LEA RCX,[EscFileColor]
.77:StdOutput BoxV,RCX,RDI,EscBaseColor,BoxV
INC R12
INC R10
CALL Goto:
StdOutput Box4D
SUB R10,2
LEA RDX,[RDX+4+R11]
ADD RBX,SIZE# VAL
JMP .73:
.80:; First row of buttons is full.
MOV [NrOfLocalesCol],R12D
ADD R10,3
CALL .Frame3:
JMP .70:
.85:ADD R10,3
MOV EDX,1
CALL Goto:
StdOutput BoxUR
MOV EAX,[MainWidth]
LEA ECX,[EAX+2*EAX-6]
StdOutput Boxes,Size=RCX
StdOutput BoxUL
INC R10
MOV [CancelSortRow],R10D
CALL .Frame3:
MOV EDX,1
CALL Goto:
StdOutput Box14U
MOV EDX,[MainWidth]
SUB EDX,13
CALL Goto:
StdOutput Box14U
INC R10
MOV EDX,1
CALL Goto:
StdOutput Box2V,=B' Cancel ',Box2V
MOV EDX,[MainWidth]
SUB EDX,13
CALL Goto:
StdOutput Box2V,=B' Sort ',Box2V
INC R10
MOV EDX,1
CALL Goto:
StdOutput Box14D
MOV EDX,[MainWidth]
SUB EDX,13
CALL Goto:
StdOutput Box14D
INC R10
MOV EDX,1
CALL Goto:
RET
.NumField: PROC1 ; Paint the number RAX to the edit area between boxes.
StoD Number,Align=right,Size=4
StdOutput BoxV
StdOutput Number,Size=4
StdOutput BoxV
StdOutput Spaces,Size=RSI
RET
ENDP1 .NumField:
.Frame3: PROC1 ; Preformat three empty lines. Input:R10=line. Clobbers RAX,RCX,RDX.
MOV EDX,1
MOV ECX,3
.2: CALL Goto:
StdOutput BoxV
MOV EAX,[MainWidth]
SUB EAX,2
StdOutput Spaces,Size=RAX
StdOutput BoxV
INC R10
LOOP .2:
SUB R10,3
RET
ENDP1 .Frame3:
ENDP PaintWindow
Goto PROC
PUSH RDI,RAX,RAX,RAX
MOV RDI,RSP
MOV AL,27
STOSB
MOV AL,'['
STOSB
MOV RAX,R10
StoD RDI
MOV AL,';'
STOSB
MOV EAX,EDX
StoD RDI
MOV AX,'H'
STOSW
MOV RDI,RSP
StdOutput RDI
POP RAX,RAX,RAX,RDI
RET
ENDP Goto
Gui2Arg PROC
PUSH RSI
arg %FOR RecordSize,HeaderSize,HeaderLength,FooterSize,FooterLength,KeyOffset,KeyLength
LEA RSI,[Gui%arg]
LodD RSI
MOV [Arg%arg::],EAX
%ENDFOR arg
POP RSI
RET
ENDP Gui2Arg
Arg2Gui PROC
PUSH RDI
arg %FOR RecordSize,HeaderSize,HeaderLength,FooterSize,FooterLength,KeyOffset,KeyLength
MOV EAX,[Arg%arg::]
CDQE
LEA RDI,[Gui%arg]
StoD RDI,Signed=yes,Align=left
%ENDFOR arg
POP RDI
RET
ENDP Arg2Gui
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
SUB EAX,ECX
JA .20:
XOR EAX,EAX
.20: ADD R11,RCX
StdOutput EscShowCursor,EscEditColor,RSI
StdOutput Spaces,Size=RAX
POP R11
.30: CALL .CursorAtR11: ; Display (perhaps new) cursor position.
.40: XOR EDI,EDI ; Read the keyboard.
LEA RSI,[KeyBuffer]
MOV [RSI],RDI ; Clear the 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
JE .0x0A: ; treat as an escape from edit window.
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:
.EscHome:
XOR R11,R11
JMP .30:
.EscEnd:
GetLengthUTF8 R9
MOV R11,RCX
JMP .30:
.EscLeft:
TEST R11
JZ .30:
DEC R11
JMP .30:
.EscRight:
GetLengthUTF8 R9
CMP R11,RCX
JAE .30:
INC R11
JMP .30:
.0x08:
.0x7F: ; Move the cursor left and then perform .EscDelete.
TEST R11
JZ .30:
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 .60:
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]
.60: LEA RDI,[R9+R12]
LEA RSI,[RDI+RDX]
GetLength$ R9
INC ECX
SUB RCX,R12
REP MOVSB
JMP .10:
.0x0D:
.0x0A:
.0x09:
.EscShiftTab:
.EscEscape:
.80: StdOutput EscBaseColor,EscHideCursor
RET
.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.
.1: CMP RCX,R11
JAE .8:
MOVZXB EAX,[R9+R12]
INC RCX
INC R12
CMP AL,0x80
JB .1:
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 .1:
.8: ; 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
ENDP EditField
ENDPROGRAM sortling