;license:MIT ;(c) 2018 by 4am ; ; User interface - views and paint routines for main screen ; ; Public functions ; - PaintMain ; - RepaintMainIfDirty ; ; Public variables ; - gMainScreenPaintDirty ; - gViewInUse ; ; 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 gMainScreenPaintDirty !byte 0 ; 0=false, 1=true gViewInUse !byte 0,1,1,1,1,0,0,0,0,0,0,0,0,0,0 ;------------------------------------------------------------------------------ ; 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 ;------------------------------------------------------------------------------ !zone { PaintMain jsr HardResetWeeGUI stz gViewInUse+ID_BOXART stz gViewInUse+ID_HINTS stz gViewInUse+ID_VERSIONS ldx #1 ; flag - clear screen before painting stx gMainScreenPaintDirty !byte $2C 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 '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 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 ;------------------------------------------------------------------------------ !zone { CreateOrDestroyButton +PARAMS_ON_STACK 5 ldy #1 lda (PARAM),y sta .viewID +LDPARAM 2 +STAY .viewConfigurationRecord +LDPARAM 4 +STAY .optionsStoreKey jsr okvs_get !word gOptionsStore .optionsStoreKey !word $FDFD ; SMC .viewID=*+1 ldx #$FD ; SMC (X = WeeGUI view ID) jsr okvs_as_boolean beq .destroy lda gViewInUse,x ; create button if it doesn't exist bne .done ; oh it does exist, so we're done lda #1 sta gViewInUse,x jsr CreateButton .viewConfigurationRecord !word $FDFD ; SMC bra .done .destroy lda gViewInUse,x ; destroy button if it exists beq .done ; 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 jsr WeeGUI .done rts } !zone { PaintDescriptionView ldx #WGSelectView lda #ID_DESCRIPTION jsr WeeGUI +LDAY addrDescription ldx #kDescriptionPaintWidth jsr MultiPrint lda SAVE cmp #10 ; minimum content height bcs + lda #10 + 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 !byte $2C ; execution falls through here MultiPrint stz SAVE ; VTAB, but 0-indexed stx .printLineLength+1 +STAY SRC .printLoop 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 .printLineLength adc #$FD ; SMC sta SRC bcc + inc SRC+1 + inc SAVE lda (SRC) bne .printLoop rts } ;------------------------------------------------------------------------------ kViewPrevious !byte ID_PREVIOUS ; view ID !byte 1 ; left !byte 2 ; top !byte 13 ; width !word callback_previous ; callback !word kStringPrevious ; caption kStringPrevious !text "< " !byte $10 ; 'P' inverse !text "revious",0 kViewNext !byte ID_NEXT ; view ID !byte 66 ; left !byte 2 ; top !byte 13 ; width !word callback_next ; callback !word kStringNext ; caption kStringNext !byte $0E ; 'N' inverse !text "ext game >",0 kViewOptions !byte ID_OPTIONS ; view ID !byte 34 ; left !byte 2 ; top !byte 12 ; width !word callback_options ; callback !word kStringOptions kStringOptions !byte $13 ; 'S' inverse !text "ettings",0 kViewPlay !byte ID_PLAY ; view ID !byte 66 ; left !byte 6 ; top !byte 13 ; width !word callback_play ; callback !word kStringPlay ; caption kStringPlay !byte 144 !text "lay " !byte $67 ; 'g' inverse !text "ame",0 kViewResume !byte ID_PLAY ; view ID !byte 66 ; left !byte 6 ; top !byte 13 ; width !word callback_resume ; callback !word kStringResume ; caption kStringResume !byte 146 !text "esume " !byte $67 ; 'g' inverse !text "ame",0 kViewBoxArt !byte ID_BOXART ; view ID !byte 66 ; left !byte 8 ; top !byte 13 ; width !word callback_boxart ; callback !word kStringBoxArt ; caption kStringBoxArt !byte $01 ; 'A' inverse !text "rtwork",0 kViewHints !byte ID_HINTS ; view ID !byte 66 ; left !byte 10 ; top !byte 13 ; width !word callback_hints ; callback !word kStringHints ; caption kStringHints !byte $08 ; 'H' inverse !text "ints",0 kViewVersions !byte ID_VERSIONS ; view ID !byte 66 ; left !byte 12 ; top !byte 13 ; width !word callback_versions ; callback !word kStringVersions ; caption kStringVersions !byte $16 ; 'V' inverse !text "ersion",0 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