2019-11-08 22:02:52 +00:00
/*
* * listmenu . cpp
* * A simple menu consisting of a list of items
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 2010 Christoph Oelckers
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
# include "v_font.h"
# include "cmdlib.h"
# include "gstrings.h"
# include "d_gui.h"
# include "d_event.h"
# include "menu.h"
# include "v_draw.h"
2019-11-23 11:38:38 +00:00
# include "baselayer.h"
2019-11-08 22:02:52 +00:00
//=============================================================================
//
//
//
//=============================================================================
DListMenu : : DListMenu ( DMenu * parent , FListMenuDescriptor * desc )
: DMenu ( parent )
{
mDesc = NULL ;
if ( desc ! = NULL ) Init ( parent , desc ) ;
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenu : : Init ( DMenu * parent , FListMenuDescriptor * desc )
{
mParentMenu = parent ;
mDesc = desc ;
2019-11-23 22:05:24 +00:00
if ( mDesc - > mScriptId ) scriptID = mDesc - > mScriptId ;
2019-11-08 22:02:52 +00:00
if ( desc - > mCenter )
{
int center = 160 ;
for ( unsigned i = 0 ; i < mDesc - > mItems . Size ( ) ; i + + )
{
int xpos = mDesc - > mItems [ i ] - > GetX ( ) ;
int width = mDesc - > mItems [ i ] - > GetWidth ( ) ;
int curx = mDesc - > mSelectOfsX ;
if ( width > 0 & & mDesc - > mItems [ i ] - > Selectable ( ) )
{
int left = 160 - ( width - curx ) / 2 - curx ;
if ( left < center ) center = left ;
}
}
for ( unsigned i = 0 ; i < mDesc - > mItems . Size ( ) ; i + + )
{
int width = mDesc - > mItems [ i ] - > GetWidth ( ) ;
if ( width > 0 )
{
mDesc - > mItems [ i ] - > SetX ( center ) ;
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
FListMenuItem * DListMenu : : GetItem ( FName name )
{
for ( unsigned i = 0 ; i < mDesc - > mItems . Size ( ) ; i + + )
{
FName nm = mDesc - > mItems [ i ] - > GetAction ( NULL ) ;
if ( nm = = name ) return mDesc - > mItems [ i ] ;
}
return NULL ;
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenu : : Responder ( event_t * ev )
{
if ( ev - > type = = EV_GUI_Event )
{
if ( ev - > subtype = = EV_GUI_KeyDown )
{
int ch = tolower ( ev - > data1 ) ;
for ( unsigned i = mDesc - > mSelectedItem + 1 ; i < mDesc - > mItems . Size ( ) ; i + + )
{
if ( mDesc - > mItems [ i ] - > CheckHotkey ( ch ) )
{
mDesc - > mSelectedItem = i ;
2019-11-23 22:05:24 +00:00
gi - > MenuSelectSound ( ) ;
2019-11-08 22:02:52 +00:00
return true ;
}
}
for ( int i = 0 ; i < mDesc - > mSelectedItem ; i + + )
{
if ( mDesc - > mItems [ i ] - > CheckHotkey ( ch ) )
{
mDesc - > mSelectedItem = i ;
2019-11-23 22:05:24 +00:00
gi - > MenuSelectSound ( ) ;
2019-11-08 22:02:52 +00:00
return true ;
}
}
}
}
return Super : : Responder ( ev ) ;
}
//=============================================================================
//
//
//
//=============================================================================
bool DListMenu : : MenuEvent ( int mkey , bool fromcontroller )
{
int startedAt = mDesc - > mSelectedItem ;
switch ( mkey )
{
case MKEY_Up :
do
{
if ( - - mDesc - > mSelectedItem < 0 ) mDesc - > mSelectedItem = mDesc - > mItems . Size ( ) - 1 ;
}
while ( ! mDesc - > mItems [ mDesc - > mSelectedItem ] - > Selectable ( ) & & mDesc - > mSelectedItem ! = startedAt ) ;
2019-11-23 22:05:24 +00:00
gi - > MenuSelectSound ( ) ;
2019-11-08 22:02:52 +00:00
return true ;
case MKEY_Down :
do
{
if ( + + mDesc - > mSelectedItem > = ( int ) mDesc - > mItems . Size ( ) ) mDesc - > mSelectedItem = 0 ;
}
while ( ! mDesc - > mItems [ mDesc - > mSelectedItem ] - > Selectable ( ) & & mDesc - > mSelectedItem ! = startedAt ) ;
2019-11-23 22:05:24 +00:00
gi - > MenuSelectSound ( ) ;
2019-11-08 22:02:52 +00:00
return true ;
case MKEY_Enter :
if ( mDesc - > mSelectedItem > = 0 & & mDesc - > mItems [ mDesc - > mSelectedItem ] - > Activate ( ) )
{
2019-11-23 22:05:24 +00:00
gi - > MenuChooseSound ( ) ;
2019-11-08 22:02:52 +00:00
}
return true ;
default :
return Super : : MenuEvent ( mkey , fromcontroller ) ;
}
}
//=============================================================================
//
//
//
//=============================================================================
2019-11-23 22:05:24 +00:00
bool DListMenu : : MouseEvent ( int type , int xx , int yy )
2019-11-08 22:02:52 +00:00
{
int sel = - 1 ;
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
2019-11-23 22:05:24 +00:00
//x = ((x - (screen->GetWidth() / 2)) / CleanXfac) + 160;
//y = ((y - (screen->GetHeight() / 2)) / CleanYfac) + 100;
int width43 = ( screen - > GetHeight ( ) * 4 / 3 ) ;
int x = ( xx - ( screen - > GetWidth ( ) - width43 ) / 2 ) * 320 / width43 ;
int y = yy * 200 / screen - > GetHeight ( ) ;
2019-11-08 22:02:52 +00:00
if ( mFocusControl ! = NULL )
{
mFocusControl - > MouseEvent ( type , x , y ) ;
return true ;
}
else
{
if ( ( mDesc - > mWLeft < = 0 | | x > mDesc - > mWLeft ) & &
( mDesc - > mWRight < = 0 | | x < mDesc - > mWRight ) )
{
for ( unsigned i = 0 ; i < mDesc - > mItems . Size ( ) ; i + + )
{
if ( mDesc - > mItems [ i ] - > CheckCoordinate ( x , y ) )
{
if ( ( int ) i ! = mDesc - > mSelectedItem )
{
2019-11-23 22:05:24 +00:00
// no sound. This is too noisy.
2019-11-08 22:02:52 +00:00
}
mDesc - > mSelectedItem = i ;
mDesc - > mItems [ i ] - > MouseEvent ( type , x , y ) ;
return true ;
}
}
}
}
mDesc - > mSelectedItem = - 1 ;
return Super : : MouseEvent ( type , x , y ) ;
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenu : : Ticker ( )
{
Super : : Ticker ( ) ;
for ( unsigned i = 0 ; i < mDesc - > mItems . Size ( ) ; i + + )
{
mDesc - > mItems [ i ] - > Ticker ( ) ;
}
}
//=============================================================================
//
//
//
//=============================================================================
void DListMenu : : Drawer ( )
{
2019-11-22 21:52:11 +00:00
PreDraw ( ) ;
2019-11-08 22:02:52 +00:00
for ( unsigned i = 0 ; i < mDesc - > mItems . Size ( ) ; i + + )
{
2019-11-23 16:50:36 +00:00
if ( mDesc - > mItems [ i ] - > mEnabled ) mDesc - > mItems [ i ] - > Drawer ( origin , mDesc - > mSelectedItem = = ( int ) i ) ;
2019-11-08 22:02:52 +00:00
}
if ( mDesc - > mSelectedItem > = 0 & & mDesc - > mSelectedItem < ( int ) mDesc - > mItems . Size ( ) )
mDesc - > mItems [ mDesc - > mSelectedItem ] - > DrawSelector ( mDesc - > mSelectOfsX , mDesc - > mSelectOfsY , mDesc - > mSelector ) ;
2019-11-22 21:52:11 +00:00
PostDraw ( ) ;
2019-11-08 22:02:52 +00:00
Super : : Drawer ( ) ;
}
//=============================================================================
//
// base class for menu items
//
//=============================================================================
FListMenuItem : : ~ FListMenuItem ( )
{
}
bool FListMenuItem : : CheckCoordinate ( int x , int y )
{
return false ;
}
void FListMenuItem : : Ticker ( )
{
}
2019-11-23 11:38:38 +00:00
void FListMenuItem : : Drawer ( const vec2_t & origin , bool selected )
2019-11-08 22:02:52 +00:00
{
}
bool FListMenuItem : : Selectable ( )
{
return false ;
}
void FListMenuItem : : DrawSelector ( int xofs , int yofs , FTexture * tex )
{
if ( ! tex )
{
if ( ( DMenu : : MenuTime % 8 ) < 6 )
{
DrawText ( & twod , ConFont , OptionSettings . mFontColorSelection ,
( mXpos + xofs - 160 ) * CleanXfac + screen - > GetWidth ( ) / 2 ,
( mYpos + yofs - 100 ) * CleanYfac + screen - > GetHeight ( ) / 2 ,
" \ xd " ,
DTA_CellX , 8 * CleanXfac ,
DTA_CellY , 8 * CleanYfac ,
TAG_DONE ) ;
}
}
else
{
DrawTexture ( & twod , tex , mXpos + xofs , mYpos + yofs , DTA_Clean , true , TAG_DONE ) ;
}
}
bool FListMenuItem : : Activate ( )
{
return false ; // cannot be activated
}
FName FListMenuItem : : GetAction ( int * pparam )
{
return mAction ;
}
bool FListMenuItem : : SetString ( int i , const char * s )
{
return false ;
}
bool FListMenuItem : : GetString ( int i , char * s , int len )
{
return false ;
}
bool FListMenuItem : : SetValue ( int i , int value )
{
return false ;
}
bool FListMenuItem : : GetValue ( int i , int * pvalue )
{
return false ;
}
void FListMenuItem : : Enable ( bool on )
{
mEnabled = on ;
}
bool FListMenuItem : : MenuEvent ( int mkey , bool fromcontroller )
{
return false ;
}
bool FListMenuItem : : MouseEvent ( int type , int x , int y )
{
return false ;
}
bool FListMenuItem : : CheckHotkey ( int c )
{
return false ;
}
int FListMenuItem : : GetWidth ( )
{
return 0 ;
}
//=============================================================================
//
// static patch
//
//=============================================================================
FListMenuItemStaticPatch : : FListMenuItemStaticPatch ( int x , int y , FTexture * patch , bool centered )
: FListMenuItem ( x , y )
{
mTexture = patch ;
mCentered = centered ;
}
2019-11-23 11:38:38 +00:00
void FListMenuItemStaticPatch : : Drawer ( const vec2_t & origin , bool selected )
2019-11-08 22:02:52 +00:00
{
if ( ! mTexture )
{
return ;
}
int x = mXpos ;
FTexture * tex = mTexture ;
if ( mYpos > = 0 )
{
if ( mCentered ) x - = tex - > GetWidth ( ) / 2 ;
DrawTexture ( & twod , tex , x , mYpos , DTA_Clean , true , TAG_DONE ) ;
}
else
{
int x = ( mXpos - 160 ) * CleanXfac + ( screen - > GetWidth ( ) > > 1 ) ;
if ( mCentered ) x - = ( tex - > GetWidth ( ) * CleanXfac ) / 2 ;
DrawTexture ( & twod , tex , x , - mYpos * CleanYfac , DTA_CleanNoMove , true , TAG_DONE ) ;
}
}
//=============================================================================
//
// static text
//
//=============================================================================
FListMenuItemStaticText : : FListMenuItemStaticText ( int x , int y , const char * text , FFont * font , EColorRange color , bool centered )
: FListMenuItem ( x , y )
{
mText = text ;
mFont = font ;
mColor = color ;
mCentered = centered ;
}
2019-11-23 11:38:38 +00:00
void FListMenuItemStaticText : : Drawer ( const vec2_t & origin , bool selected )
2019-11-08 22:02:52 +00:00
{
const char * text = mText ;
if ( text ! = NULL )
{
if ( * text = = ' $ ' ) text = GStrings ( text + 1 ) ;
if ( mYpos > = 0 )
{
int x = mXpos ;
if ( mCentered ) x - = mFont - > StringWidth ( text ) / 2 ;
DrawText ( & twod , mFont , mColor , x , mYpos , text , DTA_Clean , true , TAG_DONE ) ;
}
else
{
int x = ( mXpos - 160 ) * CleanXfac + ( screen - > GetWidth ( ) > > 1 ) ;
if ( mCentered ) x - = ( mFont - > StringWidth ( text ) * CleanXfac ) / 2 ;
DrawText ( & twod , mFont , mColor , x , - mYpos * CleanYfac , text , DTA_CleanNoMove , true , TAG_DONE ) ;
}
}
}
FListMenuItemStaticText : : ~ FListMenuItemStaticText ( )
{
if ( mText ! = NULL ) delete [ ] mText ;
}
//=============================================================================
//
// base class for selectable items
//
//=============================================================================
FListMenuItemSelectable : : FListMenuItemSelectable ( int x , int y , int height , FName action , int param )
: FListMenuItem ( x , y , action )
{
mHeight = height ;
mParam = param ;
mHotkey = 0 ;
}
bool FListMenuItemSelectable : : CheckCoordinate ( int x , int y )
{
return mEnabled & & y > = mYpos & & y < mYpos + mHeight ; // no x check here
}
bool FListMenuItemSelectable : : Selectable ( )
{
return mEnabled ;
}
bool FListMenuItemSelectable : : Activate ( )
{
M_SetMenu ( mAction , mParam ) ;
return true ;
}
FName FListMenuItemSelectable : : GetAction ( int * pparam )
{
if ( pparam ! = NULL ) * pparam = mParam ;
return mAction ;
}
bool FListMenuItemSelectable : : CheckHotkey ( int c )
{
return c = = tolower ( mHotkey ) ;
}
bool FListMenuItemSelectable : : MouseEvent ( int type , int x , int y )
{
if ( type = = DMenu : : MOUSE_Release )
{
if ( NULL ! = DMenu : : CurrentMenu & & DMenu : : CurrentMenu - > MenuEvent ( MKEY_Enter , true ) )
{
return true ;
}
}
return false ;
}
//=============================================================================
//
// text item
//
//=============================================================================
2019-11-21 21:31:46 +00:00
FListMenuItemText : : FListMenuItemText ( int x , int y , int height , int hotkey , const FString & text , FFont * font , EColorRange color , EColorRange color2 , FName child , int param )
2019-11-08 22:02:52 +00:00
: FListMenuItemSelectable ( x , y , height , child , param )
{
mText = text ;
2019-11-21 21:31:46 +00:00
/*
2019-11-08 22:02:52 +00:00
mFont = font ;
mColor = color ;
mColorSelected = color2 ;
2019-11-21 21:31:46 +00:00
*/
mFont = NewSmallFont ;
mColor = CR_RED ;
mColorSelected = CR_GOLD ;
2019-11-08 22:02:52 +00:00
mHotkey = hotkey ;
}
FListMenuItemText : : ~ FListMenuItemText ( )
{
}
2019-11-23 11:38:38 +00:00
void FListMenuItemText : : Drawer ( const vec2_t & origin , bool selected )
2019-11-08 22:02:52 +00:00
{
const char * text = mText ;
2019-11-21 21:31:46 +00:00
if ( mText . Len ( ) )
2019-11-08 22:02:52 +00:00
{
if ( * text = = ' $ ' ) text = GStrings ( text + 1 ) ;
DrawText ( & twod , mFont , selected ? mColorSelected : mColor , mXpos , mYpos , text , DTA_Clean , true , TAG_DONE ) ;
}
}
int FListMenuItemText : : GetWidth ( )
{
const char * text = mText ;
2019-11-21 21:31:46 +00:00
if ( mText . Len ( ) )
2019-11-08 22:02:52 +00:00
{
if ( * text = = ' $ ' ) text = GStrings ( text + 1 ) ;
return mFont - > StringWidth ( text ) ;
}
return 1 ;
}
2019-11-23 11:38:38 +00:00
//=============================================================================
//
// native text item
//
//=============================================================================
FListMenuItemNativeText : : FListMenuItemNativeText ( int x , int y , int height , int hotkey , const FString & text , int fontnum , int palnum , float fontscale , FName child , int param )
: FListMenuItemSelectable ( x , y , height , child , param )
{
mText = text ;
mFontnum = NIT_BigFont ;
mPalnum = NIT_ActiveColor ;
mFontscale = fontscale ;
mHotkey = hotkey ;
}
FListMenuItemNativeText : : ~ FListMenuItemNativeText ( )
{
}
void FListMenuItemNativeText : : Drawer ( const vec2_t & origin , bool selected )
{
const char * text = mText ;
if ( mText . Len ( ) )
{
if ( * text = = ' $ ' ) text = GStrings ( text + 1 ) ;
2019-11-23 16:50:36 +00:00
gi - > DrawNativeMenuText ( mFontnum , selected ? NIT_SelectedState : mEnabled ? NIT_ActiveState : NIT_InactiveState , mXpos + origin . x , mYpos + origin . y , 1.f , text , TOR_Center ) ; // needs to be able to handle other orientations, too.
2019-11-23 11:38:38 +00:00
}
2019-11-23 16:50:36 +00:00
}
2019-11-23 11:38:38 +00:00
2019-11-23 16:50:36 +00:00
int FListMenuItemNativeText : : GetWidth ( )
2019-11-23 11:38:38 +00:00
{
return 1 ;
}
2019-11-08 22:02:52 +00:00
//=============================================================================
//
// patch item
//
//=============================================================================
FListMenuItemPatch : : FListMenuItemPatch ( int x , int y , int height , int hotkey , FTexture * patch , FName child , int param )
: FListMenuItemSelectable ( x , y , height , child , param )
{
mHotkey = hotkey ;
mTexture = patch ;
}
2019-11-23 11:38:38 +00:00
void FListMenuItemPatch : : Drawer ( const vec2_t & origin , bool selected )
2019-11-08 22:02:52 +00:00
{
DrawTexture ( & twod , mTexture , mXpos , mYpos , DTA_Clean , true , TAG_DONE ) ;
}
int FListMenuItemPatch : : GetWidth ( )
{
return mTexture
? mTexture - > GetWidth ( )
: 0 ;
}