;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