xwords/xwords4/linux/cursesletterask.c
Eric House 598be04bef make curses app more like the rest
Lots of changes adding a games-list view to the app from which you
create new games, open and delete existing ones, etc. There's still
plenty that's unimplemented, but it's already more useful for testing
and development. Which is the point.
2020-01-24 09:05:16 -08:00

218 lines
6.2 KiB
C

/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */
/*
* Copyright 2003 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef PLATFORM_NCURSES
#include "linuxutl.h"
#include "cursesletterask.h"
#include "cursesdlgutil.h"
#define MAX_TILE_BUTTON_ROWS 10
#define MAX_TILE_BUTTON_WIDTH 6
static void
sizeTextsAsButtons( XP_U16 maxLen, XP_U16 nTiles, XP_U16* textsCols,
XP_U16* textsRows, XP_U16* textsOffsets )
{
XP_U16 nCols = maxLen / MAX_TILE_BUTTON_WIDTH;
XP_U16 nRows = (nTiles + nCols - 1) / nCols;
XP_U16 i;
*textsCols = nCols;
*textsRows = nRows;
for ( i = 0; i < nRows; ++i ) {
textsOffsets[i] = i * nCols;
}
XP_DEBUGF( "broke %d letters into %d rows of %d cols",
nTiles, nRows, nCols );
} /* sizeTextsAsButtons */
XP_S16
curses_askLetter( WINDOW* window, XP_UCHAR* query,
const XP_UCHAR** texts, XP_U16 nTiles )
{
XP_S16 result;
WINDOW* confWin;
int x, y, rows, row, nLines, i;
short newSelButton = 0;
short curSelButton = 1; /* force draw by being different */
short maxWidth;
short numCtlButtons;
const char* ctlButtons[] = { "Ok", "Cancel" };
XP_Bool dismissed = XP_FALSE;
FormatInfo fi;
int len;
XP_U16 textsCols, textsRows;
XP_U16 textsOffsets[MAX_TILE_BUTTON_ROWS];
XP_U16 spacePerCtlButton;
char* textPtrs[MAX_UNIQUE_TILES];
for ( i = 0; i < nTiles; ++i ) {
textPtrs[i] = (char*)&texts[i];
}
getmaxyx( window, y, x );
numCtlButtons = VSIZE(ctlButtons);
maxWidth = x - (PAD*2) - 2; /* 2 for two borders */
measureAskText( query, maxWidth, &fi );
sizeTextsAsButtons( x, nTiles, &textsCols, &textsRows, textsOffsets );
len = XP_MAX( fi.maxLen, textsCols * MAX_TILE_BUTTON_WIDTH );
if ( len < MIN_WIDTH ) {
len = MIN_WIDTH;
}
rows = fi.nLines + textsRows + 1;
XP_DEBUGF( "set maxWidth=%d", maxWidth );
if ( len > x-2 ) {
rows = (len / maxWidth) + 1;
len = maxWidth;
}
nLines = ASK_HEIGHT + rows - 1;
XP_DEBUGF( "newwin( %d, %d, (%d/2) - (%d/2), (%d-%d-2)/2",
nLines, len,//+(PAD*2),
y, nLines, x, len );
XP_ASSERT( y >= nLines );
confWin = newwin( nLines, len,//+(PAD*2),
(y/2) - (nLines/2), (x-len-2)/2 );
keypad( confWin, TRUE );
XP_ASSERT( !!confWin );
wclear( confWin );
box( confWin, '|', '-');
for ( row = 0; row < fi.nLines; ++row ) {
mvwaddnstr( confWin, row+1, PAD,
fi.line[row].substr, fi.line[row].len );
}
spacePerCtlButton = (len+(PAD*2)) / (numCtlButtons + 1);
result = newSelButton;
while ( !dismissed ) {
int ch;
if ( newSelButton != curSelButton ) {
XP_U16 i;
for ( i = 0; i < textsRows; ++i ) {
XP_U16 nInRow = textsCols;
if ( i + 1 == textsRows ) {
nInRow = nTiles % textsCols;
if ( nInRow == 0 ) {
nInRow = textsCols;
}
}
XP_DEBUGF( "printing %d cols, row %d, first char %s",
nInRow, i, textPtrs[textsOffsets[i]] );
drawButtons( confWin, rows + 2 - textsRows + i,
MAX_TILE_BUTTON_WIDTH-1,
nInRow,
newSelButton - textsOffsets[i],
(const char**)&textPtrs[textsOffsets[i]] );
}
drawButtons( confWin, rows+2, spacePerCtlButton,
numCtlButtons,
newSelButton - nTiles, ctlButtons );
curSelButton = newSelButton;
}
ch = wgetch( confWin );
int incr = 0;
switch ( ch ) {
case '\t':
case 'R':
case KEY_RIGHT:
case 525:
incr = 1;
break;
case 'L':
case KEY_LEFT:
case 524:
incr = -1;
break;
case KEY_DOWN:
case 526:
incr = textsCols;
break;
case KEY_UP:
case 523:
incr = -textsCols;
break;
case EOF:
case 4: /* C-d */
case 27: /* ESC */
curSelButton = 0; /* should be the cancel case */
case KEY_B2: /* "center of keypad" */
case '\r':
case '\n':
dismissed = XP_TRUE;
break;
default:
if ( ch >= 'a' && ch <= 'z' ) {
ch += 'A' - 'a';
}
for ( i = 0; i < nTiles; ++i ) {
if ( ch == texts[i][0] ) {
XP_DEBUGF( "picking %c", (char)ch);
newSelButton = i;
result = i;
break;
}
}
}
if ( incr != 0 ) {
newSelButton = curSelButton + incr;
if ( newSelButton < 0 ) {
newSelButton = 0;
} else if ( newSelButton >= numCtlButtons + nTiles ) {
newSelButton = numCtlButtons + nTiles - 1;
}
}
}
delwin( confWin );
/* this leaves a ghost line, but I can't figure out a better way. */
wtouchln( window, (y/2)-(nLines/2), ASK_HEIGHT + rows - 1, 1 );
wrefresh( window );
return result;
} /* curses_askLetter */
#endif /* PLATFORM_NCURSES */