/*
** Command & Conquer Generals Zero Hour(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: W3DTextEntry.cpp /////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: W3DTextEntry.cpp
//
// Created: Colin Day, June 2001
//
// Desc: W3D implementation for the text entry gadget
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "GameClient/GameWindowGlobal.h"
#include "GameClient/GadgetTextEntry.h"
#include "GameClient/IMEManager.h"
#include "W3DDevice/GameClient/W3DGadget.h"
#include "W3DDevice/GameClient/W3DDisplay.h"
#ifdef _INTERNAL
// for occasional debugging...
//#pragma optimize("", off)
//#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
#endif
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// drawTextEntryText ==========================================================
//=============================================================================
static void drawTextEntryText( GameWindow *window, WinInstanceData *instData,
Color textColor, Color textDropColor,
Color compositeColor, Color compositeDropColor,
Int x, Int y, Int width, Int fontHeight )
{
static Byte drawCnt = 0;
EntryData *e = (EntryData *)window->winGetUserData();
// Int charPos = e->charPos;
Int cursorPos;
// WideChar buffer[ ENTRY_TEXT_LEN + 1 ];
// WideChar *bufptr = buffer;
// Color constructColor = TheWindowManager->winMakeColor( 192, 0, 192, 255 );
DisplayString *text = e->text;
IRegion2D clipRegion;
ICoord2D origin, size;
Int compositeCursorPos = 0;
// Check to see if the IME manager is composing text
e->constructText->setText(UnicodeString::TheEmptyString);
if ( TheIMEManager && TheIMEManager->isAttachedTo( window) && TheIMEManager->isComposing())
{
// The user is composing a string.
// Show the composition in the text gadget.
UnicodeString composition;
TheIMEManager->getCompositionString( composition );
if ( e->secretText )
{
e->sText->setText( UnicodeString::TheEmptyString );
Int len = composition.getLength() + e->text->getTextLength();
for ( int i = 0; i < len; i++ )
{
e->sText->appendChar( '*' );
}
}
else
{
e->constructText->setText( composition );
compositeCursorPos = TheIMEManager->getCompositionCursorPosition();
}
}
// get out of here if no text color to show up
if( textColor == WIN_COLOR_UNDEFINED )
return;
// if our text is "secret" we will print only '*' characters
if( e->secretText )
text = e->sText;
// make sure our font is the same as our parents
if( text->getFont() != window->winGetFont() )
text->setFont( window->winGetFont() );
if( e->constructText->getFont() != window->winGetFont() )
e->constructText->setFont( window->winGetFont() );
// get the size of our text, and construct text
Int textWidth = text->getWidth();
if (!e->drawTextFromStart)
{
// clip the text to the edit window size
window->winGetScreenPosition( &origin.x, &origin.y );
window->winGetSize( &size.x, &size.y );
clipRegion.lo.x = x;
clipRegion.hi.x = x + width ;
clipRegion.lo.y = y;
clipRegion.hi.y = y + fontHeight;
text->setClipRegion( &clipRegion );
e->constructText->setClipRegion( &clipRegion );
// set construct window position if needed
//if( e->constructList && e->constructText->getTextLength() )
// e->constructList->winSetPosition( (x + textWidth1), (y + fontHeight) );
x+= 2;
// draw the text
if(textWidth < width)
{
text->draw( x, y, textColor, textDropColor );
cursorPos = textWidth + x;
}
else
{
Int div = textWidth / (width / 2) - 1;
text->draw(x - (div * (width/2)), y, textColor, textDropColor);
cursorPos = textWidth - (div * (width/2)) + x;
}
//cursorPos = x + textWidth;
}
else
{
window->winGetScreenPosition( &origin.x, &origin.y );
window->winGetSize( &size.x, &size.y );
clipRegion.lo.x = origin.x;
clipRegion.hi.x = origin.x + size.x;
clipRegion.lo.y = origin.y;
clipRegion.hi.y = origin.y + size.y;
text->setClipRegion( &clipRegion );
e->constructText->setClipRegion( &clipRegion );
// set construct window position if needed
//if( e->constructList && e->constructText->getTextLength() )
// e->constructList->winSetPosition( (x + textWidth1), (y + fontHeight) );
x+= 5;
// draw the text
text->draw( x, y, textColor, textDropColor );
cursorPos = textWidth + x;
}
if (e->constructText->getTextLength() > 0 )
{
e->constructText->draw( x + textWidth, y, compositeColor, compositeDropColor );
cursorPos += e->constructText->getWidth( compositeCursorPos );
}
// draw blinking cursor
GameWindow *parent;
parent = window->winGetParent();
if(parent && !BitTest(parent->winGetStyle(), GWS_COMBO_BOX))
parent = NULL;
if( (window == TheWindowManager->winGetFocus() || (parent && parent == TheWindowManager->winGetFocus())) && ((drawCnt++ >> 3) & 0x1) )
TheWindowManager->winFillRect( textColor, WIN_DRAW_LINE_WIDTH,
cursorPos, origin.y + 3,
cursorPos + 2, origin.y + size.y - 3 );
window->winSetCursorPosition( cursorPos + 2 - origin.x, 0 );
} // end drawTextEntryText
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// W3DGadgetTextEntryDraw =====================================================
/** Draw colored entry field using standard graphics */
//=============================================================================
void W3DGadgetTextEntryDraw( GameWindow *window, WinInstanceData *instData )
{
EntryData *e = (EntryData *)window->winGetUserData();
ICoord2D origin, size, start, end;
Color backBorder, backColor, textColor, textBorder,
compositeColor, compositeBorder;
// cancel unichar flag
e->receivedUnichar = FALSE;
// get size and position of window
window->winGetScreenPosition( &origin.x, &origin.y );
window->winGetSize( &size.x, &size.y );
// get the right colors
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
{
compositeColor = window->winGetDisabledTextColor();
compositeBorder = window->winGetDisabledTextBorderColor();
textColor = window->winGetDisabledTextColor();
textBorder = window->winGetDisabledTextBorderColor();
backColor = GadgetTextEntryGetDisabledColor( window );
backBorder = GadgetTextEntryGetDisabledBorderColor( window );
} // end if, disabled
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
{
compositeColor = window->winGetIMECompositeTextColor();
compositeBorder = window->winGetIMECompositeBorderColor();
textColor = window->winGetHiliteTextColor();
textBorder = window->winGetHiliteTextBorderColor();
backColor = GadgetTextEntryGetHiliteColor( window );
backBorder = GadgetTextEntryGetHiliteBorderColor( window );
} // end else if, hilited
else
{
compositeColor = window->winGetIMECompositeTextColor();
compositeBorder = window->winGetIMECompositeBorderColor();
textColor = window->winGetEnabledTextColor();
textBorder = window->winGetEnabledTextBorderColor();
backColor = GadgetTextEntryGetEnabledColor( window );
backBorder = GadgetTextEntryGetEnabledBorderColor( window );
} // end else, just enabled
// draw the back border
if( backBorder != WIN_COLOR_UNDEFINED )
{
start.x = origin.x;
start.y = origin.y;
end.x = start.x + size.x;
end.y = start.y + size.y;
TheWindowManager->winOpenRect( backBorder, WIN_DRAW_LINE_WIDTH,
start.x, start.y, end.x, end.y );
} // end if
// draw the filled back
if( backColor != WIN_COLOR_UNDEFINED )
{
start.x = origin.x + 1;
start.y = origin.y + 1;
end.x = start.x + size.x - 2;
end.y = start.y + size.y - 2;
TheWindowManager->winFillRect( backColor, WIN_DRAW_LINE_WIDTH,
start.x, start.y, end.x, end.y );
} // end if
// draw the text
Int fontHeight = TheWindowManager->winFontHeight( instData->getFont() );
Int startOffset = 5;
Int width;
width = size.x - (2 * startOffset);
start.x = origin.x + startOffset; // offset a little bit into the entry
if( BitTest( window->winGetStatus(), WIN_STATUS_ONE_LINE ) )
start.y = size.y / 2 - fontHeight / 2;
else
start.y = origin.y + startOffset; // offset a little bit into the entry
// draw the edit text
drawTextEntryText( window, instData, textColor, textBorder, compositeColor, compositeBorder,
start.x, start.y, width, fontHeight );
} // end W3DGadgetTextEntryDraw
// W3DGadgetTextEntryImageDraw ================================================
/** Draw horizontal slider with user supplied images */
//=============================================================================
void W3DGadgetTextEntryImageDraw( GameWindow *window, WinInstanceData *instData )
{
EntryData *e = (EntryData *)window->winGetUserData();
ICoord2D origin, size, start, end;
Color textColor, textBorder;
Color compositeColor, compositeBorder;
const Image *leftImage, *rightImage, *centerImage, *smallCenterImage;
Int xOffset, yOffset;
Int i;
// cancel unichar flag
e->receivedUnichar = FALSE;
// get size and position of window
window->winGetScreenPosition( &origin.x, &origin.y );
window->winGetSize( &size.x, &size.y );
// get image offset
xOffset = instData->m_imageOffset.x;
yOffset = instData->m_imageOffset.y;
// get the right colors
if( BitTest( window->winGetStatus(), WIN_STATUS_ENABLED ) == FALSE )
{
textColor = window->winGetDisabledTextColor();
textBorder = window->winGetDisabledTextBorderColor();
compositeColor = window->winGetDisabledTextColor();
compositeBorder = window->winGetDisabledTextBorderColor();
leftImage = GadgetTextEntryGetDisabledImageLeft( window );
rightImage = GadgetTextEntryGetDisabledImageRight( window );
centerImage = GadgetTextEntryGetDisabledImageCenter( window );
smallCenterImage = GadgetTextEntryGetDisabledImageSmallCenter( window );
} // end if, disabled
else if( BitTest( instData->getState(), WIN_STATE_HILITED ) )
{
textColor = window->winGetHiliteTextColor();
textBorder = window->winGetHiliteTextBorderColor();
compositeColor = window->winGetIMECompositeTextColor();
compositeBorder = window->winGetIMECompositeBorderColor();
leftImage = GadgetTextEntryGetHiliteImageLeft( window );
rightImage = GadgetTextEntryGetHiliteImageRight( window );
centerImage = GadgetTextEntryGetHiliteImageCenter( window );
smallCenterImage = GadgetTextEntryGetHiliteImageSmallCenter( window );
} // end else if, hilited
else
{
textColor = window->winGetEnabledTextColor();
textBorder = window->winGetEnabledTextBorderColor();
compositeColor = window->winGetIMECompositeTextColor();
compositeBorder = window->winGetIMECompositeBorderColor();
leftImage = GadgetTextEntryGetEnabledImageLeft( window );
rightImage = GadgetTextEntryGetEnabledImageRight( window );
centerImage = GadgetTextEntryGetEnabledImageCenter( window );
smallCenterImage = GadgetTextEntryGetEnabledImageSmallCenter( window );
} // end else, just enabled
// get image sizes for the ends
ICoord2D leftSize, rightSize;
leftSize.x = leftImage->getImageWidth();
leftSize.y = leftImage->getImageHeight();
rightSize.x = rightImage->getImageWidth();
rightSize.y = rightImage->getImageHeight();
// get two key points used in the end drawing
ICoord2D leftEnd, rightStart;
leftEnd.x = origin.x + leftSize.x + xOffset;
leftEnd.y = origin.y + size.y + yOffset;
rightStart.x = origin.x + size.x - rightSize.x + xOffset;
rightStart.y = origin.y + yOffset;
// draw the center repeating bar
Int centerWidth, pieces;
// get width we have to draw our repeating center in
centerWidth = rightStart.x - leftEnd.x;
// how many whole repeating pieces will fit in that width
pieces = centerWidth / centerImage->getImageWidth();
// draw the pieces
start.x = leftEnd.x;
start.y = origin.y + yOffset;
end.y = start.y + size.y;
for( i = 0; i < pieces; i++ )
{
end.x = start.x + centerImage->getImageWidth();
TheWindowManager->winDrawImage( centerImage,
start.x, start.y,
end.x, end.y );
start.x += centerImage->getImageWidth();
} // end for i
//
// how many small repeating pieces will fit in the gap from where the
// center repeating bar stopped and the right image, draw them
// and overlapping underneath where the right end will go
//
centerWidth = rightStart.x - start.x;
pieces = centerWidth / smallCenterImage->getImageWidth() + 1;
end.y = start.y + size.y;
for( i = 0; i < pieces; i++ )
{
end.x = start.x + smallCenterImage->getImageWidth();
TheWindowManager->winDrawImage( smallCenterImage,
start.x, start.y,
end.x, end.y );
start.x += smallCenterImage->getImageWidth();
} // end for i
// draw left end
start.x = origin.x + xOffset;
start.y = origin.y + yOffset;
end = leftEnd;
TheWindowManager->winDrawImage(leftImage, start.x, start.y, end.x, end.y);
// draw right end
start = rightStart;
end.x = start.x + rightSize.x;
end.y = start.y + size.y;
TheWindowManager->winDrawImage(rightImage, start.x, start.y, end.x, end.y);
// draw the text
Int fontHeight = TheWindowManager->winFontHeight( instData->getFont() );
Int startOffset = 5;
Int width;
width = size.x - (2 * startOffset);
start.x = origin.x + startOffset; // offset a little bit into the entry
if( BitTest( window->winGetStatus(), WIN_STATUS_ONE_LINE ) )
start.y = size.y / 2 - fontHeight / 2;
else
start.y = origin.y + startOffset; // offset a little bit into the entry
// draw the edit text
drawTextEntryText( window, instData, textColor, textBorder, compositeColor, compositeBorder,
start.x, start.y, width, fontHeight );
} // end W3DGadgetTextEntryImageDraw