;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