pitch-dark/src/ui.common.a

382 lines
12 KiB
Plaintext

;license:MIT
;(c) 2018 by 4am
;
; User interface - common views and paint routines across screens
;
; Public functions
; - HardResetWeeGUI
; - ExitWeeGUI
; - ClearPendingInput
; - CreateRadio
; - CreateCheckbox
; - CreateButton
; - PaintTitleBar
; - PrintAt
; - SimulateClick
; - GetCheckedRadioButton
; - HandleUpDownRadio
; - CreateNullTerminatedString
; - AnyKeyOrClick
;
; Public variables
; - gViewInUse array of byte (each 0=false, nonzero=true)
; Public constants
; - kStringGlobalTitle
; - kStringOK
; - kStringCancel
;
gViewInUse
!byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
kStringGlobalTitle
!raw " "
!byte 16 ; inverse P
!raw "itch "
!byte 4 ; inverse D
!raw "ark ",0
kStringOK
!byte $0F ; 'O' inverse
!byte 139,0
kStringCancel
!byte $03 ; 'C' inverse
!text "ancel",0
; IDs of actions that do not correspond to WeeGUI view IDs have high bit set
ID_RADIO_PREVIOUS = $81
ID_RADIO_NEXT = $82
;------------------------------------------------------------------------------
; HardResetWeeGUI
; super-resets all WeeGUI views by creating 16 dummy views (which clears their
; internal state and callbacks and so on) then calling WeeGUI WGResetAll method
;
; in: WeeGUI initialized
; out: PARAM0/PARAM1 clobbered
; all registers clobbered
;------------------------------------------------------------------------------
HardResetWeeGUI
lda #15 ; highest possible WeeGUI view ID
sta @kHardResetDummyView
+LDAY @kHardResetDummyView
+STAY PARAM0
- ldx #WGCreateView
jsr WeeGUI ; create dummy views to reset state on all views
ldx @kHardResetDummyView
lda #0
sta gViewInUse,x
dec @kHardResetDummyView
bpl -
ldx #WGResetAll ; reset WeeGUI (destroys everything we just created)
jmp WeeGUI
@kHardResetDummyView
!byte 0,0,0,0,0,0,0,0
;------------------------------------------------------------------------------
; ExitWeeGUI
; clears the screen and safely shuts down WeeGUI
;
; in: WeeGUI initialized
; out: A,Y preserved
; X clobbered
;------------------------------------------------------------------------------
ExitWeeGUI
ldx #WGDisableMouse ; disable mouse support before quitting
jsr WeeGUI
ldx #WGClearScreen ; clear screen (HOME)
jsr WeeGUI
ldx #WGExit ; clean up WeeGUI
jmp WeeGUI
;------------------------------------------------------------------------------
; ClearPendingInput
; clears keyboard strobe and WeeGUI mouse click queue
;
; in: WeeGUI initialized
; out: A,Y preserved
; X clobbered
;------------------------------------------------------------------------------
ClearPendingInput
bit $C010 ; clear keyboard strobe
ldx #WGClearPendingClick ; clear WeeGUI mouse strobe
jmp WeeGUI
;------------------------------------------------------------------------------
; CreateRadio/CreateCheckbox/CreateButton
; creates a WeeGUI UI control with the 'raw title' option set
;
; in: WeeGUI initialized
; stack contains 2 bytes of parameters:
; +1 [word] pointer to WeeGUI view configuration block
; out: $00/$01 clobbered
; all registers clobbered
;------------------------------------------------------------------------------
CreateRadio
ldx #WGCreateRadio
+HIDE_NEXT_2_BYTES
CreateCheckbox
ldx #WGCreateCheckbox
+HIDE_NEXT_2_BYTES
CreateButton
ldx #WGCreateButton
stx @type
+PARAMS_ON_STACK 2
+LDPARAM 1
+STAY PARAM0
@type=*+1
ldx #$FD ; SMC
jsr WeeGUI
lda (PARAM0)
tax
lda #1
sta gViewInUse,x
ldx #WGViewSetRawTitle
sta PARAM0
jmp WeeGUI
;------------------------------------------------------------------------------
; CreateDialog
; creates a WeeGUI decorated frame view
;
; in: WeeGUI initialized
; stack contains 4 bytes of parameters:
; +1 [word] address of WeeGUI view configuration block for frame
; +3 [word] address of null-terminated string for frame title
; out: $00/$01 clobbered
; all registers clobbered
;------------------------------------------------------------------------------
CreateDialog
+PARAMS_ON_STACK 4
+LDPARAM 1
+STAY PARAM0
ldx #WGCreateView ; create frame
jsr WeeGUI
lda (PARAM0)
tax
lda #1
sta gViewInUse,x
+LDPARAM 3
+STAY PARAM0
ldx #WGViewSetTitle ; set frame title
jmp WeeGUI
;------------------------------------------------------------------------------
; PaintTitleBar
; paints the title bar on the top line
;
; in: WeeGUI initialized
; out: all registers and flags clobbered
;------------------------------------------------------------------------------
PaintTitleBar
ldy #79
- sty PARAM0
stz PARAM1
ldx #WGSetGlobalCursor
jsr WeeGUI
ldx #WGPlot
lda kStringGlobalTitle,y
jsr WeeGUI
dey
bpl -
ldx #WGSyncGlobalCursor
jmp WeeGUI
;------------------------------------------------------------------------------
; PrintAt
; print a null-terminated string at a specified position
;
; in: WeeGUI initialized
; stack contains 4 bytes of parameters:
; +1 [byte] X coordinate (relative to selected view)
; +2 [byte] Y coordinate (relative to selected view)
; +3 [word] address of null-terminated string
; out: WeeGUI local cursor positioned after string
; $00/$01 clobbered
; all registers and flags clobbered
;------------------------------------------------------------------------------
PrintAt
+PARAMS_ON_STACK 4
+LDPARAM 1
+STAY PARAM0
ldx #WGSetCursor
jsr WeeGUI
+LDPARAM 3
+STAY PARAM0
ldx #WGPrint
jmp WeeGUI
;------------------------------------------------------------------------------
; SimulateClick
; focus, activate, and unfocus a WeeGUI view
; note: does *not* select the view first, which you may or may not wish to do
; before calling
;
; in: WeeGUI initialized
; A contains WeeGUI view ID
; out: X clobbered
;------------------------------------------------------------------------------
SimulateClick
ldx #WGViewFocus
jsr WeeGUI
ldx #WGViewFocusAction
jsr WeeGUI
ldx #WGViewUnfocus
jmp WeeGUI
;------------------------------------------------------------------------------
; GetCheckedRadioButton
; determine which radio button on screen is visually checked
; WeeGUI only supports a single radio group, so there is only ever one
; selected radio button.
; WeeGUI has no way to query the type of a view, so this function takes the
; lower and upper IDs and all views within that range are presumed to be
; radio buttons.
; WeeGUI has no way to query if a view is in use, so each view within the
; given range must either (a) be in use, or (b) have had its state set to 0
; (perhaps by calling HardResetWeeGUI earlier).
;
; in: WeeGUI initialized
; X = WeeGUI view ID of first radio button
; Y = WeeGUI view ID of last radio button
; out: C clear -> A contains WeeGUI view ID of selected radio button
; C set -> error, there is no selected radio button
; Y preserved
; X clobbered
; other flags clobbered
;------------------------------------------------------------------------------
GetCheckedRadioButton
iny
sty @max
dey
txa
- pha
ldx #WGSelectView
jsr WeeGUI
ldx #WGGetState
jsr WeeGUI
lda PARAM0
and #1
bne @found
pla
inc
@max=*+1
cmp #$FD ; SMC
bcc -
+HIDE_NEXT_2_BYTES
@found pla
clc
rts
;------------------------------------------------------------------------------
; HandleUpDownRadio
;
; in: WeeGUI initialized
; A = action ID (#ID_RADIO_PREVIOUS or #ID_RADIO_NEXT)
; X = WeeGUI view ID of first radio button
; Y = WeeGUI view ID of last radio button
; out: all registers and flags clobbered
;------------------------------------------------------------------------------
HandleUpDownRadio
sta @action ; action ID >= #$80 is a screen-specific action, so stash it for now
stx @first
sty @last
jsr GetCheckedRadioButton ; A = WeeGUI view ID of currently checked radio button
ldx #WGSelectView ; uncheck it and repaint it
jsr WeeGUI
stz PARAM0
ldx #WGSetState
jsr WeeGUI
ldx #WGPaintView
jsr WeeGUI
@findNewLoop
@action=*+1
ldx #$FD
cpx #ID_RADIO_PREVIOUS
beq @up
@last=*+1
cmp #$FD
bcs +
inc ; move to next
+HIDE_NEXT_2_BYTES
@first=*+1
+ lda #$FD ; move to first
bra @checkNew
@up dec ; tentatively move to previous
cmp @first
bcs @checkNew
lda @last ; nope, we were already on the first, so move to last
@checkNew
tax
ldy gViewInUse,x ; if new radio is unused, move again
beq @findNewLoop
ldx #WGSelectView ; check new radio button and repaint it
jsr WeeGUI
ldx #WGViewFocus
jsr WeeGUI
ldx #WGSetState
lda #1
sta PARAM0
jsr WeeGUI
ldx #WGPaintView
jmp WeeGUI
;------------------------------------------------------------------------------
; CreateNullTerminatedString
; Copy a length-prefixed string to kNullTerminatedBuffer and null-terminate it.
; Destination string is left-padded with a single space because reasons.
; Maximum length is 127 bytes.
;
; in: A/Y contains address of length-prefixed string to copy
; X contains length of null-terminated string -- if > length of source,
; remaining buffer will be padded with spaces (#$A0)
; out: X preserved
; all other registers and flags clobbered
; $00/$01 clobbered
;------------------------------------------------------------------------------
CreateNullTerminatedString
+STAY $00
phx
lda #$A0
- dex
sta kNullTerminatedBuffer,x
bpl -
plx
lda #$00
sta kNullTerminatedBuffer,x
lda ($00)
tay
- lda ($00),y
sta kNullTerminatedBuffer,y
dey
bne -
rts
;------------------------------------------------------------------------------
; AnyKeyOrClick
; check for any user input (keypress or mouse click)
;
; in: none
; out: C set if key has been pressed or mouse has been clicked
; C clear if there have been no user input events
; all other flags clobbered
; all registers preserved
;------------------------------------------------------------------------------
AnyKeyOrClick
phx
ldx #WGPendingClick
jsr WeeGUI
cpx #$FF
bne + ; X != #$FF -> user clicked mouse
ldx $C000
bmi +
clc
+HIDE_NEXT_BYTE
+ sec
plx
rts