Blame |
Last modification |
View Log
| RSS feed
#include "WidgetContainer.h"
#include "WidgetManager.h"
#include "Widget.h"
#include "Debug.h"
#include <algorithm>
using namespace Sexy;
WidgetContainer::WidgetContainer()
{
mX = 0;
mY = 0;
mWidth = 0;
mHeight = 0;
mParent = NULL;
mWidgetManager = NULL;
mUpdateIteratorModified = false;
mUpdateIterator = mWidgets.end();
mLastWMUpdateCount = 0;
mUpdateCnt = 0;
mDirty = false;
mHasAlpha = false;
mClip = true;
mPriority = 0;
mZOrder = 0;
}
WidgetContainer::~WidgetContainer()
{
// call RemoveWidget before you delete it!
DBG_ASSERT(mParent == NULL);
DBG_ASSERT(mWidgets.empty());
}
void WidgetContainer::RemoveAllWidgets(bool doDelete, bool recursive)
{
while (!mWidgets.empty())
{
Widget *aWidget = mWidgets.front();
RemoveWidget(aWidget);
if (recursive)
aWidget->RemoveAllWidgets(doDelete,recursive);
if (doDelete)
delete aWidget;
}
}
Rect WidgetContainer::GetRect()
{
return Rect(mX, mY, mWidth, mHeight);
}
bool WidgetContainer::Intersects(WidgetContainer* theWidget)
{
return GetRect().Intersects(theWidget->GetRect());
}
void WidgetContainer::AddWidget(Widget* theWidget)
{
if (std::find(mWidgets.begin(), mWidgets.end(), theWidget) == mWidgets.end())
{
InsertWidgetHelper(mWidgets.end(),theWidget);
theWidget->mWidgetManager = mWidgetManager;
theWidget->mParent = this;
if (mWidgetManager != NULL)
{
theWidget->AddedToManager(mWidgetManager);
theWidget->MarkDirtyFull();
mWidgetManager->RehupMouse();
}
MarkDirty();
}
}
bool WidgetContainer::HasWidget(Widget* theWidget)
{
return std::find(mWidgets.begin(), mWidgets.end(), theWidget) != mWidgets.end();
}
void WidgetContainer::RemoveWidget(Widget* theWidget)
{
WidgetList::iterator anItr = std::find(mWidgets.begin(), mWidgets.end(), theWidget);
if (anItr != mWidgets.end())
{
theWidget->WidgetRemovedHelper();
theWidget->mParent = NULL;
bool erasedCur = (anItr == mUpdateIterator);
mWidgets.erase(anItr++);
if (erasedCur)
{
mUpdateIterator = anItr;
mUpdateIteratorModified = true;
}
}
}
Widget* WidgetContainer::GetWidgetAtHelper(int x, int y, int theFlags, bool* found, int* theWidgetX, int* theWidgetY)
{
bool belowModal = false;
ModFlags(theFlags, mWidgetFlagsMod);
WidgetList::reverse_iterator anItr = mWidgets.rbegin();
while (anItr != mWidgets.rend())
{
Widget* aWidget = *anItr;
int aCurFlags = theFlags;
ModFlags(aCurFlags, aWidget->mWidgetFlagsMod);
if (belowModal) ModFlags(aCurFlags, mWidgetManager->mBelowModalFlagsMod);
if (aCurFlags & WIDGETFLAGS_ALLOW_MOUSE)
{
if (aWidget->mVisible)
{
bool childFound;
Widget* aCheckWidget = aWidget->GetWidgetAtHelper(x - aWidget->mX, y - aWidget->mY, aCurFlags, &childFound, theWidgetX, theWidgetY);
if ((aCheckWidget != NULL) || (childFound))
{
*found = true;
return aCheckWidget;
}
if ((aWidget->mMouseVisible) && (aWidget->GetInsetRect().Contains(x, y)))
{
*found = true;
if (aWidget->IsPointVisible(x-aWidget->mX,y-aWidget->mY))
{
if (theWidgetX)
*theWidgetX = x - aWidget->mX;
if (theWidgetY)
*theWidgetY = y - aWidget->mY;
return aWidget;
}
}
}
}
belowModal |= aWidget == mWidgetManager->mBaseModalWidget;
++anItr;
}
*found = false;
return NULL;
}
bool WidgetContainer::IsBelowHelper(Widget* theWidget1, Widget* theWidget2, bool* found)
{
WidgetList::iterator anItr = mWidgets.begin();
while (anItr != mWidgets.end())
{
Widget* aWidget = *anItr;
if (aWidget == theWidget1)
{
*found = true;
return true;
}
else if (aWidget == theWidget2)
{
*found = true;
return false;
}
bool result = aWidget->IsBelowHelper(theWidget1, theWidget2, found);
if (*found)
return result;
++anItr;
}
return false;
}
bool WidgetContainer::IsBelow(Widget* theWidget1, Widget* theWidget2)
{
bool found = false;
return IsBelowHelper(theWidget1, theWidget2, &found);
}
void WidgetContainer::MarkAllDirty()
{
MarkDirty();
WidgetList::iterator anItr = mWidgets.begin();
while (anItr != mWidgets.end())
{
(*anItr)->mDirty = true;
(*anItr)->MarkAllDirty();
++anItr;
}
}
void WidgetContainer::InsertWidgetHelper(const WidgetList::iterator &where, Widget *theWidget)
{
// Search forwards
WidgetList::iterator anItr = where;
while (anItr!=mWidgets.end())
{
Widget *aWidget = *anItr;
if (aWidget->mZOrder >= theWidget->mZOrder)
{
if (anItr!=mWidgets.begin())
{
WidgetList::iterator anItr2 = anItr;
anItr2--;
aWidget = *anItr;
if (aWidget->mZOrder>theWidget->mZOrder) // need to search backwards
break;
}
mWidgets.insert(anItr,theWidget);
return;
}
++anItr;
}
// Search backwards
while (anItr!=mWidgets.begin())
{
--anItr;
Widget *aWidget = *anItr;
if (aWidget->mZOrder <= theWidget->mZOrder)
{
mWidgets.insert(++anItr,theWidget);
return;
}
}
// It goes at the beginning
mWidgets.push_front(theWidget);
}
void WidgetContainer::BringToFront(Widget* theWidget)
{
WidgetList::iterator anItr = std::find(mWidgets.begin(), mWidgets.end(), theWidget);
if (anItr != mWidgets.end())
{
if (anItr == mUpdateIterator)
{
mUpdateIterator++;
mUpdateIteratorModified = true;
}
mWidgets.erase(anItr);
InsertWidgetHelper(mWidgets.end(),theWidget);
theWidget->OrderInManagerChanged();
}
}
void WidgetContainer::BringToBack(Widget* theWidget)
{
WidgetList::iterator anItr = std::find(mWidgets.begin(), mWidgets.end(), theWidget);
if (anItr != mWidgets.end())
{
if (anItr == mUpdateIterator)
{
mUpdateIterator++;
mUpdateIteratorModified = true;
}
mWidgets.erase(anItr);
InsertWidgetHelper(mWidgets.begin(),theWidget);
theWidget->OrderInManagerChanged();
}
}
void WidgetContainer::PutBehind(Widget* theWidget, Widget* theRefWidget)
{
WidgetList::iterator anItr = std::find(mWidgets.begin(), mWidgets.end(), theWidget);
if (anItr != mWidgets.end())
{
if (anItr == mUpdateIterator)
{
mUpdateIterator++;
mUpdateIteratorModified = true;
}
mWidgets.erase(anItr);
anItr = std::find(mWidgets.begin(), mWidgets.end(), theRefWidget);
InsertWidgetHelper(anItr, theWidget);
theWidget->OrderInManagerChanged();
}
}
void WidgetContainer::PutInfront(Widget* theWidget, Widget* theRefWidget)
{
WidgetList::iterator anItr = std::find(mWidgets.begin(), mWidgets.end(), theWidget);
if (anItr != mWidgets.end())
{
if (anItr == mUpdateIterator)
{
mUpdateIterator++;
mUpdateIteratorModified = true;
}
mWidgets.erase(anItr);
anItr = std::find(mWidgets.begin(), mWidgets.end(), theRefWidget);
if (anItr != mWidgets.end())
anItr++;
InsertWidgetHelper(anItr, theWidget);
theWidget->OrderInManagerChanged();
}
}
Point WidgetContainer::GetAbsPos() // relative to top level
{
if (mParent==NULL)
return Point(mX,mY);
else
return Point(mX,mY) + mParent->GetAbsPos();
}
void WidgetContainer::AddedToManager(WidgetManager* theWidgetManager)
{
WidgetList::iterator anItr = mWidgets.begin();
while (anItr != mWidgets.end())
{
Widget* theWidget = *anItr;
theWidget->mWidgetManager = theWidgetManager;
theWidget->AddedToManager(theWidgetManager);
++anItr;
MarkDirty();
}
}
void WidgetContainer::RemovedFromManager(WidgetManager* theWidgetManager)
{
for (WidgetList::iterator anItr = mWidgets.begin(); anItr != mWidgets.end(); ++anItr)
{
Widget* aWidget = *anItr;
theWidgetManager->DisableWidget(aWidget);
aWidget->RemovedFromManager(theWidgetManager);
aWidget->mWidgetManager = NULL;
}
if (theWidgetManager->mPopupCommandWidget==this)
theWidgetManager->mPopupCommandWidget = NULL;
}
void WidgetContainer::MarkDirty()
{
if (mParent != NULL)
mParent->MarkDirty(this);
else
mDirty = true;
}
void WidgetContainer::MarkDirtyFull()
{
if (mParent != NULL)
mParent->MarkDirtyFull(this);
else
mDirty = true;
}
void WidgetContainer::MarkDirtyFull(WidgetContainer* theWidget)
{
// Mark all things dirty that are under or over this widget
// Mark ourselves dirty
MarkDirtyFull();
theWidget->mDirty = true;
// Top-level windows are treated differently, as marking a child dirty always
// causes a parent redraw which always causes all children to redraw
if (mParent != NULL)
return;
WidgetList::iterator aFoundWidgetItr = std::find(mWidgets.begin(), mWidgets.end(), theWidget);
if (aFoundWidgetItr == mWidgets.end())
return;
WidgetList::iterator anItr = aFoundWidgetItr;
if (anItr != mWidgets.begin())
{
anItr--;
for (;;)
{
Widget* aWidget = *anItr;
if (aWidget->mVisible)
{
if ((!aWidget->mHasTransparencies) && (!aWidget->mHasAlpha))
{
// Clip the widget's bounds to the screen and check if it fully overlapped by this non-transparent widget underneath it
// If it is fully overlapped then we can stop marking dirty underneath it since it's not transparent.
Rect aRect = Rect(theWidget->mX,theWidget->mY,theWidget->mWidth,theWidget->mHeight).Intersection(Rect(0,0,mWidth,mHeight));
if ((aWidget->Contains(aRect.mX, aRect.mY) &&
(aWidget->Contains(aRect.mX + aRect.mWidth - 1, aRect.mY + aRect.mHeight - 1))))
{
// If this widget is fully contained within a lower widget, there is no need to dig down
// any deeper.
aWidget->MarkDirty();
break;
}
}
if (aWidget->Intersects(theWidget))
MarkDirty(aWidget);
}
if (anItr == mWidgets.begin())
break;
--anItr;
}
}
anItr = aFoundWidgetItr;
while (anItr != mWidgets.end())
{
Widget* aWidget = *anItr;
if ((aWidget->mVisible) && (aWidget->Intersects(theWidget)))
MarkDirty(aWidget);
++anItr;
}
}
void WidgetContainer::MarkDirty(WidgetContainer* theWidget)
{
if (theWidget->mDirty)
return;
// Only mark things dirty that are on top of this widget
// Mark ourselves dirty
MarkDirty();
theWidget->mDirty = true;
// Top-level windows are treated differently, as marking a child dirty always
// causes a parent redraw which always causes all children to redraw
if (mParent != NULL)
return;
if (theWidget->mHasAlpha)
MarkDirtyFull(theWidget);
else
{
bool found = false;
WidgetList::iterator anItr = mWidgets.begin();
while (anItr != mWidgets.end())
{
Widget* aWidget = *anItr;
if (aWidget == theWidget)
found = true;
else if (found)
{
if ((aWidget->mVisible) && (aWidget->Intersects(theWidget)))
MarkDirty(aWidget);
}
++anItr;
}
}
}
void WidgetContainer::Update()
{
mUpdateCnt++;
}
void WidgetContainer::UpdateAll(ModalFlags* theFlags)
{
AutoModalFlags anAutoModalFlags(theFlags, mWidgetFlagsMod);
if (theFlags->GetFlags() & WIDGETFLAGS_MARK_DIRTY)
MarkDirty();
// Can update?
WidgetManager *aWidgetManager = mWidgetManager;
if (aWidgetManager==NULL)
return;
if (theFlags->GetFlags() & WIDGETFLAGS_UPDATE)
{
if (mLastWMUpdateCount != mWidgetManager->mUpdateCnt)
{
mLastWMUpdateCount = mWidgetManager->mUpdateCnt;
Update();
}
}
mUpdateIterator = mWidgets.begin();
while (mUpdateIterator != mWidgets.end())
{
mUpdateIteratorModified = false;
Widget* aWidget = *mUpdateIterator;
if (aWidget == aWidgetManager->mBaseModalWidget)
theFlags->mIsOver = true;
aWidget->UpdateAll(theFlags);
if (!mUpdateIteratorModified)
++mUpdateIterator;
}
mUpdateIteratorModified = true; // prevent incrementing iterator off the end of the list
}
void WidgetContainer::UpdateF(float theFrac)
{
}
void WidgetContainer::UpdateFAll(ModalFlags* theFlags, float theFrac)
{
AutoModalFlags anAutoModalFlags(theFlags, mWidgetFlagsMod);
// Can update?
if (theFlags->GetFlags() & WIDGETFLAGS_UPDATE)
{
UpdateF(theFrac);
}
mUpdateIterator = mWidgets.begin();
while (mUpdateIterator != mWidgets.end())
{
mUpdateIteratorModified = false;
Widget* aWidget = *mUpdateIterator;
if (aWidget == mWidgetManager->mBaseModalWidget)
theFlags->mIsOver = true;
aWidget->UpdateFAll(theFlags, theFrac);
if (!mUpdateIteratorModified)
++mUpdateIterator;
}
mUpdateIteratorModified = true; // prevent incrementing iterator off the end of the list
}
void WidgetContainer::Draw(Graphics* g)
{
}
void WidgetContainer::DrawAll(ModalFlags* theFlags, Graphics* g)
{
if (mPriority > mWidgetManager->mMinDeferredOverlayPriority)
mWidgetManager->FlushDeferredOverlayWidgets(mPriority);
AutoModalFlags anAutoModalFlags(theFlags, mWidgetFlagsMod);
if ((mClip) && (theFlags->GetFlags() & WIDGETFLAGS_CLIP))
g->ClipRect(0, 0, mWidth, mHeight);
if (mWidgets.size() == 0)
{
if (theFlags->GetFlags() & WIDGETFLAGS_DRAW)
Draw(g);
return;
}
if (theFlags->GetFlags() & WIDGETFLAGS_DRAW)
{
g->PushState();
Draw(g);
g->PopState();
}
WidgetList::iterator anItr = mWidgets.begin();
while (anItr != mWidgets.end())
{
Widget* aWidget = *anItr;
if (aWidget->mVisible)
{
if (aWidget == mWidgetManager->mBaseModalWidget)
theFlags->mIsOver = true;
Graphics aClipG(*g);
aClipG.Translate(aWidget->mX, aWidget->mY);
aWidget->DrawAll(theFlags, &aClipG);
aWidget->mDirty = false;
}
++anItr;
}
}
void WidgetContainer::SysColorChanged()
{
}
void WidgetContainer::SysColorChangedAll()
{
SysColorChanged();
static int aDepthCount = 0;
if (mWidgets.size() > 0)
aDepthCount++;
WidgetList::iterator anItr = mWidgets.begin();
while (anItr != mWidgets.end())
{
Widget* aWidget = *anItr;
aWidget->SysColorChangedAll();
++anItr;
}
}
void WidgetContainer::DisableWidget(Widget* theWidget)
{
}
void WidgetContainer::SetFocus(Widget* theWidget)
{
}