/*
** Command & Conquer Generals(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see .
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: GadgetListBox.cpp ////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: ListBox.cpp
//
// Created: Dean Iverson, March 1998
// Colin Day, June 2001
//
// Desc: ListBox GUI control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
#include "Common/AudioEventRTS.h"
#include "Common/Language.h"
#include "Common/Debug.h"
#include "Common/GameAudio.h"
#include "GameClient/DisplayStringManager.h"
#include "GameClient/GameWindow.h"
#include "GameClient/Gadget.h"
#include "GameClient/GameWindowManager.h"
#include "GameClient/GadgetListBox.h"
#include "GameClient/GadgetPushButton.h"
#include "GameClient/GadgetSlider.h"
#include "GameClient/GameWindowGlobal.h"
#include "GameClient/Keyboard.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// DEFINES ////////////////////////////////////////////////////////////////////
// Sets up the user's OS set doubleclick time so if they don't like it... they can
// change it in their OS.
static UnsignedInt doubleClickTime = GetDoubleClickTime();
// PRIVATE TYPES //////////////////////////////////////////////////////////////
typedef struct _AddMessageStruct
{
Int row; // The row to add the data to
Int column; // The column to add the data to
const void *data; // void pointer, can be either an DisplayString or an Image
Int type; // Can either be set to LISTBOX_TEXT or LISTBOX_IMAGE
Bool overwrite; // Do we overwrite existing data?
Int width; // set to -1 if we want the defaults
Int height; // set to -1 if we want the defaults
} AddMessageStruct;
typedef struct _TextAndColor
{
UnicodeString string; // Holds a unicode String
Color color; // holds a text's color
} TextAndColor;
///////////////////////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
static void doAudioFeedback(GameWindow *window)
{
if (!window)
return;
ListboxData *lData = (ListboxData *)window->winGetUserData();
if (!lData)
return;
if (lData->audioFeedback)
{
AudioEventRTS buttonClick("GUIComboBoxClick");
if( TheAudio )
{
TheAudio->addAudioEvent( &buttonClick );
} // end if
}
}
static Int getListboxEntryBasedOnCoord(GameWindow *window, Int x, Int y, Int &row, Int &column)
{
Int pos;
Int winx, winy, i;
WinInstanceData *instData = window->winGetInstanceData();
ListboxData *list = (ListboxData *)window->winGetUserData();
window->winGetScreenPosition( &winx, &winy );
// Adjust for title if present
if( instData->getTextLength() )
winy += TheWindowManager->winFontHeight( instData->getFont() ) + 1;
pos = -2;
for( i=0; ; i++ )
{
if( i > 0 )
if( list->listData[ i - 1 ].listHeight >
(list->displayPos + list->displayHeight ) )
{
pos = -1;
break;
}
if( i == list->endPos )
{
pos = -1;
break;
}
if( list->listData[i].listHeight > (y - winy + list->displayPos) )
break;
}
column = -1;
if( pos == -2 )
{
pos = i;
Int total = 0;
for( i = 0; i < list->columns ;i++)
{
total += list->columnWidth[i];
if(x - winx < total)
{
column = i;
break;
}
}
}
row = pos;
return pos;
}
Int GadgetListBoxGetEntryBasedOnXY( GameWindow *listbox, Int x, Int y, Int &row, Int &column)
{
return getListboxEntryBasedOnCoord( listbox, x, y, row, column );
}
// getListboxTopEntry =========================================================
//=============================================================================
static Int getListboxTopEntry( ListboxData *list )
{
Int entry;
// determin which entry is at the top of the display area
for( entry=0; ; entry++ )
{
if( list->listData[entry].listHeight > list->displayPos )
return entry;
if( entry >= list->endPos )
return 0;
}
return 0;
}
// getListboxTopEntry =========================================================
//=============================================================================
static Int getListboxBottomEntry( ListboxData *list )
{
Int entry;
// determin which entry is at the top of the display area
for( entry=list->endPos - 1; ; entry-- )
{
if( list->listData[entry].listHeight == list->displayPos + list->displayHeight )
return entry;
if( list->listData[entry].listHeight < list->displayPos + list->displayHeight && entry != list->endPos - 1)
return entry + 1;
if( list->listData[entry].listHeight < list->displayPos + list->displayHeight)
return entry;
if( entry < 0 )
return 0;
}
return 0;
}
// removeSelection ============================================================
/** Remove Selection from a multiple selection list */
//=============================================================================
static void removeSelection( ListboxData *list, Int i )
{
memcpy( &list->selections[i], &list->selections[(i+1)],
((list->listLength - i) * sizeof(Int)) );
// put -1 at end of list just for safety
list->selections[(list->listLength - 1)] = -1;
}
// adjustDisplay ==============================================================
/** Update Display List information inlcuding scrollbar */
//=============================================================================
static void adjustDisplay( GameWindow *window, Int adjustment,
Bool updateSlider )
{
Int entry;
SliderData *sData;
ListboxData *list = (ListboxData *)window->winGetUserData();
// determin which entry is at the top of the display area
entry = getListboxTopEntry( list ) + adjustment;
if( entry < 0 )
entry = 0;
else if( entry >= list->endPos )
entry = list->endPos - 1;
if( updateSlider )
{
if( entry > 0 )
list->displayPos = list->listData[(entry - 1)].listHeight + 1;
else
list->displayPos = 0;
}
if( list->slider != NULL )
{
ICoord2D sliderSize, sliderChildSize;
GameWindow *child;
sData = (SliderData *)list->slider->winGetUserData();
list->slider->winGetSize( &sliderSize.x, &sliderSize.y );
// Take into account that there is a line-drawn outline surrounding listbox
sData->maxVal = list->totalHeight - ( list->displayHeight - TOTAL_OUTLINE_HEIGHT ) + 1;
if( sData->maxVal < 0 )
{
sData->maxVal = 0;
}
child = list->slider->winGetChild();
child->winGetSize( &sliderChildSize.x, &sliderChildSize.y );
sData->numTicks = (float)((sliderSize.y - sliderChildSize.y) / (float)sData->maxVal);
if( updateSlider )
TheWindowManager->winSendSystemMsg( list->slider,
GSM_SET_SLIDER,
(sData->maxVal - list->displayPos),
0 );
}
} // end adjustDisplay
// computeTotalHeight =========================================================
/** Compute Total Height and fill in listHeight values */
//=============================================================================
static void computeTotalHeight( GameWindow *window )
{
Int i, height = 0;
Int tempHeight;
ListboxData *list = (ListboxData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
for( i=0; iendPos; i++ )
{
if(!list->listData[i].cell)
continue;
tempHeight = 0;
for (Int j = 0; j < list->columns; j++)
{
Int cellHeight = 0;
if(list->listData[i].cell[j].cellType == LISTBOX_TEXT)
{
if( BitTest( window->winGetStatus(), WIN_STATUS_ONE_LINE ) == TRUE )
{
cellHeight = TheWindowManager->winFontHeight( instData->getFont() );
}
else
{
DisplayString *displayString = (DisplayString *)list->listData[i].cell[j].data;
if(displayString)
displayString->getSize( NULL, &cellHeight );
}//else
}//if
else if(list->listData[i].cell[j].cellType == LISTBOX_IMAGE)
{
if(list->listData[i].cell[j].height > 0)
cellHeight = list->listData[i].cell[j].height + 1;
else
cellHeight = TheWindowManager->winFontHeight( instData->getFont() );
}
if(cellHeight > tempHeight)
tempHeight = cellHeight;
}//for
list->listData[i].height = tempHeight;
height += (list->listData[i].height + 1);
list->listData[i].listHeight = height;
}
list->totalHeight = height;
adjustDisplay( window, 0, TRUE );
}
// addImageEntry ==============================================================
/** Add Images to position and column. Row and Column are both based from starting
Position 0 */
//=============================================================================
static Int addImageEntry( const Image *image, Color color, Int row, Int column, GameWindow *window, Bool overwrite, Int width, Int height )
{
// WinInstanceData *instData = window->winGetInstanceData();
ListboxData *list = (ListboxData *)window->winGetUserData();
if( column >= list->columns || row >= list->listLength )
{
DEBUG_ASSERTCRASH(false, ("Tried to add Image to Listbox at invalid position"));
return -1;
}
// If we want to just add an entry to the bottom, set the defaults
if (row == -1)
{
row = list->insertPos;
list->insertPos++;
list->endPos++;
}
if( column == -1 )
column = 0;
ListEntryRow *listRow = &list->listData[row];
// Check and see if we have allocated cells for that row yet, if not, allocate them
if(!listRow->cell)
{
listRow->cell = NEW ListEntryCell[list->columns];
memset(listRow->cell,0,list->columns * sizeof(ListEntryCell));
}
// if we're copying over strings, then lets first deallocate them.
if(listRow->cell[column].cellType == LISTBOX_TEXT)
{
TheDisplayStringManager->freeDisplayString((DisplayString *)listRow->cell[column].data);
}
//add Image to selected row/cell
listRow->cell[column].cellType = LISTBOX_IMAGE;
listRow->cell[column].data = (void *)image;
listRow->cell[column].color = color;
listRow->cell[column].height = height;
listRow->cell[column].width = width;
computeTotalHeight( window );
return (row);
}// static Int addImageEntry( Image image, Int column, GameWindow *window)
// startingRow will get moved to startingRow+1, etc. This assumes there is space!!!!!
static Int moveRowsDown(ListboxData *list, Int startingRow)
{
//
// copy the cells down
//
Int copyLen = (list->endPos - startingRow) * sizeof(ListEntryRow);
char *buf = NEW char[copyLen];
memcpy(buf, list->listData + startingRow, copyLen);
memcpy(list->listData + startingRow + 1, buf, copyLen );
delete buf;
list->endPos ++;
list->insertPos = list->endPos;
//
// remove the display or links to images after the shift
//
list->listData[startingRow].cell = NULL;
list->listData[startingRow].height = 0;
list->listData[startingRow].listHeight = 0;
if( list->multiSelect )
{
Int i = 0;
while( list->selections[i] >= 0 )
{
if( startingRow <= list->selections[i] )
list->selections[i]++;
i++;
}
}
else
{
if( list->selectPos >= startingRow )
list->selectPos++;
}
/*
if( list->displayPos > 0 )
adjustDisplay( window, (-1 * mData1), TRUE );
computeTotalHeight( window );
*/
return 1;
}
// addEntry ===================================================================
/** Add and process one string at insertPos */
//=============================================================================
static Int addEntry( UnicodeString *string, Int color, Int row, Int column, GameWindow *window, Bool overwrite )
{
// WinInstanceData *instData = window->winGetInstanceData();
ListboxData *list = (ListboxData *)window->winGetUserData();
Int width;
DisplayString *displayString;
// make sure our params are good
if( column >= list->columns || row >= list->listLength )
{
DEBUG_ASSERTCRASH(false, ("Tried to add text to Listbox at invalid position"));
return -1;
}
// If we want to just add an entry to the bottom, set the defaults
if (row == -1)
{
row = list->insertPos;
list->insertPos++;
list->endPos++;
}
if( column == -1 )
column = 0;
width = list->columnWidth[column] - TEXT_WIDTH_OFFSET;
Int rowsAdded = 0;
ListEntryRow *listRow = &list->listData[row];
// Here I've decided to just overright what's in the row, if that's not what we want, change it here
// Check and see if we have allocated cells for that row yet, if not, allocate them
if(!listRow->cell)
{
listRow->cell = NEW ListEntryCell[list->columns];
memset(listRow->cell,0,list->columns * sizeof(ListEntryCell));
rowsAdded = 1;
}
else if (!overwrite)
{
// Shove things down
moveRowsDown(list, row);
listRow->cell = NEW ListEntryCell[list->columns];
memset(listRow->cell,0,list->columns * sizeof(ListEntryCell));
rowsAdded = 1;
}
//add Image to selected row/cell
listRow->cell[column].cellType = LISTBOX_TEXT;
// assign the color to the list data element
listRow->cell[column].color = color;
// copy text
if( !listRow->cell[column].data )
listRow->cell[column].data = (void *) TheDisplayStringManager->newDisplayString();
displayString = (DisplayString *) listRow->cell[column].data;
if ( BitTest( window->winGetStatus(), WIN_STATUS_ONE_LINE ) == FALSE )
displayString->setWordWrap( width );
displayString->setText( *string );
/** @todo we need for formalize this, but for now just set the font
of this listbox entry to the font of the window */
displayString->setFont( window->winGetFont() );
if (overwrite)
{
Int oldRowHeight = listRow->height;
Int oldTotalHeight = listRow->listHeight;
Int rowHeight;
Int totalHeight;
if (!oldTotalHeight && row)
{
oldTotalHeight = list->listData[row-1].listHeight;
}
displayString->getSize( NULL, &rowHeight );
if (rowHeight > oldRowHeight)
{
totalHeight = oldTotalHeight + (rowHeight - oldRowHeight);
listRow->height = rowHeight;
listRow->listHeight = totalHeight + rowsAdded;
list->totalHeight += (rowHeight - oldRowHeight) + rowsAdded;
adjustDisplay( window, 0, TRUE );
}
}
else
{
computeTotalHeight( window );
}
return (row);
} // end addEntry
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// GadgetListBoxInput =========================================================
/** Handle input for list box */
//=============================================================================
WindowMsgHandledType GadgetListBoxInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
ListboxData *list = (ListboxData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
switch (msg)
{
// ------------------------------------------------------------------------
case GWM_CHAR:
{
switch (mData1)
{
// --------------------------------------------------------------------
case KEY_ENTER:
case KEY_SPACE:
{
if( BitTest( mData2, KEY_STATE_UP ) )
{
doAudioFeedback(window);
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_DOUBLE_CLICKED,
(WindowMsgData)window,
list->selectPos );
} // end if
break;
} // end enter or space
// --------------------------------------------------------------------
case KEY_DOWN:
{
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
if( list->selectPos == -1 )
{
list->selectPos = 0;
adjustDisplay( window, 0, TRUE );
}
else if( list->selectPos < list->endPos - 1 )
{
list->selectPos++;
while (1)
{
Int cellBottom = list->listData[list->selectPos].listHeight;
Int cellTop = cellBottom - list->listData[list->selectPos].height;
Int displayTop = list->displayPos;
Int displayBottom = list->displayPos + list->displayHeight - 1; // account for the border
if ( cellTop < displayTop )
{
adjustDisplay(window, -1, TRUE );
}
else if ( cellBottom < displayBottom )
{
adjustDisplay(window, 0, TRUE );
break;
}
else
{
adjustDisplay(window, 1, TRUE );
}
}
}
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_SELECTED,
(WindowMsgData)window,
list->selectPos );
} // end if
break;
} // end key down
// --------------------------------------------------------------------
case KEY_UP:
{
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
if( list->selectPos == -1 )
{
list->selectPos = 0;
adjustDisplay( window, 0, TRUE );
}
else if( list->selectPos > 0 )
{
list->selectPos--;
while (1)
{
if( list->listData[list->selectPos].listHeight - list->listData[list->selectPos].height < list->displayPos )
{
list->displayPos = list->listData[list->selectPos].listHeight +1;
adjustDisplay( window, -1, TRUE );
}
else if( list->listData[list->selectPos].listHeight > list->displayPos + list->displayHeight)
{
list->displayPos = list->listData[list->selectPos].listHeight - list->displayHeight;
adjustDisplay(window, 1, TRUE);
}
else
{
adjustDisplay(window, 0, TRUE);
break;
}
}
}
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_SELECTED,
(WindowMsgData)window,
list->selectPos );
}
break;
} // end key up
// --------------------------------------------------------------------
case KEY_RIGHT:
case KEY_TAB:
if( BitTest( mData2, KEY_STATE_DOWN ) )
TheWindowManager->winNextTab(window);
break;
// --------------------------------------------------------------------
case KEY_LEFT:
if( BitTest( mData2, KEY_STATE_DOWN ) )
TheWindowManager->winPrevTab(window);
break;
// --------------------------------------------------------------------
default:
{
Bool foundIt = false;
if( BitTest( mData2, KEY_STATE_DOWN ) )
{
// set the position to start looking for the line of text with this character
Int position = list->selectPos;
// only search the max number of times so that we're not looping over and over
for(Int i = 0; i < list->endPos; ++i)
{
// start at the next position
++position;
// if we've reached the end of the list, start at the beginning
if( position >= list->endPos)
position = 0;
ListEntryCell *cell = NULL;
// go through the columns until we find a column with text
for(Int j = 0; j < list->columns; ++j)
{
cell = &list->listData[position].cell[j];
if(cell && cell->cellType == LISTBOX_TEXT && cell->data)
{
break;
}
}
if(!cell || cell->cellType != LISTBOX_TEXT)
continue;
DisplayString *dString = (DisplayString *)cell->data;
if(!dString)
continue;
for(j = 0; j < TheKeyboard->MAX_KEY_STATES; ++j)
{
if(dString->getText().getCharAt(0) == TheKeyboard->getPrintableKey(mData1, j))
{
list->selectPos = position;
Int prevPos = getListboxTopEntry(list);
//list->displayPos = list->listData[position].listHeight - list->displayHeight;
adjustDisplay(window, position - prevPos, TRUE);
foundIt = TRUE;
break;
}
}
if(foundIt)
{
doAudioFeedback(window);
break;
}
}
}
if (!foundIt)
return MSG_IGNORED;
}
} // end switch( mData1 )
break;
} // end case char
// ------------------------------------------------------------------------
case GWM_WHEEL_DOWN:
{
if( list->endPos <= 0)
break;
if (list->listData[list->endPos - 1].listHeight > list->displayHeight + list->displayPos)
adjustDisplay( window, 1, TRUE );
break;
} // end wheel down
// ------------------------------------------------------------------------
case GWM_WHEEL_UP:
{
if( list->endPos <= 0)
break;
adjustDisplay( window, -1, TRUE );
break;
} // end wheel up
// ------------------------------------------------------------------------
case GWM_LEFT_UP:
{
TheWindowManager->winSetFocus( window );
// Int mousex = mData1 & 0xFFFF;
Int mousey = mData1 >> 16;
Int x, y, i;
Int oldPos = list->selectPos;
window->winGetScreenPosition( &x, &y );
// Adjust for title if present
if( instData->getTextLength() )
y += TheWindowManager->winFontHeight( instData->getFont() ) + 1;
list->selectPos = -2;
for( i=0; ; i++ )
{
if( i > 0 )
if( list->listData[ i - 1 ].listHeight >
(list->displayPos + list->displayHeight) )
{
list->selectPos = -1;
break;
}
if( i == list->endPos )
{
list->selectPos = -1;
break;
}
if( list->listData[i].listHeight > (mousey - y + list->displayPos) )
break;
}
//Bool dblClicked = FALSE;
if( list->doubleClickTime + doubleClickTime > timeGetTime() &&
(i == oldPos || (oldPos == -1 && ( i>=0 && iendPos ) )) )
{
int temp;
list->doubleClickTime = 0;
if( oldPos == -1 )
temp = i;
else
temp = oldPos;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_DOUBLE_CLICKED,
(WindowMsgData)window,
temp );
//break;
}
if( (i == oldPos) && (list->forceSelect == FALSE) )
{
list->selectPos = -1;
}
if( (list->selectPos == -2) && (i < list->endPos) )
{
list->selectPos = i;
}
if( (list->selectPos < 0) && (list->forceSelect) )
{
list->selectPos = oldPos;
}
list->doubleClickTime = timeGetTime();
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_SELECTED,
(WindowMsgData)window,
list->selectPos );
break;
} // end left click, left up
// ------------------------------------------------------------------------
case GWM_RIGHT_DOWN:
doAudioFeedback(window);
break; // if we're in game, we want to eat this message because we're right clicking on a listbox
case GWM_RIGHT_UP:
{
TheWindowManager->winSetFocus( window );
Int pos;
Int mousex = mData1 & 0xFFFF;
Int mousey = mData1 >> 16;
Int x, y, i;
RightClickStruct rc;
window->winGetScreenPosition( &x, &y );
// Adjust for title if present
if( instData->getTextLength() )
y += TheWindowManager->winFontHeight( instData->getFont() ) + 1;
pos = -2;
for( i=0; ; i++ )
{
if( i > 0 )
if( list->listData[ i - 1 ].listHeight >
(list->displayPos + list->displayHeight ) )
{
pos = -1;
break;
}
if( i == list->endPos )
{
pos = -1;
break;
}
if( list->listData[i].listHeight > (mousey - y + list->displayPos) )
break;
}
if( pos == -2 )
pos = i;
rc.pos = pos;
rc.mouseX = mousex;
rc.mouseY = mousey;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_RIGHT_CLICKED,
(WindowMsgData)window,
(WindowMsgData)&rc );
break;
} // end right up, right click
// ------------------------------------------------------------------------
case GWM_MOUSE_ENTERING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_ENTERING,
(WindowMsgData)window,
0 );
//TheWindowManager->winSetFocus( window );
} // end if
break;
} // end mouse entering
// ------------------------------------------------------------------------
case GWM_MOUSE_LEAVING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ))
{
BitClear( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_LEAVING,
(WindowMsgData)window,
0 );
} // end if
break;
} // end mouse leaving
// ------------------------------------------------------------------------
case GWM_LEFT_DRAG:
if (BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_LEFT_DRAG,
(WindowMsgData)window,
0 );
break;
// ------------------------------------------------------------------------
case GWM_LEFT_DOWN:
doAudioFeedback(window);
// we want to eat the down... so we may receive the up.
return MSG_HANDLED;
//-------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch msg
return MSG_HANDLED;
} // end GadgetListBoxInput
// GadgetListBoxMultiInput ====================================================
/** Handle input for multiple selection list box */
//=============================================================================
WindowMsgHandledType GadgetListBoxMultiInput( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
ListboxData *list = (ListboxData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_CHAR:
{
switch( mData1 )
{
// --------------------------------------------------------------------
case KEY_TAB:
if( BitTest( mData2, KEY_STATE_DOWN ) )
window->winNextTab();
break;
// --------------------------------------------------------------------
default:
return MSG_IGNORED;
}
break;
} // end char
// ------------------------------------------------------------------------
case GWM_LEFT_UP:
//case GWM_LEFT_CLICK:
{
TheWindowManager->winSetFocus( window );
// Int *selections = list->selections;
Int selectPos = -2;
// Int mousex = mData1 & 0xFFFF;
Int mousey = mData1 >> 16;
Int x, y, i;
Bool removed = FALSE;
window->winGetScreenPosition( &x, &y );
// Adjust for title if present
if( instData->getTextLength() )
y += TheWindowManager->winFontHeight( instData->getFont() ) + 1;
for( i = 0; ; i++ )
{
if( i > 0 )
if( list->listData[ i - 1 ].listHeight >
(list->displayPos + list->displayHeight ) )
{
selectPos = -1;
break;
}
if( i == list->endPos )
{
selectPos = -1;
break;
}
if( list->listData[i].listHeight > (mousey - y + list->displayPos) )
break;
}
if( selectPos == -2 )
selectPos = i;
i = 0;
while( list->selections[i] >= 0 )
{
if( list->selections[i] == selectPos )
{
removeSelection( list, i );
removed = TRUE;
break;
}
i++;
}
if( removed == FALSE )
{
list->selections[ i] = selectPos;
list->selections[ i + 1 ] = -1;
}
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_SELECTED,
(WindowMsgData)window,
selectPos );
break;
} // end left up, left click
// ------------------------------------------------------------------------
case GWM_RIGHT_UP:
{
/*
Int selectPos = -2;
// Int mousex = mData1 & 0xFFFF;
Int mousey = mData1 >> 16;
Int x, y, i;
window->winGetScreenPosition( &x, &y );
// Adjust for title if present
if( instData->getTextLength() )
y += TheWindowManager->winFontHeight( instData->getFont() ) + 1;
for( i = 0; ; i++ )
{
if( i > 0 )
if( list->listData[ i - 1 ].listHeight >
(list->displayPos + list->displayHeight ) )
{
selectPos = -1;
break;
}
if( i == list->endPos )
{
selectPos = -1;
break;
}
if( list->listData[i].listHeight > (mousey - y + list->displayPos) )
break;
}
if( selectPos == -2 )
selectPos = i;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_RIGHT_CLICKED,
(WindowMsgData)window,
selectPos );*/
TheWindowManager->winSetFocus( window );
Int pos;
Int mousex = mData1 & 0xFFFF;
Int mousey = mData1 >> 16;
Int x, y, i;
RightClickStruct rc;
window->winGetScreenPosition( &x, &y );
// Adjust for title if present
if( instData->getTextLength() )
y += TheWindowManager->winFontHeight( instData->getFont() ) + 1;
pos = -2;
for( i=0; ; i++ )
{
if( i > 0 )
if( list->listData[ i - 1 ].listHeight >
(list->displayPos + list->displayHeight ) )
{
pos = -1;
break;
}
if( i == list->endPos )
{
pos = -1;
break;
}
if( list->listData[i].listHeight > (mousey - y + list->displayPos) )
break;
}
if( pos == -2 )
pos = i;
rc.pos = pos;
rc.mouseX = mousex;
rc.mouseY = mousey;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_RIGHT_CLICKED,
(WindowMsgData)window,
(WindowMsgData)&rc );
break;
} // end right up, right click
// ------------------------------------------------------------------------
case GWM_WHEEL_DOWN:
// Simulate the down button if it exists
if( list->downButton )
{
if( list->displayPos + list->displayHeight <= list->totalHeight )
adjustDisplay( window, 1, TRUE );
}
break;
// ------------------------------------------------------------------------
case GWM_WHEEL_UP:
// Simulate the up button if it exists
if( list->upButton )
{
if( list->displayPos > 0 )
adjustDisplay( window, -1, TRUE );
}
break;
// ------------------------------------------------------------------------
case GWM_MOUSE_ENTERING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
{
BitSet( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_ENTERING,
(WindowMsgData)window,
0 );
//TheWindowManager->winSetFocus( window );
} // end if
break;
} // end mouse entering
// ------------------------------------------------------------------------
case GWM_MOUSE_LEAVING:
{
if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ))
{
BitClear( instData->m_state, WIN_STATE_HILITED );
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GBM_MOUSE_LEAVING,
(WindowMsgData)window,
0 );
} // end if
break;
} // end mouse leaving
// ------------------------------------------------------------------------
case GWM_LEFT_DRAG:
if (BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_LEFT_DRAG,
(WindowMsgData)window,
0 );
break;
// ------------------------------------------------------------------------
case GWM_LEFT_DOWN:
doAudioFeedback(window);
// we want to eat the down... so we may receive the up.
return MSG_HANDLED;
// ------------------------------------------------------------------------
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetListBoxMultiInput
// GadgetListBoxSystem ========================================================
/** Handle system messages for list box */
//=============================================================================
WindowMsgHandledType GadgetListBoxSystem( GameWindow *window, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
ListboxData *list = (ListboxData *)window->winGetUserData();
WinInstanceData *instData = window->winGetInstanceData();
ICoord2D *pos;
switch( msg )
{
// ------------------------------------------------------------------------
case GGM_SET_LABEL:
{
instData->setText(*(UnicodeString*)mData1);
break;
} // end set lavel
// ------------------------------------------------------------------------
case GLM_GET_TEXT:
{
pos = (ICoord2D *)mData1;
TextAndColor *tAndC = (TextAndColor *)mData2;
if(pos->x >= list->columns || pos->y >= list->listLength ||
list->listData[pos->y].cell[pos->x].cellType != LISTBOX_TEXT)
{
tAndC->string = UnicodeString.TheEmptyString;
tAndC->color = 0;
}
else
{
tAndC->string = ((DisplayString *)list->listData[ pos->y ].cell[pos->x].data)->getText();
tAndC->color = list->listData[ pos->y ].cell[pos->x].color;
}
break;
}
// ------------------------------------------------------------------------
case GBM_SELECTED:
{
// See if the up button was selected
if( (GameWindow *)mData1 == list->upButton )
{
if( list->displayPos > 0 )
adjustDisplay( window, -1, TRUE );
}
else if( (GameWindow *)mData1 == list->downButton )
{
if( list->displayPos + list->displayHeight <= list->totalHeight )
adjustDisplay( window, 1, TRUE );
}
break;
} // end selected
// ------------------------------------------------------------------------
case GGM_LEFT_DRAG:
{
if( (GameWindow *)mData1 == list->upButton )
{
if( list->displayPos > 0 )
adjustDisplay( window, -1, TRUE );
}
else if( (GameWindow *)mData1 == list->downButton )
{
if( list->displayPos + list->displayHeight <= list->totalHeight )
adjustDisplay( window, 1, TRUE );
}
break;
} // end left drag
// ------------------------------------------------------------------------
case GLM_DEL_ALL:
{
//
// Reset the listbox by freeing all the display string stuff and setting
// everything else to zero
//
// Loop through and destroy any display strings we've allocated that aren't used
for( Int i = 0; i < list->listLength; i++ )
{
// Loop though
ListEntryCell *cells = list->listData[i].cell;
for (int j = list->columns - 1; j >=0; j-- )
{
if(!cells)
break;
if( cells[j].cellType == LISTBOX_TEXT )
{
if ( cells[j].data )
{
TheDisplayStringManager->freeDisplayString((DisplayString *) cells[j].data );
}
}
cells[j].userData = NULL;
cells[j].data = NULL;
}
delete(list->listData[i].cell);
list->listData[i].cell = NULL;
}
//zero out the header structure
memset(list->listData,0,list->listLength * sizeof(ListEntryRow));
if( mData1 != GP_DONT_UPDATE )
{
list->displayPos = 0;
}
if( list->multiSelect )
memset( list->selections, -1, list->listLength * sizeof( Int ) );
else
list->selectPos = -1;
list->insertPos = 0;
list->endPos = 0;
list->totalHeight = 0;
adjustDisplay( window, 0, TRUE );
break;
} // end delete all
// ------------------------------------------------------------------------
case GLM_DEL_ENTRY:
{
Int i;
if( list->endPos <= (Int)mData1 )
break;
ListEntryCell *cells = list->listData[mData1].cell;
if(cells)
for( i = 0; i <= list->columns; i ++ )
{
if( cells[i].cellType == LISTBOX_TEXT && cells[i].data )
TheDisplayStringManager->freeDisplayString((DisplayString *) cells[i].data );
cells[i].data = NULL;
cells[i].userData = NULL;
}
delete [](list->listData[mData1].cell);
memcpy( &list->listData[mData1], &list->listData[(mData1+1)],
(list->endPos - mData1 - 1) * sizeof(ListEntryRow) );
list->endPos--;
list->insertPos = list->endPos;
if( list->multiSelect )
{
i = 0;
while( list->selections[i] >= 0 )
{
if( (Int)mData1 < list->selections[i] )
list->selections[i]--;
else if ( (Int)mData1 == list->selections[i] )
{
removeSelection( list, i );
i--; // compensate for lost entry
}
i++;
}
}
else
{
if( (Int)mData1 < list->selectPos )
list->selectPos--;
else if ( (Int)mData1 == list->selectPos )
list->selectPos = -1;
}
computeTotalHeight( window );
break;
} // end delete entry
// ------------------------------------------------------------------------
case GLM_ADD_ENTRY:
{
Bool success = TRUE;
Int addedIndex = -1;
AddMessageStruct *addInfo = (AddMessageStruct*)mData1;
if (addInfo->row >= list->insertPos)
addInfo->row = -1;
Int row = addInfo->row;
// Special case, we're just appending and we've reached the end.
if( addInfo->row == -1 && list->insertPos == list->listLength )
{
row = list->insertPos;
// Check to see if we've filled our buffer and need to scroll the window
if( list->insertPos == list->listLength )
{
if( list->autoPurge )
TheWindowManager->winSendSystemMsg( window, GLM_SCROLL_BUFFER, 1, 0 );
else
success = FALSE;
}
}
else if (addInfo->row != -1 && !addInfo->overwrite && list->insertPos == list->listLength)
{
// We're inserting into the middle with no space - see if we can scroll the window
if( list->autoPurge )
TheWindowManager->winSendSystemMsg( window, GLM_SCROLL_BUFFER, 1, 0 );
else
success = FALSE;
}
if(success)
{
if( addInfo->type == LISTBOX_TEXT )
{
addedIndex = addEntry( (UnicodeString *)addInfo->data, mData2, addInfo->row, addInfo->column, window, addInfo->overwrite );
}
else if ( addInfo->type == LISTBOX_IMAGE )
{
addedIndex = addImageEntry( (const Image *)addInfo->data, mData2, addInfo->row, addInfo->column, window, addInfo->overwrite,addInfo->width, addInfo->height );
}
else
success = FALSE;
}
if( success )
{
if( list->autoScroll )
{
while( TRUE )
{
// If off bottom of screen, scroll and try again.
// we use -1 because insertPos was increased in addEntry
if( row == -1 )
{
if( list->listData[(list->insertPos - 1)].listHeight >=
(list->displayPos + list->displayHeight) )
adjustDisplay( window, 1, TRUE );
else
break;
}
else
{
if( list->listData[( row )].listHeight >=
(list->displayPos + list->displayHeight) )
adjustDisplay( window, 1, TRUE );
else
break;
}
}
}
if( list->multiSelect )
{
Int i = 0;
while( list->selections[i] >= 0 )
{
if( (row = list->selections[i]) != 0 )
list->selections[i] = -1;
i++;
} // end while
} // end if
else
{
if( row == list->selectPos )
list->selectPos = -1;
}
} // end success
return((WindowMsgHandledType) addedIndex );
} // end add entry
// ------------------------------------------------------------------------
case GLM_TOGGLE_MULTI_SELECTION:
{
if( (Int)mData1 < 0 )
{
// a negative number will purge the entire list.
if( list->multiSelect )
memset( list->selections, -1, list->listLength * sizeof(Int) );
else
{
// this message has no effect in a non-multi listbox
}
break;
}
// if there is no cells we shouldn't be selecting this entry
if( !list->listData[ mData1 ].cell )
break;
if( list->multiSelect )
{
Int i = 0;
Bool removed = FALSE;
while( list->selections[i] >= 0 )
{
if( list->selections[i] == (Int)mData1 )
{
removeSelection( list, i );
removed = TRUE;
break;
}
i++;
}
if( removed == FALSE )
{
list->selections[i] = (Int)mData1;
list->selections[i+1] = -1;
}
}
else
{
// this message has no effect in a non-multi listbox
}
break;
} // end toggle multi-select
// ------------------------------------------------------------------------
case GLM_SET_SELECTION:
{
const Int *selectList = (const Int *)mData1;
Int selectCount = (Int)mData2;
DEBUG_ASSERTCRASH( list->multiSelect || selectCount == 1, ("Bad selection size"));
if( selectList[0] < 0 || list->listLength <= selectList[0] )
{
if( list->multiSelect )
memset( list->selections, -1, list->listLength * sizeof(Int) );
else
list->selectPos = -1;
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_SELECTED,
(WindowMsgData)window,
list->selectPos );
break;
}
if( list->multiSelect )
{
// forced selections override the entire selection list.
for (Int i=0; iendPos; ++i)
{
// don't select off the end
if (list->listLength <= selectList[i])
{
break;
}
// if there is no cells we shouldn't be selecting this entry
if( !list->listData[ selectList[i] ].cell )
{
break;
}
list->selections[i] = selectList[i];
}
list->selections[i] = -1;
}
else
{
// if there is no cells we shouldn't be selecting this entry
if( !list->listData[ selectList[0] ].cell )
{
break;
}
list->selectPos = selectList[0];
GameWindow *parent = window->winGetParent();
if( parent && BitTest( parent->winGetStyle(), GWS_COMBO_BOX ) )
{
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_SELECTED,
(WindowMsgData)window,
list->selectPos );
break;
}
if( list->listData[list->selectPos].listHeight < list->displayPos )
{
TheWindowManager->winSendSystemMsg( window, GLM_UPDATE_DISPLAY,
list->selectPos, 0 );
}
else if( list->listData[list->selectPos].listHeight >
(list->displayPos + list->displayHeight) )
{
if( list->selectPos > 0 )
list->displayPos =
list->listData[list->selectPos].listHeight - list->displayHeight;
else
list->displayPos = 0;
adjustDisplay( window, 0, TRUE );
} // end else if
} // end else
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GLM_SELECTED,
(WindowMsgData)window,
list->selectPos );
break;
} // end set selection
// ------------------------------------------------------------------------
case GLM_SCROLL_BUFFER:
{
if( list->endPos < (Int)mData1 )
break;
//
// scroll buffer literally scrolls the entire list data buffer
// up one entry, effectively removing the top entry.
//
//
// Loop through and remove all the entries from the top up until we reach
// the position mData1 contains
//
ListEntryCell *cells = NULL;
for (Int i = 0; i < (Int)mData1; i++)
{
cells = list->listData[i].cell;
if(cells)
for( Int j = 0; j < list->columns; j++ )
{
if( cells[j].cellType == LISTBOX_TEXT && cells[j].data )
TheDisplayStringManager->freeDisplayString((DisplayString *) cells[j].data );
// if (cells[i].userData)
// free(cells[i].userData);
cells[j].data = NULL;
cells[j].userData = NULL;
cells[j].color = 0;
cells[j].cellType = 0;
}
delete(list->listData[i].cell);
list->listData[i].cell = NULL;
}
//
// copy the cells up
//
memcpy(list->listData, &list->listData[mData1],
(list->endPos - mData1) * sizeof(ListEntryRow) );
list->endPos -= mData1;
list->insertPos = list->endPos;
//
// remove the display or links to images after the shift
//
for(i = 0; i < (Int)mData1; i ++)
{
list->listData[list->endPos + i].cell = NULL;
}
if( list->multiSelect )
{
Int i = 0;
while( list->selections[i] >= 0 )
{
if( (Int)mData1 >= list->selections[i] )
list->selections[i] -= (Int)mData1;
else
{
removeSelection( list, i );
i--; // compensate for lost entry
}
i++;
}
}
else
{
if( list->selectPos > 0 )
list->selectPos -= mData1;
}
if( list->displayPos > 0 )
adjustDisplay( window, (-1 * mData1), TRUE );
computeTotalHeight( window );
break;
} // end scroll buffer
// ------------------------------------------------------------------------
case GLM_GET_SELECTION:
{
if( list->multiSelect )
*(Int*)mData2 = (Int)list->selections;
else
*(Int*)mData2 = list->selectPos;
break;
} // end get selection
// ------------------------------------------------------------------------
case GLM_SET_UP_BUTTON:
list->upButton = (GameWindow *)mData1;
break;
// ------------------------------------------------------------------------
case GLM_SET_DOWN_BUTTON:
list->downButton = (GameWindow *)mData1;
break;
// ------------------------------------------------------------------------
case GLM_SET_SLIDER:
list->slider = (GameWindow *)mData1;
break;
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GGM_RESIZED:
{
Int width = (Int)mData1;
Int height = (Int)mData2;
ICoord2D downSize = {0, 0};
ICoord2D upSize = {0, 0};
ICoord2D sliderSize = {0, 0};
GameWindow *child = NULL;
ICoord2D sliderChildSize = {0, 0};
// get needed window sizes
if (list->downButton)
list->downButton->winGetSize( &downSize.x, &downSize.y );
if (list->upButton)
list->upButton->winGetSize( &upSize.x, &upSize.y );
if (list->slider)
{
list->slider->winGetSize( &sliderSize.x, &sliderSize.y );
child = list->slider->winGetChild();
if (child)
child->winGetSize( &sliderChildSize.x, &sliderChildSize.y );
}
if( list->upButton )
{
list->upButton->winSetPosition( width - upSize.x - 2, 2 );
}
if( list->downButton )
{
list->downButton->winSetPosition( width - downSize.x - 2,
height - downSize.y - 2 );
}
if( list->slider )
{
list->slider->winSetSize( sliderSize.x,
height - (2 * upSize.y) -6 );
list->slider->winSetPosition( width - sliderSize.x -2, upSize.y + 3 );
}
list->displayHeight = height;
// store display height
if( instData->getTextLength() )
{
list->displayHeight -= TheWindowManager->winFontHeight( instData->getFont() );
}
//
// Setup listbox Columns
//
if( list->columns == 1 )
{
list->columnWidth[0] = width;
if( list->slider )
{
ICoord2D sliderSize;
list->slider->winGetSize( &sliderSize.x, &sliderSize.y );
list->columnWidth[0] -= sliderSize.x;
} // end if
}// if
else
{
if( !list->columnWidthPercentage )
break;
if(!list->columnWidth)
break;
Int totalWidth = width;
if( list->slider )
{
ICoord2D sliderSize;
list->slider->winGetSize( &sliderSize.x, &sliderSize.y );
totalWidth -= sliderSize.x;
} // end if
for(Int i = 0; i < list->columns; i++ )
{
list->columnWidth[i] = list->columnWidthPercentage[i] * totalWidth / 100;
}// for
}// else
//reset the total height
computeTotalHeight(window);
break;
} // end resized
// ------------------------------------------------------------------------
case GLM_UPDATE_DISPLAY:
{
if( mData1 > 0 )
// set the display to the top of a specific entry
// which is the previous listHeight + 1
list->displayPos = list->listData[(mData1 - 1)].listHeight + 1;
else
list->displayPos = 0;
if( list->displayPos + list->displayHeight >= list->totalHeight )
{
list->displayPos = list->totalHeight - list->displayHeight;
}
adjustDisplay( window, 0, TRUE );
break;
} // end update display
// ------------------------------------------------------------------------
case GWM_DESTROY:
{
Int i;
// Loop through and destroy any display strings we've allocated
for( i = 0; i < list->listLength; i++ )
{
//We're now onto a row of cells we are not using anymore Pull off the cells and loop through them
ListEntryCell *cells = list->listData[i].cell;
for (int j = list->columns - 1; j >=0; j-- )
{
if(!cells)
break;
if( cells[j].cellType == LISTBOX_TEXT )
{
// If we can delete the stuff that won't be showing up in the new listData struture
if ( cells[j].data )
{
TheDisplayStringManager->freeDisplayString((DisplayString *) cells[j].data );
}
}
// if ( cells[j].userData )
// free(cells[j].userData);
// Null out the data pointers so they're not destroyed when we free up this listdata
cells[j].userData = NULL;
cells[j].data = NULL;
}
delete[](list->listData[i].cell);
list->listData[i].cell = NULL;
}
delete[]( list->listData );
if( list->columnWidth )
delete[]( list->columnWidth );
if( list->columnWidthPercentage )
delete[]( list->columnWidthPercentage );
if( list->multiSelect )
delete[]( list->selections );
delete( list );
break;
} // end destroy
// ------------------------------------------------------------------------
case GWM_INPUT_FOCUS:
{
// If we're losing focus
if( mData1 == FALSE )
{
BitClear( instData->m_state, WIN_STATE_HILITED );
}
else
{
BitSet( instData->m_state, WIN_STATE_HILITED );
}
TheWindowManager->winSendSystemMsg( window->winGetOwner(),
GGM_FOCUS_CHANGE,
mData1,
window->winGetWindowId() );
*(Bool*)mData2 = TRUE;
break;
} // end input focus
// ------------------------------------------------------------------------
case GSM_SLIDER_TRACK:
{
SliderData *sData = (SliderData *)list->slider->winGetUserData();
list->displayPos = sData->maxVal - mData2;
if( list->displayPos > (list->totalHeight - list->displayHeight + 1) )
list->displayPos = (list->totalHeight - list->displayHeight + 1);
if( list->displayPos < 0)
list->displayPos = 0;
adjustDisplay( window, 0, FALSE );
break;
} // end slider track
// ------------------------------------------------------------------------
case GLM_SET_ITEM_DATA:
{
void *data = (void *)mData2;
pos = (ICoord2D *)mData1;
if (pos->y >= 0 && pos->y < list->endPos && list->listData[pos->y].cell)
list->listData[pos->y].cell[pos->x].userData = data;
break;
}//case GLM_SET_ITEM_DATA:
// ------------------------------------------------------------------------
case GLM_GET_ITEM_DATA:
{
pos = (ICoord2D *)mData1;
void **data = (void **)mData2;
*data = NULL; // initialize to NULL
if (pos->y >= 0 && pos->y < list->endPos && list->listData[pos->y].cell)
*data = list->listData[pos->y].cell[pos->x].userData;
break;
}//case GLM_GET_ITEM_DATA:
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetListBoxSystem
// GadgetListBoxSetColors =====================================================
/** Set the colors for a list box, note that this will also automatically
* change the colors of any attached slider, slider thumb, and slider
* buttons */
//=============================================================================
void GadgetListBoxSetColors( GameWindow *listbox,
Color enabledColor,
Color enabledBorderColor,
Color enabledSelectedItemColor,
Color enabledSelectedItemBorderColor,
Color disabledColor,
Color disabledBorderColor,
Color disabledSelectedItemColor,
Color disabledSelectedItemBorderColor,
Color hiliteColor,
Color hiliteBorderColor,
Color hiliteSelectedItemColor,
Color hiliteSelectedItemBorderColor )
{
ListboxData *listboxData = (ListboxData *)listbox->winGetUserData();
// enabled
GadgetListBoxSetEnabledColor( listbox, enabledColor );
GadgetListBoxSetEnabledBorderColor( listbox, enabledBorderColor );
GadgetListBoxSetEnabledSelectedItemColor( listbox, enabledSelectedItemColor );
GadgetListBoxSetEnabledSelectedItemBorderColor( listbox, enabledSelectedItemBorderColor );
// disabled
GadgetListBoxSetDisabledColor( listbox, disabledColor );
GadgetListBoxSetDisabledBorderColor( listbox, disabledBorderColor );
GadgetListBoxSetDisabledSelectedItemColor( listbox, disabledSelectedItemColor );
GadgetListBoxSetDisabledSelectedItemBorderColor( listbox, disabledSelectedItemBorderColor );
// hilited
GadgetListBoxSetHiliteColor( listbox, hiliteColor );
GadgetListBoxSetHiliteBorderColor( listbox, hiliteBorderColor );
GadgetListBoxSetHiliteSelectedItemColor( listbox, hiliteSelectedItemColor );
GadgetListBoxSetHiliteSelectedItemBorderColor( listbox, hiliteSelectedItemBorderColor );
// assign default slider colors and images as part of the list box
GameWindow *slider = listboxData->slider;
if( slider )
{
GameWindow *upButton = listboxData->upButton;
GameWindow *downButton = listboxData->downButton;
// slider and slider thumb ----------------------------------------------
// enabled
GadgetSliderSetEnabledColor( slider, GadgetListBoxGetEnabledColor( listbox ) );
GadgetSliderSetEnabledBorderColor( slider, GadgetListBoxGetEnabledBorderColor( listbox ) );
// Disabled
GadgetSliderSetDisabledColor( slider, GadgetListBoxGetDisabledColor( listbox ) );
GadgetSliderSetDisabledBorderColor( slider, GadgetListBoxGetDisabledBorderColor( listbox ) );
// Hilite
GadgetSliderSetHiliteColor( slider, GadgetListBoxGetHiliteColor( listbox ) );
GadgetSliderSetHiliteBorderColor( slider, GadgetListBoxGetHiliteBorderColor( listbox ) );
// up button ------------------------------------------------------------
// enabled
GadgetButtonSetEnabledColor( upButton, GadgetSliderGetEnabledColor( slider ) );
GadgetButtonSetEnabledBorderColor( upButton, GadgetSliderGetEnabledBorderColor( slider ) );
GadgetButtonSetEnabledSelectedColor( upButton, GadgetSliderGetEnabledSelectedThumbColor( slider ) );
GadgetButtonSetEnabledSelectedBorderColor( upButton, GadgetSliderGetEnabledSelectedThumbBorderColor( slider ) );
// disabled
GadgetButtonSetDisabledColor( upButton, GadgetSliderGetDisabledColor( slider ) );
GadgetButtonSetDisabledBorderColor( upButton, GadgetSliderGetDisabledBorderColor( slider ) );
GadgetButtonSetDisabledSelectedColor( upButton, GadgetSliderGetDisabledSelectedThumbColor( slider ) );
GadgetButtonSetDisabledSelectedBorderColor( upButton, GadgetSliderGetDisabledSelectedThumbBorderColor( slider ) );
// hilite
GadgetButtonSetHiliteColor( upButton, GadgetSliderGetHiliteColor( slider ) );
GadgetButtonSetHiliteBorderColor( upButton, GadgetSliderGetHiliteBorderColor( slider ) );
GadgetButtonSetHiliteSelectedColor( upButton, GadgetSliderGetHiliteSelectedThumbColor( slider ) );
GadgetButtonSetHiliteSelectedBorderColor( upButton, GadgetSliderGetHiliteSelectedThumbBorderColor( slider ) );
// down button ----------------------------------------------------------
// enabled
GadgetButtonSetEnabledColor( downButton, GadgetSliderGetEnabledColor( slider ) );
GadgetButtonSetEnabledBorderColor( downButton, GadgetSliderGetEnabledBorderColor( slider ) );
GadgetButtonSetEnabledSelectedColor( downButton, GadgetSliderGetEnabledSelectedThumbColor( slider ) );
GadgetButtonSetEnabledSelectedBorderColor( downButton, GadgetSliderGetEnabledSelectedThumbBorderColor( slider ) );
// disabled
GadgetButtonSetDisabledColor( downButton, GadgetSliderGetDisabledColor( slider ) );
GadgetButtonSetDisabledBorderColor( downButton, GadgetSliderGetDisabledBorderColor( slider ) );
GadgetButtonSetDisabledSelectedColor( downButton, GadgetSliderGetDisabledSelectedThumbColor( slider ) );
GadgetButtonSetDisabledSelectedBorderColor( downButton, GadgetSliderGetDisabledSelectedThumbBorderColor( slider ) );
// hilite
GadgetButtonSetHiliteColor( downButton, GadgetSliderGetHiliteColor( slider ) );
GadgetButtonSetHiliteBorderColor( downButton, GadgetSliderGetHiliteBorderColor( slider ) );
GadgetButtonSetHiliteSelectedColor( downButton, GadgetSliderGetHiliteSelectedThumbColor( slider ) );
GadgetButtonSetHiliteSelectedBorderColor( downButton, GadgetSliderGetHiliteSelectedThumbBorderColor( slider ) );
} // end if
} // end GadgetListBoxSetColors
// GadgetListBoxGetText =======================================================
/** Get the text for a list box entry */
//=============================================================================
UnicodeString GadgetListBoxGetText( GameWindow *listbox, Int row, Int column)
{
Color color;
return GadgetListBoxGetTextAndColor( listbox,&color,row,column );
} // end GadgetListBoxGetText
// GadgetListBoxGetText =======================================================
/** Get the text for a list box entry */
//=============================================================================
UnicodeString GadgetListBoxGetTextAndColor( GameWindow *listbox, Color *color, Int row, Int column)
{
*color = 0;
// sanity
if( listbox == NULL || row == -1 || column == -1)
return UnicodeString::TheEmptyString;
// verify that this is a list box
if( BitTest( listbox->winGetStyle(), GWS_SCROLL_LISTBOX ) == FALSE )
return UnicodeString::TheEmptyString;
TextAndColor tAndC;
//UnicodeString result;
ICoord2D pos;
pos.x = column;
pos.y = row;
TheWindowManager->winSendSystemMsg( listbox, GLM_GET_TEXT, (WindowMsgData)&pos, (WindowMsgData)&tAndC );
*color = tAndC.color;
return tAndC.string;
//return UnicodeString::TheEmptyString;
} // end GadgetListBoxGetText
// GadgetListBoxAddEntryText ==================================================
/** Add a new string entry into the listbox at the insert position */
//=============================================================================
Int GadgetListBoxAddEntryText( GameWindow *listbox,
UnicodeString text,
Color color, Int row, Int column, Bool overwrite )
{
if (!listbox)
return -1;
if (text.isEmpty())
text = UnicodeString(L" ");
Int index;
AddMessageStruct addInfo;
addInfo.row = row;
addInfo.column = column;
addInfo.type = LISTBOX_TEXT;
addInfo.data = &text;
addInfo.overwrite = overwrite;
addInfo.height = -1;
addInfo.width = -1;
ListboxData *listData = (ListboxData *)listbox->winGetUserData();
Bool wasFull = (listData->listLength <= listData->endPos);
Int newEntryOffset = (wasFull)?0:1;
Int oldBottomIndex = GadgetListBoxGetBottomVisibleEntry(listbox);
/// @TODO: Don't do this type cast!
index = (Int) TheWindowManager->winSendSystemMsg( listbox, GLM_ADD_ENTRY, (WindowMsgData)&addInfo, color );
//DEBUG_ASSERTLOG(!listData->scrollIfAtEnd, ("Adding line %d (orig end was %d, newEntryOffset is %d, (%d-%d)?=%d, isFull=%d/%d ll=%d, end=%d\n",
//index, oldBottomIndex, newEntryOffset, index, oldBottomIndex, newEntryOffset, wasFull, GadgetListBoxIsFull(listbox), listData->listLength, listData->endPos));
if(listData->scrollIfAtEnd && index - oldBottomIndex == newEntryOffset && GadgetListBoxIsFull(listbox))
{
GadgetListBoxSetBottomVisibleEntry( listbox, index );
}
return (index);
} // end GadgetListBoxAddEntry
// GadgetListBoxAddEntryImage =================================================
/** Add a new string entry into the listbox at the insert position */
//=============================================================================
Int GadgetListBoxAddEntryImage( GameWindow *listbox, const Image *image,
Int row, Int column,
Int hight, Int width,
Bool overwrite, Color color )
{
Int index;
AddMessageStruct addInfo;
addInfo.row = row;
addInfo.column = column;
addInfo.type = LISTBOX_IMAGE;
addInfo.data = image;
addInfo.overwrite = overwrite;
addInfo.height = hight;
addInfo.width = width;
/// @TODO: Don't do this type cast!
index = (Int) TheWindowManager->winSendSystemMsg( listbox, GLM_ADD_ENTRY, (WindowMsgData)&addInfo, color );
return (index);
} // end GadgetListBoxAddEntryImage
Int GadgetListBoxAddEntryImage( GameWindow *listbox, const Image *image,
Int row, Int column,
Bool overwrite, Color color )
{
return GadgetListBoxAddEntryImage(listbox, image, row, column, -1, -1, overwrite, color);
}
// GadgetListBoxSetFont =======================================================
/** Set the font for a listbox control, we need to set the window
* text font, the tooltip font, and the edit text display strings for
* the text data itself and the secret text */
//=============================================================================
void GadgetListBoxSetFont( GameWindow *g, GameFont *font )
{
ListboxData *listData = (ListboxData *)g->winGetUserData();
DisplayString *dString;
// set the font for the display strings all windows have
dString = g->winGetInstanceData()->getTextDisplayString();
if( dString )
dString->setFont( font );
dString = g->winGetInstanceData()->getTooltipDisplayString();
if( dString )
dString->setFont( font );
// listbox specific
if( listData )
for( Int i = 0; i < listData->listLength; i++ )
{
if(listData->listData[i].cell)
for( Int j = 0; j < listData->columns; j++ )
{
if( listData->listData[i].cell[j].cellType == LISTBOX_TEXT && listData->listData[i].cell[j].data )
{
dString = (DisplayString *)listData->listData[i].cell[j].data;
dString->setFont( font );
}
}
} // end for i
} // end GadgetListBoxSetFont
// GadgetListboxCreateScrollbar ===============================================
/** Create the scroll bar using a slider and two buttons for a listbox */
//=============================================================================
void GadgetListboxCreateScrollbar( GameWindow *listbox )
{
ListboxData *listData = (ListboxData *)listbox->winGetUserData();
WinInstanceData winInstData;
SliderData sData = { 0 };
Int buttonWidth, buttonHeight;
Int sliderButtonWidth, sliderButtonHeight;
Int fontHeight;
Int top;
Int bottom;
UnsignedInt status = listbox->winGetStatus();
Bool title = FALSE;
Int width, height;
// get width and height of listbox
listbox->winGetSize( &width, &height );
// do we have a title
if( listbox->winGetTextLength() )
title = TRUE;
// remove unwanted status bits.
status &= ~(WIN_STATUS_BORDER | WIN_STATUS_HIDDEN | WIN_STATUS_NO_INPUT);
fontHeight = TheWindowManager->winFontHeight( listbox->winGetFont() );
top = title ? (fontHeight + 1):0;
bottom = title ? (height - (fontHeight + 1)):height;
// intialize instData
winInstData.init();
// size of button
buttonWidth = 21;//GADGET_SIZE;
buttonHeight = 22;//GADGET_SIZE;
// ----------------------------------------------------------------------
// Create Top Button
// ----------------------------------------------------------------------
status |= WIN_STATUS_IMAGE;
winInstData.m_owner = listbox;
winInstData.m_style = GWS_PUSH_BUTTON;
// if listbox tracks, so will this sub control
if( BitTest( listbox->winGetStyle(), GWS_MOUSE_TRACK ) )
BitSet( winInstData.m_style, GWS_MOUSE_TRACK );
listData->upButton =
TheWindowManager->gogoGadgetPushButton( listbox,
status | WIN_STATUS_ACTIVE | WIN_STATUS_ENABLED,
width - buttonWidth -2, top+2,
buttonWidth, buttonHeight,
&winInstData, NULL, TRUE );
// ----------------------------------------------------------------------
// Create Bottom Button
// ----------------------------------------------------------------------
winInstData.init();
winInstData.m_style = GWS_PUSH_BUTTON;
winInstData.m_owner = listbox;
// if listbox tracks, so will this sub control
if( BitTest( listbox->winGetStyle(), GWS_MOUSE_TRACK ) )
BitSet( winInstData.m_style, GWS_MOUSE_TRACK );
listData->downButton =
TheWindowManager->gogoGadgetPushButton( listbox,
status | WIN_STATUS_ACTIVE | WIN_STATUS_ENABLED,
width - buttonWidth -2,
(top + bottom - buttonHeight -2),
buttonWidth, buttonHeight,
&winInstData, NULL, TRUE );
// ----------------------------------------------------------------------
// create the slider
// ----------------------------------------------------------------------
// size of button
sliderButtonWidth = buttonWidth;//GADGET_SIZE;
sliderButtonHeight = GADGET_SIZE;
// intialize instData
winInstData.init();
winInstData.m_style = GWS_VERT_SLIDER;
winInstData.m_owner = listbox;
// if listbox tracks, so will this sub control
if( BitTest( listbox->winGetStyle(), GWS_MOUSE_TRACK ) )
BitSet( winInstData.m_style, GWS_MOUSE_TRACK );
// intialize sData
memset( &sData, 0, sizeof(SliderData) );
// Create Slider
listData->slider =
TheWindowManager->gogoGadgetSlider( listbox,
status | WIN_STATUS_ACTIVE | WIN_STATUS_ENABLED,
width - sliderButtonWidth - 2,
(top + buttonHeight + 3),
sliderButtonWidth, bottom - (2 * buttonHeight) - 6,
&winInstData, &sData, NULL, TRUE );
// we now have all the scrollbar parts, this better be set :)
listData->scrollBar = TRUE;
} // end GadgetListBoxCreateScrollbar
// GadgetListBoxAddMultiSelect ================================================
/** Enable multi selections for a listbox
*
* ASSUMPTION: The listLength must already be set at this time so
* that we can make enough space to hold all the selection data, if you
* change the list length you must also change the selection array
* for multi select listboxes
*/
//=============================================================================
void GadgetListBoxAddMultiSelect( GameWindow *listbox )
{
ListboxData *listboxData = (ListboxData *)listbox->winGetUserData();
DEBUG_ASSERTCRASH(listboxData && listboxData->selections == NULL, ("selections is not NULL"));
listboxData->selections = NEW Int [listboxData->listLength];
DEBUG_LOG(( "Enable list box multi select: listLength (select) = %d * %d = %d bytes;\n",
listboxData->listLength, sizeof(Int),
listboxData->listLength *sizeof(Int) ));
if( listboxData->selections == NULL )
{
delete( listboxData->listData );
return;
} // end if
memset( listboxData->selections, -1,
listboxData->listLength * sizeof(Int) );
// set mutliselect flag
listboxData->multiSelect = TRUE;
// adjust the input procedure for the listbox
listbox->winSetInputFunc( GadgetListBoxMultiInput );
} // end GadgetListBoxEnableMultiSelect
// GadgetListBoxRemoveMultiSelect =============================================
/** Remove multi select capability from a listbox */
//=============================================================================
void GadgetListBoxRemoveMultiSelect( GameWindow *listbox )
{
ListboxData *listData = (ListboxData *)listbox->winGetUserData();
if( listData->selections )
{
delete( listData->selections );
listData->selections = NULL;
} // end if
listData->multiSelect = FALSE;
// adjust the input procedure for the listbox
listbox->winSetInputFunc( GadgetListBoxInput );
} // end GadgetListBoxRemoveMultiSelect
// GadgetListBoxSetListLength =================================================
/** Set OR reset the list length data contained in the listboxData
* parameter. When adjusting the size of lists we also have to
* adjust multiselection lists if present and any display
* strings present */
//=============================================================================
void GadgetListBoxSetListLength( GameWindow *listbox, Int newLength )
{
ListboxData *listboxData = (ListboxData *)listbox->winGetUserData();
// ListboxData *listboxData = (ListboxData *)listbox->winGetUserData();
// ListEntry *newData = (ListEntry *)malloc(newLength * sizeof(ListEntry));
DEBUG_ASSERTCRASH(listboxData, ("We don't have our needed listboxData!"));
if( !listboxData )
return;
DEBUG_ASSERTCRASH(listboxData->columns > 0,("We need at least one Column in the listbox"));
if( listboxData->columns < 1 )
return;
Int columns = listboxData->columns;
ListEntryRow *newData = NEW ListEntryRow[ newLength ];
DEBUG_ASSERTCRASH(newData, ("Unable to allocate new data structures for the Listbox"));
if( !newData )
return;
Int i;
// zero out the new Data structure
memset( newData, 0, newLength * sizeof( ListEntryRow ) );
// we want to copy over different amounts of data depending on if we're adding
// to the list box or removing from the listbox
if(newLength >= listboxData->listLength)
{
memcpy(newData,listboxData->listData,listboxData->listLength * sizeof( ListEntryRow ) );
}
else
{
// If we're removing entries from the listbox, we need to reset the length,
// position, and selection to their new places
if( listboxData->displayPos >newLength)
listboxData->displayPos = newLength;
//if we're multiselect, just select no position
if(listboxData->selectPos > newLength || listboxData->multiSelect)
listboxData->selectPos = -1;
if(listboxData->insertPos > newLength)
listboxData->insertPos = newLength;
listboxData->endPos = newLength;
//copy only the data that we'll be needing.
memcpy(newData,listboxData->listData,newLength * sizeof( ListEntryRow ) );
}
// Loop through and destroy any display strings we've allocated that aren't used
for( i = 0; i < listboxData->listLength; i++ )
{
//We're now onto a row of cells we are not using anymore Pull off the cells and loop through them
ListEntryCell *cells = listboxData->listData[i].cell;
for (int j = columns - 1; j >=0; j-- )
{
if(!cells)
break;
if ( i >= newLength )
{
if( cells[j].cellType == LISTBOX_TEXT && i >= newLength)
{
// If we can delete the stuff that won't be showing up in the new listData struture
if ( cells[j].data )
{
TheDisplayStringManager->freeDisplayString((DisplayString *) cells[j].data );
}
}
// if ( cells[j].userData )
// free(cells[j].userData);
}
}
if ( i >= newLength )
delete(listboxData->listData[i].cell);
listboxData->listData[i].cell = NULL;
}
listboxData->listLength = newLength;
if( listboxData->listData )
delete( listboxData->listData );
listboxData->listData = newData;
//reset the total height
computeTotalHeight(listbox);
// Sanity check that everything was created properly
if( listboxData->listData == NULL )
{
DEBUG_LOG(( "Unable to allocate listbox data pointer\n" ));
assert( 0 );
return;
} // end if
// adjust the selection array for multi select listboxes
if( listboxData->multiSelect )
{
GadgetListBoxRemoveMultiSelect( listbox );
GadgetListBoxAddMultiSelect( listbox );
} // end if
} // end GadgetListBoxSetListLength
// GadgetListBoxGetListLength =================================================
/** Get the list length data contained in the listboxData
* parameter. */
//=============================================================================
Int GadgetListBoxGetListLength( GameWindow *listbox )
{
ListboxData *listboxData = (ListboxData *)listbox->winGetUserData();
if (listboxData->multiSelect)
{
return listboxData->listLength;
}
else
{
return 1;
}
} // end GadgetListBoxGetListLength
// GadgetListBoxGetNumEntries =================================================
/** Get the list length data contained in the listboxData
* parameter. */
//=============================================================================
Int GadgetListBoxGetNumEntries( GameWindow *listbox )
{
if (!listbox)
return 0;
ListboxData *listboxData = (ListboxData *)listbox->winGetUserData();
if (listboxData)
return listboxData->endPos;
return 0;
} // end GadgetListBoxGetNumEntries
//-------------------------------------------------------------------------------------------------
/** Get the selected item(s) of a listbox. For a single select listbox the parameter
* should be a single integer pointer. For a multi select listbox the parameter
* should be an (Int *), this array returned will be an array of indices of the selected items
* of the list box. An entry of -1 in this array is the "end" of the selected list,
* and this list will never be larger than the max items in the list box */
//-------------------------------------------------------------------------------------------------
void GadgetListBoxGetSelected( GameWindow *listbox, Int *selectList )
{
// sanity
if( listbox == NULL )
return;
// get selected indeces via system message
TheWindowManager->winSendSystemMsg( listbox, GLM_GET_SELECTION, 0, (WindowMsgData)selectList );
} // end GadgetListBoxGetSelected
//-------------------------------------------------------------------------------------------------
/** Set the selected item of a listbox. The parameter is a single integer. If
* the selected index is less than 0, nothing is selected. */
//-------------------------------------------------------------------------------------------------
void GadgetListBoxSetSelected( GameWindow *listbox, Int selectIndex )
{
// sanity
if( listbox == NULL )
return;
// set selected index via system message
TheWindowManager->winSendSystemMsg( listbox, GLM_SET_SELECTION, (WindowMsgData)(&selectIndex), 1 );
} // end GadgetListBoxSetSelected
//-------------------------------------------------------------------------------------------------
/** Set the selected item of a listbox. */
//-------------------------------------------------------------------------------------------------
void GadgetListBoxSetSelected( GameWindow *listbox, const Int *selectList, Int selectCount )
{
// sanity
if( listbox == NULL )
return;
// set selected index via system message
TheWindowManager->winSendSystemMsg( listbox, GLM_SET_SELECTION, (WindowMsgData)selectList, selectCount );
}
//-------------------------------------------------------------------------------------------------
/** Reset the content of the listbox */
//-------------------------------------------------------------------------------------------------
void GadgetListBoxReset( GameWindow *listbox )
{
// sanity
if( listbox == NULL )
return;
// reset via system message
TheWindowManager->winSendSystemMsg( listbox, GLM_DEL_ALL, 0, 0 );
} // end GadgetListBoxReset
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void GadgetListBoxSetItemData( GameWindow *listbox, void *data, Int row, Int column )
{
ICoord2D pos;
pos.x = column;
pos.y = row;
if (listbox)
TheWindowManager->winSendSystemMsg( listbox, GLM_SET_ITEM_DATA, (WindowMsgData)&pos, (WindowMsgData)data);
}// void GadgetListBoxSetItemData( Int index, void *data )
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void *GadgetListBoxGetItemData( GameWindow *listbox, Int row, Int column)
{
void *data = NULL;
ICoord2D pos;
pos.x = column;
pos.y = row;
if (listbox)
{
TheWindowManager->winSendSystemMsg( listbox, GLM_GET_ITEM_DATA, (WindowMsgData)&pos, (WindowMsgData)&data);
}
return (data);
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Int GadgetListBoxGetBottomVisibleEntry( GameWindow *window )
{
if (!window)
return 0;
ListboxData *listData = (ListboxData *)window->winGetUserData();
if (!listData)
return 0;
return getListboxBottomEntry(listData);
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
bool GadgetListBoxIsFull(GameWindow *window)
{
if (!window)
return FALSE;
ListboxData *listData = (ListboxData *)window->winGetUserData();
if (!listData)
return FALSE;
Int entry = getListboxBottomEntry(listData);
if(listData->listData[entry].listHeight >= listData->displayPos + listData->displayHeight - 5)
return TRUE;
else
return FALSE;
}
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void GadgetListBoxSetBottomVisibleEntry( GameWindow *window, Int newPos )
{
if (!window)
return;
ListboxData *listData = (ListboxData *)window->winGetUserData();
if (!listData)
return;
int prevPos = GadgetListBoxGetBottomVisibleEntry( window );
adjustDisplay(window, newPos - prevPos + 1, true);
} // void GadgetListBoxSetTopVisibleEntry( GameWindow *window, Int newPos )
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Int GadgetListBoxGetTopVisibleEntry( GameWindow *window )
{
if (!window)
return 0;
ListboxData *listData = (ListboxData *)window->winGetUserData();
if (!listData)
return 0;
return getListboxTopEntry(listData);
} // Int GadgetListBoxGetTopVisibleEntry( GameWindow *window )
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void GadgetListBoxSetTopVisibleEntry( GameWindow *window, Int newPos )
{
if (!window)
return;
ListboxData *listData = (ListboxData *)window->winGetUserData();
if (!listData)
return;
int prevPos = GadgetListBoxGetTopVisibleEntry( window );
adjustDisplay(window, newPos - prevPos, true);
} // void GadgetListBoxSetTopVisibleEntry( GameWindow *window, Int newPos )
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
void GadgetListBoxSetAudioFeedback( GameWindow *listbox, Bool enable )
{
if (!listbox)
return;
ListboxData *listboxData = (ListboxData *)listbox->winGetUserData();
if (!listboxData)
return;
listboxData->audioFeedback = enable;
} // end GadgetListBoxSetAudioFeedback
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Int GadgetListBoxGetNumColumns( GameWindow *listbox )
{
if (!listbox)
return 0;
ListboxData *listboxData = (ListboxData *)listbox->winGetUserData();
if (!listboxData)
return 0;
return listboxData->columns;
} // end GadgetListBoxGetNumColumns
//-------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------
Int GadgetListBoxGetColumnWidth( GameWindow *listbox, Int column )
{
if (!listbox)
return 0;
ListboxData *listboxData = (ListboxData *)listbox->winGetUserData();
if (!listboxData)
return 0;
if (listboxData->columns <= column || column < 0)
return 0;
return listboxData->columnWidth[column];
} // end GadgetListBoxGetNumColumns