pitch-dark/src/ui.main.a

437 lines
14 KiB
Plaintext

;license:MIT
;(c) 2018 by 4am
;
; User interface - views and paint routines for main screen
;
; Public functions
; - MainScreen
;
; Public variables
; - gMainScreenPaintDirty byte 0=false, nonzero=true
;
; View IDs (application-specific, acceptable range 0..15, no duplicates)
ID_PREVIOUS = 1
ID_OPTIONS = 2
ID_NEXT = 3
ID_PLAY = 4
ID_BOXART = 5
ID_HINTS = 6
ID_VERSIONS = 7
ID_INFO = 8
ID_DESCRIPTION = 9
ID_ABOUT = 10
ID_CATALOG = 11
gMainScreenPaintDirty
!byte 0
kInfoPaintWidth = 65
kDescriptionPaintWidth = 78
;------------------------------------------------------------------------------
; MainScreen
; display main screen and run to completion
;------------------------------------------------------------------------------
MainScreen
ldx #$FF
txs
jsr PaintMain ; create all WeeGUI views (UI elements) and paint them
jsr ClearPendingInput
- jsr RepaintMainIfDirty
ldx #WGPendingViewAction
jsr WeeGUI ; handle mouse movement and clicks
lda $C000
bpl -
jsr ClearPendingInput
jsr HandleKey ; handle keypresses
bra -
;------------------------------------------------------------------------------
; internal functions
;------------------------------------------------------------------------------
; PaintMain/RepaintMainIfDirty
; call WeeGUI to create all application views and paint them
; PaintMain entry point will clear the screen and unconditionally paint everything
; RepaintMainIfDirty will only repaint certain views that vary between games,
; and only if gMainScreenPaintDirty=1
;
; in: WeeGUI initialized
; out: all registers and flags clobbered
;------------------------------------------------------------------------------
PaintMain
jsr HardResetWeeGUI
ldx #1 ; flag - clear screen before painting
stx gMainScreenPaintDirty
+HIDE_NEXT_2_BYTES
RepaintMainIfDirty
ldx #0 ; flag - do not clear screen before painting
lda gMainScreenPaintDirty
bne +
rts
+ stz gMainScreenPaintDirty ; clear dirty flag
phx ; push 'clear screen' flag (will pop at end of procedure)
jsr CreateButton ; create 'previous' button
!word kViewPrevious
jsr CreateButton ; create 'catalog' button
!word kViewCatalog
jsr CreateButton ; create 'settings' button
!word kViewOptions
jsr CreateButton ; create 'next game' button
!word kViewNext
lda gHasSavedGames ; create 'play game' or 'resume game' button
beq @wantPlayButton
jsr CreateButton
!word kViewResume
bra @donePlayOrResume
@wantPlayButton
jsr CreateButton
!word kViewPlay
@donePlayOrResume
jsr CreateOrDestroyButton ; create or destroy 'artwork' button
!byte ID_BOXART
!word kViewBoxArt
!word kHasArtwork
jsr CreateOrDestroyButton ; create or destroy 'hints' button
!byte ID_HINTS
!word kViewHints
!word kHasHints
jsr CreateOrDestroyButton ; create or destroy 'revisions' button
!byte ID_VERSIONS
!word kViewVersions
!word kHasVersions
jsr CreateButton ; create '?' button
!word kViewAbout
pla ; clear screen before repainting?
beq @nohome ; no -> repaint over existing screen, YOLO
ldx #WGClearScreen ; clear screen
jsr WeeGUI
jsr PaintTitleBar ; paint top bar
lda #4 ; paint horizontal separator bar
sta PARAM1
ldy #78
lda #83
- sty PARAM0
ldx #WGSetGlobalCursor
jsr WeeGUI
ldx #WGPlot
jsr WeeGUI
dey
bne -
ldx #WGSyncGlobalCursor
jsr WeeGUI
@nohome
ldx #WGSelectView ; delete info box but leave its contents on screen
lda #ID_INFO ; (harmless if it doesn't exist yet)
jsr WeeGUI
ldx #WGResetView
jsr WeeGUI
ldx #WGSelectView ; delete description box but leave its contents on screen
lda #ID_DESCRIPTION ; (harmless if it doesn't exist yet)
jsr WeeGUI
ldx #WGResetView
jsr WeeGUI
ldx #WGSelectView ; WeeGUI does NOT like repainting if the selected view does not exist
lda #ID_PREVIOUS
jsr WeeGUI
ldx #WGViewPaintAll ; repaint all WeeGUI-controlled UI elements
jsr WeeGUI
ldx #WGCreateView ; (re)create borderless frame for game title and info
+LDADDR kViewInfo ; (has the nice side effect of resetting the scroll)
+STAY PARAM0
jsr WeeGUI
jsr PaintInfoView ; paint contents of info box
ldx #WGCreateView ; (re)create scrollable frame for game description text
+LDADDR kViewDescription
+STAY PARAM0
jsr WeeGUI
ldx #WGViewSetAction ; set view action (called automatically after scrolling)
+LDADDR PaintDescriptionView
+STAY PARAM0
jsr WeeGUI
ldx #WGPaintView ; paint frame of description box
jsr WeeGUI
jmp PaintDescriptionView ; paint contents of description box
;------------------------------------------------------------------------------
; CreateOrDestroyButton
; create or destroy a WeeGUI Button view, based on per-game options
; and whether the button already exists
;
; in: WeeGUI initialized
; gOptionsStore populated
; stack contains 5 bytes of parameters:
; +1 [byte] WeeGUI view ID
; +2 [word] address of WeeGUI view configuration record
; +4 [word] address of length-prefixed key into gOptionsStore
; out: all registers and flags clobbered
;------------------------------------------------------------------------------
CreateOrDestroyButton
+PARAMS_ON_STACK 5
ldy #1
lda (PARAM),y
pha ; A = WeeGUI view ID
+LDPARAM 2
+STAY @vcr
+LDPARAM 4
+STAY @key
jsr okvs_get
!word gOptionsStore
@key !word $FDFD ; SMC
plx ; X = WeeGUI view ID
jsr okvs_as_boolean
beq @destroy
lda gViewInUse,x ; create button if it doesn't exist
bne @exit ; oh it does exist, so we're done
lda #1
sta gViewInUse,x
jsr CreateButton
@vcr !word $FDFD ; SMC
@exit rts
@destroy
lda gViewInUse,x ; destroy button if it exists
beq @exit ; oh it doesn't exist, so we're done
lda #0
sta gViewInUse,x
txa ; A = WeeGUI view ID
ldx #WGSelectView
jsr WeeGUI
ldx #WGEraseView
jsr WeeGUI
ldx #WGResetView
jmp WeeGUI
PaintDescriptionView
ldx #WGSelectView
lda #ID_DESCRIPTION
jsr WeeGUI
+LDAY addrDescription
ldx #kDescriptionPaintWidth
jsr MultiPrint
lda SAVE
cmp #10
bcs +
lda #10 ; minimum content height
+ ldx #WGSetContentHeight ; set content height so we stop scrolling on the last line of text
jmp WeeGUI
PaintInfoView
ldx #WGSelectView
lda #ID_INFO
jsr WeeGUI
+LDAY addrInfo
ldx #kInfoPaintWidth
phx
jsr MultiPrint
jsr okvs_get ; get shortname of current game
!word gGlobalPrefsStore
!word kLastPlayed
+STAY + ; A/Y contains address
jsr okvs_get ; get selected version of this game
!word gGlobalPrefsStore
+ !word $FDFD ; SMC
+STAY + ; A/Y contains address
jsr okvs_get ; get long description of this version
!word gVersionsStore
+ !word $FDFD ; SMC
; A/Y contains address
plx ; X = width a.k.a. where to put the null (rest is padded with spaces)
jsr CreateNullTerminatedString ; copies string to kNullTerminatedBuffer
+LDADDR kNullTerminatedBuffer ; now use that as the buffer to print the last line
+HIDE_NEXT_2_BYTES
MultiPrint
stz SAVE ; VTAB, but 0-indexed
stx @linelen
+STAY SRC
@loop stz PARAM0
lda SAVE
sta PARAM1
ldx #WGSetCursor
jsr WeeGUI
+LDAY SRC
+STAY PARAM0
bit MAGICRTS ; set overflow bit to trigger raw printing (with mousetext)
ldx #WGPrint
jsr WeeGUI
lda SRC
clc
@linelen=*+1
adc #$FD ; SMC
sta SRC
bcc +
inc SRC+1
+ inc SAVE
lda (SRC)
bne @loop
rts
;------------------------------------------------------------------------------
; WeeGUI view configuration records
kViewPrevious
!byte ID_PREVIOUS ; view ID
!byte 1 ; left
!byte 2 ; top
!byte 13 ; width
!word callback_previous ; callback
!word kStringPrevious ; caption
kViewNext
!byte ID_NEXT ; view ID
!byte 66 ; left
!byte 2 ; top
!byte 13 ; width
!word callback_next ; callback
!word kStringNext ; caption
kViewCatalog
!byte ID_CATALOG ; view ID
!byte 27 ; left
!byte 2 ; top
!byte 11 ; width
!word CatalogDialog ; callback
!word kStringCatalog
kViewOptions
!byte ID_OPTIONS ; view ID
!byte 41 ; left
!byte 2 ; top
!byte 12 ; width
!word OptionsDialog ; callback
!word kStringOptions
kViewPlay
!byte ID_PLAY ; view ID
!byte 66 ; left
!byte 6 ; top
!byte 13 ; width
!word LaunchInterpreterWithNewGame ; callback
!word kStringPlay ; caption
kViewResume
!byte ID_PLAY ; view ID
!byte 66 ; left
!byte 6 ; top
!byte 13 ; width
!word ResumeDialog ; callback
!word kStringResume ; caption
kViewBoxArt
!byte ID_BOXART ; view ID
!byte 66 ; left
!byte 8 ; top
!byte 13 ; width
!word DisplayArtwork ; callback
!word kStringBoxArt ; caption
kViewHints
!byte ID_HINTS ; view ID
!byte 66 ; left
!byte 10 ; top
!byte 13 ; width
!word LaunchInterpreterWithHints ; callback
!word kStringHints ; caption
kViewVersions
!byte ID_VERSIONS ; view ID
!byte 66 ; left
!byte 12 ; top
!byte 13 ; width
!word VersionsDialog ; callback
!word kStringVersions ; caption
kViewInfo
!byte ID_INFO ; view ID
!byte 0 ; style
!byte 0 ; left
!byte 6 ; top
!byte 65 ; visible width
!byte 6 ; visible height
!byte 65 ; width
!byte 6 ; height
kViewDescription
!byte ID_DESCRIPTION ; view ID
!byte 2 ; style
!byte 1 ; left
!byte 15 ; top
!byte 77 ; visible width
!byte 8 ; visible height
!byte 77 ; width
!byte 39 ; height
kViewAbout
!byte ID_ABOUT ; view ID
!byte 79 ; left
!byte 0 ; top
!byte 1 ; width
!word CreditsDialog ; callback
!word kStringAbout
kStringPrevious
!text "< "
!byte $10 ; 'P' inverse
!text "revious",0
kStringNext
!byte $0E ; 'N' inverse
!text "ext game >",0
kStringCatalog
!byte $0A ; 'J' inverse
!text "ump to",0
kStringOptions
!byte $13 ; 'S' inverse
!text "ettings",0
kStringPlay
!byte 144
!text "lay "
!byte $67 ; 'g' inverse
!text "ame",0
kStringResume
!byte 146
!text "esume "
!byte $67 ; 'g' inverse
!text "ame",0
kStringBoxArt
!byte $01 ; 'A' inverse
!text "rtwork",0
kStringHints
!byte $08 ; 'H' inverse
!text "ints",0
kStringVersions
!byte $16 ; 'V' inverse
!text "ersion",0
kStringAbout
!byte $3F, 0 ; '?' inverse