Torque3D/Engine/source/gui/containers/guiFormCtrl.cpp
Areloch 5525f8ecdd Converts all game, gui editor, and system classes to utilize assets
Processed core, tools and default modules to utilize assets
Converted all console types that were string based, such as TypeImageFilename to utilize const char*/the string table, which avoids a lot of type swapping shenanigans and avoids string corruption
Removed unneeded MainEditor mockup module
Removed some unused/duplicate image assets from the tools
2021-07-19 01:07:08 -05:00

413 lines
11 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "console/engineAPI.h"
#include "platform/platform.h"
#include "gui/containers/guiFormCtrl.h"
#include "gui/core/guiDefaultControlRender.h"
#include "gfx/gfxDrawUtil.h"
#ifdef TORQUE_TOOLS
IMPLEMENT_CONOBJECT(GuiFormCtrl);
ConsoleDocClass( GuiFormCtrl,
"@brief A generic form control.\n\n"
"Currently editor use only.\n\n "
"@internal"
);
IMPLEMENT_CALLBACK( GuiFormCtrl, onResize, void, (), (),
"Called when the control is resized." );
GuiFormCtrl::GuiFormCtrl()
{
setMinExtent(Point2I(200,100));
mActive = true;
mMouseOver = false;
mDepressed = false;
mCanMove = false;
mCaption = "[none]";
mUseSmallCaption = false;
mContentLibrary = StringTable->EmptyString();
mContent = StringTable->EmptyString();
mCanSaveFieldDictionary = true;
mIsContainer = true;
// The attached menu bar
mHasMenu = false;
mMenuBar = NULL;
mMouseMovingWin = false;
}
GuiFormCtrl::~GuiFormCtrl()
{
// If we still have a menu bar, delete it.
if( mMenuBar )
mMenuBar->deleteObject();
}
bool GuiFormCtrl::_setHasMenu( void *object, const char *index, const char *data )
{
GuiFormCtrl* ctrl = reinterpret_cast< GuiFormCtrl* >( object );
ctrl->setHasMenu( dAtob( data ) );
return false;
}
void GuiFormCtrl::initPersistFields()
{
addField("caption", TypeRealString, Offset(mCaption, GuiFormCtrl));
addField("contentLibrary",TypeString, Offset(mContentLibrary, GuiFormCtrl));
addField("content", TypeString, Offset(mContent, GuiFormCtrl));
addField("movable", TypeBool, Offset(mCanMove, GuiFormCtrl));
addProtectedField( "hasMenu", TypeBool, Offset(mHasMenu, GuiFormCtrl),
&_setHasMenu, &defaultProtectedGetFn,
"" );
Parent::initPersistFields();
}
void GuiFormCtrl::setHasMenu( bool value )
{
if( mHasMenu == value )
return;
if( !value )
{
mMenuBar->deleteObject();
mMenuBar = NULL;
}
else
{
if( !mMenuBar )
{
mMenuBar = new GuiMenuBar();
mMenuBar->setField( "profile", "GuiFormMenuBarProfile" );
mMenuBar->setField( "horizSizing", "right" );
mMenuBar->setField( "vertSizing", "bottom" );
mMenuBar->setField( "extent", "16 16" );
mMenuBar->setField( "minExtent", "16 16" );
mMenuBar->setField( "position", "0 0" );
mMenuBar->setField( "class", "FormMenuBarClass "); // Give a generic class to the menu bar so that one set of functions may be used for all of them.
mMenuBar->registerObject();
mMenuBar->setProcessTicks(true); // Activate the processing of ticks to track if the mouse pointer has been hovering within the menu
}
addObject( mMenuBar ); // Add the menu bar to the form
}
mHasMenu = value;
}
bool GuiFormCtrl::onWake()
{
if ( !Parent::onWake() )
return false;
mFont = mProfile->mFont;
AssertFatal(mFont, "GuiFormCtrl::onWake: invalid font in profile" );
mProfile->constructBitmapArray();
if(mProfile->mUseBitmapArray && mProfile->mBitmapArrayRects.size())
{
mThumbSize.set( mProfile->mBitmapArrayRects[0].extent.x, mProfile->mBitmapArrayRects[0].extent.y );
mThumbSize.setMax( mProfile->mBitmapArrayRects[1].extent );
if(mFont->getHeight() > mThumbSize.y)
mThumbSize.y = mFont->getHeight();
}
else
{
mThumbSize.set(20, 20);
}
return true;
}
void GuiFormCtrl::addObject(SimObject *newObj )
{
if( ( mHasMenu && size() > 1) || (!mHasMenu && size() > 0 ) )
{
Con::warnf("GuiFormCtrl::addObject - Forms may only have one *direct* child - Placing on Parent!");
GuiControl* parent = getParent();
if ( parent )
parent->addObject( newObj );
return;
}
GuiControl *newCtrl = dynamic_cast<GuiControl*>( newObj );
GuiFormCtrl*formCtrl = dynamic_cast<GuiFormCtrl*>( newObj );
if( newCtrl && formCtrl )
newCtrl->setCanSave( true );
else if ( newCtrl )
newCtrl->setCanSave( false );
Parent::addObject( newObj );
}
void GuiFormCtrl::removeObject( SimObject* object )
{
if( object == mMenuBar )
{
mHasMenu = false;
mMenuBar = NULL;
}
Parent::removeObject( object );
}
bool GuiFormCtrl::acceptsAsChild( SimObject* object ) const
{
return Parent::acceptsAsChild( object ) &&
( ( mHasMenu && size() == 1 ) || ( !mHasMenu && !size() ) ); // Only accept a single child.
}
void GuiFormCtrl::onSleep()
{
Parent::onSleep();
mFont = NULL;
}
bool GuiFormCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
{
if( !Parent::resize(newPosition, newExtent) )
return false;
if( !mAwake || !mProfile->mBitmapArrayRects.size() )
return false;
// Should the caption be modified because the title bar is too small?
S32 textWidth = mProfile->mFont->getStrWidth(mCaption);
S32 newTextArea = getWidth() - mThumbSize.x - mProfile->mBitmapArrayRects[4].extent.x;
if(newTextArea < textWidth)
{
static char buf[256];
mUseSmallCaption = true;
mSmallCaption = StringTable->EmptyString();
S32 strlen = dStrlen((const char*)mCaption);
for(S32 i=strlen; i>=0; --i)
{
dStrcpy(buf, "", i);
dStrcat(buf, (const char*)mCaption, i);
dStrcat(buf, "...", i);
textWidth = mProfile->mFont->getStrWidth(buf);
if(textWidth < newTextArea)
{
mSmallCaption = StringTable->insert(buf, true);
break;
}
}
} else
{
mUseSmallCaption = false;
}
onResize_callback();
return true;
}
void GuiFormCtrl::onRender(Point2I offset, const RectI &updateRect)
{
// Fill in the control's child area
RectI boundsRect(offset, getExtent());
boundsRect.point.y += mThumbSize.y;
boundsRect.extent.y -= mThumbSize.y;
// draw the border of the form if specified
if (mProfile->mOpaque)
GFX->getDrawUtil()->drawRectFill(boundsRect, mProfile->mFillColor);
if (mProfile->mBorder)
renderBorder(boundsRect, mProfile);
// If we don't have a child, put some text in the child area
if( empty() )
{
GFX->getDrawUtil()->setBitmapModulation(ColorI(0,0,0));
renderJustifiedText(boundsRect.point, boundsRect.extent, "[none]");
}
S32 textWidth = 0;
// Draw our little bar, too
if (mProfile->mBitmapArrayRects.size() >= 5)
{
GFX->getDrawUtil()->clearBitmapModulation();
S32 barStart = offset.x + textWidth;
S32 barTop = mThumbSize.y / 2 + offset.y - mProfile->mBitmapArrayRects[3].extent.y / 2;
Point2I barOffset(barStart, barTop);
// Draw the start of the bar...
GFX->getDrawUtil()->drawBitmapStretchSR(mProfile->getBitmapResource(),RectI(barOffset, mProfile->mBitmapArrayRects[2].extent), mProfile->mBitmapArrayRects[2] );
// Now draw the middle...
barOffset.x += mProfile->mBitmapArrayRects[2].extent.x;
S32 barMiddleSize = (getExtent().x - (barOffset.x - offset.x)) - mProfile->mBitmapArrayRects[4].extent.x + 1;
if (barMiddleSize > 0)
{
// We have to do this inset to prevent nasty stretching artifacts
RectI foo = mProfile->mBitmapArrayRects[3];
foo.inset(1,0);
GFX->getDrawUtil()->drawBitmapStretchSR(
mProfile->getBitmapResource(),
RectI(barOffset, Point2I(barMiddleSize, mProfile->mBitmapArrayRects[3].extent.y)),
foo
);
}
// And the end
barOffset.x += barMiddleSize;
GFX->getDrawUtil()->drawBitmapStretchSR( mProfile->getBitmapResource(), RectI(barOffset, mProfile->mBitmapArrayRects[4].extent),
mProfile->mBitmapArrayRects[4]);
GFX->getDrawUtil()->setBitmapModulation((mMouseOver ? mProfile->mFontColorHL : mProfile->mFontColor));
renderJustifiedText(Point2I(mThumbSize.x, 0) + offset, Point2I(getWidth() - mThumbSize.x - mProfile->mBitmapArrayRects[4].extent.x, mThumbSize.y), (mUseSmallCaption ? mSmallCaption : mCaption) );
}
// Render the children
renderChildControls(offset, updateRect);
}
void GuiFormCtrl::onMouseMove(const GuiEvent &event)
{
Point2I localMove = globalToLocalCoord(event.mousePoint);
// If we're clicking in the header then resize
mMouseOver = (localMove.y < mThumbSize.y);
if(isMouseLocked())
mDepressed = mMouseOver;
}
void GuiFormCtrl::onMouseEnter(const GuiEvent &event)
{
setUpdate();
if(isMouseLocked())
{
mDepressed = true;
mMouseOver = true;
}
else
{
mMouseOver = true;
}
}
void GuiFormCtrl::onMouseLeave(const GuiEvent &event)
{
setUpdate();
if(isMouseLocked())
mDepressed = false;
mMouseOver = false;
}
void GuiFormCtrl::onMouseDown(const GuiEvent &event)
{
Point2I localClick = globalToLocalCoord(event.mousePoint);
// If we're clicking in the header then resize
if(localClick.y < mThumbSize.y)
{
mouseLock();
mDepressed = true;
mMouseMovingWin = mCanMove;
//update
setUpdate();
}
mOrigBounds = getBounds();
mMouseDownPosition = event.mousePoint;
if (mMouseMovingWin )
{
mouseLock();
}
else
{
GuiControl *ctrl = findHitControl(localClick);
if (ctrl && ctrl != this)
ctrl->onMouseDown(event);
}
}
void GuiFormCtrl::onMouseUp(const GuiEvent &event)
{
// Make sure we only get events we ought to be getting...
if (! mActive)
return;
mouseUnlock();
setUpdate();
// If we're clicking in the header then resize
//if(localClick.y < mThumbSize.y && mDepressed)
// setCollapsed(!mCollapsed);
}
DefineEngineMethod( GuiFormCtrl, getMenuID, S32, (),,
"Get the ID of this form's menu.\n\n"
"@return The ID of the form menu\n" )
{
return object->getMenuBarID();
}
U32 GuiFormCtrl::getMenuBarID()
{
return mMenuBar ? mMenuBar->getId() : 0;
}
DefineEngineMethod( GuiFormCtrl, setCaption, void, ( const char* caption ),,
"Sets the title of the form.\n\n"
"@param caption Form caption\n" )
{
object->setCaption( caption );
}
#endif