blob: 688bb4373bf12e4998b8a6c7eac9182da8c925ea [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#ifndef _VCL_ARRANGE_HXX
#define _VCL_ARRANGE_HXX
#include "vcl/window.hxx"
#include <vector>
#include <map>
#include <boost/shared_ptr.hpp>
namespace vcl
{
/* some helper classes for simple window layouting
guidelines:
- a WindowArranger is not a Window
- a WindowArranger hierarchy manages exactly one level of child windows inside a common parent
this is to keep the vcl Window hierarchy flat, as some code like accelerators depend on such behavior
- a WindowArranger never becomes owner of a Window, windows need to be destroyed separately
- a WindowArranger however always is owner of its child WindowArrangers, that is the
WindowArranger hierarchy will keep track of its objects and delete them
- a managed element of a WindowArranger can either be a Window (a leaf in the hierarchy)
or a child WindowArranger (a node in the hierarchy), but never both
*/
class VCL_DLLPUBLIC WindowArranger
{
protected:
struct Element
{
Window* m_pElement;
boost::shared_ptr<WindowArranger> m_pChild;
sal_Int32 m_nExpandPriority;
Size m_aMinSize;
bool m_bHidden;
long m_nLeftBorder;
long m_nTopBorder;
long m_nRightBorder;
long m_nBottomBorder;
Element()
: m_pElement( NULL )
, m_pChild()
, m_nExpandPriority( 0 )
, m_bHidden( false )
, m_nLeftBorder( 0 )
, m_nTopBorder( 0 )
, m_nRightBorder( 0 )
, m_nBottomBorder( 0 )
{}
Element( Window* i_pWin,
boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(),
sal_Int32 i_nExpandPriority = 0,
const Size& i_rMinSize = Size()
)
: m_pElement( i_pWin )
, m_pChild( i_pChild )
, m_nExpandPriority( i_nExpandPriority )
, m_aMinSize( i_rMinSize )
, m_bHidden( false )
, m_nLeftBorder( 0 )
, m_nTopBorder( 0 )
, m_nRightBorder( 0 )
, m_nBottomBorder( 0 )
{}
void deleteChild() { m_pChild.reset(); }
sal_Int32 getExpandPriority() const;
Size getOptimalSize( WindowSizeType ) const;
bool isVisible() const;
void setPosSize( const Point&, const Size& );
};
Window* m_pParentWindow;
WindowArranger* m_pParentArranger;
Rectangle m_aManagedArea;
long m_nOuterBorder;
rtl::OUString m_aIdentifier;
virtual Element* getElement( size_t i_nIndex ) = 0;
const Element* getConstElement( size_t i_nIndex ) const
{ return const_cast<WindowArranger*>(this)->getElement( i_nIndex ); }
public:
static long getDefaultBorder();
static long getBorderValue( long nBorder )
{ return nBorder >= 0 ? nBorder : -nBorder * getDefaultBorder(); }
WindowArranger( WindowArranger* i_pParent = NULL )
: m_pParentWindow( i_pParent ? i_pParent->m_pParentWindow : NULL )
, m_pParentArranger( i_pParent )
, m_nOuterBorder( 0 )
{}
virtual ~WindowArranger();
// ask what would be the optimal size
virtual Size getOptimalSize( WindowSizeType ) const = 0;
// call Resize to trigger layouting inside the managed area
// without function while parent window is unset
virtual void resize() = 0;
// avoid this if possible, using the constructor instead
// there can be only one parent window and all managed windows MUST
// be direct children of that window
// violating that condition will result in undefined behavior
virtual void setParentWindow( Window* );
virtual void setParent( WindowArranger* );
virtual size_t countElements() const = 0;
boost::shared_ptr<WindowArranger> getChild( size_t i_nIndex ) const
{
const Element* pEle = getConstElement( i_nIndex );
return pEle ? pEle->m_pChild : boost::shared_ptr<WindowArranger>();
}
Window* getWindow( size_t i_nIndex ) const
{
const Element* pEle = getConstElement( i_nIndex );
return pEle ? pEle->m_pElement : NULL;
}
virtual bool isVisible() const; // true if any element is visible
virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getProperties() const;
virtual void setProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& );
sal_Int32 getExpandPriority( size_t i_nIndex ) const
{
const Element* pEle = getConstElement( i_nIndex );
return pEle ? pEle->getExpandPriority() : 0;
}
Size getMinimumSize( size_t i_nIndex ) const
{
const Element* pEle = getConstElement( i_nIndex );
return pEle ? pEle->m_aMinSize : Size();
}
bool setMinimumSize( size_t i_nIndex, const Size& i_rMinSize )
{
Element* pEle = getElement( i_nIndex );
if( pEle )
pEle->m_aMinSize = i_rMinSize;
return pEle != NULL;
}
void setBorders( size_t i_nIndex, long i_nLeft, long i_nTop, long i_nRight, long i_nBottom )
{
Element* pEle = getElement( i_nIndex );
if( pEle )
{
pEle->m_nLeftBorder = i_nLeft;
pEle->m_nRightBorder = i_nRight;
pEle->m_nTopBorder = i_nTop;
pEle->m_nBottomBorder = i_nBottom;
}
}
void getBorders( size_t i_nIndex, long* i_pLeft = NULL, long* i_pTop = NULL, long* i_pRight = NULL, long* i_pBottom = NULL ) const
{
const Element* pEle = getConstElement( i_nIndex );
if( pEle )
{
if( i_pLeft ) *i_pLeft = pEle->m_nLeftBorder;
if( i_pTop ) *i_pTop = pEle->m_nTopBorder;
if( i_pRight ) *i_pRight = pEle->m_nRightBorder;
if( i_pBottom ) *i_pBottom = pEle->m_nBottomBorder;
}
}
void show( bool i_bShow = true, bool i_bImmediateUpdate = true );
void setManagedArea( const Rectangle& i_rArea )
{
m_aManagedArea = i_rArea;
resize();
}
const Rectangle& getManagedArea() const { return m_aManagedArea; }
void setOuterBorder( long i_nBorder )
{
m_nOuterBorder = i_nBorder;
resize();
}
const rtl::OUString getIdentifier() const
{ return m_aIdentifier; }
void setIdentifier( const rtl::OUString& i_rId )
{ m_aIdentifier = i_rId; }
};
class VCL_DLLPUBLIC RowOrColumn : public WindowArranger
{
long m_nBorderWidth;
bool m_bColumn;
std::vector< WindowArranger::Element > m_aElements;
void distributeRowWidth( std::vector< Size >& io_rSizes, long i_nUsedWidth, long i_nExtraWidth );
void distributeColumnHeight( std::vector< Size >& io_rSizes, long i_nUsedHeight, long i_nExtraHeight );
protected:
virtual Element* getElement( size_t i_nIndex )
{ return i_nIndex < m_aElements.size() ? &m_aElements[ i_nIndex ] : 0; }
public:
RowOrColumn( WindowArranger* i_pParent = NULL,
bool bColumn = true, long i_nBorderWidth = -1 )
: WindowArranger( i_pParent )
, m_nBorderWidth( i_nBorderWidth )
, m_bColumn( bColumn )
{}
virtual ~RowOrColumn();
virtual Size getOptimalSize( WindowSizeType ) const;
virtual void resize();
virtual size_t countElements() const { return m_aElements.size(); }
// add a managed window at the given index
// an index smaller than zero means add the window at the end
size_t addWindow( Window*, sal_Int32 i_nExpandPrio = 0, const Size& i_rMinSize = Size(), size_t i_nIndex = ~0 );
void remove( Window* );
size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 );
// convenience: use for addChild( new WindowArranger( ... ) ) constructs
size_t addChild( WindowArranger* i_pNewChild, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 )
{ return addChild( boost::shared_ptr<WindowArranger>( i_pNewChild ), i_nExpandPrio, i_nIndex ); }
void remove( boost::shared_ptr<WindowArranger> const & );
long getBorderWidth() const { return m_nBorderWidth; }
};
class VCL_DLLPUBLIC LabeledElement : public WindowArranger
{
WindowArranger::Element m_aLabel;
WindowArranger::Element m_aElement;
long m_nDistance;
long m_nLabelColumnWidth;
int m_nLabelStyle;
protected:
virtual Element* getElement( size_t i_nIndex )
{
if( i_nIndex == 0 )
return &m_aLabel;
else if( i_nIndex == 1 )
return &m_aElement;
return 0;
}
public:
LabeledElement( WindowArranger* i_pParent = NULL, int i_nLabelStyle = 0, long i_nDistance = -1 )
: WindowArranger( i_pParent )
, m_nDistance( i_nDistance )
, m_nLabelColumnWidth( 0 )
, m_nLabelStyle( i_nLabelStyle )
{}
virtual ~LabeledElement();
virtual Size getOptimalSize( WindowSizeType ) const;
virtual void resize();
virtual size_t countElements() const { return 2; }
void setLabel( Window* );
void setLabel( boost::shared_ptr<WindowArranger> const & );
void setElement( Window* );
void setElement( boost::shared_ptr<WindowArranger> const & );
void setLabelColumnWidth( long i_nWidth )
{ m_nLabelColumnWidth = i_nWidth; }
Size getLabelSize( WindowSizeType i_eType ) const
{ return m_aLabel.getOptimalSize( i_eType ); }
Size getElementSize( WindowSizeType i_eType ) const
{ return m_aElement.getOptimalSize( i_eType ); }
};
class VCL_DLLPUBLIC LabelColumn : public RowOrColumn
{
long getLabelWidth() const;
public:
LabelColumn( WindowArranger* i_pParent = NULL, long i_nBorderWidth = -1 )
: RowOrColumn( i_pParent, true, i_nBorderWidth )
{}
virtual ~LabelColumn();
virtual Size getOptimalSize( WindowSizeType ) const;
virtual void resize();
// returns the index of the added label
size_t addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent = 0 );
size_t addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent = 0, const Size& i_rElementMinSize = Size() );
};
class VCL_DLLPUBLIC Indenter : public WindowArranger
{
long m_nIndent;
WindowArranger::Element m_aElement;
protected:
virtual Element* getElement( size_t i_nIndex )
{ return i_nIndex == 0 ? &m_aElement : NULL; }
public:
Indenter( WindowArranger* i_pParent = NULL, long i_nIndent = 3*getDefaultBorder() )
: WindowArranger( i_pParent )
, m_nIndent( i_nIndent )
{}
virtual ~Indenter();
virtual Size getOptimalSize( WindowSizeType ) const;
virtual void resize();
virtual size_t countElements() const { return (m_aElement.m_pElement != 0 || m_aElement.m_pChild != 0) ? 1 : 0; }
void setIndent( long i_nIndent )
{
m_nIndent = i_nIndent;
resize();
}
void setWindow( Window*, sal_Int32 i_nExpandPrio = 0 );
void setChild( boost::shared_ptr<WindowArranger> const &, sal_Int32 i_nExpandPrio = 0 );
// convenience: use for setChild( new WindowArranger( ... ) ) constructs
void setChild( WindowArranger* i_pChild, sal_Int32 i_nExpandPrio = 0 )
{ setChild( boost::shared_ptr<WindowArranger>( i_pChild ), i_nExpandPrio ); }
};
class VCL_DLLPUBLIC Spacer : public WindowArranger
{
WindowArranger::Element m_aElement;
Size m_aSize;
protected:
virtual Element* getElement( size_t i_nIndex )
{ return i_nIndex == 0 ? &m_aElement : NULL; }
public:
Spacer( WindowArranger* i_pParent = NULL, sal_Int32 i_nPrio = 20, const Size& i_rSize = Size( 0, 0 ) )
: WindowArranger( i_pParent )
, m_aElement( NULL, boost::shared_ptr<WindowArranger>(), i_nPrio )
, m_aSize( i_rSize )
{}
virtual ~Spacer() {}
virtual Size getOptimalSize( WindowSizeType ) const
{ return m_aSize; }
virtual void resize() {}
virtual void setParentWindow( Window* ) {}
virtual size_t countElements() const { return 1; }
virtual bool isVisible() const { return true; }
};
class VCL_DLLPUBLIC MatrixArranger : public WindowArranger
{
long m_nBorderX;
long m_nBorderY;
struct MatrixElement : public WindowArranger::Element
{
sal_uInt32 m_nX;
sal_uInt32 m_nY;
MatrixElement()
: WindowArranger::Element()
, m_nX( 0 )
, m_nY( 0 )
{}
MatrixElement( Window* i_pWin,
sal_uInt32 i_nX, sal_uInt32 i_nY,
boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(),
sal_Int32 i_nExpandPriority = 0,
const Size& i_rMinSize = Size()
)
: WindowArranger::Element( i_pWin, i_pChild, i_nExpandPriority, i_rMinSize )
, m_nX( i_nX )
, m_nY( i_nY )
{
}
};
std::vector< MatrixElement > m_aElements;
std::map< sal_uInt64, size_t > m_aMatrixMap; // maps (x | (y << 32)) to index in m_aElements
sal_uInt64 getMap( sal_uInt32 i_nX, sal_uInt32 i_nY )
{ return static_cast< sal_uInt64 >(i_nX) | (static_cast< sal_uInt64>(i_nY) << 32 ); }
static void distributeExtraSize( std::vector<long>& io_rSizes, const std::vector<sal_Int32>& i_rPrios, long i_nExtraWidth );
Size getOptimalSize( WindowSizeType,
std::vector<long>& o_rColumnWidths, std::vector<long>& o_rRowHeights,
std::vector<sal_Int32>& o_rColumnPrio, std::vector<sal_Int32>& o_rRowPrio
) const;
protected:
virtual Element* getElement( size_t i_nIndex )
{ return i_nIndex < m_aElements.size() ? &m_aElements[ i_nIndex ] : 0; }
public:
MatrixArranger( WindowArranger* i_pParent = NULL,
long i_nBorderX = -1,
long i_nBorderY = -1 )
: WindowArranger( i_pParent )
, m_nBorderX( i_nBorderX )
, m_nBorderY( i_nBorderY )
{}
virtual ~MatrixArranger();
virtual Size getOptimalSize( WindowSizeType ) const;
virtual void resize();
virtual size_t countElements() const { return m_aElements.size(); }
// add a managed window at the given matrix position
size_t addWindow( Window*, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0, const Size& i_rMinSize = Size() );
void remove( Window* );
size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 );
// convenience: use for addChild( new WindowArranger( ... ) ) constructs
size_t addChild( WindowArranger* i_pNewChild, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 )
{ return addChild( boost::shared_ptr<WindowArranger>( i_pNewChild ), i_nX, i_nY, i_nExpandPrio ); }
void remove( boost::shared_ptr<WindowArranger> const & );
};
}
#endif