// Five MENU TO — simplified port of Harbour menuto.prg // Compiles via gengo to native binary STATIC aPrompts := {} // @row, col PROMPT text → collects menu items FUNCTION __AtPrompt(nRow, nCol, cPrompt, cMsg) AAdd(aPrompts, {nRow, nCol, cPrompt, cMsg}) SetPos(nRow, nCol) DevOut(cPrompt) RETURN .F. // MENU TO nChoice → displays menu, returns selection FUNCTION __MenuTo(nStart) LOCAL n, nKey, nLen, q, lExit nLen := Len(aPrompts) IF nLen = 0 RETURN 0 ENDIF n := nStart IF n < 1 n := 1 ENDIF IF n > nLen n := nLen ENDIF SetCursor(0) lExit := .F. DO WHILE !lExit // Highlight current item (reverse video) SetPos(aPrompts[n][1], aPrompts[n][2]) DevOut(Chr(27) + "[7m" + aPrompts[n][3] + Chr(27) + "[0m") // Show message if any IF aPrompts[n][4] != NIL .AND. Len(aPrompts[n][4]) > 0 SetPos(MaxRow(), 0) DevOut(PadR(aPrompts[n][4], MaxCol() + 1)) ENDIF // Wait for key nKey := Inkey(0) // Unhighlight current q := n SetPos(aPrompts[q][1], aPrompts[q][2]) DevOut(aPrompts[q][3]) DO CASE CASE nKey = 24 .OR. nKey = 4 // Down or Right n++ IF n > nLen n := 1 ENDIF CASE nKey = 5 .OR. nKey = 19 // Up or Left n-- IF n < 1 n := nLen ENDIF CASE nKey = 1 // Home n := 1 CASE nKey = 6 // End n := nLen CASE nKey = 13 .OR. nKey = 10 // Enter (CR or LF) lExit := .T. CASE nKey = 27 // ESC n := 0 lExit := .T. ENDCASE ENDDO // Clear message line SetPos(MaxRow(), 0) DevOut(Space(MaxCol() + 1)) SetCursor(1) // Clear prompts for next use aPrompts := {} RETURN n // AChoice — array-based menu selection FUNCTION AChoice(nTop, nLeft, nBottom, nRight, aItems) LOCAL n := 1, nKey, nLen, nVisible, nOffset, r, i, lExit nLen := Len(aItems) IF nLen = 0 RETURN 0 ENDIF nVisible := nBottom - nTop + 1 nOffset := 0 lExit := .F. SetCursor(0) DO WHILE !lExit // Draw visible items FOR r := 1 TO nVisible i := nOffset + r SetPos(nTop + r - 1, nLeft) IF i <= nLen IF i = n DevOut(Chr(27) + "[7m" + PadR(aItems[i], nRight - nLeft + 1) + Chr(27) + "[0m") ELSE DevOut(PadR(aItems[i], nRight - nLeft + 1)) ENDIF ELSE DevOut(Space(nRight - nLeft + 1)) ENDIF NEXT nKey := Inkey(0) DO CASE CASE nKey = 24 // Down IF n < nLen n++ IF n > nOffset + nVisible nOffset++ ENDIF ENDIF CASE nKey = 5 // Up IF n > 1 n-- IF n <= nOffset nOffset := n - 1 ENDIF ENDIF CASE nKey = 3 // PgDn n += nVisible IF n > nLen n := nLen ENDIF nOffset := n - nVisible IF nOffset < 0 nOffset := 0 ENDIF CASE nKey = 18 // PgUp n -= nVisible IF n < 1 n := 1 ENDIF nOffset := n - 1 IF nOffset < 0 nOffset := 0 ENDIF CASE nKey = 1 // Home n := 1 nOffset := 0 CASE nKey = 6 // End n := nLen nOffset := nLen - nVisible IF nOffset < 0 nOffset := 0 ENDIF CASE nKey = 13 // Enter lExit := .T. CASE nKey = 27 // ESC n := 0 lExit := .T. ENDCASE ENDDO SetCursor(1) RETURN n