xref: /trunk/main/vcl/inc/vcl/arrange.hxx (revision 0d63794c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 #ifndef _VCL_ARRANGE_HXX
25 #define _VCL_ARRANGE_HXX
26 
27 #include "vcl/window.hxx"
28 
29 #include <vector>
30 #include <map>
31 #include <boost/shared_ptr.hpp>
32 
33 namespace vcl
34 {
35     /* some helper classes for simple window layouting
36        guidelines:
37        - a WindowArranger is not a Window
38        - a WindowArranger hierarchy manages exactly one level of child windows inside a common parent
39          this is to keep the vcl Window hierarchy flat, as some code like accelerators depend on such behavior
40        - a WindowArranger never becomes owner of a Window, windows need to be destroyed separately
41        - a WindowArranger however always is owner of its child WindowArrangers, that is the
42          WindowArranger hierarchy will keep track of its objects and delete them
43        - a managed element of a WindowArranger can either be a Window (a leaf in the hierarchy)
44          or a child WindowArranger (a node in the hierarchy), but never both
45     */
46 
47     class VCL_DLLPUBLIC WindowArranger
48     {
49     protected:
50         struct Element
51         {
52             Window*                            m_pElement;
53             boost::shared_ptr<WindowArranger>  m_pChild;
54             sal_Int32                          m_nExpandPriority;
55             Size                               m_aMinSize;
56             bool                               m_bHidden;
57             long                               m_nLeftBorder;
58             long                               m_nTopBorder;
59             long                               m_nRightBorder;
60             long                               m_nBottomBorder;
61 
Elementvcl::WindowArranger::Element62             Element()
63             : m_pElement( NULL )
64             , m_pChild()
65             , m_nExpandPriority( 0 )
66             , m_bHidden( false )
67             , m_nLeftBorder( 0 )
68             , m_nTopBorder( 0 )
69             , m_nRightBorder( 0 )
70             , m_nBottomBorder( 0 )
71             {}
72 
Elementvcl::WindowArranger::Element73             Element( Window* i_pWin,
74                      boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(),
75                      sal_Int32 i_nExpandPriority = 0,
76                      const Size& i_rMinSize = Size()
77                    )
78             : m_pElement( i_pWin )
79             , m_pChild( i_pChild )
80             , m_nExpandPriority( i_nExpandPriority )
81             , m_aMinSize( i_rMinSize )
82             , m_bHidden( false )
83             , m_nLeftBorder( 0 )
84             , m_nTopBorder( 0 )
85             , m_nRightBorder( 0 )
86             , m_nBottomBorder( 0 )
87             {}
88 
deleteChildvcl::WindowArranger::Element89             void deleteChild() { m_pChild.reset(); }
90 
91             sal_Int32 getExpandPriority() const;
92             Size getOptimalSize( WindowSizeType ) const;
93             bool isVisible() const;
94             void setPosSize( const Point&, const Size& );
95         };
96 
97         Window*                     m_pParentWindow;
98         WindowArranger*             m_pParentArranger;
99         Rectangle                   m_aManagedArea;
100         long                        m_nOuterBorder;
101 
102         rtl::OUString               m_aIdentifier;
103 
104         virtual Element* getElement( size_t i_nIndex ) = 0;
getConstElement(size_t i_nIndex) const105         const Element* getConstElement( size_t i_nIndex ) const
106         { return const_cast<WindowArranger*>(this)->getElement( i_nIndex ); }
107 
108 
109     public:
110         static long getDefaultBorder();
111 
getBorderValue(long nBorder)112         static long getBorderValue( long nBorder )
113         { return nBorder >= 0 ? nBorder : -nBorder * getDefaultBorder(); }
114 
WindowArranger(WindowArranger * i_pParent=NULL)115         WindowArranger( WindowArranger* i_pParent = NULL )
116         : m_pParentWindow( i_pParent ? i_pParent->m_pParentWindow : NULL )
117         , m_pParentArranger( i_pParent )
118         , m_nOuterBorder( 0 )
119         {}
120         virtual ~WindowArranger();
121 
122         // ask what would be the optimal size
123         virtual Size getOptimalSize( WindowSizeType ) const = 0;
124         // call Resize to trigger layouting inside the managed area
125         // without function while parent window is unset
126         virtual void resize() = 0;
127         // avoid this if possible, using the constructor instead
128         // there can be only one parent window and all managed windows MUST
129         // be direct children of that window
130         // violating that condition will result in undefined behavior
131         virtual void setParentWindow( Window* );
132 
133         virtual void setParent( WindowArranger* );
134 
135         virtual size_t countElements() const = 0;
getChild(size_t i_nIndex) const136         boost::shared_ptr<WindowArranger> getChild( size_t i_nIndex ) const
137         {
138             const Element* pEle = getConstElement( i_nIndex );
139             return pEle ? pEle->m_pChild : boost::shared_ptr<WindowArranger>();
140         }
getWindow(size_t i_nIndex) const141         Window* getWindow( size_t i_nIndex ) const
142         {
143             const Element* pEle = getConstElement( i_nIndex );
144             return pEle ? pEle->m_pElement : NULL;
145         }
146 
147         virtual bool isVisible() const; // true if any element is visible
148 
149         virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getProperties() const;
150         virtual void setProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& );
151 
getExpandPriority(size_t i_nIndex) const152         sal_Int32 getExpandPriority( size_t i_nIndex ) const
153         {
154             const Element* pEle = getConstElement( i_nIndex );
155             return pEle ? pEle->getExpandPriority() : 0;
156         }
157 
getMinimumSize(size_t i_nIndex) const158         Size getMinimumSize( size_t i_nIndex ) const
159         {
160             const Element* pEle = getConstElement( i_nIndex );
161             return pEle ? pEle->m_aMinSize : Size();
162         }
163 
setMinimumSize(size_t i_nIndex,const Size & i_rMinSize)164         bool setMinimumSize( size_t i_nIndex, const Size& i_rMinSize )
165         {
166             Element* pEle = getElement( i_nIndex );
167             if( pEle )
168                 pEle->m_aMinSize = i_rMinSize;
169             return pEle != NULL;
170         }
171 
setBorders(size_t i_nIndex,long i_nLeft,long i_nTop,long i_nRight,long i_nBottom)172         void setBorders( size_t i_nIndex, long i_nLeft, long i_nTop, long i_nRight, long i_nBottom  )
173         {
174             Element* pEle = getElement( i_nIndex );
175             if( pEle )
176             {
177                 pEle->m_nLeftBorder   = i_nLeft;
178                 pEle->m_nRightBorder  = i_nRight;
179                 pEle->m_nTopBorder    = i_nTop;
180                 pEle->m_nBottomBorder = i_nBottom;
181             }
182         }
183 
getBorders(size_t i_nIndex,long * i_pLeft=NULL,long * i_pTop=NULL,long * i_pRight=NULL,long * i_pBottom=NULL) const184         void getBorders( size_t i_nIndex, long* i_pLeft = NULL, long* i_pTop = NULL, long* i_pRight = NULL, long* i_pBottom = NULL ) const
185         {
186             const Element* pEle = getConstElement( i_nIndex );
187             if( pEle )
188             {
189                 if( i_pLeft )   *i_pLeft   = pEle->m_nLeftBorder;
190                 if( i_pTop )    *i_pTop    = pEle->m_nTopBorder;
191                 if( i_pRight )  *i_pRight  = pEle->m_nRightBorder;
192                 if( i_pBottom ) *i_pBottom = pEle->m_nBottomBorder;
193             }
194         }
195 
196 
197         void show( bool i_bShow = true, bool i_bImmediateUpdate = true );
198 
setManagedArea(const Rectangle & i_rArea)199         void setManagedArea( const Rectangle& i_rArea )
200         {
201             m_aManagedArea = i_rArea;
202             resize();
203         }
getManagedArea() const204         const Rectangle& getManagedArea() const { return m_aManagedArea; }
205 
setOuterBorder(long i_nBorder)206         void setOuterBorder( long i_nBorder )
207         {
208             m_nOuterBorder = i_nBorder;
209             resize();
210         }
211 
getIdentifier() const212         const rtl::OUString getIdentifier() const
213         { return m_aIdentifier; }
214 
setIdentifier(const rtl::OUString & i_rId)215         void setIdentifier( const rtl::OUString& i_rId )
216         { m_aIdentifier = i_rId; }
217     };
218 
219     class VCL_DLLPUBLIC RowOrColumn : public WindowArranger
220     {
221         long    m_nBorderWidth;
222         bool    m_bColumn;
223 
224         std::vector< WindowArranger::Element > m_aElements;
225 
226         void distributeRowWidth( std::vector< Size >& io_rSizes, long i_nUsedWidth, long i_nExtraWidth );
227         void distributeColumnHeight( std::vector< Size >& io_rSizes, long i_nUsedHeight, long i_nExtraHeight );
228     protected:
getElement(size_t i_nIndex)229         virtual Element* getElement( size_t i_nIndex )
230         { return i_nIndex < m_aElements.size() ? &m_aElements[ i_nIndex ] : 0; }
231 
232     public:
RowOrColumn(WindowArranger * i_pParent=NULL,bool bColumn=true,long i_nBorderWidth=-1)233         RowOrColumn( WindowArranger* i_pParent = NULL,
234                      bool bColumn = true, long i_nBorderWidth = -1 )
235         : WindowArranger( i_pParent )
236         , m_nBorderWidth( i_nBorderWidth )
237         , m_bColumn( bColumn )
238         {}
239 
240         virtual ~RowOrColumn();
241 
242         virtual Size getOptimalSize( WindowSizeType ) const;
243         virtual void resize();
countElements() const244         virtual size_t countElements() const { return m_aElements.size(); }
245 
246         // add a managed window at the given index
247         // an index smaller than zero means add the window at the end
248         size_t addWindow( Window*, sal_Int32 i_nExpandPrio = 0, const Size& i_rMinSize = Size(), size_t i_nIndex = ~0 );
249         void remove( Window* );
250 
251         size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 );
252         // convenience: use for addChild( new WindowArranger( ... ) ) constructs
addChild(WindowArranger * i_pNewChild,sal_Int32 i_nExpandPrio=0,size_t i_nIndex=~0)253         size_t addChild( WindowArranger* i_pNewChild, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 )
254         { return addChild( boost::shared_ptr<WindowArranger>( i_pNewChild ), i_nExpandPrio, i_nIndex ); }
255         void remove( boost::shared_ptr<WindowArranger> const & );
256 
getBorderWidth() const257         long getBorderWidth() const { return m_nBorderWidth; }
258     };
259 
260     class VCL_DLLPUBLIC LabeledElement : public WindowArranger
261     {
262         WindowArranger::Element m_aLabel;
263         WindowArranger::Element m_aElement;
264         long                    m_nDistance;
265         long                    m_nLabelColumnWidth;
266         int                     m_nLabelStyle;
267     protected:
getElement(size_t i_nIndex)268         virtual Element* getElement( size_t i_nIndex )
269         {
270             if( i_nIndex == 0 )
271                 return &m_aLabel;
272             else if( i_nIndex == 1 )
273                 return &m_aElement;
274             return 0;
275         }
276 
277     public:
LabeledElement(WindowArranger * i_pParent=NULL,int i_nLabelStyle=0,long i_nDistance=-1)278         LabeledElement( WindowArranger* i_pParent = NULL, int i_nLabelStyle = 0, long i_nDistance = -1 )
279         : WindowArranger( i_pParent )
280         , m_nDistance( i_nDistance )
281         , m_nLabelColumnWidth( 0 )
282         , m_nLabelStyle( i_nLabelStyle )
283         {}
284 
285         virtual ~LabeledElement();
286 
287         virtual Size getOptimalSize( WindowSizeType ) const;
288         virtual void resize();
countElements() const289         virtual size_t countElements() const { return 2; }
290 
291         void setLabel( Window* );
292         void setLabel( boost::shared_ptr<WindowArranger> const & );
293         void setElement( Window* );
294         void setElement( boost::shared_ptr<WindowArranger> const & );
setLabelColumnWidth(long i_nWidth)295         void setLabelColumnWidth( long i_nWidth )
296         { m_nLabelColumnWidth = i_nWidth; }
297 
getLabelSize(WindowSizeType i_eType) const298         Size getLabelSize( WindowSizeType i_eType ) const
299         { return m_aLabel.getOptimalSize( i_eType ); }
getElementSize(WindowSizeType i_eType) const300         Size getElementSize( WindowSizeType i_eType ) const
301         { return m_aElement.getOptimalSize( i_eType ); }
302     };
303 
304     class VCL_DLLPUBLIC LabelColumn : public RowOrColumn
305     {
306         long getLabelWidth() const;
307     public:
LabelColumn(WindowArranger * i_pParent=NULL,long i_nBorderWidth=-1)308         LabelColumn( WindowArranger* i_pParent = NULL, long i_nBorderWidth = -1 )
309         : RowOrColumn( i_pParent, true, i_nBorderWidth )
310         {}
311         virtual ~LabelColumn();
312 
313         virtual Size getOptimalSize( WindowSizeType ) const;
314         virtual void resize();
315 
316         // returns the index of the added label
317         size_t addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent = 0 );
318         size_t addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent = 0, const Size& i_rElementMinSize = Size() );
319     };
320 
321     class VCL_DLLPUBLIC Indenter : public WindowArranger
322     {
323         long                        m_nIndent;
324         WindowArranger::Element     m_aElement;
325 
326     protected:
getElement(size_t i_nIndex)327         virtual Element* getElement( size_t i_nIndex )
328         { return i_nIndex == 0 ? &m_aElement : NULL; }
329 
330     public:
Indenter(WindowArranger * i_pParent=NULL,long i_nIndent=3* getDefaultBorder ())331         Indenter( WindowArranger* i_pParent = NULL, long i_nIndent = 3*getDefaultBorder() )
332         : WindowArranger( i_pParent )
333         , m_nIndent( i_nIndent )
334         {}
335 
336         virtual ~Indenter();
337 
338         virtual Size getOptimalSize( WindowSizeType ) const;
339         virtual void resize();
countElements() const340         virtual size_t countElements() const { return (m_aElement.m_pElement != 0 || m_aElement.m_pChild != 0) ? 1 : 0; }
341 
setIndent(long i_nIndent)342         void setIndent( long i_nIndent )
343         {
344             m_nIndent = i_nIndent;
345             resize();
346         }
347 
348         void setWindow( Window*, sal_Int32 i_nExpandPrio = 0 );
349         void setChild( boost::shared_ptr<WindowArranger> const &, sal_Int32 i_nExpandPrio = 0 );
350         // convenience: use for setChild( new WindowArranger( ... ) ) constructs
setChild(WindowArranger * i_pChild,sal_Int32 i_nExpandPrio=0)351         void setChild( WindowArranger* i_pChild, sal_Int32 i_nExpandPrio = 0 )
352         { setChild( boost::shared_ptr<WindowArranger>( i_pChild ), i_nExpandPrio ); }
353     };
354 
355     class VCL_DLLPUBLIC Spacer : public WindowArranger
356     {
357         WindowArranger::Element     m_aElement;
358         Size                        m_aSize;
359 
360     protected:
getElement(size_t i_nIndex)361         virtual Element* getElement( size_t i_nIndex )
362         { return i_nIndex == 0 ? &m_aElement : NULL; }
363 
364     public:
Spacer(WindowArranger * i_pParent=NULL,sal_Int32 i_nPrio=20,const Size & i_rSize=Size (0,0))365         Spacer( WindowArranger* i_pParent = NULL, sal_Int32 i_nPrio = 20, const Size& i_rSize = Size( 0, 0 ) )
366         : WindowArranger( i_pParent )
367         , m_aElement( NULL, boost::shared_ptr<WindowArranger>(), i_nPrio )
368         , m_aSize( i_rSize )
369         {}
370 
~Spacer()371         virtual ~Spacer() {}
372 
getOptimalSize(WindowSizeType) const373         virtual Size getOptimalSize( WindowSizeType ) const
374         { return m_aSize; }
resize()375         virtual void resize() {}
setParentWindow(Window *)376         virtual void setParentWindow( Window* ) {}
countElements() const377         virtual size_t countElements() const { return 1; }
isVisible() const378         virtual bool isVisible() const { return true; }
379     };
380 
381     class VCL_DLLPUBLIC MatrixArranger : public WindowArranger
382     {
383         long    m_nBorderX;
384         long    m_nBorderY;
385 
386         struct MatrixElement : public WindowArranger::Element
387         {
388             sal_uInt32  m_nX;
389             sal_uInt32  m_nY;
390 
MatrixElementvcl::MatrixArranger::MatrixElement391             MatrixElement()
392             : WindowArranger::Element()
393             , m_nX( 0 )
394             , m_nY( 0 )
395             {}
396 
MatrixElementvcl::MatrixArranger::MatrixElement397             MatrixElement( Window* i_pWin,
398                            sal_uInt32 i_nX, sal_uInt32 i_nY,
399                            boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(),
400                            sal_Int32 i_nExpandPriority = 0,
401                            const Size& i_rMinSize = Size()
402                           )
403             : WindowArranger::Element( i_pWin, i_pChild, i_nExpandPriority, i_rMinSize )
404             , m_nX( i_nX )
405             , m_nY( i_nY )
406             {
407             }
408         };
409 
410         std::vector< MatrixElement >            m_aElements;
411         std::map< sal_uInt64, size_t >          m_aMatrixMap;  // maps (x | (y << 32)) to index in m_aElements
412 
getMap(sal_uInt32 i_nX,sal_uInt32 i_nY)413         sal_uInt64 getMap( sal_uInt32 i_nX, sal_uInt32 i_nY )
414         { return static_cast< sal_uInt64 >(i_nX) | (static_cast< sal_uInt64>(i_nY) << 32 ); }
415 
416         static void distributeExtraSize( std::vector<long>& io_rSizes, const std::vector<sal_Int32>& i_rPrios, long i_nExtraWidth );
417 
418         Size getOptimalSize( WindowSizeType,
419                              std::vector<long>& o_rColumnWidths, std::vector<long>& o_rRowHeights,
420                              std::vector<sal_Int32>& o_rColumnPrio, std::vector<sal_Int32>& o_rRowPrio
421                             ) const;
422     protected:
getElement(size_t i_nIndex)423         virtual Element* getElement( size_t i_nIndex )
424         { return i_nIndex < m_aElements.size() ? &m_aElements[ i_nIndex ] : 0; }
425 
426     public:
MatrixArranger(WindowArranger * i_pParent=NULL,long i_nBorderX=-1,long i_nBorderY=-1)427         MatrixArranger( WindowArranger* i_pParent = NULL,
428                         long i_nBorderX = -1,
429                         long i_nBorderY = -1 )
430         : WindowArranger( i_pParent )
431         , m_nBorderX( i_nBorderX )
432         , m_nBorderY( i_nBorderY )
433         {}
434 
435         virtual ~MatrixArranger();
436 
437         virtual Size getOptimalSize( WindowSizeType ) const;
438         virtual void resize();
countElements() const439         virtual size_t countElements() const { return m_aElements.size(); }
440 
441         // add a managed window at the given matrix position
442         size_t addWindow( Window*, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0, const Size& i_rMinSize = Size() );
443         void remove( Window* );
444 
445         size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 );
446         // convenience: use for addChild( new WindowArranger( ... ) ) constructs
addChild(WindowArranger * i_pNewChild,sal_uInt32 i_nX,sal_uInt32 i_nY,sal_Int32 i_nExpandPrio=0)447         size_t addChild( WindowArranger* i_pNewChild, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 )
448         { return addChild( boost::shared_ptr<WindowArranger>( i_pNewChild ), i_nX, i_nY, i_nExpandPrio ); }
449         void remove( boost::shared_ptr<WindowArranger> const & );
450     };
451 
452 }
453 
454 #endif
455 
456