123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "gui/containers/guiTabBookCtrl.h"
- #include "console/engineAPI.h"
- #include "gui/core/guiCanvas.h"
- #include "gui/editor/guiEditCtrl.h"
- #include "gui/controls/guiPopUpCtrl.h"
- #include "gui/core/guiDefaultControlRender.h"
- #include "gfx/gfxDrawUtil.h"
- IMPLEMENT_CONOBJECT( GuiTabBookCtrl );
- ConsoleDocClass( GuiTabBookCtrl,
- "@brief A container \n\n"
-
- "@tsexample\n"
- "// Create \n"
- "@endtsexample\n\n"
-
- "@note Only GuiTabPageCtrls must be added to GuiTabBookCtrls. If an object of a different "
- "class is added to the control, it will be reassigned to either the active page or the "
- "tab book's parent.\n\n"
-
- "@see GuiTabPageCtrl\n"
-
- "@ingroup GuiContainers"
- );
- ImplementEnumType( GuiTabPosition,
- "Where the control should put the tab headers for selecting individual pages.\n\n"
- "@ingroup GuiContainers" )
- { GuiTabBookCtrl::AlignTop, "Top", "Tab headers on top edge." },
- { GuiTabBookCtrl::AlignBottom,"Bottom", "Tab headers on bottom edge." }
- EndImplementEnumType;
- IMPLEMENT_CALLBACK( GuiTabBookCtrl, onTabSelected, void, ( const String& text, U32 index ), ( text, index ),
- "Called when a new tab page is selected.\n\n"
- "@param text Text of the page header for the tab that is being selected.\n"
- "@param index Index of the tab page being selected." );
- IMPLEMENT_CALLBACK( GuiTabBookCtrl, onTabRightClick, void, ( const String& text, U32 index ), ( text, index ),
- "Called when the user right-clicks on a tab page header.\n\n"
- "@param text Text of the page header for the tab that is being selected.\n"
- "@param index Index of the tab page being selected." );
- //-----------------------------------------------------------------------------
- GuiTabBookCtrl::GuiTabBookCtrl()
- {
- VECTOR_SET_ASSOCIATION( mPages );
-
- mTabHeight = 24;
- mTabPosition = AlignTop;
- mActivePage = NULL;
- mHoverTab = NULL;
- mHasTexture = false;
- mBitmapBounds = NULL;
- setExtent( 400, 300 );
- mPageRect = RectI(0,0,0,0);
- mTabRect = RectI(0,0,0,0);
- mFrontTabPadding = 0;
- mPages.reserve(12);
- mTabMargin = 7;
- mMinTabWidth = 64;
- mIsContainer = true;
- mSelectedPageNum = -1;
- mDefaultPageNum = -1;
- mAllowReorder = false;
- mDraggingTab = false;
- mDraggingTabRect = false;
- mIsFirstWake = true;
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::initPersistFields()
- {
- addGroup( "TabBook" );
-
- addField( "tabPosition", TYPEID< TabPosition >(), Offset( mTabPosition, GuiTabBookCtrl ),
- "Where to place the tab page headers." );
- addField( "tabMargin", TypeS32, Offset( mTabMargin, GuiTabBookCtrl ),
- "Spacing to put between individual tab page headers." );
- addField( "minTabWidth", TypeS32, Offset( mMinTabWidth, GuiTabBookCtrl ),
- "Minimum width allocated to a tab page header." );
- addField( "tabHeight", TypeS32, Offset( mTabHeight, GuiTabBookCtrl ),
- "Height of tab page headers." );
- addField( "allowReorder", TypeBool, Offset( mAllowReorder, GuiTabBookCtrl ),
- "Whether reordering tabs with the mouse is allowed." );
- addField( "defaultPage", TypeS32, Offset( mDefaultPageNum, GuiTabBookCtrl ),
- "Index of page to select on first onWake() call (-1 to disable)." );
- addProtectedField( "selectedPage", TypeS32, Offset( mSelectedPageNum, GuiTabBookCtrl ),
- &_setSelectedPage, &defaultProtectedGetFn,
- "Index of currently selected page." );
- addField( "frontTabPadding", TypeS32, Offset( mFrontTabPadding, GuiTabBookCtrl ),
- "X offset of first tab page header." );
- endGroup( "TabBook" );
- Parent::initPersistFields();
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::onChildRemoved( GuiControl* child )
- {
- for (S32 i = 0; i < mPages.size(); i++ )
- {
- GuiTabPageCtrl* tab = mPages[i].Page;
- if( tab == child )
- {
- mPages.erase( i );
- break;
- }
- }
- // Calculate Page Information
- calculatePageTabs();
- // Active Index.
- mSelectedPageNum = getMin( mSelectedPageNum, mPages.size() - 1 );
- if ( mSelectedPageNum != -1 )
- {
- // Select Page.
- selectPage( mSelectedPageNum );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::onChildAdded( GuiControl *child )
- {
- GuiTabPageCtrl *page = dynamic_cast<GuiTabPageCtrl*>(child);
- if( !page )
- {
- Con::warnf("GuiTabBookCtrl::onChildAdded - attempting to add NON GuiTabPageCtrl as child page");
- SimObject *simObj = reinterpret_cast<SimObject*>(child);
- removeObject( simObj );
- if( mActivePage )
- {
- mActivePage->addObject( simObj );
- }
- else
- {
- Con::warnf("GuiTabBookCtrl::onChildAdded - unable to find active page to reassign ownership of new child control to, placing on parent");
- GuiControl *rent = getParent();
- if( rent )
- rent->addObject( simObj );
- }
- return;
- }
- TabHeaderInfo newPage;
- newPage.Page = page;
- newPage.TabRow = -1;
- newPage.TabColumn = -1;
- mPages.push_back( newPage );
- // Calculate Page Information
- calculatePageTabs();
- if( page->getFitBook() )
- fitPage( page );
- // Select this Page
- selectPage( page );
- }
- //-----------------------------------------------------------------------------
- bool GuiTabBookCtrl::reOrder(SimObject* obj, SimObject* target)
- {
- if ( !Parent::reOrder(obj, target) )
- return false;
- // Store the Selected Page.
- GuiTabPageCtrl *selectedPage = NULL;
- if ( mSelectedPageNum != -1 )
- selectedPage = mPages[mSelectedPageNum].Page;
- // Determine the Target Page Index.
- S32 targetIndex = -1;
- for( S32 i = 0; i < mPages.size(); i++ )
- {
- const TabHeaderInfo &info = mPages[i];
- if ( info.Page == target )
- {
- targetIndex = i;
- break;
- }
- }
- if ( targetIndex == -1 )
- {
- return false;
- }
- for( S32 i = 0; i < mPages.size(); i++ )
- {
- const TabHeaderInfo &info = mPages[i];
- if ( info.Page == obj )
- {
- // Store Info.
- TabHeaderInfo objPage = info;
- // Remove.
- mPages.erase( i );
- // Insert.
- mPages.insert( targetIndex, objPage );
- break;
- }
- }
- // Update Tabs.
- calculatePageTabs();
- // Reselect Page.
- selectPage( selectedPage );
- return true;
- }
- //-----------------------------------------------------------------------------
- bool GuiTabBookCtrl::acceptsAsChild( SimObject* object ) const
- {
- // Only accept tab pages.
- return ( dynamic_cast< GuiTabPageCtrl* >( object ) != NULL );
- }
- //-----------------------------------------------------------------------------
- bool GuiTabBookCtrl::onWake()
- {
- if (! Parent::onWake())
- return false;
- mHasTexture = mProfile->constructBitmapArray() > 0;
- if( mHasTexture )
- {
- mBitmapBounds = mProfile->mBitmapArrayRects.address();
- mTabHeight = mBitmapBounds[TabSelected].extent.y;
- }
- calculatePageTabs();
-
- if( mIsFirstWake )
- {
- // Awaken all pages, visible or not. We need to do this so
- // any pages that make use of a language table for their label
- // are correctly initialized.
- for ( U32 i = 0; i < mPages.size(); ++i)
- {
- if ( !mPages[i].Page->isAwake() )
- {
- mPages[i].Page->awaken();
- }
- }
- if( mDefaultPageNum >= 0 && mDefaultPageNum < mPages.size() )
- selectPage( mDefaultPageNum );
- mIsFirstWake = false;
- }
- return true;
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::addNewPage( const char* text )
- {
- GuiTabPageCtrl* page = new GuiTabPageCtrl();
-
- if( text )
- page->setText( text );
-
- page->registerObject();
- addObject( page );
- }
- //-----------------------------------------------------------------------------
- bool GuiTabBookCtrl::resize(const Point2I &newPosition, const Point2I &newExtent)
- {
- bool result = Parent::resize( newPosition, newExtent );
- calculatePageTabs();
-
- return result;
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::childResized(GuiControl *child)
- {
- Parent::childResized( child );
- //child->resize( mPageRect.point, mPageRect.extent );
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::onMouseDown(const GuiEvent &event)
- {
- mDraggingTab = false;
- mDraggingTabRect = false;
- Point2I localMouse = globalToLocalCoord( event.mousePoint );
- if( mTabRect.pointInRect( localMouse ) )
- {
- GuiTabPageCtrl *tab = findHitTab( localMouse );
- if( tab != NULL )
- {
- selectPage( tab );
- mDraggingTab = mAllowReorder;
- }
- else
- {
- mDraggingTabRect = true;
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::onMouseUp(const GuiEvent &event)
- {
- Parent::onMouseUp( event );
- mDraggingTab = false;
- mDraggingTabRect = false;
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::onMouseDragged(const GuiEvent &event)
- {
- Parent::onMouseDragged( event );
- if ( !mDraggingTab )
- return;
- GuiTabPageCtrl *selectedPage = NULL;
- if ( mSelectedPageNum != -1 )
- selectedPage = mPages[mSelectedPageNum].Page;
- if ( !selectedPage )
- return;
- Point2I localMouse = globalToLocalCoord( event.mousePoint );
- if( mTabRect.pointInRect( localMouse ) )
- {
- GuiTabPageCtrl *tab = findHitTab( localMouse );
- if( tab != NULL && tab != selectedPage )
- {
- S32 targetIndex = -1;
- for( S32 i = 0; i < mPages.size(); i++ )
- {
- if( mPages[i].Page == tab )
- {
- targetIndex = i;
- break;
- }
- }
- if ( targetIndex > mSelectedPageNum )
- {
- reOrder( tab, selectedPage );
- }
- else
- {
- reOrder( selectedPage, tab );
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::onMouseMove(const GuiEvent &event)
- {
- Point2I localMouse = globalToLocalCoord( event.mousePoint );
- if( mTabRect.pointInRect( localMouse ) )
- {
- GuiTabPageCtrl *tab = findHitTab( localMouse );
- if( tab != NULL && mHoverTab != tab )
- mHoverTab = tab;
- else if ( !tab )
- mHoverTab = NULL;
- }
- Parent::onMouseMove( event );
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::onMouseLeave( const GuiEvent &event )
- {
- Parent::onMouseLeave( event );
-
- mHoverTab = NULL;
- }
- //-----------------------------------------------------------------------------
- bool GuiTabBookCtrl::onMouseDownEditor(const GuiEvent &event, Point2I offset)
- {
- bool handled = false;
- Point2I localMouse = globalToLocalCoord( event.mousePoint );
- if( mTabRect.pointInRect( localMouse ) )
- {
- GuiTabPageCtrl *tab = findHitTab( localMouse );
- if( tab != NULL )
- {
- selectPage( tab );
- handled = true;
- }
- }
- #ifdef TORQUE_TOOLS
- // This shouldn't be called if it's not design time, but check just incase
- if ( GuiControl::smDesignTime )
- {
- // If we clicked in the editor and our addset is the tab book
- // ctrl, select the child ctrl so we can edit it's properties
- GuiEditCtrl* edit = GuiControl::smEditorHandle;
- if( edit && ( edit->getAddSet() == this ) && mActivePage != NULL )
- edit->select( mActivePage );
- }
- #endif
- // Return whether we handled this or not.
- return handled;
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::onRightMouseUp( const GuiEvent& event )
- {
- Point2I localMouse = globalToLocalCoord( event.mousePoint );
- if( mTabRect.pointInRect( localMouse ) )
- {
- GuiTabPageCtrl* tab = findHitTab( localMouse );
- if( tab )
- onTabRightClick_callback( tab->getText(), getPageNum( tab ) );
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::onRender(Point2I offset, const RectI &updateRect)
- {
- RectI tabRect = mTabRect;
- tabRect.point += offset;
- RectI pageRect = mPageRect;
- pageRect.point += offset;
- // We're so nice we'll store the old modulation before we clear it for our rendering! :)
- ColorI oldModulation;
- GFX->getDrawUtil()->getBitmapModulation( &oldModulation );
- // Wipe it out
- GFX->getDrawUtil()->clearBitmapModulation();
- Parent::onRender(offset, updateRect);
- // Clip to tab area
- RectI savedClipRect = GFX->getClipRect();
- RectI clippedTabRect = tabRect;
- clippedTabRect.intersect( savedClipRect );
- GFX->setClipRect( clippedTabRect );
- // Render our tabs
- renderTabs( offset, tabRect );
- // Restore Rect.
- GFX->setClipRect( savedClipRect );
- // Restore old modulation
- GFX->getDrawUtil()->setBitmapModulation( oldModulation );
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::renderTabs( const Point2I &offset, const RectI &tabRect )
- {
- // If the tab size is zero, don't render tabs,
- // assuming it's a tab-less book
- if( mPages.empty() || mTabHeight <= 0 )
- return;
- for( S32 i = 0; i < mPages.size(); i++ )
- {
- const TabHeaderInfo ¤tTabInfo = mPages[i];
- RectI tabBounds = mPages[i].TabRect;
- tabBounds.point += offset;
- GuiTabPageCtrl *tab = mPages[i].Page;
- if( tab != NULL )
- renderTab( tabBounds, tab );
- // If we're on the last tab, draw the nice end piece
- if( i + 1 == mPages.size() )
- {
- Point2I tabEndPoint = Point2I(currentTabInfo.TabRect.point.x + currentTabInfo.TabRect.extent.x + offset.x, currentTabInfo.TabRect.point.y + offset.y);
- Point2I tabEndExtent = Point2I((tabRect.point.x + tabRect.extent.x) - tabEndPoint.x, currentTabInfo.TabRect.extent.y);
- RectI tabEndRect = RectI(tabEndPoint,tabEndExtent);
- GFX->setClipRect( tabEndRect );
- // As it turns out the last tab can be outside the viewport in which
- // case trying to render causes a DX assert. Could be better if
- // setClipRect returned a bool.
- if ( GFX->getViewport().isValidRect() )
- renderFixedBitmapBordersFilled( tabEndRect, TabEnds + 1, mProfile );
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::renderTab(const RectI& tabRect, GuiTabPageCtrl *tab)
- {
- StringTableEntry text = tab->getText();
- ColorI oldColor;
- GFX->getDrawUtil()->getBitmapModulation( &oldColor );
- // Is this a skinned control?
- if( mHasTexture && mProfile->mBitmapArrayRects.size() >= 9 )
- {
- S32 indexMultiplier = 1;
- switch( mTabPosition )
- {
- case AlignTop:
- case AlignBottom:
-
- if ( mActivePage == tab )
- indexMultiplier += TabSelected;
- else if( mHoverTab == tab )
- indexMultiplier += TabHover;
- else
- indexMultiplier += TabNormal;
- break;
- }
- renderFixedBitmapBordersFilled( tabRect, indexMultiplier, mProfile );
- }
- else
- {
- // If this isn't a skinned control or the bitmap is simply missing, handle it WELL
- if ( mActivePage == tab )
- GFX->getDrawUtil()->drawRectFill(tabRect, mProfile->mFillColor);
- else if( mHoverTab == tab )
- GFX->getDrawUtil()->drawRectFill(tabRect, mProfile->mFillColorHL);
- else
- GFX->getDrawUtil()->drawRectFill(tabRect, mProfile->mFillColorNA);
- }
- GFX->getDrawUtil()->setBitmapModulation(mProfile->mFontColor);
- switch( mTabPosition )
- {
- case AlignTop:
- case AlignBottom:
- renderJustifiedText( tabRect.point, tabRect.extent, text);
- break;
- }
- GFX->getDrawUtil()->setBitmapModulation( oldColor);
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::setUpdate()
- {
- Parent::setUpdate();
- setUpdateRegion(Point2I(0,0), getExtent());
- calculatePageTabs();
- }
- //-----------------------------------------------------------------------------
- S32 GuiTabBookCtrl::calculatePageTabWidth( GuiTabPageCtrl *page )
- {
- if( !page )
- return mMinTabWidth;
- const char* text = page->getText();
- if( !text || dStrlen(text) == 0 || mProfile == NULL || mProfile->mFont == NULL )
- return mMinTabWidth;
- GFont *font = mProfile->mFont;
- return font->getStrNWidth( text, dStrlen(text) );
- }
- //-----------------------------------------------------------------------------
- const RectI GuiTabBookCtrl::getClientRect()
- {
- if( !mProfile || mProfile->mBitmapArrayRects.size() < NumBitmaps )
- return Parent::getClientRect();
- return mPageRect;
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::calculatePageTabs()
- {
- // Short Circuit.
- //
- // If the tab size is zero, don't render tabs,
- // assuming it's a tab-less book
- if( mPages.empty() || mTabHeight <= 0 )
- {
- mPageRect.point.x = 0;
- mPageRect.point.y = 0;
- mPageRect.extent.x = getWidth();
- mPageRect.extent.y = getHeight();
- return;
- }
- S32 currRow = 0;
- S32 currColumn = 0;
- S32 currX = mFrontTabPadding;
- S32 maxWidth = 0;
- for( S32 i = 0; i < mPages.size(); i++ )
- {
- // Fetch Tab Width
- S32 tabWidth = calculatePageTabWidth( mPages[i].Page ) + ( mTabMargin * 2 );
- tabWidth = getMax( tabWidth, mMinTabWidth );
- TabHeaderInfo &info = mPages[i];
- switch( mTabPosition )
- {
- case AlignTop:
- case AlignBottom:
- // If we're going to go outside our bounds
- // with this tab move it down a row
- if( currX + tabWidth > getWidth() )
- {
- // Calculate and Advance State.
- maxWidth = getMax( tabWidth, maxWidth );
- balanceRow( currRow, currX );
- info.TabRow = ++currRow;
- // Reset Necessaries
- info.TabColumn = currColumn = maxWidth = currX = 0;
- }
- else
- {
- info.TabRow = currRow;
- info.TabColumn = currColumn++;
- }
- // Calculate Tabs Bounding Rect
- info.TabRect.point.x = currX;
- info.TabRect.extent.x = tabWidth;
- info.TabRect.extent.y = mTabHeight;
- // Adjust Y Point based on alignment
- if( mTabPosition == AlignTop )
- info.TabRect.point.y = ( info.TabRow * mTabHeight );
- else
- info.TabRect.point.y = getHeight() - ( ( 1 + info.TabRow ) * mTabHeight );
- currX += tabWidth;
- break;
- };
- }
- currRow++;
- currColumn++;
- Point2I localPoint = getExtent();
- // Calculate
- switch( mTabPosition )
- {
- case AlignTop:
- localPoint.y -= getTop();
- mTabRect.point.x = 0;
- mTabRect.extent.x = localPoint.x;
- mTabRect.point.y = 0;
- mTabRect.extent.y = currRow * mTabHeight;
- mPageRect.point.x = 0;
- mPageRect.point.y = mTabRect.extent.y;
- mPageRect.extent.x = mTabRect.extent.x;
- mPageRect.extent.y = getHeight() - mTabRect.extent.y;
- break;
- case AlignBottom:
- mTabRect.point.x = 0;
- mTabRect.extent.x = localPoint.x;
- mTabRect.extent.y = currRow * mTabHeight;
- mTabRect.point.y = getHeight() - mTabRect.extent.y;
- mPageRect.point.x = 0;
- mPageRect.point.y = 0;
- mPageRect.extent.x = mTabRect.extent.x;
- mPageRect.extent.y = localPoint.y - mTabRect.extent.y;
- break;
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::balanceRow( S32 row, S32 totalTabWidth )
- {
- // Short Circuit.
- //
- // If the tab size is zero, don't render tabs,
- // and assume it's a tab-less tab-book - JDD
- if( mPages.empty() || mTabHeight <= 0 )
- return;
- Vector<TabHeaderInfo*> rowTemp;
- rowTemp.clear();
- for( S32 i = 0; i < mPages.size(); i++ )
- {
- TabHeaderInfo &info = mPages[i];
- if(info.TabRow == row )
- rowTemp.push_back( &mPages[i] );
- }
- if( rowTemp.empty() )
- return;
- // Balance the tabs across the remaining space
- S32 spaceToDivide = getWidth() - totalTabWidth;
- S32 pointDelta = 0;
- for( S32 i = 0; i < rowTemp.size(); i++ )
- {
- TabHeaderInfo &info = *rowTemp[i];
- S32 extraSpace = (S32)spaceToDivide / ( rowTemp.size() );
- info.TabRect.extent.x += extraSpace;
- info.TabRect.point.x += pointDelta;
- pointDelta += extraSpace;
- }
- }
- //-----------------------------------------------------------------------------
- GuiTabPageCtrl *GuiTabBookCtrl::findHitTab( const GuiEvent &event )
- {
- return findHitTab( event.mousePoint );
- }
- //-----------------------------------------------------------------------------
- GuiTabPageCtrl *GuiTabBookCtrl::findHitTab( Point2I hitPoint )
- {
- // Short Circuit.
- //
- // If the tab size is zero, don't render tabs,
- // and assume it's a tab-less tab-book - JDD
- if( mPages.empty() || mTabHeight <= 0 )
- return NULL;
- for( S32 i = 0; i < mPages.size(); i++ )
- {
- if( mPages[i].TabRect.pointInRect( hitPoint ) )
- return mPages[i].Page;
- }
- return NULL;
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::selectPage( S32 index )
- {
- if( mPages.empty() || index < 0 )
- return;
- if( mPages.size() <= index )
- index = mPages.size() - 1;
- // Select the page
- selectPage( mPages[ index ].Page );
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::selectPage( GuiTabPageCtrl *page )
- {
- // Return if already selected.
- if( mSelectedPageNum >= 0 && mSelectedPageNum < mPages.size() && mPages[ mSelectedPageNum ].Page == page )
- return;
-
- mSelectedPageNum = -1;
- Vector<TabHeaderInfo>::iterator i = mPages.begin();
- for( S32 index = 0; i != mPages.end() ; i++, index++ )
- {
- GuiTabPageCtrl *tab = (*i).Page;
- if( page == tab )
- {
- mActivePage = tab;
- tab->setVisible( true );
- mSelectedPageNum = index;
-
- // Notify User
- onTabSelected_callback( tab->getText(), index );
- }
- else
- tab->setVisible( false );
- }
- setUpdateLayout( updateSelf );
- }
- //-----------------------------------------------------------------------------
- bool GuiTabBookCtrl::_setSelectedPage( void *object, const char *index, const char *data )
- {
- GuiTabBookCtrl* book = reinterpret_cast< GuiTabBookCtrl* >( object );
- book->selectPage( dAtoi( data ) );
- return false;
- }
- //-----------------------------------------------------------------------------
- bool GuiTabBookCtrl::onKeyDown(const GuiEvent &event)
- {
- // Tab = Next Page
- // Ctrl-Tab = Previous Page
- if( 0 && event.keyCode == KEY_TAB )
- {
- if( event.modifier & SI_PRIMARY_CTRL )
- selectPrevPage();
- else
- selectNextPage();
- return true;
- }
- return Parent::onKeyDown( event );
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::selectNextPage()
- {
- if( mPages.empty() )
- return;
- if( mActivePage == NULL )
- mActivePage = mPages[0].Page;
- S32 nI = 0;
- for( ; nI < mPages.size(); nI++ )
- {
- GuiTabPageCtrl *tab = mPages[ nI ].Page;
- if( tab == mActivePage )
- {
- if( nI == ( mPages.size() - 1 ) )
- selectPage( 0 );
- else if ( nI + 1 <= ( mPages.size() - 1 ) )
- selectPage( nI + 1 );
- else
- selectPage( 0 );
- return;
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::selectPrevPage()
- {
- if( mPages.empty() )
- return;
- if( mActivePage == NULL )
- mActivePage = mPages[0].Page;
- S32 nI = 0;
- for( ; nI < mPages.size(); nI++ )
- {
- GuiTabPageCtrl *tab = mPages[ nI ].Page;
- if( tab == mActivePage )
- {
- if( nI == 0 )
- selectPage( mPages.size() - 1 );
- else
- selectPage( nI - 1 );
- return;
- }
- }
- }
- //-----------------------------------------------------------------------------
- void GuiTabBookCtrl::fitPage( GuiTabPageCtrl* page )
- {
- page->resize( mPageRect.point, mPageRect.extent );
- }
- //-----------------------------------------------------------------------------
- S32 GuiTabBookCtrl::getPageNum( GuiTabPageCtrl* page ) const
- {
- const U32 numPages = mPages.size();
- for( U32 i = 0; i < numPages; ++ i )
- if( mPages[ i ].Page == page )
- return i;
-
- return -1;
- }
- //=============================================================================
- // API.
- //=============================================================================
- // MARK: ---- API ----
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTabBookCtrl, addPage, void, ( const char* title ), ( "" ),
- "Add a new tab page to the control.\n\n"
- "@param title Title text for the tab page header." )
- {
- object->addNewPage( title );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTabBookCtrl, selectPage, void, ( S32 index ),,
- "Set the selected tab page.\n\n"
- "@param index Index of the tab page." )
- {
- object->selectPage( index );
- }
- //-----------------------------------------------------------------------------
- DefineEngineMethod( GuiTabBookCtrl, getSelectedPage, S32, (),,
- "Get the index of the currently selected tab page.\n\n"
- "@return Index of the selected tab page or -1 if no tab page is selected." )
- {
- return object->getSelectedPageNum();
- }
|