Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

#include "WidgetManager.h"
#include "Widget.h"
#include "Graphics.h"
#include "Image.h"
#include "KeyCodes.h"
#include "DDImage.h"
#include "SexyAppBase.h"
#include "PerfTimer.h"
#include "Debug.h"

using namespace Sexy;
using namespace std;

WidgetManager::WidgetManager(SexyAppBase* theApp)
{
        mApp = theApp;

        mMinDeferredOverlayPriority = 0x7FFFFFFF;
        mWidgetManager = this; 
        mMouseIn = false;
        mDefaultTab = NULL;
        mImage = NULL;
        mLastHadTransients = false;
        mPopupCommandWidget = NULL;
        mFocusWidget = NULL;
        mLastDownWidget = NULL;
        mOverWidget = NULL;
        mBaseModalWidget = NULL;
        mDefaultBelowModalFlagsMod.mRemoveFlags = WIDGETFLAGS_ALLOW_MOUSE | WIDGETFLAGS_ALLOW_FOCUS;   
        mWidth = 0;
        mHeight = 0;
        mHasFocus = true;
        mUpdateCnt = 0;
        mLastDownButtonId = 0;
        mDownButtons = 0;
        mActualDownButtons = 0;
        mWidgetFlags = WIDGETFLAGS_UPDATE | WIDGETFLAGS_DRAW | WIDGETFLAGS_CLIP |
                WIDGETFLAGS_ALLOW_MOUSE | WIDGETFLAGS_ALLOW_FOCUS;

        for (int i = 0; i < 0xFF; i++)
                mKeyDown[i] = false;
}

WidgetManager::~WidgetManager()
{      
        FreeResources();       
}

void WidgetManager::FreeResources()
{      
       
}

void WidgetManager::DisableWidget(Widget* theWidget)
{
        if (mOverWidget == theWidget)
        {
                Widget* aOverWidget = mOverWidget;
                mOverWidget = NULL;
                MouseLeave(aOverWidget);
        }
       
        if (mLastDownWidget     == theWidget)
        {
                Widget* aLastDownWidget = mLastDownWidget;
                mLastDownWidget = NULL;
                DoMouseUps(aLastDownWidget, mDownButtons);
                mDownButtons = 0;              
        }
       
        if (mFocusWidget == theWidget)
        {
                Widget* aFocusWidget = mFocusWidget;
                mFocusWidget = NULL;
                aFocusWidget->LostFocus();
        }
       
        if (mBaseModalWidget == theWidget)
                mBaseModalWidget = NULL;
}

int WidgetManager::GetWidgetFlags()
{
        return mHasFocus ? mWidgetFlags : GetModFlags(mWidgetFlags, mLostFocusFlagsMod);
}

Widget* WidgetManager::GetAnyWidgetAt(int x, int y, int* theWidgetX, int* theWidgetY)
{
        bool found;
        return GetWidgetAtHelper(x, y, GetWidgetFlags(), &found, theWidgetX, theWidgetY);
}

Widget* WidgetManager::GetWidgetAt(int x, int y, int* theWidgetX, int* theWidgetY)
{      
        Widget* aWidget = GetAnyWidgetAt(x, y, theWidgetX, theWidgetY);
        if ((aWidget != NULL) && (aWidget->mDisabled))
                aWidget = NULL;
        return aWidget;
}

bool WidgetManager::IsLeftButtonDown()
{
        return (mActualDownButtons&1)?true:false;
}

bool WidgetManager::IsMiddleButtonDown()
{
        return (mActualDownButtons&4)?true:false;
}

bool WidgetManager::IsRightButtonDown()
{
        return (mActualDownButtons&2)?true:false;
}

void WidgetManager::DoMouseUps()
{
        if (mLastDownWidget!=NULL && mDownButtons!=0)
        {
                DoMouseUps(mLastDownWidget, mDownButtons);
                mDownButtons = 0;
                mLastDownWidget = NULL;
        }
}

void WidgetManager::DeferOverlay(Widget* theWidget, int thePriority)
{
        mDeferredOverlayWidgets.push_back(std::pair<Widget*, int>(theWidget, thePriority));
        if (thePriority < mMinDeferredOverlayPriority)
                mMinDeferredOverlayPriority = thePriority;
}

void WidgetManager::FlushDeferredOverlayWidgets(int theMaxPriority)
{
        for (;;)
        {
                int aNextMinPriority = 0x7FFFFFFF;

                for (int i = 0; i < (int) mDeferredOverlayWidgets.size(); i++)
                {
                        Widget* aWidget = mDeferredOverlayWidgets[i].first;                    
                        if (aWidget != NULL)
                        {
                                int aPriority = mDeferredOverlayWidgets[i].second;

                                if (aPriority == mMinDeferredOverlayPriority)
                                {
                                        // Overlays don't get clipped
                                        Graphics g(*mCurG);
                                        g.Translate(-mMouseDestRect.mX, -mMouseDestRect.mY);
                                        g.Translate(aWidget->mX, aWidget->mY);
                                        g.SetFastStretch(!g.Is3D());
                                        g.SetLinearBlend(g.Is3D());

                                        aWidget->DrawOverlay(&g, aPriority);
                                        mDeferredOverlayWidgets[i].first = NULL;
                                }
                                else
                                {
                                        if (aPriority < aNextMinPriority)
                                                aNextMinPriority = aPriority;
                                }
                        }
                }

                mMinDeferredOverlayPriority = aNextMinPriority;
                if (aNextMinPriority == 0x7FFFFFFF)
                {
                        // No more widgets lined up for overlays, clear our vector
                        mDeferredOverlayWidgets.resize(0);
                        break;
                }

                // Lowest overlay priority is higher or equal to our current widget,
                //  so continue deferring
                if (aNextMinPriority >= theMaxPriority)
                        break;
        }
}

void WidgetManager::DoMouseUps(Widget* theWidget, ulong theDownCode)
{
        int aClickCountTable[3] = { 1,-1, 3 };
        for (int i = 0; i < 3; i++)
        {
                if ((theDownCode & (1 << i)) != 0)
                {
                        theWidget->mIsDown = false;
                        theWidget->MouseUp(mLastMouseX - theWidget->mX, mLastMouseY - theWidget->mY, aClickCountTable[i]);
                }
        }
}

void WidgetManager::RemapMouse(int& theX, int& theY)
{
        theX = ( theX - mMouseSourceRect.mX ) * mMouseDestRect.mWidth / mMouseSourceRect.mWidth + mMouseDestRect.mX;
        theY = ( theY - mMouseSourceRect.mY ) * mMouseDestRect.mHeight / mMouseSourceRect.mHeight + mMouseDestRect.mY;
}

void WidgetManager::MouseEnter(Widget* theWidget)
{
        theWidget->mIsOver = true;
       
        theWidget->MouseEnter();
        if (theWidget->mDoFinger)
                theWidget->ShowFinger(true);   
}

void WidgetManager::MouseLeave(Widget* theWidget)
{
        theWidget->mIsOver = false;
       
        theWidget->MouseLeave();
        if (theWidget->mDoFinger)
                theWidget->ShowFinger(false);
}

void WidgetManager::SetBaseModal(Widget* theWidget, const FlagsMod& theBelowFlagsMod)
{
        mBaseModalWidget = theWidget;
        mBelowModalFlagsMod = theBelowFlagsMod;
       
        if ((mOverWidget != NULL) && (mBelowModalFlagsMod.mRemoveFlags & WIDGETFLAGS_ALLOW_MOUSE) &&
                (IsBelow(mOverWidget, mBaseModalWidget)))
        {
                Widget* aWidget = mOverWidget;
                mOverWidget = NULL;
                MouseLeave(aWidget);           
        }
       
        if ((mLastDownWidget != NULL) && (mBelowModalFlagsMod.mRemoveFlags & WIDGETFLAGS_ALLOW_MOUSE) &&
                (IsBelow(mLastDownWidget, mBaseModalWidget)))
        {
                Widget* aWidget = mLastDownWidget;
                int aDownButtons = mDownButtons;
                mDownButtons = 0;              
                mLastDownWidget = NULL;
                DoMouseUps(aWidget, aDownButtons);             
        }
       
        if ((mFocusWidget != NULL) && (mBelowModalFlagsMod.mRemoveFlags & WIDGETFLAGS_ALLOW_FOCUS) &&
                (IsBelow(mFocusWidget, mBaseModalWidget)))
        {
                Widget* aWidget = mFocusWidget;
                mFocusWidget = NULL;
                aWidget->LostFocus();          
        }
}

void WidgetManager::AddBaseModal(Widget* theWidget, const FlagsMod& theBelowFlagsMod)
{
        PreModalInfo aPreModalInfo;
        aPreModalInfo.mBaseModalWidget = theWidget;
        aPreModalInfo.mPrevBaseModalWidget = mBaseModalWidget;
        aPreModalInfo.mPrevFocusWidget = mFocusWidget;
        aPreModalInfo.mPrevBelowModalFlagsMod = mBelowModalFlagsMod;
        mPreModalInfoList.push_back(aPreModalInfo);

        SetBaseModal(theWidget, theBelowFlagsMod);
}

void WidgetManager::AddBaseModal(Widget* theWidget)
{
        AddBaseModal(theWidget, mDefaultBelowModalFlagsMod);
}

void WidgetManager::RemoveBaseModal(Widget* theWidget)
{
        DBG_ASSERT(mPreModalInfoList.size() > 0);
       
        bool first = true;
       
        while (mPreModalInfoList.size() > 0)
        {
                PreModalInfo* aPreModalInfo = &mPreModalInfoList.back();
               
                if ((first) && (aPreModalInfo->mBaseModalWidget != theWidget))
                {
                        // We don't remove it yet, because we want to restore
                        //  its keyboard focused widget and crap later
                        return;
                }
               
                // If we removed a widget's self from pre-modal info before
                //  then that means the dialog got removed out-of-order but we
                //  deferred setting the state back until now
                bool done = (aPreModalInfo->mPrevBaseModalWidget != NULL) ||
                        (mPreModalInfoList.size() == 1);

                SetBaseModal(aPreModalInfo->mPrevBaseModalWidget,
                        aPreModalInfo->mPrevBelowModalFlagsMod);

                if (mFocusWidget == NULL)
                {
                        mFocusWidget = aPreModalInfo->mPrevFocusWidget;
                        if (mFocusWidget != NULL)
                                mFocusWidget->GotFocus();
                }

                mPreModalInfoList.pop_back();          

                if (done)
                        break;

                first = false;
        }
}

void WidgetManager::Resize(const Rect& theMouseDestRect, const Rect& theMouseSourceRect)
{      
        mWidth = theMouseDestRect.mWidth + 2 * theMouseDestRect.mX;
        mHeight = theMouseDestRect.mHeight + 2 * theMouseDestRect.mY;
        mMouseDestRect = theMouseDestRect;
        mMouseSourceRect = theMouseSourceRect;
}

void WidgetManager::SetFocus(Widget* aWidget)
{      
        if (aWidget==mFocusWidget)
                return;

        if (mFocusWidget != NULL)
                mFocusWidget->LostFocus();

        if ((aWidget != NULL) && (aWidget->mWidgetManager == this))
        {
                mFocusWidget = aWidget;
               
                if ((mHasFocus) && (mFocusWidget != NULL))
                        mFocusWidget->GotFocus();
        }
        else
                mFocusWidget = NULL;
}

void WidgetManager::GotFocus()
{
        if (!mHasFocus)
        {
                mHasFocus = true;
       
                if (mFocusWidget != NULL)
                        mFocusWidget->GotFocus();
        }
}

void WidgetManager::LostFocus()
{
        if (mHasFocus)
        {
                mActualDownButtons = 0;
                for (int aKeyNum = 0; aKeyNum < 0xFF; aKeyNum++)
                {
                        if (mKeyDown[aKeyNum])
                                KeyUp((KeyCode) aKeyNum);
                }

                mHasFocus = false;
         
                if (mFocusWidget != NULL)
                        mFocusWidget->LostFocus();
        }
}

void WidgetManager::InitModalFlags(ModalFlags* theModalFlags)
{
        theModalFlags->mIsOver = mBaseModalWidget == NULL;
        theModalFlags->mOverFlags = GetWidgetFlags();
        theModalFlags->mUnderFlags = GetModFlags(theModalFlags->mOverFlags, mBelowModalFlagsMod);
}

void WidgetManager::DrawWidgetsTo(Graphics* g)
{
        mCurG = g;

        ModalFlags aModalFlags;
        InitModalFlags(&aModalFlags);

        WidgetList::iterator anItr = mWidgets.begin();
        while (anItr != mWidgets.end())
        {
                Widget* aWidget = *anItr;
               
                if (aWidget->mVisible)
                {
                        Graphics aClipG(*g);
                        aClipG.SetFastStretch(true);
                        aClipG.Translate(aWidget->mX, aWidget->mY);
                        aWidget->DrawAll(&aModalFlags, &aClipG);                       
                }

                ++anItr;
        }

        mCurG = NULL;
}

bool WidgetManager::DrawScreen()
{
        SEXY_AUTO_PERF("WidgetManager::DrawScreen");
        //DWORD start = timeGetTime();

        ModalFlags aModalFlags;
        InitModalFlags(&aModalFlags);

        bool drewStuff = false;
       
        int aDirtyCount = 0;
        bool hasTransients = false;
        bool hasDirtyTransients = false;

        // Survey
        WidgetList::iterator anItr = mWidgets.begin();
        while (anItr != mWidgets.end())
        {
                Widget* aWidget = *anItr;
                if (aWidget->mDirty)
                        aDirtyCount++;
                ++anItr;
        }
       
        mMinDeferredOverlayPriority = 0x7FFFFFFF;
        mDeferredOverlayWidgets.resize(0);

        Graphics aScrG(mImage);
        mCurG = &aScrG;

        DDImage* aDDImage = dynamic_cast<DDImage*>(mImage);
        bool surfaceLocked = false;
        if (aDDImage != NULL)
                surfaceLocked = aDDImage->LockSurface();

        if (aDirtyCount > 0)
        {
                Graphics g(aScrG);
                g.Translate(-mMouseDestRect.mX, -mMouseDestRect.mY);
                bool is3D = mApp->Is3DAccelerated();

                WidgetList::iterator anItr = mWidgets.begin();
                while (anItr != mWidgets.end())
                {
                        Widget* aWidget = *anItr;
                       
                        if (aWidget == mWidgetManager->mBaseModalWidget)
                                aModalFlags.mIsOver = true;

                        if ((aWidget->mDirty) && (aWidget->mVisible))
                        {
                                Graphics aClipG(g);
                                aClipG.SetFastStretch(!is3D);
                                aClipG.SetLinearBlend(is3D);
                                aClipG.Translate(aWidget->mX, aWidget->mY);                            
                                aWidget->DrawAll(&aModalFlags, &aClipG);
                                 
                                aDirtyCount++;
                                drewStuff = true;
                                aWidget->mDirty = false;
                        }

                        ++anItr;
                }
        }
       
        FlushDeferredOverlayWidgets(0x7FFFFFFF);

        if (aDDImage != NULL && surfaceLocked)
                aDDImage->UnlockSurface();

        mCurG = NULL;

        return drewStuff;
}

bool WidgetManager::UpdateFrame()
{
        SEXY_AUTO_PERF("WidgetManager::UpdateFrame");

        ModalFlags aModalFlags;
        InitModalFlags(&aModalFlags);

        // Keep us from having mLastWMUpdateCount interfere with our own updating
        mUpdateCnt++;
        mLastWMUpdateCount = mUpdateCnt;       
        UpdateAll(&aModalFlags);

        return mDirty;
}

bool WidgetManager::UpdateFrameF(float theFrac)
{
        SEXY_AUTO_PERF("WidgetManager::UpdateFrame");

        ModalFlags aModalFlags;
        InitModalFlags(&aModalFlags);

        UpdateFAll(&aModalFlags, theFrac);
        return mDirty;
}

void WidgetManager::SetPopupCommandWidget(Widget* theList)
{
        mPopupCommandWidget = theList;
        AddWidget(mPopupCommandWidget);
}

void WidgetManager::RemovePopupCommandWidget()
{
        if (mPopupCommandWidget != NULL)
        {
                Widget *aWidget = mPopupCommandWidget;
                mPopupCommandWidget = NULL;    
                RemoveWidget(aWidget);
        }
}

void WidgetManager::MousePosition(int x, int y)
{

        int aLastMouseX = mLastMouseX;
        int aLastMouseY = mLastMouseY;

        mLastMouseX = x;
        mLastMouseY = y;
       
        int aWidgetX;
        int aWidgetY;
        Widget* aWidget = GetWidgetAt(x, y, &aWidgetX, &aWidgetY);
       
        if (aWidget != mOverWidget)
        {
                Widget* aLastOverWidget = mOverWidget;
                mOverWidget = NULL;

                if (aLastOverWidget != NULL)
                        MouseLeave(aLastOverWidget);
               
                mOverWidget = aWidget;
                if (aWidget != NULL)
                {
                        MouseEnter(aWidget);
                        aWidget->MouseMove(aWidgetX, aWidgetY);
                }
        }
        else if ((aLastMouseX != x) || (aLastMouseY != y))
        {
                if (aWidget != NULL)
                        aWidget->MouseMove(aWidgetX, aWidgetY);        
        }
}

void WidgetManager::RehupMouse()
{
        if (mLastDownWidget != NULL)
        {
                if (mOverWidget != NULL)
                {                                              
                        Widget* aWidgetOver = GetWidgetAt(mLastMouseX, mLastMouseY, NULL, NULL);

                        if (aWidgetOver != mLastDownWidget)
                        {                                                              
                                Widget* anOverWidget = mOverWidget;
                                mOverWidget = NULL;    
                                MouseLeave(anOverWidget);
                        }
                }
        }
        else if (mMouseIn)
                MousePosition(mLastMouseX, mLastMouseY);
}

bool WidgetManager::MouseUp(int x, int y, int theClickCount)
{      
        mLastInputUpdateCnt = mUpdateCnt;
       
        int aMask;
       
        if (theClickCount < 0)
                aMask = 0x02;
        else if (theClickCount == 3)
                aMask = 0x04;
        else
                aMask = 0x01;

        // Make sure that we thought this button was down anyway - possibly not, if we
        //  disabled the widget already or something
        mActualDownButtons &= ~aMask;
        if ((mLastDownWidget != NULL) && ((mDownButtons & aMask) != 0))
        {
                Widget* aLastDownWidget = mLastDownWidget;

                mDownButtons &= ~aMask;        
                if (mDownButtons == 0)
                        mLastDownWidget = NULL;

                aLastDownWidget->mIsDown = false;
                aLastDownWidget->MouseUp(x - aLastDownWidget->mX, y - aLastDownWidget->mY, theClickCount);
        }      
        else
                mDownButtons &= ~aMask;        

        MousePosition(x, y);
       
        return true;
}

bool WidgetManager::MouseDown(int x, int y, int theClickCount)
{      
        mLastInputUpdateCnt = mUpdateCnt;

        if (theClickCount < 0)
                mActualDownButtons |= 0x02;
        else if (theClickCount == 3)
                mActualDownButtons |= 0x04;
        else
                mActualDownButtons |= 0x01;

        MousePosition(x, y);

        if ((mPopupCommandWidget != NULL) && (!mPopupCommandWidget->Contains(x, y)))
                RemovePopupCommandWidget();

        int aWidgetX;
        int aWidgetY;
        Widget* aWidget = GetWidgetAt(x, y, &aWidgetX, &aWidgetY);     

        // Begin mouse down options
/*     
        // Option 1
        //This code sets a new widget as the mouse drag focus widget and lets the old
        //mousedownwidget think the buttons popped up.
        if ((mLastDownWidget != NULL) && (mLastDownWidget != aWidget))
        {
                DoMouseUps(mLastDownWidget, mDownButtons);
                mDownButtons = 0;
        }
*/

        // Option 2
        // This code passes all button downs to the mLastDownWidget
        if (mLastDownWidget != NULL)
                aWidget = mLastDownWidget;

        // End mouse down options

        if (theClickCount < 0)
        {
                mLastDownButtonId = -1;
                mDownButtons |= 0x02;
        }
        else if (theClickCount == 3)
        {
                mLastDownButtonId = 2;
                mDownButtons |= 0x04;
        }
        else
        {
                mLastDownButtonId = 1;
                mDownButtons |= 0x01;
        }
       
        mLastDownWidget = aWidget;
        if (aWidget != NULL)
        {
                if (aWidget->WantsFocus())
                        SetFocus(aWidget);
               
                aWidget->mIsDown = true;
                aWidget->MouseDown(aWidgetX, aWidgetY, theClickCount);
        }
       
        return true;
}

bool WidgetManager::MouseMove(int x, int y)
{      
        mLastInputUpdateCnt = mUpdateCnt;

        if (mDownButtons)
                return MouseDrag(x,y);

        mMouseIn = true;
        MousePosition(x, y);   
                       
        return true;
}

bool WidgetManager::MouseDrag(int x, int y)
{      
        mLastInputUpdateCnt = mUpdateCnt;

        mMouseIn = true;
        mLastMouseX = x;
        mLastMouseY = y;

        if ((mOverWidget != NULL) && (mOverWidget != mLastDownWidget))
        {
                Widget* anOverWidget = mOverWidget;
                mOverWidget = NULL;    
                MouseLeave(anOverWidget);              
        }

        if (mLastDownWidget != NULL)
        {
                Point anAbsPos = mLastDownWidget->GetAbsPos();

                int aWidgetX = x - anAbsPos.mX;
                int aWidgetY = y - anAbsPos.mY;        
                mLastDownWidget->MouseDrag(aWidgetX, aWidgetY);        
               
                Widget* aWidgetOver = GetWidgetAt(x, y, NULL, NULL);

                if ((aWidgetOver == mLastDownWidget) && (aWidgetOver != NULL))
                {
                        if (mOverWidget == NULL)
                        {
                                mOverWidget = mLastDownWidget;
                                MouseEnter(mOverWidget);
                        }
                }
                else
                {
                        if (mOverWidget != NULL)
                        {
                                Widget* anOverWidget = mOverWidget;
                                mOverWidget = NULL;    
                                MouseLeave(anOverWidget);                              
                        }
                }
        }
       
        return true;   
}

bool WidgetManager::MouseExit(int x, int y)
{      
        mLastInputUpdateCnt = mUpdateCnt;

        mMouseIn = false;

        if (mOverWidget != NULL)
        {
                MouseLeave(mOverWidget);
                mOverWidget = NULL;
        }
       
        return true;
}

void WidgetManager::MouseWheel(int theDelta)
{
        mLastInputUpdateCnt = mUpdateCnt;

        if (mFocusWidget != NULL)
                mFocusWidget->MouseWheel(theDelta);
}

bool WidgetManager::KeyChar(SexyChar theChar)
{
        mLastInputUpdateCnt = mUpdateCnt;

        if (theChar == KEYCODE_TAB)
        {
                //TODO: Check thing

                if (mKeyDown[KEYCODE_CONTROL])
                {
                        if (mDefaultTab != NULL)
                                mDefaultTab->KeyChar(theChar);
                       
                        return true;
                }
        }

        if (mFocusWidget != NULL)
                mFocusWidget->KeyChar(theChar);
       
        return true;
}

bool WidgetManager::KeyDown(KeyCode key)
{
        mLastInputUpdateCnt = mUpdateCnt;

        if ((key >= 0) && (key < 0xFF))
                mKeyDown[key] = true;

        if (mFocusWidget != NULL)
                mFocusWidget->KeyDown(key);
       
        return true;
}

bool WidgetManager::KeyUp(KeyCode key)
{
        mLastInputUpdateCnt = mUpdateCnt;

        if ((key >= 0) && (key < 0xFF))
                mKeyDown[key] = false;

        if ((key == KEYCODE_TAB) && (mKeyDown[KEYCODE_CONTROL]))
                return true;   

        if (mFocusWidget != NULL)
                mFocusWidget->KeyUp(key);
       
        return true;
}