2011-08-28 15:17:58 +02:00
/*
2017-01-13 11:47:07 +01:00
* Copyright ( c ) 2010 - 2017 OTClient < https : //github.com/edubart/otclient>
2011-08-28 15:17:58 +02:00
*
* 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 .
*/
2011-08-26 17:06:52 +02:00
# include "uianchorlayout.h"
# include "uiwidget.h"
2013-02-18 17:16:22 +01:00
UIWidgetPtr UIAnchor : : getHookedWidget ( const UIWidgetPtr & widget , const UIWidgetPtr & parentWidget )
{
// determine hooked widget
UIWidgetPtr hookedWidget ;
if ( parentWidget ) {
if ( m_hookedWidgetId = = " parent " )
hookedWidget = parentWidget ;
else if ( m_hookedWidgetId = = " next " )
hookedWidget = parentWidget - > getChildAfter ( widget ) ;
else if ( m_hookedWidgetId = = " prev " )
hookedWidget = parentWidget - > getChildBefore ( widget ) ;
else
hookedWidget = parentWidget - > getChildById ( m_hookedWidgetId ) ;
}
return hookedWidget ;
}
int UIAnchor : : getHookedPoint ( const UIWidgetPtr & hookedWidget , const UIWidgetPtr & parentWidget )
{
// determine hooked widget edge point
Rect hookedWidgetRect = hookedWidget - > getRect ( ) ;
if ( hookedWidget = = parentWidget )
hookedWidgetRect = parentWidget - > getPaddingRect ( ) ;
int point = 0 ;
switch ( m_hookedEdge ) {
case Fw : : AnchorLeft :
point = hookedWidgetRect . left ( ) ;
break ;
case Fw : : AnchorRight :
point = hookedWidgetRect . right ( ) ;
break ;
case Fw : : AnchorTop :
point = hookedWidgetRect . top ( ) ;
break ;
case Fw : : AnchorBottom :
point = hookedWidgetRect . bottom ( ) ;
break ;
case Fw : : AnchorHorizontalCenter :
point = hookedWidgetRect . horizontalCenter ( ) ;
break ;
case Fw : : AnchorVerticalCenter :
point = hookedWidgetRect . verticalCenter ( ) ;
break ;
default :
// must never happens
assert ( false ) ;
break ;
}
if ( hookedWidget = = parentWidget ) {
switch ( m_hookedEdge ) {
case Fw : : AnchorLeft :
case Fw : : AnchorRight :
case Fw : : AnchorHorizontalCenter :
point - = parentWidget - > getVirtualOffset ( ) . x ;
break ;
case Fw : : AnchorBottom :
case Fw : : AnchorTop :
case Fw : : AnchorVerticalCenter :
point - = parentWidget - > getVirtualOffset ( ) . y ;
break ;
default :
break ;
}
}
return point ;
}
void UIAnchorGroup : : addAnchor ( const UIAnchorPtr & anchor )
2011-08-26 17:06:52 +02:00
{
// duplicated anchors must be replaced
2013-02-18 17:16:22 +01:00
for ( UIAnchorPtr & other : m_anchors ) {
if ( other - > getAnchoredEdge ( ) = = anchor - > getAnchoredEdge ( ) ) {
2011-08-26 17:06:52 +02:00
other = anchor ;
return ;
}
}
m_anchors . push_back ( anchor ) ;
}
2011-08-28 18:02:26 +02:00
void UIAnchorLayout : : addAnchor ( const UIWidgetPtr & anchoredWidget , Fw : : AnchorEdge anchoredEdge ,
const std : : string & hookedWidgetId , Fw : : AnchorEdge hookedEdge )
2011-08-26 17:06:52 +02:00
{
if ( ! anchoredWidget )
return ;
assert ( anchoredWidget ! = getParentWidget ( ) ) ;
2013-02-18 17:16:22 +01:00
UIAnchorPtr anchor ( new UIAnchor ( anchoredEdge , hookedWidgetId , hookedEdge ) ) ;
UIAnchorGroupPtr & anchorGroup = m_anchorsGroups [ anchoredWidget ] ;
if ( ! anchorGroup )
anchorGroup = UIAnchorGroupPtr ( new UIAnchorGroup ) ;
anchorGroup - > addAnchor ( anchor ) ;
2011-08-26 17:06:52 +02:00
// layout must be updated because a new anchor got in
update ( ) ;
}
void UIAnchorLayout : : removeAnchors ( const UIWidgetPtr & anchoredWidget )
{
m_anchorsGroups . erase ( anchoredWidget ) ;
update ( ) ;
}
2012-03-28 16:10:21 +02:00
bool UIAnchorLayout : : hasAnchors ( const UIWidgetPtr & anchoredWidget )
{
return m_anchorsGroups . find ( anchoredWidget ) ! = m_anchorsGroups . end ( ) ;
}
2011-08-26 17:06:52 +02:00
void UIAnchorLayout : : centerIn ( const UIWidgetPtr & anchoredWidget , const std : : string & hookedWidgetId )
{
2011-08-28 18:02:26 +02:00
addAnchor ( anchoredWidget , Fw : : AnchorHorizontalCenter , hookedWidgetId , Fw : : AnchorHorizontalCenter ) ;
addAnchor ( anchoredWidget , Fw : : AnchorVerticalCenter , hookedWidgetId , Fw : : AnchorVerticalCenter ) ;
2011-08-26 17:06:52 +02:00
}
void UIAnchorLayout : : fill ( const UIWidgetPtr & anchoredWidget , const std : : string & hookedWidgetId )
{
2011-08-28 18:02:26 +02:00
addAnchor ( anchoredWidget , Fw : : AnchorLeft , hookedWidgetId , Fw : : AnchorLeft ) ;
addAnchor ( anchoredWidget , Fw : : AnchorRight , hookedWidgetId , Fw : : AnchorRight ) ;
addAnchor ( anchoredWidget , Fw : : AnchorTop , hookedWidgetId , Fw : : AnchorTop ) ;
addAnchor ( anchoredWidget , Fw : : AnchorBottom , hookedWidgetId , Fw : : AnchorBottom ) ;
2011-08-26 17:06:52 +02:00
}
void UIAnchorLayout : : addWidget ( const UIWidgetPtr & widget )
{
update ( ) ;
}
void UIAnchorLayout : : removeWidget ( const UIWidgetPtr & widget )
{
removeAnchors ( widget ) ;
}
2013-02-18 17:16:22 +01:00
bool UIAnchorLayout : : updateWidget ( const UIWidgetPtr & widget , const UIAnchorGroupPtr & anchorGroup , UIWidgetPtr first )
2011-08-26 17:06:52 +02:00
{
UIWidgetPtr parentWidget = getParentWidget ( ) ;
2012-01-23 14:47:15 +01:00
if ( ! parentWidget )
2012-03-27 20:14:35 +02:00
return false ;
2012-01-23 14:47:15 +01:00
2012-05-01 15:06:38 +02:00
if ( first = = widget ) {
2012-06-01 22:39:23 +02:00
g_logger . error ( stdext : : format ( " child '%s' of parent widget '%s' is recursively anchored to itself, please fix this " , widget - > getId ( ) , parentWidget - > getId ( ) ) ) ;
2012-05-01 15:06:38 +02:00
return false ;
}
if ( ! first )
first = widget ;
2011-08-26 17:06:52 +02:00
Rect newRect = widget - > getRect ( ) ;
bool verticalMoved = false ;
bool horizontalMoved = false ;
// calculates new rect based on anchors
2013-02-18 17:16:22 +01:00
for ( const UIAnchorPtr & anchor : anchorGroup - > getAnchors ( ) ) {
2011-08-26 17:06:52 +02:00
// skip invalid anchors
2013-02-18 17:16:22 +01:00
if ( anchor - > getHookedEdge ( ) = = Fw : : AnchorNone )
2011-08-26 17:06:52 +02:00
continue ;
// determine hooked widget
2013-02-18 17:16:22 +01:00
UIWidgetPtr hookedWidget = anchor - > getHookedWidget ( widget , parentWidget ) ;
2011-08-26 17:06:52 +02:00
// skip invalid anchors
if ( ! hookedWidget )
continue ;
if ( hookedWidget ! = getParentWidget ( ) ) {
// update this hooked widget anchors
auto it = m_anchorsGroups . find ( hookedWidget ) ;
if ( it ! = m_anchorsGroups . end ( ) ) {
2013-02-18 17:16:22 +01:00
const UIAnchorGroupPtr & hookedAnchorGroup = it - > second ;
if ( ! hookedAnchorGroup - > isUpdated ( ) )
2012-05-01 15:06:38 +02:00
updateWidget ( hookedWidget , hookedAnchorGroup , first ) ;
2011-08-26 17:06:52 +02:00
}
}
2013-02-18 17:16:22 +01:00
int point = anchor - > getHookedPoint ( hookedWidget , parentWidget ) ;
2012-03-27 00:24:01 +02:00
2013-02-18 17:16:22 +01:00
switch ( anchor - > getAnchoredEdge ( ) ) {
2011-08-28 18:02:26 +02:00
case Fw : : AnchorHorizontalCenter :
2011-08-26 17:06:52 +02:00
newRect . moveHorizontalCenter ( point + widget - > getMarginLeft ( ) - widget - > getMarginRight ( ) ) ;
horizontalMoved = true ;
break ;
2011-08-28 18:02:26 +02:00
case Fw : : AnchorLeft :
2011-08-26 17:06:52 +02:00
if ( ! horizontalMoved ) {
newRect . moveLeft ( point + widget - > getMarginLeft ( ) ) ;
horizontalMoved = true ;
} else
newRect . setLeft ( point + widget - > getMarginLeft ( ) ) ;
break ;
2011-08-28 18:02:26 +02:00
case Fw : : AnchorRight :
2011-08-26 17:06:52 +02:00
if ( ! horizontalMoved ) {
newRect . moveRight ( point - widget - > getMarginRight ( ) ) ;
horizontalMoved = true ;
} else
newRect . setRight ( point - widget - > getMarginRight ( ) ) ;
break ;
2011-08-28 18:02:26 +02:00
case Fw : : AnchorVerticalCenter :
2011-08-26 17:06:52 +02:00
newRect . moveVerticalCenter ( point + widget - > getMarginTop ( ) - widget - > getMarginBottom ( ) ) ;
verticalMoved = true ;
break ;
2011-08-28 18:02:26 +02:00
case Fw : : AnchorTop :
2011-08-26 17:06:52 +02:00
if ( ! verticalMoved ) {
newRect . moveTop ( point + widget - > getMarginTop ( ) ) ;
verticalMoved = true ;
} else
newRect . setTop ( point + widget - > getMarginTop ( ) ) ;
break ;
2011-08-28 18:02:26 +02:00
case Fw : : AnchorBottom :
2011-08-26 17:06:52 +02:00
if ( ! verticalMoved ) {
newRect . moveBottom ( point - widget - > getMarginBottom ( ) ) ;
verticalMoved = true ;
} else
newRect . setBottom ( point - widget - > getMarginBottom ( ) ) ;
break ;
default :
break ;
}
}
2012-03-27 20:14:35 +02:00
bool changed = false ;
if ( widget - > setRect ( newRect ) )
changed = true ;
2013-02-18 17:16:22 +01:00
anchorGroup - > setUpdated ( true ) ;
2012-03-27 20:14:35 +02:00
return changed ;
2011-08-26 17:06:52 +02:00
}
2012-01-08 23:32:55 +01:00
2012-03-27 20:14:35 +02:00
bool UIAnchorLayout : : internalUpdate ( )
2012-01-08 23:32:55 +01:00
{
2012-03-27 20:14:35 +02:00
bool changed = false ;
2012-01-08 23:32:55 +01:00
// reset all anchors groups update state
for ( auto & it : m_anchorsGroups ) {
2013-02-18 17:16:22 +01:00
const UIAnchorGroupPtr & anchorGroup = it . second ;
anchorGroup - > setUpdated ( false ) ;
2012-01-08 23:32:55 +01:00
}
// update all anchors
for ( auto & it : m_anchorsGroups ) {
const UIWidgetPtr & widget = it . first ;
2013-02-18 17:16:22 +01:00
const UIAnchorGroupPtr & anchorGroup = it . second ;
if ( ! anchorGroup - > isUpdated ( ) ) {
2012-03-27 20:14:35 +02:00
if ( updateWidget ( widget , anchorGroup ) )
changed = true ;
}
2012-01-08 23:32:55 +01:00
}
2012-03-27 20:14:35 +02:00
return changed ;
2012-01-08 23:32:55 +01:00
}