t2 engine svn checkout

This commit is contained in:
loop 2024-01-07 04:36:33 +00:00
commit ff569bd2ae
988 changed files with 394180 additions and 0 deletions

283
gui/channelVector.cc Normal file
View file

@ -0,0 +1,283 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/channelVector.h"
struct TempLineBreak
{
S32 start;
S32 end;
char *content;
};
IMPLEMENT_CONOBJECT(ChannelVector);
//-------------------------------------- Console methods
ConsoleMethod(ChannelVector,AddMember,bool,4,5,"obj.addMember(id,nick,flags)")
{
ChannelVector* pCV = static_cast<ChannelVector*>(object);
if (argc == 4)
return pCV->addMember(dAtoi(argv[2]),argv[3]);
else
return pCV->addMember(dAtoi(argv[2]),argv[3],dAtoi(argv[4]));
}
ConsoleMethod(ChannelVector,RemoveMember,bool,3,3,"obj.removeMember(id)")
{
argc;
ChannelVector* pCV = static_cast<ChannelVector*>(object);
return pCV->removeMember(dAtoi(argv[2]));
}
ConsoleMethod(ChannelVector,Sort,void,2,2,"obj.sort()")
{
argc; argv;
ChannelVector* pCV = static_cast<ChannelVector*>(object);
pCV->sort();
}
ConsoleMethod(ChannelVector,FindMember,S32,3,3,"obj.findMember(id)")
{
argc;
ChannelVector* pCV = static_cast<ChannelVector*>(object);
return pCV->findMember(dAtoi(argv[2]));
}
ConsoleMethod(ChannelVector,NumMembers,S32,2,2,"obj.numMembers()")
{
argc; argv;
ChannelVector* pCV = static_cast<ChannelVector*>(object);
return pCV->numMembers();
}
ConsoleMethod(ChannelVector,GetMemberId,S32,3,3,"obj.getMemberId(i)")
{
argc;
ChannelVector* pCV = static_cast<ChannelVector*>(object);
return pCV->getMemberId(dAtoi(argv[2]));
}
ConsoleMethod(ChannelVector,GetMemberNick,const char *,3,3,"obj.getMemberNick(i)")
{
argc;
ChannelVector* pCV = static_cast<ChannelVector*>(object);
return pCV->getMemberNick(dAtoi(argv[2]));
}
ConsoleMethod(ChannelVector,SetMemberNick,bool,4,4,"obj.setMemberNick(i,nick)")
{
argc;
ChannelVector* pCV = static_cast<ChannelVector*>(object);
return pCV->setMemberNick(dAtoi(argv[2]),argv[3]);
}
ConsoleMethod(ChannelVector,SetFlags,void,5,5,"obj.setFlags(i,flags,set)")
{
argc;
ChannelVector* pCV = static_cast<ChannelVector*>(object);
pCV->setFlags(dAtoi(argv[2]),dAtoi(argv[3]),dAtob(argv[4]));
}
ConsoleMethod(ChannelVector,GetFlags,S32,3,3,"obj.getFlags(i)")
{
argc;
ChannelVector* pCV = static_cast<ChannelVector*>(object);
return pCV->getFlags(dAtoi(argv[2]));
}
//--------------------------------------------------------------------------
ChannelVector::ChannelVector()
{
VECTOR_SET_ASSOCIATION(mLineTags);
VECTOR_SET_ASSOCIATION(mMembers);
}
//--------------------------------------------------------------------------
ChannelVector::~ChannelVector()
{
for (U32 i = 0; i < mLineTags.size(); ++i)
delete [] mLineTags[i].specials;
mLineTags.clear();
}
//------------------------------------------------------------------------------
S32 QSORT_CALLBACK ChannelVector::compareMembers(const void *a, const void *b)
{
Member *memberA = (Member*) a;
Member *memberB = (Member*) b;
S32 ao = memberA->flags & (PERSON_SPEAKER|PERSON_OPERATOR);
S32 bo = memberB->flags & (PERSON_SPEAKER|PERSON_OPERATOR);
if (ao != bo)
return (bo-ao);
char atag[64];
const char *anick;
char btag[64];
const char *bnick;
dStrcpy(atag,memberA->nick);
atag[7] = '\0';
if (dStrcmp(atag,"<tribe:") == 0)
anick = &memberA->nick[9];
else
anick = memberA->nick;
dStrcpy(btag,memberB->nick);
btag[7] = '\0';
if (dStrcmp(btag,"<tribe:") == 0)
bnick = &memberB->nick[9];
else
bnick = memberB->nick;
return (dStricmp(anick, bnick));
}
//------------------------------------------------------------------------------
void ChannelVector::sort()
{
dQsort((void*) &mMembers[0], mMembers.size(), sizeof(Member), compareMembers);
}
//--------------------------------------------------------------------------
void ChannelVector::initPersistFields()
{
Parent::initPersistFields();
}
//--------------------------------------------------------------------------
void ChannelVector::consoleInit()
{
}
//--------------------------------------------------------------------------
bool ChannelVector::onAdd()
{
return Parent::onAdd();
}
//--------------------------------------------------------------------------
void ChannelVector::onRemove()
{
Parent::onRemove();
}
//--------------------------------------------------------------------------
void ChannelVector::insertLine(const U32 position, const char *newMessage, const S32 newMessageTag)
{
Vector<TempLineBreak> tempSpecials(__FILE__, __LINE__);
Vector<S32> tempTypes(__FILE__, __LINE__);
char *copy = new char[dStrlen(newMessage) + 1];
const char* cur = copy;
dStrcpy(copy,newMessage);
while(cur[0] != '\0')
{
const char *open;
if ((open = dStrstr(cur,"<tribe:")) != NULL)
{
const char *close;
tempTypes.push_back((open[7] == '0') ? NickTag : TribeTag);
tempSpecials.increment();
TempLineBreak &tag = tempSpecials.last();
tag.start = open - copy;
tag.content = NULL;
open += 9;
close = dStrstr(open,"</tribe>");
tag.end = tag.start + (close-open) - 1;
dMemcpy(&copy[tag.start],open,tag.end-tag.start+1);
dStrcpy(&copy[tag.end+1],close+8);
cur = &copy[tempSpecials.last().end+1];
}
else
if ((open = dStrstr(cur,"<t2server:")) != NULL)
{
const char *close;
tempTypes.push_back(ServerTag);
tempSpecials.increment();
TempLineBreak &tag = tempSpecials.last();
tag.start = open - copy;
const char *content = open+10;
open = dStrstr(open,">");
tag.content = new char[open-content+1];
dMemcpy(tag.content,content,open-content);
tag.content[open-content] = '\0';
++open;
close = dStrstr(open,"</t2server>");
tag.end = tag.start + (close-open) - 1;
dMemcpy(&copy[tag.start],open,tag.end-tag.start+1);
dStrcpy(&copy[tag.end+1],close+11);
cur = &copy[tag.end+1];
}
else
break;
}
SpecialMarkers tags;
if ((tags.numSpecials = tempSpecials.size()) != 0) {
tags.specials = new SpecialMarkers::Special[tempSpecials.size()];
for (U32 i = 0; i < tempSpecials.size(); i++) {
tags.specials[i].specialType = tempTypes[i];
tags.specials[i].start = tempSpecials[i].start;
tags.specials[i].end = tempSpecials[i].end;
tags.specials[i].content = tempSpecials[i].content;
}
} else
tags.specials = NULL;
mLineTags.insert(position);
mLineTags[position] = tags;
Parent::insertLine(position,copy,newMessageTag);
delete [] copy;
}
//--------------------------------------------------------------------------
void ChannelVector::deleteLine(const U32 position)
{
delete [] mLineTags[position].specials;
mLineTags.erase(position);
Parent::deleteLine(position);
}

202
gui/channelVector.h Normal file
View file

@ -0,0 +1,202 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _CHANNELVECTOR_H_
#define _CHANNELVECTOR_H_
#ifndef _GUIMESSAGEVECTORCTRL_H_
#include "GUI/guiMessageVectorCtrl.h"
#endif
class ChannelVector : public MessageVector
{
private:
typedef MessageVector Parent;
enum Constants {
// Person flags
PERSON_SPEAKER = BIT(0),
PERSON_OPERATOR = BIT(1),
PERSON_IGNORE = BIT(2),
PERSON_AWAY = BIT(3),
};
public:
enum {
NickTag = -3,
TribeTag = -2,
ServerTag = -1,
};
struct SpecialMarkers {
struct Special {
S32 specialType;
S32 start;
S32 end;
char *content;
Special() { content = NULL; };
~Special() { delete [] content; };
};
U32 numSpecials;
Special* specials;
};
ChannelVector();
~ChannelVector();
DECLARE_CONOBJECT(ChannelVector);
virtual void insertLine(const U32 position, const char*, const S32);
virtual void deleteLine(const U32);
const SpecialMarkers & getLineTags(U32 position)
{
return mLineTags[position];
}
bool addMember(S32 id, const char *nick, S32 flags = 0);
bool removeMember(S32 id);
static S32 QSORT_CALLBACK compareMembers(const void *a, const void *b);
void sort();
S32 findMember(S32 id);
S32 numMembers();
S32 getMemberId(S32 i);
const char *getMemberNick(S32 i);
bool setMemberNick(S32 i, const char *nick);
void setFlags(S32 i, S32 flags, bool set);
S32 getFlags(S32 i);
static void initPersistFields();
static void consoleInit();
protected:
struct Member
{
S32 id;
StringTableEntry nick;
S32 flags;
};
bool onAdd();
void onRemove();
Vector<SpecialMarkers> mLineTags;
Vector<Member> mMembers;
};
//------------------------------------------------------------------------------
inline bool ChannelVector::addMember(S32 id, const char *nick, S32 flags)
{
Vector<Member>::iterator itr = mMembers.begin();
for (; itr != mMembers.end(); itr++)
if (id == itr->id)
break;
if (itr == mMembers.end())
{
mMembers.increment();
Member *pm = mMembers.end()-1;
pm->id = id;
pm->nick = StringTable->insert(nick);
pm->flags = flags;
sort();
return true;
}
return false;
}
//------------------------------------------------------------------------------
inline bool ChannelVector::removeMember(S32 id)
{
Vector<Member>::iterator itr = mMembers.begin();
for (; itr != mMembers.end(); itr++)
if (id == itr->id)
{
mMembers.erase(itr);
return true;
}
return false;
}
//------------------------------------------------------------------------------
inline S32 ChannelVector::findMember(S32 id)
{
for (S32 i = 0; i < mMembers.size(); ++i)
if (id == mMembers[i].id)
return i;
return -1;
}
//------------------------------------------------------------------------------
inline S32 ChannelVector::numMembers()
{
return mMembers.size();
}
//------------------------------------------------------------------------------
inline S32 ChannelVector::getMemberId(S32 i)
{
if (i >= 0 && i < mMembers.size())
return mMembers[i].id;
else
return 0;
}
//------------------------------------------------------------------------------
inline const char * ChannelVector::getMemberNick(S32 i)
{
if (i >= 0 && i < mMembers.size())
return mMembers[i].nick;
else
return NULL;
}
//------------------------------------------------------------------------------
inline bool ChannelVector::setMemberNick(S32 i, const char *nick)
{
if (i >= 0 && i < mMembers.size())
{
mMembers[i].nick = StringTable->insert(nick);
return true;
}
else
return false;
}
//------------------------------------------------------------------------------
inline void ChannelVector::setFlags(S32 i, S32 flags, bool set)
{
if (i >= 0 && i < mMembers.size())
if (set)
mMembers[i].flags |= flags;
else
mMembers[i].flags &= ~flags;
}
//------------------------------------------------------------------------------
inline S32 ChannelVector::getFlags(S32 i)
{
if (i >= 0 && i < mMembers.size())
return mMembers[i].flags;
else
return 0;
}
#endif // _H_CHANNELVECTOR_

488
gui/guiArrayCtrl.cc Normal file
View file

@ -0,0 +1,488 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "dgl/dgl.h"
#include "Platform/event.h"
#include "GUI/guiScrollCtrl.h"
#include "GUI/guiArrayCtrl.h"
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
GuiArrayCtrl::GuiArrayCtrl()
{
mActive = true;
mCellSize.set(80, 30);
mSize = Point2I(5, 30);
mSelectedCell.set(-1, -1);
mMouseOverCell.set(-1, -1);
mHeaderDim.set(0, 0);
}
bool GuiArrayCtrl::onWake()
{
if (! Parent::onWake())
return false;
//get the font
mFont = mProfile->mFont;
return true;
}
void GuiArrayCtrl::onSleep()
{
Parent::onSleep();
mFont = NULL;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
void GuiArrayCtrl::setSize(Point2I newSize)
{
mSize = newSize;
Point2I newExtent(newSize.x * mCellSize.x + mHeaderDim.x, newSize.y * mCellSize.y + mHeaderDim.y);
resize(mBounds.point, newExtent);
}
void GuiArrayCtrl::getScrollDimensions(S32 &cell_size, S32 &num_cells)
{
cell_size = mCellSize.y;
num_cells = mSize.y;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
bool GuiArrayCtrl::cellSelected(Point2I cell)
{
if (cell.x < 0 || cell.x >= mSize.x || cell.y < 0 || cell.y >= mSize.y)
{
mSelectedCell = Point2I(-1,-1);
return false;
}
mSelectedCell = cell;
scrollSelectionVisible();
onCellSelected(cell);
return true;
}
void GuiArrayCtrl::onCellSelected(Point2I cell)
{
Con::executef(this, 3, "onSelect", Con::getFloatArg(cell.x), Con::getFloatArg(cell.y));
//call the console function
if (mConsoleCommand[0])
Con::evaluate(mConsoleCommand, false);
}
void GuiArrayCtrl::setSelectedCell(Point2I cell)
{
cellSelected(cell);
}
Point2I GuiArrayCtrl::getSelectedCell()
{
return mSelectedCell;
}
void GuiArrayCtrl::scrollSelectionVisible()
{
scrollCellVisible(mSelectedCell);
}
void GuiArrayCtrl::scrollCellVisible(Point2I cell)
{
//make sure we have a parent
GuiControl *parent = getParent();
if (! parent) return;
//make sure we have a valid cell selected
if ((cell.x < 0) || (cell.y < 0)) return;
//get the parent extent, and the offset of the selected cell
Point2I parentExtent = parent->getExtent();
Point2I cellPos(mBounds.point.x + cell.x * mCellSize.x,
mBounds.point.y + cell.y * mCellSize.y);
Point2I delta(0,0);
//find out how far the selected cell is outside the parent extent horizontally
if (cellPos.x <= 0)
{
delta.x = -cellPos.x;
}
else if (cellPos.x + mCellSize.x > parentExtent.x)
{
delta.x = parentExtent.x - (cellPos.x + mCellSize.x);
}
//find out how far the selected cell is outside the parent extent vertically
if (cellPos.y <= 0)
{
delta.y = -cellPos.y;
}
else if (cellPos.y + mCellSize.y > parentExtent.y)
{
delta.y = parentExtent.y - (cellPos.y + mCellSize.y);
}
//if we need to scroll, set the new position
if (delta.x || delta.y)
{
Point2I newPosition = mBounds.point;
newPosition.x += delta.x;
newPosition.y += delta.y;
resize(newPosition, mBounds.extent);
}
}
void GuiArrayCtrl::scrollSelectionTop()
{
scrollCellTop( mSelectedCell );
}
void GuiArrayCtrl::scrollSelectionBottom()
{
scrollCellBottom( mSelectedCell );
}
void GuiArrayCtrl::scrollCellTop( Point2I cell )
{
// Make sure we have a parent:
GuiControl* parent = getParent();
if ( !parent )
return;
// Make sure the cell is valid:
if ( ( cell.x < 0 ) || ( cell.y < 0 ) )
return;
// This is the >desired< new position--let the scroll control decide
// whether it is a reasonable position or not...
Point2I newPos( -( cell.x * mCellSize.x ), -( cell.y * mCellSize.y ) );
resize( newPos, mBounds.extent );
}
void GuiArrayCtrl::scrollCellBottom( Point2I cell )
{
// Make sure we have a parent:
GuiControl* parent = getParent();
if ( !parent )
return;
// Make sure the cell is valid:
if ( ( cell.x < 0 ) || ( cell.y < 0 ) )
return;
// This is the >desired< new position--let the scroll control decide
// whether it is a reasonable position or not...
Point2I newPos( parent->mBounds.extent.x - ( ( cell.x + 1 ) * mCellSize.x ),
parent->mBounds.extent.y - ( ( cell.y + 1 ) * mCellSize.y ) );
resize( newPos, mBounds.extent );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
void GuiArrayCtrl::onRenderColumnHeaders(Point2I offset, Point2I parentOffset, Point2I headerDim)
{
if (mProfile->mBorder)
{
RectI cellR(offset.x + headerDim.x, parentOffset.y, mBounds.extent.x - headerDim.x, headerDim.y);
dglDrawRectFill(cellR, mProfile->mBorderColor);
}
}
void GuiArrayCtrl::onRenderRowHeader(Point2I offset, Point2I parentOffset, Point2I headerDim, Point2I cell)
{
ColorI color;
RectI cellR;
if (cell.x % 2)
color.set(255, 0, 0, 255);
else
color.set(0, 255, 0, 255);
cellR.point.set(parentOffset.x, offset.y);
cellR.extent.set(headerDim.x, mCellSize.y);
dglDrawRectFill(cellR, color);
}
void GuiArrayCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
{
ColorI color(255 * (cell.x % 2), 255 * (cell.y % 2), 255 * ((cell.x + cell.y) % 2), 255);
if (selected)
{
color.set(255, 0, 0, 255);
}
else if (mouseOver)
{
color.set(0, 0, 255, 255);
}
//draw the cell
RectI cellR(offset.x, offset.y, mCellSize.x, mCellSize.y);
dglDrawRectFill(cellR, color);
}
void GuiArrayCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
firstResponder;
//make sure we have a parent
GuiControl *parent = getParent();
if (! parent)
return;
S32 i, j;
RectI headerClip;
RectI clipRect(updateRect.point, updateRect.extent);
Point2I parentOffset = parent->localToGlobalCoord(Point2I(0, 0));
//if we have column headings
if (mHeaderDim.y > 0)
{
headerClip.point.x = parentOffset.x + mHeaderDim.x;
headerClip.point.y = parentOffset.y;
headerClip.extent.x = clipRect.extent.x - headerClip.point.x;
headerClip.extent.y = mHeaderDim.y;
if (headerClip.intersect(clipRect))
{
dglSetClipRect(headerClip);
//now render the header
onRenderColumnHeaders(offset, parentOffset, mHeaderDim);
clipRect.point.y = headerClip.point.y + headerClip.extent.y - 1;
}
offset.y += mHeaderDim.y;
}
//if we have row headings
if (mHeaderDim.x > 0)
{
clipRect.point.x = getMax(clipRect.point.x, parentOffset.x + mHeaderDim.x);
offset.x += mHeaderDim.x;
}
//save the original for clipping the row headers
RectI origClipRect = clipRect;
for (j = 0; j < mSize.y; j++)
{
//skip until we get to a visible row
if ((j + 1) * mCellSize.y + offset.y < updateRect.point.y)
continue;
//break once we've reached the last visible row
if(j * mCellSize.y + offset.y >= updateRect.point.y + updateRect.extent.y)
break;
//render the header
if (mHeaderDim.x > 0)
{
headerClip.point.x = parentOffset.x;
headerClip.extent.x = mHeaderDim.x;
headerClip.point.y = offset.y + j * mCellSize.y;
headerClip.extent.y = mCellSize.y;
if (headerClip.intersect(origClipRect))
{
dglSetClipRect(headerClip);
//render the row header
onRenderRowHeader(Point2I(0, offset.y + j * mCellSize.y),
Point2I(parentOffset.x, offset.y + j * mCellSize.y),
mHeaderDim, Point2I(0, j));
}
}
//render the cells for the row
for (i = 0; i < mSize.x; i++)
{
//skip past columns off the left edge
if ((i + 1) * mCellSize.x + offset.x < updateRect.point.x)
continue;
//break once past the last visible column
if (i * mCellSize.x + offset.x >= updateRect.point.x + updateRect.extent.x)
break;
S32 cellx = offset.x + i * mCellSize.x;
S32 celly = offset.y + j * mCellSize.y;
RectI cellClip(cellx, celly, mCellSize.x, mCellSize.y);
//make sure the cell is within the update region
if (cellClip.intersect(clipRect))
{
//set the clip rect
dglSetClipRect(cellClip);
//render the cell
onRenderCell(Point2I(cellx, celly), Point2I(i, j),
i == mSelectedCell.x && j == mSelectedCell.y,
i == mMouseOverCell.x && j == mMouseOverCell.y);
}
}
}
}
void GuiArrayCtrl::onMouseDown(const GuiEvent &event)
{
if ( !mActive || !mAwake || !mVisible ) return;
//let the guiControl method take care of the rest
Parent::onMouseDown(event);
Point2I pt = globalToLocalCoord(event.mousePoint);
pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
{
//store the previously selected cell
Point2I prevSelected = mSelectedCell;
//select the new cell
cellSelected(Point2I(cell.x, cell.y));
//if we double clicked on the *same* cell, evaluate the altConsole Command
if ( ( event.mouseClickCount > 1 ) && ( prevSelected == mSelectedCell ) && mAltConsoleCommand[0] )
Con::evaluate( mAltConsoleCommand, false );
}
}
void GuiArrayCtrl::onMouseEnter(const GuiEvent &event)
{
Point2I pt = globalToLocalCoord(event.mousePoint);
pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
//get the cell
Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
{
mMouseOverCell = cell;
setUpdateRegion(Point2I(cell.x * mCellSize.x + mHeaderDim.x,
cell.y * mCellSize.y + mHeaderDim.y), mCellSize );
}
}
void GuiArrayCtrl::onMouseLeave(const GuiEvent & /*event*/)
{
setUpdateRegion(Point2I(mMouseOverCell.x * mCellSize.x + mHeaderDim.x,
mMouseOverCell.y * mCellSize.y + mHeaderDim.y), mCellSize);
mMouseOverCell.set(-1,-1);
}
void GuiArrayCtrl::onMouseMove(const GuiEvent &event)
{
Point2I pt = globalToLocalCoord(event.mousePoint);
pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
if (cell.x != mMouseOverCell.x || cell.y != mMouseOverCell.y)
{
if (mMouseOverCell.x != -1)
{
setUpdateRegion(Point2I(mMouseOverCell.x * mCellSize.x + mHeaderDim.x,
mMouseOverCell.y * mCellSize.y + mHeaderDim.y), mCellSize);
}
if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
{
setUpdateRegion(Point2I(cell.x * mCellSize.x + mHeaderDim.x,
cell.y * mCellSize.y + mHeaderDim.y), mCellSize);
mMouseOverCell = cell;
}
else
mMouseOverCell.set(-1,-1);
}
}
bool GuiArrayCtrl::onKeyDown(const GuiEvent &event)
{
//if this control is a dead end, kill the event
if ((! mVisible) || (! mActive) || (! mAwake)) return true;
//get the parent
S32 pageSize = 1;
GuiControl *parent = getParent();
if (parent && mCellSize.y > 0)
{
pageSize = getMax(1, (parent->mBounds.extent.y / mCellSize.y) - 1);
}
Point2I delta(0,0);
switch (event.keyCode)
{
case KEY_LEFT:
delta.set(-1, 0);
break;
case KEY_RIGHT:
delta.set(1, 0);
break;
case KEY_UP:
delta.set(0, -1);
break;
case KEY_DOWN:
delta.set(0, 1);
break;
case KEY_PAGE_UP:
delta.set(0, -pageSize);
break;
case KEY_PAGE_DOWN:
delta.set(0, pageSize);
break;
case KEY_HOME:
cellSelected( Point2I( 0, 0 ) );
return( true );
case KEY_END:
cellSelected( Point2I( 0, mSize.y - 1 ) );
return( true );
default:
return Parent::onKeyDown(event);
}
if (mSize.x < 1 || mSize.y < 1)
return true;
//select the first cell if no previous cell was selected
if (mSelectedCell.x == -1 || mSelectedCell.y == -1)
{
cellSelected(Point2I(0,0));
return true;
}
//select the cell
Point2I cell = mSelectedCell;
cell.x = getMax(0, getMin(mSize.x - 1, cell.x + delta.x));
cell.y = getMax(0, getMin(mSize.y - 1, cell.y + delta.y));
cellSelected(cell);
return true;
}
void GuiArrayCtrl::onRightMouseDown(const GuiEvent &event)
{
if ( !mActive || !mAwake || !mVisible )
return;
Parent::onRightMouseDown( event );
Point2I pt = globalToLocalCoord( event.mousePoint );
pt.x -= mHeaderDim.x; pt.y -= mHeaderDim.y;
Point2I cell((pt.x < 0 ? -1 : pt.x / mCellSize.x), (pt.y < 0 ? -1 : pt.y / mCellSize.y));
if (cell.x >= 0 && cell.x < mSize.x && cell.y >= 0 && cell.y < mSize.y)
{
char buf[32];
dSprintf( buf, sizeof( buf ), "%d %d", event.mousePoint.x, event.mousePoint.y );
// Pass it to the console:
Con::executef(this, 4, "onRightMouseDown", Con::getIntArg(cell.x), Con::getIntArg(cell.y), buf);
}
}

76
gui/guiArrayCtrl.h Normal file
View file

@ -0,0 +1,76 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIARRAYCTRL_H_
#define _GUIARRAYCTRL_H_
#ifndef _GUITYPES_H_
#include "GUI/guiTypes.h"
#endif
#ifndef _GUITEXTCTRL_H_
#include "GUI/guiTextCtrl.h"
#endif
class GuiArrayCtrl : public GuiControl
{
typedef GuiControl Parent;
protected:
Point2I mHeaderDim;
Point2I mSize;
Point2I mCellSize;
Point2I mSelectedCell;
Point2I mMouseOverCell;
Resource<GFont> mFont;
bool cellSelected(Point2I cell);
virtual void onCellSelected(Point2I cell);
public:
GuiArrayCtrl();
DECLARE_CONOBJECT(GuiArrayCtrl);
bool onWake();
void onSleep();
//array attribute methods
Point2I getSize() { return mSize; }
virtual void setSize(Point2I size);
void setHeaderDim(const Point2I &dim) { mHeaderDim = dim; }
void getScrollDimensions(S32 &cell_size, S32 &num_cells);
//selected cell methods
void setSelectedCell(Point2I cell);
void deselectCells() { mSelectedCell.set(-1,-1); }
Point2I getSelectedCell();
void scrollSelectionVisible();
void scrollCellVisible(Point2I cell);
void scrollSelectionTop();
void scrollSelectionBottom();
void scrollCellTop(Point2I cell);
void scrollCellBottom(Point2I cell);
//rendering methods
virtual void onRenderColumnHeaders(Point2I offset, Point2I parentOffset, Point2I headerDim);
virtual void onRenderRowHeader(Point2I offset, Point2I parentOffset, Point2I headerDim, Point2I cell);
virtual void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
//void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
//mouse input methods
void onMouseDown(const GuiEvent &event);
void onMouseMove(const GuiEvent &event);
void onMouseEnter(const GuiEvent &event);
void onMouseLeave(const GuiEvent &event);
bool onKeyDown(const GuiEvent &event);
void onRightMouseDown(const GuiEvent &event);
};
#endif //_GUI_ARRAY_CTRL_H

1387
gui/guiAviBitmapCtrl.cc Normal file

File diff suppressed because it is too large Load diff

190
gui/guiAviBitmapCtrl.h Normal file
View file

@ -0,0 +1,190 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIAVIBITMAPCTRL_H_
#define _GUIAVIBITMAPCTRL_H_
#if !ENABLE_AVI_GUI && !ENABLE_MPG_GUI
class GuiAviBitmapCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
bool mDone;
public:
DECLARE_CONOBJECT(GuiAviBitmapCtrl);
GuiAviBitmapCtrl();
~GuiAviBitmapCtrl();
static void initPersistFields();
};
#endif /* No movie control */
#if ENABLE_AVI_GUI
class GuiAviBitmapCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
StringTableEntry mAviFilename;
StringTableEntry mWavFilename;
U32 mNumTextures;
TextureHandle *mTextureHandles;
U32 mWidthCount;
U32 mHeightCount;
U32 mBitmapWidth;
U32 mBitmapAlignedWidth;
U32 mBitmapHeight;
PAVIFILE mPFile;
PAVISTREAM mPAviVideo; // video stream to play
AUDIOHANDLE mWavHandle; // music to play along with it
bool mBPlaying;
bool mDone;
bool mLetterBox;
F32 mFrate;
F32 mSpeed;
S32 mTimePlayStart;
S32 mTimePlayStartPos;
S16 mPlayFPrev;
S16 mPlayFSkipped;
S32 mVidsCurrent; // attempted frame to draw
S32 mVidsPrevious; // last successfully decoded frame
S32 mVidsPrevKey, mVidsNextKey;
S32 mVidsFirst, mVidsLast;
S32 mCBVBuf;
U8 *mPVBuf;
HIC mHic;
FOURCC mFccHandler;
BITMAPINFOHEADER *mPBiSrc;
BITMAPINFOHEADER *mPBiDst;
S32 mCBuf;
U8 *mPBuf;
bool mSwapRB;
ALint mAudioLatency;
S32 fileOpen();
S32 fileClose();
S32 movieOpen();
S32 movieClose();
S32 vidsVideoOpen();
S32 vidsVideoClose();
S32 vidsVideoStart();
S32 vidsVideoStop();
S32 vidsVideoDraw();
S32 vidsTimeToSample(S32 lTime);
bool vidsIsKey(S32 frame = -1);
void vidsResetDraw() { mVidsPrevious = -1; }
bool vidsSync();
void vidsCatchup();
S32 vcmOpen(FOURCC fccHandler, BITMAPINFOHEADER *pbiSrc);
S32 vcmClose();
S32 vcmBegin();
S32 vcmEnd();
S32 vcmDrawStart();
S32 vcmDrawStop();
S32 vcmDraw(U64 dwICflags = 0);
S32 vcmDrawIn(U64 dwICflags = 0);
bool sndOpen();
void sndStart();
void sndStop();
S32 getMilliseconds();
public:
DECLARE_CONOBJECT(GuiAviBitmapCtrl);
GuiAviBitmapCtrl();
~GuiAviBitmapCtrl();
static void consoleInit();
static void initPersistFields();
void setFilename(const char *filename);
S32 movieStart();
S32 movieStop();
bool onWake();
void onSleep();
void onMouseDown(const GuiEvent&);
bool onKeyDown(const GuiEvent&);
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
};
#endif /* ENABLE_AVI_GUI */
#if ENABLE_MPG_GUI
class GuiAviBitmapCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
StringTableEntry mAviFilename;
StringTableEntry mWavFilename;
U32 mNumTextures;
TextureHandle *mTextureHandles;
U32 mWidthCount;
U32 mHeightCount;
U32 mBitmapWidth;
U32 mBitmapAlignedWidth;
U32 mBitmapHeight;
SDL_Surface *mSurface;
U8 *mPBuf;
SDL_mutex *mDecodeLock;
ALint mAudioLatency;
SMPEG *mMPEG; // video stream to play
AUDIOHANDLE mWavHandle; // music to play along with it
bool mBPlaying;
bool mDone;
bool mLetterBox;
SMPEG_Info mInfo;
S32 fileOpen();
S32 fileClose();
S32 movieOpen();
S32 movieClose();
bool sndOpen();
void sndStart();
void sndStop();
public:
DECLARE_CONOBJECT(GuiAviBitmapCtrl);
GuiAviBitmapCtrl();
~GuiAviBitmapCtrl();
static void consoleInit();
static void initPersistFields();
void setFilename(const char *filename);
S32 movieStart();
S32 movieStop();
bool onWake();
void onSleep();
void onMouseDown(const GuiEvent&);
bool onKeyDown(const GuiEvent&);
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
};
#endif /* ENABLE_MPG_GUI */
#endif /* _GUIAVIBITMAPCTRL_H_ */

26
gui/guiBackgroundCtrl.cc Normal file
View file

@ -0,0 +1,26 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "gui/guiBackgroundCtrl.h"
//--------------------------------------------------------------------------
GuiBackgroundCtrl::GuiBackgroundCtrl() : GuiControl()
{
mDraw = false;
}
//--------------------------------------------------------------------------
void GuiBackgroundCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
if ( mDraw )
Parent::onRender( offset, updateRect, firstResponder );
renderChildControls(offset, updateRect, firstResponder);
}

30
gui/guiBackgroundCtrl.h Normal file
View file

@ -0,0 +1,30 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIBACKGROUNDCTRL_H_
#define _GUIBACKGROUNDCTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/guiControl.h"
#endif
class GuiBackgroundCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
public:
bool mDraw;
//creation methods
DECLARE_CONOBJECT(GuiBackgroundCtrl);
GuiBackgroundCtrl();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
};
#endif

120
gui/guiBitmapBorderCtrl.cc Normal file
View file

@ -0,0 +1,120 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
//
// Copyright (c) 2002 GarageGames.Com
//-----------------------------------------------------------------------------
#include "gui/guiControl.h"
#include "dgl/dgl.h"
class GuiBitmapBorderCtrl : public GuiControl
{
typedef GuiControl Parent;
enum {
BorderTopLeft,
BorderTopRight,
BorderTop,
BorderLeft,
BorderRight,
BorderBottomLeft,
BorderBottom,
BorderBottomRight,
NumBitmaps
};
RectI *mBitmapBounds; //bmp is [3*n], bmpHL is [3*n + 1], bmpNA is [3*n + 2]
TextureHandle mTextureHandle;
public:
bool onWake();
void onSleep();
void onRender(Point2I offset, const RectI &updateRect);
DECLARE_CONOBJECT(GuiBitmapBorderCtrl);
};
IMPLEMENT_CONOBJECT(GuiBitmapBorderCtrl);
bool GuiBitmapBorderCtrl::onWake()
{
if (! Parent::onWake())
return false;
//get the texture for the close, minimize, and maximize buttons
mTextureHandle = mProfile->mTextureHandle;
bool result = mProfile->constructBitmapArray() >= NumBitmaps;
AssertFatal(result, "Failed to create the bitmap array");
if(!result)
return false;
mBitmapBounds = mProfile->mBitmapArrayRects.address();
return true;
}
void GuiBitmapBorderCtrl::onSleep()
{
mTextureHandle = NULL;
Parent::onSleep();
}
void GuiBitmapBorderCtrl::onRender(Point2I offset, const RectI &updateRect)
{
renderChildControls( offset, updateRect );
dglSetClipRect(updateRect);
//draw the outline
RectI winRect;
winRect.point = offset;
winRect.extent = mBounds.extent;
winRect.point.x += mBitmapBounds[BorderLeft].extent.x;
winRect.point.y += mBitmapBounds[BorderTop].extent.y;
winRect.extent.x -= mBitmapBounds[BorderLeft].extent.x + mBitmapBounds[BorderRight].extent.x;
winRect.extent.y -= mBitmapBounds[BorderTop].extent.y + mBitmapBounds[BorderBottom].extent.y;
if(mProfile->mOpaque)
dglDrawRectFill(winRect, mProfile->mFillColor);
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, offset, mBitmapBounds[BorderTopLeft]);
dglDrawBitmapSR(mTextureHandle, Point2I(offset.x + mBounds.extent.x - mBitmapBounds[BorderTopRight].extent.x, offset.y),
mBitmapBounds[BorderTopRight]);
RectI destRect;
destRect.point.x = offset.x + mBitmapBounds[BorderTopLeft].extent.x;
destRect.point.y = offset.y;
destRect.extent.x = mBounds.extent.x - mBitmapBounds[BorderTopLeft].extent.x - mBitmapBounds[BorderTopRight].extent.x;
destRect.extent.y = mBitmapBounds[BorderTop].extent.y;
RectI stretchRect = mBitmapBounds[BorderTop];
stretchRect.inset(1,0);
dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
destRect.point.x = offset.x;
destRect.point.y = offset.y + mBitmapBounds[BorderTopLeft].extent.y;
destRect.extent.x = mBitmapBounds[BorderLeft].extent.x;
destRect.extent.y = mBounds.extent.y - mBitmapBounds[BorderTopLeft].extent.y - mBitmapBounds[BorderBottomLeft].extent.y;
stretchRect = mBitmapBounds[BorderLeft];
stretchRect.inset(0,1);
dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
destRect.point.x = offset.x + mBounds.extent.x - mBitmapBounds[BorderRight].extent.x;
destRect.extent.x = mBitmapBounds[BorderRight].extent.x;
destRect.point.y = offset.y + mBitmapBounds[BorderTopRight].extent.y;
destRect.extent.y = mBounds.extent.y - mBitmapBounds[BorderTopRight].extent.y - mBitmapBounds[BorderBottomRight].extent.y;
stretchRect = mBitmapBounds[BorderRight];
stretchRect.inset(0,1);
dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
dglDrawBitmapSR(mTextureHandle, offset + Point2I(0, mBounds.extent.y - mBitmapBounds[BorderBottomLeft].extent.y), mBitmapBounds[BorderBottomLeft]);
dglDrawBitmapSR(mTextureHandle, offset + mBounds.extent - mBitmapBounds[BorderBottomRight].extent, mBitmapBounds[BorderBottomRight]);
destRect.point.x = offset.x + mBitmapBounds[BorderBottomLeft].extent.x;
destRect.extent.x = mBounds.extent.x - mBitmapBounds[BorderBottomLeft].extent.x - mBitmapBounds[BorderBottomRight].extent.x;
destRect.point.y = offset.y + mBounds.extent.y - mBitmapBounds[BorderBottom].extent.y;
destRect.extent.y = mBitmapBounds[BorderBottom].extent.y;
stretchRect = mBitmapBounds[BorderBottom];
stretchRect.inset(1,0);
dglDrawBitmapStretchSR(mTextureHandle, destRect, stretchRect);
}

148
gui/guiBitmapCtrl.cc Normal file
View file

@ -0,0 +1,148 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "GUI/guiBitmapCtrl.h"
GuiBitmapCtrl::GuiBitmapCtrl(void)
{
mBitmapName = StringTable->insert("");
startPoint.set(0, 0);
mWrap = false;
}
void GuiBitmapCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("bitmap", TypeString, Offset(mBitmapName, GuiBitmapCtrl));
addField("wrap", TypeBool, Offset(mWrap, GuiBitmapCtrl));
}
static void cBitmapSetValue(SimObject *obj, S32, const char **argv)
{
GuiBitmapCtrl *ctrl = static_cast<GuiBitmapCtrl*>(obj);
ctrl->setValue(dAtoi(argv[2]), dAtoi(argv[3]));
}
static void cBitmapSetBitmap(SimObject *obj, S32, const char **argv)
{
GuiBitmapCtrl *ctrl = static_cast<GuiBitmapCtrl*>(obj);
ctrl->setBitmap(argv[2]);
}
void GuiBitmapCtrl::consoleInit()
{
Con::addCommand("GuiBitmapCtrl", "setBitmap", cBitmapSetBitmap, "guiBitmapCtrl.setBitmap(blah)", 3, 3);
Con::addCommand("GuiBitmapCtrl", "setValue", cBitmapSetValue, "guiBitmapCtrl.setValue(xAxis, yAxis)", 4, 4);
}
bool GuiBitmapCtrl::onWake()
{
if (! Parent::onWake())
return false;
setActive(true);
setBitmap(mBitmapName);
return true;
}
void GuiBitmapCtrl::onSleep()
{
mTextureHandle = NULL;
Parent::onSleep();
}
void GuiBitmapCtrl::setBitmap(const char *name)
{
mBitmapName = StringTable->insert(name);
if (*mBitmapName)
mTextureHandle = TextureHandle(mBitmapName, BitmapTexture, true);
else
mTextureHandle = NULL;
setUpdate();
}
void GuiBitmapCtrl::setBitmap(const TextureHandle &handle)
{
mTextureHandle = handle;
}
void GuiBitmapCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
if (mTextureHandle)
{
dglClearBitmapModulation();
if(mWrap)
{
TextureObject* texture = (TextureObject *) mTextureHandle;
RectI srcRegion;
RectI dstRegion;
float xdone = ((float)mBounds.extent.x/(float)texture->bitmapWidth)+1;
float ydone = ((float)mBounds.extent.y/(float)texture->bitmapHeight)+1;
int xshift = startPoint.x%texture->bitmapWidth;
int yshift = startPoint.y%texture->bitmapHeight;
for(int y = 0; y < ydone; ++y)
for(int x = 0; x < xdone; ++x)
{
srcRegion.set(0,0,texture->bitmapWidth,texture->bitmapHeight);
dstRegion.set( ((texture->bitmapWidth*x)+offset.x)-xshift,
((texture->bitmapHeight*y)+offset.y)-yshift,
texture->bitmapWidth,
texture->bitmapHeight);
dglDrawBitmapStretchSR(texture,dstRegion, srcRegion, false);
}
}
else
{
RectI rect(offset, mBounds.extent);
// RectI rect = mBounds;
// rect.point += offset;
dglDrawBitmapStretch(mTextureHandle, rect);
}
}
else
{
RectI rect = mBounds;
rect.point += offset;
glColor4f(0, 0, 0, 1);
glBegin(GL_LINE_LOOP);
glVertex2i(rect.point.x, rect.point.y);
glVertex2i(rect.point.x + rect.extent.x - 1, rect.point.y);
glVertex2i(rect.point.x + rect.extent.x - 1, rect.point.y + rect.extent.y - 1);
glVertex2i(rect.point.x, rect.point.y + rect.extent.y - 1);
glEnd();
}
renderChildControls(offset, updateRect, firstResponder);
}
void GuiBitmapCtrl::setValue(S32 x, S32 y)
{
if (mTextureHandle)
{
TextureObject* texture = (TextureObject *) mTextureHandle;
x+=texture->bitmapWidth/2;
y+=texture->bitmapHeight/2;
}
while (x < 0)
x += 256;
startPoint.x = x % 256;
while (y < 0)
y += 256;
startPoint.y = y % 256;
}

50
gui/guiBitmapCtrl.h Normal file
View file

@ -0,0 +1,50 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIBITMAPCTRL_H_
#define _GUIBITMAPCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
class GuiBitmapCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
StringTableEntry mBitmapName;
TextureHandle mTextureHandle;
Point2I startPoint;
bool mWrap;
public:
//creation methods
DECLARE_CONOBJECT(GuiBitmapCtrl);
GuiBitmapCtrl();
static void initPersistFields();
static void consoleInit();
//Parental methods
bool onWake();
void onSleep();
void setBitmap(const char *name);
void setBitmap(const TextureHandle &handle);
S32 getWidth() const { return(mTextureHandle.getWidth()); }
S32 getHeight() const { return(mTextureHandle.getHeight()); }
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void setValue(S32 x, S32 y);
};
#endif

42
gui/guiBorderButton.cc Normal file
View file

@ -0,0 +1,42 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
//
// Copyright (c) 2001 GarageGames.Com
//-----------------------------------------------------------------------------
#include "dgl/dgl.h"
#include "gui/guiCanvas.h"
#include "gui/guiButtonBaseCtrl.h"
class GuiBorderButtonCtrl : public GuiButtonBaseCtrl
{
typedef GuiButtonBaseCtrl Parent;
protected:
public:
DECLARE_CONOBJECT(GuiBorderButtonCtrl);
void onRender(Point2I offset, const RectI &updateRect);
};
IMPLEMENT_CONOBJECT(GuiBorderButtonCtrl);
void GuiBorderButtonCtrl::onRender(Point2I offset, const RectI &updateRect)
{
RectI bounds(offset, mBounds.extent);
if(mActive && mMouseOver)
{
bounds.inset(2,2);
dglDrawRect(bounds, mProfile->mFontColorHL);
bounds.inset(-2,-2);
}
if(mActive && (mStateOn || mDepressed))
{
dglDrawRect(bounds, mProfile->mFontColorHL);
bounds.inset(1,1);
dglDrawRect(bounds, mProfile->mFontColorHL);
}
renderChildControls(offset, updateRect);
}

73
gui/guiBubbleTextCtrl.cc Normal file
View file

@ -0,0 +1,73 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/guiBubbleTextCtrl.h"
#include "GUI/guiCanvas.h"
IMPLEMENT_CONOBJECT(GuiBubbleTextCtrl);
//------------------------------------------------------------------------------
void GuiBubbleTextCtrl::popBubble()
{
// Release the mouse:
mInAction = false;
mouseUnlock();
// Pop the dialog
getRoot()->popDialogControl(mDlg);
// Kill the popup
mDlg->removeObject(mPopup);
mPopup->removeObject(mMLText);
mMLText->deleteObject();
mPopup->deleteObject();
mDlg->deleteObject();
}
//------------------------------------------------------------------------------
void GuiBubbleTextCtrl::onMouseDown(const GuiEvent &event)
{
if (mInAction)
{
popBubble();
return;
}
mDlg = new GuiControl();
AssertFatal(mDlg, "Failed to create the GuiControl for the BubbleTextCtrl");
mDlg->setField("profile","GuiModelessDialogProfile");
mDlg->setField("horizSizing", "width");
mDlg->setField("vertSizing", "height");
mDlg->setField("extent", "640 480");
mPopup = new GuiControl();
AssertFatal(mPopup, "Failed to create the GuiControl for the BubbleTextCtrl");
mPopup->setField("profile","GuiBubblePopupProfile");
mMLText = new GuiMLTextCtrl();
AssertFatal(mMLText, "Failed to create the GuiMLTextCtrl for the BubbleTextCtrl");
mMLText->setField("profile","GuiBubbleTextProfile");
mMLText->setField("position", "2 2");
mMLText->setField("extent", "296 51");
mMLText->setText(mText,dStrlen(mText));
mMLText->registerObject();
mPopup->registerObject();
mDlg->registerObject();
mPopup->addObject(mMLText);
mDlg->addObject(mPopup);
mPopup->resize(event.mousePoint,Point2I(300,55));
getRoot()->pushDialogControl(mDlg,0);
mouseLock();
mInAction = true;
}

39
gui/guiBubbleTextCtrl.h Normal file
View file

@ -0,0 +1,39 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIBUBBLETEXTCTRL_H_
#define _GUIBUBBLETEXTCTRL_H_
#ifndef _GUITEXTCTRL_H_
#include "GUI/guiTextCtrl.h"
#endif
#ifndef _GUIMLTEXTCTRL_H_
#include "GUI/guiMLTextCtrl.h"
#endif
class GuiBubbleTextCtrl : public GuiTextCtrl
{
private:
typedef GuiTextCtrl Parent;
protected:
bool mInAction;
GuiControl *mDlg;
GuiControl *mPopup;
GuiMLTextCtrl *mMLText;
void popBubble();
public:
DECLARE_CONOBJECT(GuiBubbleTextCtrl);
GuiBubbleTextCtrl() { mInAction = false; }
virtual void onMouseDown(const GuiEvent &event);
};
#endif /* _GUI_BUBBLE_TEXT_CONTROL_H_ */

189
gui/guiButtonBaseCtrl.cc Normal file
View file

@ -0,0 +1,189 @@
//-----------------------------------------------------------------------------
// Torque Engine
//
// Copyright (c) 2001 GarageGames.Com
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "dgl/dgl.h"
#include "console/consoleTypes.h"
#include "platform/platformAudio.h"
#include "gui/guiCanvas.h"
#include "gui/guiButtonBaseCtrl.h"
GuiButtonBaseCtrl::GuiButtonBaseCtrl()
{
mDepressed = false;
mMouseOver = false;
mActive = true;
mButtonText = StringTable->insert("");
}
ConsoleMethod( GuiButtonBaseCtrl, setText, void, 3, 3, "(string text) - sets the text of the button to the string." )
{
argc;
GuiButtonBaseCtrl* ctrl = static_cast<GuiButtonBaseCtrl*>( object );
ctrl->setText( argv[2] );
}
ConsoleMethod( GuiButtonBaseCtrl, getText, const char *, 2, 2, "() - returns the text of the button." )
{
argc; argv;
GuiButtonBaseCtrl* ctrl = static_cast<GuiButtonBaseCtrl*>( object );
return ctrl->getText( );
}
void GuiButtonBaseCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("text", TypeCaseString, Offset(mButtonText, GuiButtonBaseCtrl));
}
void GuiButtonBaseCtrl::setText(const char *text)
{
mButtonText = StringTable->insert(text);
}
const char *GuiButtonBaseCtrl::getText()
{
return mButtonText;
}
//---------------------------------------------------------------------------
void GuiButtonBaseCtrl::AcceleratorKeyPress(void)
{
if (! mActive)
return;
//set the bool
mDepressed = true;
if (mProfile->mTabable)
setFirstResponder();
}
//---------------------------------------------------------------------------
void GuiButtonBaseCtrl::AcceleratorKeyRelease(void)
{
if (! mActive)
return;
//set the bool
mDepressed = false;
//perform the action
onAction();
//update
setUpdate();
}
void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
{
if (! mActive)
return;
if (mProfile->mCanKeyFocus)
setFirstResponder();
if (mProfile->mSoundButtonDown)
{
F32 pan = (F32(event.mousePoint.x)/F32(Canvas->mBounds.extent.x)*2.0f-1.0f)*0.8f;
AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonDown);
alxPlay(handle);
}
//lock the mouse
mouseLock();
mDepressed = true;
//update
setUpdate();
}
void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent &event)
{
setUpdate();
if(isMouseLocked())
{
mDepressed = true;
mMouseOver = true;
}
else
{
if ( mActive && mProfile->mSoundButtonOver )
{
F32 pan = (F32(event.mousePoint.x)/F32(Canvas->mBounds.extent.x)*2.0f-1.0f)*0.8f;
AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonOver);
alxPlay(handle);
}
mMouseOver = true;
}
}
void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent &)
{
setUpdate();
if(isMouseLocked())
mDepressed = false;
mMouseOver = false;
}
void GuiButtonBaseCtrl::onMouseUp(const GuiEvent &)
{
if (! mActive)
return;
mouseUnlock();
setUpdate();
//if we released the mouse within this control, perform the action
if (mDepressed)
onAction();
mDepressed = false;
}
//--------------------------------------------------------------------------
bool GuiButtonBaseCtrl::onKeyDown(const GuiEvent &event)
{
//if the control is a dead end, kill the event
if (!mActive)
return true;
//see if the key down is a return or space or not
if ((event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE)
&& event.modifier == 0)
{
if ( mProfile->mSoundButtonDown )
{
F32 pan = ( F32( event.mousePoint.x ) / F32( Canvas->mBounds.extent.x ) * 2.0f - 1.0f ) * 0.8f;
AUDIOHANDLE handle = alxCreateSource( mProfile->mSoundButtonDown );
alxPlay( handle );
}
return true;
}
//otherwise, pass the event to it's parent
return Parent::onKeyDown(event);
}
//--------------------------------------------------------------------------
bool GuiButtonBaseCtrl::onKeyUp(const GuiEvent &event)
{
//if the control is a dead end, kill the event
if (!mActive)
return true;
//see if the key down is a return or space or not
if ((event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE)
&& event.modifier == 0)
{
onAction();
return true;
}
//otherwise, pass the event to it's parent
return Parent::onKeyDown(event);
}

42
gui/guiButtonBaseCtrl.h Normal file
View file

@ -0,0 +1,42 @@
//-----------------------------------------------------------------------------
// Torque Engine
//
// Copyright (c) 2001 GarageGames.Com
//-----------------------------------------------------------------------------
#ifndef _GUIBUTTONBASECTRL_H_
#define _GUIBUTTONBASECTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/guiControl.h"
#endif
class GuiButtonBaseCtrl : public GuiControl
{
typedef GuiControl Parent;
protected:
StringTableEntry mButtonText;
bool mDepressed;
bool mMouseOver;
public:
GuiButtonBaseCtrl();
static void initPersistFields();
void setText(const char *text);
const char *getText();
void AcceleratorKeyPress();
void AcceleratorKeyRelease();
void onMouseDown(const GuiEvent &);
void onMouseUp(const GuiEvent &);
void onMouseEnter(const GuiEvent &);
void onMouseLeave(const GuiEvent &);
bool onKeyDown(const GuiEvent &event);
bool onKeyUp(const GuiEvent &event);
};
#endif

262
gui/guiButtonCtrl.cc Normal file
View file

@ -0,0 +1,262 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "dgl/dgl.h"
#include "console/consoleTypes.h"
#include "Platform/platformAudio.h"
#include "audio/audioDataBlock.h"
#include "GUI/guiCanvas.h"
#include "GUI/guiButtonCtrl.h"
GuiButtonCtrl::GuiButtonCtrl()
{
mActive = true;
mBounds.extent.set(140, 30);
mButtonText = 0;
mButtonState = Normal;
mMouseInControl = false;
}
void GuiButtonCtrl::consoleInit()
{
}
void GuiButtonCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("text", TypeCaseString, Offset(mButtonText, GuiButtonCtrl));
}
const char * GuiButtonCtrl::getScriptValue()
{
return(mButtonText);
}
void GuiButtonCtrl::setScriptValue(const char * value)
{
mButtonText = StringTable->insert(value);
}
//--------------------------------------------------------------------------
void GuiButtonCtrl::AcceleratorKeyPress(void)
{
if ((! mVisible) || (! mActive) || (! mAwake))
return;
onAction();
setFirstResponder();
}
//--------------------------------------------------------------------------
bool GuiButtonCtrl::onKeyDown(const GuiEvent &event)
{
//if the control is a dead end, kill the event
if ((! mVisible) || (! mActive) || (! mAwake))
return true;
//see if the key down is a return or space or not
if ((event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE)
&& event.modifier == 0)
{
if ( mProfile->mSoundButtonDown )
{
F32 pan = ( F32( event.mousePoint.x ) / F32( Canvas->mBounds.extent.x ) * 2.0f - 1.0f ) * 0.8f;
AUDIOHANDLE handle = alxCreateSource( mProfile->mSoundButtonDown );
alxSourcef( handle, AL_PAN, pan );
alxPlay( handle );
}
onAction();
return true;
}
//otherwise, pass the event to it's parent
return Parent::onKeyDown(event);
}
//--------------------------------------------------------------------------
void GuiButtonCtrl::onMouseDown(const GuiEvent &event)
{
// Are we answering the phone?
if (!mVisible || !mActive || !mAwake)
return;
// Ok, this is a bona-fide real click. Check our preconditions
AssertFatal(mButtonState == Normal, "Error, we should never reach this state!");
setFirstResponder();
mButtonState = MouseDown;
getRoot()->mouseLock(this);
if (mProfile->mSoundButtonDown)
{
F32 pan = (F32(event.mousePoint.x)/F32(Canvas->mBounds.extent.x)*2.0f-1.0f)*0.8f;
AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonDown);
alxSourcef(handle, AL_PAN, pan);
alxPlay(handle);
//alxPlay(mProfile->mSoundButtonDown, NULL, NULL);
//Audio::play2D(mProfile->mSoundButtonDown->getName(), mProfile->mSoundButtonDown->getDescription(), pan);
}
setUpdate();
}
//--------------------------------------------------------------------------
void GuiButtonCtrl::onMouseUp(const GuiEvent&)
{
GuiCanvas* root = getRoot();
if (mButtonState == Normal) {
AssertFatal(root->getMouseLockedControl() != this, "Error, we should not have the mouse locked here!");
return;
}
mButtonState = Normal;
setUpdate();
root->mouseUnlock(this);
if (cursorInControl())
onAction();
}
//--------------------------------------------------------------------------
void GuiButtonCtrl::onMouseEnter(const GuiEvent& event)
{
mMouseInControl = true;
if ( mActive && mProfile->mSoundButtonOver )
{
F32 pan = (F32(event.mousePoint.x)/F32(Canvas->mBounds.extent.x)*2.0f-1.0f)*0.8f;
AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonOver);
alxSourcef(handle, AL_PAN, pan);
alxPlay(handle);
//alxPlay(mProfile->mSoundButtonOver, NULL, NULL);
//Audio::play2D(mProfile->mSoundButtonOver->getName(), mProfile->mSoundButtonOver->getDescription(), pan);
}
Parent::onMouseEnter( event );
setUpdate();
}
//--------------------------------------------------------------------------
void GuiButtonCtrl::onMouseLeave(const GuiEvent& event)
{
mMouseInControl = false;
Parent::onMouseLeave(event);
setUpdate();
}
//--------------------------------------------------------------------------
void GuiButtonCtrl::onSleep()
{
mMouseInControl = false;
mButtonState = Normal;
Parent::onSleep();
}
//--------------------------------------------------------------------------
void GuiButtonCtrl::onRender(Point2I offset,
const RectI& updateRect,
GuiControl* firstResponder)
{
bool highlight = false;
bool depressed = false;
if ( mActive )
{
if ( mButtonState == MouseDown )
{
highlight = true;
depressed = cursorInControl();
}
else
highlight = mMouseInControl;
}
ColorI fontColor = mActive ? (highlight ? mProfile->mFontColorHL : mProfile->mFontColor) : mProfile->mFontColorNA;
ColorI backColor = mActive ? mProfile->mFillColor : mProfile->mFillColorNA;
ColorI borderColor = mActive ? mProfile->mBorderColor : mProfile->mBorderColorNA;
#if 1
// first draw the background
Point2I extent( offset.x+mBounds.extent.x-1, offset.y+mBounds.extent.y-1);
if ( mProfile->mOpaque )
{
if (depressed)
renderLoweredBox(offset, extent, backColor);
else
renderRaisedBox(offset, extent, backColor);
}
else
if ( mProfile->mBorder )
dglDrawRect( offset, Point2I(extent.x+1, extent.y+1), backColor );
#else
// first draw the background
RectI r( offset, mBounds.extent );
if ( mProfile->mOpaque )
dglDrawRectFill( r, backColor );
if ( mProfile->mBorder )
{
dglDrawRect( r, borderColor );
if ( mActive && firstResponder == this )
{
r.point += Point2I(1, 1);
r.extent -= Point2I(2, 2);
dglDrawRect( r, mProfile->mBorderColorHL );
}
}
#endif
// finally draw the text
if ( mButtonText && mButtonText[0] != NULL )
{
S32 txt_w = mProfile->mFont->getStrWidth( mButtonText );
Point2I localStart;
// align the horizontal
switch (mProfile->mAlignment)
{
case GuiControlProfile::RightJustify:
localStart.x = mBounds.extent.x - txt_w;
break;
case GuiControlProfile::CenterJustify:
localStart.x = ( mBounds.extent.x - txt_w ) / 2;
break;
default:
// GuiControlProfile::LeftJustify
localStart.x = 0;
break;
}
// center the vertical
localStart.y = ( mBounds.extent.y - ( mProfile->mFont->getHeight() - 2 ) ) / 2;
localStart.y -= 2;
if ( depressed )
{
localStart.x += 1;
localStart.y += 1;
}
Point2I globalStart = localToGlobalCoord( localStart );
dglSetBitmapModulation( fontColor );
dglDrawText(mProfile->mFont, globalStart, mButtonText, mProfile->mFontColors);
//render the children
renderChildControls( offset, updateRect, firstResponder );
}
}

54
gui/guiButtonCtrl.h Normal file
View file

@ -0,0 +1,54 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIBUTTONCTRL_H_
#define _GUIBUTTONCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
class GuiButtonCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
enum State {
Normal,
MouseDown
};
bool mMouseInControl;
State mButtonState;
StringTableEntry mButtonText;
public:
DECLARE_CONOBJECT(GuiButtonCtrl);
GuiButtonCtrl();
static void consoleInit();
static void initPersistFields();
void AcceleratorKeyPress(void);
bool onKeyDown(const GuiEvent&);
void onMouseUp(const GuiEvent&);
void onMouseDown(const GuiEvent&);
void onMouseEnter(const GuiEvent&);
void onMouseLeave(const GuiEvent&);
const char * getScriptValue();
void setScriptValue(const char *);
void onSleep();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void drawBorder(const RectI &r, const ColorI &color);
};
#endif //_GUI_BUTTON_CTRL_H

1260
gui/guiCanvas.cc Normal file

File diff suppressed because it is too large Load diff

147
gui/guiCanvas.h Normal file
View file

@ -0,0 +1,147 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUICANVAS_H_
#define _GUICANVAS_H_
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _EVENT_H_
#include "Platform/event.h"
#endif
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
class GuiCanvas : public GuiControl
{
private:
typedef GuiControl Parent;
typedef SimObject Grandparent;
//Rendering members
RectI mOldUpdateRects[2];
RectI mCurUpdateRect;
F32 rLastFrameTime;
public:
private:
//Mouse members
F32 mPixelsPerMickey;
bool cursorON;
bool mShowCursor;
bool mRenderFront;
Point2F cursorPt;
Point2I lastCursorPt;
GuiCursor *defaultCursor;
GuiCursor *lastCursor;
bool lastCursorON;
//Input Members - mouse
SimObjectPtr<GuiControl> mMouseCapturedControl; // All mouse events will go to this ctrl only
SimObjectPtr<GuiControl> mMouseControl; // the control the mouse was last seen in unless some other on captured it
bool mMouseControlClicked; // whether the current ctrl has been clicked - used by helpctrl
U32 mPrevMouseTime; // this determines how long the mouse has been in the same control
U32 mNextMouseTime; // used for onMouseRepeat()
U32 mInitialMouseDelay; // also used for onMouseRepeat()
bool mMouseButtonDown; // bool to determine if the button is depressed
bool mMouseRightButtonDown; // bool to determine if the right button is depressed
GuiEvent mLastMouseEvent;
//Input Members - keyboard
GuiControl *keyboardControl; // All keyboard events will go to this ctrl first
U32 nextKeyTime;
//GuiEvent lastKeyEvent;
U8 mLastMouseClickCount;
S32 mLastMouseDownTime;
bool mLeftMouseLast;
//accelerator key map
struct AccKeyMap
{
GuiControl *ctrl;
U32 keyCode;
U32 modifier;
};
Vector <AccKeyMap> mAcceleratorMap;
void findMouseControl(const GuiEvent &event);
void refreshMouseControl();
public:
DECLARE_CONOBJECT(GuiCanvas);
GuiCanvas();
~GuiCanvas();
static void consoleInit();
//Rendering methods
void renderFrame(bool preRenderOnly); //called ever cycle to repaint the updateRects
void paint(); //causes the entire canvas to be repainted
void addUpdateRegion(Point2I pos, Point2I ext);
void resetUpdateRegions();
void buildUpdateUnion(RectI *updateUnion);
//Control content methods
void setContentControl(GuiControl *gui);
GuiControl *getContentControl();
void pushDialogControl(GuiControl *gui, S32 layer = 0);
void popDialogControl(S32 layer = 0);
void popDialogControl(GuiControl *gui);
// general cursor commands
void setCursor(GuiCursor *curs) { defaultCursor = curs; }
void setRenderFront(bool front) { mRenderFront = front; }
bool isCursorON() {return cursorON; }
void setCursorON(bool onOff);
void setCursorPos(const Point2I &pt) { cursorPt.x = F32(pt.x); cursorPt.y = F32(pt.y); }
Point2I getCursorPos() { return Point2I(S32(cursorPt.x), S32(cursorPt.y)); }
void showCursor(bool state) { mShowCursor = state; }
bool isCursorShown() { return(mShowCursor); }
//all input events come through the canvas
bool processInputEvent(const InputEvent *event);
void processMouseMoveEvent(const MouseMoveEvent *event);
//mouse methods
void mouseLock(GuiControl *lockingControl);
void mouseUnlock(GuiControl *lockingControl);
GuiControl* getMouseControl() { return mMouseControl; }
GuiControl* getMouseLockedControl() { return mMouseCapturedControl; }
bool mouseButtonDown(void) { return mMouseButtonDown; }
bool mouseRightButtonDown(void) { return mMouseRightButtonDown; }
//Mouse input methods
void rootMouseUp(const GuiEvent &event);
void rootMouseDown(const GuiEvent &event);
void rootMouseMove(const GuiEvent &event);
void rootMouseDragged(const GuiEvent &event);
void rootRightMouseDown(const GuiEvent &event);
void rootRightMouseUp(const GuiEvent &event);
void rootRightMouseDragged(const GuiEvent &event);
void rootMouseWheelUp(const GuiEvent &event);
void rootMouseWheelDown(const GuiEvent &event);
//Keyboard input methods
void tabNext(void);
void tabPrev(void);
void AddAcceleratorKey(GuiControl *ctrl, U32 keyCode, U32 modifier);
void setFirstResponder(GuiControl *firstResponder);
//deleted? possibly
//DWORD onMessage(SimObject *sender, DWORD msg); // root handles IDGUI and IDCMD messages
};
extern GuiCanvas *Canvas;
#endif

300
gui/guiChannelVectorCtrl.cc Normal file
View file

@ -0,0 +1,300 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/guiChannelVectorCtrl.h"
#include "GUI/channelVector.h"
#include "GUI/guiScrollCtrl.h"
#include "dgl/dgl.h"
IMPLEMENT_CONOBJECT(GuiChannelVectorCtrl);
//--------------------------------------------------------------------------
void GuiChannelVectorCtrl::lineInserted(const U32 arg)
{
AssertFatal(mMessageVector != NULL, "Should not be here unless we're attached!");
GuiScrollCtrl* pScroll = NULL;
GuiControl* pParent = getParent();
if (pParent) {
GuiControl* pGrandParent = pParent->getParent();
if (pGrandParent)
pScroll = dynamic_cast<GuiScrollCtrl*>(pGrandParent);
}
bool scrollToBottom = false;
if (pScroll != NULL)
scrollToBottom = pScroll->getCurrVPos() == 1.0;
mSpecialMarkers.insert(arg);
createSpecialMarkers(mSpecialMarkers[arg], mMessageVector->getLine(arg).message);
const ChannelVector::SpecialMarkers &tags = ((ChannelVector *) mMessageVector)->getLineTags(arg);
if (tags.numSpecials)
{
U32 n = mSpecialMarkers[arg].numSpecials+tags.numSpecials;
SpecialMarkers::Special *s = new SpecialMarkers::Special[n];
for (U32 i = 0, j = 0, k = 0; k < n; ++k)
{
if (i < mSpecialMarkers[arg].numSpecials &&
(j == tags.numSpecials ||
mSpecialMarkers[arg].specials[i].start <= tags.specials[j].start))
s[k] = mSpecialMarkers[arg].specials[i++];
else
{
s[k].specialType = tags.specials[j].specialType;
s[k].start = tags.specials[j].start;
s[k].end = tags.specials[j].end;
++j;
}
}
mSpecialMarkers[arg].numSpecials = n;
delete [] mSpecialMarkers[arg].specials;
mSpecialMarkers[arg].specials = s;
}
mLineWrappings.insert(arg);
createLineWrapping(mLineWrappings[arg], mMessageVector->getLine(arg).message);
mLineElements.insert(arg);
createLineElement(mLineElements[arg], mLineWrappings[arg], mSpecialMarkers[arg]);
U32 numLines = 0;
for (U32 i = 0; i < mLineWrappings.size(); i++) {
// We need to rebuild the physicalLineStart markers at the same time as
// we find out how many of them are left...
mLineElements[i].physicalLineStart = numLines;
numLines += mLineWrappings[i].numLines;
}
U32 newHeight = (mProfile->mFont->getHeight() + mLineSpacingPixels) * getMax(numLines, U32(1));
resize(mBounds.point, Point2I(mBounds.extent.x, newHeight));
if (arg == mSpecialMarkers.size() - 1 && scrollToBottom == true)
pScroll->scrollTo(0, 1);
}
//--------------------------------------------------------------------------
void GuiChannelVectorCtrl::onRender(Point2I offset,
const RectI& updateRect,
GuiControl*fr)
{
GuiControl::onRender(offset, updateRect,fr);
if (isAttached()) {
U32 linePixels = mProfile->mFont->getHeight() + mLineSpacingPixels;
U32 currLine = 0;
for (U32 i = 0; i < mMessageVector->getNumLines(); i++) {
TextElement* pElement = mLineElements[i].headLineElements;
ColorI lastColor = mProfile->mFontColor;
dglSetBitmapModulation(lastColor);
while (pElement != NULL) {
Point2I localStart(pElement == mLineElements[i].headLineElements ? 0 : mLineContinuationIndent, currLine * linePixels);
Point2I globalCheck = localToGlobalCoord(localStart);
U32 globalRangeStart = globalCheck.y;
U32 globalRangeEnd = globalCheck.y + mProfile->mFont->getHeight();
if (globalRangeStart > updateRect.point.y + updateRect.extent.y ||
globalRangeEnd < updateRect.point.y) {
currLine++;
pElement = pElement->nextPhysicalLine;
continue;
}
TextElement* walkAcross = pElement;
while (walkAcross) {
if (walkAcross->start > walkAcross->end)
break;
Point2I globalStart = localToGlobalCoord(localStart);
U32 strWidth;
if (walkAcross->specialReference == -1) {
dglSetBitmapModulation(lastColor);
dglSetTextAnchorColor(mProfile->mFontColor);
strWidth = dglDrawTextN(mProfile->mFont, globalStart, &mMessageVector->getLine(i).message[walkAcross->start],
walkAcross->end - walkAcross->start + 1, mProfile->mFontColors);
dglGetBitmapModulation(&lastColor);
} else {
SpecialMarkers::Special &s = mSpecialMarkers[i].specials[walkAcross->specialReference];
dglGetBitmapModulation(&lastColor);
if (s.specialType >= 0)
dglSetBitmapModulation(mSpecialColor);
else
{
U32 colorIndex;
switch(s.specialType)
{
case ChannelVector::NickTag:
colorIndex = NickColor;
break;
case ChannelVector::TribeTag:
colorIndex = TribeColor;
break;
case ChannelVector::ServerTag:
colorIndex = ServerColor;
break;
}
dglSetBitmapModulation(mProfile->mFontColors[colorIndex]);
}
dglSetTextAnchorColor(mProfile->mFontColor);
strWidth = dglDrawTextN(mProfile->mFont, globalStart, &mMessageVector->getLine(i).message[walkAcross->start],
walkAcross->end - walkAcross->start + 1);
// in case we have 2 in a row...
dglSetBitmapModulation(lastColor);
}
if (walkAcross->specialReference != -1) {
Point2I lineStart = localStart;
Point2I lineEnd = localStart;
SpecialMarkers::Special &s = mSpecialMarkers[i].specials[walkAcross->specialReference];
lineStart.y += mProfile->mFont->getBaseline() + 2;
lineEnd.x += strWidth;
lineEnd.y += mProfile->mFont->getBaseline() + 2;
if (s.specialType >= 0)
dglDrawLine(localToGlobalCoord(lineStart),
localToGlobalCoord(lineEnd),
mSpecialColor);
else
{
U32 colorIndex;
switch(s.specialType)
{
case ChannelVector::NickTag:
colorIndex = NickColor;
break;
case ChannelVector::TribeTag:
colorIndex = TribeColor;
break;
case ChannelVector::ServerTag:
colorIndex = ServerColor;
break;
}
dglDrawLine(localToGlobalCoord(lineStart),
localToGlobalCoord(lineEnd),
mProfile->mFontColors[colorIndex]);
}
}
localStart.x += strWidth;
walkAcross = walkAcross->nextInLine;
}
currLine++;
pElement = pElement->nextPhysicalLine;
}
}
dglClearBitmapModulation();
}
}
//--------------------------------------------------------------------------
void GuiChannelVectorCtrl::onMouseUp(const GuiEvent& event)
{
GuiControl::onMouseUp(event);
mouseUnlock();
// Is this an up from a dragged click?
if (mMouseDown == false)
return;
// Find the special we are in, if any...
S32 currSpecialLine;
S32 currSpecialRef;
findSpecialFromCoord(globalToLocalCoord(event.mousePoint), &currSpecialLine, &currSpecialRef);
if (currSpecialRef != -1 &&
(currSpecialLine == mMouseSpecialLine &&
currSpecialRef == mMouseSpecialRef))
{
// Execute the callback
char type[16];
const char *content;
SpecialMarkers& rSpecial = mSpecialMarkers[currSpecialLine];
S32 specialStart = rSpecial.specials[currSpecialRef].start;
S32 specialEnd = rSpecial.specials[currSpecialRef].end;
switch (rSpecial.specials[currSpecialRef].specialType)
{
case ChannelVector::TribeTag:
if (currSpecialRef &&
rSpecial.specials[currSpecialRef-1].specialType == ChannelVector::NickTag)
{
--currSpecialRef;
specialStart = rSpecial.specials[currSpecialRef].start;
specialEnd = rSpecial.specials[currSpecialRef].end;
}
else
{
++currSpecialRef;
specialStart = rSpecial.specials[currSpecialRef].start;
specialEnd = rSpecial.specials[currSpecialRef].end;
}
case ChannelVector::NickTag:
dStrcpy(type,"warrior");
content = "";
break;
case ChannelVector::ServerTag:
{
const ChannelVector::SpecialMarkers &tags = ((ChannelVector *) mMessageVector)->getLineTags(currSpecialLine);
dStrcpy(type,"server");
for (U32 i = 0; i < tags.numSpecials; ++i)
if (tags.specials[i].start == specialStart)
{
content = tags.specials[i].content;
break;
}
break;
}
default:
{
dStrcpy(type,"http");
content = "";
}
break;
}
char* copyURL = new char[specialEnd - specialStart + 2];
dStrncpy(copyURL, &mMessageVector->getLine(currSpecialLine).message[specialStart], specialEnd - specialStart + 1);
copyURL[specialEnd - specialStart + 1] = '\0';
Con::executef(this, 4, "urlClickCallback", type, copyURL, content);
delete [] copyURL;
}
mMouseDown = false;
mMouseSpecialLine = -1;
mMouseSpecialRef = -1;
}

View file

@ -0,0 +1,35 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUICHANNELVECTORCTRL_H_
#define _GUICHANNELVECTORCTRL_H_
#ifndef _CHANNELVECTOR_H_
#include "GUI/channelVector.h"
#endif
class GuiChannelVectorCtrl : public GuiMessageVectorCtrl
{
typedef GuiMessageVectorCtrl Parent;
protected:
enum {
NickColor = 1,
TribeColor = 2,
ServerColor = 3,
};
virtual void onMouseUp(const GuiEvent &event);
virtual void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
virtual void lineInserted(const U32);
public:
DECLARE_CONOBJECT(GuiChannelVectorCtrl);
};
#endif // _H_GUICHANNELVECTORCTRL_

262
gui/guiChatMenuTreeCtrl.cc Normal file
View file

@ -0,0 +1,262 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "dgl/dgl.h"
#include "GUI/guiChatMenuTreeCtrl.h"
#include "console/consoleTypes.h"
#include "Platform/event.h"
IMPLEMENT_CONOBJECT(GuiChatMenuTreeCtrl);
//------------------------------------------------------------------------------
GuiChatMenuTreeCtrl::GuiChatMenuTreeCtrl() : GuiTreeViewCtrl()
{
mTexRollover = NULL;
mTexSelected = NULL;
// Default colors:
mAltFontColor.set( 6, 215, 245 );
mAltFontColorHL.set( 6, 215, 245 );
mAltFontColorSE.set( 25, 56, 68 );
}
//------------------------------------------------------------------------------
void GuiChatMenuTreeCtrl::initPersistFields()
{
Parent::initPersistFields();
addField( "altFontColor", TypeColorI, Offset( mAltFontColor, GuiChatMenuTreeCtrl ) );
addField( "altFontColorHL", TypeColorI, Offset( mAltFontColorHL, GuiChatMenuTreeCtrl ) );
addField( "altFontColorSE", TypeColorI, Offset( mAltFontColorSE, GuiChatMenuTreeCtrl ) );
}
//------------------------------------------------------------------------------
void GuiChatMenuTreeCtrl::consoleInit()
{
}
//------------------------------------------------------------------------------
bool GuiChatMenuTreeCtrl::onWake()
{
if ( !Parent::onWake() )
return( false );
// Set the item height to the height of the bitmaps so we know they
// will connect up right:
mItemHeight = mImageBounds[BmpDunno].extent.y;
char buf[512];
dSprintf( buf, sizeof( buf ), "%s_rol.png", mProfile->mBitmapBase );
mTexRollover = TextureHandle( buf, BitmapTexture );
dSprintf( buf, sizeof( buf ), "%s_act.png", mProfile->mBitmapBase );
mTexSelected = TextureHandle( buf, BitmapTexture );
return( true );
}
//------------------------------------------------------------------------------
void GuiChatMenuTreeCtrl::onSleep()
{
mTexRollover = NULL;
mTexSelected = NULL;
Parent::onSleep();
}
//------------------------------------------------------------------------------
bool GuiChatMenuTreeCtrl::onKeyDown( const GuiEvent& event )
{
if ( !mVisible || !mActive || !mAwake )
return true;
if ( !mSelectedItem )
return true;
Item* item = getItem( mSelectedItem );
if ( !item )
return true;
if ( event.modifier == 0 )
{
if ( event.keyCode == KEY_RETURN )
{
if ( mAltConsoleCommand[0] )
Con::evaluate( mAltConsoleCommand );
return true;
}
if ( event.keyCode == KEY_DELETE )
{
// Don't delete the root!
if ( item->mParent )
{
removeItem( item->mId );
return true;
}
}
}
// The Alt key lets you move items around:
if ( event.modifier & SI_ALT )
{
switch ( event.keyCode )
{
case KEY_UP:
if ( item->mPrevious )
{
moveItemUp( item->mId );
buildVisibleTree();
}
return true;
case KEY_DOWN:
if ( item->mNext )
{
moveItemUp( item->mNext->mId );
buildVisibleTree();
}
return true;
case KEY_LEFT:
if ( item->mParent )
{
if ( item->mParent->mParent )
{
// We're movin'...
if ( item->mPrevious )
item->mPrevious->mNext = item->mNext;
else
item->mParent->mChild = item->mNext;
if ( item->mNext )
item->mNext->mPrevious = item->mPrevious;
// Make the item be its former parent's next sibling:
item->mPrevious = item->mParent;
item->mNext = item->mParent->mNext;
if ( item->mNext )
item->mNext->mPrevious = item;
item->mParent->mNext = item;
item->mParent = item->mParent->mParent;
buildVisibleTree();
}
}
return true;
case KEY_RIGHT:
if ( item->mPrevious )
{
// Make the item the last child of its previous sibling:
if ( dStrcmp( item->mPrevious->mValue, "0" ) == 0 )
{
item->mPrevious->mNext = item->mNext;
if ( item->mNext )
item->mNext->mPrevious = item->mPrevious;
item->mParent = item->mPrevious;
item->mNext = NULL;
if ( item->mParent->mChild )
{
Item* temp = item->mParent->mChild;
while ( temp->mNext )
temp = temp->mNext;
temp->mNext = item;
item->mPrevious = temp;
}
else
{
// only child...<sniff>
item->mParent->mChild = item;
item->mPrevious = NULL;
}
// Make sure the new parent is expanded:
if ( !item->mParent->mState.test( Item::Expanded ) )
expandItem( item->mParent->mId, true );
buildVisibleTree();
}
}
return true;
}
}
// Not handled, so pass to parent:
return Parent::onKeyDown( event );
}
//------------------------------------------------------------------------------
void GuiChatMenuTreeCtrl::onRenderCell( Point2I offset, Point2I cell, bool, bool )
{
AssertFatal( cell.y < mVisibleItems.size(), "GuiChatMenuTreeCtrl::onRenderCell: invalid cell" );
Item* item = mVisibleItems[cell.y];
RectI drawRect( offset, mCellSize );
U32 bitmap;
dglClearBitmapModulation();
// Draw inheritance lines:
drawRect.point.x += ( mTabSize * item->mTabLevel );
Item* parent = item->mParent;
for ( S32 i = item->mTabLevel; ( parent && i > 0 ); i-- )
{
drawRect.point.x -= mTabSize;
if ( parent->mNext )
dglDrawBitmapSR( mImagesHandle, drawRect.point, mImageBounds[BmpLine] );
parent = parent->mParent;
}
// Draw the bitmap:
drawRect.point.x = offset.x + mTabSize * item->mTabLevel;
if ( !item->mChild )
bitmap = item->mNext ? BmpChild : BmpLastChild;
else
{
bitmap = item->mState.test( Item::Expanded ) ? BmpExp : BmpCon;
if ( item->mParent || item->mPrevious )
bitmap += ( item->mNext ? 3 : 2 );
else
bitmap += ( item->mNext ? 1 : 0 );
}
if ( ( bitmap >= 0 ) && ( bitmap < mNumImages ) )
{
dglDrawBitmapSR( mImagesHandle, drawRect.point, mImageBounds[bitmap] );
// Draw the rollover glow if applicable:
if ( bitmap > BmpChild && item->mState.test( Item::MouseOverBmp ) )
dglDrawBitmapSR( mImagesHandle, drawRect.point, mImageBounds[BmpGlow] );
drawRect.point.x += ( mImageBounds[bitmap].extent.x + 2 );
}
// Draw the rollover/selected bar if applicable:
drawRect.extent.x = mProfile->mFont->getStrWidth( item->mText ) + ( 2 * mTextOffset );
if ( item->mState.test( Item::Selected ) && mTexSelected )
dglDrawBitmapStretch( mTexSelected, drawRect );
else if ( item->mState.test( Item::MouseOverText ) && mTexRollover )
dglDrawBitmapStretch( mTexRollover, drawRect );
drawRect.point.x += mTextOffset;
ColorI fontColor;
if ( dStrcmp( item->mValue, "0" ) )
fontColor = item->mState.test( Item::Selected ) ? mProfile->mFontColorSEL : ( item->mState.test( Item::MouseOverText ) ? mProfile->mFontColorHL : mProfile->mFontColor );
else
fontColor = item->mState.test( Item::Selected ) ? mAltFontColorSE : ( item->mState.test( Item::MouseOverText ) ? mAltFontColorHL : mAltFontColor );
dglSetBitmapModulation( fontColor );
dglDrawText( mProfile->mFont, drawRect.point, item->mText, mProfile->mFontColors );
}

60
gui/guiChatMenuTreeCtrl.h Normal file
View file

@ -0,0 +1,60 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUICHATMENUTREECTRL_H_
#define _GUICHATMENUTREECTRL_H_
#ifndef _GUITREEVIEWCTRL_H_
#include "GUI/guiTreeViewCtrl.h"
#endif
class GuiChatMenuTreeCtrl : public GuiTreeViewCtrl
{
private:
typedef GuiTreeViewCtrl Parent;
protected:
enum BmpIndices
{
BmpDunno,
BmpLastChild,
BmpChild,
BmpExp,
BmpExpN,
BmpExpP,
BmpExpPN,
BmpCon,
BmpConN,
BmpConP,
BmpConPN,
BmpLine,
BmpGlow,
};
TextureHandle mTexRollover;
TextureHandle mTexSelected;
ColorI mAltFontColor;
ColorI mAltFontColorHL;
ColorI mAltFontColorSE;
public:
DECLARE_CONOBJECT(GuiChatMenuTreeCtrl);
GuiChatMenuTreeCtrl();
static void consoleInit();
static void initPersistFields();
bool onWake();
void onSleep();
bool onKeyDown( const GuiEvent& event );
void onRenderCell( Point2I offset, Point2I cell, bool, bool );
};
#endif // _GUI_CHATMENUTREECTRL_H

233
gui/guiCheckBoxCtrl.cc Normal file
View file

@ -0,0 +1,233 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "dgl/dgl.h"
#include "GUI/guiCanvas.h"
#include "GUI/guiCheckBoxCtrl.h"
#include "console/consoleTypes.h"
//---------------------------------------------------------------------------
GuiCheckBoxCtrl::GuiCheckBoxCtrl()
{
mActive = true;
mBounds.extent.set(140, 30);
mKeyPressed = false;
mStateOn = false;
}
//---------------------------------------------------------------------------
void GuiCheckBoxCtrl::consoleInit()
{
}
//---------------------------------------------------------------------------
void GuiCheckBoxCtrl::setScriptValue(const char *value)
{
mStateOn = dAtob(value);
// Update the console variable:
if ( mConsoleVariable[0] )
Con::setBoolVariable( mConsoleVariable, mStateOn );
setUpdate();
}
//---------------------------------------------------------------------------
const char *GuiCheckBoxCtrl::getScriptValue()
{
return mStateOn ? "1" : "0";
}
//---------------------------------------------------------------------------
void GuiCheckBoxCtrl::AcceleratorKeyPress(void)
{
if (! mActive) return;
//set the bool
mKeyPressed = true;
if (mProfile->mTabable)
{
setFirstResponder();
}
}
//---------------------------------------------------------------------------
void GuiCheckBoxCtrl::AcceleratorKeyRelease(void)
{
if (! mActive) return;
//set the bool
mKeyPressed = false;
//perform the action
onAction();
//update
setUpdate();
}
//---------------------------------------------------------------------------
bool GuiCheckBoxCtrl::onKeyDown(const GuiEvent &event)
{
//if the control is a dead end, kill the event
if ((! mVisible) || (! mActive) || (! mAwake))
return true;
//see if the key down is a <return> or not
if (event.keyCode == KEY_RETURN && event.modifier == 0)
{
onAction();
return true;
}
//otherwise, pass the event to it's parent
return Parent::onKeyDown(event);
}
//---------------------------------------------------------------------------
void GuiCheckBoxCtrl::drawBorder(const RectI &r, const ColorI &color)
{
Point2I p1, p2;
p1 = r.point;
p2 = r.point;
p2.x += r.extent.x - 1;
p2.y += r.extent.y - 1;
glColor4ub(color.red, color.green, color.blue, color.alpha);
glBegin(GL_LINE_LOOP);
glVertex2i(p1.x + 2, p1.y);
glVertex2i(p2.x - 2, p1.y);
glVertex2i(p2.x, p1.y + 2);
glVertex2i(p2.x, p2.y - 2);
glVertex2i(p2.x - 2, p2.y);
glVertex2i(p1.x + 2, p2.y);
glVertex2i(p1.x, p2.y - 2);
glVertex2i(p1.x, p1.y + 2);
glEnd();
}
//---------------------------------------------------------------------------
void GuiCheckBoxCtrl::onAction()
{
mStateOn = mStateOn ? false : true;
// Update the console variable:
if ( mConsoleVariable[0] )
Con::setBoolVariable( mConsoleVariable, mStateOn );
Parent::onAction();
}
//---------------------------------------------------------------------------
void GuiCheckBoxCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
ColorI backColor = mActive ? mProfile->mFillColor : mProfile->mFillColorNA;
ColorI fontColor = (cursorInControl()) ? mProfile->mFontColorHL : mProfile->mFontColor;
ColorI insideBorderColor = (firstResponder == this) ? mProfile->mBorderColorHL : mProfile->mBorderColor;
if(mText[0] != NULL)
{
ColorI outsideBorderColor = mProfile->mBorderColor;
S32 txt_w = mFont->getStrWidth(mText);
Point2I localStart;
// align the horizontal
switch (mProfile->mAlignment)
{
case GuiControlProfile::RightJustify:
localStart.x = mBounds.extent.x - txt_w;
break;
case GuiControlProfile::CenterJustify:
localStart.x = (mBounds.extent.x - txt_w) / 2;
break;
default:
// GuiControlProfile::LeftJustify
localStart.x = 0;
break;
}
// center the vertical
localStart.y = (mBounds.extent.y - (mFont->getHeight() - 2)) / 2;
// first draw the background
RectI r(offset, mBounds.extent);
dglDrawRectFill(r, backColor);
r.point.x +=2;
r.point.y +=2;
r.extent.x -=4;
r.extent.y -=4;
dglDrawRectFill(r, backColor);
S32 incVal = mBounds.extent.y - 8;
//draw the check box
glColor3i(insideBorderColor.red, insideBorderColor.green, insideBorderColor.blue);
glBegin(GL_LINE_LOOP);
glVertex2i(r.point.x+3, r.point.y+3);
glVertex2i(r.point.x+incVal, r.point.y+3);
glVertex2i(r.point.x+incVal, r.point.y+incVal);
glVertex2i(r.point.x+3, r.point.y+incVal);
glEnd();
if (mStateOn)
{
glColor3i(fontColor.red, fontColor.green, fontColor.blue);
glBegin(GL_LINES);
glVertex2i(r.point.x+3, r.point.y+3);
glVertex2i(r.point.x+incVal, r.point.y+incVal);
glVertex2i(r.point.x+incVal, r.point.y+3);
glVertex2i(r.point.x+3, r.point.y+incVal);
glEnd();
}
// draw the oustside border
r.point.x -=1;
r.point.y -=1;
r.extent.x +=2;
r.extent.y +=2;
drawBorder(r, outsideBorderColor);
// finally draw the text
localStart.y -= 2;
localStart.x += 4;
if (mStateOn)
{
localStart.x += 1;
localStart.y += 1;
}
Point2I globalStart = localToGlobalCoord(localStart);
dglSetBitmapModulation(fontColor);
dglDrawText(mFont, globalStart, mText, mProfile->mFontColors);
}
else
{
RectI r(Point2I(offset.x+3, offset.y+3), Point2I(mBounds.extent.x-3, mBounds.extent.y-3));
dglDrawRectFill(r, backColor);
dglDrawRect(r,insideBorderColor);
if (mStateOn)
{
glColor3i(fontColor.red, fontColor.green, fontColor.blue);
glBegin(GL_LINES);
glVertex2i(r.point.x-1, r.point.y);
glVertex2i(r.point.x-1 + r.extent.x, r.point.y + r.extent.y);
glVertex2i(r.point.x-1 + r.extent.x, r.point.y);
glVertex2i(r.point.x-1, r.point.y + r.extent.y);
glEnd();
}
}
//render the children
renderChildControls(offset, updateRect, firstResponder);
}
//---------------------------------------------------------------------------
// EOF //

44
gui/guiCheckBoxCtrl.h Normal file
View file

@ -0,0 +1,44 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUICHECKBOXCTRL_H_
#define _GUICHECKBOXCTRL_H_
#ifndef _GUITEXTCTRL_H_
#include "GUI/guiTextCtrl.h"
#endif
class GuiCheckBoxCtrl : public GuiTextCtrl
{
private:
typedef GuiTextCtrl Parent;
protected:
bool mStateOn;
bool mKeyPressed;
public:
DECLARE_CONOBJECT(GuiCheckBoxCtrl);
GuiCheckBoxCtrl();
static void consoleInit();
void AcceleratorKeyPress(void);
void AcceleratorKeyRelease(void);
bool onKeyDown(const GuiEvent &event);
// GuiTextCtrl updates mText with the variable value, which is not desired
void onPreRender() {}
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void drawBorder(const RectI &r, const ColorI &color);
void onAction();
void setScriptValue(const char *value);
const char *getScriptValue();
};
#endif //_GUI_CHECKBOX_CTRL_H

127
gui/guiChunkedBitmapCtrl.cc Normal file
View file

@ -0,0 +1,127 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "dgl/gBitmap.h"
#include "GUI/guiControl.h"
#include "dgl/gTexManager.h"
#include "dgl/gChunkedTexManager.h"
class GuiChunkedBitmapCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
StringTableEntry mBitmapName;
ChunkedTextureHandle mTexHandle;
bool mUseVariable;
public:
//creation methods
DECLARE_CONOBJECT(GuiChunkedBitmapCtrl);
GuiChunkedBitmapCtrl();
static void initPersistFields();
static void consoleInit();
//Parental methods
bool onWake();
void onSleep();
void setBitmap(const char *name);
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
};
IMPLEMENT_CONOBJECT(GuiChunkedBitmapCtrl);
void GuiChunkedBitmapCtrl::initPersistFields()
{
Parent::initPersistFields();
addField( "bitmap", TypeString, Offset( mBitmapName, GuiChunkedBitmapCtrl ) );
addField( "useVariable", TypeBool, Offset( mUseVariable, GuiChunkedBitmapCtrl ) );
}
static void cChunkBmpSetBitmap( SimObject* obj, S32, const char** argv )
{
AssertFatal( dynamic_cast<GuiChunkedBitmapCtrl*>( obj ), "Object passed to cChunkBmpSetBitmap is not a GuiChunkedBitmapCtrl!" );
GuiChunkedBitmapCtrl* ctrl = static_cast<GuiChunkedBitmapCtrl*>( obj );
ctrl->setBitmap( argv[2] );
}
void GuiChunkedBitmapCtrl::consoleInit()
{
Con::addCommand( "GuiChunkedBitmapCtrl", "setBitmap", cChunkBmpSetBitmap, "ctrl.setBitmap( name );", 3, 3 );
}
GuiChunkedBitmapCtrl::GuiChunkedBitmapCtrl()
{
mBitmapName = StringTable->insert("");
mUseVariable = false;
}
void GuiChunkedBitmapCtrl::setBitmap(const char *name)
{
bool awake = mAwake;
if(awake)
onSleep();
mBitmapName = StringTable->insert(name);
if(awake)
onWake();
setUpdate();
}
bool GuiChunkedBitmapCtrl::onWake()
{
if(!Parent::onWake())
return false;
if ( mUseVariable )
mTexHandle = ChunkedTextureHandle( Con::getVariable( mConsoleVariable ) );
else
mTexHandle = ChunkedTextureHandle( mBitmapName );
return true;
}
void GuiChunkedBitmapCtrl::onSleep()
{
mTexHandle = NULL;
Parent::onSleep();
}
void GuiChunkedBitmapCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
if(mTexHandle)
{
U32 widthCount = mTexHandle.getTextureCountWidth();
U32 heightCount = mTexHandle.getTextureCountHeight();
if(!widthCount || !heightCount)
return;
F32 widthScale = F32(mBounds.extent.x) / F32(mTexHandle.getWidth());
F32 heightScale = F32(mBounds.extent.y) / F32(mTexHandle.getHeight());
dglSetBitmapModulation(ColorF(1,1,1));
for(U32 i = 0; i < widthCount; i++)
{
for(U32 j = 0; j < heightCount; j++)
{
TextureHandle t = mTexHandle.getSubTexture(i, j);
RectI stretchRegion;
stretchRegion.point.x = (S32)(i * 256 * widthScale + offset.x);
stretchRegion.point.y = (S32)(j * 256 * heightScale + offset.y);
stretchRegion.extent.x = (S32)((i * 256 + t.getWidth() ) * widthScale + offset.x - stretchRegion.point.x);
stretchRegion.extent.y = (S32)((j * 256 + t.getHeight()) * heightScale + offset.y - stretchRegion.point.y);
dglDrawBitmapStretch(t, stretchRegion);
}
}
renderChildControls(offset, updateRect, firstResponder);
}
else
Parent::onRender(offset, updateRect, firstResponder);
}

102
gui/guiConsole.cc Normal file
View file

@ -0,0 +1,102 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "dgl/dgl.h"
#include "GUI/guiTypes.h"
#include "GUI/guiControl.h"
#include "GUI/guiConsole.h"
GuiConsole::GuiConsole()
{
mBounds.extent.set(1, 1);
mCellSize.set(1, 1);
mSize.set(1, 0);
}
bool GuiConsole::onWake()
{
if (! Parent::onWake())
return false;
//get the font
mFont = mProfile->mFont;
return true;
}
S32 GuiConsole::getMaxWidth(S32 startIndex, S32 endIndex)
{
//sanity check
U32 size;
ConsoleLogEntry *log;
Con::getLog(log, size);
if(startIndex < 0 || (U32)endIndex >= size || startIndex > endIndex)
return 0;
S32 result = 0;
for(S32 i = startIndex; i <= endIndex; i++)
result = getMax(result, (S32)(mFont->getStrWidth(log[i].mString)));
return(result + 6);
}
void GuiConsole::onPreRender()
{
//see if the size has changed
U32 prevSize = mBounds.extent.y / mCellSize.y;
U32 size;
ConsoleLogEntry *log;
Con::getLog(log, size);
if(size != prevSize)
{
//first, find out if the console was scrolled up
bool scrolled = false;
GuiControl *parent = getParent();
if (mBounds.point.y > parent->mBounds.extent.y - mBounds.extent.y)
scrolled = true;
//find the max cell width for the new entries
S32 newMax = getMaxWidth(prevSize, size - 1);
if(newMax > mCellSize.x)
mCellSize.set(newMax, mFont->getHeight());
//set the array size
mSize.set(1, size);
//resize the control
resize(mBounds.point, Point2I(mCellSize.x, mCellSize.y * size));
//if the console was not scrolled, make the last entry visible
if (! scrolled)
{
mSelectedCell.set(0, mSize.y - 1);
scrollSelectionVisible();
}
}
}
void GuiConsole::onRenderCell(Point2I offset, Point2I cell, bool /*selected*/, bool /*mouseOver*/)
{
U32 size;
ConsoleLogEntry *log;
Con::getLog(log, size);
ConsoleLogEntry &entry = log[cell.y];
switch (entry.mLevel)
{
case ConsoleLogEntry::Normal: dglSetBitmapModulation(mProfile->mFontColor); break;
case ConsoleLogEntry::Warning: dglSetBitmapModulation(mProfile->mFontColorHL); break;
case ConsoleLogEntry::Error: dglSetBitmapModulation(mProfile->mFontColorNA); break;
}
dglDrawText(mFont, Point2I(offset.x + 3, offset.y), entry.mString, mProfile->mFontColors);
}

34
gui/guiConsole.h Normal file
View file

@ -0,0 +1,34 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUICONSOLE_H_
#define _GUICONSOLE_H_
#ifndef _GUIARRAYCTRL_H_
#include "GUI/guiArrayCtrl.h"
#endif
class GuiConsole : public GuiArrayCtrl
{
private:
typedef GuiArrayCtrl Parent;
Resource<GFont> mFont;
S32 getMaxWidth(S32 startIndex, S32 endIndex);
public:
GuiConsole();
DECLARE_CONOBJECT(GuiConsole);
bool onWake();
void onPreRender();
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
};
#endif

97
gui/guiConsoleEditCtrl.cc Normal file
View file

@ -0,0 +1,97 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/dgl.h"
#include "GUI/guiCanvas.h"
#include "GUI/guiConsoleEditCtrl.h"
IMPLEMENT_CONOBJECT(GuiConsoleEditCtrl);
GuiConsoleEditCtrl::GuiConsoleEditCtrl()
{
tabBuffer[0] = 0;
baseStart = 0;
baseLen = 0;
}
void GuiConsoleEditCtrl::handleTab(bool forwardTab)
{
char buf[GuiTextCtrl::MAX_STRING_LENGTH + 1];
if(dStrcmp(tabBuffer, mText))
{
dStrcpy(tabBuffer, mText);
// scan back from mCursorPos
S32 p = mCursorPos;
while(p > 0 && mText[p-1] != ' ' && mText[p-1] != '.' && mText[p-1] != '(')
p--;
baseStart = p;
baseLen = mCursorPos-p;
if(mText[p-1] == '.')
{
if(p <= 1)
return;
S32 objLast = --p;
while(p > 0 && mText[p-1] != ' ')
p--;
if(objLast == p)
return;
dStrncpy(buf, mText + p, objLast - p);
buf[objLast - p] = 0;
tabObject = Sim::findObject(buf);
if(!bool(tabObject))
return;
}
else
tabObject = 0;
}
const char *newText;
mText[mCursorPos] = 0;
if(bool(tabObject))
newText = tabObject->tabComplete(mText + baseStart, baseLen, forwardTab);
else
newText = Con::tabComplete(mText + baseStart, baseLen, forwardTab);
if(newText)
{
S32 len = dStrlen(newText);
if(len + baseStart > GuiTextCtrl::MAX_STRING_LENGTH)
len = GuiTextCtrl::MAX_STRING_LENGTH - baseStart;
dStrncpy(mText + baseStart, newText, len);
mText[baseStart + len] = 0;
mCursorPos = baseStart + len;
}
else
{
mText[baseStart + baseLen] = 0;
mCursorPos = baseStart + baseLen;
}
dStrcpy(tabBuffer, mText);
}
bool GuiConsoleEditCtrl::onKeyDown(const GuiEvent &event)
{
S32 stringLen = dStrlen(mText);
setUpdate();
if (event.keyCode == KEY_TAB)
{
if (event.modifier & SI_SHIFT)
{
handleTab(false);
return true;
}
else
{
handleTab(true);
return true;
}
}
return Parent::onKeyDown(event);
}

36
gui/guiConsoleEditCtrl.h Normal file
View file

@ -0,0 +1,36 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUICONSOLEEDITCTRL_H_
#define _GUICONSOLEEDITCTRL_H_
#ifndef _GUITYPES_H_
#include "GUI/guiTypes.h"
#endif
#ifndef _GUITEXTEDITCTRL_H_
#include "GUI/guiTextEditCtrl.h"
#endif
class GuiConsoleEditCtrl : public GuiTextEditCtrl
{
private:
typedef GuiTextEditCtrl Parent;
// max string len, must be less then or equal to 255
SimObjectPtr<SimObject> tabObject;
S32 baseStart;
S32 baseLen;
char tabBuffer[GuiTextCtrl::MAX_STRING_LENGTH + 1];
public:
GuiConsoleEditCtrl();
DECLARE_CONOBJECT(GuiConsoleEditCtrl);
bool onKeyDown(const GuiEvent &event);
void handleTab(bool forwardTab);
};
#endif //_GUI_TEXTEDIT_CTRL_H

160
gui/guiConsoleTextCtrl.cc Normal file
View file

@ -0,0 +1,160 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "Core/color.h"
#include "GUI/guiConsoleTextCtrl.h"
#include "dgl/dgl.h"
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
GuiConsoleTextCtrl::GuiConsoleTextCtrl()
{
//default fonts
mConsoleExpression = NULL;
mResult = NULL;
}
void GuiConsoleTextCtrl::consoleInit()
{
}
void GuiConsoleTextCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("expression", TypeCaseString, Offset(mConsoleExpression, GuiConsoleTextCtrl));
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
bool GuiConsoleTextCtrl::onWake()
{
if (! Parent::onWake())
return false;
mFont = mProfile->mFont;
return true;
}
void GuiConsoleTextCtrl::onSleep()
{
Parent::onSleep();
mFont = NULL;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
void GuiConsoleTextCtrl::setText(const char *txt)
{
//make sure we don't call this before onAdd();
AssertFatal(mProfile, "Can't call setText() until setProfile() has been called.");
if (txt)
mConsoleExpression = StringTable->insert(txt);
else
mConsoleExpression = NULL;
//Make sure we have a font
mProfile->incRefCount();
mFont = mProfile->mFont;
setUpdate();
//decrement the profile referrence
mProfile->decRefCount();
}
void GuiConsoleTextCtrl::calcResize()
{
if (!mResult)
return;
//resize
if (mProfile->mAutoSizeWidth)
{
if (mProfile->mAutoSizeHeight)
resize(mBounds.point, Point2I(mFont->getStrWidth(mResult) + 4, mFont->getHeight() + 4));
else
resize(mBounds.point, Point2I(mFont->getStrWidth(mResult) + 4, mBounds.extent.y));
}
else if (mProfile->mAutoSizeHeight)
{
resize(mBounds.point, Point2I(mBounds.extent.x, mFont->getHeight() + 4));
}
}
void GuiConsoleTextCtrl::onPreRender()
{
if (mConsoleExpression)
mResult = Con::evaluatef("$temp = %s;", mConsoleExpression);
calcResize();
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
void GuiConsoleTextCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
// draw the background rectangle
RectI r(offset, mBounds.extent);
dglDrawRectFill(r, ColorI(255,255,255));
// draw the border
r.extent += r.point;
glColor4ub(0, 0, 0, 0);
glBegin(GL_LINE_LOOP);
glVertex2i(r.point.x, r.point.y);
glVertex2i(r.extent.x-1, r.point.y);
glVertex2i(r.extent.x-1, r.extent.y-1);
glVertex2i(r.point.x, r.extent.y-1);
glEnd();
if (mResult)
{
S32 txt_w = mFont->getStrWidth(mResult);
Point2I localStart;
switch (mProfile->mAlignment)
{
case GuiControlProfile::RightJustify:
localStart.set(mBounds.extent.x - txt_w-2, 0);
break;
case GuiControlProfile::CenterJustify:
localStart.set((mBounds.extent.x - txt_w) / 2, 0);
break;
default:
// GuiControlProfile::LeftJustify
localStart.set(2,0);
break;
}
Point2I globalStart = localToGlobalCoord(localStart);
//draw the text
dglSetBitmapModulation(mProfile->mFontColor);
dglDrawText(mFont, globalStart, mResult, mProfile->mFontColors);
}
//render the child controls
renderChildControls(offset, updateRect, firstResponder);
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
const char *GuiConsoleTextCtrl::getScriptValue()
{
return getText();
}
void GuiConsoleTextCtrl::setScriptValue(const char *val)
{
setText(val);
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// EOF //

61
gui/guiConsoleTextCtrl.h Normal file
View file

@ -0,0 +1,61 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUICONSOLETEXTCTRL_H_
#define _GUICONSOLETEXTCTRL_H_
#ifndef _GFONT_H_
#include "dgl/gFont.h"
#endif
#ifndef _GUITYPES_H_
#include "GUI/guiTypes.h"
#endif
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
class GuiConsoleTextCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
public:
enum Constants { MAX_STRING_LENGTH = 255 };
protected:
const char *mConsoleExpression;
const char *mResult;
Resource<GFont> mFont;
public:
//creation methods
DECLARE_CONOBJECT(GuiConsoleTextCtrl);
GuiConsoleTextCtrl();
static void consoleInit();
static void initPersistFields();
//Parental methods
bool onWake();
void onSleep();
//text methods
virtual void setText(const char *txt = NULL);
const char *getText() { return mConsoleExpression; }
//rendering methods
void calcResize();
void onPreRender(); // do special pre render processing
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
//Console methods
const char *getScriptValue();
void setScriptValue(const char *value);
};
#endif //_GUI_TEXT_CONTROL_H_

1276
gui/guiControl.cc Normal file

File diff suppressed because it is too large Load diff

243
gui/guiControl.h Normal file
View file

@ -0,0 +1,243 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUICONTROL_H_
#define _GUICONTROL_H_
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _MPOINT_H_
#include "Math/mPoint.h"
#endif
#ifndef _MRECT_H_
#include "Math/mRect.h"
#endif
#ifndef _COLOR_H_
#include "Core/color.h"
#endif
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _GUITYPES_H_
#include "GUI/guiTypes.h"
#endif
#ifndef _EVENT_H_
#include "Platform/event.h"
#endif
class GuiCanvas;
class GuiControl : public SimGroup
{
private:
typedef SimGroup Parent;
public:
GuiControlProfile *mProfile;
bool mVisible;
bool mActive;
bool mAwake;
bool mSetFirstResponder;
S32 mLayer;
RectI mBounds;
Point2I mMinExtent;
//keyboard input
GuiControl *mFirstResponder;
static GuiControl *gPrevResponder;
static GuiControl *gCurResponder;
enum horizSizingOptions
{
horizResizeRight = 0, // fixed on the left and width
horizResizeWidth, // fixed on the left and right
horizResizeLeft, // fixed on the right and width
horizResizeCenter,
horizResizeRelative //resize relative
};
enum vertSizingOptions
{
vertResizeBottom = 0, // fixed on the top and in height
vertResizeHeight, // fixed on the top and bottom
vertResizeTop, // fixed in height and on the bottom
vertResizeCenter,
vertResizeRelative // resize relative
};
protected:
S32 mHorizSizing;
S32 mVertSizing;
StringTableEntry mConsoleVariable;
StringTableEntry mConsoleCommand;
StringTableEntry mAltConsoleCommand;
StringTableEntry mAcceleratorKey;
S32 mHelpTag;
StringTableEntry mHelpText;
// console variable and command methods
void setVariable(const char *value);
void setIntVariable(S32 value);
void setFloatVariable(F32 value);
const char* getVariable();
S32 getIntVariable();
F32 getFloatVariable();
public:
void setConsoleVariable(const char *variable);
void setConsoleCommand(const char *newCmd);
const char * getConsoleCommand();
void setSizing(S32 horz, S32 vert);
void inspectPreApply();
void inspectPostApply();
public:
static GuiControl* find(const char *name);
DECLARE_CONOBJECT(GuiControl);
GuiControl();
virtual ~GuiControl();
bool onAdd();
static void initPersistFields();
static void consoleInit();
const Point2I& getPosition() { return mBounds.point; }
const Point2I& getExtent() { return mBounds.extent; }
const Point2I& getMinExtent() { return mMinExtent; }
virtual void setVisible(bool value);
inline bool isVisible() { return mVisible; }
virtual void makeFirstResponder(bool value);
void setActive(bool value);
bool isActive() { return mActive; }
bool isAwake()
{
return( mAwake );
}
//tag, mouseTag and helpTag related calls
virtual void setHelp(S32 helpTag);
virtual void setHelp(const char *);
virtual S32 getHelpTag(F32) { return mHelpTag; }
virtual const char *getHelpText(F32) { return mHelpText; }
virtual GuiCursor *getCursor() {return NULL; }
//methods for organizing the children
void addObject(SimObject*);
void removeObject(SimObject*);
GuiControl *getParent();
GuiCanvas *getRoot();
//parents//children coordinate and sizing methods
Point2I localToGlobalCoord(const Point2I &src);
Point2I globalToLocalCoord(const Point2I &src);
virtual void resize(const Point2I &newPosition, const Point2I &newExtent);
virtual void childResized(GuiControl *child);
virtual void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
//rendering related methods
virtual void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void renderChildControls(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void setUpdateRegion(Point2I pos, Point2I ext);
void setUpdate();
//child hierarchy calls
void awaken(); // called when this control and it's children have been wired up.
void sleep(); // called when this control are no longer
void preRender(); //prerender it and all it's children
//parent hierarchy calls - should call Parent::..();
virtual bool onWake();
virtual void onSleep(); //mostly resource stuff
virtual void onPreRender(); // do special pre render processing
virtual void onRemove();
//console related methods
virtual const char *getScriptValue();
virtual void setScriptValue(const char *value);
//mouse/keyboard input related methods
virtual bool pointInControl(const Point2I& parentCoordPoint);
bool cursorInControl();
virtual GuiControl* findHitControl(const Point2I &pt, S32 initialLayer = -1);
void mouseLock(GuiControl *lockingControl);
void mouseLock();
void mouseUnlock();
// General input handler -- for in-GUI control mapping:
virtual bool onInputEvent(const InputEvent &event);
virtual void onMouseUp(const GuiEvent &event);
virtual void onMouseDown(const GuiEvent &event);
virtual void onMouseMove(const GuiEvent &event);
virtual void onMouseDragged(const GuiEvent &event);
virtual void onMouseEnter(const GuiEvent &event);
virtual void onMouseLeave(const GuiEvent &event);
virtual bool onMouseWheelUp(const GuiEvent &event);
virtual bool onMouseWheelDown(const GuiEvent &event);
virtual void onRightMouseDown(const GuiEvent &event);
virtual void onRightMouseUp(const GuiEvent &event);
virtual void onRightMouseDragged(const GuiEvent &event);
virtual GuiControl* findFirstTabable();
virtual GuiControl* findLastTabable(bool firstCall = true);
virtual GuiControl* findPrevTabable(GuiControl *curResponder, bool firstCall = true);
virtual GuiControl* findNextTabable(GuiControl *curResponder, bool firstCall = true);
virtual bool ControlIsChild(GuiControl *child);
virtual void setFirstResponder(GuiControl *firstResponder);
void setFirstResponder();
void clearFirstResponder();
GuiControl *getFirstResponder() { return mFirstResponder; }
virtual void onLoseFirstResponder();
void AddAcceleratorKey();
void BuildAcceleratorMap();
virtual void AcceleratorKeyPress();
virtual void AcceleratorKeyRelease();
virtual bool onKeyDown(const GuiEvent &event);
virtual bool onKeyUp(const GuiEvent &event);
virtual bool onKeyRepeat(const GuiEvent &event);
//misc
void setControlProfile(GuiControlProfile *prof);
//the action
virtual void onAction();
//peer messaging
void messageSiblings(S32 message); //send a message to all siblings
virtual void onMessage(GuiControl *sender, S32 msg); //receive a message from another control
//functions called by the canvas
virtual void onDialogPush();
virtual void onDialogPop();
//this will move into the graphics library at some poing
bool createBitmapArray(GBitmap *bmp, RectI *boundsArray, S32 numStates, S32 numBitmaps);
};
// default renderer helper functions
void renderRaisedBox(const Point2I &offset, const Point2I &extent, const ColorI &color);
void renderLoweredBox(const Point2I &offset, const Point2I &extent, const ColorI &color);
#endif

View file

@ -0,0 +1,40 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/guiPopUpCtrl.h"
class GuiControlListPopUp : public GuiPopUpMenuCtrl
{
typedef GuiPopUpMenuCtrl Parent;
public:
bool onAdd();
static void consoleInit();
DECLARE_CONOBJECT(GuiControlListPopUp);
};
IMPLEMENT_CONOBJECT(GuiControlListPopUp);
void GuiControlListPopUp::consoleInit()
{
}
bool GuiControlListPopUp::onAdd()
{
if(!Parent::onAdd())
return false;
clear();
for(AbstractClassRep *rep = AbstractClassRep::getClassList(); rep; rep = rep->getNextClass())
{
ConsoleObject *obj = rep->create();
if(obj && dynamic_cast<GuiControl *>(obj))
addEntry(rep->getClassName(), 0);
delete obj;
}
return true;
}

1462
gui/guiDebugger.cc Normal file

File diff suppressed because it is too large Load diff

85
gui/guiDebugger.h Normal file
View file

@ -0,0 +1,85 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIDEBUGGER_H_
#define _GUIDEBUGGER_H_
#ifndef _GUIARRAYCTRL_H_
#include "GUI/guiArrayCtrl.h"
#endif
class DbgFileView : public GuiArrayCtrl
{
private:
typedef GuiArrayCtrl Parent;
struct FileLine
{
bool breakPosition;
bool breakOnLine;
char *text;
};
Vector<FileLine> mFileView;
StringTableEntry mFileName;
void AdjustCellSize();
//used to display the program counter
StringTableEntry mPCFileName;
S32 mPCCurrentLine;
//vars used to highlight the selected line segment for copying
bool mbMouseDragging;
S32 mMouseDownChar;
S32 mBlockStart;
S32 mBlockEnd;
char mMouseOverVariable[256];
char mMouseOverValue[256];
S32 findMouseOverChar(const char *text, S32 stringPosition);
bool findMouseOverVariable();
S32 mMouseVarStart;
S32 mMouseVarEnd;
//find vars
char mFindString[256];
S32 mFindLineNumber;
public:
DbgFileView();
~DbgFileView();
DECLARE_CONOBJECT(DbgFileView);
static void consoleInit();
bool onWake();
void clear();
void clearBreakPositions();
void setCurrentLine(S32 lineNumber, bool setCurrentLine);
const char *getCurrentLine(S32 &lineNumber);
bool openFile(const char *fileName);
void scrollToLine(S32 lineNumber);
void setBreakPointStatus(U32 lineNumber, bool value);
void setBreakPosition(U32 line);
void addLine(const char *text, U32 textLen);
bool findString(const char *text);
void onMouseDown(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
void onPreRender();
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
};
#endif //_GUI_DEBUGGER_H

View file

@ -0,0 +1,51 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
//
// Copyright (c) 2001 GarageGames.Com
//-----------------------------------------------------------------------------
#include "dgl/dgl.h"
#include "gui/guiDefaultControlRender.h"
#include "core/color.h"
#include "math/mRect.h"
static ColorI colorLightGray(192, 192, 192);
static ColorI colorGray(128, 128, 128);
static ColorI colorDarkGray(64, 64, 64);
static ColorI colorWhite(255,255,255);
static ColorI colorBlack(0,0,0);
void renderRaisedBox(RectI &bounds)
{
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x - 1;
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - 1;
dglDrawRectFill( bounds, colorLightGray);
dglDrawLine(l, t, l, b - 1, colorWhite);
dglDrawLine(l, t, r - 1, t, colorWhite);
dglDrawLine(l, b, r, b, colorBlack);
dglDrawLine(r, b - 1, r, t, colorBlack);
dglDrawLine(l + 1, b - 1, r - 1, b - 1, colorGray);
dglDrawLine(r - 1, b - 2, r - 1, t + 1, colorGray);
}
void renderLoweredBox(RectI &bounds)
{
S32 l = bounds.point.x, r = bounds.point.x + bounds.extent.x - 1;
S32 t = bounds.point.y, b = bounds.point.y + bounds.extent.y - 1;
dglDrawRectFill( bounds, colorLightGray);
dglDrawLine(l, b, r, b, colorWhite);
dglDrawLine(r, b - 1, r, t, colorWhite);
dglDrawLine(l, t, r - 1, t, colorBlack);
dglDrawLine(l, t + 1, l, b - 1, colorBlack);
dglDrawLine(l + 1, t + 1, r - 2, t + 1, colorGray);
dglDrawLine(l + 1, t + 2, l + 1, b - 2, colorGray);
}

View file

@ -0,0 +1,13 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
//
// Copyright (c) 2001 GarageGames.Com
//-----------------------------------------------------------------------------
#ifndef _H_GUIDEFAULTCONTROLRENDER_
#define _H_GUIDEFAULTCONTROLRENDER_
void renderRaisedBox(RectI &bounds);
void renderLoweredBox(RectI &bounds);
#endif

775
gui/guiEditCtrl.cc Normal file
View file

@ -0,0 +1,775 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "dgl/dgl.h"
#include "console/simBase.h"
#include "GUI/guiCanvas.h"
#include "GUI/guiEditCtrl.h"
#include "Platform/event.h"
#include "Core/fileStream.h"
GuiEditCtrl::GuiEditCtrl()
{
VECTOR_SET_ASSOCIATION(mSelectedControls);
mActive = true;
mCurrentAddSet = NULL;
mGridSnap.set(0, 0);
}
static void cGuiEditCtrlSetRoot(SimObject *obj, S32, const char **argv)
{
GuiControl *ctrl;
if(!Sim::findObject(argv[2], ctrl))
return;
((GuiEditCtrl *) obj)->setRoot(ctrl);
}
static void cGuiEditCtrlAdd(SimObject *obj, S32, const char **argv)
{
GuiControl *ctrl;
if(!Sim::findObject(argv[2], ctrl))
return;
((GuiEditCtrl *) obj)->addNewControl(ctrl);
}
static void cGuiEditCtrlSelect(SimObject *obj, S32, const char **argv)
{
GuiControl *ctrl;
if(!Sim::findObject(argv[2], ctrl))
return;
((GuiEditCtrl *) obj)->select(ctrl);
}
static void cGuiEditCtrlSetAddSet(SimObject *obj, S32, const char **argv)
{
GuiEditCtrl *editor = static_cast<GuiEditCtrl*>(obj);
GuiControl *addSet = NULL;
SimObject *target = Sim::findObject(argv[2]);
if (target)
addSet = dynamic_cast<GuiControl*>(target);
if (! addSet)
{
Con::printf("%s(): Invalid control: %s", argv[0], argv[2]);
return;
}
editor->setCurrentAddSet(addSet);
}
static void cGuiEditCtrlToggle(SimObject *obj, S32, const char **)
{
GuiEditCtrl *editor = static_cast<GuiEditCtrl*>(obj);
editor->setEditMode(! editor->mActive);
}
static void cGuiEditCtrlJustify(SimObject *obj, S32, const char **argv)
{
GuiEditCtrl *editor = static_cast<GuiEditCtrl*>(obj);
editor->justifySelection((GuiEditCtrl::Justification)dAtoi(argv[2]));
}
static void cGuiEditCtrlBringToFront(SimObject *obj, S32, const char **)
{
GuiEditCtrl *editor = static_cast<GuiEditCtrl*>(obj);
editor->bringToFront();
}
static void cGuiEditCtrlPushToBack(SimObject *obj, S32, const char **)
{
GuiEditCtrl *editor = static_cast<GuiEditCtrl*>(obj);
editor->pushToBack();
}
void GuiEditCtrl::consoleInit()
{
Con::addCommand("GuiEditCtrl", "addNewCtrl", cGuiEditCtrlAdd, "editCtrl.addNewCtrl(ctrl)", 3, 3);
Con::addCommand("GuiEditCtrl", "select", cGuiEditCtrlSelect, "editCtrl.select(ctrl)", 3, 3);
Con::addCommand("GuiEditCtrl", "setRoot", cGuiEditCtrlSetRoot, "editCtrl.setRoot(root)", 3, 3);
Con::addCommand("GuiEditCtrl", "setCurrentAddSet", cGuiEditCtrlSetAddSet, "editCtrl.setCurrentAddSet(ctrl)", 3, 3);
Con::addCommand("GuiEditCtrl", "toggle", cGuiEditCtrlToggle, "editCtrl.toggle()", 2, 2);
Con::addCommand("GuiEditCtrl", "justify", cGuiEditCtrlJustify, "editCtrl.justify(mode)", 3, 3);
Con::addCommand("GuiEditCtrl", "bringToFront", cGuiEditCtrlBringToFront, "editCtrl.bringToFront()", 2, 2);
Con::addCommand("GuiEditCtrl", "pushToBack", cGuiEditCtrlPushToBack, "editCtrl.pushToBack()", 2, 2);
}
bool GuiEditCtrl::onWake()
{
if (! Parent::onWake())
return false;
setEditMode(true);
return true;
}
void GuiEditCtrl::setRoot(GuiControl *root)
{
mContentControl = root;
}
enum { GUI_BLACK = 0, GUI_WHITE = 255 };
enum { NUT_SIZE = 3 };
void GuiEditCtrl::setEditMode(bool value)
{
mActive = value;
mSelectedControls.clear();
if (mActive && mAwake)
mCurrentAddSet = NULL;
}
void GuiEditCtrl::setCurrentAddSet(GuiControl *ctrl)
{
if (ctrl != mCurrentAddSet)
{
mSelectedControls.clear();
mCurrentAddSet = ctrl;
}
}
void GuiEditCtrl::setSelection(GuiControl *ctrl, bool inclusive)
{
//sanity check
if (! ctrl)
return;
// otherwise, we hit a new control...
GuiControl *newAddSet = ctrl->getParent();
//see if we should clear the old selection set
if (newAddSet != mCurrentAddSet || (! inclusive))
mSelectedControls.clear();
//set the selection
mCurrentAddSet = newAddSet;
mSelectedControls.push_back(ctrl);
}
void GuiEditCtrl::addNewControl(GuiControl *ctrl)
{
if (! mCurrentAddSet)
mCurrentAddSet = mContentControl;
mCurrentAddSet->addObject(ctrl);
mSelectedControls.clear();
mSelectedControls.push_back(ctrl);
}
void GuiEditCtrl::drawNut(const Point2I &nut, bool multisel)
{
RectI r(nut.x - NUT_SIZE, nut.y - NUT_SIZE, 2 * NUT_SIZE + 1, 2 * NUT_SIZE + 1);
dglDrawRect(r, multisel ? ColorI(0, 0, 0) : ColorI(255, 255, 255));
r.point += Point2I(1, 1);
r.extent -= Point2I(1, 1);
dglDrawRectFill(r, multisel ? ColorI(255, 255, 255) : ColorI(0, 0, 0));
}
static inline bool inNut(const Point2I &pt, S32 x, S32 y)
{
S32 dx = pt.x - x;
S32 dy = pt.y - y;
return dx <= NUT_SIZE && dx >= -NUT_SIZE && dy <= NUT_SIZE && dy >= -NUT_SIZE;
}
S32 GuiEditCtrl::getSizingHitKnobs(const Point2I &pt, const RectI &box)
{
S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1;
S32 cx = (lx + rx) >> 1;
S32 ty = box.point.y, by = box.point.y + box.extent.y - 1;
S32 cy = (ty + by) >> 1;
if (inNut(pt, lx, ty))
return sizingLeft | sizingTop;
if (inNut(pt, cx, ty))
return sizingTop;
if (inNut(pt, rx, ty))
return sizingRight | sizingTop;
if (inNut(pt, lx, by))
return sizingLeft | sizingBottom;
if (inNut(pt, cx, by))
return sizingBottom;
if (inNut(pt, rx, by))
return sizingRight | sizingBottom;
if (inNut(pt, lx, cy))
return sizingLeft;
if (inNut(pt, rx, cy))
return sizingRight;
return sizingNone;
}
void GuiEditCtrl::drawNuts(RectI &box, bool multisel)
{
S32 lx = box.point.x, rx = box.point.x + box.extent.x - 1;
S32 cx = (lx + rx) >> 1;
S32 ty = box.point.y, by = box.point.y + box.extent.y - 1;
S32 cy = (ty + by) >> 1;
drawNut(Point2I(lx, ty), multisel);
drawNut(Point2I(lx, cy), multisel);
drawNut(Point2I(lx, by), multisel);
drawNut(Point2I(rx, ty), multisel);
drawNut(Point2I(rx, cy), multisel);
drawNut(Point2I(rx, by), multisel);
drawNut(Point2I(cx, ty), multisel);
drawNut(Point2I(cx, by), multisel);
}
void GuiEditCtrl::getDragRect(RectI &box)
{
box.point.x = getMin(mLastMousePos.x, mSelectionAnchor.x);
box.extent.x = getMax(mLastMousePos.x, mSelectionAnchor.x) - box.point.x + 1;
box.point.y = getMin(mLastMousePos.y, mSelectionAnchor.y);
box.extent.y = getMax(mLastMousePos.y, mSelectionAnchor.y) - box.point.y + 1;
}
void GuiEditCtrl::onPreRender()
{
setUpdate();
}
void GuiEditCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
Point2I ctOffset;
Point2I cext;
if (mActive)
{
if (mCurrentAddSet)
{
// draw a white frame inset around the current add set.
cext = mCurrentAddSet->getExtent();
ctOffset = mCurrentAddSet->localToGlobalCoord(Point2I(0,0));
RectI box(ctOffset.x + 1,ctOffset.y + 1, cext.x - 2, cext.y - 2);
dglDrawRect(box, ColorI(255, 255, 255));
box.point -= Point2I(1, 1);
box.extent += Point2I(1, 1);
dglDrawRect(box, ColorI(0, 0, 0));
}
Vector<GuiControl *>::iterator i;
bool multisel = mSelectedControls.size() > 1;
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
{
GuiControl *ctrl = (*i);
cext = ctrl->getExtent();
ctOffset = ctrl->localToGlobalCoord(Point2I(0,0));
RectI box(ctOffset.x,ctOffset.y, cext.x, cext.y);
drawNuts(box, multisel);
}
if (mMouseDownMode == DragSelecting)
{
RectI b;
getDragRect(b);
dglDrawRect(b, ColorI(255, 255, 255));
}
}
renderChildControls(offset, updateRect, firstResponder);
}
bool GuiEditCtrl::selectionContains(GuiControl *ctrl)
{
Vector<GuiControl *>::iterator i;
for (i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
if (ctrl == *i) return true;
return false;
}
void GuiEditCtrl::onRightMouseDown(const GuiEvent &event)
{
if (! mActive)
{
Parent::onRightMouseDown(event);
return;
}
setFirstResponder();
//search for the control hit in any layer below the edit layer
GuiControl *hitCtrl = mContentControl->findHitControl(event.mousePoint, mLayer - 1);
if (hitCtrl != mCurrentAddSet)
{
mSelectedControls.clear();
mCurrentAddSet = hitCtrl;
}
}
void GuiEditCtrl::select(GuiControl *ctrl)
{
mSelectedControls.clear();
if(ctrl != mContentControl)
mSelectedControls.push_back(ctrl);
else
mCurrentAddSet = mContentControl;
}
void GuiEditCtrl::onMouseDown(const GuiEvent &event)
{
if (! mActive)
{
Parent::onMouseDown(event);
return;
}
if(!mContentControl)
return;
setFirstResponder();
//lock the mouse
mouseLock();
Point2I ctOffset;
Point2I cext;
GuiControl *ctrl;
mLastMousePos = event.mousePoint;
// first see if we hit a sizing knob on the currently selected control...
if (mSelectedControls.size() == 1)
{
ctrl = mSelectedControls.first();
cext = ctrl->getExtent();
ctOffset = ctrl->localToGlobalCoord(Point2I(0,0));
RectI box(ctOffset.x,ctOffset.y,cext.x, cext.y);
if ((mSizingMode = (GuiEditCtrl::sizingModes)getSizingHitKnobs(event.mousePoint, box)) != 0)
{
mMouseDownMode = SizingSelection;
return;
}
}
if(!mCurrentAddSet)
mCurrentAddSet = mContentControl;
//find the control we clicked
ctrl = mContentControl->findHitControl(event.mousePoint, mCurrentAddSet->mLayer);
if (selectionContains(ctrl))
{
//if we're holding shift, de-select the clicked ctrl
if (event.modifier & SI_SHIFT)
{
Vector<GuiControl *>::iterator i;
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
{
if (*i == ctrl)
{
mSelectedControls.erase(i);
break;
}
}
//set the mode
mMouseDownMode = Selecting;
}
//else we hit a ctrl we've already selected, so set the mode to moving
else
mMouseDownMode = MovingSelection;
}
//else we clicked on an unselected control
else
{
//if we clicked in the current add set
if (ctrl == mCurrentAddSet)
{
// start dragging a rectangle
// if the shift is not down, nuke prior selection
if (!(event.modifier & SI_SHIFT))
mSelectedControls.clear();
mSelectionAnchor = event.mousePoint;
mMouseDownMode = DragSelecting;
}
else
{
//find the new add set
GuiControl *newAddSet = ctrl->getParent();
//if we're holding shift and the ctrl is in the same add set
if (event.modifier & SI_SHIFT && newAddSet == mCurrentAddSet)
{
mSelectedControls.push_back(ctrl);
mMouseDownMode = Selecting;
}
else if (ctrl != mContentControl)
{
//find and set the new add set
mCurrentAddSet = ctrl->getParent();
//clear and set the selected controls
mSelectedControls.clear();
mSelectedControls.push_back(ctrl);
mMouseDownMode = Selecting;
}
else
mMouseDownMode = Selecting;
}
}
}
void GuiEditCtrl::onMouseUp(const GuiEvent &event)
{
if (! mActive)
{
Parent::onMouseUp(event);
return;
}
//unlock the mouse
mouseUnlock();
mLastMousePos = event.mousePoint;
if (mMouseDownMode == DragSelecting)
{
RectI b;
getDragRect(b);
GuiControl::iterator i;
for(i = mCurrentAddSet->begin(); i != mCurrentAddSet->end(); i++)
{
GuiControl *ctrl = dynamic_cast<GuiControl *>(*i);
Point2I upperL = ctrl->localToGlobalCoord(Point2I(0,0));
Point2I lowerR = upperL + ctrl->mBounds.extent - Point2I(1, 1);
if (b.pointInRect(upperL) && b.pointInRect(lowerR) && !selectionContains(ctrl))
mSelectedControls.push_back(ctrl);
}
}
if (mSelectedControls.size() == 1)
Con::executef(this, 2, "onSelect", avar("%d", mSelectedControls[0]->getId()));
setFirstResponder();
//reset the mouse mode
mMouseDownMode = Selecting;
}
void GuiEditCtrl::onMouseDragged(const GuiEvent &event)
{
if (! mActive)
{
Parent::onMouseDragged(event);
return;
}
if(!mCurrentAddSet)
mCurrentAddSet = mContentControl;
Point2I mousePoint = event.mousePoint;
if (mMouseDownMode == SizingSelection)
{
if (mGridSnap.x)
mousePoint.x -= mousePoint.x % mGridSnap.x;
if (mGridSnap.y)
mousePoint.y -= mousePoint.y % mGridSnap.y;
GuiControl *ctrl = mSelectedControls.first();
Point2I ctrlPoint = mCurrentAddSet->globalToLocalCoord(mousePoint);
Point2I newPosition = ctrl->getPosition();
Point2I newExtent = ctrl->getExtent();
Point2I minExtent = ctrl->getMinExtent();
if (mSizingMode & sizingLeft)
{
newPosition.x = ctrlPoint.x;
newExtent.x = ctrl->mBounds.extent.x + ctrl->mBounds.point.x - ctrlPoint.x;
if(newExtent.x < minExtent.x)
{
newPosition.x -= minExtent.x - newExtent.x;
newExtent.x = minExtent.x;
}
}
else if (mSizingMode & sizingRight)
{
newExtent.x = ctrlPoint.x - ctrl->mBounds.point.x;
if(newExtent.x < minExtent.x)
newExtent.x = minExtent.x;
}
if (mSizingMode & sizingTop)
{
newPosition.y = ctrlPoint.y;
newExtent.y = ctrl->mBounds.extent.y + ctrl->mBounds.point.y - ctrlPoint.y;
if(newExtent.y < minExtent.y)
{
newPosition.y -= minExtent.y - newExtent.y;
newExtent.y = minExtent.y;
}
}
else if (mSizingMode & sizingBottom)
{
newExtent.y = ctrlPoint.y - ctrl->mBounds.point.y;
if(newExtent.y < minExtent.y)
newExtent.y = minExtent.y;
}
ctrl->resize(newPosition, newExtent);
mCurrentAddSet->childResized(ctrl);
}
else if (mMouseDownMode == MovingSelection && mSelectedControls.size())
{
Vector<GuiControl *>::iterator i = mSelectedControls.begin();
Point2I minPos = (*i)->mBounds.point;
for(; i != mSelectedControls.end(); i++)
{
if ((*i)->mBounds.point.x < minPos.x)
minPos.x = (*i)->mBounds.point.x;
if ((*i)->mBounds.point.y < minPos.y)
minPos.y = (*i)->mBounds.point.y;
}
Point2I delta = mousePoint - mLastMousePos;
delta += minPos; // find new minPos;
if (mGridSnap.x)
delta.x -= delta.x % mGridSnap.x;
if (mGridSnap.y)
delta.y -= delta.y % mGridSnap.y;
delta -= minPos;
moveSelection(delta);
mLastMousePos += delta;
}
else
mLastMousePos = mousePoint;
}
void GuiEditCtrl::moveSelection(const Point2I &delta)
{
Vector<GuiControl *>::iterator i;
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
(*i)->resize((*i)->mBounds.point + delta, (*i)->mBounds.extent);
}
void GuiEditCtrl::justifySelection(Justification j)
{
S32 minX, maxX;
S32 minY, maxY;
S32 extentX, extentY;
if (mSelectedControls.size() < 2)
return;
Vector<GuiControl *>::iterator i = mSelectedControls.begin();
minX = (*i)->mBounds.point.x;
maxX = minX + (*i)->mBounds.extent.x;
minY = (*i)->mBounds.point.y;
maxY = minY + (*i)->mBounds.extent.y;
extentX = (*i)->mBounds.extent.x;
extentY = (*i)->mBounds.extent.y;
i++;
for(;i != mSelectedControls.end(); i++)
{
minX = getMin(minX, (*i)->mBounds.point.x);
maxX = getMax(maxX, (*i)->mBounds.point.x + (*i)->mBounds.extent.x);
minY = getMin(minY, (*i)->mBounds.point.y);
maxY = getMax(maxY, (*i)->mBounds.point.y + (*i)->mBounds.extent.y);
extentX += (*i)->mBounds.extent.x;
extentY += (*i)->mBounds.extent.y;
}
S32 deltaX = maxX - minX;
S32 deltaY = maxY - minY;
switch(j)
{
case JUSTIFY_LEFT:
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
(*i)->resize(Point2I(minX, (*i)->mBounds.point.y), (*i)->mBounds.extent);
break;
case JUSTIFY_TOP:
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
(*i)->resize(Point2I((*i)->mBounds.point.x, minY), (*i)->mBounds.extent);
break;
case JUSTIFY_RIGHT:
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
(*i)->resize(Point2I(maxX - (*i)->mBounds.extent.x + 1, (*i)->mBounds.point.y), (*i)->mBounds.extent);
break;
case JUSTIFY_BOTTOM:
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
(*i)->resize(Point2I((*i)->mBounds.point.x, maxY - (*i)->mBounds.extent.y + 1), (*i)->mBounds.extent);
break;
case JUSTIFY_CENTER:
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
(*i)->resize(Point2I(minX + ((deltaX - (*i)->mBounds.extent.x) >> 1), (*i)->mBounds.point.y),
(*i)->mBounds.extent);
break;
case SPACING_VERTICAL:
{
Vector<GuiControl *> sortedList;
Vector<GuiControl *>::iterator k;
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
{
for(k = sortedList.begin(); k != sortedList.end(); k++)
{
if ((*i)->mBounds.point.y < (*k)->mBounds.point.y)
break;
}
sortedList.insert(k, *i);
}
S32 space = (deltaY - extentY) / (mSelectedControls.size() - 1);
S32 curY = minY;
for(k = sortedList.begin(); k != sortedList.end(); k++)
{
(*k)->resize(Point2I((*k)->mBounds.point.x, curY), (*k)->mBounds.extent);
curY += (*k)->mBounds.extent.y + space;
}
}
break;
case SPACING_HORIZONTAL:
{
Vector<GuiControl *> sortedList;
Vector<GuiControl *>::iterator k;
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
{
for(k = sortedList.begin(); k != sortedList.end(); k++)
{
if ((*i)->mBounds.point.x < (*k)->mBounds.point.x)
break;
}
sortedList.insert(k, *i);
}
S32 space = (deltaX - extentX) / (mSelectedControls.size() - 1);
S32 curX = minX;
for(k = sortedList.begin(); k != sortedList.end(); k++)
{
(*k)->resize(Point2I(curX, (*k)->mBounds.point.y), (*k)->mBounds.extent);
curX += (*k)->mBounds.extent.x + space;
}
}
break;
}
}
void GuiEditCtrl::deleteSelection(void)
{
Vector<GuiControl *>::iterator i;
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
(*i)->deleteObject();
mSelectedControls.clear();
}
void GuiEditCtrl::loadSelection(const char* filename)
{
if (! mCurrentAddSet)
mCurrentAddSet = mContentControl;
Con::executef(2, "exec", filename);
SimSet *set;
if(!Sim::findObject("guiClipboard", set))
return;
if(set->size())
{
mSelectedControls.clear();
for(U32 i = 0; i < set->size(); i++)
{
GuiControl *ctrl = dynamic_cast<GuiControl *>((*set)[i]);
if(ctrl)
{
mCurrentAddSet->addObject(ctrl);
mSelectedControls.push_back(ctrl);
}
}
}
set->deleteObject();
}
void GuiEditCtrl::saveSelection(const char* filename)
{
FileStream stream;
if(!ResourceManager->openFileForWrite(stream, NULL, filename))
return;
SimSet *clipboardSet = new SimSet;
clipboardSet->registerObject();
Sim::getRootGroup()->addObject(clipboardSet, "guiClipboard");
Vector<GuiControl *>::iterator i;
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
clipboardSet->addObject(*i);
clipboardSet->write(stream, 0);
clipboardSet->deleteObject();
}
void GuiEditCtrl::selectAll()
{
GuiControl::iterator i;
if (!mCurrentAddSet)
return;
mSelectedControls.clear();
for(i = mCurrentAddSet->begin(); i != mCurrentAddSet->end(); i++)
{
GuiControl *ctrl = dynamic_cast<GuiControl *>(*i);
mSelectedControls.push_back(ctrl);
}
}
void GuiEditCtrl::bringToFront()
{
if (mSelectedControls.size() != 1)
return;
GuiControl *ctrl = *(mSelectedControls.begin());
mCurrentAddSet->bringObjectToFront(ctrl);
}
void GuiEditCtrl::pushToBack()
{
if (mSelectedControls.size() != 1)
return;
GuiControl *ctrl = *(mSelectedControls.begin());
mCurrentAddSet->pushObjectToBack(ctrl);
}
bool GuiEditCtrl::onKeyDown(const GuiEvent &event)
{
if (! mActive)
return Parent::onKeyDown(event);
if (event.modifier & SI_CTRL)
{
switch(event.keyCode)
{
case KEY_A:
selectAll();
break;
case KEY_C:
saveSelection("gui/clipboard.gui");
break;
case KEY_X:
saveSelection("gui/clipboard.gui");
deleteSelection();
break;
case KEY_V:
loadSelection("gui/clipboard.gui");
break;
}
}
else
{
S32 delta = (event.modifier & SI_SHIFT) ? 10 : 1;
switch(event.keyCode)
{
case KEY_RIGHT:
moveSelection(Point2I(delta, 0));
break;
case KEY_LEFT:
moveSelection(Point2I(-delta, 0));
break;
case KEY_UP:
moveSelection(Point2I(0, -delta));
break;
case KEY_DOWN:
moveSelection(Point2I(0, delta));
break;
case KEY_BACKSPACE:
case KEY_DELETE:
deleteSelection();
break;
}
}
return false;
}

79
gui/guiEditCtrl.h Normal file
View file

@ -0,0 +1,79 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIEDITCTRL_H_
#define _GUIEDITCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
class GuiEditCtrl : public GuiControl
{
typedef GuiControl Parent;
Vector<GuiControl *> mSelectedControls;
GuiControl* mCurrentAddSet;
GuiControl* mContentControl;
Point2I mLastMousePos;
Point2I mSelectionAnchor;
Point2I mGridSnap;
enum mouseModes { Selecting, MovingSelection, SizingSelection, DragSelecting };
enum sizingModes { sizingNone = 0, sizingLeft = 1, sizingRight = 2, sizingTop = 4, sizingBottom = 8 };
mouseModes mMouseDownMode;
sizingModes mSizingMode;
public:
GuiEditCtrl();
DECLARE_CONOBJECT(GuiEditCtrl);
static void consoleInit();
bool onWake();
void select(GuiControl *ctrl);
void setRoot(GuiControl *ctrl);
void setEditMode(bool value);
S32 getSizingHitKnobs(const Point2I &pt, const RectI &box);
void getDragRect(RectI &b);
void drawNut(const Point2I &nut, bool);
void drawNuts(RectI &box, bool);
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void addNewControl(GuiControl *ctrl);
bool selectionContains(GuiControl *ctrl);
void setCurrentAddSet(GuiControl *ctrl);
void setSelection(GuiControl *ctrl, bool inclusive = false);
bool onKeyDown(const GuiEvent &event);
void onMouseDown(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
void onRightMouseDown(const GuiEvent &event);
enum Justification {
JUSTIFY_LEFT,
JUSTIFY_CENTER,
JUSTIFY_RIGHT,
JUSTIFY_TOP,
JUSTIFY_BOTTOM,
SPACING_VERTICAL,
SPACING_HORIZONTAL
};
void justifySelection( Justification j);
void moveSelection(const Point2I &delta);
void saveSelection(const char *filename);
void loadSelection(const char *filename);
void deleteSelection();
void selectAll();
void bringToFront();
void pushToBack();
};
#endif //_GUI_EDIT_CTRL_H

251
gui/guiFilterCtrl.cc Normal file
View file

@ -0,0 +1,251 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "dgl/gTexManager.h"
#include "GUI/guiFilterCtrl.h"
#include "Platform/event.h"
#include "Math/mMath.h"
GuiFilterCtrl::GuiFilterCtrl()
{
mControlPointRequest = 7;
mFilter.setSize(7);
identity();
}
void GuiFilterCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("controlPoints", TypeS32, Offset(mControlPointRequest, GuiFilterCtrl));
addField("filter", TypeF32Vector, Offset(mFilter, GuiFilterCtrl));
}
static const char* cGuiFilter_GetValue(SimObject *obj, S32, const char **argv)
{
argv;
static char buffer[512];
const Filter *filter = static_cast<GuiFilterCtrl*>(obj)->get();
*buffer = 0;
for (U32 i=0; i < filter->size(); i++)
{
char value[32];
dSprintf(value, 31, "%1.5f ", *(filter->begin()+i) );
dStrcat(buffer, value);
}
return buffer;
}
static void cGuiFilter_SetValue(SimObject *obj, S32 argc, const char **argv)
{
GuiFilterCtrl *ctrl = static_cast<GuiFilterCtrl*>(obj);
Filter filter;
argc -= 2;
argv += 2;
filter.set(argc, argv);
ctrl->set(filter);
}
static void cGuiFilter_Identity(SimObject *obj, S32, const char **)
{
GuiFilterCtrl *ctrl = static_cast<GuiFilterCtrl*>(obj);
ctrl->identity();
}
void GuiFilterCtrl::consoleInit()
{
Con::addCommand("GuiFilterCtrl", "getValue", cGuiFilter_GetValue, "guiFilterCtrl.getValue()", 2, 2);
Con::addCommand("GuiFilterCtrl", "setValue", cGuiFilter_SetValue, "guiFilterCtrl.setValue(f1, f2, ...)", 3, 20);
Con::addCommand("GuiFilterCtrl", "identity", cGuiFilter_Identity, "guiFilterCtrl.identity()", 2, 2);
}
bool GuiFilterCtrl::onWake()
{
if (!Parent::onWake())
return false;
if (U32(mControlPointRequest) != mFilter.size())
{
mFilter.setSize(mControlPointRequest);
identity();
}
return true;
}
void GuiFilterCtrl::identity()
{
S32 size = mFilter.size()-1;
for (U32 i=0; S32(i) <= size; i++)
mFilter[i] = (F32)i/(F32)size;
}
void GuiFilterCtrl::onMouseDown(const GuiEvent &event)
{
mouseLock();
setFirstResponder();
Point2I p = globalToLocalCoord(event.mousePoint);
// determine which knot (offset same as in onRender)
F32 w = F32(mBounds.extent.x-4) / F32(mFilter.size()-1);
F32 val = (F32(p.x) + (w / 2.f)) / w;
mCurKnot = S32(val);
mFilter[mCurKnot] = 1.0f - F32(getMin(getMax(0, p.y), mBounds.extent.y)/(F32)mBounds.extent.y);
setUpdate();
}
void GuiFilterCtrl::onMouseDragged(const GuiEvent &event)
{
mouseLock();
setFirstResponder();
Point2I p = globalToLocalCoord(event.mousePoint);
mFilter[mCurKnot] = 1.0f - F32(getMin(getMax(0, p.y), mBounds.extent.y)/(F32)mBounds.extent.y);
setUpdate();
}
void GuiFilterCtrl::onMouseUp(const GuiEvent &)
{
mouseUnlock();
if (mConsoleCommand[0])
Con::evaluate(mConsoleCommand, false);
}
void GuiFilterCtrl::onPreRender()
{
if(U32(mControlPointRequest) != mFilter.size())
{
mFilter.setSize(mControlPointRequest);
identity();
setUpdate();
}
}
void GuiFilterCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
Point2I pos = offset;
Point2I ext = mBounds.extent;
RectI r(pos, ext);
dglDrawRectFill(r, ColorI(255,255,255));
dglDrawRect(r, ColorI(0,0,0));
// shrink by 2 pixels
pos.x += 2;
pos.y += 2;
ext.x -= 4;
ext.y -= 4;
// draw the identity line
glColor3f(0.9, 0.9, 0.9);
glBegin(GL_LINES);
glVertex2i(pos.x, pos.y+ext.y);
glVertex2i(pos.x+ext.x, pos.y);
glEnd();
// draw the curv
glColor3f(0.4, 0.4, 0.4);
glBegin(GL_LINE_STRIP);
F32 scale = 1.0f/F32(ext.x);
for (U32 i=0; S32(i) < ext.x; i++)
{
F32 index = F32(i)*scale;
S32 y = (S32)(ext.y*(1.0f-mFilter.getValue(index)));
glVertex2i(pos.x+i, pos.y+y );
}
glEnd();
// draw the knots
for (U32 k=0; k < mFilter.size(); k++)
{
RectI r;
r.point.x = (S32)(((F32)ext.x/(F32)(mFilter.size()-1)*(F32)k));
r.point.y = (S32)(ext.y - ((F32)ext.y * mFilter[k]));
r.point += pos + Point2I(-2,-2);
r.extent = Point2I(5,5);
dglDrawRectFill(r, ColorI(255,0,0));
}
renderChildControls(offset, updateRect, firstResponder);
}
//--------------------------------------
void Filter::set(S32 argc, const char *argv[])
{
setSize(0);
if (argc == 1)
{ // in the form of one string "1.0 1.0 1.0"
char list[1024];
dStrcpy(list, *argv); // strtok modifies the string so we need to copy it
char *value = dStrtok(list, " ");
while (value)
{
push_back(dAtof(value));
value = dStrtok(NULL, " ");
}
}
else
{ // in the form of seperate strings "1.0" "1.0" "1.0"
for (; argc ; argc--, argv++)
push_back(dAtof(*argv));
}
}
//--------------------------------------
F32 Filter::getValue(F32 x) const
{
if (size() < 2)
return 0.0f;
x = mClampF(x, 0.0f, 1.0f);
x *= F32(size()-1);
F32 p0,p1,p2,p3;
S32 i1 = (S32)mFloor(x);
S32 i2 = i1+1;
F32 dt = x - F32(i1);
p1 = *(begin()+i1);
p2 = *(begin()+i2);
if (i1 == 0)
p0 = p1 + (p1 - p2);
else
p0 = *(begin()+i1-1);
if (i2 == S32(size()-1))
p3 = p2 + (p2 - p1);
else
p3 = *(begin()+i2+1);
return mClampF( mCatmullrom(dt, p0, p1, p2, p3), 0.0f, 1.0f );
}

77
gui/guiFilterCtrl.h Normal file
View file

@ -0,0 +1,77 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIFILTERCTRL_H_
#define _GUIFILTERCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
//--------------------------------------
// helper class
class Filter: public Vector<F32>
{
public:
Filter() : Vector<F32>(__FILE__, __LINE__) { }
void set(S32 argc, const char *argv[]);
F32 getValue(F32 t) const;
};
//--------------------------------------
class GuiFilterCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
S32 mControlPointRequest;
S32 mCurKnot;
Filter mFilter;
public:
//creation methods
DECLARE_CONOBJECT(GuiFilterCtrl);
GuiFilterCtrl();
static void initPersistFields();
static void consoleInit();
//Parental methods
bool onWake();
void onMouseDown(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
void onMouseUp(const GuiEvent &);
F32 getValue(S32 n);
const Filter* get() { return &mFilter; }
void set(const Filter &f);
S32 getNumControlPoints() {return mFilter.size(); }
void identity();
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
};
inline F32 GuiFilterCtrl::getValue(S32 n)
{
S32 index = getMin(getMax(n,0), (S32)mFilter.size()-1);
return mFilter[n];
}
inline void GuiFilterCtrl::set(const Filter &f)
{
mControlPointRequest = f.size();
mFilter = f;
}
#endif

1048
gui/guiFrameCtrl.cc Normal file

File diff suppressed because it is too large Load diff

182
gui/guiFrameCtrl.h Normal file
View file

@ -0,0 +1,182 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
/******************************************************************************
* FILENAME: D:\Tribes\darkstar\GUI\guiFrameCtrl.h
*
* DESCRIPTION: A gui control allowing a window to be subdivided into panes,
* each of which displays a gui control child of the
* GuiFrameSetCtrl. Each gui control child will have an associated
* FrameDetail through which frame-specific details can be
* assigned. Frame-specific values override the values specified
* for the entire frameset.
*
* Note that it is possible to have more children than frames,
* or more frames than children. In the former case, the extra
* children will not be visible (they are moved beyond the
* visible extent of the frameset). In the latter case, frames
* will be empty.
*
* If a frameset had two columns and two rows but only three
* gui control children they would be assigned to frames as
* follows:
* 1 | 2
* -----
* 3 |
*
* The last frame would be blank.
*
* CREATED: 10/08/99 14:40:24
*
* BY: PeteW
******************************************************************************/
#ifndef _GUIFRAMECTRL_H_
#define _GUIFRAMECTRL_H_
#define DISABLE_COPY_CTOR(className) \
className(const className &)
#define DISABLE_ASSIGNMENT(className) \
className& operator=(const className &)
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
// for debugging porpoises...
#define GUI_FRAME_DEBUG
// ...save the porpoises
class GuiFrameSetCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
public:
enum
{
FRAME_STATE_ON, // ON overrides OFF
FRAME_STATE_OFF, // OFF overrides AUTO
FRAME_STATE_AUTO, // AUTO == ON, unless overridden
NO_HIT = -1,
DEFAULT_BORDER_WIDTH = 4,
DEFAULT_COLUMNS = 1,
DEFAULT_ROWS = 1,
DEFAULT_MIN_FRAME_EXTENT = 20
};
enum Region
{
VERTICAL_DIVIDER,
HORIZONTAL_DIVIDER,
DIVIDER_INTERSECTION,
NONE
};
struct FrameDetail
{
U32 mBorderWidth;
ColorI mBorderColor;
S32 mBorderEnable;
S32 mBorderMovable;
Point2I mMinExtent;
FrameDetail() { mBorderWidth = DEFAULT_BORDER_WIDTH; mBorderEnable = FRAME_STATE_AUTO; mBorderMovable = FRAME_STATE_AUTO; mMinExtent.set(DEFAULT_MIN_FRAME_EXTENT, DEFAULT_MIN_FRAME_EXTENT); }
};
DECLARE_CONOBJECT(GuiFrameSetCtrl);
static void consoleInit();
static void initPersistFields();
GuiFrameSetCtrl();
GuiFrameSetCtrl(U32 columns, U32 rows, const U32 columnOffsets[] = NULL, const U32 rowOffsets[] = NULL);
virtual ~GuiFrameSetCtrl();
void addObject(SimObject *object);
void removeObject(SimObject *object);
virtual void resize(const Point2I &newPos, const Point2I &newExtent);
virtual void onMouseMove(const GuiEvent &event);
virtual void onMouseDown(const GuiEvent &event);
virtual void onMouseUp(const GuiEvent &event);
virtual void onMouseDragged(const GuiEvent &event);
virtual void onMouseEnter(const GuiEvent &event);
virtual void onMouseLeave(const GuiEvent &event);
bool onAdd();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
protected:
/* member variables */
Vector<S32> mColumnOffsets;
Vector<S32> mRowOffsets;
GuiCursor *mMoveCursor;
GuiCursor *mUpDownCursor;
GuiCursor *mLeftRightCursor;
GuiCursor *mDefaultCursor;
FrameDetail mFramesetDetails;
VectorPtr<FrameDetail *> mFrameDetails;
bool mAutoBalance;
S32 mFudgeFactor;
/* divider activation member variables */
Region mCurHitRegion;
Point2I mLocOnDivider;
S32 mCurVerticalHit;
S32 mCurHorizontalHit;
bool init(U32 columns, U32 rows, const U32 columnOffsets[], const U32 rowOffsets[]);
bool initCursors();
Region findHitRegion(const Point2I &point);
Region pointInAnyRegion(const Point2I &point);
S32 findResizableFrames(S32 indexes[]);
bool hitVerticalDivider(S32 x, const Point2I &point);
bool hitHorizontalDivider(S32 y, const Point2I &point);
void rebalance(const Point2I &newExtent);
void computeSizes(bool balanceFrames = false);
void computeMovableRange(Region hitRegion, S32 vertHit, S32 horzHit, S32 numIndexes, const S32 indexes[], S32 ranges[]);
void drawDividers(const Point2I &offset);
public:
U32 columns() const { return(mColumnOffsets.size()); }
U32 rows() const { return(mRowOffsets.size()); }
U32 borderWidth() const { return(mFramesetDetails.mBorderWidth); }
Vector<S32>* columnOffsets() { return(&mColumnOffsets); }
Vector<S32>* rowOffsets() { return(&mRowOffsets); }
FrameDetail* framesetDetails() { return(&mFramesetDetails); }
bool findFrameContents(S32 index, GuiControl **gc, FrameDetail **fd);
void frameBorderEnable(S32 index, const char *state = NULL);
void frameBorderMovable(S32 index, const char *state = NULL);
void frameMinExtent(S32 index, const Point2I &extent);
void balanceFrames() { computeSizes(true); }
void updateSizes() { computeSizes(); }
private:
DISABLE_COPY_CTOR(GuiFrameSetCtrl);
DISABLE_ASSIGNMENT(GuiFrameSetCtrl);
};
//-----------------------------------------------------------------------------
// x is the first value inside the next column, so the divider x-coords
// precede x.
inline bool GuiFrameSetCtrl::hitVerticalDivider(S32 x, const Point2I &point)
{
return((point.x >= S32(x - mFramesetDetails.mBorderWidth)) && (point.x < x) && (point.y >= 0) && (point.y < S32(mBounds.extent.y)));
}
//-----------------------------------------------------------------------------
// y is the first value inside the next row, so the divider y-coords precede y.
inline bool GuiFrameSetCtrl::hitHorizontalDivider(S32 y, const Point2I &point)
{
return((point.x >= 0) && (point.x < S32(mBounds.extent.x)) && (point.y >= S32(y - mFramesetDetails.mBorderWidth)) && (point.y < y));
}
#endif // _GUI_FRAME_CTRL_H

99
gui/guiHelpCtrl.cc Normal file
View file

@ -0,0 +1,99 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "g_surfac.h"
#include "GUI/guiCanvas.h"
#include "GUI/guiHelpCtrl.h"
GuiHelpCtrl::GuiHelpCtrl(void)
{
//set the id
id = guiHelpObjectID;
mHelpTag = 0;
mHelpText = NULL;
}
GuiHelpCtrl::~GuiHelpCtrl()
{
if (mHelpText)
{
delete [] (char*)mHelpText;
mHelpText = NULL;
}
}
bool GuiHelpCtrl::onAdd(void)
{
if (! Parent::onAdd())
return FALSE;
setGFXFont(mFont, mFontString);
setGFXFont(mFontHL, mFontStringHL);
setGFXFont(mFontNA, mFontStringNA);
return TRUE;
}
void GuiHelpCtrl::render(GFXSurface *sfc)
{
if ((! mHelpText) || (! mHelpText[0]))
return;
//if opaque, fill the update rect with the fill color
if (mOpaque)
{
sfc->drawRect2d_f(&RectI(mPosition, Point2I(mPosition.x + mExtent.x - 1, mPosition.y + mExtent.y - 1)), mFillColor);
}
//if there's a boarder, draw the boarder
if (mBorder)
{
sfc->drawRect2d(&RectI(mPosition, Point2I(mPosition.x + mExtent.x - 1, mPosition.y + mExtent.y - 1)), mBorderColor);
}
//draw the help text
sfc->drawText_p(mFont, &Point2I(mPosition.x + 2, mPosition.y), mHelpText);
}
void GuiHelpCtrl::setHelpText(guiCanvas *root, const char *text, F32 /* rElapsedTime */, bool /*mouseClicked*/)
{
Point2I newPos, newExt;
if (mHelpText)
{
delete [] (char*)mHelpText;
mHelpText = NULL;
newPos.set(0, 0);
newExt.set(1, 1);
}
if (text && text[0])
{
mHelpText = strnew(text);
mHelpTag = 0;
if (bool(mFont) && root)
{
newExt.set(mFont->getStrWidth(text) + 4, mFont->getHeight() + 4);
newPos = root->getCursorPos();
newPos.x = MAX(0, MIN(newPos.x, root->mExtent.x - newExt.x));
newPos.y = MAX(0, MIN(newPos.y, root->mExtent.y - newExt.y));
}
}
resize(newPos, newExt);
}
void GuiHelpCtrl::setHelpTag(guiCanvas *root, S32 helpTag, F32 /* rElapsedTime */, bool /*mouseClicked*/)
{
if (mHelpText)
{
delete [] (char*)mHelpText;
mHelpText = NULL;
}
mHelpTag = helpTag;
}

40
gui/guiHelpCtrl.h Normal file
View file

@ -0,0 +1,40 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIHELPCTRL_H_
#define _GUIHELPCTRL_H_
#ifndef _GUITEXTCTRL_H_
#include "GUI/guiTextCtrl.h"
#endif
class guiCanvas;
class GuiHelpCtrl : public guiTextCtrl
{
private:
typedef guiTextCtrl Parent;
protected:
S32 mHelpTag;
const char *mHelpText;
public:
GuiHelpCtrl();
~GuiHelpCtrl();
bool onAdd(void);
virtual void setHelpText(guiCanvas *root, const char *text, F32 timeElapsed, bool mouseClicked = FALSE);
virtual void setHelpTag(guiCanvas *root, S32 helpTag, F32 timeElapsed, bool mouseClicked = FALSE);
virtual void render(GFXSurface *sfc);
DECLARE_PERSISTENT(GuiHelpCtrl);
};
#endif //_GUI_HELP_CTRL_H

94
gui/guiInputCtrl.cc Normal file
View file

@ -0,0 +1,94 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "gui/guiInputCtrl.h"
#include "sim/actionMap.h"
IMPLEMENT_CONOBJECT(GuiInputCtrl);
//------------------------------------------------------------------------------
bool GuiInputCtrl::onWake()
{
// Set the default profile on start-up:
if ( !mProfile )
{
SimObject *obj = Sim::findObject("GuiInputCtrlProfile");
if ( obj )
mProfile = dynamic_cast<GuiControlProfile*>( obj );
}
if ( !Parent::onWake() )
return( false );
mouseLock();
setFirstResponder();
return( true );
}
//------------------------------------------------------------------------------
void GuiInputCtrl::onSleep()
{
Parent::onSleep();
mouseUnlock();
clearFirstResponder();
}
//------------------------------------------------------------------------------
static bool isModifierKey( U16 keyCode )
{
switch ( keyCode )
{
case KEY_LCONTROL:
case KEY_RCONTROL:
case KEY_LALT:
case KEY_RALT:
case KEY_LSHIFT:
case KEY_RSHIFT:
return( true );
}
return( false );
}
//------------------------------------------------------------------------------
bool GuiInputCtrl::onInputEvent( const InputEvent &event )
{
// TODO - add POV support...
if ( event.action == SI_MAKE )
{
if ( event.objType == SI_BUTTON
|| event.objType == SI_POV
|| ( ( event.objType == SI_KEY ) && !isModifierKey( event.objInst ) ) )
{
char deviceString[32];
if ( !ActionMap::getDeviceName( event.deviceType, event.deviceInst, deviceString ) )
return( false );
const char* actionString = ActionMap::buildActionString( &event );
Con::executef( this, 3, "onInputEvent", deviceString, actionString );
return( true );
}
}
else if ( event.action == SI_BREAK )
{
if ( ( event.objType == SI_KEY ) && isModifierKey( event.objInst ) )
{
char keyString[32];
if ( !ActionMap::getKeyString( event.objInst, keyString ) )
return( false );
Con::executef( this, 3, "onInputEvent", "keyboard", keyString );
return( true );
}
}
return( false );
}

32
gui/guiInputCtrl.h Normal file
View file

@ -0,0 +1,32 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIINPUTCTRL_H_
#define _GUIINPUTCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
#ifndef _EVENT_H_
#include "Platform/event.h"
#endif
class GuiInputCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
public:
DECLARE_CONOBJECT(GuiInputCtrl);
bool onWake();
void onSleep();
bool onInputEvent( const InputEvent &event );
};
#endif // _GUI_INPUTCTRL_H

491
gui/guiInspector.cc Normal file
View file

@ -0,0 +1,491 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/dgl.h"
#include "gui/guiTypes.h"
#include "gui/guiTextCtrl.h"
#include "gui/guiTextEditCtrl.h"
#include "gui/guiInspector.h"
#include "gui/guiCheckBoxCtrl.h"
#include "gui/guiPopUpCtrl.h"
#include "platform/event.h"
// datablocks
#include "game/gameBase.h"
#include "game/explosion.h"
#include "game/particleEngine.h"
#include "game/projectile.h"
#include "sim/cannedChatDataBlock.h"
#include "game/Debris.h"
#include "game/commanderMapIcon.h"
#include "game/shockwave.h"
#include "game/splash.h"
#include "game/shieldImpact.h"
#include "game/projEnergy.h"
#include "game/projBomb.h"
#define NULL_STRING "<NULL>"
GuiInspector::GuiInspector()
{
mEditControlOffset = 5;
mEntryHeight = 16;
mTextExtent = 80;
mEntrySpacing = 2;
mMaxMenuExtent = 80;
}
void GuiInspector::onRemove()
{
mTarget = 0;
while(size())
first()->deleteObject();
Parent::onRemove();
}
//------------------------------------------------------------------------------
static S32 QSORT_CALLBACK stringCompare(const void *a,const void *b)
{
StringTableEntry sa = *(StringTableEntry*)a;
StringTableEntry sb = *(StringTableEntry*)b;
return(dStricmp(sa, sb));
}
void GuiInspector::inspect(SimObject * obj)
{
mTarget = obj;
while(size())
first()->deleteObject();
S32 curYOffset = mEntrySpacing;
if(!bool(mTarget))
{
resize(mBounds.point, Point2I(mBounds.extent.x, curYOffset));
return;
}
// add in the static fields
AbstractClassRep::FieldList fieldList = mTarget->getFieldList();
AbstractClassRep::FieldList::iterator itr;
for(itr = fieldList.begin(); itr != fieldList.end(); itr++)
{
if(itr->type == AbstractClassRep::DepricatedFieldType)
continue;
char fdata[1024];
const char * dstr = Con::getData(itr->type, (void *)(S32(obj) + itr->offset), 0, itr->table, itr->flag);
if(!dstr)
dstr = "";
expandEscape(fdata, dstr);
GuiTextCtrl * textCtrl = new GuiTextCtrl();
textCtrl->setField("profile", "GuiTextProfile");
textCtrl->setField("text", itr->pFieldname);
textCtrl->registerObject();
addObject(textCtrl);
S32 textWidth = textCtrl->mProfile->mFont->getStrWidth(itr->pFieldname);
S32 xStartPoint = (textWidth < (mTextExtent + mEntrySpacing + mEditControlOffset)) ?
(mEntrySpacing + mTextExtent) : textWidth + mEditControlOffset;
textCtrl->mBounds.point = Point2I(mEntrySpacing, curYOffset);
textCtrl->mBounds.extent = Point2I(textWidth, mEntryHeight);
S32 maxWidth = mBounds.extent.x - xStartPoint - mEntrySpacing;
//now add the field
GuiControl * editControl = NULL;
switch(itr->type)
{
// text control
default:
{
GuiTextEditCtrl * edit = new GuiTextEditCtrl();
edit->setField("profile", "GuiInspectorTextEditProfile");
edit->setField("text", fdata);
editControl = edit;
edit->mBounds.point = Point2I(xStartPoint, curYOffset);
edit->mBounds.extent = Point2I(maxWidth, mEntryHeight);
edit->setSizing(GuiControl::horizResizeWidth, GuiControl::vertResizeBottom);
break;
}
// checkbox
case TypeBool:
case TypeFlag:
{
GuiCheckBoxCtrl * checkBox = new GuiCheckBoxCtrl();
checkBox->setField("profile", "GuiCheckBoxProfile");
checkBox->mBounds.point = Point2I(xStartPoint, curYOffset);
checkBox->mBounds.extent = Point2I(mEntryHeight, mEntryHeight);
checkBox->setScriptValue(fdata);
editControl = checkBox;
break;
}
// dropdown list
case TypeEnum:
{
AssertFatal(itr->table, "TypeEnum declared with NULL table");
GuiPopUpMenuCtrl * menu = new GuiPopUpMenuCtrl();
menu->setField("profile", "GuiPopUpMenuProfile");
menu->setField("text", fdata);
menu->mBounds.point = Point2I(xStartPoint, curYOffset);
menu->mBounds.extent = Point2I(getMin(maxWidth, mMaxMenuExtent), mEntryHeight);
//now add the entries
for(S32 i = 0; i < itr->table->size; i++)
menu->addEntry(itr->table->table[i].label, itr->table->table[i].index);
editControl = menu;
break;
}
// guiprofiles
case TypeGuiProfile:
{
GuiPopUpMenuCtrl * menu = new GuiPopUpMenuCtrl();
menu->setField("profile", "GuiPopUpMenuProfile");
menu->setField("text", *fdata ? fdata : NULL_STRING);
menu->mBounds.point = Point2I(xStartPoint, curYOffset);
menu->mBounds.extent = Point2I(getMin(maxWidth, mMaxMenuExtent), mEntryHeight);
// add 'NULL'
menu->addEntry(NULL_STRING, -1);
// add entries to list so they can be sorted prior to adding to menu (want null on top)
Vector<StringTableEntry> entries;
SimGroup * grp = Sim::getGuiDataGroup();
for(SimGroup::iterator i = grp->begin(); i != grp->end(); i++)
{
GuiControlProfile * profile = dynamic_cast<GuiControlProfile *>(*i);
if(profile)
entries.push_back(profile->getName());
}
// sort the entries
dQsort(entries.address(), entries.size(), sizeof(StringTableEntry), stringCompare);
for(U32 j = 0; j < entries.size(); j++)
menu->addEntry(entries[j], 0);
editControl = menu;
break;
}
// datablock types
case TypeGameBaseDataPtr:
case TypeExplosionDataPtr:
case TypeShockwaveDataPtr:
case TypeSplashDataPtr:
case TypeEnergyProjectileDataPtr:
case TypeBombProjectileDataPtr:
case TypeParticleEmitterDataPtr:
case TypeAudioDescriptionPtr:
case TypeAudioProfilePtr:
case TypeProjectileDataPtr:
case TypeCannedChatItemPtr:
case TypeDebrisDataPtr:
case TypeCommanderIconDataPtr:
{
GuiPopUpMenuCtrl * menu = new GuiPopUpMenuCtrl();
menu->setField("profile", "GuiPopUpMenuProfile");
menu->setField("text", *fdata ? fdata : NULL_STRING);
menu->mBounds.point = Point2I(xStartPoint, curYOffset);
menu->mBounds.extent = Point2I(getMin(maxWidth, mMaxMenuExtent), mEntryHeight);
// add the 'NULL' entry on top
menu->addEntry(NULL_STRING, -1);
// add to a list so they can be sorted
Vector<StringTableEntry> entries;
SimGroup * grp = Sim::getDataBlockGroup();
for(SimGroup::iterator i = grp->begin(); i != grp->end(); i++)
{
SimObject * obj = 0;
switch(itr->type)
{
case TypeGameBaseDataPtr:
obj = dynamic_cast<GameBaseData*>(*i);
break;
case TypeExplosionDataPtr:
obj = dynamic_cast<ExplosionData*>(*i);
break;
case TypeShockwaveDataPtr:
obj = dynamic_cast<ShockwaveData*>(*i);
break;
case TypeSplashDataPtr:
obj = dynamic_cast<SplashData*>(*i);
break;
case TypeEnergyProjectileDataPtr:
obj = dynamic_cast<EnergyProjectileData*>(*i);
break;
case TypeBombProjectileDataPtr:
obj = dynamic_cast<BombProjectileData*>(*i);
break;
case TypeParticleEmitterDataPtr:
obj = dynamic_cast<ParticleEmitterData*>(*i);
break;
case TypeAudioDescriptionPtr:
obj = dynamic_cast<AudioDescription*>(*i);
break;
case TypeAudioProfilePtr:
obj = dynamic_cast<AudioProfile*>(*i);
break;
case TypeProjectileDataPtr:
obj = dynamic_cast<ProjectileData*>(*i);
break;
case TypeCannedChatItemPtr:
obj = dynamic_cast<CannedChatItem*>(*i);
break;
case TypeDebrisDataPtr:
obj = dynamic_cast<DebrisData*>(*i);
break;
case TypeCommanderIconDataPtr:
obj = dynamic_cast<CommanderIconData*>(*i);
break;
}
if(obj)
entries.push_back(obj->getName());
}
// sort the entries
dQsort(entries.address(), entries.size(), sizeof(StringTableEntry), stringCompare);
for(U32 j = 0; j < entries.size(); j++)
menu->addEntry(entries[j], 0);
editControl = menu;
break;
}
}
if(editControl)
{
char buf[256];
dSprintf(buf, sizeof(buf), "InspectStatic%s", itr->pFieldname);
editControl->registerObject(buf);
addObject(editControl);
}
curYOffset += (mEntryHeight + mEntrySpacing);
}
// dynamic field seperator: text
GuiTextCtrl * textCtrl = new GuiTextCtrl();
textCtrl->setField("profile", "GuiTextProfile");
textCtrl->setField("text", " Dynamic Fields");
textCtrl->registerObject();
textCtrl->mBounds.point = Point2I(mEntrySpacing, curYOffset);
textCtrl->mBounds.extent = Point2I(mTextExtent, mEntryHeight);
addObject(textCtrl);
// button
GuiButtonCtrl * button = new GuiButtonCtrl();
button->setField("profile", "GuiButtonProfile");
button->setField("text", "Add");
Con::setIntVariable("InspectingObject", mTarget->getId());
Con::setIntVariable("Inspector", getId());
S32 textWidth = textCtrl->mProfile->mFont->getStrWidth(textCtrl->getScriptValue());
S32 xStartPoint = (textWidth < (mTextExtent + mEntrySpacing + mEditControlOffset)) ?
(mEntrySpacing + mTextExtent) : textWidth + mEditControlOffset;
S32 maxWidth = mBounds.extent.x - xStartPoint - mEntrySpacing;
button->mBounds.point = Point2I(xStartPoint, curYOffset);
button->mBounds.extent = Point2I(getMin(maxWidth, mMaxMenuExtent), mEntryHeight);
button->registerObject();
char buf[1024];
dSprintf(buf, sizeof(buf), "%d.addDynamicField(%d);", getId(), mTarget->getId());
button->setField("command", buf);
addObject(button);
// offset
curYOffset += (mEntryHeight + mEntrySpacing);
// add the dynamic fields
SimFieldDictionary * fieldDictionary = mTarget->getFieldDictionary();
for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
{
SimFieldDictionary::Entry * entry = (*ditr);
// create the name ctrl
GuiTextCtrl * nameCtrl = new GuiTextCtrl();
nameCtrl->setField("profile", "GuiTextProfile");
nameCtrl->setField("text", entry->slotName);
nameCtrl->registerObject();
addObject(nameCtrl);
nameCtrl->mBounds.point = Point2I(mEntrySpacing, curYOffset);
nameCtrl->mBounds.extent = Point2I(mTextExtent, mEntryHeight);
// add a 'remove' button
GuiButtonCtrl * button = new GuiButtonCtrl();
button->setField("profile", "GuiButtonProfile");
button->setField("text", "x");
button->registerObject();
addObject(button);
char buf[1024];
dSprintf(buf, sizeof(buf), "%d.%s = \"\";%d.inspect(%d);", mTarget->getId(), entry->slotName, getId(), mTarget->getId());
button->setField("command", buf);
S32 textWidth = mProfile->mFont->getStrWidth(entry->slotName);
// 10x10 with 2x2 frame
button->mBounds.point.set(textWidth + 4, curYOffset + 2);
button->mBounds.extent.set(10, 10);
textWidth += 14;
S32 xStartPoint = (textWidth < (mTextExtent + mEntrySpacing + mEditControlOffset)) ?
(mEntrySpacing + mTextExtent) : textWidth + mEditControlOffset;
S32 maxWidth = mBounds.extent.x - xStartPoint - mEntrySpacing;
expandEscape(buf, entry->value ? entry->value : "");
// create the edit ctrl
GuiTextEditCtrl * editCtrl = new GuiTextEditCtrl();
editCtrl->setField("profile", "GuiInspectorTextEditProfile");
editCtrl->setField("text", buf);
editCtrl->setSizing(GuiControl::horizResizeWidth, GuiControl::vertResizeBottom);
dSprintf(buf, sizeof(buf), "InspectDynamic%s", entry->slotName);
editCtrl->registerObject(buf);
addObject(editCtrl);
editCtrl->mBounds.point = Point2I(xStartPoint, curYOffset);
editCtrl->mBounds.extent = Point2I(maxWidth, mEntryHeight);
curYOffset += (mEntryHeight + mEntrySpacing);
}
resize(mBounds.point, Point2I(mBounds.extent.x, curYOffset));
}
void GuiInspector::apply(const char * newName)
{
if(!bool(mTarget))
{
while(size())
first()->deleteObject();
return;
}
mTarget->assignName(newName);
mTarget->inspectPreApply();
SimObject * obj = static_cast<SimObject*>(mTarget);
//now add in the fields
AbstractClassRep::FieldList fieldList = mTarget->getFieldList();
AbstractClassRep::FieldList::iterator itr;
for(itr = fieldList.begin(); itr != fieldList.end(); itr++)
{
if(itr->type == AbstractClassRep::DepricatedFieldType)
continue;
char fdata[1024];
dSprintf(fdata, sizeof(fdata), "InspectStatic%s", itr->pFieldname);
GuiControl * editCtrl = NULL;
SimObject * inspectObj = Sim::findObject(fdata);
if(inspectObj)
editCtrl = dynamic_cast<GuiControl*>(inspectObj);
if(!editCtrl)
continue;
const char * newValue = 0;
// check for null on profiles (-1 popup id)
GuiPopUpMenuCtrl * menu = dynamic_cast<GuiPopUpMenuCtrl*>(editCtrl);
if(!(menu && (menu->getSelected() == -1)))
newValue = editCtrl->getScriptValue();
if(!newValue)
newValue = "";
dStrcpy(fdata, newValue);
collapseEscape(fdata);
//now set the field
const char *argv[1];
argv[0] = &fdata[0];
Con::setData(itr->type, (void *)(S32(obj) + itr->offset), 0, 1, argv, itr->table, itr->flag);
}
// get the dynamic field data
SimFieldDictionary * fieldDictionary = mTarget->getFieldDictionary();
for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
{
SimFieldDictionary::Entry * entry = (*ditr);
char buf[1024];
dSprintf(buf, sizeof(buf), "InspectDynamic%s", entry->slotName);
GuiControl * editCtrl = static_cast<GuiControl*>(Sim::findObject(buf));
if(!editCtrl)
continue;
const char * newValue = editCtrl->getScriptValue();
dStrcpy(buf, newValue ? newValue : "");
collapseEscape(buf);
fieldDictionary->setFieldValue(entry->slotName, buf);
}
mTarget->inspectPostApply();
//now re-inspect the object
inspect(mTarget);
}
//------------------------------------------------------------------------------
static void cInspect(SimObject *obj, S32, const char **argv)
{
GuiInspector * inspector = static_cast<GuiInspector*>(obj);
SimObject * target = Sim::findObject(argv[2]);
if(!target)
{
Con::printf("%s(): invalid object: %s", argv[0], argv[2]);
return;
}
inspector->inspect(target);
}
static void cApply(SimObject *obj, S32, const char **argv)
{
GuiInspector *inspector = static_cast<GuiInspector*>(obj);
inspector->apply(argv[2]);
}
void GuiInspector::consoleInit()
{
Con::addCommand("GuiInspector", "inspect", cInspect, "inspector.inspect(obj)", 3, 3);
Con::addCommand("GuiInspector", "apply", cApply, "inspector.apply(newName)", 3, 3);
}
void GuiInspector::initPersistFields()
{
Parent::initPersistFields();
addField("editControlOffset", TypeS32, Offset(mEditControlOffset, GuiInspector));
addField("entryHeight", TypeS32, Offset(mEntryHeight, GuiInspector));
addField("textExtent", TypeS32, Offset(mTextExtent, GuiInspector));
addField("entrySpacing", TypeS32, Offset(mEntrySpacing, GuiInspector));
addField("maxMenuExtent", TypeS32, Offset(mMaxMenuExtent, GuiInspector));
}

44
gui/guiInspector.h Normal file
View file

@ -0,0 +1,44 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIINSPECTOR_H_
#define _GUIINSPECTOR_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
#ifndef _GUIARRAYCTRL_H_
#include "GUI/guiArrayCtrl.h"
#endif
class GuiInspector : public GuiControl
{
private:
typedef GuiControl Parent;
SimObjectPtr<SimObject> mTarget;
public:
DECLARE_CONOBJECT(GuiInspector);
GuiInspector();
// field data
S32 mEditControlOffset;
S32 mEntryHeight;
S32 mTextExtent;
S32 mEntrySpacing;
S32 mMaxMenuExtent;
static void consoleInit();
static void initPersistFields();
void onRemove();
void inspect(SimObject *);
void apply(const char *);
};
#endif

1990
gui/guiMLTextCtrl.cc Normal file

File diff suppressed because it is too large Load diff

257
gui/guiMLTextCtrl.h Normal file
View file

@ -0,0 +1,257 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIMLTEXTCTRL_H_
#define _GUIMLTEXTCTRL_H_
#ifndef _GUICONTROL_H_
#include "gui/guiControl.h"
#endif
class GFont;
class GuiMLTextCtrl : public GuiControl
{
typedef GuiControl Parent;
//-------------------------------------- Public interfaces...
public:
enum Justification
{
LeftJustify,
RightJustify,
CenterJustify,
};
struct Font {
char *faceName;
U32 faceNameLen;
U32 size;
Resource<GFont> fontRes;
Font *next;
};
struct Bitmap {
const char *bitmapName;
U32 bitmapNameLen;
TextureHandle bitmapHandle;
Bitmap *next;
};
struct URL
{
bool mouseDown;
U32 textStart;
U32 len;
bool noUnderline;
};
struct Style
{
ColorI color;
Font *font;
bool used;
Style *next;
};
struct Atom
{
U32 textStart;
U32 len;
U32 xStart;
U32 yStart;
U32 width;
U32 baseLine;
U32 descent;
Style *style;
bool isClipped;
URL *url;
Atom *next;
};
struct Line {
U32 y;
U32 height;
U32 divStyle;
U32 textStart;
U32 len;
Atom *atomList;
Line *next;
};
struct BitmapRef : public RectI
{
BitmapRef *nextBlocker;
U32 textStart;
U32 len;
Bitmap *bitmap;
BitmapRef *next;
};
struct LineTag {
U32 id;
S32 y;
LineTag *next;
};
GuiMLTextCtrl();
~GuiMLTextCtrl();
// Text retrieval functions
U32 getNumChars() const;
U32 getText(char* pBuffer, const U32 bufferSize) const;
U32 getWrappedText(char* pBuffer, const U32 bufferSize) const;
const char* getTextContent();
// Text substitution functions
void setText(const char* textBuffer, const U32 numChars);
void addText(const char* textBuffer, const U32 numChars, bool reformat);
bool setCursorPosition(const S32);
void ensureCursorOnScreen();
// Scroll functions
void scrollToTag( U32 id );
void scrollToTop();
DECLARE_CONOBJECT(GuiMLTextCtrl);
static void initPersistFields();
static void consoleInit();
void setScriptValue(const char *value);
const char *getScriptValue();
static char *stripControlChars(const char *inString);
//-------------------------------------- Protected Structures and constants
protected:
bool mIsEditCtrl;
U32 *mTabStops;
U32 mTabStopCount;
U32 mCurTabStop;
DataChunker mViewChunker;
DataChunker mResourceChunker;
Line *mLineList;
Bitmap *mBitmapList;
BitmapRef *mBitmapRefList;
Font *mFontList;
LineTag *mTagList;
bool mDirty;
Style *mCurStyle;
U32 mCurLMargin;
U32 mCurRMargin;
U32 mCurJustify;
U32 mCurDiv;
U32 mCurY;
U32 mCurClipX;
Atom *mLineAtoms;
Atom **mLineAtomPtr;
Atom *mEmitAtoms;
Atom **mEmitAtomPtr;
BitmapRef mSentinel;
Line **mLineInsert;
BitmapRef *mBlockList;
U32 mScanPos;
U32 mCurX;
U32 mMaxY;
URL *mCurURL;
URL *mHitURL;
void freeLineBuffers();
void freeResources();
virtual void reflow();
Bitmap *allocBitmap(char *bitmapName, U32 bitmapNameLen);
Font *allocFont(char *faceName, U32 faceNameLen, U32 size);
LineTag *allocLineTag(U32 id);
void emitNewLine(U32 textStart);
Atom *buildTextAtom(U32 start, U32 len, U32 left, U32 right, URL *url);
void emitTextToken(U32 textStart, U32 len);
void emitBitmapToken(Bitmap *bmp, U32 textStart);
void processEmitAtoms();
Atom *splitAtomListEmit(Atom *list, U32 width);
void drawAtomText(bool sel, U32 start, U32 end, Atom *atom, Line *line, Point2I offset);
Atom *findHitAtom(const Point2I localCoords);
Style *allocStyle(Style *style);
static const U32 csmTextBufferGrowthSize;
//-------------------------------------- Data...
protected:
// Cursor position should always be <= mCurrTextSize
U32 mCursorPosition;
// Actual text data. The line buffer is rebuilt from the linear text
// given a specific width. TextBuffer is /not/ \0 terminated
char* mTextBuffer;
U32 mCurrTextSize;
U32 mCurrBufferSize;
U32 mLineStart;
S32 mMaxBufferSize;
// Selection information
bool mSelectionActive;
U32 mSelectionStart;
U32 mSelectionEnd;
U32 mVertMoveAnchor;
bool mVertMoveAnchorValid;
S32 mSelectionAnchor;
Point2I mSelectionAnchorDropped;
// Font resource
Resource<GFont> mFont;
U32 mMinSensibleWidth;
// Console settable parameters
U32 mLineSpacingPixels;
bool mAllowColorChars;
// Too many chars sound:
AudioProfile* mDeniedSound;
//-------------------------------------- Protected interface
protected:
// Inserting and deleting character blocks...
void insertChars(const char* inputChars,
const U32 numInputChars,
const U32 position);
void deleteChars(const U32 rangeStart,
const U32 rangeEnd);
void copyToClipboard(const U32 rangeStart,
const U32 rangeEnd);
// Selection maintainance
bool isSelectionActive() const;
void clearSelection();
// Pixel -> textposition mappings
S32 getTextPosition(const Point2I& localPosition);
// Gui control overrides
bool onWake();
void onSleep();
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void getCursorPositionAndColor(Point2I &cursorTop, Point2I &cursorBottom, ColorI &color);
void inspectPostApply();
void resize(const Point2I &newPosition, const Point2I &newExtent);
void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
bool onKeyDown(const GuiEvent& event);
void onMouseDown(const GuiEvent&);
void onMouseDragged(const GuiEvent&);
void onMouseUp(const GuiEvent&);
};
#endif // _H_GUIMLTEXTCTRL_

365
gui/guiMLTextEditCtrl.cc Normal file
View file

@ -0,0 +1,365 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/guiMLTextEditCtrl.h"
#include "GUI/guiScrollCtrl.h"
#include "dgl/dgl.h"
#include "console/consoleTypes.h"
#include "Platform/event.h"
IMPLEMENT_CONOBJECT(GuiMLTextEditCtrl);
//--------------------------------------------------------------------------
GuiMLTextEditCtrl::GuiMLTextEditCtrl()
{
mEscapeCommand = StringTable->insert( "" );
mIsEditCtrl = true;
mActive = true;
mVertMoveAnchorValid = false;
}
//--------------------------------------------------------------------------
GuiMLTextEditCtrl::~GuiMLTextEditCtrl()
{
}
//--------------------------------------------------------------------------
void GuiMLTextEditCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
{
// We don't want to get any smaller than our parent:
Point2I newExt = newExtent;
GuiControl* parent = getParent();
if ( parent )
newExt.y = getMax( parent->mBounds.extent.y, newExt.y );
Parent::resize( newPosition, newExt );
}
//--------------------------------------------------------------------------
void GuiMLTextEditCtrl::initPersistFields()
{
Parent::initPersistFields();
addField( "escapeCommand", TypeString, Offset( mEscapeCommand, GuiMLTextEditCtrl ) );
}
//--------------------------------------------------------------------------
void GuiMLTextEditCtrl::consoleInit()
{
}
//--------------------------------------------------------------------------
// Key events...
bool GuiMLTextEditCtrl::onKeyDown(const GuiEvent& event)
{
setUpdate();
//handle modifiers first...
if (event.modifier & SI_CTRL)
{
switch(event.keyCode)
{
//copy/cut
case KEY_C:
case KEY_X:
{
//make sure we actually have something selected
if (mSelectionActive)
{
copyToClipboard(mSelectionStart, mSelectionEnd);
//if we're cutting, also delete the selection
if (event.keyCode == KEY_X)
{
mSelectionActive = false;
deleteChars(mSelectionStart, mSelectionEnd);
mCursorPosition = mSelectionStart;
}
else
mCursorPosition = mSelectionEnd + 1;
}
return true;
}
//paste
case KEY_V:
{
const char *clipBuf = Platform::getClipboard();
if (dStrlen(clipBuf) > 0)
{
// Normal ascii keypress. Go ahead and add the chars...
if (mSelectionActive == true)
{
mSelectionActive = false;
deleteChars(mSelectionStart, mSelectionEnd);
mCursorPosition = mSelectionStart;
}
insertChars(clipBuf, dStrlen(clipBuf), mCursorPosition);
}
return true;
}
}
}
else if ( event.modifier & SI_SHIFT )
{
switch ( event.keyCode )
{
case KEY_TAB:
return( Parent::onKeyDown( event ) );
}
}
else if ( event.modifier == 0 )
{
switch (event.keyCode)
{
// Escape:
case KEY_ESCAPE:
if ( mEscapeCommand[0] )
{
Con::evaluate( mEscapeCommand );
return( true );
}
return( Parent::onKeyDown( event ) );
// Deletion
case KEY_BACKSPACE:
case KEY_DELETE:
handleDeleteKeys(event);
return true;
// Cursor movement
case KEY_LEFT:
case KEY_RIGHT:
case KEY_UP:
case KEY_DOWN:
case KEY_HOME:
case KEY_END:
handleMoveKeys(event);
return true;
// Special chars...
case KEY_TAB:
// insert 3 spaces
if (mSelectionActive == true)
{
mSelectionActive = false;
deleteChars(mSelectionStart, mSelectionEnd);
mCursorPosition = mSelectionStart;
}
insertChars( "\t", 1, mCursorPosition );
return true;
case KEY_RETURN:
// insert carriage return
if (mSelectionActive == true)
{
mSelectionActive = false;
deleteChars(mSelectionStart, mSelectionEnd);
mCursorPosition = mSelectionStart;
}
insertChars( "\n", 1, mCursorPosition );
return true;
}
}
if (event.ascii != 0)
{
// Normal ascii keypress. Go ahead and add the chars...
if (mSelectionActive == true)
{
mSelectionActive = false;
deleteChars(mSelectionStart, mSelectionEnd);
mCursorPosition = mSelectionStart;
}
char ascii = char(event.ascii);
insertChars(&ascii, 1, mCursorPosition);
mVertMoveAnchorValid = false;
return true;
}
// Otherwise, let the parent have the event...
return Parent::onKeyDown(event);
}
//--------------------------------------
void GuiMLTextEditCtrl::handleDeleteKeys(const GuiEvent& event)
{
if ( isSelectionActive() )
{
mSelectionActive = false;
deleteChars(mSelectionStart, mSelectionEnd);
mCursorPosition = mSelectionStart;
}
else
{
switch ( event.keyCode )
{
case KEY_BACKSPACE:
if (mCursorPosition != 0)
{
// delete one character left
deleteChars(mCursorPosition-1, mCursorPosition-1);
setUpdate();
}
break;
case KEY_DELETE:
if (mCursorPosition != mCurrTextSize)
{
// delete one character right
deleteChars(mCursorPosition, mCursorPosition);
setUpdate();
}
break;
default:
AssertFatal(false, "Should not be here!");
}
}
}
//--------------------------------------
void GuiMLTextEditCtrl::handleMoveKeys(const GuiEvent& event)
{
if ( event.modifier & SI_SHIFT )
return;
mSelectionActive = false;
switch ( event.keyCode )
{
case KEY_LEFT:
mVertMoveAnchorValid = false;
// move one left
if ( mCursorPosition != 0 )
{
mCursorPosition--;
setUpdate();
}
break;
case KEY_RIGHT:
mVertMoveAnchorValid = false;
// move one right
if ( mCursorPosition != mCurrTextSize )
{
mCursorPosition++;
setUpdate();
}
break;
case KEY_UP:
case KEY_DOWN:
{
Line* walk;
for ( walk = mLineList; walk->next; walk = walk->next )
{
if ( mCursorPosition <= ( walk->textStart + walk->len ) )
break;
}
if ( !walk )
return;
if ( event.keyCode == KEY_UP )
{
if ( walk == mLineList )
return;
}
else if ( walk->next == NULL )
return;
Point2I newPos;
newPos.set( 0, walk->y );
// Find the x-position:
if ( !mVertMoveAnchorValid )
{
Point2I cursorTopP, cursorBottomP;
ColorI color;
getCursorPositionAndColor(cursorTopP, cursorBottomP, color);
mVertMoveAnchor = cursorTopP.x;
mVertMoveAnchorValid = true;
}
newPos.x = mVertMoveAnchor;
// Set the new y-position:
if (event.keyCode == KEY_UP)
newPos.y--;
else
newPos.y += (walk->height + 1);
if (setCursorPosition(getTextPosition(newPos)))
mVertMoveAnchorValid = false;
break;
}
case KEY_HOME:
case KEY_END:
{
mVertMoveAnchorValid = false;
Line* walk;
for (walk = mLineList; walk->next; walk = walk->next)
{
if (mCursorPosition <= (walk->textStart + walk->len))
break;
}
if (walk)
{
if (event.keyCode == KEY_HOME)
{
//place the cursor at the beginning of the first atom if there is one
if (walk->atomList)
mCursorPosition = walk->atomList->textStart;
else
mCursorPosition = walk->textStart;
}
else
{
mCursorPosition = walk->textStart;
mCursorPosition += walk->len;
}
setUpdate();
}
break;
}
default:
AssertFatal(false, "Should not be here!");
}
ensureCursorOnScreen();
}
//--------------------------------------------------------------------------
void GuiMLTextEditCtrl::onRender(Point2I offset, const RectI& updateRect, GuiControl* firstResponder)
{
Parent::onRender(offset, updateRect, firstResponder);
// We are the first responder, draw our cursor in the appropriate position...
if (firstResponder == this) {
Point2I top, bottom;
ColorI color;
getCursorPositionAndColor(top, bottom, color);
dglDrawLine(top + offset, bottom + offset, mProfile->mCursorColor);
}
}

44
gui/guiMLTextEditCtrl.h Normal file
View file

@ -0,0 +1,44 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIMLTEXTEDITCTRL_H_
#define _GUIMLTEXTEDITCTRL_H_
#ifndef _GUIMLTEXTCTRL_H_
#include "GUI/guiMLTextCtrl.h"
#endif
class GuiMLTextEditCtrl : public GuiMLTextCtrl
{
typedef GuiMLTextCtrl Parent;
//-------------------------------------- Overrides
protected:
StringTableEntry mEscapeCommand;
// Events
bool onKeyDown(const GuiEvent&);
// Event forwards
void handleMoveKeys(const GuiEvent&);
void handleDeleteKeys(const GuiEvent&);
// rendering
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
public:
GuiMLTextEditCtrl();
~GuiMLTextEditCtrl();
void resize(const Point2I &newPosition, const Point2I &newExtent);
DECLARE_CONOBJECT(GuiMLTextEditCtrl);
static void initPersistFields();
static void consoleInit();
};
#endif // _H_GUIMLTEXTEDITCTRL_

693
gui/guiMenuBar.cc Normal file
View file

@ -0,0 +1,693 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/dgl.h"
#include "gui/guiCanvas.h"
#include "gui/guiDefaultControlRender.h"
#include "gui/guiTextListCtrl.h"
#include "sim/actionMap.h"
#include "gui/guiMenuBar.h"
// menu bar:
// basic idea - fixed height control bar at the top of a window, placed and sized in gui editor
// menu text for menus or menu items should not begin with a digit
// all menus can be removed via the clearMenus() console command
// each menu is added via the addMenu(menuText, menuId) console command
// each menu is added with a menu id
// menu items are added to menus via that addMenuItem(menu, menuItemText, menuItemId, accelerator) console command
// each menu item is added with a menu item id and an optional accelerator
// menu items are initially enabled, but can be disabled/re-enabled via the setMenuItemEnable(menu,menuItem,bool)
// menu text can be set via the setMenuText(menu, newMenuText) console method
// menu item text can be set via the setMenuItemText console method
// menu items can be removed via the removeMenuItem(menu, menuItem) console command
// menu items can be cleared via the clearMenuItems(menu) console command
// menus can be removed via the removeMenu console command
// specification arguments for menus and menu items can be either the id or the text of the menu or menu item
// adding the menu item "-" will add an un-selectable seperator to the menu
// callbacks:
// when a menu is clicked, before it is displayed, the menu calls its onMenuSelect(menuId, menuText) method -
// this allows the callback to enable/disable menu items, or add menu items in a context-sensitive way
// when a menu item is clicked, the menu removes itself from display, then calls onMenuItemSelect(menuId, menuText, menuItemId, menuItemText)
// the initial implementation does not support:
// hierarchal menus
// keyboard accelerators on menu text (i.e. via alt-key combos)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// console methods
//------------------------------------------------------------------------------
ConsoleMethod(GuiMenuBar, clearMenus, void, 2, 2, "() - clears all the menus from the menu bar.")
{
((GuiMenuBar *)object)->clearMenus();
}
ConsoleMethod(GuiMenuBar, addMenu, void, 4, 4, "(string menuText, int menuId) - adds a new menu to the menu bar.")
{
if(dIsdigit(argv[2][0]))
{
Con::errorf("Cannot add menu %s (id = %s). First character of a menu's text cannot be a digit.", argv[2], argv[3]);
return;
}
GuiMenuBar *menuBar = (GuiMenuBar *) object;
menuBar->addMenu(argv[2], dAtoi(argv[3]));
}
ConsoleMethod(GuiMenuBar, addMenuItem, void, 5, 6, "(string menu, string menuItemText, int menuItemId, string accelerator = NULL) - adds a menu item to the specified menu. The menu argument can be either the text of a menu or its id.")
{
GuiMenuBar *menuBar = (GuiMenuBar *) object;
if(dIsdigit(argv[3][0]))
{
Con::errorf("Cannot add menu item %s (id = %s). First character of a menu item's text cannot be a digit.", argv[3], argv[4]);
return;
}
GuiMenuBar::Menu *menu = menuBar->findMenu(argv[2]);
if(!menu)
{
Con::errorf("Cannot find menu %s for addMenuItem.", argv[2]);
return;
}
menuBar->addMenuItem(menu, argv[3], dAtoi(argv[4]), argc == 5 ? NULL : argv[5]);
}
ConsoleMethod(GuiMenuBar, setMenuItemEnable, void, 5, 5, "(string menu, string menuItem, bool enabled) - sets the menu item to enabled or disabled based on the enable parameter. The specified menu and menu item can either be text or ids.")
{
GuiMenuBar *menuBar = (GuiMenuBar *) object;
GuiMenuBar::Menu *menu = menuBar->findMenu(argv[2]);
if(!menu)
{
Con::errorf("Cannot find menu %s for setMenuItemEnable.", argv[2]);
return;
}
GuiMenuBar::MenuItem *menuItem = menuBar->findMenuItem(menu, argv[3]);
if(!menuItem)
{
Con::errorf("Cannot find menu item %s for setMenuItemEnable.", argv[3]);
return;
}
menuItem->enabled = dAtob(argv[4]);
}
ConsoleMethod(GuiMenuBar, setMenuText, void, 4, 4, "(string menu, string newMenuText) - sets the text of the specified menu to the new string.")
{
GuiMenuBar *menuBar = (GuiMenuBar *) object;
if(dIsdigit(argv[3][0]))
{
Con::errorf("Cannot name menu %s to %s. First character of a menu's text cannot be a digit.", argv[2], argv[3]);
return;
}
GuiMenuBar::Menu *menu = menuBar->findMenu(argv[2]);
if(!menu)
{
Con::errorf("Cannot find menu %s for setMenuText.", argv[2]);
return;
}
dFree(menu->text);
menu->text = dStrdup(argv[3]);
menuBar->menuBarDirty = true;
}
ConsoleMethod(GuiMenuBar, setMenuItemText, void, 5, 5, "(string menu, string menuItem, string newMenuItemText) - sets the text of the specified menu item to the new string.")
{
GuiMenuBar *menuBar = (GuiMenuBar *) object;
if(dIsdigit(argv[4][0]))
{
Con::errorf("Cannot name menu item %s to %s. First character of a menu item's text cannot be a digit.", argv[3], argv[4]);
return;
}
GuiMenuBar::Menu *menu = menuBar->findMenu(argv[2]);
if(!menu)
{
Con::errorf("Cannot find menu %s for setMenuItemText.", argv[2]);
return;
}
GuiMenuBar::MenuItem *menuItem = menuBar->findMenuItem(menu, argv[3]);
if(!menuItem)
{
Con::errorf("Cannot find menu item %s for setMenuItemText.", argv[3]);
return;
}
dFree(menuItem->text);
menuItem->text = dStrdup(argv[4]);
}
ConsoleMethod(GuiMenuBar, removeMenuItem, void, 4, 4, "(string menu, string menuItem) - removes the specified menu item from the menu.")
{
GuiMenuBar *menuBar = (GuiMenuBar *) object;
GuiMenuBar::Menu *menu = menuBar->findMenu(argv[2]);
if(!menu)
{
Con::errorf("Cannot find menu %s for removeMenuItem.", argv[2]);
return;
}
GuiMenuBar::MenuItem *menuItem = menuBar->findMenuItem(menu, argv[3]);
if(!menuItem)
{
Con::errorf("Cannot find menu item %s for removeMenuItem.", argv[3]);
return;
}
menuBar->removeMenuItem(menu, menuItem);
}
ConsoleMethod(GuiMenuBar, clearMenuItems, void, 3, 3, "(string menu) - removes all the menu items from the specified menu.")
{
GuiMenuBar *menuBar = (GuiMenuBar *) object;
GuiMenuBar::Menu *menu = menuBar->findMenu(argv[2]);
if(!menu)
{
Con::errorf("Cannot find menu %s for clearMenuItems.", argv[2]);
return;
}
menuBar->clearMenuItems(menu);
}
ConsoleMethod(GuiMenuBar, removeMenu, void, 3, 3, "(string menu) - removes the specified menu from the menu bar.")
{
GuiMenuBar *menuBar = (GuiMenuBar *) object;
GuiMenuBar::Menu *menu = menuBar->findMenu(argv[2]);
if(!menu)
{
Con::errorf("Cannot find menu %s for removeMenu.", argv[2]);
return;
}
menuBar->clearMenuItems(menu);
menuBar->menuBarDirty = true;
}
//------------------------------------------------------------------------------
// menu management methods
//------------------------------------------------------------------------------
void GuiMenuBar::addMenu(const char *menuText, U32 menuId)
{
// allocate the menu
Menu *newMenu = new Menu;
newMenu->text = dStrdup(menuText);
newMenu->id = menuId;
newMenu->nextMenu = NULL;
newMenu->firstMenuItem = NULL;
// add it to the menu list
menuBarDirty = true;
Menu **walk;
for(walk = &menuList; *walk; walk = &(*walk)->nextMenu)
;
*walk = newMenu;
}
GuiMenuBar::Menu *GuiMenuBar::findMenu(const char *menu)
{
if(dIsdigit(menu[0]))
{
U32 id = dAtoi(menu);
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
if(id == walk->id)
return walk;
return NULL;
}
else
{
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
if(!dStricmp(menu, walk->text))
return walk;
return NULL;
}
}
GuiMenuBar::MenuItem *GuiMenuBar::findMenuItem(Menu *menu, const char *menuItem)
{
if(dIsdigit(menuItem[0]))
{
U32 id = dAtoi(menuItem);
for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
if(id == walk->id)
return walk;
return NULL;
}
else
{
for(MenuItem *walk = menu->firstMenuItem; walk; walk = walk->nextMenuItem)
if(!dStricmp(menuItem, walk->text))
return walk;
return NULL;
}
}
void GuiMenuBar::removeMenu(Menu *menu)
{
menuBarDirty = true;
clearMenuItems(menu);
for(Menu **walk = &menuList; *walk; walk = &(*walk)->nextMenu)
{
if(*walk == menu)
{
*walk = menu->nextMenu;
break;
}
}
dFree(menu->text);
delete menu;
}
void GuiMenuBar::removeMenuItem(Menu *menu, MenuItem *menuItem)
{
for(MenuItem **walk = &menu->firstMenuItem; *walk; walk = &(*walk)->nextMenuItem)
{
if(*walk == menuItem)
{
*walk = menuItem->nextMenuItem;
break;
}
}
dFree(menuItem->text);
dFree(menuItem->accelerator);
delete menuItem;
}
void GuiMenuBar::addMenuItem(Menu *menu, const char *text, U32 id, const char *accelerator)
{
// allocate the new menu item
MenuItem *newMenuItem = new MenuItem;
newMenuItem->text = dStrdup(text);
if(accelerator)
newMenuItem->accelerator = dStrdup(accelerator);
else
newMenuItem->accelerator = NULL;
newMenuItem->id = id;
newMenuItem->nextMenuItem = NULL;
newMenuItem->acceleratorIndex = 0;
newMenuItem->enabled = true;
// link it into the menu's menu item list
MenuItem **walk = &menu->firstMenuItem;
while(*walk)
walk = &(*walk)->nextMenuItem;
*walk = newMenuItem;
}
void GuiMenuBar::clearMenuItems(Menu *menu)
{
while(menu->firstMenuItem)
removeMenuItem(menu, menu->firstMenuItem);
}
void GuiMenuBar::clearMenus()
{
while(menuList)
removeMenu(menuList);
}
//------------------------------------------------------------------------------
// initialization, input and render methods
//------------------------------------------------------------------------------
GuiMenuBar::GuiMenuBar()
{
menuList = NULL;
menuBarDirty = true;
mouseDownMenu = NULL;
mouseOverMenu = NULL;
mCurAcceleratorIndex = 0;
}
GuiMenuBar::Menu *GuiMenuBar::findHitMenu(Point2I mousePoint)
{
Point2I pos = globalToLocalCoord(mousePoint);
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
if(walk->bounds.pointInRect(pos))
return walk;
return NULL;
}
void GuiMenuBar::onPreRender()
{
Parent::onPreRender();
if(menuBarDirty)
{
menuBarDirty = false;
U32 curX = 0;
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
{
walk->bounds.set(curX, 1, mProfile->mFont->getStrWidth(walk->text) + 12, mBounds.extent.y - 2);
curX += walk->bounds.extent.x;
}
mouseOverMenu = NULL;
mouseDownMenu = NULL;
}
}
void GuiMenuBar::checkMenuMouseMove(const GuiEvent &event)
{
Menu *hit = findHitMenu(event.mousePoint);
if(hit && hit != mouseDownMenu)
{
// gotta close out the current menu...
mTextList->setSelectedCell(Point2I(-1, -1));
closeMenu();
mouseOverMenu = mouseDownMenu = hit;
setUpdate();
onAction();
}
}
void GuiMenuBar::onMouseMove(const GuiEvent &event)
{
Menu *hit = findHitMenu(event.mousePoint);
if(hit != mouseOverMenu)
{
mouseOverMenu = hit;
setUpdate();
}
}
void GuiMenuBar::onMouseLeave(const GuiEvent &event)
{
if(mouseOverMenu)
setUpdate();
mouseOverMenu = NULL;
}
void GuiMenuBar::onMouseDragged(const GuiEvent &event)
{
Menu *hit = findHitMenu(event.mousePoint);
if(hit != mouseOverMenu)
{
mouseOverMenu = hit;
mouseDownMenu = hit;
setUpdate();
onAction();
}
}
void GuiMenuBar::onMouseDown(const GuiEvent &event)
{
mouseDownMenu = mouseOverMenu = findHitMenu(event.mousePoint);
setUpdate();
onAction();
}
void GuiMenuBar::onMouseUp(const GuiEvent &event)
{
mouseDownMenu = NULL;
setUpdate();
}
void GuiMenuBar::onRender(Point2I offset, const RectI &updateRect)
{
//if opaque, fill the update rect with the fill color
if (mProfile->mOpaque)
dglDrawRectFill(RectI(offset, mBounds.extent), mProfile->mFillColor);
for(Menu *walk = menuList; walk; walk = walk->nextMenu)
{
ColorI fontColor = mProfile->mFontColor;
RectI bounds = walk->bounds;
bounds.point += offset;
Point2I start;
start.x = walk->bounds.point.x + 6;
start.y = walk->bounds.point.y + ( walk->bounds.extent.y - ( mProfile->mFont->getHeight() - 2 ) ) / 2;
if(walk == mouseDownMenu)
renderSlightlyLoweredBox(bounds);
else if(walk == mouseOverMenu && mouseDownMenu == NULL)
renderSlightlyRaisedBox(bounds);
dglSetBitmapModulation( fontColor );
dglDrawText( mProfile->mFont, start + offset, walk->text, mProfile->mFontColors );
}
}
void GuiMenuBar::buildAcceleratorMap()
{
Parent::buildAcceleratorMap();
// ok, accelerator map is cleared...
// add all our keys:
mCurAcceleratorIndex = 1;
for(Menu *menu = menuList; menu; menu = menu->nextMenu)
{
for(MenuItem *item = menu->firstMenuItem; item; item = item->nextMenuItem)
{
if(!item->accelerator)
{
item->accelerator = 0;
continue;
}
EventDescriptor accelEvent;
ActionMap::createEventDescriptor(item->accelerator, &accelEvent);
//now we have a modifier, and a key, add them to the canvas
GuiCanvas *root = getRoot();
if (root)
root->addAcceleratorKey(this, mCurAcceleratorIndex, accelEvent.eventCode, accelEvent.flags);
item->acceleratorIndex = mCurAcceleratorIndex;
mCurAcceleratorIndex++;
}
}
}
void GuiMenuBar::acceleratorKeyPress(U32 index)
{
// loop through all the menus
// and find the item that corresponds to the accelerator index
for(Menu *menu = menuList; menu; menu = menu->nextMenu)
{
for(MenuItem *item = menu->firstMenuItem; item; item = item->nextMenuItem)
{
if(item->acceleratorIndex == index)
{
menuItemSelected(menu, item);
return;
}
}
}
}
//------------------------------------------------------------------------------
// Menu display class methods
//------------------------------------------------------------------------------
GuiMenuBackgroundCtrl::GuiMenuBackgroundCtrl(GuiMenuBar *ctrl, GuiMenuTextListCtrl *textList)
{
mMenuBarCtrl = ctrl;
mTextList = textList;
}
void GuiMenuBackgroundCtrl::onMouseDown(const GuiEvent &event)
{
mTextList->setSelectedCell(Point2I(-1,-1));
mMenuBarCtrl->closeMenu();
}
void GuiMenuBackgroundCtrl::onMouseMove(const GuiEvent &event)
{
GuiCanvas *root = getRoot();
GuiControl *ctrlHit = root->findHitControl(event.mousePoint, mLayer - 1);
if(ctrlHit == mMenuBarCtrl) // see if the current mouse over menu is right...
mMenuBarCtrl->checkMenuMouseMove(event);
}
void GuiMenuBackgroundCtrl::onMouseDragged(const GuiEvent &event)
{
GuiCanvas *root = getRoot();
GuiControl *ctrlHit = root->findHitControl(event.mousePoint, mLayer - 1);
if(ctrlHit == mMenuBarCtrl) // see if the current mouse over menu is right...
mMenuBarCtrl->checkMenuMouseMove(event);
}
GuiMenuTextListCtrl::GuiMenuTextListCtrl(GuiMenuBar *ctrl)
{
mMenuBarCtrl = ctrl;
}
void GuiMenuTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
{
if(dStrcmp(mList[cell.y].text, "-\t"))
Parent::onRenderCell(offset, cell, selected, mouseOver);
else
{
S32 yp = offset.y + mCellSize.y / 2;
dglDrawLine(offset.x, yp, offset.x + mCellSize.x, yp, ColorI(128,128,128));
dglDrawLine(offset.x, yp+1, offset.x + mCellSize.x, yp+1, ColorI(255,255,255));
}
}
bool GuiMenuTextListCtrl::onKeyDown(const GuiEvent &event)
{
//if the control is a dead end, don't process the input:
if ( !mVisible || !mActive || !mAwake )
return false;
//see if the key down is a <return> or not
if ( event.modifier == 0 )
{
if ( event.keyCode == KEY_RETURN )
{
mMenuBarCtrl->closeMenu();
return true;
}
else if ( event.keyCode == KEY_ESCAPE )
{
mSelectedCell.set( -1, -1 );
mMenuBarCtrl->closeMenu();
return true;
}
}
//otherwise, pass the event to it's parent
return Parent::onKeyDown(event);
}
void GuiMenuTextListCtrl::onMouseDown(const GuiEvent &event)
{
Parent::onMouseDown(event);
mMenuBarCtrl->closeMenu();
}
void GuiMenuTextListCtrl::onMouseUp(const GuiEvent &event)
{
// ok, this is kind of strange... but!
// here's the deal: if we get a mouse up in this control
// it means the mouse was dragged from the initial menu mouse click
// so: activate the menu result as though this event were,
// instead, a mouse down.
onMouseDown(event);
}
//------------------------------------------------------------------------------
void GuiMenuBar::menuItemSelected(GuiMenuBar::Menu *menu, GuiMenuBar::MenuItem *item)
{
if(item->enabled)
Con::executef( this, 6, "onMenuItemSelect", Con::getIntArg(menu->id),
menu->text, Con::getIntArg(item->id), item->text);
}
void GuiMenuBar::closeMenu()
{
// Get the selection from the text list:
S32 selectionIndex = mTextList->getSelectedCell().y;
// Pop the background:
getRoot()->popDialogControl(mBackground);
// Kill the popup:
mBackground->deleteObject();
// Now perform the popup action:
if ( selectionIndex != -1 )
{
MenuItem *list = mouseDownMenu->firstMenuItem;
while(selectionIndex && list)
{
list = list->nextMenuItem;
selectionIndex--;
}
if(list)
menuItemSelected(mouseDownMenu, list);
}
mouseDownMenu = NULL;
}
//------------------------------------------------------------------------------
void GuiMenuBar::onAction()
{
if(!mouseDownMenu)
return;
// first, call the script callback for menu selection:
Con::executef( this, 4, "onMenuSelect", Con::getIntArg(mouseDownMenu->id),
mouseDownMenu->text);
if(!mouseDownMenu->firstMenuItem)
{
mouseDownMenu = NULL;
return;
}
mTextList = new GuiMenuTextListCtrl(this);
mTextList->mProfile = mProfile;
mBackground = new GuiMenuBackgroundCtrl(this, mTextList);
GuiCanvas *root = getRoot();
Point2I windowExt = root->mBounds.extent;
mBackground->mBounds.point.set(0,0);
mBackground->mBounds.extent = root->mBounds.extent;
S32 textWidth = 0, width = 0;
S32 acceleratorWidth = 0;
GFont *font = mProfile->mFont;
for(MenuItem *walk = mouseDownMenu->firstMenuItem; walk; walk = walk->nextMenuItem)
{
S32 iTextWidth = font->getStrWidth(walk->text);
S32 iAcceleratorWidth = walk->accelerator ? font->getStrWidth(walk->accelerator) : 0;
if(iTextWidth > textWidth)
textWidth = iTextWidth;
if(iAcceleratorWidth > acceleratorWidth)
acceleratorWidth = iAcceleratorWidth;
}
width = textWidth + acceleratorWidth + 8;
mTextList->setCellSize(Point2I(width, font->getHeight()+3));
mTextList->addColumnOffset(textWidth + 4);
U32 entryCount = 0;
for(MenuItem *walk = mouseDownMenu->firstMenuItem; walk; walk = walk->nextMenuItem)
{
char buf[512];
dSprintf(buf, sizeof(buf), "%s\t%s", walk->text, walk->accelerator ? walk->accelerator : "");
mTextList->addEntry(entryCount, buf);
if(!walk->enabled)
mTextList->setEntryActive(entryCount, false);
entryCount++;
}
Point2I menuPoint = localToGlobalCoord(mouseDownMenu->bounds.point);
menuPoint.y += mouseDownMenu->bounds.extent.y + 2;
GuiControl *ctrl = new GuiControl;
ctrl->mBounds.point = menuPoint;
ctrl->mBounds.extent = mTextList->mBounds.extent + Point2I(6, 6);
ctrl->mProfile = mProfile;
mTextList->mBounds.point += Point2I(3,3);
//mTextList->mBounds.point = Point2I(3,3);
mTextList->registerObject();
mBackground->registerObject();
ctrl->registerObject();
mBackground->addObject( ctrl );
ctrl->addObject( mTextList );
root->pushDialogControl(mBackground, mLayer + 1);
mTextList->setFirstResponder();
}

125
gui/guiMenuBar.h Normal file
View file

@ -0,0 +1,125 @@
//-----------------------------------------------------------------------------
// Torque Game Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIMENUBAR_H_
#define _GUIMENUBAR_H_
#ifndef _GUITEXTLISTCTRL_H_
#include "gui/guiTextListCtrl.h"
#endif
class GuiMenuBar;
class GuiMenuTextListCtrl;
class GuiMenuBackgroundCtrl : public GuiControl
{
protected:
GuiMenuBar *mMenuBarCtrl;
GuiMenuTextListCtrl *mTextList;
public:
GuiMenuBackgroundCtrl(GuiMenuBar *ctrl, GuiMenuTextListCtrl* textList);
void onMouseDown(const GuiEvent &event);
void onMouseMove(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
};
//------------------------------------------------------------------------------
class GuiMenuTextListCtrl : public GuiTextListCtrl
{
private:
typedef GuiTextListCtrl Parent;
protected:
GuiMenuBar *mMenuBarCtrl;
public:
GuiMenuTextListCtrl(); // for inheritance
GuiMenuTextListCtrl(GuiMenuBar *ctrl);
// GuiControl overloads:
bool onKeyDown(const GuiEvent &event);
void onMouseDown(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
};
//------------------------------------------------------------------------------
class GuiMenuBar : public GuiControl
{
typedef GuiControl Parent;
public:
struct MenuItem // an individual item in a pull-down menu
{
char *text; // the text of the menu item
U32 id; // a script-assigned identifier
char *accelerator; // the keyboard accelerator shortcut for the menu item
U32 acceleratorIndex; // index of this accelerator
bool enabled; // true if the menu item is selectable
MenuItem *nextMenuItem; // next menu item in the linked list
};
struct Menu
{
char *text;
U32 id;
RectI bounds;
Menu *nextMenu;
MenuItem *firstMenuItem;
};
GuiMenuBackgroundCtrl *mBackground;
GuiMenuTextListCtrl *mTextList;
Menu *menuList;
Menu *mouseDownMenu;
Menu *mouseOverMenu;
bool menuBarDirty;
U32 mCurAcceleratorIndex;
GuiMenuBar();
// internal menu handling functions
// these are used by the script manipulation functions to add/remove/change menu items
void addMenu(const char *menuText, U32 menuId);
Menu *findMenu(const char *menu); // takes either a menu text or a string id
MenuItem *findMenuItem(Menu *menu, const char *menuItem); // takes either a menu text or a string id
void removeMenu(Menu *menu);
void removeMenuItem(Menu *menu, MenuItem *menuItem);
void addMenuItem(Menu *menu, const char *text, U32 id, const char *accelerator);
void clearMenuItems(Menu *menu);
void clearMenus();
// display/mouse functions
Menu *findHitMenu(Point2I mousePoint);
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect);
void checkMenuMouseMove(const GuiEvent &event);
void onMouseMove(const GuiEvent &event);
void onMouseLeave(const GuiEvent &event);
void onMouseDown(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
void onAction();
void closeMenu();
void buildAcceleratorMap();
void acceleratorKeyPress(U32 index);
void menuItemSelected(Menu *menu, MenuItem *item);
DECLARE_CONOBJECT(GuiMenuBar);
};
#endif

840
gui/guiMessageVectorCtrl.cc Normal file
View file

@ -0,0 +1,840 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/guiMessageVectorCtrl.h"
#include "GUI/messageVector.h"
#include "dgl/dgl.h"
#include "console/consoleTypes.h"
#include "GUI/guiScrollCtrl.h"
IMPLEMENT_CONOBJECT(GuiMessageVectorCtrl);
//-------------------------------------- Console functions
namespace {
bool cGMVCAttach(SimObject* obj, S32, const char** argv)
{
AssertFatal(dynamic_cast<GuiMessageVectorCtrl*>(obj) != NULL, "How did this get here?");
GuiMessageVectorCtrl* pGMVC = static_cast<GuiMessageVectorCtrl*>(obj);
MessageVector* pMV = NULL;
Sim::findObject(argv[2], pMV);
if (pMV == NULL) {
Con::errorf(ConsoleLogEntry::General, "Could not find MessageVector: %s", argv[2]);
return false;
}
return pGMVC->attach(pMV);
}
void cGMVCDetach(SimObject* obj, S32, const char**)
{
AssertFatal(dynamic_cast<GuiMessageVectorCtrl*>(obj) != NULL, "How did this get here?");
GuiMessageVectorCtrl* pGMVC = static_cast<GuiMessageVectorCtrl*>(obj);
if (pGMVC->isAttached() == false) {
Con::warnf(ConsoleLogEntry::General, "GuiMessageVectorCtrl: double detach");
return;
}
pGMVC->detach();
}
struct TempLineBreak
{
S32 start;
S32 end;
};
} // namespace {}
//--------------------------------------------------------------------------
// Callback for messageVector
void sMVCtrlCallback(const U32 spectatorKey,
const MessageVector::MessageCode code,
const U32 argument)
{
GuiMessageVectorCtrl* pMVC = reinterpret_cast<GuiMessageVectorCtrl*>(spectatorKey);
pMVC->callbackRouter(code, argument);
}
//--------------------------------------------------------------------------
GuiMessageVectorCtrl::GuiMessageVectorCtrl()
{
VECTOR_SET_ASSOCIATION(mLineWrappings);
VECTOR_SET_ASSOCIATION(mSpecialMarkers);
VECTOR_SET_ASSOCIATION(mLineElements);
mMessageVector = NULL;
mLineSpacingPixels = 0;
mLineContinuationIndent = 10;
mMouseDown = false;
mMouseSpecialLine = -1;
mMouseSpecialRef = -1;
for (U32 i = 0; i < 16; i++)
mAllowedMatches[i] = "";
mSpecialColor.set(0, 0, 255);
mMaxColorIndex = 9;
}
//--------------------------------------------------------------------------
GuiMessageVectorCtrl::~GuiMessageVectorCtrl()
{
AssertFatal(mLineWrappings.size() == 0, "Error, line wrappings not properly cleared!");
AssertFatal(mSpecialMarkers.size() == 0, "Error, special markers not properly cleared!");
AssertFatal(mLineElements.size() == 0, "Error, line elements not properly cleared!");
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("lineSpacing", TypeS32, Offset(mLineSpacingPixels, GuiMessageVectorCtrl));
addField("lineContinuedIndex", TypeS32, Offset(mLineContinuationIndent, GuiMessageVectorCtrl));
addField("allowedMatches", TypeString, Offset(mAllowedMatches, GuiMessageVectorCtrl), 16);
addField("matchColor", TypeColorI, Offset(mSpecialColor, GuiMessageVectorCtrl));
addField("maxColorIndex", TypeS32, Offset(mMaxColorIndex, GuiMessageVectorCtrl));
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::consoleInit()
{
Con::addCommand("GuiMessageVectorCtrl", "attach", cGMVCAttach, "[GuiMessageVectorCtrl].attach(MessageVectorId)", 3, 3);
Con::addCommand("GuiMessageVectorCtrl", "detach", cGMVCDetach, "[GuiMessageVectorCtrl].detach()", 2, 2);
}
bool GuiMessageVectorCtrl::onAdd()
{
return Parent::onAdd();
}
void GuiMessageVectorCtrl::onRemove()
{
Parent::onRemove();
}
//--------------------------------------------------------------------------
bool GuiMessageVectorCtrl::isAttached() const
{
return (mMessageVector != NULL);
}
//--------------------------------------------------------------------------
bool GuiMessageVectorCtrl::attach(MessageVector* newAttachment)
{
AssertFatal(newAttachment, "No attachment!");
if (newAttachment == NULL)
return false;
if (isAttached()) {
Con::warnf(ConsoleLogEntry::General, "GuiMessageVectorCtrl::attach: overriding attachment");
detach();
}
AssertFatal(mLineWrappings.size() == 0, "Error, line wrappings not properly cleared!");
mMessageVector = newAttachment;
mMessageVector->registerSpectator(sMVCtrlCallback, U32(this));
return true;
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::detach()
{
if (isAttached() == false) {
Con::warnf(ConsoleLogEntry::General, "GuiMessageVectorCtrl::detach: not attached!");
return;
}
mMessageVector->unregisterSpectator(U32(this));
mMessageVector = NULL;
AssertFatal(mLineWrappings.size() == 0, "Error, line wrappings not properly cleared!");
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::lineInserted(const U32 arg)
{
AssertFatal(mMessageVector != NULL, "Should not be here unless we're attached!");
GuiScrollCtrl* pScroll = NULL;
GuiControl* pParent = getParent();
if (pParent) {
GuiControl* pGrandParent = pParent->getParent();
if (pGrandParent)
pScroll = dynamic_cast<GuiScrollCtrl*>(pGrandParent);
}
bool scrollToBottom = false;
if (pScroll != NULL)
scrollToBottom = pScroll->getCurrVPos() == 1.0;
mSpecialMarkers.insert(arg);
createSpecialMarkers(mSpecialMarkers[arg], mMessageVector->getLine(arg).message);
mLineWrappings.insert(arg);
createLineWrapping(mLineWrappings[arg], mMessageVector->getLine(arg).message);
mLineElements.insert(arg);
createLineElement(mLineElements[arg], mLineWrappings[arg], mSpecialMarkers[arg]);
U32 numLines = 0;
for (U32 i = 0; i < mLineWrappings.size(); i++) {
// We need to rebuild the physicalLineStart markers at the same time as
// we find out how many of them are left...
mLineElements[i].physicalLineStart = numLines;
numLines += mLineWrappings[i].numLines;
}
U32 newHeight = (mProfile->mFont->getHeight() + mLineSpacingPixels) * getMax(numLines, U32(1));
resize(mBounds.point, Point2I(mBounds.extent.x, newHeight));
if (arg == mSpecialMarkers.size() - 1 && scrollToBottom == true)
pScroll->scrollTo(0, 1);
}
void GuiMessageVectorCtrl::lineDeleted(const U32 arg)
{
AssertFatal(mMessageVector != NULL, "Should not be here unless we're attached!");
AssertFatal(arg < mLineWrappings.size(), "Error, out of bounds line deleted!");
// It's a somewhat involved process to delete the lineelements...
LineElement& rElement = mLineElements[arg];
TextElement* walk = rElement.headLineElements;
while (walk != NULL) {
TextElement* lineWalk = walk->nextInLine;
while (lineWalk != NULL) {
TextElement* temp = lineWalk;
lineWalk = lineWalk->nextPhysicalLine;
delete temp;
}
TextElement* temp = walk;
walk = walk->nextPhysicalLine;
delete temp;
}
rElement.headLineElements = NULL;
mLineElements.erase(arg);
delete [] mLineWrappings[arg].startEndPairs;
mLineWrappings.erase(arg);
delete [] mSpecialMarkers[arg].specials;
mSpecialMarkers.erase(arg);
U32 numLines = 0;
for (U32 i = 0; i < mLineWrappings.size(); i++) {
// We need to rebuild the physicalLineStart markers at the same time as
// we find out how many of them are left...
mLineElements[i].physicalLineStart = numLines;
numLines += mLineWrappings[i].numLines;
}
U32 newHeight = (mProfile->mFont->getHeight() + mLineSpacingPixels) * getMax(numLines, U32(1));
resize(mBounds.point, Point2I(mBounds.extent.x, newHeight));
}
void GuiMessageVectorCtrl::vectorDeleted()
{
AssertFatal(mMessageVector != NULL, "Should not be here unless we're attached!");
AssertFatal(mLineWrappings.size() == 0, "Error, line wrappings not properly cleared out!");
mMessageVector = NULL;
U32 newHeight = mProfile->mFont->getHeight() + mLineSpacingPixels;
resize(mBounds.point, Point2I(mBounds.extent.x, newHeight));
}
void GuiMessageVectorCtrl::callbackRouter(const MessageVector::MessageCode code,
const U32 arg)
{
switch (code) {
case MessageVector::LineInserted:
lineInserted(arg);
break;
case MessageVector::LineDeleted:
lineDeleted(arg);
break;
case MessageVector::VectorDeletion:
vectorDeleted();
break;
}
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::createSpecialMarkers(SpecialMarkers& rSpecial, const char* string)
{
// The first thing we need to do is create a version of the string with no uppercase
// chars for matching...
char* pLCCopy = new char[dStrlen(string) + 1];
for (U32 i = 0; string[i] != '\0'; i++)
pLCCopy[i] = dTolower(string[i]);
pLCCopy[dStrlen(string)] = '\0';
Vector<TempLineBreak> tempSpecials(__FILE__, __LINE__);
Vector<S32> tempTypes(__FILE__, __LINE__);
const char* pCurr = pLCCopy;
while (pCurr[0] != '\0') {
const char* pMinMatch = &pLCCopy[dStrlen(string)];
U32 minMatchType = 0xFFFFFFFF;
AssertFatal(pMinMatch[0] == '\0', "Error, bad positioning of sentry...");
for (U32 i = 0; i < 16; i++) {
if (mAllowedMatches[i][0] == '\0')
continue;
// Not the most efficient...
char matchBuffer[512];
dStrncpy(matchBuffer, mAllowedMatches[i], 500);
matchBuffer[499] = '\0';
dStrcat(matchBuffer, "://");
const char* pMatch = dStrstr(pCurr, (const char*)matchBuffer);
if (pMatch != NULL && pMatch < pMinMatch) {
pMinMatch = pMatch;
minMatchType = i;
}
}
if (pMinMatch[0] != '\0') {
AssertFatal(minMatchType != 0xFFFFFFFF, "Hm, that's bad");
// Found a match...
U32 start = pMinMatch - pLCCopy;
U32 j;
for (j = 0; pLCCopy[start + j] != '\0'; j++) {
if (pLCCopy[start + j] == '\n' ||
pLCCopy[start + j] == ' ' ||
pLCCopy[start + j] == '\t')
break;
}
AssertFatal(j > 0, "Error, j must be > 0 at this point!");
U32 end = start + j - 1;
tempSpecials.increment();
tempSpecials.last().start = start;
tempSpecials.last().end = end;
tempTypes.push_back(minMatchType);
pCurr = &pLCCopy[end + 1];
} else {
// No match. This will cause the while loop to terminate...
pCurr = pMinMatch;
}
}
if ((rSpecial.numSpecials = tempSpecials.size()) != 0) {
rSpecial.specials = new SpecialMarkers::Special[tempSpecials.size()];
for (U32 i = 0; i < tempSpecials.size(); i++) {
rSpecial.specials[i].start = tempSpecials[i].start;
rSpecial.specials[i].end = tempSpecials[i].end;
rSpecial.specials[i].specialType = tempTypes[i];
}
} else {
rSpecial.specials = NULL;
}
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::createLineWrapping(LineWrapping& rWrapping, const char* string)
{
Vector<TempLineBreak> tempBreaks(__FILE__, __LINE__);
U32 i;
U32 currStart = 0;
if (dStrlen(string) != 0) {
for (i = 0; i < dStrlen(string); i++) {
if (string[i] == '\n') {
tempBreaks.increment();
tempBreaks.last().start = currStart;
tempBreaks.last().end = i-1;
currStart = i+1;
} else if (i == dStrlen(string) - 1) {
tempBreaks.increment();
tempBreaks.last().start = currStart;
tempBreaks.last().end = i;
currStart = i+1;
}
}
} else {
tempBreaks.increment();
tempBreaks.last().start = 0;
tempBreaks.last().end = -1;
}
bool used = false;
U32 splitWidth = mBounds.extent.x;
U32 currLine = 0;
while (currLine < tempBreaks.size()) {
TempLineBreak& rLine = tempBreaks[currLine];
if (rLine.start >= rLine.end) {
if (currLine == 0)
splitWidth -= mLineContinuationIndent;
currLine++;
continue;
}
// Ok, there's some actual text in this line. How long is it?
U32 baseLength = mProfile->mFont->getStrNWidthPrecise(&string[rLine.start], rLine.end-rLine.start+1);
if (baseLength > splitWidth) {
// DMMNOTE: Replace with bin search eventually
U32 currPos;
U32 breakPos;
for (currPos = 0; currPos < rLine.end-rLine.start+1; currPos++) {
U32 currLength = mProfile->mFont->getStrNWidthPrecise(&string[rLine.start], currPos+1);
if (currLength > splitWidth) {
// Make sure that the currPos has advanced, then set the breakPoint.
breakPos = currPos != 0 ? currPos - 1 : 0;
break;
}
}
if (currPos == rLine.end-rLine.start+1) {
AssertFatal(false, "Error, if the line must be broken, the position must be before this point!");
currLine++;
continue;
}
// Ok, the character at breakPos is the last valid char we can render. We
// want to scan back to the first whitespace character (which, in the bounds
// of the line, is guaranteed to be a space or a tab).
U32 originalBreak = breakPos;
while (true) {
if (string[rLine.start + breakPos] == ' ' || string[rLine.start + breakPos] == '\t') {
break;
} else {
AssertFatal(string[rLine.start + breakPos] != '\n',
"Bad characters in line range...");
if (breakPos == 0) {
breakPos = originalBreak;
break;
}
breakPos--;
}
}
// Ok, everything up to and including breakPos is in the currentLine. Insert
// a new line at this point, and put everything after in that line.
S32 oldStart = rLine.start;
S32 oldEnd = rLine.end;
rLine.end = rLine.start + breakPos;
// Note that rLine is NOTNOTNOTNOT valid after this point!
tempBreaks.insert(currLine+1);
tempBreaks[currLine+1].start = oldStart + breakPos + 1;
tempBreaks[currLine+1].end = oldEnd;
}
if (currLine == 0)
splitWidth -= mLineContinuationIndent;
currLine++;
}
rWrapping.numLines = tempBreaks.size();
rWrapping.startEndPairs = new LineWrapping::SEPair[tempBreaks.size()];
for (i = 0; i < tempBreaks.size(); i++) {
rWrapping.startEndPairs[i].start = tempBreaks[i].start;
rWrapping.startEndPairs[i].end = tempBreaks[i].end;
}
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::createLineElement(LineElement& rElement,
LineWrapping& rWrapping,
SpecialMarkers& rSpecial)
{
// First, do a straighforward translation of the wrapping...
TextElement** ppWalk = &rElement.headLineElements;
for (U32 i = 0; i < rWrapping.numLines; i++) {
*ppWalk = new TextElement;
(*ppWalk)->nextInLine = NULL;
(*ppWalk)->nextPhysicalLine = NULL;
(*ppWalk)->specialReference = -1;
(*ppWalk)->start = rWrapping.startEndPairs[i].start;
(*ppWalk)->end = rWrapping.startEndPairs[i].end;
ppWalk = &((*ppWalk)->nextPhysicalLine);
}
if (rSpecial.numSpecials != 0) {
// Ok. Now, walk down the lines, and split the elements into their contiuent parts...
//
TextElement* walk = rElement.headLineElements;
while (walk) {
TextElement* walkAcross = walk;
while (walkAcross) {
S32 specialMatch = -1;
for (U32 i = 0; i < rSpecial.numSpecials; i++) {
if (walkAcross->start <= rSpecial.specials[i].end &&
walkAcross->end >= rSpecial.specials[i].start) {
specialMatch = i;
break;
}
}
if (specialMatch != -1) {
// We have a match here. Break it into the appropriate number of segments.
// this will vary depending on how the overlap is occuring...
if (walkAcross->start >= rSpecial.specials[specialMatch].start) {
if (walkAcross->end <= rSpecial.specials[specialMatch].end) {
// The whole thing is part of the special
AssertFatal(walkAcross->nextInLine == NULL, "Bad assumption!");
walkAcross->specialReference = specialMatch;
} else {
// The first part is in the special, the tail is out
AssertFatal(walkAcross->nextInLine == NULL, "Bad assumption!");
walkAcross->nextInLine = new TextElement;
walkAcross->nextInLine->nextInLine = NULL;
walkAcross->nextInLine->nextPhysicalLine = NULL;
walkAcross->nextInLine->specialReference = -1;
walkAcross->specialReference = specialMatch;
walkAcross->nextInLine->end = walkAcross->end;
walkAcross->end = rSpecial.specials[specialMatch].end;
walkAcross->nextInLine->start = rSpecial.specials[specialMatch].end + 1;
AssertFatal(walkAcross->end >= walkAcross->start && walkAcross->nextInLine->end >= walkAcross->nextInLine->start, "Bad textelements generated!");
}
walkAcross = walkAcross->nextInLine;
} else {
if (walkAcross->end <= rSpecial.specials[specialMatch].end) {
// The first part is out of the special, the second part in.
AssertFatal(walkAcross->nextInLine == NULL, "Bad assumption!");
walkAcross->nextInLine = new TextElement;
walkAcross->nextInLine->nextInLine = NULL;
walkAcross->nextInLine->nextPhysicalLine = NULL;
walkAcross->nextInLine->specialReference = specialMatch;
walkAcross->specialReference = -1;
walkAcross->nextInLine->end = walkAcross->end;
walkAcross->end = rSpecial.specials[specialMatch].start - 1;
walkAcross->nextInLine->start = rSpecial.specials[specialMatch].start;
AssertFatal(walkAcross->end >= walkAcross->start && walkAcross->nextInLine->end >= walkAcross->nextInLine->start, "Bad textelements generated!");
walkAcross = walkAcross->nextInLine;
} else {
// First out, middle in, last out. Oy.
AssertFatal(walkAcross->nextInLine == NULL, "Bad assumption!");
walkAcross->nextInLine = new TextElement;
walkAcross->nextInLine->nextInLine = NULL;
walkAcross->nextInLine->nextPhysicalLine = NULL;
walkAcross->nextInLine->specialReference = specialMatch;
walkAcross->nextInLine->nextInLine = new TextElement;
walkAcross->nextInLine->nextInLine->nextInLine = NULL;
walkAcross->nextInLine->nextInLine->nextPhysicalLine = NULL;
walkAcross->nextInLine->nextInLine->specialReference = -1;
walkAcross->nextInLine->start = rSpecial.specials[specialMatch].start;
walkAcross->nextInLine->end = rSpecial.specials[specialMatch].end;
walkAcross->nextInLine->nextInLine->start = rSpecial.specials[specialMatch].end+1;
walkAcross->nextInLine->nextInLine->end = walkAcross->end;
walkAcross->end = walkAcross->nextInLine->start - 1;
AssertFatal((walkAcross->end >= walkAcross->start &&
walkAcross->nextInLine->end >= walkAcross->nextInLine->start &&
walkAcross->nextInLine->nextInLine->end >= walkAcross->nextInLine->nextInLine->start),
"Bad textelements generated!");
walkAcross = walkAcross->nextInLine->nextInLine;
}
}
} else {
walkAcross = walkAcross->nextInLine;
}
}
walk = walk->nextPhysicalLine;
}
}
}
//--------------------------------------------------------------------------
bool GuiMessageVectorCtrl::onWake()
{
if (Parent::onWake() == false)
return false;
if (bool(mProfile->mFont) == false)
return false;
mMinSensibleWidth = 1;
for (U32 i = 0; i < 256; i++) {
if (mProfile->mFont->isValidChar(U8(i))) {
if (mProfile->mFont->getCharWidth(U8(i)) > mMinSensibleWidth)
mMinSensibleWidth = mProfile->mFont->getCharWidth(U8(i));
}
}
AssertFatal(mLineWrappings.size() == 0, "Error, line wrappings not properly cleared!");
return true;
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::onSleep()
{
if (isAttached())
detach();
Parent::onSleep();
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::onRender(Point2I offset,
const RectI& updateRect,
GuiControl*fr)
{
Parent::onRender(offset, updateRect,fr);
if (isAttached()) {
U32 linePixels = mProfile->mFont->getHeight() + mLineSpacingPixels;
U32 currLine = 0;
for (U32 i = 0; i < mMessageVector->getNumLines(); i++) {
TextElement* pElement = mLineElements[i].headLineElements;
ColorI lastColor = mProfile->mFontColor;
while (pElement != NULL) {
Point2I localStart(pElement == mLineElements[i].headLineElements ? 0 : mLineContinuationIndent, currLine * linePixels);
Point2I globalCheck = localToGlobalCoord(localStart);
U32 globalRangeStart = globalCheck.y;
U32 globalRangeEnd = globalCheck.y + mProfile->mFont->getHeight();
if (globalRangeStart > updateRect.point.y + updateRect.extent.y ||
globalRangeEnd < updateRect.point.y) {
currLine++;
pElement = pElement->nextPhysicalLine;
continue;
}
TextElement* walkAcross = pElement;
while (walkAcross) {
if (walkAcross->start > walkAcross->end)
break;
Point2I globalStart = localToGlobalCoord(localStart);
U32 strWidth;
if (walkAcross->specialReference == -1) {
dglSetBitmapModulation(lastColor);
dglSetTextAnchorColor(mProfile->mFontColor);
strWidth = dglDrawTextN(mProfile->mFont, globalStart, &mMessageVector->getLine(i).message[walkAcross->start],
walkAcross->end - walkAcross->start + 1, mProfile->mFontColors, mMaxColorIndex);
dglGetBitmapModulation(&lastColor);
} else {
dglGetBitmapModulation(&lastColor);
dglSetBitmapModulation(mSpecialColor);
dglSetTextAnchorColor(mProfile->mFontColor);
strWidth = dglDrawTextN(mProfile->mFont, globalStart, &mMessageVector->getLine(i).message[walkAcross->start],
walkAcross->end - walkAcross->start + 1);
// in case we have 2 in a row...
dglSetBitmapModulation(lastColor);
}
if (walkAcross->specialReference != -1) {
Point2I lineStart = localStart;
Point2I lineEnd = localStart;
lineStart.y += mProfile->mFont->getBaseline() + 1;
lineEnd.x += strWidth;
lineEnd.y += mProfile->mFont->getBaseline() + 1;
dglDrawLine(localToGlobalCoord(lineStart),
localToGlobalCoord(lineEnd),
mSpecialColor);
}
localStart.x += strWidth;
walkAcross = walkAcross->nextInLine;
}
currLine++;
pElement = pElement->nextPhysicalLine;
}
}
dglClearBitmapModulation();
}
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::inspectPostApply()
{
Parent::inspectPostApply();
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::parentResized(const Point2I& oldSize,
const Point2I& newSize)
{
Parent::parentResized(oldSize, newSize);
if (mMessageVector)
{
MessageVector *reflowme = mMessageVector;
detach();
attach(reflowme);
}
}
//--------------------------------------------------------------------------
void GuiMessageVectorCtrl::findSpecialFromCoord(const Point2I& point, S32* specialLine, S32* specialRef)
{
if (mLineElements.size() == 0) {
*specialLine = -1;
*specialRef = -1;
return;
}
U32 linePixels = mProfile->mFont->getHeight() + mLineSpacingPixels;
if ((point.x < 0 || point.x >= mBounds.extent.x) ||
(point.y < 0 || point.y >= mBounds.extent.y)) {
*specialLine = -1;
*specialRef = -1;
return;
}
// Ok, we have real work to do here. Let's determine the physical line that it's on...
U32 physLine = point.y / linePixels;
AssertFatal(physLine >= 0, "Bad physical line!");
// And now we find the LineElement that contains that physicalline...
U32 elemIndex;
for (elemIndex = 0; elemIndex < mLineElements.size(); elemIndex++) {
if (mLineElements[elemIndex].physicalLineStart > physLine) {
// We've passed it.
AssertFatal(elemIndex != 0, "Error, bad elemIndex, check assumptions.");
elemIndex--;
break;
}
}
if (elemIndex == mLineElements.size()) {
// On the last line...
elemIndex = mLineElements.size() - 1;
}
TextElement* line = mLineElements[elemIndex].headLineElements;
for (U32 i = 0; i < physLine - mLineElements[elemIndex].physicalLineStart; i++) {
line = line->nextPhysicalLine;
AssertFatal(line != NULL, "Error, moved too far!");
}
// Ok, line represents the current line. We now need to find out which textelement
// the points x coord falls in.
U32 currX = 0;
if ((physLine - mLineElements[elemIndex].physicalLineStart) != 0) {
currX = mLineContinuationIndent;
// First, if this isn't the first line in this wrapping, we have to make sure
// that the coord isn't in the margin...
if (point.x < mLineContinuationIndent) {
*specialLine = -1;
*specialRef = -1;
return;
}
}
if (line->start > line->end) {
// Empty line special case...
*specialLine = -1;
*specialRef = -1;
return;
}
U32 currElem = 0;
while (line) {
U32 newX = currX + mProfile->mFont->getStrNWidth(mMessageVector->getLine(elemIndex).message,
line->end - line->start + 1);
if (point.x < newX) {
// That's the one!
*specialLine = elemIndex;
*specialRef = line->specialReference;
return;
}
currX = newX;
line = line->nextInLine;
}
// Off to the right. Aw...
*specialLine = -1;
*specialRef = -1;
}
void GuiMessageVectorCtrl::onMouseDown(const GuiEvent& event)
{
Parent::onMouseDown(event);
mouseUnlock();
mMouseDown = true;
// Find the special we are in, if any...
findSpecialFromCoord(globalToLocalCoord(event.mousePoint),
&mMouseSpecialLine, &mMouseSpecialRef);
}
void GuiMessageVectorCtrl::onMouseUp(const GuiEvent& event)
{
Parent::onMouseUp(event);
mouseUnlock();
// Is this an up from a dragged click?
if (mMouseDown == false)
return;
// Find the special we are in, if any...
S32 currSpecialLine;
S32 currSpecialRef;
findSpecialFromCoord(globalToLocalCoord(event.mousePoint), &currSpecialLine, &currSpecialRef);
if (currSpecialRef != -1 &&
(currSpecialLine == mMouseSpecialLine &&
currSpecialRef == mMouseSpecialRef)) {
// Execute the callback
SpecialMarkers& rSpecial = mSpecialMarkers[currSpecialLine];
S32 specialStart = rSpecial.specials[currSpecialRef].start;
S32 specialEnd = rSpecial.specials[currSpecialRef].end;
char* copyURL = new char[specialEnd - specialStart + 2];
dStrncpy(copyURL, &mMessageVector->getLine(currSpecialLine).message[specialStart], specialEnd - specialStart + 1);
copyURL[specialEnd - specialStart + 1] = '\0';
Con::executef(this, 2, "urlClickCallback", copyURL);
delete [] copyURL;
}
mMouseDown = false;
mMouseSpecialLine = -1;
mMouseSpecialRef = -1;
}

130
gui/guiMessageVectorCtrl.h Normal file
View file

@ -0,0 +1,130 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIMESSAGEVECTORCTRL_H_
#define _GUIMESSAGEVECTORCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
#ifndef _MESSAGEVECTOR_H_
#include "GUI/messageVector.h"
#endif
class GuiMessageVectorCtrl : public GuiControl
{
typedef GuiControl Parent;
//-------------------------------------- Public interfaces...
public:
struct SpecialMarkers {
struct Special {
S32 specialType;
S32 start;
S32 end;
};
U32 numSpecials;
Special* specials;
};
GuiMessageVectorCtrl();
~GuiMessageVectorCtrl();
bool isAttached() const;
bool attach(MessageVector*);
void detach();
// Gui control overrides
protected:
bool onAdd();
void onRemove();
bool onWake();
void onSleep();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void inspectPostApply();
void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
void onMouseUp(const GuiEvent &event);
void onMouseDown(const GuiEvent &event);
// void onMouseMove(const GuiEvent &event);
// Overrideables
protected:
virtual void lineInserted(const U32);
virtual void lineDeleted(const U32);
virtual void vectorDeleted();
MessageVector* mMessageVector;
// Font resource
protected:
U32 mMinSensibleWidth;
U32 mLineSpacingPixels;
U32 mLineContinuationIndent;
StringTableEntry mAllowedMatches[16];
ColorI mSpecialColor;
U32 mMaxColorIndex;
bool mMouseDown;
S32 mMouseSpecialLine;
S32 mMouseSpecialRef;
// Derived classes must keep this set of variables consistent if they
// use this classes onRender. Note that this has the fairly large
// disadvantage of requiring lots of ugly, tiny mem allocs. A rewrite
// to a more memory friendly version might be a good idea...
struct LineWrapping {
struct SEPair {
S32 start;
S32 end;
};
U32 numLines;
SEPair* startEndPairs; // start[linex] = startEndPairs[linex*2+0]
// end[linex] = startEndPairs[linex*2+1]
// if end < start, line is empty...
};
struct TextElement {
TextElement* nextInLine;
TextElement* nextPhysicalLine;
S32 specialReference; // if (!= -1), indicates a special reference
S32 start;
S32 end;
};
struct LineElement {
U32 physicalLineStart;
TextElement* headLineElements;
};
Vector<LineWrapping> mLineWrappings;
Vector<SpecialMarkers> mSpecialMarkers;
Vector<LineElement> mLineElements;
void createLineWrapping(LineWrapping&, const char*);
void createSpecialMarkers(SpecialMarkers&, const char*);
void createLineElement(LineElement&, LineWrapping&, SpecialMarkers&);
void findSpecialFromCoord(const Point2I&, S32*, S32*);
public:
void callbackRouter(const MessageVector::MessageCode, const U32);
public:
DECLARE_CONOBJECT(GuiMessageVectorCtrl);
static void initPersistFields();
static void consoleInit();
};
#endif // _H_GUIMESSAGEVECTORCTRL_

100
gui/guiMouseEventCtrl.cc Normal file
View file

@ -0,0 +1,100 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/guiMouseEventCtrl.h"
#include "console/consoleTypes.h"
IMPLEMENT_CONOBJECT(GuiMouseEventCtrl);
GuiMouseEventCtrl::GuiMouseEventCtrl()
{
mLockMouse = false;
}
//------------------------------------------------------------------------------
void GuiMouseEventCtrl::sendMouseEvent(const char * name, const GuiEvent & event)
{
char buf[3][32];
dSprintf(buf[0], 32, "%d", event.modifier);
dSprintf(buf[1], 32, "%d %d", event.mousePoint.x, event.mousePoint.y);
dSprintf(buf[2], 32, "%d", event.mouseClickCount);
Con::executef(this, 4, name, buf[0], buf[1], buf[2]);
}
//------------------------------------------------------------------------------
void GuiMouseEventCtrl::consoleInit()
{
Con::setIntVariable("$EventModifier::LSHIFT", SI_LSHIFT);
Con::setIntVariable("$EventModifier::RSHIFT", SI_RSHIFT);
Con::setIntVariable("$EventModifier::SHIFT", SI_SHIFT);
Con::setIntVariable("$EventModifier::LCTRL", SI_LCTRL);
Con::setIntVariable("$EventModifier::RCTRL", SI_RCTRL);
Con::setIntVariable("$EventModifier::CTRL", SI_CTRL);
Con::setIntVariable("$EventModifier::LALT", SI_LALT);
Con::setIntVariable("$EventModifier::RALT", SI_RALT);
Con::setIntVariable("$EventModifier::ALT", SI_ALT);
}
void GuiMouseEventCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("lockMouse", TypeBool, Offset(mLockMouse, GuiMouseEventCtrl));
}
//------------------------------------------------------------------------------
void GuiMouseEventCtrl::onMouseDown(const GuiEvent & event)
{
if(mLockMouse)
mouseLock();
sendMouseEvent("onMouseDown", event);
}
void GuiMouseEventCtrl::onMouseUp(const GuiEvent & event)
{
if(mLockMouse)
mouseUnlock();
sendMouseEvent("onMouseUp", event);
}
void GuiMouseEventCtrl::onMouseMove(const GuiEvent & event)
{
sendMouseEvent("onMouseMove", event);
}
void GuiMouseEventCtrl::onMouseDragged(const GuiEvent & event)
{
sendMouseEvent("onMouseDragged", event);
}
void GuiMouseEventCtrl::onMouseEnter(const GuiEvent & event)
{
sendMouseEvent("onMouseEnter", event);
}
void GuiMouseEventCtrl::onMouseLeave(const GuiEvent & event)
{
sendMouseEvent("onMouseLeave", event);
}
void GuiMouseEventCtrl::onRightMouseDown(const GuiEvent & event)
{
if(mLockMouse)
mouseLock();
sendMouseEvent("onRightMouseDown", event);
}
void GuiMouseEventCtrl::onRightMouseUp(const GuiEvent & event)
{
if(mLockMouse)
mouseUnlock();
sendMouseEvent("onRightMouseUp", event);
}
void GuiMouseEventCtrl::onRightMouseDragged(const GuiEvent & event)
{
sendMouseEvent("onRightMouseDragged", event);
}

49
gui/guiMouseEventCtrl.h Normal file
View file

@ -0,0 +1,49 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIMOUSEEVENTCTRL_H_
#define _GUIMOUSEEVENTCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
#ifndef _EVENT_H_
#include "Platform/event.h"
#endif
class GuiMouseEventCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
void sendMouseEvent(const char * name, const GuiEvent &);
// field info
bool mLockMouse;
public:
GuiMouseEventCtrl();
// GuiControl
void onMouseDown(const GuiEvent & event);
void onMouseUp(const GuiEvent & event);
void onMouseMove(const GuiEvent & event);
void onMouseDragged(const GuiEvent & event);
void onMouseEnter(const GuiEvent & event);
void onMouseLeave(const GuiEvent & event);
void onRightMouseDown(const GuiEvent & event);
void onRightMouseUp(const GuiEvent & event);
void onRightMouseDragged(const GuiEvent & event);
static void consoleInit();
static void initPersistFields();
DECLARE_CONOBJECT(GuiMouseEventCtrl);
};
#endif

929
gui/guiPopUpCtrl.cc Normal file
View file

@ -0,0 +1,929 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "dgl/dgl.h"
#include "GUI/guiCanvas.h"
#include "GUI/guiPopUpCtrl.h"
#include "console/consoleTypes.h"
//------------------------------------------------------------------------------
GuiPopUpTextListCtrl::GuiPopUpTextListCtrl()
{
mPopUpCtrl = NULL;
mMouseDown = AlreadyDown;
}
//------------------------------------------------------------------------------
GuiPopUpTextListCtrl::GuiPopUpTextListCtrl(GuiPopUpMenuCtrl *ctrl)
{
mPopUpCtrl = ctrl;
mMouseDown = AlreadyDown;
}
//------------------------------------------------------------------------------
GuiPopUpTextListCtrl::~GuiPopUpTextListCtrl()
{
}
//------------------------------------------------------------------------------
void GuiPopUpTextListCtrl::onSleep()
{
mMouseDown = None;
Parent::onSleep();
}
//------------------------------------------------------------------------------
void GuiPopUpTextListCtrl::onCellSelected( Point2I /*cell*/ )
{
// Do nothing, the parent control will take care of everything...
}
//------------------------------------------------------------------------------
bool GuiPopUpTextListCtrl::onKeyDown(const GuiEvent &event)
{
//if the control is a dead end, don't process the input:
if ( !mVisible || !mActive || !mAwake )
return false;
//see if the key down is a <return> or not
if ( event.modifier == 0 )
{
if ( event.keyCode == KEY_RETURN )
{
mPopUpCtrl->closePopUp();
return true;
}
else if ( event.keyCode == KEY_ESCAPE )
{
mSelectedCell.set( -1, -1 );
mPopUpCtrl->closePopUp();
return true;
}
}
//otherwise, pass the event to it's parent
return Parent::onKeyDown(event);
}
//------------------------------------------------------------------------------
void GuiPopUpTextListCtrl::onMouseDown(const GuiEvent &event)
{
mMouseDown = None;
// See if it's within the scroll content ctrl:
GuiControl *parent = getParent();
if ( !parent )
return;
if ( parent->cursorInControl() )
{
//let the parent handle the event
Parent::onMouseDown(event);
mMouseDown = TextListArea;
//we're done
return;
}
//see if it's within the scroll control
GuiControl *grandParent = parent->getParent();
if ( !grandParent )
return;
if ( grandParent->cursorInControl() )
{
//let the scroll control deal with it
grandParent->onMouseDown(event);
mMouseDown = ScrollArea;
//and we're done
return;
}
}
//------------------------------------------------------------------------------
void GuiPopUpTextListCtrl::onMouseDragged(const GuiEvent &event)
{
//the only way to get here, is if the scroll control is dragging
//else see if it's within the scroll control
GuiControl *parent = getParent();
if ( !parent )
return;
GuiControl *grandParent = parent->getParent();
if ( !grandParent )
return;
//let the scroll control deal with it
grandParent->onMouseDragged( event );
//will highlight the text while dragging
onMouseMove( event );
if ( mMouseDown == AlreadyDown )
{
if ( parent->cursorInControl() )
mMouseDown = TextListArea;
return;
}
if ( mMouseDown != ScrollArea )
mPopUpCtrl->setupAutoScroll( event );
}
//------------------------------------------------------------------------------
void GuiPopUpTextListCtrl::onMouseUp(const GuiEvent &event)
{
mPopUpCtrl->mScrollDir = GuiScrollCtrl::None;
//see if it's within the scroll content ctrl
GuiControl *parent = getParent();
if ( !parent )
return;
// Initial case--this control locks the mouse upon creation.
// If mouse is released outside of the menu, just move to next stage
// else if dragged over menu and released, select the appropriate entry
if ( mMouseDown == AlreadyDown )
{
if ( !parent->cursorInControl() )
{
mMouseDown = None;
return;
}
}
if ( parent->cursorInControl() )
{
// Select the item the mouse is over:
Point2I localPt = globalToLocalCoord( event.mousePoint );
Point2I cell( 0, ( localPt.y < 0 ? -1 : localPt.y / mCellSize.y ) );
if ( cell.y >= 0 && cell.y < mSize.y )
cellSelected( Point2I( 0, cell.y ) );
//now let the pop up know a cell has been selected...
mPopUpCtrl->closePopUp();
//we're done
return;
}
//see if it's within the scroll control
GuiControl *grandParent = parent->getParent();
if ( !grandParent )
return;
if ( grandParent->cursorInControl() )
{
//let the scroll control deal with it
grandParent->onMouseUp( event );
//and we're done
return;
}
// otherwise, we clicked outside the popup, and we're done
// let the pop up know a cell has been selected...
if ( mMouseDown == None )
mPopUpCtrl->closePopUp();
}
//------------------------------------------------------------------------------
void GuiPopUpTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
{
ColorI fontColor;
mPopUpCtrl->getFontColor( fontColor, mList[cell.y].id, selected, mouseOver );
dglSetBitmapModulation( fontColor );
dglDrawText( mFont, Point2I( offset.x + 4, offset.y ), mList[cell.y].text );
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
GuiPopUpMenuCtrl::GuiPopUpMenuCtrl(void)
{
VECTOR_SET_ASSOCIATION(mEntries);
VECTOR_SET_ASSOCIATION(mSchemes);
mSelIndex = -1;
mActive = true;
mMaxPopupHeight = 200;
mScrollDir = GuiScrollCtrl::None;
mScrollCount = 0;
mLastYvalue = 0;
mIncValue = 0;
mRevNum = 0;
mInAction = false;
}
//------------------------------------------------------------------------------
GuiPopUpMenuCtrl::~GuiPopUpMenuCtrl()
{
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::initPersistFields(void)
{
Parent::initPersistFields();
addField("maxPopupHeight", TypeS32, Offset(mMaxPopupHeight, GuiPopUpMenuCtrl));
}
//------------------------------------------------------------------------------
static void cGuiPopUpMenuAdd(SimObject *obj, S32 argc, const char **argv)
{
GuiPopUpMenuCtrl *ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
if ( argc > 4 )
ctrl->addEntry(argv[2],dAtoi(argv[3]),dAtoi(argv[4]));
else
ctrl->addEntry(argv[2],dAtoi(argv[3]),0);
}
static void cGuiPopUpMenuAddScheme(SimObject *obj, S32, const char **argv)
{
GuiPopUpMenuCtrl *ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
ColorI fontColor, fontColorHL, fontColorSEL;
U32 r, g, b;
char buf[64];
dStrcpy( buf, argv[3] );
char* temp = dStrtok( buf, " \0" );
r = temp ? dAtoi( temp ) : 0;
temp = dStrtok( NULL, " \0" );
g = temp ? dAtoi( temp ) : 0;
temp = dStrtok( NULL, " \0" );
b = temp ? dAtoi( temp ) : 0;
fontColor.set( r, g, b );
dStrcpy( buf, argv[4] );
temp = dStrtok( buf, " \0" );
r = temp ? dAtoi( temp ) : 0;
temp = dStrtok( NULL, " \0" );
g = temp ? dAtoi( temp ) : 0;
temp = dStrtok( NULL, " \0" );
b = temp ? dAtoi( temp ) : 0;
fontColorHL.set( r, g, b );
dStrcpy( buf, argv[5] );
temp = dStrtok( buf, " \0" );
r = temp ? dAtoi( temp ) : 0;
temp = dStrtok( NULL, " \0" );
g = temp ? dAtoi( temp ) : 0;
temp = dStrtok( NULL, " \0" );
b = temp ? dAtoi( temp ) : 0;
fontColorSEL.set( r, g, b );
ctrl->addScheme( dAtoi( argv[2] ), fontColor, fontColorHL, fontColorSEL );
}
static void cGuiPopUpMenuSetText(SimObject *obj, S32, const char **argv)
{
GuiPopUpMenuCtrl *ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
ctrl->setText(argv[2]);
}
static const char * cGuiPopUpMenuGetText(SimObject *obj, S32, const char **)
{
GuiPopUpMenuCtrl *ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
return ctrl->getText();
}
static void cGuiPopUpMenuClear(SimObject *obj, S32, const char **)
{
GuiPopUpMenuCtrl *ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
ctrl->clear();
}
static void cGuiPopUpMenuSort(SimObject *obj, S32, const char **)
{
GuiPopUpMenuCtrl *ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
ctrl->sort();
}
static void cGuiPopUpMenuOnAction(SimObject *obj, S32, const char **)
{
GuiPopUpMenuCtrl *ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
ctrl->onAction();
}
static void cGuiPopUpMenuClose(SimObject *obj, S32, const char **)
{
GuiPopUpMenuCtrl *ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
ctrl->closePopUp();
}
static S32 cGuiPopUpMenuGetSelected(SimObject * obj, S32, const char **)
{
GuiPopUpMenuCtrl * ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
return ctrl->getSelected();
}
static void cGuiPopUpMenuSetSelected(SimObject * obj, S32, const char ** argv)
{
GuiPopUpMenuCtrl * ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
ctrl->setSelected(dAtoi(argv[2]));
}
static const char * cGuiPopUpMenuGetTextById(SimObject * obj, S32, const char ** argv)
{
GuiPopUpMenuCtrl * ctrl = static_cast<GuiPopUpMenuCtrl*>(obj);
return(ctrl->getTextById(dAtoi(argv[2])));
}
//------------------------------------------------------------------------------
// this fills the popup with a classrep's field enumeration type info - more of a
// helper function than anything. If console access to the field list is added,
// at least for the enumerated types, then this should go away..
//
// args:
// argv[2] - class
// argv[3] - field
static void cGuiPopUpMenuSetEnumContent(SimObject * obj, S32, const char ** argv)
{
GuiPopUpMenuCtrl * menu = static_cast<GuiPopUpMenuCtrl*>(obj);
AbstractClassRep * classRep = AbstractClassRep::getClassList();
// walk the class list to get our class
while(classRep)
{
if(!dStricmp(classRep->getClassName(), argv[2]))
break;
classRep = classRep->getNextClass();
}
// get it?
if(!classRep)
{
Con::warnf(ConsoleLogEntry::General, "failed to locate class rep for '%s'", argv[2]);
return;
}
// walk the fields to check for this one (findField checks StringTableEntry ptrs...)
U32 i;
for(i = 0; i < classRep->mFieldList.size(); i++)
if(!dStricmp(classRep->mFieldList[i].pFieldname, argv[3]))
break;
// found it?
if(i == classRep->mFieldList.size())
{
Con::warnf(ConsoleLogEntry::General, "failed to locate field '%s' for class '%s'", argv[3], argv[2]);
return;
}
const AbstractClassRep::Field & field = classRep->mFieldList[i];
// check the type
if(field.type != TypeEnum)
{
Con::warnf(ConsoleLogEntry::General, "field '%s' is not an enumeration for class '%s'", argv[3], argv[2]);
return;
}
AssertFatal(field.table, avar("enumeration '%s' for class '%s' with NULL ", argv[3], argv[2]));
// fill it
for(i = 0; i < field.table->size; i++)
menu->addEntry(field.table->table[i].label, field.table->table[i].index);
}
//------------------------------------------------------------------------------
static S32 cGuiPopUpMenuFindText( SimObject* obj, S32, const char** argv )
{
AssertFatal( dynamic_cast<GuiPopUpMenuCtrl*>( obj ), "Object passed to cGuiPopUpMenuFindText is not a GuiPopUpMenuCtrl!" );
GuiPopUpMenuCtrl* ctrl = static_cast<GuiPopUpMenuCtrl*>( obj );
return( ctrl->findText( argv[2] ) );
}
//------------------------------------------------------------------------------
static S32 cGuiPopUpSize( SimObject* obj, S32, const char** )
{
AssertFatal( dynamic_cast<GuiPopUpMenuCtrl*>( obj ), "Object passed to cGuiPopUpSize is not a GuiPopUpMenuCtrl!" );
GuiPopUpMenuCtrl* ctrl = static_cast<GuiPopUpMenuCtrl*>( obj );
return( ctrl->getNumEntries() );
}
//------------------------------------------------------------------------------
void cGuiReplaceText( SimObject* obj, S32, const char** argv)
{
GuiPopUpMenuCtrl* ctrl = static_cast<GuiPopUpMenuCtrl*>( obj );
ctrl->replaceText(dAtoi(argv[2]));
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::consoleInit()
{
Con::addCommand("GuiPopUpMenuCtrl", "sort", cGuiPopUpMenuSort, "menu.sort()", 2, 2);
Con::addCommand("GuiPopUpMenuCtrl", "add", cGuiPopUpMenuAdd, "menu.add(name,idNum{,scheme})", 4, 5);
Con::addCommand("GuiPopUpMenuCtrl", "addScheme", cGuiPopUpMenuAddScheme, "menu.addScheme(id, fontColor, fontColorHL, fontColorSEL)", 6, 6);
Con::addCommand("GuiPopUpMenuCtrl", "getText", cGuiPopUpMenuGetText, "menu.getText()", 2, 2);
Con::addCommand("GuiPopUpMenuCtrl", "setText", cGuiPopUpMenuSetText, "menu.setText(text)", 3, 3);
Con::addCommand("GuiPopUpMenuCtrl", "getValue", cGuiPopUpMenuGetText, "menu.getValue()", 2, 2);
Con::addCommand("GuiPopUpMenuCtrl", "setValue", cGuiPopUpMenuSetText, "menu.setValue(text)", 3, 3);
Con::addCommand("GuiPopUpMenuCtrl", "clear", cGuiPopUpMenuClear, "menu.clear()", 2, 2);
Con::addCommand("GuiPopUpMenuCtrl", "forceOnAction", cGuiPopUpMenuOnAction, "menu.forceOnAction()", 2, 2);
Con::addCommand("GuiPopUpMenuCtrl", "forceClose", cGuiPopUpMenuClose, "menu.forceClose()", 2, 2);
Con::addCommand("GuiPopUpMenuCtrl", "getSelected", cGuiPopUpMenuGetSelected, "menu.getSelected()", 2, 2);
Con::addCommand("GuiPopUpMenuCtrl", "setSelected", cGuiPopUpMenuSetSelected, "menu.setSelected(id)", 3, 3);
Con::addCommand("GuiPopUpMenuCtrl", "getTextById", cGuiPopUpMenuGetTextById, "menu.getTextById(id)", 3, 3);
Con::addCommand("GuiPopUpMenuCtrl", "setEnumContent", cGuiPopUpMenuSetEnumContent, "menu.setEnumContent(class, enum)", 4, 4);
Con::addCommand("GuiPopUpMenuCtrl", "findText", cGuiPopUpMenuFindText, "menu.findText(text)", 3, 3);
Con::addCommand("GuiPopUpMenuCtrl", "size", cGuiPopUpSize, "menu.size()", 2, 2);
Con::addCommand("GuiPopUpMenuCtrl", "replaceText", cGuiReplaceText, "menu.replaceText(bool)", 3, 3);
}
//------------------------------------------------------------------------------
bool GuiPopUpMenuCtrl::onAdd()
{
if (!Parent::onAdd())
return false;
mSelIndex = -1;
mReplaceText = true;
return true;
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::onSleep()
{
Parent::onSleep();
closePopUp(); // Tests in function.
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::clear()
{
mEntries.setSize(0);
setText("");
mSelIndex = -1;
mRevNum = 0;
}
//------------------------------------------------------------------------------
static S32 QSORT_CALLBACK textCompare(const void *a,const void *b)
{
GuiPopUpMenuCtrl::Entry *ea = (GuiPopUpMenuCtrl::Entry *) (a);
GuiPopUpMenuCtrl::Entry *eb = (GuiPopUpMenuCtrl::Entry *) (b);
return (dStricmp(eb->buf, ea->buf));
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::sort()
{
dQsort((void *)&(mEntries[0]), mEntries.size(), sizeof(Entry), textCompare);
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::addEntry(const char *buf, S32 id, U32 scheme)
{
Entry e;
dStrcpy(e.buf, buf);
e.id = id;
e.scheme = scheme;
// see if there is a shortcut key
char * cp = dStrchr(e.buf, '~');
e.ascii = cp ? cp[1] : 0;
mEntries.push_back(e);
if ( mInAction && mTl )
{
// Add the new entry:
mTl->addEntry( e.id, e.buf );
repositionPopup();
}
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::addScheme( U32 id, ColorI fontColor, ColorI fontColorHL, ColorI fontColorSEL )
{
if ( !id )
return;
Scheme newScheme;
newScheme.id = id;
newScheme.fontColor = fontColor;
newScheme.fontColorHL = fontColorHL;
newScheme.fontColorSEL = fontColorSEL;
mSchemes.push_back( newScheme );
}
//------------------------------------------------------------------------------
S32 GuiPopUpMenuCtrl::getSelected()
{
if (mSelIndex == -1)
return 0;
return mEntries[mSelIndex].id;
}
//------------------------------------------------------------------------------
const char* GuiPopUpMenuCtrl::getTextById(S32 id)
{
for ( U32 i = 0; i < mEntries.size(); i++ )
{
if ( mEntries[i].id == id )
return( mEntries[i].buf );
}
return( "" );
}
//------------------------------------------------------------------------------
S32 GuiPopUpMenuCtrl::findText( const char* text )
{
for ( U32 i = 0; i < mEntries.size(); i++ )
{
if ( dStrcmp( text, mEntries[i].buf ) == 0 )
return( mEntries[i].id );
}
return( -1 );
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::setSelected(S32 id)
{
S32 i;
for (i = 0; U32(i) < mEntries.size(); i++)
if (id == mEntries[i].id)
{
i = (mRevNum > i) ? mRevNum - i : i;
mSelIndex = i;
setText(mEntries[i].buf);
return;
}
setText("");
mSelIndex = -1;
}
//------------------------------------------------------------------------------
const char *GuiPopUpMenuCtrl::getScriptValue()
{
return getText();
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
updateRect;
firstResponder;
Point2I localStart;
if(mScrollDir != GuiScrollCtrl::None)
autoScroll();
RectI r(offset, mBounds.extent);
dglDrawRectFill(r, mProfile->mBorderColor);
r.point.x +=2;
r.point.y +=2;
r.extent.x -=4;
r.extent.y -=4;
dglDrawRectFill(r, mProfile->mFillColor);
S32 txt_w = mFont->getStrWidth(mText);
localStart.x = 0;
localStart.y = (mBounds.extent.y - (mFont->getHeight())) / 2;
// align the horizontal
switch (mProfile->mAlignment)
{
case GuiControlProfile::RightJustify:
localStart.x = mBounds.extent.x - txt_w;
break;
case GuiControlProfile::CenterJustify:
localStart.x = (mBounds.extent.x - txt_w) / 2;
break;
default:
// GuiControlProfile::LeftJustify
localStart.x = 0;
break;
}
Point2I globalStart = localToGlobalCoord(localStart);
dglSetBitmapModulation(mProfile->mFontColor);
dglDrawText(mFont, globalStart, mText, mProfile->mFontColors);
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::closePopUp()
{
if ( !mInAction )
return;
// Get the selection from the text list:
mSelIndex = mTl->getSelectedCell().y;
mSelIndex = (mRevNum >= mSelIndex && mSelIndex != -1) ? mRevNum - mSelIndex : mSelIndex;
if ( mSelIndex != -1 )
{
if(mReplaceText)
setText( mEntries[mSelIndex].buf );
setIntVariable( mEntries[mSelIndex].id );
}
// Release the mouse:
mInAction = false;
mTl->mouseUnlock();
// Pop the background:
getRoot()->popDialogControl(mBackground);
// Kill the popup:
mBackground->removeObject( mSc );
mTl->deleteObject();
mSc->deleteObject();
mBackground->deleteObject();
// Set this as the first responder:
setFirstResponder();
// Now perform the popup action:
if ( mSelIndex != -1 )
{
char idval[24];
dSprintf( idval, sizeof(idval), "%d", mEntries[mSelIndex].id );
Con::executef( this, 3, "onSelect", idval, mEntries[mSelIndex].buf );
}
else
Con::executef( this, 1, "onCancel" );
// Execute the popup console command:
if ( mConsoleCommand[0] )
Con::evaluate( mConsoleCommand, false );
}
//------------------------------------------------------------------------------
bool GuiPopUpMenuCtrl::onKeyDown(const GuiEvent &event)
{
//if the control is a dead end, don't process the input:
if ( !mVisible || !mActive || !mAwake )
return false;
//see if the key down is a <return> or not
if ( event.keyCode == KEY_RETURN && event.modifier == 0 )
{
onAction();
return true;
}
//otherwise, pass the event to its parent
return Parent::onKeyDown( event );
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::onAction()
{
GuiControl *canCtrl = getParent();
addChildren();
GuiCanvas *root = getRoot();
Point2I windowExt = root->mBounds.extent;
mBackground->mBounds.point.set(0,0);
mBackground->mBounds.extent = root->mBounds.extent;
S32 textWidth = 0, width = mBounds.extent.x;
const S32 menuSpace = 5;
const S32 textSpace = 2;
bool setScroll = false;
for(U32 i=0; i<mEntries.size(); ++i)
if(S32(mFont->getStrWidth(mEntries[i].buf)) > textWidth)
textWidth = mFont->getStrWidth(mEntries[i].buf);
if(textWidth > mBounds.extent.x)
{
textWidth +=10;
width = textWidth;
}
mTl->setCellSize(Point2I(width, mFont->getHeight()+3));
for(U32 j=0; j<mEntries.size(); ++j)
mTl->addEntry(mEntries[j].id, mEntries[j].buf);
Point2I pointInGC = canCtrl->localToGlobalCoord(mBounds.point);
Point2I scrollPoint(pointInGC.x, pointInGC.y + mBounds.extent.y);
//Calc max Y distance, so Scroll Ctrl will fit on window
S32 maxYdis = windowExt.y - pointInGC.y - mBounds.extent.y - menuSpace;
//If scroll bars need to be added
if(maxYdis < mTl->mBounds.extent.y + textSpace)
{
//Should we pop menu list above the button
if(maxYdis < pointInGC.y - menuSpace)
{
reverseTextList();
maxYdis = pointInGC.y - menuSpace;
//Does the menu need a scroll bar
if(maxYdis < mTl->mBounds.extent.y + textSpace)
{
//Calc for the width of the scroll bar
if(textWidth >= width)
width += 20;
mTl->setCellSize(Point2I(width,mFont->getHeight() + textSpace));
//Pop menu list above the button
scrollPoint.set(pointInGC.x, menuSpace - 1);
setScroll = true;
}
//No scroll bar needed
else
{
maxYdis = mTl->mBounds.extent.y + textSpace;
scrollPoint.set(pointInGC.x, pointInGC.y - maxYdis -1);
}
}
//Scroll bar needed but Don't pop above button
else
{
mRevNum = 0;
//Calc for the width of the scroll bar
if(textWidth >= width)
width += 20;
mTl->setCellSize(Point2I(width,mFont->getHeight() + textSpace));
setScroll = true;
}
}
//No scroll bar needed
else
maxYdis = mTl->mBounds.extent.y + textSpace;
//offset it from the background so it lines up properly
mSc->mBounds.point = mBackground->globalToLocalCoord(scrollPoint);
if(mSc->mBounds.point.x + width > mBackground->mBounds.extent.x)
if(width - mBounds.extent.x > 0)
mSc->mBounds.point.x -= width - mBounds.extent.x;
mSc->mBounds.extent.set(width-1, maxYdis);
mSc->registerObject();
mTl->registerObject();
mBackground->registerObject();
mSc->addObject( mTl );
mBackground->addObject( mSc );
root->pushDialogControl(mBackground,canCtrl->mLayer);
if ( setScroll )
{
if ( mSelIndex )
mTl->scrollSelectionTop();
else
mTl->scrollCellVisible( Point2I( 0, 0 ) );
}
mTl->setFirstResponder();
mTl->mouseLock();
mInAction = true;
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::addChildren()
{
mTl = new GuiPopUpTextListCtrl(this);
AssertFatal(mTl, "Failed to create the GuiPopUpTextListCtrl for the PopUpMenu");
mTl->mProfile = mProfile;
mTl->setField("noDuplicates", "false");
mSc = new GuiScrollCtrl;
AssertFatal(mSc, "Failed to create the GuiScrollCtrl for the PopUpMenu");
mSc->mProfile = mProfile;
mSc->setField("hScrollBar","AlwaysOff");
mSc->setField("vScrollBar","dynamic");
mBackground = new GuiBackgroundCtrl;
AssertFatal(mBackground, "Failed to create the GuiBackgroundCtrl for the PopUpMenu");
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::repositionPopup()
{
if ( !mInAction || !mSc || !mTl )
return;
// I'm not concerned with this right now...
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::reverseTextList()
{
mTl->clear();
for(S32 i=mEntries.size()-1; i >= 0; --i)
mTl->addEntry(mEntries[i].id, mEntries[i].buf);
// Don't lose the selected cell:
if ( mSelIndex >= 0 )
mTl->setSelectedCell( Point2I( 0, mEntries.size() - mSelIndex - 1 ) );
mRevNum = mEntries.size() - 1;
}
//------------------------------------------------------------------------------
bool GuiPopUpMenuCtrl::getFontColor( ColorI &fontColor, S32 id, bool selected, bool mouseOver )
{
U32 i;
Entry* entry = NULL;
for ( i = 0; i < mEntries.size(); i++ )
{
if ( mEntries[i].id == id )
{
entry = &mEntries[i];
break;
}
}
if ( !entry )
return( false );
if ( entry->scheme != 0 )
{
// Find the entry's color scheme:
for ( i = 0; i < mSchemes.size(); i++ )
{
if ( mSchemes[i].id == entry->scheme )
{
fontColor = selected ? mSchemes[i].fontColorSEL : mouseOver ? mSchemes[i].fontColorHL : mSchemes[i].fontColor;
return( true );
}
}
}
// Default color scheme...
fontColor = selected ? mProfile->mFontColorSEL : mouseOver ? mProfile->mFontColorHL : mProfile->mFontColor;
return( true );
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::onMouseDown(const GuiEvent &event)
{
event;
onAction();
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::onMouseUp(const GuiEvent &event)
{
event;
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::setupAutoScroll(const GuiEvent &event)
{
GuiControl *parent = getParent();
if (! parent) return;
Point2I mousePt = mSc->globalToLocalCoord(event.mousePoint);
mEventSave = event;
if(mLastYvalue != mousePt.y)
{
mScrollDir = GuiScrollCtrl::None;
if(mousePt.y > mSc->mBounds.extent.y || mousePt.y < 0)
{
S32 topOrBottom = (mousePt.y > mSc->mBounds.extent.y) ? 1 : 0;
mSc->scrollTo(0, topOrBottom);
return;
}
F32 percent = (F32)mousePt.y / (F32)mSc->mBounds.extent.y;
if(percent > 0.7f && mousePt.y > mLastYvalue)
{
mIncValue = percent - 0.5f;
mScrollDir = GuiScrollCtrl::DownArrow;
}
else if(percent < 0.3f && mousePt.y < mLastYvalue)
{
mIncValue = 0.5f - percent;
mScrollDir = GuiScrollCtrl::UpArrow;
}
mLastYvalue = mousePt.y;
}
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::autoScroll()
{
mScrollCount += mIncValue;
while(mScrollCount > 1)
{
mSc->autoScroll(mScrollDir);
mScrollCount -= 1;
}
mTl->onMouseMove(mEventSave);
}
//------------------------------------------------------------------------------
void GuiPopUpMenuCtrl::replaceText(S32 boolVal)
{
mReplaceText = boolVal;
}
// EOF //

139
gui/guiPopUpCtrl.h Normal file
View file

@ -0,0 +1,139 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIPOPUPCTRL_H_
#define _GUIPOPUPCTRL_H_
#ifndef _GUITEXTCTRL_H_
#include "GUI/guiTextCtrl.h"
#endif
#ifndef _GUITEXTLISTCTRL_H_
#include "GUI/guiTextListCtrl.h"
#endif
#ifndef _GUIBUTTONCTRL_H_
#include "GUI/guiButtonCtrl.h"
#endif
#ifndef _GUIBACKGROUNDCTRL_H_
#include "GUI/guiBackgroundCtrl.h"
#endif
#ifndef _GUISCROLLCTRL_H_
#include "GUI/guiScrollCtrl.h"
#endif
class GuiPopUpMenuCtrl;
class GuiPopUpTextListCtrl : public GuiTextListCtrl
{
private:
typedef GuiTextListCtrl Parent;
public:
enum ButtonDown
{
None = 0,
AlreadyDown = 1,
ScrollArea = 2,
TextListArea = 3
};
protected:
GuiPopUpMenuCtrl *mPopUpCtrl;
ButtonDown mMouseDown;
public:
GuiPopUpTextListCtrl(); // for inheritance
GuiPopUpTextListCtrl(GuiPopUpMenuCtrl *ctrl);
~GuiPopUpTextListCtrl();
void onSleep();
// GuiArrayCtrl overload:
void onCellSelected(Point2I cell);
// GuiControl overloads:
void onMouseDown(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
bool onKeyDown(const GuiEvent &event);
void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
};
class GuiPopUpMenuCtrl : public GuiTextCtrl
{
typedef GuiTextCtrl Parent;
public:
struct Entry
{
char buf[256];
S32 id;
U16 ascii;
U16 scheme;
};
struct Scheme
{
U32 id;
ColorI fontColor;
ColorI fontColorHL;
ColorI fontColorSEL;
};
protected:
GuiPopUpTextListCtrl *mTl;
GuiScrollContentCtrl *mSContentc;
GuiScrollCtrl *mSc;
GuiBackgroundCtrl *mBackground;
Vector<Entry> mEntries;
Vector<Scheme> mSchemes;
S32 mSelIndex;
S32 mMaxPopupHeight;
F32 mIncValue;
F32 mScrollCount;
S32 mLastYvalue;
GuiEvent mEventSave;
S32 mRevNum;
bool mInAction;
bool mReplaceText;
virtual void addChildren();
virtual void repositionPopup();
public:
GuiPopUpMenuCtrl(void);
~GuiPopUpMenuCtrl();
GuiScrollCtrl::Region mScrollDir;
bool onAdd();
void onSleep();
static void consoleInit();
void sort();
void addEntry(const char *buf, S32 id, U32 scheme = 0);
void addScheme(U32 id, ColorI fontColor, ColorI fontColorHL, ColorI fontColorSEL);
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void onAction();
virtual void closePopUp();
void clear();
void onMouseDown(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
void setupAutoScroll(const GuiEvent &event);
void autoScroll();
bool onKeyDown(const GuiEvent &event);
void reverseTextList();
bool getFontColor(ColorI &fontColor, S32 id, bool selected, bool mouseOver);
S32 getSelected();
void setSelected(S32 id);
const char *getScriptValue();
const char *getTextById(S32 id);
S32 findText( const char* text );
S32 getNumEntries() { return( mEntries.size() ); }
void replaceText(S32);
DECLARE_CONOBJECT(GuiPopUpMenuCtrl);
static void initPersistFields(void);
};
#endif //_GUI_POPUPMENU_CTRL_H

84
gui/guiProgressCtrl.cc Normal file
View file

@ -0,0 +1,84 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "GUI/guiProgressCtrl.h"
GuiProgressCtrl::GuiProgressCtrl()
{
mProgress = 0.0f;
}
const char* GuiProgressCtrl::getScriptValue()
{
char * ret = Con::getReturnBuffer(64);
dSprintf(ret, 64, "%f", mProgress);
return ret;
}
void GuiProgressCtrl::setScriptValue(const char *value)
{
//set the value
if (! value)
mProgress = 0.0f;
else
mProgress = dAtof(value);
//validate the value
mProgress = mClampF(mProgress, 0.f, 1.f);
setUpdate();
}
void GuiProgressCtrl::onPreRender()
{
const char * var = getVariable();
if(var)
{
F32 value = mClampF(dAtof(var), 0.f, 1.f);
if(value != mProgress)
{
mProgress = value;
setUpdate();
}
}
}
void GuiProgressCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
RectI ctrlRect(offset, mBounds.extent);
//draw the progress
S32 width = (S32)((F32)mBounds.extent.x * mProgress);
if (width > 0)
{
RectI progressRect = ctrlRect;
progressRect.extent.x = width;
dglDrawRectFill(progressRect, mProfile->mFillColor);
}
//now draw the border
if (mProfile->mBorder)
{
dglDrawRect(ctrlRect, mProfile->mBorderColor);
RectI copyRect = ctrlRect;
copyRect.point.x += 1;
copyRect.point.y += 1;
copyRect.extent.x -= 2;
copyRect.extent.y -= 2;
ColorI color = mProfile->mBorderColor*0.75;
color.alpha = 255;
dglDrawRect(copyRect, color);
}
//render the children
renderChildControls(offset, updateRect, firstResponder);
}

35
gui/guiProgressCtrl.h Normal file
View file

@ -0,0 +1,35 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIPROGRESSCTRL_H_
#define _GUIPROGRESSCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
class GuiProgressCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
F32 mProgress;
public:
//creation methods
DECLARE_CONOBJECT(GuiProgressCtrl);
GuiProgressCtrl();
//console related methods
virtual const char *getScriptValue();
virtual void setScriptValue(const char *value);
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
};
#endif

228
gui/guiRadioCtrl.cc Normal file
View file

@ -0,0 +1,228 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "dgl/dgl.h"
#include "GUI/guiCanvas.h"
#include "GUI/guiRadioCtrl.h"
#include "console/consoleTypes.h"
//---------------------------------------------------------------------------
GuiRadioCtrl::GuiRadioCtrl()
{
mActive = true;
mBounds.extent.set(140, 30);
mKeyPressed = false;
mStateOn = false;
mGroupNum = -1;
}
//---------------------------------------------------------------------------
void GuiRadioCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("groupNum", TypeS32, Offset(mGroupNum, GuiRadioCtrl));
}
//---------------------------------------------------------------------------
void GuiRadioCtrl::consoleInit()
{
}
//---------------------------------------------------------------------------
void GuiRadioCtrl::AcceleratorKeyPress(void)
{
if (! mActive) return;
//set the bool
mKeyPressed = true;
if (mProfile->mTabable)
{
setFirstResponder();
}
}
//---------------------------------------------------------------------------
void GuiRadioCtrl::AcceleratorKeyRelease(void)
{
if (! mActive) return;
//set the bool
mKeyPressed = false;
//perform the action
onAction();
//update
setUpdate();
}
//---------------------------------------------------------------------------
bool GuiRadioCtrl::onKeyDown(const GuiEvent &event)
{
//if the control is a dead end, kill the event
if ((! mVisible) || (! mActive) || (! mAwake))
return true;
//see if the key down is a <return> or not
if (event.keyCode == KEY_RETURN && event.modifier == 0)
{
onAction();
return true;
}
//otherwise, pass the event to it's parent
return Parent::onKeyDown(event);
}
//---------------------------------------------------------------------------
void GuiRadioCtrl::drawBorder(const RectI &r, const ColorI &color)
{
Point2I p1, p2;
p1 = r.point;
p2 = r.point;
p2.x += r.extent.x - 1;
p2.y += r.extent.y - 1;
glColor4ub(color.red, color.green, color.blue, color.alpha);
glBegin(GL_LINE_LOOP);
glVertex2i(p1.x + 2, p1.y);
glVertex2i(p2.x - 2, p1.y);
glVertex2i(p2.x, p1.y + 2);
glVertex2i(p2.x, p2.y - 2);
glVertex2i(p2.x - 2, p2.y);
glVertex2i(p1.x + 2, p2.y);
glVertex2i(p1.x, p2.y - 2);
glVertex2i(p1.x, p1.y + 2);
glEnd();
}
//---------------------------------------------------------------------------
void GuiRadioCtrl::onAction()
{
mStateOn = true;
if (mGroupNum >= 0)
messageSiblings(mGroupNum);
setUpdate();
Parent::onAction();
}
//---------------------------------------------------------------------------
void GuiRadioCtrl::onMessage(GuiControl *sender, S32 msg)
{
Parent::onMessage(sender, msg);
if (mGroupNum == msg)
{
setUpdate();
mStateOn = (sender == this);
}
}
//---------------------------------------------------------------------------
void GuiRadioCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
bool stateOver = cursorInControl();
bool stateDepressed = mGroupNum >= 0 && mStateOn;
ColorI fontColor = (stateOver ? mProfile->mFontColorHL : mProfile->mFontColor);
ColorI backColor = mActive ? mProfile->mFillColor : mProfile->mFillColorNA;
ColorI insideBorderColor = (firstResponder == this) ? mProfile->mBorderColorHL : mProfile->mBorderColor;
ColorI outsideBorderColor = mProfile->mBorderColor;
S32 txt_w = mFont->getStrWidth(mText);
Point2I localStart;
// align the horizontal
switch (mProfile->mAlignment)
{
case GuiControlProfile::RightJustify:
localStart.x = mBounds.extent.x - txt_w;
break;
case GuiControlProfile::CenterJustify:
localStart.x = (mBounds.extent.x - txt_w) / 2;
break;
default:
// GuiControlProfile::LeftJustify
localStart.x = 0;
break;
}
// center the vertical
localStart.y = (mBounds.extent.y - (mFont->getHeight() - 2)) / 2;
// first draw the background
RectI r(offset, mBounds.extent);
dglDrawRectFill(r, backColor);
r.point.x +=2;
r.point.y +=2;
r.extent.x -=4;
r.extent.y -=4;
dglDrawRectFill(r, backColor);
//draw the radio box
glColor3f(0.4f,0.4f,0.4f);
glBegin(GL_LINE_LOOP);
glVertex2i(r.point.x+3, r.point.y+3);
glVertex2i(r.point.x+12, r.point.y+3);
glVertex2i(r.point.x+12, r.point.y+12);
glVertex2i(r.point.x+3, r.point.y+12);
glEnd();
if (stateDepressed)
{
glColor3f(0.0f,0.0f,0.0f);
glBegin(GL_QUADS);
glVertex2i(r.point.x+6, r.point.y+6);
glVertex2i(r.point.x+10, r.point.y+6);
glVertex2i(r.point.x+10, r.point.y+10);
glVertex2i(r.point.x+6, r.point.y+10);
glEnd();
}
// draw the oustside border
r.point.x -=1;
r.point.y -=1;
r.extent.x +=2;
r.extent.y +=2;
drawBorder(r, outsideBorderColor);
// finally draw the text
localStart.y -= 2;
localStart.x += 4;
if (stateDepressed)
{
localStart.x += 1;
localStart.y += 1;
}
Point2I globalStart = localToGlobalCoord(localStart);
dglSetBitmapModulation(fontColor);
dglDrawText(mFont, globalStart, mText, mProfile->mFontColors);
//render the children
renderChildControls(offset, updateRect, firstResponder);
}
//---------------------------------------------------------------------------
void GuiRadioCtrl::setScriptValue(const char *newState)
{
if(dAtob(newState))
onAction();
else
mStateOn = false;
setUpdate();
}
//---------------------------------------------------------------------------
const char *GuiRadioCtrl::getScriptValue()
{
return mStateOn ? "1" : "0";
}
// EOF //

47
gui/guiRadioCtrl.h Normal file
View file

@ -0,0 +1,47 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIRADIOCTRL_H_
#define _GUIRADIOCTRL_H_
#ifndef _GUITEXTCTRL_H_
#include "GUI/guiTextCtrl.h"
#endif
class GuiRadioCtrl : public GuiTextCtrl
{
private:
typedef GuiTextCtrl Parent;
protected:
bool mKeyPressed;
bool mStateOn;
S32 mGroupNum;
public:
DECLARE_CONOBJECT(GuiRadioCtrl);
GuiRadioCtrl();
static void consoleInit();
static void initPersistFields();
void AcceleratorKeyPress(void);
void AcceleratorKeyRelease(void);
bool onKeyDown(const GuiEvent &event);
// GuiTextCtrl updates mText with the variable value, which is not desired
void onPreRender() {}
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
void drawBorder(const RectI &r, const ColorI &color);
void onAction();
void onMessage(GuiControl *,S32 msg);
void setScriptValue(const char *);
const char *getScriptValue();
};
#endif //_GUI_RADIO_CTRL_H

956
gui/guiScrollCtrl.cc Normal file
View file

@ -0,0 +1,956 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/gBitmap.h"
#include "dgl/gTexManager.h"
#include "Core/resManager.h"
#include "Platform/event.h"
#include "dgl/dgl.h"
#include "GUI/guiArrayCtrl.h"
#include "GUI/guiScrollCtrl.h"
void GuiScrollContentCtrl::childResized(GuiControl *child)
{
GuiControl *parent = getParent();
if (parent)
{
((GuiScrollCtrl *)parent)->computeSizes();
}
Parent::childResized(child);
}
void GuiScrollContentCtrl::removeObject(SimObject *object)
{
Parent::removeObject(object);
GuiScrollCtrl *sctrl = NULL;
GuiControl *parent = getParent();
if (parent)
{
sctrl = dynamic_cast<GuiScrollCtrl *>(parent);
}
if (sctrl)
{
sctrl->computeSizes();
}
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
GuiScrollCtrl::GuiScrollCtrl()
{
mBounds.extent.set(200,200);
mChildMargin.set(0,0);
mBorderThickness = 1;
mScrollBarThickness = 16;
mScrollBarArrowBtnLength = 16;
stateDepressed = false;
curHitRegion = None;
mBitmapBounds = NULL;
mLine_V = 0.1f;
mLine_H = 0.1f;
mPage_V = 0.2f;
mPage_H = 0.2f;
mWillFirstRespond = true;
mThumbAnchorPos = 0.0f;
mUseConstantHeightThumb = false;
mForceVScrollBar = ScrollBarAlwaysOn;
mForceHScrollBar = ScrollBarAlwaysOn;
mVBarThumbPos = 0;
mHBarThumbPos = 0;
mDefaultLineHeight = 15;
mContentCtrl = NULL;
}
GuiScrollCtrl::~GuiScrollCtrl()
{
if ( mBitmapBounds != NULL )
{
delete [] mBitmapBounds;
mBitmapBounds = NULL;
}
}
static EnumTable::Enums scrollBarEnums[] =
{
{ GuiScrollCtrl::ScrollBarAlwaysOn, "alwaysOn" },
{ GuiScrollCtrl::ScrollBarAlwaysOff, "alwaysOff" },
{ GuiScrollCtrl::ScrollBarDynamic, "dynamic" },
};
static EnumTable gScrollBarTable(3, &scrollBarEnums[0]);
static void cGuiScrollCtrlScrollToTop( SimObject* obj, S32, const char** )
{
AssertFatal( dynamic_cast<GuiScrollCtrl*>( obj ), "Control passed to cGuiScrollCtrlScrollToTop is not a GuiScrollCtrl!" );
GuiScrollCtrl* control = static_cast<GuiScrollCtrl*>( obj );
control->scrollTo( 0, 0 );
}
static void cGuiScrollCtrlScrollToBottom( SimObject* obj, S32, const char** )
{
AssertFatal( dynamic_cast<GuiScrollCtrl*>( obj ), "Control passed to cGuiScrollCtrlScrollToBottom is not a GuiScrollCtrl!" );
GuiScrollCtrl* control = static_cast<GuiScrollCtrl*>( obj );
control->scrollTo( 0, 1 );
}
void GuiScrollCtrl::consoleInit()
{
Con::addCommand( "GuiScrollCtrl", "scrollToTop", cGuiScrollCtrlScrollToTop, "control.scrollToTop();", 2, 2 );
Con::addCommand( "GuiScrollCtrl", "scrollToBottom", cGuiScrollCtrlScrollToBottom, "control.scrollToBottom();", 2, 2 );
}
void GuiScrollCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("willFirstRespond", TypeBool, Offset(mWillFirstRespond, GuiScrollCtrl));
addField("hScrollBar", TypeEnum, Offset(mForceHScrollBar, GuiScrollCtrl), 1, &gScrollBarTable);
addField("vScrollBar", TypeEnum, Offset(mForceVScrollBar, GuiScrollCtrl), 1, &gScrollBarTable);
addField("constantThumbHeight", TypeBool, Offset(mUseConstantHeightThumb, GuiScrollCtrl));
addField("defaultLineHeight", TypeS32, Offset(mDefaultLineHeight, GuiScrollCtrl));
addField("childMargin", TypePoint2I, Offset(mChildMargin, GuiScrollCtrl));
}
void GuiScrollCtrl::resize(const Point2I &newPos, const Point2I &newExt)
{
Parent::resize(newPos, newExt);
computeSizes();
}
bool GuiScrollCtrl::onAdd()
{
if(!Parent::onAdd())
return false;
GuiScrollContentCtrl *content = new GuiScrollContentCtrl;
if (!content->registerObject())
Con::errorf(ConsoleLogEntry::General, "Unhandled execption, could not add content in GuiScrollCtrl::onAdd()");
addObject(content);
return true;
}
bool GuiScrollCtrl::onWake()
{
if (! Parent::onWake())
return false;
AssertFatal(size(), "Scroll control created with no content control.");
mTextureHandle = mProfile->mTextureHandle;
mBitmapBounds = new RectI[BmpStates * BmpCount];
AssertFatal( mBitmapBounds, "Failed to allocate memory for bitmap array!" );
bool result = createBitmapArray(mTextureHandle.getBitmap(), mBitmapBounds, BmpStates, BmpCount);
AssertFatal(result, "Failed to create the bitmap array");
for(S32 i = 0; i < BmpStates; i++)
{
mBitmapBounds[BmpStates * BmpVThumb + i].inset(0, 1);
mBitmapBounds[BmpStates * BmpVPage + i].inset(0, 1);
mBitmapBounds[BmpStates * BmpHThumb + i].inset(1, 0);
mBitmapBounds[BmpStates * BmpHPage + i].inset(1, 0);
}
//init
mBaseThumbSize = mBitmapBounds[BmpStates * BmpVThumbTopCap].extent.y +
mBitmapBounds[BmpStates * BmpVThumbBottomCap].extent.y;
mScrollBarThickness = mBitmapBounds[BmpStates * BmpVPage].extent.x;
mScrollBarArrowBtnLength = mBitmapBounds[BmpStates * BmpUp].extent.y;
computeSizes();
return true;
}
void GuiScrollCtrl::onSleep()
{
Parent::onSleep();
if ( mBitmapBounds )
{
delete [] mBitmapBounds;
mBitmapBounds = NULL;
}
mTextureHandle = NULL;
}
bool GuiScrollCtrl::calcChildExtents(Point2I *pos, Point2I *ext)
{
// loop through the children of this scroll view...
if (! mContentCtrl->size())
return false;
#if 1
GuiControl *ctrl = (GuiControl *) (mContentCtrl->front());
*ext = ctrl->mBounds.extent;
*pos = ctrl->mBounds.point;
return true;
#else
bool anyVisible = false;
SimGroup::iterator i;
for(i = mContentCtrl->begin(); i != mContentCtrl->end();i++)
{
GuiControl *ctrl = (GuiControl *) (*i);
if (ctrl->isVisible())
{
anyVisible = true;
pos->x = getMin(pos->x, ctrl->mBounds.point.x);
pos->y = getMin(pos->y, ctrl->mBounds.point.y);
if (ctrl->mBounds.point.x + ctrl->mBounds.extent.x > pos->x + ext->x)
ext->x = ctrl->mBounds.point.x + ctrl->mBounds.extent.x - pos->x;
if (ctrl->mBounds.point.y + ctrl->mBounds.extent.y > pos->y + ext->y)
ext->y = ctrl->mBounds.point.y + ctrl->mBounds.extent.y - pos->y;
}
}
return anyVisible;
#endif
}
void GuiScrollCtrl::addObject(SimObject *object)
{
GuiScrollContentCtrl *content = dynamic_cast<GuiScrollContentCtrl *>(object);
if(content)
{
if(mContentCtrl)
mContentCtrl->deleteObject();
Parent::addObject(object);
mContentCtrl = content;
computeSizes();
return;
}
AssertFatal(mContentCtrl, "ERROR - no content control for a scroll control");
mContentCtrl->addObject(object);
computeSizes();
}
void GuiScrollCtrl::computeSizes()
{
Point2I pos(mBorderThickness, mBorderThickness);
Point2I ext(mBounds.extent.x - (mBorderThickness << 1), mBounds.extent.y - (mBorderThickness << 1));
Point2I cpos;
Point2I cext;
mHBarEnabled = false;
mVBarEnabled = false;
mHasVScrollBar = (mForceVScrollBar == ScrollBarAlwaysOn);
mHasHScrollBar = (mForceHScrollBar == ScrollBarAlwaysOn);
setUpdate();
if (calcChildExtents(&cpos, &cext))
{
if (mHasVScrollBar)
ext.x -= mScrollBarThickness;
if (mHasHScrollBar)
{
ext.y -= mScrollBarThickness;
}
if (cext.x > ext.x && (mForceHScrollBar == ScrollBarDynamic))
{
mHasHScrollBar = true;
ext.y -= mScrollBarThickness;
}
if (cext.y > ext.y && (mForceVScrollBar == ScrollBarDynamic))
{
mHasVScrollBar = true;
ext.x -= mScrollBarThickness;
// doh! ext.x changed, so check hscrollbar again
if (cext.x > ext.x && !mHasHScrollBar && (mForceHScrollBar == ScrollBarDynamic))
{
mHasHScrollBar = true;
ext.y -= mScrollBarThickness;
}
}
mContentCtrl->mBounds.point = pos + mChildMargin;
mContentCtrl->mBounds.extent = (ext - mChildMargin) - mChildMargin;
ext = mContentCtrl->mBounds.extent;
// see if the child controls need to be repositioned (null space in control)
Point2I delta(0,0);
if (cpos.x > 0)
delta.x = -cpos.x;
else if (ext.x > cpos.x + cext.x)
{
S32 diff = ext.x - (cpos.x + cext.x);
delta.x = getMin(-cpos.x, diff);
}
//reposition the children if the child extent > the scroll content extent
if (cpos.y > 0)
delta.y = -cpos.y;
else if (ext.y > cpos.y + cext.y)
{
S32 diff = ext.y - (cpos.y + cext.y);
delta.y = getMin(-cpos.y, diff);
}
// apply the deltas to the children...
if (delta.x || delta.y)
{
SimGroup::iterator i;
for(i = mContentCtrl->begin(); i != mContentCtrl->end();i++)
{
GuiControl *ctrl = (GuiControl *) (*i);
ctrl->mBounds.point += delta;
}
cpos += delta;
}
if (cext.x < ext.x)
cext.x = ext.x;
if (cext.y < ext.y)
cext.y = ext.y;
// enable needed scroll bars
if (cext.x > ext.x)
mHBarEnabled = true;
if (cext.y > ext.y)
mVBarEnabled = true;
}
// build all the rectangles and such...
calcScrollRects();
mLine_V = 0.1f;
mLine_H = 0.1f;
mPage_V = 0.2f;
mPage_H = 0.2f;
/*
SimGroup::iterator i;
i = mContentCtrl->begin();
if (i != mContentCtrl->end())
{
GuiControl *ctrl = (GuiControl *) (*i);
RectI clientR(0,0,mContentCtrl->mBounds.extent.x, mContentCtrl->mBounds.extent.y);
if (ctrl->mBounds.extent.y)
{
mLine_V = ctrl->scroll_mLine_V(clientR) / (F32)ctrl->mBounds.extent.y;
mPage_V = ctrl->scroll_mPage_V(clientR) / (F32)ctrl->mBounds.extent.y;
}
if (ctrl->mBounds.extent.x)
{
mLine_H = ctrl->scroll_mLine_H(clientR) / (F32)ctrl->mBounds.extent.x;
mPage_H = ctrl->scroll_mPage_H(clientR) / (F32)ctrl->mBounds.extent.x;
}
}
*/
calcThumbs(cpos, cext);
}
void GuiScrollCtrl::calcScrollRects(void)
{
if (mHasHScrollBar)
{
mLeftArrowRect.set(mBorderThickness,
mBounds.extent.y - mBorderThickness - mScrollBarThickness - 1,
mScrollBarArrowBtnLength,
mScrollBarThickness);
mRightArrowRect.set(mBounds.extent.x - mBorderThickness - (mHasVScrollBar ? mScrollBarThickness : 0) - mScrollBarArrowBtnLength,
mBounds.extent.y - mBorderThickness - mScrollBarThickness - 1,
mScrollBarArrowBtnLength,
mScrollBarThickness);
mHTrackRect.set(mLeftArrowRect.point.x + mLeftArrowRect.extent.x,
mLeftArrowRect.point.y,
mRightArrowRect.point.x - (mLeftArrowRect.point.x + mLeftArrowRect.extent.x),
mScrollBarThickness);
}
if (mHasVScrollBar)
{
mUpArrowRect.set(mBounds.extent.x - mBorderThickness - mScrollBarThickness,
mBorderThickness,
mScrollBarThickness,
mScrollBarArrowBtnLength);
mDownArrowRect.set(mBounds.extent.x - mBorderThickness - mScrollBarThickness,
mBounds.extent.y - mBorderThickness - mScrollBarArrowBtnLength - (mHasHScrollBar ? ( mScrollBarThickness + 1 ) : 0),
mScrollBarThickness,
mScrollBarArrowBtnLength);
mVTrackRect.set(mUpArrowRect.point.x,
mUpArrowRect.point.y + mUpArrowRect.extent.y,
mScrollBarThickness,
mDownArrowRect.point.y - (mUpArrowRect.point.y + mUpArrowRect.extent.y) );
}
}
void GuiScrollCtrl::calcThumbs(Point2I cpos, Point2I cext)
{
Point2I ext = mContentCtrl->mBounds.extent;
if (mHBarEnabled)
{
mHBarThumbPos = -cpos.x / F32(cext.x - ext.x);
mHBarThumbWidth = ext.x / F32(cext.x);
if (mUseConstantHeightThumb)
mHThumbSize = mBaseThumbSize;
else
mHThumbSize = getMax(mBaseThumbSize, S32(mHBarThumbWidth * mHTrackRect.len_x()));
mHThumbPos = (S32)(mHTrackRect.point.x + mHBarThumbPos * (mHTrackRect.len_x() - mHThumbSize));
}
if (mVBarEnabled)
{
mVBarThumbPos = -cpos.y / F32(cext.y - ext.y);
mVBarThumbWidth = ext.y / F32(cext.y);
if (mUseConstantHeightThumb)
mVThumbSize = mBaseThumbSize;
else
mVThumbSize = getMax(mBaseThumbSize, S32(mVBarThumbWidth * mVTrackRect.len_y()));
mVThumbPos = (S32)(mVTrackRect.point.y + mVBarThumbPos * (mVTrackRect.len_y() - mVThumbSize));
}
}
void GuiScrollCtrl::scrollTo(F32 x, F32 y)
{
setUpdate();
if (x < 0)
x = 0;
else if (x > 1)
x = 1;
if (y < 0)
y = 0;
else if (y > 1)
y = 1;
if (x == mHBarThumbPos && y == mVBarThumbPos)
return;
Point2I cpos, cext;
if (calcChildExtents(&cpos, &cext))
{
Point2I ext = mContentCtrl->mBounds.extent;
Point2I npos;
if (ext.x < cext.x)
npos.x = (S32)(-x * (cext.x - ext.x));
else
npos.x = 0;
if (ext.y < cext.y)
npos.y = (S32)(-y * (cext.y - ext.y));
else
npos.y = 0;
Point2I delta(npos.x - cpos.x, npos.y - cpos.y);
// get rid of bad (roundoff) deltas
if (x == mHBarThumbPos)
delta.x = 0;
if (y == mVBarThumbPos)
delta.y = 0;
SimGroup::iterator i;
for(i = mContentCtrl->begin(); i != mContentCtrl->end();i++)
{
GuiControl *ctrl = (GuiControl *) (*i);
ctrl->mBounds.point += delta;
}
cpos += delta;
calcThumbs(cpos, cext);
}
}
GuiScrollCtrl::Region GuiScrollCtrl::findHitRegion(const Point2I &pt)
{
if (mVBarEnabled && mHasVScrollBar)
{
if (mUpArrowRect.pointInRect(pt))
return UpArrow;
else if (mDownArrowRect.pointInRect(pt))
return DownArrow;
else if (mVTrackRect.pointInRect(pt))
{
if (pt.y < mVThumbPos)
return UpPage;
else if (pt.y < mVThumbPos + mVThumbSize)
return VertThumb;
else
return DownPage;
}
}
if (mHBarEnabled && mHasHScrollBar)
{
if (mLeftArrowRect.pointInRect(pt))
return LeftArrow;
else if (mRightArrowRect.pointInRect(pt))
return RightArrow;
else if (mHTrackRect.pointInRect(pt))
{
if (pt.x < mHThumbPos)
return LeftPage;
else if (pt.x < mHThumbPos + mHThumbSize)
return HorizThumb;
else
return RightPage;
}
}
return None;
}
bool GuiScrollCtrl::wantsTabListMembership()
{
return true;
}
bool GuiScrollCtrl::loseFirstResponder()
{
setUpdate();
return true;
}
bool GuiScrollCtrl::becomeFirstResponder()
{
setUpdate();
return mWillFirstRespond;
}
bool GuiScrollCtrl::onKeyDown(const GuiEvent &event)
{
if (mWillFirstRespond)
{
switch (event.keyCode)
{
case KEY_RIGHT:
scrollByRegion(RightArrow);
return true;
case KEY_LEFT:
scrollByRegion(LeftArrow);
return true;
case KEY_DOWN:
scrollByRegion(DownArrow);
return true;
case KEY_UP:
scrollByRegion(UpArrow);
return true;
case KEY_PAGE_UP:
scrollByRegion(UpPage);
return true;
case KEY_PAGE_DOWN:
scrollByRegion(DownPage);
return true;
}
}
return Parent::onKeyDown(event);
}
void GuiScrollCtrl::onMouseDown(const GuiEvent &event)
{
mouseLock();
setFirstResponder();
setUpdate();
Point2I curMousePos = globalToLocalCoord(event.mousePoint);
curHitRegion = findHitRegion(curMousePos);
stateDepressed = true;
scrollByRegion(curHitRegion);
if (curHitRegion == VertThumb)
{
mThumbAnchorPos = mVBarThumbPos;
mThumbDelta = curMousePos.y - mVThumbPos;
}
else if (curHitRegion == HorizThumb)
{
mThumbAnchorPos = mHBarThumbPos;
mThumbDelta = curMousePos.x - mHThumbPos;
}
}
void GuiScrollCtrl::onMouseUp(const GuiEvent &)
{
mouseUnlock();
setUpdate();
curHitRegion = None;
stateDepressed = false;
}
void GuiScrollCtrl::onMouseDragged(const GuiEvent &event)
{
Point2I curMousePos = globalToLocalCoord(event.mousePoint);
setUpdate();
if ( (curHitRegion != VertThumb) && (curHitRegion != HorizThumb) )
{
Region hit = findHitRegion(curMousePos);
if (hit != curHitRegion)
stateDepressed = false;
else
stateDepressed = true;
return;
}
// ok... if the mouse is 'near' the scroll bar, scroll with it
// otherwise, snap back to the previous position.
if (curHitRegion == VertThumb)
{
if (curMousePos.x >= mVTrackRect.point.x - mScrollBarThickness &&
curMousePos.x <= mVTrackRect.point.x + mVTrackRect.extent.x - 1 + mScrollBarThickness &&
curMousePos.y >= mVTrackRect.point.y - mScrollBarThickness &&
curMousePos.y <= mVTrackRect.point.y + mVTrackRect.extent.y - 1 + mScrollBarThickness)
{
scrollTo(mHBarThumbPos,
(curMousePos.y - mThumbDelta - mVTrackRect.point.y) /
F32(mVTrackRect.len_y() - mVThumbSize));
}
else
scrollTo(mHBarThumbPos, mThumbAnchorPos);
}
else if (curHitRegion == HorizThumb)
{
if (curMousePos.x >= mHTrackRect.point.x - mScrollBarThickness &&
curMousePos.x <= mHTrackRect.point.x + mHTrackRect.extent.x - 1 + mScrollBarThickness &&
curMousePos.y >= mHTrackRect.point.y - mScrollBarThickness &&
curMousePos.y <= mHTrackRect.point.y + mHTrackRect.extent.y - 1 + mScrollBarThickness)
{
scrollTo((curMousePos.x - mThumbDelta - mHTrackRect.point.x) /
F32(mHTrackRect.len_x() - mHThumbSize),
mVBarThumbPos);
}
else
scrollTo(mThumbAnchorPos, mVBarThumbPos);
}
}
bool GuiScrollCtrl::onMouseWheelUp(const GuiEvent &event)
{
if ( !mAwake || !mVisible )
return( false );
scrollByRegion((event.modifier & SI_CTRL) ? UpPage : UpArrow);
// Tell the kids that the mouse moved (relatively):
iterator itr;
for ( itr = mContentCtrl->begin(); itr != mContentCtrl->end(); itr++ )
{
GuiControl* grandKid = static_cast<GuiControl*>( *itr );
grandKid->onMouseMove( event );
}
return( true );
}
bool GuiScrollCtrl::onMouseWheelDown(const GuiEvent &event)
{
if ( !mAwake || !mVisible )
return( false );
scrollByRegion((event.modifier & SI_CTRL) ? DownPage : DownArrow);
// Tell the kids that the mouse moved (relatively):
iterator itr;
for ( itr = mContentCtrl->begin(); itr != mContentCtrl->end(); itr++ )
{
GuiControl* grandKid = static_cast<GuiControl *>( *itr );
grandKid->onMouseMove( event );
}
return( true );
}
void GuiScrollCtrl::scrollByRegion(Region reg)
{
setUpdate();
if (mVBarEnabled)
{
bool alreadyScrolled = false;
GuiControl* grandKid = NULL;
GuiArrayCtrl *ac = NULL;
if (mContentCtrl->begin())
{
grandKid = (GuiControl *)(mContentCtrl->front());
ac = dynamic_cast<GuiArrayCtrl*>(grandKid);
}
if ( ac || ( grandKid && mDefaultLineHeight > 0 ) )
{
S32 lineHeight, numCells;
if ( ac )
ac->getScrollDimensions(lineHeight, numCells);
else
{
lineHeight = mDefaultLineHeight;
numCells = 47; // OK, we're just fakin'...
}
if (lineHeight > 0 && numCells > 0)
{
S32 pageHeight = S32(mContentCtrl->mBounds.extent.y / lineHeight) * (lineHeight - 1) - 1;
switch(reg)
{
case UpPage:
grandKid->mBounds.point.y = getMin(0, getMax(mContentCtrl->mBounds.extent.y - grandKid->mBounds.extent.y, grandKid->mBounds.point.y + pageHeight));
break;
case DownPage:
grandKid->mBounds.point.y = getMin(0, getMax(mContentCtrl->mBounds.extent.y - grandKid->mBounds.extent.y, grandKid->mBounds.point.y - pageHeight));
break;
case UpArrow:
grandKid->mBounds.point.y = getMin(0, getMax(mContentCtrl->mBounds.extent.y - grandKid->mBounds.extent.y, grandKid->mBounds.point.y + lineHeight));
break;
case DownArrow:
grandKid->mBounds.point.y = getMin(0, getMax(mContentCtrl->mBounds.extent.y - grandKid->mBounds.extent.y, grandKid->mBounds.point.y - lineHeight));
break;
}
calcThumbs(grandKid->mBounds.point, grandKid->mBounds.extent);
alreadyScrolled = true;
}
}
if (! alreadyScrolled)
{
// If all else fails, scroll by percentage:
mPage_V = 0.1f;
mLine_V = 0.1f;
switch(reg)
{
case UpPage:
scrollTo(mHBarThumbPos, mVBarThumbPos - mPage_V);
break;
case DownPage:
scrollTo(mHBarThumbPos, mVBarThumbPos + mPage_V);
break;
case UpArrow:
scrollTo(mHBarThumbPos, mVBarThumbPos - mLine_V);
break;
case DownArrow:
scrollTo(mHBarThumbPos, mVBarThumbPos + mLine_V);
break;
}
}
}
if (mHBarEnabled)
{
switch(reg)
{
case LeftPage:
scrollTo(mHBarThumbPos - mPage_H, mVBarThumbPos);
break;
case RightPage:
scrollTo(mHBarThumbPos + mPage_H, mVBarThumbPos);
break;
case LeftArrow:
scrollTo(mHBarThumbPos - mLine_H, mVBarThumbPos);
break;
case RightArrow:
scrollTo(mHBarThumbPos + mLine_H, mVBarThumbPos);
break;
}
}
}
void GuiScrollCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
// draw border
drawBorder( offset, ( firstResponder == this ) );
// draw scroll bars
if (mHasVScrollBar)
drawVScrollBar(offset);
if (mHasHScrollBar)
drawHScrollBar(offset);
//draw the scroll corner
if (mHasVScrollBar && mHasHScrollBar)
drawScrollCorner(offset);
// draw content and its children
renderChildControls(offset, updateRect, firstResponder);
}
void GuiScrollCtrl::drawBorder( const Point2I &offset, bool /*isFirstResponder*/ )
{
RectI r(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
if (mProfile->mOpaque)
dglDrawRectFill(r, mProfile->mFillColor);
if (mProfile->mBorder)
dglDrawRect(r, mProfile->mBorderColor);
}
void GuiScrollCtrl::drawVScrollBar(const Point2I &offset)
{
Point2I pos = offset + mUpArrowRect.point;
S32 bitmap = (mVBarEnabled ? ((curHitRegion == UpArrow && stateDepressed) ?
BmpStates * BmpUp + BmpHilite : BmpStates * BmpUp) : BmpStates * BmpUp + BmpDisabled);
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[bitmap]);
pos.y += mScrollBarArrowBtnLength;
S32 end;
if (mVBarEnabled)
end = mVThumbPos + offset.y;
else
end = mDownArrowRect.point.y + offset.y;
bitmap = (mVBarEnabled ? ((curHitRegion == DownPage && stateDepressed) ?
BmpStates * BmpVPage + BmpHilite : BmpStates * BmpVPage) : BmpStates * BmpVPage + BmpDisabled);
if (end > pos.y)
{
dglClearBitmapModulation();
dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(mBitmapBounds[bitmap].extent.x, end - pos.y)), mBitmapBounds[bitmap]);
}
pos.y = end;
if (mVBarEnabled)
{
bool thumbSelected = (curHitRegion == VertThumb && stateDepressed);
S32 ttop = (thumbSelected ? BmpStates * BmpVThumbTopCap + BmpHilite : BmpStates * BmpVThumbTopCap);
S32 tmid = (thumbSelected ? BmpStates * BmpVThumb + BmpHilite : BmpStates * BmpVThumb);
S32 tbot = (thumbSelected ? BmpStates * BmpVThumbBottomCap + BmpHilite : BmpStates * BmpVThumbBottomCap);
// draw the thumb
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[ttop]);
pos.y += mBitmapBounds[ttop].extent.y;
end = mVThumbPos + mVThumbSize - mBitmapBounds[tbot].extent.y + offset.y;
if (end > pos.y)
{
dglClearBitmapModulation();
dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(mBitmapBounds[tmid].extent.x, end - pos.y)), mBitmapBounds[tmid]);
}
pos.y = end;
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[tbot]);
pos.y += mBitmapBounds[tbot].extent.y;
end = mVTrackRect.point.y + mVTrackRect.extent.y - 1 + offset.y;
bitmap = (curHitRegion == DownPage && stateDepressed) ? BmpStates * BmpVPage + BmpHilite : BmpStates * BmpVPage;
if (end > pos.y)
{
dglClearBitmapModulation();
dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(mBitmapBounds[bitmap].extent.x, end - pos.y)), mBitmapBounds[bitmap]);
}
pos.y = end;
}
bitmap = (mVBarEnabled ? ((curHitRegion == DownArrow && stateDepressed ) ?
BmpStates * BmpDown + BmpHilite : BmpStates * BmpDown) : BmpStates * BmpDown + BmpDisabled);
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[bitmap]);
}
void GuiScrollCtrl::drawHScrollBar(const Point2I &offset)
{
S32 bitmap;
//draw the left arrow
bitmap = (mHBarEnabled ? ((curHitRegion == LeftArrow && stateDepressed) ?
BmpStates * BmpLeft + BmpHilite : BmpStates * BmpLeft) : BmpStates * BmpLeft + BmpDisabled);
Point2I pos = offset;
pos += mLeftArrowRect.point;
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[bitmap]);
pos.x += mLeftArrowRect.extent.x;
//draw the left page
S32 end;
if (mHBarEnabled)
end = mHThumbPos + offset.x;
else
end = mRightArrowRect.point.x + offset.x;
bitmap = (mHBarEnabled ? ((curHitRegion == LeftPage && stateDepressed) ?
BmpStates * BmpHPage + BmpHilite : BmpStates * BmpHPage) : BmpStates * BmpHPage + BmpDisabled);
if (end > pos.x)
{
dglClearBitmapModulation();
dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(end - pos.x, mBitmapBounds[bitmap].extent.y)), mBitmapBounds[bitmap]);
}
pos.x = end;
//draw the thumb and the rightPage
if (mHBarEnabled)
{
bool thumbSelected = (curHitRegion == HorizThumb && stateDepressed);
S32 ttop = (thumbSelected ? BmpStates * BmpHThumbLeftCap + BmpHilite : BmpStates * BmpHThumbLeftCap );
S32 tmid = (thumbSelected ? BmpStates * BmpHThumb + BmpHilite : BmpStates * BmpHThumb);
S32 tbot = (thumbSelected ? BmpStates * BmpHThumbRightCap + BmpHilite : BmpStates * BmpHThumbRightCap);
// draw the thumb
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[ttop]);
pos.x += mBitmapBounds[ttop].extent.x;
end = mHThumbPos + mHThumbSize - mBitmapBounds[tbot].extent.x + offset.x;
if (end > pos.x)
{
dglClearBitmapModulation();
dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(end - pos.x, mBitmapBounds[tmid].extent.y)), mBitmapBounds[tmid]);
}
pos.x = end;
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[tbot]);
pos.x += mBitmapBounds[tbot].extent.x;
end = mHTrackRect.point.x + mHTrackRect.extent.x - 1 + offset.x;
bitmap = ((curHitRegion == RightPage && stateDepressed) ? BmpStates * BmpHPage + BmpHilite : BmpStates * BmpHPage);
if (end > pos.x)
{
dglClearBitmapModulation();
dglDrawBitmapStretchSR(mTextureHandle, RectI(pos, Point2I(end - pos.x, mBitmapBounds[bitmap].extent.y)), mBitmapBounds[bitmap]);
}
pos.x = end;
}
bitmap = (mHBarEnabled ? ((curHitRegion == RightArrow && stateDepressed) ?
BmpStates * BmpRight + BmpHilite : BmpStates * BmpRight) : BmpStates * BmpRight + BmpDisabled);
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[bitmap]);
}
void GuiScrollCtrl::drawScrollCorner(const Point2I &offset)
{
Point2I pos = offset;
pos.x += mRightArrowRect.point.x + mRightArrowRect.extent.x;
pos.y += mRightArrowRect.point.y;
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, pos, mBitmapBounds[BmpStates * BmpResize]);
}
void GuiScrollCtrl::autoScroll(Region reg)
{
scrollByRegion(reg);
}

238
gui/guiScrollCtrl.h Normal file
View file

@ -0,0 +1,238 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUISCROLLCTRL_H_
#define _GUISCROLLCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
// the function of the scroll content control class
// is to notify the parent class that children have resized.
// basically it just calls it's parent (enclosing) control's
// childResized method which turns around and computes new sizes
// for the scroll bars
class GuiScrollContentCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
void childResized(GuiControl *child);
void removeObject(SimObject *object);
public:
DECLARE_CONOBJECT(GuiScrollContentCtrl);
};
class GuiScrollCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
// the scroll control uses a bitmap array to draw all its
// stuff... these are the bitmaps it needs:
enum BitmapIndices
{
BmpUp,
BmpDown,
BmpVThumbTopCap,
BmpVThumb,
BmpVThumbBottomCap,
BmpVPage,
BmpLeft,
BmpRight,
BmpHThumbLeftCap,
BmpHThumb,
BmpHThumbRightCap,
BmpHPage,
BmpResize,
BmpCount
};
enum BitmapStates
{
BmpDefault = 0,
BmpHilite,
BmpDisabled,
BmpStates
};
RectI* mBitmapBounds; //bmp is [3*n], bmpHL is [3*n + 1], bmpNA is [3*n + 2]
TextureHandle mTextureHandle;
GuiScrollContentCtrl *mContentCtrl; // always have a pointer to the content control
S32 mBorderThickness; // this gets set per class in the constructor
Point2I mChildMargin; // the thickeness of the margin around the child controls
// note - it is implicit in the scroll view that the buttons all have the same
// arrow length and that horizontal and vertical scroll bars have the
// same thickness
S32 mScrollBarThickness; // determined by the width of the vertical page bmp
S32 mScrollBarArrowBtnLength; // determined by the height of the up arrow
bool mHBarEnabled;
bool mVBarEnabled;
bool mHasHScrollBar;
bool mHasVScrollBar;
F32 mHBarThumbPos;
F32 mHBarThumbWidth;
F32 mVBarThumbPos;
F32 mVBarThumbWidth;
S32 mHThumbSize;
S32 mHThumbPos;
S32 mVThumbSize;
S32 mVThumbPos;
S32 mBaseThumbSize;
RectI mUpArrowRect;
RectI mDownArrowRect;
RectI mLeftArrowRect;
RectI mRightArrowRect;
RectI mHTrackRect;
RectI mVTrackRect;
S32 mDefaultLineHeight; // line height for scroll controls that DO NOT have array controls in them
// ignored if left at zero
F32 mLine_V; // percentage to scroll line Vertically
F32 mLine_H;
F32 mPage_V; // percentage to scroll page Vertically
F32 mPage_H;
//--------------------------------------
// for determing hit area
public: //called by the ComboPopUp class
enum Region
{
UpArrow,
DownArrow,
LeftArrow,
RightArrow,
UpPage,
DownPage,
LeftPage,
RightPage,
VertThumb,
HorizThumb,
None
};
Region findHitRegion(const Point2I &);
protected:
bool stateDepressed;
Region curHitRegion;
virtual bool calcChildExtents(Point2I *pos, Point2I *ext);
virtual void calcScrollRects(void);
void calcThumbs(Point2I cpos, Point2I cext);
void scrollByRegion(Region reg);
//--------------------------------------
//--------------------------------------
// for mouse dragging the thumb
F32 mThumbAnchorPos;
S32 mThumbDelta;
//--------------------------------------
public:
GuiScrollCtrl();
~GuiScrollCtrl();
DECLARE_CONOBJECT(GuiScrollCtrl);
static void consoleInit();
static void initPersistFields();
void autoScroll(Region reg);
bool disabled;
F32 getCurrVPos() const;
F32 getCurrHPos() const;
void scrollTo(F32 x, F32 y);
void computeSizes();
enum {
ScrollBarAlwaysOn = 0,
ScrollBarAlwaysOff = 1,
ScrollBarDynamic = 2
};
// you can change the bitmap array dynamically.
void loadBitmapArray();
S32 mForceHScrollBar;
S32 mForceVScrollBar;
bool mUseConstantHeightThumb;
bool mWillFirstRespond; // for automatically handling arrow keys
GuiScrollContentCtrl *getScrollContentCtrl() { return mContentCtrl; }
void addObject(SimObject *object);
void resize(const Point2I &newPos, const Point2I &newExt);
S32 getBorderThickness(void) { return mBorderThickness; }
S32 scrollBarThickness() const { return(mScrollBarThickness); }
S32 scrollBarArrowBtnLength() const { return(mScrollBarArrowBtnLength); }
bool hasHScrollBar() const { return(mHasHScrollBar); }
bool hasVScrollBar() const { return(mHasVScrollBar); }
bool enabledHScrollBar() const { return(mHBarEnabled); }
bool enabledVScrollBar() const { return(mVBarEnabled); }
bool wantsTabListMembership();
bool becomeFirstResponder();
bool loseFirstResponder();
Region getCurHitRegion(void) { return curHitRegion; }
bool onKeyDown(const GuiEvent &event);
void onMouseDown(const GuiEvent &event);
void onMouseRepeat(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
bool onMouseWheelUp(const GuiEvent &event);
bool onMouseWheelDown(const GuiEvent &event);
bool onAdd();
bool onWake();
void onSleep();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
virtual void drawBorder(const Point2I &offset, bool isFirstResponder);
virtual void drawVScrollBar(const Point2I &offset);
virtual void drawHScrollBar(const Point2I &offset);
virtual void drawScrollCorner(const Point2I &offset);
};
//--------------------------------------------------------------------------
inline F32 GuiScrollCtrl::getCurrVPos() const
{
if (mHasVScrollBar)
return mVBarThumbPos;
else
return 1.0;
}
inline F32 GuiScrollCtrl::getCurrHPos() const
{
if (mHasVScrollBar)
return mVBarThumbPos;
else
return 1.0;
}
#endif //_GUI_SCROLL_CTRL_H

256
gui/guiSliderCtrl.cc Normal file
View file

@ -0,0 +1,256 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "dgl/gTexManager.h"
#include "GUI/guiSliderCtrl.h"
#include "Platform/event.h"
//----------------------------------------------------------------------------
GuiSliderCtrl::GuiSliderCtrl(void)
{
mActive = true;
mRange.set( 0.0f, 1.0f );
mTicks = 1000;
mValue = 0.5f;
mThumbSize.set(8,20);
mShiftPoint = 5;
mShiftExtent = 10;
mDisplayValue = false;
}
//----------------------------------------------------------------------------
void GuiSliderCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("range", TypePoint2F, Offset(mRange, GuiSliderCtrl));
addField("ticks", TypeS32, Offset(mTicks, GuiSliderCtrl));
addField("value", TypeF32, Offset(mValue, GuiSliderCtrl));
}
//----------------------------------------------------------------------------
static F32 cGuiSlider_GetValue(SimObject *obj, S32, const char **)
{
GuiSliderCtrl *ctrl = static_cast<GuiSliderCtrl*>(obj);
return ctrl->getValue();
}
//----------------------------------------------------------------------------
void GuiSliderCtrl::setScriptValue(const char *val)
{
mValue = dAtof(val);
updateThumb(mValue);
}
//----------------------------------------------------------------------------
void GuiSliderCtrl::consoleInit()
{
Con::addCommand("GuiSliderCtrl", "getValue", cGuiSlider_GetValue, "guiSliderCtrl.getValue()", 2, 2);
}
//----------------------------------------------------------------------------
bool GuiSliderCtrl::onWake()
{
if (! Parent::onWake())
return false;
if(mThumbSize.y + mProfile->mFont->getHeight()-4 <= mBounds.extent.y)
mDisplayValue = true;
else
mDisplayValue = false;
updateThumb( mValue, true );
return true;
}
//----------------------------------------------------------------------------
void GuiSliderCtrl::onMouseDown(const GuiEvent &event)
{
if ( !mActive || !mAwake || !mVisible )
return;
mouseLock();
setFirstResponder();
Point2I curMousePos = globalToLocalCoord(event.mousePoint);
F32 value;
if (mBounds.extent.x >= mBounds.extent.y)
value = F32(curMousePos.x-mShiftPoint) / F32(mBounds.extent.x-mShiftExtent)*(mRange.y-mRange.x) + mRange.x;
else
value = F32(curMousePos.y) / F32(mBounds.extent.y)*(mRange.y-mRange.x) + mRange.x;
updateThumb(value);
}
//----------------------------------------------------------------------------
void GuiSliderCtrl::onMouseDragged(const GuiEvent &event)
{
if ( !mActive || !mAwake || !mVisible )
return;
Point2I curMousePos = globalToLocalCoord(event.mousePoint);
F32 value;
if (mBounds.extent.x >= mBounds.extent.y)
value = F32(curMousePos.x-mShiftPoint) / F32(mBounds.extent.x-mShiftExtent)*(mRange.y-mRange.x) + mRange.x;
else
value = F32(curMousePos.y) / F32(mBounds.extent.y)*(mRange.y-mRange.x) + mRange.x;
if (value > mRange.y)
value = mRange.y;
else if (value < mRange.x)
value = mRange.x;
if ((event.modifier & SI_SHIFT) && mTicks > 2) {
// If the shift key is held, snap to the nearest tick, if any are being drawn
Con::printf("snapping");
F32 tickStep = (mRange.y - mRange.x) / F32(mTicks + 1);
F32 tickSteps = (value - mRange.x) / tickStep;
S32 actualTick = S32(tickSteps + 0.5);
value = actualTick * tickStep + mRange.x;
AssertFatal(value <= mRange.y && value >= mRange.x, "Error, out of bounds value generated from shift-snap of slider");
}
updateThumb(value);
}
//----------------------------------------------------------------------------
void GuiSliderCtrl::onMouseUp(const GuiEvent &)
{
if ( !mActive || !mAwake || !mVisible )
return;
mouseUnlock();
if (mConsoleCommand[0])
{
char buf[16];
dSprintf(buf, sizeof(buf), "%d", getId());
Con::setVariable("$ThisControl", buf);
Con::evaluate(mConsoleCommand, false);
}
}
//----------------------------------------------------------------------------
void GuiSliderCtrl::updateThumb( F32 value, bool onWake )
{
mValue = value;
// clamp the thumb to legal values
if (mValue < mRange.x) mValue = mRange.x;
if (mValue > mRange.y) mValue = mRange.y;
Point2I ext = mBounds.extent;
ext.x -= ( mShiftExtent + mThumbSize.x );
// update the bounding thumb rect
if (mBounds.extent.x >= mBounds.extent.y)
{ // HORZ thumb
S32 mx = (S32)((F32(ext.x) * (mValue-mRange.x) / (mRange.y-mRange.x)));
S32 my = ext.y/2;
if(mDisplayValue)
my = mThumbSize.y/2;
mThumb.point.x = mx - (mThumbSize.x/2);
mThumb.point.y = my - (mThumbSize.y/2);
mThumb.extent = mThumbSize;
}
else
{ // VERT thumb
S32 mx = ext.x/2;
S32 my = (S32)((F32(ext.y) * (mValue-mRange.x) / (mRange.y-mRange.x)));
mThumb.point.x = mx - (mThumbSize.y/2);
mThumb.point.y = my - (mThumbSize.x/2);
mThumb.extent.x = mThumbSize.y;
mThumb.extent.y = mThumbSize.x;
}
setConsoleVariable("value");
setFloatVariable(mValue);
setUpdate();
// Use the alt console command if you want to continually update:
if ( !onWake && mAltConsoleCommand[0] )
Con::evaluate( mAltConsoleCommand, false );
}
//----------------------------------------------------------------------------
void GuiSliderCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
Point2I pos(offset.x+mShiftPoint, offset.y);
Point2I ext(mBounds.extent.x - mShiftExtent, mBounds.extent.y);
if (mBounds.extent.x >= mBounds.extent.y)
{
Point2I mid(ext.x, ext.y/2);
if(mDisplayValue)
mid.set(ext.x, mThumbSize.y/2);
glColor4f(0, 0, 0, 1);
glBegin(GL_LINES);
// horz rule
glVertex2i(pos.x, pos.y+mid.y);
glVertex2i(pos.x+mid.x, pos.y+mid.y);
// tick marks
for (U32 t = 0; t <= (mTicks+1); t++)
{
S32 x = (S32)(F32(mid.x-1)/F32(mTicks+1)*F32(t));
glVertex2i(pos.x+x, pos.y+mid.y-mShiftPoint);
glVertex2i(pos.x+x, pos.y+mid.y+mShiftPoint);
}
glEnd();
}
else
{
Point2I mid(ext.x/2, ext.y);
glColor4f(0, 0, 0, 1);
glBegin(GL_LINES);
// horz rule
glVertex2i(pos.x+mid.x, pos.y);
glVertex2i(pos.x+mid.x, pos.y+mid.y);
// tick marks
for (U32 t = 0; t <= (mTicks+1); t++)
{
S32 y = (S32)(F32(mid.y-1)/F32(mTicks+1)*F32(t));
glVertex2i(pos.x+mid.x-mShiftPoint, pos.y+y);
glVertex2i(pos.x+mid.x+mShiftPoint, pos.y+y);
}
glEnd();
mDisplayValue = false;
}
// draw the thumb
RectI thumb = mThumb;
thumb.point += pos;
dglDrawRectFill(thumb, ColorI(255,255,255));
dglDrawRect(thumb, ColorI(0,0,0));
if(mDisplayValue)
{
char buf[20];
dSprintf(buf,sizeof(buf),"%0.3f",mValue);
Point2I textStart = thumb.point;
S32 txt_w = mProfile->mFont->getStrWidth(buf);
textStart.x += (S32)((thumb.extent.x/2.0f));
textStart.y += thumb.extent.y - 2; //19
textStart.x -= (txt_w/2);
if(textStart.x < offset.x)
textStart.x = offset.x;
else if(textStart.x + txt_w > offset.x+mBounds.extent.x)
textStart.x -=((textStart.x + txt_w) - (offset.x+mBounds.extent.x));
dglSetBitmapModulation(mProfile->mFontColor);
dglDrawText(mProfile->mFont, textStart, buf, mProfile->mFontColors);
}
renderChildControls(offset, updateRect, firstResponder);
}

51
gui/guiSliderCtrl.h Normal file
View file

@ -0,0 +1,51 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUISLIDERCTRL_H_
#define _GUISLIDERCTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
class GuiSliderCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
protected:
Point2F mRange;
U32 mTicks;
F32 mValue;
RectI mThumb;
Point2I mThumbSize;
void updateThumb( F32 value, bool onWake = false );
S32 mShiftPoint;
S32 mShiftExtent;
bool mDisplayValue;
public:
//creation methods
DECLARE_CONOBJECT(GuiSliderCtrl);
GuiSliderCtrl();
static void initPersistFields();
static void consoleInit();
//Parental methods
bool onWake();
void onMouseDown(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
void onMouseUp(const GuiEvent &);
F32 getValue() { return mValue; }
void setScriptValue(const char *val);
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
};
#endif

130
gui/guiTSControl.cc Normal file
View file

@ -0,0 +1,130 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/guiTSControl.h"
#include "console/consoleTypes.h"
#include "sceneGraph/sceneLighting.h"
IMPLEMENT_CONOBJECT(GuiTSCtrl);
U32 GuiTSCtrl::smFrameCount = 0;
GuiTSCtrl::GuiTSCtrl()
{
for(U32 i = 0; i < 16; i++)
{
mSaveModelview[i] = 0;
mSaveProjection[i] = 0;
}
mSaveModelview[0] = 1;
mSaveModelview[5] = 1;
mSaveModelview[10] = 1;
mSaveModelview[15] = 1;
mSaveProjection[0] = 1;
mSaveProjection[5] = 1;
mSaveProjection[10] = 1;
mSaveProjection[15] = 1;
mSaveViewport[0] = 0;
mSaveViewport[1] = 0;
mSaveViewport[2] = 2;
mSaveViewport[3] = 2;
}
void GuiTSCtrl::consoleInit()
{
Con::addVariable("$TSControl::frameCount", TypeS32, &smFrameCount);
}
void GuiTSCtrl::onPreRender()
{
setUpdate();
}
bool GuiTSCtrl::processCameraQuery(CameraQuery *)
{
return false;
}
void GuiTSCtrl::renderWorld(const RectI& /*updateRect*/)
{
}
bool GuiTSCtrl::project(const Point3F &pt, Point3F *dest)
{
GLdouble winx, winy, winz;
GLint result = gluProject(pt.x, pt.y, pt.z,
mSaveModelview, mSaveProjection, mSaveViewport,
&winx, &winy, &winz);
if(result == GL_FALSE || winz < 0 || winz > 1)
return false;
dest->set(winx, winy, winz);
return true;
}
bool GuiTSCtrl::unproject(const Point3F &pt, Point3F *dest)
{
GLdouble objx, objy, objz;
GLint result = gluUnProject(pt.x, pt.y, pt.z,
mSaveModelview, mSaveProjection, mSaveViewport,
&objx, &objy, &objz);
if(result == GL_FALSE)
return false;
dest->set(objx, objy, objz);
return true;
}
void GuiTSCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl* /*firstResponder*/)
{
if(SceneLighting::isLighting())
return;
if(!processCameraQuery(&mLastCameraQuery))
return;
// set up the camera and viewport stuff:
F32 wwidth = mLastCameraQuery.nearPlane * mTan(mLastCameraQuery.fov / 2);
F32 wheight = F32(mBounds.extent.y) / F32(mBounds.extent.x) * wwidth;
F32 hscale = wwidth * 2 / F32(mBounds.extent.x);
F32 vscale = wheight * 2 / F32(mBounds.extent.y);
F32 left = (updateRect.point.x - offset.x) * hscale - wwidth;
F32 right = (updateRect.point.x + updateRect.extent.x - offset.x) * hscale - wwidth;
F32 top = wheight - vscale * (updateRect.point.y - offset.y);
F32 bottom = wheight - vscale * (updateRect.point.y + updateRect.extent.y - offset.y);
dglSetViewport(updateRect);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
dglSetFrustum(left, right, bottom, top, mLastCameraQuery.nearPlane, mLastCameraQuery.farPlane);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//Point3F refPt = query.position + query.viewVector;
mLastCameraQuery.cameraMatrix.inverse();
dglMultMatrix(&mLastCameraQuery.cameraMatrix);
glGetDoublev(GL_PROJECTION_MATRIX, mSaveProjection);
glGetDoublev(GL_MODELVIEW_MATRIX, mSaveModelview);
//glGetIntegerv(GL_VIEWPORT, mSaveViewport);
//U32 screenHeight = Platform::getWindowSize().y;
mSaveViewport[0] = updateRect.point.x;
mSaveViewport[1] = updateRect.point.y + updateRect.extent.y;
mSaveViewport[2] = updateRect.extent.x;
mSaveViewport[3] = -updateRect.extent.y;
//gluLookAt(query.position.x, query.position.y, query.position.z,
// refPt.x, refPt.y, refPt.z,
// query.upVector.x, query.upVector.y, query.upVector.z);
renderWorld(updateRect);
smFrameCount++;
}

61
gui/guiTSControl.h Normal file
View file

@ -0,0 +1,61 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUITSCONTROL_H_
#define _GUITSCONTROL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
#ifndef _MMATH_H_
#include "Math/mMath.h"
#endif
#ifndef _DGL_H_
#include "dgl/dgl.h"
#endif
struct CameraQuery
{
SimObject* object;
F32 nearPlane;
F32 farPlane;
F32 fov;
MatrixF cameraMatrix;
//Point3F position;
//Point3F viewVector;
//Point3F upVector;
};
class GuiTSCtrl : public GuiControl
{
typedef GuiControl Parent;
GLdouble mSaveModelview[16];
GLdouble mSaveProjection[16];
GLint mSaveViewport[4];
static U32 smFrameCount;
public:
CameraQuery mLastCameraQuery;
GuiTSCtrl();
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
virtual bool processCameraQuery(CameraQuery *query);
virtual void renderWorld(const RectI &updateRect);
static void consoleInit();
bool project(const Point3F &pt, Point3F *dest); // returns screen space X,Y and Z for world space point
bool unproject(const Point3F &pt, Point3F *dest); // returns world space point for X, Y and Z
DECLARE_CONOBJECT(GuiTSCtrl);
};
#endif

191
gui/guiTextCtrl.cc Normal file
View file

@ -0,0 +1,191 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "Core/color.h"
#include "GUI/guiTextCtrl.h"
#include "dgl/dgl.h"
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
GuiTextCtrl::GuiTextCtrl()
{
//default fonts
mInitialText = StringTable->insert("");
mText[0] = '\0';
mMaxStrLen = GuiTextCtrl::MAX_STRING_LENGTH;
}
ConsoleMethod( GuiTextCtrl, setText, void, 3, 3, "obj.setText( newText )" )
{
argc;
GuiTextCtrl* ctrl = static_cast<GuiTextCtrl*>( object );
ctrl->setText( argv[2] );
}
void GuiTextCtrl::consoleInit()
{
}
void GuiTextCtrl::initPersistFields()
{
Parent::initPersistFields();
addField( "text", TypeCaseString, Offset( mInitialText, GuiTextCtrl ) );
addField( "maxLength", TypeS32, Offset( mMaxStrLen, GuiTextCtrl ) );
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
bool GuiTextCtrl::onAdd()
{
if(!Parent::onAdd())
return false;
dStrncpy(mText, mInitialText, MAX_STRING_LENGTH);
mText[MAX_STRING_LENGTH] = '\0';
return true;
}
void GuiTextCtrl::inspectPostApply()
{
Parent::inspectPostApply();
setText(mInitialText);
}
bool GuiTextCtrl::onWake()
{
if ( !Parent::onWake() )
return false;
mFont = mProfile->mFont;
AssertFatal( bool( mFont ), "GuiTextCtrl::onWake: invalid font in profile" );
if ( mConsoleVariable[0] )
{
const char *txt = Con::getVariable( mConsoleVariable );
if ( txt )
{
if ( dStrlen( txt ) > mMaxStrLen )
{
char* buf = new char[mMaxStrLen + 1];
dStrncpy( buf, txt, mMaxStrLen );
buf[mMaxStrLen] = 0;
setScriptValue( buf );
delete [] buf;
}
else
setScriptValue( txt );
}
}
//resize
if ( mProfile->mAutoSizeWidth )
{
if ( mProfile->mAutoSizeHeight )
resize( mBounds.point, Point2I( mFont->getStrWidth( mText ), mFont->getHeight() + 4 ) );
else
resize( mBounds.point, Point2I( mFont->getStrWidth( mText ), mBounds.extent.y ) );
}
else if ( mProfile->mAutoSizeHeight )
resize( mBounds.point, Point2I( mBounds.extent.x, mFont->getHeight() + 4 ) );
return true;
}
void GuiTextCtrl::onSleep()
{
Parent::onSleep();
mFont = NULL;
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
void GuiTextCtrl::setText(const char *txt)
{
//make sure we don't call this before onAdd();
AssertFatal(mProfile, "Can't call setText() until setProfile() has been called.");
if (txt)
dStrncpy(mText, txt, MAX_STRING_LENGTH);
mText[MAX_STRING_LENGTH] = '\0';
//Make sure we have a font
mProfile->incRefCount();
mFont = mProfile->mFont;
//resize
if (mProfile->mAutoSizeWidth)
{
if (mProfile->mAutoSizeHeight)
resize(mBounds.point, Point2I(mFont->getStrWidth(mText), mFont->getHeight() + 4));
else
resize(mBounds.point, Point2I(mFont->getStrWidth(mText), mBounds.extent.y));
}
else if (mProfile->mAutoSizeHeight)
{
resize(mBounds.point, Point2I(mBounds.extent.x, mFont->getHeight() + 4));
}
setVariable(mText);
setUpdate();
//decrement the profile referrence
mProfile->decRefCount();
}
//------------------------------------------------------------------------------
void GuiTextCtrl::onPreRender()
{
const char * var = getVariable();
if(var && var[0] && dStricmp(mText, var))
setText(var);
}
//------------------------------------------------------------------------------
void GuiTextCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
S32 txt_w = mFont->getStrWidth(mText);
Point2I localStart;
switch (mProfile->mAlignment)
{
case GuiControlProfile::RightJustify:
localStart.set(mBounds.extent.x - txt_w, 0);
break;
case GuiControlProfile::CenterJustify:
localStart.set((mBounds.extent.x - txt_w) / 2, 0);
break;
default:
// GuiControlProfile::LeftJustify
localStart.set(0,0);
break;
}
Point2I globalStart = localToGlobalCoord(localStart);
//draw the text
dglSetBitmapModulation(mProfile->mFontColor);
dglDrawText(mFont, globalStart, mText, mProfile->mFontColors);
//render the child controls
renderChildControls(offset, updateRect, firstResponder);
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
const char *GuiTextCtrl::getScriptValue()
{
return getText();
}
void GuiTextCtrl::setScriptValue(const char *val)
{
setText(val);
}
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
// EOF //

63
gui/guiTextCtrl.h Normal file
View file

@ -0,0 +1,63 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUITEXTCTRL_H_
#define _GUITEXTCTRL_H_
#ifndef _GFONT_H_
#include "dgl/gFont.h"
#endif
#ifndef _GUITYPES_H_
#include "GUI/guiTypes.h"
#endif
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
class GuiTextCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
public:
enum Constants { MAX_STRING_LENGTH = 255 };
protected:
StringTableEntry mInitialText;
char mText[MAX_STRING_LENGTH + 1];
S32 mMaxStrLen; // max string len, must be less then or equal to 255
Resource<GFont> mFont;
public:
//creation methods
DECLARE_CONOBJECT(GuiTextCtrl);
GuiTextCtrl();
static void consoleInit();
static void initPersistFields();
//Parental methods
bool onAdd();
virtual bool onWake();
virtual void onSleep();
//text methods
virtual void setText(const char *txt = NULL);
const char *getText() { return mText; }
void inspectPostApply();
//rendering methods
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
//Console methods
const char *getScriptValue();
void setScriptValue(const char *value);
};
#endif //_GUI_TEXT_CONTROL_H_

1110
gui/guiTextEditCtrl.cc Normal file

File diff suppressed because it is too large Load diff

99
gui/guiTextEditCtrl.h Normal file
View file

@ -0,0 +1,99 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUITEXTEDITCTRL_H_
#define _GUITEXTEDITCTRL_H_
#ifndef _GUITYPES_H_
#include "gui/guiTypes.h"
#endif
#ifndef _GUITEXTCTRL_H_
#include "gui/guiTextCtrl.h"
#endif
class GuiTextEditCtrl : public GuiTextCtrl
{
private:
typedef GuiTextCtrl Parent;
static U32 mNumAwake;
protected:
StringTableEntry mValidateCommand;
StringTableEntry mEscapeCommand;
AudioProfile* mDeniedSound;
// for animating the cursor
S32 mNumFramesElapsed;
U32 mTimeLastCursorFlipped;
ColorI mCursorColor;
bool mCursorOn;
bool mInsertOn;
S32 mMouseDragStart;
Point2I mTextOffset;
bool mDragHit;
bool mTabComplete;
S32 mScrollDir;
//undo members
char mUndoText[GuiTextCtrl::MAX_STRING_LENGTH + 1];
S32 mUndoBlockStart;
S32 mUndoBlockEnd;
S32 mUndoCursorPos;
void saveUndoState();
S32 mBlockStart;
S32 mBlockEnd;
S32 mCursorPos;
S32 setCursorPos(const Point2I &offset);
bool mHistoryDirty;
S32 mHistoryLast;
S32 mHistoryIndex;
S32 mHistorySize;
bool mPasswordText;
char **mHistoryBuf;
void updateHistory(const char *txt, bool moveIndex);
void playDeniedSound();
public:
GuiTextEditCtrl();
~GuiTextEditCtrl();
DECLARE_CONOBJECT(GuiTextEditCtrl);
static void initPersistFields();
static void consoleInit();
bool onAdd();
bool onWake();
void onSleep();
void getText(char *dest); // dest must be of size
// StructDes::MAX_STRING_LEN + 1
void setText(S32 tag);
virtual void setText(const char *txt);
S32 getCursorPos() { return( mCursorPos ); }
void reallySetCursorPos( const S32 newPos );
bool onKeyDown(const GuiEvent &event);
void onMouseDown(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
void onLoseFirstResponder();
void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
bool hasText();
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
virtual void DrawText( const RectI &drawRect, bool isFocused );
};
#endif //_GUI_TEXTEDIT_CTRL_H

View file

@ -0,0 +1,280 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/dgl.h"
#include "GUI/guiCanvas.h"
#include "GUI/guiTextEditSliderCtrl.h"
GuiTextEditSliderCtrl::GuiTextEditSliderCtrl()
{
mRange.set(0, 1);
mIncAmount = 1.0f;
mValue = 0.0f;
mMulInc = 0;
mIncCounter = 0.0f;
mFormat = StringTable->insert("%3.2f");
mTextAreaHit = None;
}
GuiTextEditSliderCtrl::~GuiTextEditSliderCtrl()
{
}
void GuiTextEditSliderCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("format", TypeString, Offset(mFormat, GuiTextEditSliderCtrl));
addField("range", TypePoint2I, Offset(mRange, GuiTextEditSliderCtrl));
addField("increment", TypeF32, Offset(mIncAmount, GuiTextEditSliderCtrl));
}
void GuiTextEditSliderCtrl::consoleInit()
{
}
void GuiTextEditSliderCtrl::getText(char *dest)
{
Parent::getText(dest);
}
void GuiTextEditSliderCtrl::setText(const char *txt)
{
mValue = dAtof(txt);
checkRange();
setValue();
}
bool GuiTextEditSliderCtrl::onKeyDown(const GuiEvent &event)
{
return Parent::onKeyDown(event);
}
void GuiTextEditSliderCtrl::checkRange()
{
if(mValue < mRange.x)
mValue = mRange.x;
else if(mValue > mRange.y)
mValue = mRange.y;
}
void GuiTextEditSliderCtrl::setValue()
{
char buf[20];
dSprintf(buf,sizeof(buf),mFormat, mValue);
Parent::setText(buf);
}
void GuiTextEditSliderCtrl::onMouseDown(const GuiEvent &event)
{
char txt[20];
Parent::getText(txt);
mValue = dAtof(txt);
mMouseDownTime = Sim::getCurrentTime();
GuiControl *parent = getParent();
if(!parent)
return;
Point2I camPos = event.mousePoint;
Point2I point = parent->localToGlobalCoord(mBounds.point);
if(camPos.x > point.x + mBounds.extent.x - 14)
{
if(camPos.y > point.y + (mBounds.extent.y/2))
{
mValue -=mIncAmount;
mTextAreaHit = ArrowDown;
mMulInc = -0.15f;
}
else
{
mValue +=mIncAmount;
mTextAreaHit = ArrowUp;
mMulInc = 0.15f;
}
checkRange();
setValue();
mouseLock();
return;
}
Parent::onMouseDown(event);
}
void GuiTextEditSliderCtrl::onMouseDragged(const GuiEvent &event)
{
if(mTextAreaHit == None || mTextAreaHit == Slider)
{
mTextAreaHit = Slider;
GuiControl *parent = getParent();
if(!parent)
return;
Point2I camPos = event.mousePoint;
Point2I point = parent->localToGlobalCoord(mBounds.point);
F32 maxDis = 100;
F32 val;
if(camPos.y < point.y)
{
if(point.y < maxDis)
maxDis = point.y;
val = point.y - maxDis;
if(point.y > 0)
mMulInc= 1.0f-(((float)camPos.y - val) / maxDis);
else
mMulInc = 1.0f;
checkIncValue();
return;
}
else if(camPos.y > point.y + mBounds.extent.y)
{
GuiCanvas *root = getRoot();
val = root->mBounds.extent.y - (point.y + mBounds.extent.y);
if(val < maxDis)
maxDis = val;
if( val > 0)
mMulInc= -(float)(camPos.y - (point.y + mBounds.extent.y))/maxDis;
else
mMulInc = -1.0f;
checkIncValue();
return;
}
mTextAreaHit = None;
Parent::onMouseDragged(event);
}
}
void GuiTextEditSliderCtrl::onMouseUp(const GuiEvent &event)
{
mMulInc = 0.0f;
mouseUnlock();
//if we released the mouse within this control, then the parent will call
//the mConsoleCommand other wise we have to call it.
Parent::onMouseUp(event);
//if we didn't release the mouse within this control, then perform the action
if (!cursorInControl())
Con::evaluate(mConsoleCommand, false);
mTextAreaHit = None;
}
void GuiTextEditSliderCtrl::checkIncValue()
{
if(mMulInc > 1.0f)
mMulInc = 1.0f;
else if(mMulInc < -1.0f)
mMulInc = -1.0f;
}
void GuiTextEditSliderCtrl::timeInc(U32 elapseTime)
{
S32 numTimes = elapseTime / 750;
if(mTextAreaHit != Slider && numTimes > 0)
{
if(mTextAreaHit == ArrowUp)
mMulInc = 0.15f * numTimes;
else
mMulInc = -0.15f * numTimes;
checkIncValue();
}
}
void GuiTextEditSliderCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
if(mTextAreaHit != None)
{
U32 elapseTime = Sim::getCurrentTime() - mMouseDownTime;
if(elapseTime > 750 || mTextAreaHit == Slider)
{
timeInc(elapseTime);
mIncCounter += mMulInc;
if(mIncCounter >= 1.0f || mIncCounter <= -1.0f)
{
mValue = (mMulInc > 0.0f) ? mValue+mIncAmount : mValue-mIncAmount;
mIncCounter = (mIncCounter > 0.0f) ? mIncCounter-1 : mIncCounter+1;
checkRange();
setValue();
}
}
}
Parent::onRender(offset, updateRect, firstResponder);
Point2I start(offset.x + mBounds.extent.x - 14, offset.y);
Point2I midPoint(start.x + 7, start.y + (mBounds.extent.y/2));
dglDrawRectFill(Point2I(start.x+1,start.y+1), Point2I(start.x+13,start.y+mBounds.extent.y-1) , mProfile->mFillColor);
dglDrawLine(start, Point2I(start.x, start.y+mBounds.extent.y),mProfile->mFontColor);
dglDrawLine(Point2I(start.x,midPoint.y),
Point2I(start.x+14,midPoint.y),
mProfile->mFontColor);
glColor3i(0,0,0);
glBegin(GL_TRIANGLES);
if(mTextAreaHit == ArrowUp)
{
glVertex2i(midPoint.x, start.y+1);
glVertex2i(start.x+11,midPoint.y-2);
glVertex2i(start.x+3,midPoint.y-2);
}
else
{
glVertex2i(midPoint.x, start.y+2);
glVertex2i(start.x+11,midPoint.y-1);
glVertex2i(start.x+3,midPoint.y-1);
}
if(mTextAreaHit == ArrowDown)
{
glVertex2i(midPoint.x, start.y+mBounds.extent.y-1);
glVertex2i(start.x+11,midPoint.y+3);
glVertex2i(start.x+3,midPoint.y+3);
}
else
{
glVertex2i(midPoint.x, start.y+mBounds.extent.y-2);
glVertex2i(start.x+11,midPoint.y+2);
glVertex2i(start.x+3,midPoint.y+2);
}
glEnd();
}
void GuiTextEditSliderCtrl::onPreRender()
{
bool focused = false;
GuiCanvas *canvas = getRoot();
if (canvas)
focused = (canvas->getFirstResponder() == this);
if (focused)
{
U32 timeElapsed = Platform::getVirtualMilliseconds() - mTimeLastCursorFlipped;
mNumFramesElapsed++;
if ((timeElapsed > 500) && (mNumFramesElapsed > 3))
{
mCursorOn = 1 - mCursorOn;
mTimeLastCursorFlipped = Sim::getCurrentTime();
mNumFramesElapsed = 0;
setUpdate();
}
//update the cursor if the text is scrolling
if (mDragHit)
{
if ((mScrollDir < 0) && (mCursorPos > 0))
{
mCursorPos--;
}
else if ((mScrollDir > 0) && (mCursorPos < (S32)dStrlen(mText)))
{
mCursorPos++;
}
}
}
}

View file

@ -0,0 +1,70 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUITEXTEDITSLIDERCTRL_H_
#define _GUITEXTEDITSLIDERCTRL_H_
#ifndef _GUITYPES_H_
#include "GUI/guiTypes.h"
#endif
#ifndef _GUITEXTEDITCTRL_H_
#include "GUI/guiTextEditCtrl.h"
#endif
class GuiTextEditSliderCtrl : public GuiTextEditCtrl
{
private:
typedef GuiTextEditCtrl Parent;
Point2I mRange;
F32 mIncAmount;
F32 mValue;
F32 mIncCounter;
F32 mMulInc;
StringTableEntry mFormat;
U32 mMouseDownTime;
// max string len, must be less then or equal to 255
public:
enum CtrlArea
{
None,
Slider,
ArrowUp,
ArrowDown
};
private:
CtrlArea mTextAreaHit;
public:
GuiTextEditSliderCtrl();
~GuiTextEditSliderCtrl();
DECLARE_CONOBJECT(GuiTextEditSliderCtrl);
static void initPersistFields();
static void consoleInit();
void getText(char *dest); // dest must be of size
// StructDes::MAX_STRING_LEN + 1
void setText(S32 tag);
void setText(const char *txt);
void setValue();
void checkRange();
void checkIncValue();
void timeInc(U32 elapseTime);
bool onKeyDown(const GuiEvent &event);
void onMouseDown(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
};
#endif //_GUI_TEXTEDIT_CTRL_H

584
gui/guiTextListCtrl.cc Normal file
View file

@ -0,0 +1,584 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "Platform/platform.h"
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/dgl.h"
#include "GUI/guiTextListCtrl.h"
static int sortColumn;
static bool sIncreasing;
static const char *getColumn(const char *text)
{
int ct = sortColumn;
while(ct--)
{
text = dStrchr(text, '\t');
if(!text)
return "";
text++;
}
return text;
}
static S32 QSORT_CALLBACK textCompare( const void* a, const void* b )
{
GuiTextListCtrl::Entry *ea = (GuiTextListCtrl::Entry *) (a);
GuiTextListCtrl::Entry *eb = (GuiTextListCtrl::Entry *) (b);
S32 result = dStricmp( getColumn( ea->text ), getColumn( eb->text ) );
return ( sIncreasing ? result : -result );
}
static S32 QSORT_CALLBACK numCompare(const void *a,const void *b)
{
GuiTextListCtrl::Entry *ea = (GuiTextListCtrl::Entry *) (a);
GuiTextListCtrl::Entry *eb = (GuiTextListCtrl::Entry *) (b);
const char* aCol = getColumn( ea->text );
const char* bCol = getColumn( eb->text );
char* aBuf = new char[dStrlen( aCol ) + 1];
char* bBuf = new char[dStrlen( bCol ) + 1];
dStrcpy( aBuf, aCol );
dStrcpy( bBuf, bCol );
char* ptr = dStrchr( aBuf, '\t' );
if ( ptr )
*ptr = '\0';
ptr = dStrchr( bBuf, '\t' );
if ( ptr )
*ptr = '\0';
S32 result = dAtoi( aBuf ) - dAtoi( bBuf );
if ( result == 0 )
return( dStricmp( ea->text, eb->text ) );
delete [] aBuf;
delete [] bBuf;
return ( sIncreasing ? result : -result );
}
GuiTextListCtrl::GuiTextListCtrl()
{
VECTOR_SET_ASSOCIATION(mList);
VECTOR_SET_ASSOCIATION(mColumnOffsets);
mActive = true;
mEnumerate = false;
mResizeCell = true;
mSize.set(1, 0);
mColumnOffsets.push_back(0);
mFitParentWidth = true;
mClipColumnText = false;
}
void GuiTextListCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("enumerate", TypeBool, Offset(mEnumerate, GuiTextListCtrl));
addField("resizeCell", TypeBool, Offset(mResizeCell, GuiTextListCtrl));
addField("columns", TypeS32Vector, Offset(mColumnOffsets, GuiTextListCtrl));
addField("fitParentWidth", TypeBool, Offset(mFitParentWidth, GuiTextListCtrl));
addField("clipColumnText", TypeBool, Offset(mClipColumnText, GuiTextListCtrl));
}
static S32 cTextListGetSelectedCellId(SimObject *obj, S32, const char **)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
return ctrl->getSelectedId();
}
static void cTextListSetSelectedCellId(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
U32 id = dAtoi(argv[2]);
S32 index = ctrl->findEntryById(id);
if(index < 0)
return ;
ctrl->setSelectedCell(Point2I(0, index));
}
static void cTextListSetSelectedRow(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>( obj );
ctrl->setSelectedCell( Point2I( 0, dAtoi( argv[2] ) ) );
}
static void cTextListClearSelection(SimObject *obj, S32, const char **)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
ctrl->setSelectedCell(Point2I(-1, -1));
}
static S32 cTextListAdd(SimObject *obj, S32 argc, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
S32 ret = ctrl->mList.size();
if(argc < 5)
ctrl->addEntry(dAtoi(argv[2]), argv[3]);
else
ctrl->insertEntry(dAtoi(argv[2]), argv[3], dAtoi(argv[4]));
return ret;
}
static void cTextListSet(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
ctrl->setEntry(dAtoi(argv[2]), argv[3]);
}
static void cTextListSort(SimObject *obj, S32 argc, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
if ( argc == 3 )
ctrl->sort(dAtoi(argv[2]));
else
ctrl->sort( dAtoi( argv[2] ), dAtob( argv[3] ) );
}
static void cTextListSortNumerical( SimObject *obj, S32 argc, const char **argv )
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
if ( argc == 3 )
ctrl->sortNumerical( dAtoi( argv[2] ) );
else
ctrl->sortNumerical( dAtoi( argv[2] ), dAtob( argv[3] ) );
}
static void cTextListClear(SimObject *obj, S32, const char **)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
ctrl->clear();
}
static S32 cTextListCount(SimObject *obj, S32, const char **)
{
return ((GuiTextListCtrl *) obj)->getNumEntries();
}
static S32 cTextListGetRowId(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
U32 index = dAtoi(argv[2]);
if(index >= ctrl->getNumEntries())
return -1;
return ctrl->mList[index].id;
}
static const char *cTextListGetRowTextById(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
U32 id = dAtoi(argv[2]);
S32 index = ctrl->findEntryById(id);
if(index < 0)
return "";
return ctrl->mList[index].text;
}
static S32 cTextListGetRowNumById(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
U32 id = dAtoi(argv[2]);
S32 index = ctrl->findEntryById(id);
if(index < 0)
return -1;
return index;
}
static const char *cTextListGetRowText(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
S32 index = dAtoi(argv[2]);
if(index < 0 || index >= ctrl->mList.size())
return "";
return ctrl->mList[index].text;
}
static void cTextListRemoveRowById(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
U32 id = dAtoi(argv[2]);
ctrl->removeEntry(id);
}
static void cTextListRemoveRow(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
U32 index = dAtoi(argv[2]);
ctrl->removeEntryByIndex(index);
}
static void cTextListScrollRowVisible(SimObject *obj, S32, const char **argv)
{
GuiTextListCtrl *ctrl = static_cast<GuiTextListCtrl*>(obj);
ctrl->scrollCellVisible(Point2I(0, dAtoi(argv[2])));
}
static S32 cTextListFindText( SimObject* obj, S32, const char** argv )
{
GuiTextListCtrl* ctrl = static_cast<GuiTextListCtrl*>( obj );
return( ctrl->findEntryByText( argv[2] ) );
}
static void cTextListSetRowActive( SimObject* obj, S32, const char** argv )
{
GuiTextListCtrl* ctrl = static_cast<GuiTextListCtrl*>( obj );
ctrl->setEntryActive( U32( dAtoi( argv[2] ) ), dAtob( argv[3] ) );
}
static bool cTextListIsRowActive( SimObject* obj, S32, const char** argv )
{
GuiTextListCtrl* ctrl = static_cast<GuiTextListCtrl*>( obj );
return( ctrl->isEntryActive( U32( dAtoi( argv[2] ) ) ) );
}
void GuiTextListCtrl::consoleInit()
{
Con::addCommand("GuiTextListCtrl", "getSelectedId", cTextListGetSelectedCellId, "textList.getSelectedId()", 2, 2);
Con::addCommand("GuiTextListCtrl", "setSelectedById", cTextListSetSelectedCellId, "textList.setSelectedById(id)", 3, 3);
Con::addCommand("GuiTextListCtrl", "setSelectedRow", cTextListSetSelectedRow, "textList.setSelectedRow(index)", 3, 3);
Con::addCommand("GuiTextListCtrl", "clearSelection", cTextListClearSelection, "textList.clearSelection()", 2, 2);
Con::addCommand("GuiTextListCtrl", "clear", cTextListClear, "textList.clear()", 2, 2);
Con::addCommand("GuiTextListCtrl", "addRow", cTextListAdd, "textList.addRow(id,text,index)", 4, 5);
Con::addCommand("GuiTextListCtrl", "setRowById", cTextListSet, "textList.setRow(id,text)", 4, 4);
Con::addCommand("GuiTextListCtrl", "getRowId", cTextListGetRowId, "textList.getRowId(index)", 3, 3);
Con::addCommand("GuiTextListCtrl", "removeRowById", cTextListRemoveRowById, "textList.removeRowById(id)", 3, 3);
Con::addCommand("GuiTextListCtrl", "getRowTextById", cTextListGetRowTextById, "textList.getRowTextById(id)", 3, 3);
Con::addCommand("GuiTextListCtrl", "getRowNumById", cTextListGetRowNumById, "textList.getRowNumById(id)", 3, 3);
Con::addCommand("GuiTextListCtrl", "getRowText", cTextListGetRowText, "textList.getRowText(index)", 3, 3);
Con::addCommand("GuiTextListCtrl", "removeRow", cTextListRemoveRow, "textList.removeRow(index)", 3, 3);
Con::addCommand("GuiTextListCtrl", "rowCount", cTextListCount, "textList.rowCount()", 2, 2);
Con::addCommand("GuiTextListCtrl", "scrollVisible", cTextListScrollRowVisible, "textList.scrollVisible(index)", 3, 3);
Con::addCommand("GuiTextListCtrl", "sort", cTextListSort, "textList.sort(colId{, increasing})", 3, 4);
Con::addCommand("GuiTextListCtrl", "sortNumerical", cTextListSortNumerical, "textList.sortNumerical(colId{, increasing})", 3, 4);
Con::addCommand("GuiTextListCtrl", "findTextIndex", cTextListFindText, "textList.findText(text)", 3, 3 );
Con::addCommand("GuiTextListCtrl", "setRowActive", cTextListSetRowActive, "textlist.setRowActive(id, <bool>)", 4, 4 );
Con::addCommand("GuiTextListCtrl", "isRowActive", cTextListIsRowActive, "textlist.isRowActive(id)", 3, 3 );
}
bool GuiTextListCtrl::onWake()
{
if(!Parent::onWake())
return false;
setSize(mSize);
return true;
}
U32 GuiTextListCtrl::getSelectedId()
{
if (mSelectedCell.y == -1)
return InvalidId;
return mList[mSelectedCell.y].id;
}
void GuiTextListCtrl::onCellSelected(Point2I cell)
{
Con::executef(this, 3, "onSelect", Con::getIntArg(mList[cell.y].id), mList[cell.y].text);
if (mConsoleCommand[0])
Con::evaluate(mConsoleCommand, false);
}
void GuiTextListCtrl::onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver)
{
if ( mList[cell.y].active )
{
if (selected)
{
dglDrawRectFill(RectI(offset.x, offset.y, mCellSize.x, mCellSize.y), mProfile->mFillColorHL);
dglSetBitmapModulation(mProfile->mFontColorHL);
}
else
dglSetBitmapModulation(mouseOver ? mProfile->mFontColorHL : mProfile->mFontColor);
}
else
dglSetBitmapModulation( mProfile->mFontColorNA );
const char *text = mList[cell.y].text;
for(U32 index = 0; index < mColumnOffsets.size(); index++)
{
const char *nextCol = dStrchr(text, '\t');
if(mColumnOffsets[index] >= 0)
{
U32 slen;
if(nextCol)
slen = nextCol - text;
else
slen = dStrlen(text);
Point2I pos(offset.x + 4 + mColumnOffsets[index], offset.y);
RectI saveClipRect;
bool clipped = false;
if(mClipColumnText && (index != (mColumnOffsets.size() - 1)))
{
saveClipRect = dglGetClipRect();
RectI clipRect(pos, Point2I(mColumnOffsets[index+1] - mColumnOffsets[index] - 4, mCellSize.y));
if(clipRect.intersect(saveClipRect))
{
clipped = true;
dglSetClipRect(clipRect);
}
}
dglDrawTextN(mFont, pos, text, slen, mProfile->mFontColors);
if(clipped)
dglSetClipRect(saveClipRect);
}
if(!nextCol)
break;
text = nextCol+1;
}
}
U32 GuiTextListCtrl::getRowWidth(Entry *row)
{
U32 width = 1;
const char *text = row->text;
for(U32 index = 0; index < mColumnOffsets.size(); index++)
{
const char *nextCol = dStrchr(text, '\t');
U32 textWidth;
if(nextCol)
textWidth = mFont->getStrNWidth(text, nextCol - text);
else
textWidth = mFont->getStrWidth(text);
if(mColumnOffsets[index] >= 0)
width = getMax(width, mColumnOffsets[index] + textWidth);
if(!nextCol)
break;
text = nextCol+1;
}
return width;
}
void GuiTextListCtrl::insertEntry(U32 id, const char *text, S32 index)
{
Entry e;
e.text = dStrdup(text);
e.id = id;
e.active = true;
if(!mList.size())
mList.push_back(e);
else
{
if(index > mList.size())
index = mList.size();
mList.insert(&mList[index],e);
}
setSize(Point2I(1, mList.size()));
}
void GuiTextListCtrl::addEntry(U32 id, const char *text)
{
Entry e;
e.text = dStrdup(text);
e.id = id;
e.active = true;
mList.push_back(e);
setSize(Point2I(1, mList.size()));
}
void GuiTextListCtrl::setEntry(U32 id, const char *text)
{
S32 e = findEntryById(id);
if(e == -1)
addEntry(id, text);
else
{
dFree(mList[e].text);
mList[e].text = dStrdup(text);
// Still have to call this to make sure cells are wide enough for new values:
setSize( Point2I( 1, mList.size() ) );
}
setUpdate();
}
void GuiTextListCtrl::setEntryActive(U32 id, bool active)
{
S32 index = findEntryById( id );
if ( index == -1 )
return;
if ( mList[index].active != active )
{
mList[index].active = active;
// You can't have an inactive entry selected...
if ( !active && mSelectedCell.y >= 0 && mSelectedCell.y < mList.size()
&& mList[mSelectedCell.y].id == id )
setSelectedCell( Point2I( -1, -1 ) );
setUpdate();
}
}
S32 GuiTextListCtrl::findEntryById(U32 id)
{
for(U32 i = 0; i < mList.size(); i++)
if(mList[i].id == id)
return i;
return -1;
}
S32 GuiTextListCtrl::findEntryByText(const char *text)
{
for(U32 i = 0; i < mList.size(); i++)
if(!dStricmp(mList[i].text, text))
return i;
return -1;
}
bool GuiTextListCtrl::isEntryActive(U32 id)
{
S32 index = findEntryById( id );
if ( index == -1 )
return( false );
return( mList[index].active );
}
void GuiTextListCtrl::setSize(Point2I newSize)
{
mSize = newSize;
if ( bool( mFont ) )
{
if ( mSize.x == 1 && mFitParentWidth )
{
GuiControl* parent = getParent();
if ( parent )
mCellSize.x = parent->mBounds.extent.x - mBounds.point.x;
}
else
{
// Find the maximum width cell:
S32 maxWidth = 1;
for ( U32 i = 0; i < mList.size(); i++ )
{
U32 rWidth = getRowWidth( &mList[i] );
if ( rWidth > maxWidth )
maxWidth = rWidth;
}
mCellSize.x = maxWidth + 8;
}
mCellSize.y = mFont->getHeight() + 2;
}
Point2I newExtent( newSize.x * mCellSize.x + mHeaderDim.x, newSize.y * mCellSize.y + mHeaderDim.y );
resize( mBounds.point, newExtent );
}
void GuiTextListCtrl::clear()
{
while (mList.size())
removeEntry(mList[0].id);
mMouseOverCell.set( -1, -1 );
setSelectedCell(Point2I(-1, -1));
}
void GuiTextListCtrl::sort(U32 column, bool increasing)
{
if (getNumEntries() < 2)
return;
sortColumn = column;
sIncreasing = increasing;
dQsort((void *)&(mList[0]), mList.size(), sizeof(Entry), textCompare);
}
void GuiTextListCtrl::sortNumerical( U32 column, bool increasing )
{
if ( getNumEntries() < 2 )
return;
sortColumn = column;
sIncreasing = increasing;
dQsort( (void*) &( mList[0] ), mList.size(), sizeof( Entry ), numCompare );
}
void GuiTextListCtrl::onRemove()
{
clear();
Parent::onRemove();
}
U32 GuiTextListCtrl::getNumEntries()
{
return mList.size();
}
void GuiTextListCtrl::removeEntryByIndex(S32 index)
{
if(index < 0 || index >= mList.size())
return;
dFree(mList[index].text);
mList.erase(index);
setSize(Point2I( 1, mList.size()));
setSelectedCell(Point2I(-1, -1));
}
void GuiTextListCtrl::removeEntry(U32 id)
{
S32 index = findEntryById(id);
removeEntryByIndex(index);
}
const char *GuiTextListCtrl::getSelectedText()
{
if (mSelectedCell.y == -1)
return NULL;
return mList[mSelectedCell.y].text;
}
const char *GuiTextListCtrl::getScriptValue()
{
return getSelectedText();
}
void GuiTextListCtrl::setScriptValue(const char *val)
{
S32 e = findEntryByText(val);
if(e == -1)
setSelectedCell(Point2I(-1, -1));
else
setSelectedCell(Point2I(0, e));
}
bool GuiTextListCtrl::onKeyDown( const GuiEvent &event )
{
//if this control is a dead end, make sure the event stops here
if ( !mVisible || !mActive || !mAwake )
return true;
if ( event.keyCode == KEY_RETURN )
{
if ( mAltConsoleCommand[0] )
Con::evaluate( mAltConsoleCommand, false );
return( true );
}
if ( event.keyCode == KEY_DELETE && ( mSelectedCell.y >= 0 && mSelectedCell.y < mList.size() ) )
{
Con::executef( this, 2, "onDeleteKey", Con::getIntArg( mList[mSelectedCell.y].id ) );
return( true );
}
return( Parent::onKeyDown( event ) );
}

93
gui/guiTextListCtrl.h Normal file
View file

@ -0,0 +1,93 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUITEXTLISTCTRL_H_
#define _GUITEXTLISTCTRL_H_
#ifndef _GUIARRAYCTRL_H_
#include "GUI/guiArrayCtrl.h"
#endif
class GuiTextListCtrl : public GuiArrayCtrl
{
private:
typedef GuiArrayCtrl Parent;
public:
struct Entry
{
char *text;
U32 id;
bool active;
};
Vector<Entry> mList;
bool mEnumerate;
bool mResizeCell;
protected:
enum ScrollConst
{
UP = 0,
DOWN = 1
};
enum {
InvalidId = 0xFFFFFFFF
};
Vector<S32> mColumnOffsets;
bool mFitParentWidth;
bool mClipColumnText;
U32 getRowWidth(Entry *row);
void onCellSelected(Point2I cell);
public:
GuiTextListCtrl();
DECLARE_CONOBJECT(GuiTextListCtrl);
static void initPersistFields();
static void consoleInit();
virtual void setCellSize( const Point2I &size ){ mCellSize = size; }
virtual void getCellSize( Point2I &size ){ size = mCellSize; }
const char *getScriptValue();
void setScriptValue(const char *value);
U32 getNumEntries();
void clear();
virtual void addEntry(U32 id, const char *text);
virtual void insertEntry(U32 id, const char *text, S32 index);
void setEntry(U32 id, const char *text);
void setEntryActive(U32 id, bool active);
S32 findEntryById(U32 id);
S32 findEntryByText(const char *text);
bool isEntryActive(U32 id);
U32 getEntryId(U32 index);
bool onWake();
void removeEntry(U32 id);
virtual void removeEntryByIndex(S32 id);
virtual void sort(U32 column, bool increasing = true);
virtual void sortNumerical(U32 column, bool increasing = true);
U32 getSelectedId();
const char *getSelectedText();
bool onKeyDown(const GuiEvent &event);
virtual void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
void setSize(Point2I newSize);
void onRemove();
};
#endif //_GUI_TEXTLIST_CTRL_H

1473
gui/guiTreeViewCtrl.cc Normal file

File diff suppressed because it is too large Load diff

253
gui/guiTreeViewCtrl.h Normal file
View file

@ -0,0 +1,253 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUITREEVIEWCTRL_H_
#define _GUITREEVIEWCTRL_H_
#ifndef _MRECT_H_
#include "Math/mRect.h"
#endif
#ifndef _GFONT_H_
#include "dgl/gFont.h"
#endif
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
#ifndef _GUIARRAYCTRL_H_
#include "GUI/guiArrayCtrl.h"
#endif
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#ifndef _BITSET_H_
#include "Core/bitSet.h"
#endif
class GuiTreeViewCtrl : public GuiArrayCtrl
{
private:
typedef GuiArrayCtrl Parent;
protected:
struct Item
{
enum ItemState {
Selected = BIT(0),
Expanded = BIT(1),
Focus = BIT(2),
MouseOverBmp = BIT(3),
MouseOverText = BIT(4),
};
BitSet32 mState;
char* mText;
char* mValue;
S16 mNormalImage;
S16 mExpandedImage;
S32 mId;
U32 mTabLevel;
Item * mParent;
Item * mChild;
Item * mNext;
Item * mPrevious;
Item();
~Item();
};
Vector<Item*> mItems;
Vector<Item*> mVisibleItems;
S32 mItemCount;
Item * mItemFreeList;
Item * mRoot;
S32 mMaxWidth;
S32 mSelectedItem;
enum TreeState {
RebuildVisible = BIT(0)
};
BitSet32 mFlags;
TextureHandle mImagesHandle;
Vector<RectI> mImageBounds;
// persist field info...
S32 mTabSize;
StringTableEntry mImagesBitmap;
S32 mNumImages;
S32 mTextOffset;
bool mFullRowSelect;
S32 mItemHeight;
Item * getItem(S32 itemId);
Item * createItem();
void destroyItem(Item * item);
void destroyTree();
//
void buildItem(Item * item, U32 tabLevel);
void buildVisibleTree();
//
enum HitFlags {
OnIndent = BIT(0),
OnImage = BIT(1),
OnText = BIT(2),
OnRow = BIT(3),
};
bool hitTest(const Point2I & pnt, Item* & item, BitSet32 & flags);
public:
GuiTreeViewCtrl();
virtual ~GuiTreeViewCtrl();
//
bool selectItem(S32 itemId, bool select);
bool expandItem(S32 itemId, bool expand);
const char * getItemText(S32 itemId);
const char * getItemValue(S32 itemId);
bool editItem( S32 itemId, const char* newText, const char* newValue );
// insertion/removal
S32 insertItem(S32 parentId, const char * text, const char * value, S16 normalImage, S16 expandedImage);
bool removeItem(S32 itemId);
// tree items
S32 getFirstRootItem();
S32 getChildItem(S32 itemId);
S32 getParentItem(S32 itemId);
S32 getNextSiblingItem(S32 itemId);
S32 getPrevSiblingItem(S32 itemId);
S32 getItemCount();
S32 getSelectedItem();
void moveItemUp( S32 itemId );
// // visible items
// S32 getFirstVisible();
// S32 getLastVisible();
// S32 getNextVisible(S32 itemId);
// S32 getPrevVisible(S32 itemId);
// S32 getVisibleCount();
// // misc.
//bool scrollVisible( S32 itemId );
// GuiControl
bool onWake();
void onSleep();
void onPreRender();
bool onKeyDown( const GuiEvent &event );
void onMouseDown(const GuiEvent &event);
void onMouseMove(const GuiEvent &event);
void onMouseEnter(const GuiEvent &event);
void onMouseLeave(const GuiEvent &event);
void onRightMouseDown(const GuiEvent &event);
// GuiArrayCtrl
void onRenderCell(Point2I offset, Point2I cell, bool, bool);
//
static void consoleInit();
static void initPersistFields();
DECLARE_CONOBJECT(GuiTreeViewCtrl);
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
class GuiTreeView : public GuiArrayCtrl
{
private:
typedef GuiArrayCtrl Parent;
struct ObjNode
{
S32 level;
SimObject *object;
bool lastInGroup;
S32 parentIndex;
ObjNode(S32 in_level, SimObject *in_object, bool in_last, S32 in_pi)
{
level = in_level;
object = in_object;
lastInGroup = in_last;
parentIndex = in_pi;
}
};
Vector<ObjNode> mObjectList;
enum BitmapIndices
{
BmpNone = -1,
BmpChildAbove,
BmpChildBelow,
BmpChildBetween,
BmpParentOpen,
BmpParentOpenAbove,
BmpParentOpenBelow,
BmpParentOpenBetween,
BmpParentClosed,
BmpParentClosedAbove,
BmpParentClosedBelow,
BmpParentClosedBetween,
BmpParentContinue,
BmpCount
};
RectI mBitmapBounds[BmpCount]; //bmp is [3*n], bmpHL is [3*n + 1], bmpNA is [3*n + 2]
TextureHandle mTextureHandle;
//font
Resource<GFont> mFont;
SimSet *mRootObject;
// persist data
bool mAllowMultipleSelections;
bool mRecurseSets;
ObjNode * getHitNode(const GuiEvent & event);
public:
DECLARE_CONOBJECT(GuiTreeView);
GuiTreeView();
static void consoleInit();
static void initPersistFields();
bool onWake();
void onSleep();
void setTreeRoot(SimSet *srcObj);
void buildTree(SimSet *srcObj, S32 srcLevel, S32 srcParentIndex);
void onPreRender();
void onMouseDown(const GuiEvent &event);
void onRightMouseDown(const GuiEvent & event);
void onRightMouseUp(const GuiEvent & event);
void setInstantGroup(SimObject * obj);
void inspectObject(SimObject * obj);
void selectObject(SimObject * obj);
void unselectObject(SimObject * obj);
void toggleSelected(SimObject * obj);
void clearSelected();
void setSelected(SimObject *selObj);
void onRenderCell(Point2I offset, Point2I cell, bool, bool);
};
#endif

233
gui/guiTypes.cc Normal file
View file

@ -0,0 +1,233 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/gFont.h"
#include "dgl/dgl.h"
#include "GUI/guiTypes.h"
#include "dgl/gBitmap.h"
#include "dgl/gTexManager.h"
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- //
GuiCursor::GuiCursor()
{
mHotSpot.set(0,0);
}
GuiCursor::~GuiCursor()
{
}
void GuiCursor::initPersistFields()
{
Parent::initPersistFields();
addField("hotSpot", TypePoint2I, Offset(mHotSpot, GuiCursor));
addField("bitmapName", TypeString, Offset(mBitmapName, GuiCursor));
}
bool GuiCursor::onAdd()
{
if(!Parent::onAdd())
return false;
mTextureHandle = TextureHandle(mBitmapName);
if(!mTextureHandle)
return false;
mExtent.set(mTextureHandle.getWidth(), mTextureHandle.getHeight());
Sim::getGuiDataGroup()->addObject(this);
return true;
}
void GuiCursor::onRemove()
{
Parent::onRemove();
}
static EnumTable::Enums alignEnums[] =
{
{ GuiControlProfile::LeftJustify, "left" },
{ GuiControlProfile::CenterJustify, "center" },
{ GuiControlProfile::RightJustify, "right" }
};
static EnumTable gAlignTable(3, &alignEnums[0]);
GuiControlProfile::GuiControlProfile(void) :
mFontColor(mFontColors[BaseColor]),
mFontColorHL(mFontColors[ColorHL]),
mFontColorNA(mFontColors[ColorNA]),
mFontColorSEL(mFontColors[ColorSEL])
{
mRefCount = 0;
GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject("GuiDefaultProfile"));
if (def)
{
mTabable = def->mTabable;
mCanKeyFocus = def->mCanKeyFocus;
mOpaque = def->mOpaque;
mFillColor = def->mFillColor;
mFillColorHL = def->mFillColorHL;
mFillColorNA = def->mFillColorNA;
mBorder = def->mBorder;
mBorderColor = def->mBorderColor;
mBorderColorHL = def->mBorderColorHL;
mBorderColorNA = def->mBorderColorNA;
// default font
mFontType = def->mFontType;
mFontSize = def->mFontSize;
for(U32 i = 0; i < 10; i++)
mFontColors[i] = def->mFontColors[i];
// default bitmap
mBitmapName = def->mBitmapName;
mBitmapBase = def->mBitmapBase;
mTextOffset = def->mTextOffset;
// default sound
mSoundButtonDown = def->mSoundButtonDown;
mSoundButtonOver = def->mSoundButtonOver;
//used by GuiTextCtrl
mModal = def->mModal;
mAlignment = def->mAlignment;
mAutoSizeWidth = def->mAutoSizeWidth;
mAutoSizeHeight= def->mAutoSizeHeight;
mReturnTab = def->mReturnTab;
mNumbersOnly = def->mNumbersOnly;
mCursorColor = def->mCursorColor;
}
}
GuiControlProfile::~GuiControlProfile()
{
}
void GuiControlProfile::initPersistFields()
{
Parent::initPersistFields();
addField("tab", TypeBool, Offset(mTabable, GuiControlProfile));
addField("canKeyFocus", TypeBool, Offset(mCanKeyFocus, GuiControlProfile));
addField("modal", TypeBool, Offset(mModal, GuiControlProfile));
addField("opaque", TypeBool, Offset(mOpaque, GuiControlProfile));
addField("fillColor", TypeColorI, Offset(mFillColor, GuiControlProfile));
addField("fillColorHL", TypeColorI, Offset(mFillColorHL, GuiControlProfile));
addField("fillColorNA", TypeColorI, Offset(mFillColorNA, GuiControlProfile));
addField("border", TypeBool, Offset(mBorder, GuiControlProfile));
addField("borderColor", TypeColorI, Offset(mBorderColor, GuiControlProfile));
addField("borderColorHL", TypeColorI, Offset(mBorderColorHL, GuiControlProfile));
addField("borderColorNA", TypeColorI, Offset(mBorderColorNA, GuiControlProfile));
addField("fontType", TypeString, Offset(mFontType, GuiControlProfile));
addField("fontSize", TypeS32, Offset(mFontSize, GuiControlProfile));
addField("fontColors", TypeColorI, Offset(mFontColors, GuiControlProfile), 10);
addField("fontColor", TypeColorI, Offset(mFontColors[BaseColor], GuiControlProfile));
addField("fontColorHL", TypeColorI, Offset(mFontColors[ColorHL], GuiControlProfile));
addField("fontColorNA", TypeColorI, Offset(mFontColors[ColorNA], GuiControlProfile));
addField("fontColorSEL", TypeColorI, Offset(mFontColors[ColorSEL], GuiControlProfile));
addField("justify", TypeEnum, Offset(mAlignment, GuiControlProfile), 1, &gAlignTable);
addField("textOffset", TypePoint2I, Offset(mTextOffset, GuiControlProfile));
addField("bitmapBase", TypeString, Offset(mBitmapBase, GuiControlProfile));
addField("autoSizeWidth", TypeBool, Offset(mAutoSizeWidth, GuiControlProfile));
addField("autoSizeHeight",TypeBool, Offset(mAutoSizeHeight, GuiControlProfile));
addField("returnTab", TypeBool, Offset(mReturnTab, GuiControlProfile));
addField("numbersOnly", TypeBool, Offset(mNumbersOnly, GuiControlProfile));
addField("cursorColor", TypeColorI, Offset(mCursorColor, GuiControlProfile));
addField("bitmap", TypeString, Offset(mBitmapName, GuiControlProfile));
addField("soundButtonDown", TypeAudioProfilePtr, Offset(mSoundButtonDown, GuiControlProfile));
addField("soundButtonOver", TypeAudioProfilePtr, Offset(mSoundButtonOver, GuiControlProfile));
}
bool GuiControlProfile::onAdd()
{
if(!Parent::onAdd())
return false;
Sim::getGuiDataGroup()->addObject(this);
return true;
}
void GuiControlProfile::incRefCount()
{
if(!mRefCount++)
{
//verify the font
mFont = GFont::create(mFontType, mFontSize);
AssertFatal(bool(mFont), "Failed to create the font.");
//verify the bitmap
mTextureHandle = TextureHandle(mBitmapName, BitmapKeepTexture);
AssertFatal(bool(mTextureHandle), "Profile has no bitmap");
}
AssertFatal(bool(mFont), "GuiControlProfile::incRefCount: invalid font");
AssertFatal(bool(mTextureHandle), "GuiControlProfile::incRefCount: invalid bitmap");
}
void GuiControlProfile::decRefCount()
{
AssertFatal(mRefCount, "GuiControlProfile::decRefCount: zero ref count");
if(!mRefCount)
return;
if(!--mRefCount)
{
mFont = NULL;
mTextureHandle = NULL;
}
}
static void setDataTypeGuiProfile(void *dptr, S32 argc, const char **argv, EnumTable *, BitSet32)
{
GuiControlProfile *profile = NULL;
if(argc == 1)
Sim::findObject(argv[0], profile);
AssertWarn(profile != NULL, avar("GuiControlProfile: requested gui profile (%s) does not exist.", argv[0]));
if(!profile)
profile = dynamic_cast<GuiControlProfile*>(Sim::findObject("GuiDefaultProfile"));
AssertFatal(profile != NULL, avar("GuiControlProfile: unable to find specified profile (%s) and GuiDefaultProfile does not exist!", argv[0]));
GuiControlProfile **obj = (GuiControlProfile **)dptr;
if((*obj) == profile)
return;
if(*obj)
(*obj)->decRefCount();
*obj = profile;
(*obj)->incRefCount();
}
static const char *getDataTypeGuiProfile(void *dptr, EnumTable *, BitSet32)
{
static char returnBuffer[256];
GuiControlProfile **obj = (GuiControlProfile**)dptr;
dSprintf(returnBuffer, sizeof(returnBuffer), "%s", *obj ? (*obj)->getName() : "");
return returnBuffer;
}
void RegisterGuiTypes(void)
{
Con::registerType(TypeGuiProfile, sizeof(GuiControlProfile *), getDataTypeGuiProfile, setDataTypeGuiProfile);
}

148
gui/guiTypes.h Normal file
View file

@ -0,0 +1,148 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUITYPES_H_
#define _GUITYPES_H_
#ifndef _GFONT_H_
#include "dgl/gFont.h"
#endif
#ifndef _COLOR_H_
#include "Core/color.h"
#endif
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
#ifndef _GTEXMANAGER_H_
#include "dgl/gTexManager.h"
#endif
#ifndef _PLATFORMAUDIO_H_
#include "Platform/platformAudio.h"
#endif
#ifndef _AUDIODATABLOCK_H_
#include "audio/audioDataBlock.h"
#endif
class GBitmap;
struct GuiEvent
{
U16 ascii; // ascii character code 'a', 'A', 'b', '*', etc (if device==keyboard) - possibly a uchar or something
U8 modifier; // SI_LSHIFT, etc
U8 keyCode; // for unprintables, 'tab', 'return', ...
Point2I mousePoint; // for mouse events
U8 mouseClickCount; // to determine double clicks, etc...
};
class GuiCursor : public SimObject
{
private:
typedef SimObject Parent;
StringTableEntry mBitmapName;
Point2I mHotSpot;
Point2I mExtent;
TextureHandle mTextureHandle;
public:
TextureHandle getTextureHandle() { return mTextureHandle; }
Point2I getHotSpot() { return mHotSpot; }
Point2I getExtent() { return mExtent; }
DECLARE_CONOBJECT(GuiCursor);
GuiCursor(void);
~GuiCursor(void);
static void initPersistFields();
bool onAdd(void);
void onRemove();
};
class GuiControlProfile : public SimObject
{
private:
typedef SimObject Parent;
public:
S32 mRefCount;
bool mTabable;
bool mCanKeyFocus;
bool mModal;
bool mOpaque;
ColorI mFillColor;
ColorI mFillColorHL;
ColorI mFillColorNA;
bool mBorder;
ColorI mBorderColor;
ColorI mBorderColorHL;
ColorI mBorderColorNA;
// font members
StringTableEntry mFontType;
S32 mFontSize;
enum {
BaseColor = 0,
ColorHL,
ColorNA,
ColorSEL,
ColorUser0,
ColorUser1,
ColorUser2,
ColorUser3,
ColorUser4,
ColorUser5,
};
ColorI mFontColors[10];
ColorI & mFontColor;
ColorI & mFontColorHL;
ColorI & mFontColorNA;
ColorI & mFontColorSEL;
Resource<GFont> mFont;
enum AlignmentType
{
LeftJustify,
RightJustify,
CenterJustify
};
AlignmentType mAlignment;
bool mAutoSizeWidth;
bool mAutoSizeHeight;
bool mReturnTab;
bool mNumbersOnly;
ColorI mCursorColor;
StringTableEntry mBitmapBase;
Point2I mTextOffset;
// bitmap members
StringTableEntry mBitmapName;
TextureHandle mTextureHandle;
// sound members
AudioProfile *mSoundButtonDown;
AudioProfile *mSoundButtonOver;
public:
DECLARE_CONOBJECT(GuiControlProfile);
GuiControlProfile();
~GuiControlProfile();
static void initPersistFields();
bool onAdd();
void incRefCount();
void decRefCount();
};
void RegisterGuiTypes(void);
#endif //_GUITYPES_H

231
gui/guiVoteCtrl.cc Normal file
View file

@ -0,0 +1,231 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "GUI/guiVoteCtrl.h"
GuiVoteCtrl::GuiVoteCtrl()
{
mYesProgress = 0.0f;
mNoProgress = 0.0f;
mQuorum = 0.5f;
mPassHash = 0.25f;
}
const char* GuiVoteCtrl::getScriptValue()
{
return NULL;
}
void GuiVoteCtrl::setScriptValue(const char *)
{
}
void GuiVoteCtrl::setQuorumValue(F32 value)
{
if(!value)
mQuorum = 0.0f;
else
mQuorum = value;
//validate the value
mQuorum = mClampF(mQuorum, 0.f, 1.f);
}
void GuiVoteCtrl::setPassValue(F32 value)
{
if(!value)
mPassHash = 0.0f;
else
mPassHash = value;
//validate the value
mPassHash = mClampF(mPassHash, 0.f, 1.f);
}
void GuiVoteCtrl::setYesValue(F32 value)
{
if(!value)
mYesProgress = 0.0f;
else
mYesProgress = value;
//validate the value
mYesProgress = mClampF(mYesProgress, 0.f, 1.f);
}
void GuiVoteCtrl::setNoValue(F32 value)
{
if(!value)
mNoProgress = 0.0f;
else
mNoProgress = value;
//validate the value
mNoProgress = mClampF(mNoProgress, 0.f, 1.f);
}
void GuiVoteCtrl::onPreRender()
{
}
void GuiVoteCtrl::onRender(Point2I offset, const RectI & /*updateRect*/, GuiControl * /*firstResponder*/)
{
RectI ctrlRect(offset, mBounds.extent);
RectI yesProgressRect = ctrlRect;
RectI noProgressRect = ctrlRect;
S32 yesWidth;
S32 noWidth;
ColorI fill;
//draw the "Yes" progress
if(mYesProgress < 1)
yesWidth = (S32)((F32)mBounds.extent.x * (1 - mYesProgress));
else
yesWidth = ctrlRect.extent.x;
if(yesWidth > 0)
{
yesProgressRect.point.y += 10;
yesProgressRect.point.x = ctrlRect.point.x;
yesProgressRect.extent.y -= 20;
if(mYesProgress < 1)
yesProgressRect.extent.x = ctrlRect.extent.x - yesWidth;
else
yesProgressRect.extent.x = ctrlRect.extent.x;
fill.set(0, 255, 0, 255);
if(mYesProgress >= mPassHash)
{
S32 time = (S32)Platform::getVirtualMilliseconds();
F32 alpha = F32(time % 500) / 250.0f;
if(alpha > 1)
alpha = 1.f - (alpha - 1.f);
fill.alpha *= alpha;
}
dglDrawRectFill(yesProgressRect, fill);
}
// draw the "No" progress
noWidth = (S32)((F32)mBounds.extent.x * mNoProgress);
fill.set(255, 0, 0, 255);
if(noWidth > 0)
{
noProgressRect.point.y += 10;
noProgressRect.point.x = ctrlRect.point.x + (S32)((F32)mBounds.extent.x * mYesProgress);
noProgressRect.extent.y -= 20;
noProgressRect.extent.x = noWidth;
if(mNoProgress >= ( 1 - mPassHash ))
{
S32 time = (S32)Platform::getVirtualMilliseconds();
F32 alpha = F32(time % 500) / 250.0f;
if(alpha > 1)
alpha = 1.f - (alpha - 1.f);
fill.alpha *= alpha;
}
dglDrawRectFill(noProgressRect, fill);
}
}
// console functions
////////////////////////////////////////////////////////////////
static const char* cGetQuorumValue(SimObject *obj, S32, const char **)
{
GuiVoteCtrl *ctrl = static_cast<GuiVoteCtrl*>(obj);
F32 quorum = ctrl->getQuorumValue();
char * ret = Con::getReturnBuffer(64);
dSprintf(ret, 64, "%f", quorum);
return ret;
}
static const char* cGetPassValue(SimObject *obj, S32, const char **)
{
GuiVoteCtrl *ctrl = static_cast<GuiVoteCtrl*>(obj);
F32 hash = ctrl->getPassValue();
char * ret = Con::getReturnBuffer(64);
dSprintf(ret, 64, "%f", hash);
return ret;
}
static const char* cGetYesValue(SimObject *obj, S32, const char **)
{
GuiVoteCtrl *ctrl = static_cast<GuiVoteCtrl*>(obj);
F32 yesValue = ctrl->getYesValue();
char * ret = Con::getReturnBuffer(64);
dSprintf(ret, 64, "%f", yesValue);
return ret;
}
static const char* cGetNoValue(SimObject *obj, S32, const char **)
{
GuiVoteCtrl *ctrl = static_cast<GuiVoteCtrl*>(obj);
F32 noValue = ctrl->getNoValue();
char * ret = Con::getReturnBuffer(64);
dSprintf(ret, 64, "%f", noValue);
return ret;
}
static void cSetQuorumValue(SimObject *obj, S32, const char **argv)
{
GuiVoteCtrl *ctrl = static_cast<GuiVoteCtrl*>(obj);
ctrl->setQuorumValue(dAtof(argv[2]));
}
static void cSetPassValue(SimObject *obj, S32, const char **argv)
{
GuiVoteCtrl *ctrl = static_cast<GuiVoteCtrl*>(obj);
ctrl->setPassValue(dAtof(argv[2]));
}
static void cSetYesValue(SimObject *obj, S32, const char **argv)
{
GuiVoteCtrl *ctrl = static_cast<GuiVoteCtrl*>(obj);
ctrl->setYesValue(dAtof(argv[2]));
}
static void cSetNoValue(SimObject *obj, S32, const char **argv)
{
GuiVoteCtrl *ctrl = static_cast<GuiVoteCtrl*>(obj);
ctrl->setNoValue(dAtof(argv[2]));
}
void GuiVoteCtrl::consoleInit()
{
Parent::consoleInit();
Con::addCommand("GuiVoteCtrl", "setQuorumValue", cSetQuorumValue, "ctrl.setQuorumValue(value)", 3, 3);
Con::addCommand("GuiVoteCtrl", "setPassValue", cSetPassValue, "ctrl.setPassValue(value)", 3, 3);
Con::addCommand("GuiVoteCtrl", "setYesValue", cSetYesValue, "ctrl.setYesValue(value)", 3, 3);
Con::addCommand("GuiVoteCtrl", "setNoValue", cSetNoValue, "ctrl.setNoValue(value)", 3, 3);
Con::addCommand("GuiVoteCtrl", "getQuorumValue", cGetQuorumValue, "ctrl.getQuorumValue()", 2, 2);
Con::addCommand("GuiVoteCtrl", "getPassValue", cGetPassValue, "ctrl.getPassValue()", 2, 2);
Con::addCommand("GuiVoteCtrl", "getYesValue", cGetYesValue, "ctrl.getYesValue()", 2, 2);
Con::addCommand("GuiVoteCtrl", "getNoValue", cGetNoValue, "ctrl.getNoValue()", 2, 2);
}

72
gui/guiVoteCtrl.h Normal file
View file

@ -0,0 +1,72 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIVOTECTRL_H_
#define _GUIVOTECTRL_H_
#ifndef _GUICONTROL_H_
#include "GUI/guiControl.h"
#endif
class GuiVoteCtrl : public GuiControl
{
private:
typedef GuiControl Parent;
F32 mNoProgress;
F32 mYesProgress;
F32 mQuorum;
F32 mPassHash;
public:
//creation methods
DECLARE_CONOBJECT(GuiVoteCtrl);
GuiVoteCtrl();
//console related methods
static void consoleInit();
virtual const char *getScriptValue();
virtual void setScriptValue(const char *value);
void onPreRender();
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
public:
void setPassValue(F32 value);
void setQuorumValue(F32 value);
void setYesValue(F32 value);
void setNoValue(F32 value);
F32 getPassValue();
F32 getQuorumValue();
F32 getYesValue();
F32 getNoValue();
};
inline F32 GuiVoteCtrl::getQuorumValue()
{
return mQuorum;
}
inline F32 GuiVoteCtrl::getPassValue()
{
return mPassHash;
}
inline F32 GuiVoteCtrl::getYesValue()
{
return mYesProgress;
}
inline F32 GuiVoteCtrl::getNoValue()
{
return mNoProgress;
}
#endif

582
gui/guiWindowCtrl.cc Normal file
View file

@ -0,0 +1,582 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "console/consoleTypes.h"
#include "console/console.h"
#include "dgl/dgl.h"
#include "GUI/guiCanvas.h"
#include "GUI/guiWindowCtrl.h"
GuiWindowCtrl::GuiWindowCtrl(void)
{
mResizeWidth = true;
mResizeHeight = true;
mCanMove = true;
mCanClose = true;
mCanMinimize = true;
mCanMaximize = true;
mTitleHeight = 20;
mResizeRightWidth = 10;
mResizeBottomHeight = 10;
mCloseCommand = StringTable->insert("");
mMinimized = false;
mMaximized = false;
mMouseMovingWin = false;
mMouseResizeWidth = false;
mMouseResizeHeight = false;
mBounds.extent.set(100, 200);
mMinSize.set(50, 50);
mMinimizeIndex = -1;
mTabIndex = -1;
RectI closeRect(80, 2, 16, 16);
mCloseButton = closeRect;
closeRect.point.x -= 18;
mMaximizeButton = closeRect;
closeRect.point.x -= 18;
mMinimizeButton = closeRect;
//other defaults
mActive = true;
}
void GuiWindowCtrl::initPersistFields()
{
Parent::initPersistFields();
addField("resizeWidth", TypeBool, Offset(mResizeWidth, GuiWindowCtrl));
addField("resizeHeight", TypeBool, Offset(mResizeHeight, GuiWindowCtrl));
addField("canMove", TypeBool, Offset(mCanMove, GuiWindowCtrl));
addField("canClose", TypeBool, Offset(mCanClose, GuiWindowCtrl));
addField("canMinimize", TypeBool, Offset(mCanMinimize, GuiWindowCtrl));
addField("canMaximize", TypeBool, Offset(mCanMaximize, GuiWindowCtrl));
addField("minSize", TypePoint2I, Offset(mMinSize, GuiWindowCtrl));
addField("closeCommand", TypeString, Offset(mCloseCommand, GuiWindowCtrl));
}
void GuiWindowCtrl::consoleInit()
{
}
bool GuiWindowCtrl::isMinimized(S32 &index)
{
index = mMinimizeIndex;
return mMinimized && mVisible;
}
bool GuiWindowCtrl::onWake()
{
if (! Parent::onWake())
return false;
//get the texture for the close, minimize, and maximize buttons
mTextureHandle = mProfile->mTextureHandle;
bool result = createBitmapArray(mTextureHandle.getBitmap(), mBitmapBounds, BmpStates, BmpCount);
AssertFatal(result, "Failed to create the bitmap array");
mTitleHeight = mBitmapBounds[BmpStates * BmpClose].extent.y + 6;
S32 buttonWidth = mBitmapBounds[BmpStates * BmpClose].extent.x;
mResizeRightWidth = mTitleHeight / 2;
mResizeBottomHeight = mTitleHeight / 2;
//set the button coords
RectI closeRect(mBounds.extent.x - buttonWidth - 3, 2, mTitleHeight - 6, buttonWidth);
mCloseButton = closeRect;
closeRect.point.x -= buttonWidth + 2;
mMaximizeButton = closeRect;
closeRect.point.x -= buttonWidth + 2;
mMinimizeButton = closeRect;
//set the tab index
mTabIndex = -1;
GuiControl *parent = getParent();
if (parent && mFirstResponder)
{
mTabIndex = 0;
//count the number of windows preceeding this one
iterator i;
for (i = parent->begin(); i != parent->end(); i++)
{
GuiWindowCtrl *ctrl = dynamic_cast<GuiWindowCtrl *>(*i);
if (ctrl)
{
if (ctrl == this) break;
else if (ctrl->mFirstResponder) mTabIndex++;
}
}
}
return true;
}
GuiControl* GuiWindowCtrl::findHitControl(const Point2I &pt, S32 initialLayer)
{
if (! mMinimized)
return Parent::findHitControl(pt, initialLayer);
else
return this;
}
void GuiWindowCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
{
Parent::resize(newPosition, newExtent);
//set the button coords
S32 buttonWidth = mBitmapBounds[BmpStates * BmpClose].extent.x;
RectI closeRect(mBounds.extent.x - buttonWidth - 3, 2, mTitleHeight - 6, buttonWidth);
mCloseButton = closeRect;
closeRect.point.x -= buttonWidth + 2;
mMaximizeButton = closeRect;
closeRect.point.x -= buttonWidth + 2;
mMinimizeButton = closeRect;
}
void GuiWindowCtrl::onMouseDown(const GuiEvent &event)
{
setUpdate();
mOrigBounds = mBounds;
mPressClose = false;
mPressMaximize = false;
mPressMinimize = false;
mMouseDownPosition = event.mousePoint;
Point2I localPoint = globalToLocalCoord(event.mousePoint);
//select this window - move it to the front, and set the first responder
selectWindow();
//if we clicked within the title bar
if (localPoint.y < mTitleHeight)
{
//if we clicked on the close button
if (mCloseButton.pointInRect(localPoint))
{
mPressClose = mCanClose;
}
else if (mMaximizeButton.pointInRect(localPoint))
{
mPressMaximize = mCanMaximize;
}
else if (mMinimizeButton.pointInRect(localPoint))
{
mPressMinimize = mCanMinimize;
}
//else we clicked within the title
else
{
mMouseMovingWin = mCanMove;
mMouseResizeWidth = false;
mMouseResizeHeight = false;
}
}
else
{
mMouseMovingWin = false;
//see if we clicked on the right edge
if (localPoint.x > mBounds.extent.x - mResizeRightWidth)
{
mMouseResizeWidth = true;
}
//see if we clicked on the bottom edge (as well)
if (localPoint.y > mBounds.extent.y - mResizeBottomHeight)
{
mMouseResizeHeight = true;
}
}
if (mMouseMovingWin || mMouseResizeWidth || mMouseResizeHeight ||
mPressClose || mPressMaximize || mPressMinimize)
{
mouseLock();
}
else
{
GuiControl *ctrl = findHitControl(event.mousePoint);
if (ctrl && ctrl != this)
{
ctrl->onMouseDown(event);
}
}
}
void GuiWindowCtrl::onMouseDragged(const GuiEvent &event)
{
GuiControl *parent = getParent();
GuiCanvas *root = getRoot();
if (! root) return;
Point2I deltaMousePosition = event.mousePoint - mMouseDownPosition;
Point2I newPosition = mBounds.point;
Point2I newExtent = mBounds.extent;
bool update = false;
if (mMouseMovingWin && parent)
{
newPosition.x = getMax(0, getMin(parent->mBounds.extent.x - mBounds.extent.x, mOrigBounds.point.x + deltaMousePosition.x));
newPosition.y = getMax(0, getMin(parent->mBounds.extent.y - mBounds.extent.y, mOrigBounds.point.y + deltaMousePosition.y));
update = true;
}
else
{
if (mMouseResizeWidth && parent)
{
newExtent.x = getMax(0, getMax(mMinSize.x, getMin(parent->mBounds.extent.x, mOrigBounds.extent.x + deltaMousePosition.x)));
update = true;
}
if (mMouseResizeHeight && parent)
{
newExtent.y = getMax(0, getMax(mMinSize.y, getMin(parent->mBounds.extent.y, mOrigBounds.extent.y + deltaMousePosition.y)));
update = true;
}
}
if (update)
{
Point2I pos = parent->localToGlobalCoord(mBounds.point);
root->addUpdateRegion(pos, mBounds.extent);
resize(newPosition, newExtent);
}
}
void GuiWindowCtrl::onMouseUp(const GuiEvent &event)
{
event;
mouseUnlock();
mMouseMovingWin = false;
mMouseResizeWidth = false;
mMouseResizeHeight = false;
GuiControl *parent = getParent();
if (! parent)
return;
//see if we take an action
Point2I localPoint = globalToLocalCoord(event.mousePoint);
if (mPressClose && mCloseButton.pointInRect(localPoint))
{
Con::evaluate(mCloseCommand);
}
else if (mPressMaximize)
{
if (mMaximized)
{
//resize to the previous position and extent, bounded by the parent
resize(Point2I(getMax(0, getMin(parent->mBounds.extent.x - mStandardBounds.extent.x, mStandardBounds.point.x)),
getMax(0, getMin(parent->mBounds.extent.y - mStandardBounds.extent.y, mStandardBounds.point.y))),
mStandardBounds.extent);
//set the flag
mMaximized = false;
}
else
{
//only save the position if we're not minimized
if (! mMinimized)
{
mStandardBounds = mBounds;
}
else
{
mMinimized = false;
}
//resize to fit the parent
resize(Point2I(0, 0), parent->mBounds.extent);
//set the flag
mMaximized = true;
}
}
else if (mPressMinimize)
{
if (mMinimized)
{
//resize to the previous position and extent, bounded by the parent
resize(Point2I(getMax(0, getMin(parent->mBounds.extent.x - mStandardBounds.extent.x, mStandardBounds.point.x)),
getMax(0, getMin(parent->mBounds.extent.y - mStandardBounds.extent.y, mStandardBounds.point.y))),
mStandardBounds.extent);
//set the flag
mMinimized = false;
}
else
{
if (parent->mBounds.extent.x < 100 || parent->mBounds.extent.y < mTitleHeight + 3)
return;
//only save the position if we're not maximized
if (! mMaximized)
{
mStandardBounds = mBounds;
}
else
{
mMaximized = false;
}
//first find the lowest unused minimized index up to 32 minimized windows
U32 indexMask = 0;
iterator i;
S32 count = 0;
for (i = parent->begin(); i != parent->end() && count < 32; i++)
{
count++;
S32 index;
GuiWindowCtrl *ctrl = dynamic_cast<GuiWindowCtrl *>(*i);
if (ctrl && ctrl->isMinimized(index))
{
indexMask |= (1 << index);
}
}
//now find the first unused bit
for (count = 0; count < 32; count++)
{
if (! (indexMask & (1 << count))) break;
}
//if we have more than 32 minimized windows, use the first position
count = getMax(0, count);
//this algorithm assumes all window have the same title height, and will minimize to 98 pix
Point2I newExtent(98, mTitleHeight);
//first, how many can fit across
S32 numAcross = getMax(1, (parent->mBounds.extent.x / newExtent.x + 2));
//find the new "mini position"
Point2I newPosition;
newPosition.x = (count % numAcross) * (newExtent.x + 2) + 2;
newPosition.y = parent->mBounds.extent.y - (((count / numAcross) + 1) * (newExtent.y + 2)) - 2;
//find the minimized position and extent
resize(newPosition, newExtent);
//set the index so other windows will not try to minimize to the same location
mMinimizeIndex = count;
//set the flag
mMinimized = true;
}
}
}
GuiControl *GuiWindowCtrl::findNextTabable(GuiControl *curResponder, bool firstCall)
{
//set the global if this is the first call (directly from the canvas)
if (firstCall)
{
GuiControl::gCurResponder = NULL;
}
//if the window does not already contain the first responder, return false
//ie. Can't tab into or out of a window
if (! ControlIsChild(curResponder))
{
return NULL;
}
//loop through, checking each child to see if it is the one that follows the firstResponder
GuiControl *tabCtrl = NULL;
iterator i;
for (i = begin(); i != end(); i++)
{
GuiControl *ctrl = static_cast<GuiControl *>(*i);
tabCtrl = ctrl->findNextTabable(curResponder, false);
if (tabCtrl) break;
}
//to ensure the tab cycles within the current window...
if (! tabCtrl)
{
tabCtrl = findFirstTabable();
}
mFirstResponder = tabCtrl;
return tabCtrl;
}
GuiControl *GuiWindowCtrl::findPrevTabable(GuiControl *curResponder, bool firstCall)
{
if (firstCall)
{
GuiControl::gPrevResponder = NULL;
}
//if the window does not already contain the first responder, return false
//ie. Can't tab into or out of a window
if (! ControlIsChild(curResponder))
{
return NULL;
}
//loop through, checking each child to see if it is the one that follows the firstResponder
GuiControl *tabCtrl = NULL;
iterator i;
for (i = begin(); i != end(); i++)
{
GuiControl *ctrl = static_cast<GuiControl *>(*i);
tabCtrl = ctrl->findPrevTabable(curResponder, false);
if (tabCtrl) break;
}
//to ensure the tab cycles within the current window...
if (! tabCtrl)
{
tabCtrl = findLastTabable();
}
mFirstResponder = tabCtrl;
return tabCtrl;
}
bool GuiWindowCtrl::onKeyDown(const GuiEvent &event)
{
//if this control is a dead end, kill the event
if ((! mVisible) || (! mActive) || (! mAwake)) return true;
if ((event.keyCode == KEY_TAB) && (event.modifier & SI_CTRL))
{
//find the next sibling window, and select it
GuiControl *parent = getParent();
if (parent)
{
GuiWindowCtrl *firstWindow = NULL;
iterator i;
for (i = parent->begin(); i != parent->end(); i++)
{
GuiWindowCtrl *ctrl = dynamic_cast<GuiWindowCtrl *>(*i);
if (ctrl && ctrl->getTabIndex() == mTabIndex + 1)
{
ctrl->selectWindow();
return true;
}
else if (ctrl && ctrl->getTabIndex() == 0)
{
firstWindow = ctrl;
}
}
//recycle from the beginning
if (firstWindow != this)
{
firstWindow->selectWindow();
return true;
}
}
}
return Parent::onKeyDown(event);
}
void GuiWindowCtrl::selectWindow(void)
{
//first make sure this window is the front most of its siblings
GuiControl *parent = getParent();
if (parent)
{
parent->bringObjectToFront(this);
}
//also set the first responder to be the one within this window
setFirstResponder(mFirstResponder);
}
void GuiWindowCtrl::drawWinRect(const RectI &myRect)
{
Point2I bl = myRect.point;
Point2I tr;
tr.x = myRect.point.x + myRect.extent.x - 1;
tr.y = myRect.point.y + myRect.extent.y - 1;
dglDrawRectFill(myRect, mProfile->mFillColor);
dglDrawLine(Point2I(bl.x + 1, tr.y), Point2I(bl.x + 1, bl.y), ColorI(255, 255, 255));
dglDrawLine(Point2I(bl.x, tr.y + 1), Point2I(tr.x, tr.y + 1), ColorI(255, 255, 255));
dglDrawRect(myRect, ColorI(0, 0, 0));
}
void GuiWindowCtrl::onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder)
{
//draw the outline
RectI winRect;
winRect.point = offset;
winRect.extent = mBounds.extent;
if (mProfile->mOpaque)
{
drawWinRect(winRect);
//title bar
ColorI titleColor = (! firstResponder || ControlIsChild(firstResponder)) ?
mProfile->mFillColorHL : mProfile->mFillColorNA;
RectI titleBarRect = winRect;
titleBarRect.extent.y = mTitleHeight;
dglDrawRectFill(titleBarRect, titleColor);
}
//outline the window
if (mProfile->mBorder)
dglDrawRect(winRect, mProfile->mBorderColor);
//draw the title
dglSetBitmapModulation(mProfile->mFontColor);
S32 fontHeight = mFont->getHeight();
dglDrawText(mFont, Point2I(offset.x + 4, offset.y + ((mTitleHeight - fontHeight) / 2)), mText);
GuiCanvas *root = getRoot();
AssertFatal(root, "Unable to get the root Canvas.");
Point2I localPoint = globalToLocalCoord(root->getCursorPos());
//draw the close button
Point2I tempUL;
Point2I tempLR;
S32 bmp = BmpStates * BmpClose;
if (! mCanClose)
bmp += BmpDisabled;
else if (mCloseButton.pointInRect(localPoint) && root->mouseButtonDown())
bmp += BmpHilite;
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, offset + mCloseButton.point, mBitmapBounds[bmp]);
//draw the maximize button
if (mMaximized)
bmp = BmpStates * BmpNormal;
else
bmp = BmpStates * BmpMaximize;
if (! mCanMaximize)
bmp += BmpDisabled;
else if (mMaximizeButton.pointInRect(localPoint) && root->mouseButtonDown())
bmp += BmpHilite;
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, offset + mMaximizeButton.point, mBitmapBounds[bmp]);
//draw the minimize button
if (mMinimized)
bmp = BmpStates * BmpNormal;
else
bmp = BmpStates * BmpMinimize;
if (! mCanMinimize)
bmp += BmpDisabled;
else if (mMinimizeButton.pointInRect(localPoint) && root->mouseButtonDown())
bmp += BmpHilite;
dglClearBitmapModulation();
dglDrawBitmapSR(mTextureHandle, offset + mMinimizeButton.point, mBitmapBounds[bmp]);
if (! mMinimized)
{
//render the children
renderChildControls(offset, updateRect, firstResponder);
}
}

109
gui/guiWindowCtrl.h Normal file
View file

@ -0,0 +1,109 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _GUIWINDOWCTRL_H_
#define _GUIWINDOWCTRL_H_
#ifndef _GUITEXTCTRL_H_
#include "GUI/guiTextCtrl.h"
#endif
class GuiWindowCtrl : public GuiTextCtrl
{
private:
typedef GuiTextCtrl Parent;
bool mResizeWidth;
bool mResizeHeight;
bool mCanMove;
bool mCanClose;
bool mCanMinimize;
bool mCanMaximize;
bool mPressClose;
bool mPressMinimize;
bool mPressMaximize;
Point2I mMinSize;
StringTableEntry mCloseCommand;
S32 mTitleHeight;
S32 mResizeRightWidth;
S32 mResizeBottomHeight;
bool mMouseMovingWin;
bool mMouseResizeWidth;
bool mMouseResizeHeight;
bool mMinimized;
bool mMaximized;
Point2I mMouseDownPosition;
RectI mOrigBounds;
RectI mStandardBounds;
RectI mCloseButton;
RectI mMinimizeButton;
RectI mMaximizeButton;
S32 mMinimizeIndex;
S32 mTabIndex;
protected:
enum BitmapIndices
{
BmpClose,
BmpMaximize,
BmpNormal,
BmpMinimize,
BmpCount
};
enum BitmapStates
{
BmpDefault = 0,
BmpHilite,
BmpDisabled,
BmpStates
};
RectI mBitmapBounds[BmpStates * BmpCount]; //bmp is [3*n], bmpHL is [3*n + 1], bmpNA is [3*n + 2]
TextureHandle mTextureHandle;
void drawWinRect(const RectI &myRect);
public:
GuiWindowCtrl();
DECLARE_CONOBJECT(GuiWindowCtrl);
static void initPersistFields();
static void consoleInit();
bool onWake();
bool isMinimized(S32 &index);
void setFont(S32 fntTag);
GuiControl* findHitControl(const Point2I &pt, S32 initialLayer = -1);
void resize(const Point2I &newPosition, const Point2I &newExtent);
void onMouseDown(const GuiEvent &event);
void onMouseDragged(const GuiEvent &event);
void onMouseUp(const GuiEvent &event);
//only cycle tabs through the current window, so overwrite the method
GuiControl* findNextTabable(GuiControl *curResponder, bool firstCall = true);
GuiControl* findPrevTabable(GuiControl *curResponder, bool firstCall = true);
bool onKeyDown(const GuiEvent &event);
S32 getTabIndex(void) { return mTabIndex; }
void selectWindow(void);
void onRender(Point2I offset, const RectI &updateRect, GuiControl *firstResponder);
};
#endif //_GUI_WINDOW_CTRL_H

408
gui/messageVector.cc Normal file
View file

@ -0,0 +1,408 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#include "GUI/messageVector.h"
#include "Core/fileObject.h"
IMPLEMENT_CONOBJECT(MessageVector);
//-------------------------------------- Console functions
namespace {
void cMVClear(SimObject *obj, S32, const char **)
{
MessageVector* pMV = static_cast<MessageVector*>(obj);
pMV->clear();
}
void cMVPushBackLine(SimObject* obj, S32 argc, const char** argv)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
U32 tag = 0;
if (argc == 4)
tag = dAtoi(argv[3]);
pMV->pushBackLine(argv[2], tag);
}
bool cMVPopBackLine(SimObject* obj, S32, const char**)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
if (pMV->getNumLines() == 0) {
Con::errorf(ConsoleLogEntry::General, "MessageVector::popBackLine(): underflow");
return false;
}
pMV->popBackLine();
return true;
}
void cMVPushFrontLine(SimObject* obj, S32 argc, const char** argv)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
U32 tag = 0;
if (argc == 4)
tag = dAtoi(argv[3]);
pMV->pushFrontLine(argv[2], tag);
}
bool cMVPopFrontLine(SimObject* obj, S32, const char**)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
if (pMV->getNumLines() == 0) {
Con::errorf(ConsoleLogEntry::General, "MessageVector::popFrontLine(): underflow");
return false;
}
pMV->popFrontLine();
return true;
}
bool cMVInsertLine(SimObject* obj, S32 argc, const char** argv)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
U32 pos = U32(dAtoi(argv[2]));
if (pos > pMV->getNumLines())
return false;
S32 tag = 0;
if (argc == 5)
tag = dAtoi(argv[4]);
pMV->insertLine(pos, argv[3], tag);
return true;
}
bool cMVDeleteLine(SimObject* obj, S32, const char** argv)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
U32 pos = U32(dAtoi(argv[2]));
if (pos >= pMV->getNumLines())
return false;
pMV->deleteLine(pos);
return true;
}
void cMVDump(SimObject* obj, S32 argc, const char** argv)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
if ( argc == 4 )
pMV->dump( argv[2], argv[3] );
else
pMV->dump( argv[2] );
}
S32 cMVGetNumLines(SimObject* obj, S32, const char**)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
return pMV->getNumLines();
}
const char *cMVGetLineTextByTag(SimObject *obj, S32, const char **argv)
{
MessageVector* pMV = static_cast<MessageVector*>(obj);
U32 tag = dAtoi(argv[2]);
for(U32 i = 0; i < pMV->getNumLines(); i++)
if(pMV->getLine(i).messageTag == tag)
return pMV->getLine(i).message;
return "";
}
S32 cMVGetLineIndexByTag(SimObject *obj, S32, const char **argv)
{
MessageVector* pMV = static_cast<MessageVector*>(obj);
U32 tag = dAtoi(argv[2]);
for(U32 i = 0; i < pMV->getNumLines(); i++)
if(pMV->getLine(i).messageTag == tag)
return i;
return -1;
}
const char* cMVGetLineText(SimObject* obj, S32, const char** argv)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
U32 pos = U32(dAtoi(argv[2]));
if (pos >= pMV->getNumLines()) {
Con::errorf(ConsoleLogEntry::General, "MessageVector::getLineText(con): out of bounds line");
return "";
}
return pMV->getLine(pos).message;
}
S32 cMVGetLineTag(SimObject* obj, S32, const char** argv)
{
AssertFatal(dynamic_cast<MessageVector*>(obj) != NULL, "Error, how did a non-MessageVector get here?");
MessageVector* pMV = static_cast<MessageVector*>(obj);
U32 pos = U32(dAtoi(argv[2]));
if (pos >= pMV->getNumLines()) {
Con::errorf(ConsoleLogEntry::General, "MessageVector::getLineTag(con): out of bounds line");
return 0;
}
return pMV->getLine(pos).messageTag;
}
} // namespace {}
//--------------------------------------------------------------------------
MessageVector::MessageVector()
{
VECTOR_SET_ASSOCIATION(mMessageLines);
VECTOR_SET_ASSOCIATION(mSpectators);
}
//--------------------------------------------------------------------------
MessageVector::~MessageVector()
{
for (U32 i = 0; i < mMessageLines.size(); i++) {
char* pDelete = const_cast<char*>(mMessageLines[i].message);
delete [] pDelete;
mMessageLines[i].message = 0;
mMessageLines[i].messageTag = 0xFFFFFFFF;
}
mMessageLines.clear();
}
//--------------------------------------------------------------------------
void MessageVector::initPersistFields()
{
Parent::initPersistFields();
}
//--------------------------------------------------------------------------
void MessageVector::consoleInit()
{
Con::addCommand("MessageVector", "pushBackLine", cMVPushBackLine, "[MessageVector].pushBackLine(\"Message\"[, Tag=0])", 3, 4);
Con::addCommand("MessageVector", "popBackLine", cMVPopBackLine, "[MessageVector].popBackLine()", 2, 2);
Con::addCommand("MessageVector", "pushFrontLine", cMVPushFrontLine, "[MessageVector].pushFrontLine(\"Message\"[, Tag=0])", 3, 4);
Con::addCommand("MessageVector", "popFrontLine", cMVPopFrontLine, "[MessageVector].popFrontLine()", 2, 2);
Con::addCommand("MessageVector", "insertLine", cMVInsertLine, "[MessageVector].insertLine(InsertPos, \"Message\"[, Tag=0])", 4, 5);
Con::addCommand("MessageVector", "deleteLine", cMVDeleteLine, "[MessageVector].deleteLine(DeletePos)", 3, 3);
Con::addCommand("MessageVector", "clear", cMVClear, "[MessageVector].clear()", 2, 2);
Con::addCommand("MessageVector", "dump", cMVDump, "[MessageVector].dump(filename{, header})", 3, 4);
Con::addCommand("MessageVector", "getNumLines", cMVGetNumLines, "[MessageVector].getNumLines()", 2, 2);
Con::addCommand("MessageVector", "getLineText", cMVGetLineText, "[MessageVector].getLineText(Line)", 3, 3);
Con::addCommand("MessageVector", "getLineTag", cMVGetLineTag, "[MessageVector].getLineTag(Line)", 3, 3);
Con::addCommand("MessageVector", "getLineTextByTag", cMVGetLineTextByTag, "[MessageVector].getLineTextByTag(Tag)", 3, 3);
Con::addCommand("MessageVector", "getLineIndexByTag", cMVGetLineIndexByTag, "[MessageVector].getLineIndexByTag(Tag)", 3, 3);
}
//--------------------------------------------------------------------------
bool MessageVector::onAdd()
{
return Parent::onAdd();
}
//--------------------------------------------------------------------------
void MessageVector::onRemove()
{
// Delete all the lines from the observers, and then forcibly detatch ourselves
//
for (S32 i = mMessageLines.size() - 1; i >= 0; i--)
spectatorMessage(LineDeleted, i);
spectatorMessage(VectorDeletion, 0);
mSpectators.clear();
Parent::onRemove();
}
//--------------------------------------------------------------------------
void MessageVector::pushBackLine(const char* newMessage, const S32 newMessageTag)
{
insertLine(mMessageLines.size(), newMessage, newMessageTag);
}
void MessageVector::popBackLine()
{
AssertFatal(mMessageLines.size() != 0, "MessageVector::popBackLine: nothing to pop!");
if (mMessageLines.size() == 0)
return;
deleteLine(mMessageLines.size() - 1);
}
void MessageVector::clear()
{
while(mMessageLines.size())
deleteLine(mMessageLines.size() - 1);
}
//--------------------------------------------------------------------------
void MessageVector::pushFrontLine(const char* newMessage, const S32 newMessageTag)
{
insertLine(0, newMessage, newMessageTag);
}
void MessageVector::popFrontLine()
{
AssertFatal(mMessageLines.size() != 0, "MessageVector::popBackLine: nothing to pop!");
if (mMessageLines.size() == 0)
return;
deleteLine(0);
}
//--------------------------------------------------------------------------
void MessageVector::insertLine(const U32 position,
const char* newMessage,
const S32 newMessageTag)
{
AssertFatal(position >= 0 && position <= mMessageLines.size(), "MessageVector::insertLine: out of range position!");
AssertFatal(newMessage != NULL, "Error, no message to insert!");
U32 len = dStrlen(newMessage) + 1;
char* copy = new char[len];
dStrcpy(copy, newMessage);
mMessageLines.insert(position);
mMessageLines[position].message = copy;
mMessageLines[position].messageTag = newMessageTag;
// Notify of insert
spectatorMessage(LineInserted, position);
}
//--------------------------------------------------------------------------
void MessageVector::deleteLine(const U32 position)
{
AssertFatal(position >= 0 && position < mMessageLines.size(), "MessageVector::deleteLine: out of range position!");
char* pDelete = const_cast<char*>(mMessageLines[position].message);
delete [] pDelete;
mMessageLines[position].message = NULL;
mMessageLines[position].messageTag = 0xFFFFFFFF;
mMessageLines.erase(position);
// Notify of delete
spectatorMessage(LineDeleted, position);
}
//--------------------------------------------------------------------------
bool MessageVector::dump( const char* filename, const char* header )
{
Con::printf( "Dumping message vector %s to %s...", getName(), filename );
FileObject file;
if ( !file.openForWrite( filename ) )
return( false );
// If passed a header line, write it out first:
if ( header )
file.writeLine( (const U8*) header );
// First write out the record count:
char* lineBuf = (char*) dMalloc( 10 );
dSprintf( lineBuf, 10, "%d", mMessageLines.size() );
file.writeLine( (const U8*) lineBuf );
// Write all of the lines of the message vector:
U32 len;
for ( U32 i = 0; i < mMessageLines.size(); i++ )
{
len = ( dStrlen( mMessageLines[i].message ) * 2 ) + 10;
lineBuf = (char*) dRealloc( lineBuf, len );
dSprintf( lineBuf, len, "%d ", mMessageLines[i].messageTag );
expandEscape( lineBuf + dStrlen( lineBuf ), mMessageLines[i].message );
file.writeLine( (const U8*) lineBuf );
}
file.close();
return( true );
}
//--------------------------------------------------------------------------
void MessageVector::registerSpectator(SpectatorCallback callBack, U32 spectatorKey)
{
AssertFatal(callBack != NULL, "Error, must have a callback!");
// First, make sure that this hasn't been registered already...
U32 i;
for (i = 0; i < mSpectators.size(); i++) {
AssertFatal(mSpectators[i].key != spectatorKey, "Error, spectator key already registered!");
if (mSpectators[i].key == spectatorKey)
return;
}
mSpectators.increment();
mSpectators.last().callback = callBack;
mSpectators.last().key = spectatorKey;
// Need to message this spectator of all the lines currently inserted...
for (i = 0; i < mMessageLines.size(); i++) {
(*mSpectators.last().callback)(mSpectators.last().key,
LineInserted, i);
}
}
void MessageVector::unregisterSpectator(U32 spectatorKey)
{
for (U32 i = 0; i < mSpectators.size(); i++) {
if (mSpectators[i].key == spectatorKey) {
// Need to message this spectator of all the lines currently inserted...
for (S32 j = mMessageLines.size() - 1; j >= 0 ; j--) {
(*mSpectators[i].callback)(mSpectators[i].key,
LineDeleted, j);
}
mSpectators.erase(i);
return;
}
}
AssertFatal(false, "MessageVector::unregisterSpectator: tried to unregister a spectator that isn't subscribed!");
Con::errorf(ConsoleLogEntry::General,
"MessageVector::unregisterSpectator: tried to unregister a spectator that isn't subscribed!");
}
void MessageVector::spectatorMessage(MessageCode code, const U32 arg)
{
for (U32 i = 0; i < mSpectators.size(); i++) {
(*mSpectators[i].callback)(mSpectators[i].key,
code, arg);
}
}

108
gui/messageVector.h Normal file
View file

@ -0,0 +1,108 @@
//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifndef _MESSAGEVECTOR_H_
#define _MESSAGEVECTOR_H_
#ifndef _PLATFORM_H_
#include "Platform/platform.h"
#endif
#ifndef _TVECTOR_H_
#include "Core/tVector.h"
#endif
#ifndef _SIMBASE_H_
#include "console/simBase.h"
#endif
class MessageVector : public SimObject
{
typedef SimObject Parent;
//-------------------------------------- Public interface...
public:
MessageVector();
~MessageVector();
public:
struct MessageLine {
char* message;
S32 messageTag;
};
// Spectator registration...
public:
enum MessageCode {
LineInserted = 0,
LineDeleted = 1,
VectorDeletion = 2
};
typedef void (*SpectatorCallback)(const U32 spectatorKey,
const MessageCode code,
const U32 argument);
void registerSpectator(SpectatorCallback, U32 spectatorKey);
void unregisterSpectator(U32 spectatorKey);
// Query functions
public:
U32 getNumLines() const;
const MessageLine& getLine(const U32 line) const;
// Mutators
public:
void pushBackLine(const char*, const S32);
void popBackLine();
void pushFrontLine(const char*, const S32);
void popFrontLine();
void clear();
virtual void insertLine(const U32 position, const char*, const S32);
virtual void deleteLine(const U32);
bool dump( const char* filename, const char* header = NULL );
//-------------------------------------- Internal interface
protected:
bool onAdd();
void onRemove();
private:
struct SpectatorRef {
SpectatorCallback callback;
U32 key;
};
Vector<MessageLine> mMessageLines;
Vector<SpectatorRef> mSpectators;
void spectatorMessage(MessageCode, const U32 arg);
public:
DECLARE_CONOBJECT(MessageVector);
static void initPersistFields();
static void consoleInit();
};
//--------------------------------------------------------------------------
inline U32 MessageVector::getNumLines() const
{
return mMessageLines.size();
}
//--------------------------------------------------------------------------
inline const MessageVector::MessageLine& MessageVector::getLine(const U32 line) const
{
AssertFatal(line < mMessageLines.size(), "MessageVector::getLine: out of bounds line index");
return mMessageLines[line];
}
#endif // _H_GUICHATVECTOR_