tge/engine/gui/editor/guiEditCtrl.cc
2017-04-17 06:17:10 -06:00

1162 lines
35 KiB
C++
Executable File

//-----------------------------------------------------------------------------
// Torque Game Engine
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "console/simBase.h"
#include "gui/core/guiCanvas.h"
#include "gui/editor/guiEditCtrl.h"
#include "platform/event.h"
#include "core/fileStream.h"
#include "gui/containers/guiScrollCtrl.h"
IMPLEMENT_CONOBJECT(GuiEditCtrl);
GuiEditCtrl::GuiEditCtrl()
{
VECTOR_SET_ASSOCIATION(mSelectedControls);
mActive = true;
mCurrentAddSet = NULL;
mGridSnap.set(0, 0);
mDragBeginPoint.set( -1,-1 );
mDragBeginPoints.clear();
mDefaultCursor = NULL;
mLeftRightCursor = NULL;
mUpDownCursor = NULL;
mNWSECursor = NULL;
mNESWCursor = NULL;
mMoveCursor = NULL;
}
ConsoleMethod( GuiEditCtrl, setRoot, void, 3, 3, "(GuiControl root)")
{
GuiControl *ctrl;
if(!Sim::findObject(argv[2], ctrl))
return;
object->setRoot(ctrl);
}
ConsoleMethod( GuiEditCtrl, addNewCtrl, void, 3, 3, "(GuiControl ctrl)")
{
GuiControl *ctrl;
if(!Sim::findObject(argv[2], ctrl))
return;
object->addNewControl(ctrl);
}
ConsoleMethod( GuiEditCtrl, addSelection, void, 3, 3, "selects a control.")
{
S32 id = dAtoi(argv[2]);
object->addSelection(id);
}
ConsoleMethod( GuiEditCtrl, removeSelection, void, 3, 3, "deselects a control.")
{
S32 id = dAtoi(argv[2]);
object->removeSelection(id);
}
ConsoleMethod( GuiEditCtrl, clearSelection, void, 2, 2, "Clear selected controls list.")
{
object->clearSelection();
}
ConsoleMethod( GuiEditCtrl, select, void, 3, 3, "(GuiControl ctrl)")
{
GuiControl *ctrl;
if(!Sim::findObject(argv[2], ctrl))
return;
object->setSelection(ctrl, false);
}
ConsoleMethod( GuiEditCtrl, setCurrentAddSet, void, 3, 3, "(GuiControl ctrl)")
{
GuiControl *addSet;
if (!Sim::findObject(argv[2], addSet))
{
Con::printf("%s(): Invalid control: %s", argv[0], argv[2]);
return;
}
object->setCurrentAddSet(addSet);
}
ConsoleMethod( GuiEditCtrl, toggle, void, 2, 2, "Toggle activation.")
{
object->setEditMode(! object->mActive);
}
ConsoleMethod( GuiEditCtrl, justify, void, 3, 3, "(int mode)" )
{
object->justifySelection((GuiEditCtrl::Justification)dAtoi(argv[2]));
}
ConsoleMethod( GuiEditCtrl, bringToFront, void, 2, 2, "")
{
object->bringToFront();
}
ConsoleMethod( GuiEditCtrl, pushToBack, void, 2, 2, "")
{
object->pushToBack();
}
ConsoleMethod( GuiEditCtrl, deleteSelection, void, 2, 2, "Delete the selected text.")
{
object->deleteSelection();
}
ConsoleMethod( GuiEditCtrl, moveSelection, void, 4, 4, "(int deltax, int deltay)")
{
object->moveSelection(Point2I(dAtoi(argv[2]), dAtoi(argv[3])));
}
ConsoleMethod( GuiEditCtrl, saveSelection, void, 3, 3, "(string fileName)")
{
object->saveSelection(argv[2]);
}
ConsoleMethod( GuiEditCtrl, loadSelection, void, 3, 3, "(string fileName)")
{
object->loadSelection(argv[2]);
}
ConsoleMethod( GuiEditCtrl, selectAll, void, 2, 2, "()")
{
object->selectAll();
}
ConsoleMethod( GuiEditCtrl, getSelected, const char *, 2, 2, "() - Gets the GUI control(s) the editor is currently selecting" )
{
char *returnText = Con::getReturnBuffer(128);
dStrcpy( returnText, "" );
const Vector<GuiControl *> *selected = object->getSelected();
for( Vector<GuiControl *>::const_iterator i = selected->begin(); i != selected->end(); i++ )
{
char temp[8];
dSprintf( temp, 8, "%d ", (*i)->getId() );
dStrcat( returnText, temp );
}
return returnText;
}
bool GuiEditCtrl::onWake()
{
if (! Parent::onWake())
return false;
// Set GUI Controls to DesignTime mode
GuiControl::smDesignTime = true;
GuiControl::smEditorHandle = this;
setEditMode(true);
return true;
}
void GuiEditCtrl::onSleep()
{
// Set GUI Controls to run time mode
GuiControl::smDesignTime = false;
GuiControl::smEditorHandle = NULL;
Parent::onSleep();
}
void GuiEditCtrl::setRoot(GuiControl *root)
{
mContentControl = root;
mCurrentAddSet = mContentControl;
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
}
enum GuiEditConstants {
GUI_BLACK = 0,
GUI_WHITE = 255,
NUT_SIZE = 3
};
// Sizing Cursors
bool GuiEditCtrl::initCursors()
{
if (mMoveCursor == NULL || mUpDownCursor == NULL || mLeftRightCursor == NULL || mDefaultCursor == NULL || mNWSECursor == NULL || mNESWCursor == NULL)
{
SimObject *obj;
obj = Sim::findObject("MoveCursor");
mMoveCursor = dynamic_cast<GuiCursor*>(obj);
obj = Sim::findObject("UpDownCursor");
mUpDownCursor = dynamic_cast<GuiCursor*>(obj);
obj = Sim::findObject("LeftRightCursor");
mLeftRightCursor = dynamic_cast<GuiCursor*>(obj);
obj = Sim::findObject("DefaultCursor");
mDefaultCursor = dynamic_cast<GuiCursor*>(obj);
obj = Sim::findObject("NESWCursor");
mNESWCursor = dynamic_cast<GuiCursor*>(obj);
obj = Sim::findObject("NWSECursor");
mNWSECursor = dynamic_cast<GuiCursor*>(obj);
obj = Sim::findObject("MoveCursor");
mMoveCursor = dynamic_cast<GuiCursor*>(obj);
return(mMoveCursor != NULL && mUpDownCursor != NULL && mLeftRightCursor != NULL && mDefaultCursor != NULL && mNWSECursor != NULL && mNESWCursor != NULL && mMoveCursor != NULL);
}
else
return(true);
}
void GuiEditCtrl::setEditMode(bool value)
{
mActive = value;
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
if (mActive && mAwake)
mCurrentAddSet = NULL;
}
void GuiEditCtrl::setCurrentAddSet(GuiControl *ctrl)
{
if (ctrl != mCurrentAddSet)
{
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
mCurrentAddSet = ctrl;
}
}
void GuiEditCtrl::clearSelection(void)
{
mSelectedControls.clear();
}
void GuiEditCtrl::setSelection(GuiControl *ctrl, bool inclusive)
{
//sanity check
if (! ctrl)
return;
if(mContentControl == ctrl)
{
mCurrentAddSet = ctrl;
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
}
else
{
// otherwise, we hit a new control...
GuiControl *newAddSet = ctrl->getParent();
//see if we should clear the old selection set
if (newAddSet != mCurrentAddSet || (! inclusive)) {
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
}
//set the selection
mCurrentAddSet = newAddSet;
if (!(ctrl->isLocked())) {
mSelectedControls.push_back(ctrl);
// Con::executef(this, 2, "onAddSelected", avar("%d", ctrl->getId()));
}
}
}
void GuiEditCtrl::addNewControl(GuiControl *ctrl)
{
if (! mCurrentAddSet)
mCurrentAddSet = mContentControl;
mCurrentAddSet->addObject(ctrl);
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
if (!(ctrl->isLocked())) {
mSelectedControls.push_back(ctrl);
Con::executef(this, 2, "onAddSelected", avar("%d", ctrl->getId()));
}
}
void GuiEditCtrl::drawNut(const Point2I &nut, ColorI &outlineColor, ColorI &nutColor)
{
RectI r(nut.x - NUT_SIZE, nut.y - NUT_SIZE, 2 * NUT_SIZE + 1, 2 * NUT_SIZE + 1);
r.inset(1, 1);
dglDrawRectFill(r, nutColor);
r.inset(-1, -1);
dglDrawRect(r, outlineColor);
}
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, ColorI &outlineColor, ColorI &nutColor)
{
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;
ColorF greenLine(0,1,0,0.6);
ColorF lightGreenLine(0,1,0,0.3);
if(lx > 0 && ty > 0)
{
dglDrawLine(0, ty, lx, ty, greenLine);
dglDrawLine(lx, 0, lx, ty, greenLine);
}
if(lx > 0 && by > 0)
dglDrawLine(0, by, lx, by, greenLine);
if(rx > 0 && ty > 0)
dglDrawLine(rx, 0, rx, ty, greenLine);
Point2I extent = localToGlobalCoord(mBounds.extent);
if(lx < extent.x && by < extent.y)
dglDrawLine(lx, by, lx, extent.y, lightGreenLine);
if(rx < extent.x && by < extent.y)
{
dglDrawLine(rx, by, rx, extent.y, lightGreenLine);
dglDrawLine(rx, by, extent.x, by, lightGreenLine);
}
if(rx < extent.x && ty < extent.y)
dglDrawLine(rx, ty, extent.x, ty, lightGreenLine);
drawNut(Point2I(lx, ty), outlineColor, nutColor);
drawNut(Point2I(lx, cy), outlineColor, nutColor);
drawNut(Point2I(lx, by), outlineColor, nutColor);
drawNut(Point2I(rx, ty), outlineColor, nutColor);
drawNut(Point2I(rx, cy), outlineColor, nutColor);
drawNut(Point2I(rx, by), outlineColor, nutColor);
drawNut(Point2I(cx, ty), outlineColor, nutColor);
drawNut(Point2I(cx, by), outlineColor, nutColor);
}
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)
{
Point2I ctOffset;
Point2I cext;
bool keyFocused = isFirstResponder();
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, ctOffset.y, cext.x, cext.y);
box.inset(-2, -2);
dglDrawRect(box, ColorI(0,0,128,140));
box.inset(1,1);
dglDrawRect(box, ColorI(0,0,128,140));
box.inset(1,1);
dglDrawRect(box, ColorI(0,255,0,140));
box.inset(1,1);
dglDrawRect(box, ColorI(255,255,0,140));
box.inset(1,1);
dglDrawRect(box, ColorI(255,255,0,140));
}
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);
ColorI nutColor = multisel ? ColorI(255,255,255) : ColorI(0,0,0);
ColorI outlineColor = multisel ? ColorI(0,0,0) : ColorI(255,255,255);
if(!keyFocused)
nutColor.set(128,128,128);
drawNuts(box, outlineColor, nutColor);
}
if (mMouseDownMode == DragSelecting)
{
RectI b;
getDragRect(b);
b.point += offset;
dglDrawRect(b, ColorI(255, 255, 255));
}
}
renderChildControls(offset, updateRect);
}
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(globalToLocalCoord(event.mousePoint), mLayer - 1);
if (hitCtrl != mCurrentAddSet)
{
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
mCurrentAddSet = hitCtrl;
}
//Design time mouse events
GuiEvent designEvent = event;
designEvent.mousePoint = mLastMousePos;
hitCtrl->onRightMouseDownEditor( designEvent, localToGlobalCoord( Point2I(0,0) ) );
}
void GuiEditCtrl::select(GuiControl *ctrl)
{
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
if(ctrl != mContentControl) {
if (!(ctrl->isLocked())) {
mSelectedControls.push_back(ctrl);
Con::executef(this, 2, "onAddSelected", avar("%d", ctrl->getId()));
}
}else
mCurrentAddSet = mContentControl;
}
void GuiEditCtrl::getCursor(GuiCursor *&cursor, bool &showCursor, const GuiEvent &lastGuiEvent)
{
showCursor = true;
Point2I ctOffset;
Point2I cext;
GuiControl *ctrl;
Point2I mousePos = globalToLocalCoord(lastGuiEvent.mousePoint);
// first see if we hit a sizing knob on the currently selected control...
if (mSelectedControls.size() == 1 && initCursors() == true )
{
ctrl = mSelectedControls.first();
cext = ctrl->getExtent();
ctOffset = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0,0)));
RectI box(ctOffset.x,ctOffset.y,cext.x, cext.y);
GuiEditCtrl::sizingModes sizeMode = (GuiEditCtrl::sizingModes)getSizingHitKnobs(mousePos, box);
if( mMouseDownMode == SizingSelection )
{
if ( ( mSizingMode == ( sizingBottom | sizingRight ) ) || ( mSizingMode == ( sizingTop | sizingLeft ) ) )
cursor = mNWSECursor;
else if ( ( mSizingMode == ( sizingBottom | sizingLeft ) ) || ( mSizingMode == ( sizingTop | sizingRight ) ) )
cursor = mNESWCursor;
else if ( mSizingMode == sizingLeft || mSizingMode == sizingRight )
cursor = mLeftRightCursor;
else if (mSizingMode == sizingTop || mSizingMode == sizingBottom )
cursor = mUpDownCursor;
else
cursor = NULL;
}
else
{
// Check for current mouse position after checking for actual sizing mode
if ( ( sizeMode == ( sizingBottom | sizingRight ) ) ||
( sizeMode == ( sizingTop | sizingLeft ) ) )
cursor = mNWSECursor;
else if ( ( sizeMode == ( sizingBottom | sizingLeft ) ) ||
( sizeMode == ( sizingTop | sizingRight ) ) )
cursor = mNESWCursor;
else if (sizeMode == sizingLeft || sizeMode == sizingRight )
cursor = mLeftRightCursor;
else if (sizeMode == sizingTop || sizeMode == sizingBottom )
cursor = mUpDownCursor;
else
cursor = NULL;
}
}
if( mMouseDownMode == MovingSelection && cursor == NULL )
cursor = mMoveCursor;
}
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 = globalToLocalCoord(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 = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0,0)));
RectI box(ctOffset.x,ctOffset.y,cext.x, cext.y);
if ((mSizingMode = (GuiEditCtrl::sizingModes)getSizingHitKnobs(mLastMousePos, box)) != 0)
{
mMouseDownMode = SizingSelection;
return;
}
}
if(!mCurrentAddSet)
mCurrentAddSet = mContentControl;
//find the control we clicked
ctrl = mContentControl->findHitControl(mLastMousePos, mCurrentAddSet->mLayer);
bool handledEvent = ctrl->onMouseDownEditor( event, localToGlobalCoord( Point2I(0,0) ) );
if( handledEvent == true )
{
// The Control handled the event and requested the edit ctrl
// *NOT* act on it. The dude abides.
return;
}
else 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)
{
Con::executef(this, 2, "onRemoveSelected", avar("%d", ctrl->getId()));
mSelectedControls.erase(i);
break;
}
}
//set the mode
mMouseDownMode = Selecting;
}
else //else we hit a ctrl we've already selected, so set the mode to moving
{
// For calculating mouse delta
mDragBeginPoint = event.mousePoint;
// Allocate enough space for our selected controls
mDragBeginPoints.reserve( mSelectedControls.size() );
// For snapping to origin
Vector<GuiControl *>::iterator i;
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
mDragBeginPoints.push_back( (*i)->mBounds.point );
// Set Mouse Mode
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)) {
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
}
mSelectionAnchor = mLastMousePos;
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)
{
if (!(ctrl->isLocked())) {
mSelectedControls.push_back(ctrl);
Con::executef(this, 2, "onAddSelected", avar("%d", ctrl->getId()));
}
mMouseDownMode = Selecting;
}
else if (ctrl != mContentControl)
{
//find and set the new add set
mCurrentAddSet = ctrl->getParent();
//clear and set the selected controls
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
if (!(ctrl->isLocked())) {
mSelectedControls.push_back(ctrl);
Con::executef(this, 2, "onAddSelected", avar("%d", ctrl->getId()));
}
mMouseDownMode = Selecting;
}
else
mMouseDownMode = Selecting;
}
}
}
void GuiEditCtrl::addSelection(S32 id)
{
GuiControl * ctrl;
if(Sim::findObject(id, ctrl))
mSelectedControls.push_back(ctrl);
}
void GuiEditCtrl::removeSelection(S32 id)
{
GuiControl * ctrl;
if (Sim::findObject(id, ctrl)) {
Vector<GuiControl *>::iterator i;
for(i = mSelectedControls.begin(); i != mSelectedControls.end(); i++)
{
if (*i == ctrl)
{
mSelectedControls.erase(i);
break;
}
}
}
}
void GuiEditCtrl::onMouseUp(const GuiEvent &event)
{
if (! mActive)
{
Parent::onMouseUp(event);
return;
}
//find the control we clicked
GuiControl *ctrl = mContentControl->findHitControl(mLastMousePos, mCurrentAddSet->mLayer);
bool handledEvent = ctrl->onMouseUpEditor( event, localToGlobalCoord( Point2I(0,0) ) );
if( handledEvent == true )
{
// The Control handled the event and requested the edit ctrl
// *NOT* act on it. The dude abides.
return;
}
//unlock the mouse
mouseUnlock();
// Reset Drag Axis Alignment Information
mDragBeginPoint.set(-1,-1);
mDragBeginPoints.clear();
mLastMousePos = globalToLocalCoord(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 = globalToLocalCoord(ctrl->localToGlobalCoord(Point2I(0,0)));
Point2I lowerR = upperL + ctrl->mBounds.extent - Point2I(1, 1);
if (b.pointInRect(upperL) && b.pointInRect(lowerR) && !selectionContains(ctrl)) {
if (!(ctrl->isLocked())) {
mSelectedControls.push_back(ctrl);
Con::executef(this, 2, "onAddSelected", avar("%d", ctrl->getId()));
}
}
}
}
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 = globalToLocalCoord(event.mousePoint);
//find the control we clicked
GuiControl *ctrl = mContentControl->findHitControl(mousePoint, mCurrentAddSet->mLayer);
bool handledEvent = ctrl->onMouseDraggedEditor( event, localToGlobalCoord( Point2I(0,0) ) );
if( handledEvent == true )
{
// The Control handled the event and requested the edit ctrl
// *NOT* act on it. The dude abides.
return;
}
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(event.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);
Con::executef(this, 2, "onSelect", avar("%d", mSelectedControls[0]->getId()));
}
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;
// Do we want to align this drag to the X and Y axes within a certain threshold?
if( event.modifier & SI_SHIFT )
{
Point2I dragTotalDelta = event.mousePoint - mDragBeginPoint;
bool snapToOriginX = false;
bool snapToOriginY = false;
if( dragTotalDelta.y < 10 && dragTotalDelta.y > -10 )
{
for(S32 i = 0; i < mSelectedControls.size(); i++)
{
Point2I snapBackPoint( mSelectedControls[i]->mBounds.point.x, mDragBeginPoints[i].y);
// This is kind of nasty but we need to snap back if we're not at origin point with selection - JDD
if( mSelectedControls[i]->mBounds.point.y != mDragBeginPoints[i].y )
mSelectedControls[i]->resize( snapBackPoint, mSelectedControls[i]->mBounds.extent);
}
delta.y = 0;
}
if( dragTotalDelta.x < 10 && dragTotalDelta.x > -10 )
{
for(S32 i = 0; i < mSelectedControls.size(); i++)
{
Point2I snapBackPoint( mDragBeginPoints[i].x,mSelectedControls[i]->mBounds.point.y);
// This is kind of nasty but we need to snap back if we're not at origin point with selection - JDD
if( mSelectedControls[i]->mBounds.point.x != mDragBeginPoints[i].x )
mSelectedControls[i]->resize( snapBackPoint, mSelectedControls[i]->mBounds.extent);
}
delta.x = 0;
}
}
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);
if (mSelectedControls.size() == 1)
Con::executef(this, 2, "onSelect", avar("%d", mSelectedControls[0]->getId()));
}
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++)
{
SimObject *obj = (*i);
if( obj )
obj->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())
{
Con::executef(this, 1, "onClearSelected");
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);
Con::executef(this, 2, "onAddSelected", avar("%d", ctrl->getId()));
}
}
}
set->deleteObject();
}
void GuiEditCtrl::saveSelection(const char* filename)
{
// if there are no selected objects, then don't save
if (mSelectedControls.size() == 0)
return;
FileStream stream;
if(!ResourceManager->openFileForWrite(stream, 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;
Con::executef(this, 1, "onClearSelected");
mSelectedControls.clear();
for(i = mCurrentAddSet->begin(); i != mCurrentAddSet->end(); i++)
{
GuiControl *ctrl = dynamic_cast<GuiControl *>(*i);
if (!(ctrl->isLocked())) {
mSelectedControls.push_back(ctrl);
Con::executef(this, 2, "onAddSelected", avar("%d", ctrl->getId()));
}
}
}
void GuiEditCtrl::bringToFront()
{
if (mSelectedControls.size() != 1)
return;
GuiControl *ctrl = *(mSelectedControls.begin());
mCurrentAddSet->pushObjectToBack(ctrl);
}
void GuiEditCtrl::pushToBack()
{
if (mSelectedControls.size() != 1)
return;
GuiControl *ctrl = *(mSelectedControls.begin());
mCurrentAddSet->bringObjectToFront(ctrl);
}
bool GuiEditCtrl::onKeyDown(const GuiEvent &event)
{
if (! mActive)
return Parent::onKeyDown(event);
if (!(event.modifier & SI_CTRL))
{
switch(event.keyCode)
{
case KEY_BACKSPACE:
case KEY_DELETE:
Con::executef(this,1,"onDelete");
deleteSelection();
return true;
}
}
return false;
}
class GuiEditorRuler : public GuiControl {
StringTableEntry refCtrl;
typedef GuiControl Parent;
public:
void onPreRender()
{
setUpdate();
}
void onRender(Point2I offset, const RectI &updateRect)
{
dglDrawRectFill(updateRect, ColorF(1,1,1,1));
GuiScrollCtrl *ref;
SimObject *o = Sim::findObject(refCtrl);
//Sim::findObject(refCtrl, &ref);
ref = dynamic_cast<GuiScrollCtrl *>(o);
Point2I choffset(0,0);
if(ref)
choffset = ref->getChildPos();
if(mBounds.extent.x > mBounds.extent.y)
{
// it's horizontal.
for(U32 i = 0; i < mBounds.extent.x; i++)
{
S32 x = offset.x + i;
S32 pos = i - choffset.x;
if(!(pos % 10))
{
S32 start = 6;
if(!(pos %20))
start = 4;
if(!(pos % 100))
start = 1;
dglDrawLine(x, offset.y + start, x, offset.y + 10, ColorF(0,0,0,1));
}
}
}
else
{
// it's vertical.
for(U32 i = 0; i < mBounds.extent.y; i++)
{
S32 y = offset.y + i;
S32 pos = i - choffset.y;
if(!(pos % 10))
{
S32 start = 6;
if(!(pos %20))
start = 4;
if(!(pos % 100))
start = 1;
dglDrawLine(offset.x + start, y, offset.x + 10, y, ColorF(0,0,0,1));
}
}
}
}
static void initPersistFields()
{
Parent::initPersistFields();
addField("refCtrl", TypeString, Offset(refCtrl, GuiEditorRuler));
}
DECLARE_CONOBJECT(GuiEditorRuler);
};
IMPLEMENT_CONOBJECT(GuiEditorRuler);