xref: /aoo41x/main/svx/source/dialog/frmsel.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svx.hxx"
30 #include <svx/frmsel.hxx>
31 
32 #include <algorithm>
33 #include <math.h>
34 #include "frmselimpl.hxx"
35 #include "AccessibleFrameSelector.hxx"
36 #include <svx/dialmgr.hxx>
37 
38 #ifndef _SVX_DIALOGS_HRC
39 #include <svx/dialogs.hrc>
40 #endif
41 #ifndef SVX_FRMSEL_HRC
42 #include "frmsel.hrc"
43 #endif
44 
45 #include <tools/rcid.h>
46 
47 namespace svx {
48 
49 using ::com::sun::star::uno::Reference;
50 using ::com::sun::star::accessibility::XAccessible;
51 
52 // ============================================================================
53 // global functions from framebordertype.hxx
54 
55 FrameBorderType GetFrameBorderTypeFromIndex( size_t nIndex )
56 {
57     DBG_ASSERT( nIndex < (size_t)FRAMEBORDERTYPE_COUNT,
58         "svx::GetFrameBorderTypeFromIndex - invalid index" );
59     return static_cast< FrameBorderType >( nIndex + 1 );
60 }
61 
62 size_t GetIndexFromFrameBorderType( FrameBorderType eBorder )
63 {
64     DBG_ASSERT( eBorder != FRAMEBORDER_NONE,
65         "svx::GetIndexFromFrameBorderType - invalid frame border type" );
66     return static_cast< size_t >( eBorder ) - 1;
67 }
68 
69 // ============================================================================
70 
71 namespace {
72 
73 /** Space between outer control border and any graphical element of the control. */
74 const long FRAMESEL_GEOM_OUTER    = 2;
75 
76 /** Space between arrows and usable inner area. */
77 const long FRAMESEL_GEOM_INNER    = 3;
78 
79 /** Maximum width to draw a frame border style. */
80 const long FRAMESEL_GEOM_WIDTH    = 9;
81 
82 /** Additional margin for click area of outer lines. */
83 const long FRAMESEL_GEOM_ADD_CLICK_OUTER = 5;
84 
85 /** Additional margin for click area of inner lines. */
86 const long FRAMESEL_GEOM_ADD_CLICK_INNER = 2;
87 
88 // ----------------------------------------------------------------------------
89 
90 static const frame::Style   OBJ_FRAMESTYLE_DONTCARE( 3, 0, 0 );
91 static const FrameBorder    OBJ_FRAMEBORDER_NONE( FRAMEBORDER_NONE );
92 
93 // ----------------------------------------------------------------------------
94 
95 /** Returns the corresponding flag for a frame border. */
96 FrameSelFlags lclGetFlagFromType( FrameBorderType eBorder )
97 {
98     switch( eBorder )
99     {
100         case FRAMEBORDER_LEFT:      return FRAMESEL_LEFT;
101         case FRAMEBORDER_RIGHT:     return FRAMESEL_RIGHT;
102         case FRAMEBORDER_TOP:       return FRAMESEL_TOP;
103         case FRAMEBORDER_BOTTOM:    return FRAMESEL_BOTTOM;
104         case FRAMEBORDER_HOR:       return FRAMESEL_INNER_HOR;
105         case FRAMEBORDER_VER:       return FRAMESEL_INNER_VER;
106         case FRAMEBORDER_TLBR:      return FRAMESEL_DIAG_TLBR;
107         case FRAMEBORDER_BLTR:      return FRAMESEL_DIAG_BLTR;
108         case FRAMEBORDER_NONE : break;
109     }
110     return FRAMESEL_NONE;
111 }
112 
113 /** Converts an SvxBorderLine line width (in twips) to a pixel line width. */
114 inline sal_uInt16 lclGetPixel( sal_uInt16 nWidth )
115 {
116     // convert all core styles expect 0 to a visible UI style (at least 1 pixel), map 1pt to 1pixel
117     return nWidth ? std::min< sal_uInt16 >( std::max< sal_uInt16 >( (nWidth + 5) / 20, 1 ), FRAMESEL_GEOM_WIDTH ) : 0;
118 }
119 
120 /** Merges the rSource polypolygon into the rDest polypolygon. */
121 inline void lclPolyPolyUnion( PolyPolygon& rDest, const PolyPolygon& rSource )
122 {
123     const PolyPolygon aTmp( rDest );
124     aTmp.GetUnion( rSource, rDest );
125 }
126 
127 } // namespace
128 
129 // ============================================================================
130 // FrameBorder
131 // ============================================================================
132 
133 FrameBorder::FrameBorder( FrameBorderType eType ) :
134     meType( eType ),
135     meState( FRAMESTATE_HIDE ),
136     meKeyLeft( FRAMEBORDER_NONE ),
137     meKeyRight( FRAMEBORDER_NONE ),
138     meKeyTop( FRAMEBORDER_NONE ),
139     meKeyBottom( FRAMEBORDER_NONE ),
140     mbEnabled( false ),
141     mbSelected( false )
142 {
143 }
144 
145 void FrameBorder::Enable( FrameSelFlags nFlags )
146 {
147     mbEnabled = (nFlags & lclGetFlagFromType( meType )) != 0;
148     if( !mbEnabled )
149         SetState( FRAMESTATE_HIDE );
150 }
151 
152 void FrameBorder::SetCoreStyle( const SvxBorderLine* pStyle )
153 {
154     if( pStyle )
155         maCoreStyle = *pStyle;
156     else
157         maCoreStyle = SvxBorderLine();
158 
159     // from twips to points
160     maUIStyle.Set( maCoreStyle, 0.05, FRAMESEL_GEOM_WIDTH, true );
161     meState = maUIStyle.Prim() ? FRAMESTATE_SHOW : FRAMESTATE_HIDE;
162 }
163 
164 void FrameBorder::SetState( FrameBorderState eState )
165 {
166     meState = eState;
167     switch( meState )
168     {
169         case FRAMESTATE_SHOW:
170             DBG_ERRORFILE( "svx::FrameBorder::SetState - use SetCoreStyle to make border visible" );
171         break;
172         case FRAMESTATE_HIDE:
173             maCoreStyle = SvxBorderLine();
174             maUIStyle.Clear();
175         break;
176         case FRAMESTATE_DONTCARE:
177             maCoreStyle = SvxBorderLine();
178             maUIStyle = OBJ_FRAMESTYLE_DONTCARE;
179         break;
180 	}
181 }
182 
183 void FrameBorder::AddFocusPolygon( const Polygon& rFocus )
184 {
185     lclPolyPolyUnion( maFocusArea, rFocus );
186 }
187 
188 void FrameBorder::MergeFocusToPolyPolygon( PolyPolygon& rPPoly ) const
189 {
190     lclPolyPolyUnion( rPPoly, maFocusArea );
191 }
192 
193 void FrameBorder::AddClickRect( const Rectangle& rRect )
194 {
195     lclPolyPolyUnion( maClickArea, Polygon( rRect ) );
196 }
197 
198 bool FrameBorder::ContainsClickPoint( const Point& rPos ) const
199 {
200     return Region( maClickArea ).IsInside( rPos );
201 }
202 
203 void FrameBorder::MergeClickAreaToPolyPolygon( PolyPolygon& rPPoly ) const
204 {
205     lclPolyPolyUnion( rPPoly, maClickArea );
206 }
207 
208 Rectangle FrameBorder::GetClickBoundRect() const
209 {
210     return maClickArea.GetBoundRect();
211 }
212 
213 void FrameBorder::SetKeyboardNeighbors(
214         FrameBorderType eLeft, FrameBorderType eRight, FrameBorderType eTop, FrameBorderType eBottom )
215 {
216     meKeyLeft = eLeft;
217     meKeyRight = eRight;
218     meKeyTop = eTop;
219     meKeyBottom = eBottom;
220 }
221 
222 FrameBorderType FrameBorder::GetKeyboardNeighbor( sal_uInt16 nKeyCode ) const
223 {
224     FrameBorderType eBorder = FRAMEBORDER_NONE;
225     switch( nKeyCode )
226     {
227         case KEY_LEFT:  eBorder = meKeyLeft;      break;
228         case KEY_RIGHT: eBorder = meKeyRight;     break;
229         case KEY_UP:    eBorder = meKeyTop;       break;
230         case KEY_DOWN:  eBorder = meKeyBottom;    break;
231         default:        DBG_ERRORFILE( "svx::FrameBorder::GetKeyboardNeighbor - unknown key code" );
232     }
233     return eBorder;
234 }
235 
236 // ============================================================================
237 // FrameSelectorImpl
238 // ============================================================================
239 
240 FrameSelectorImpl::FrameSelectorImpl( FrameSelector& rFrameSel ) :
241     Resource( SVX_RES( RID_SVXSTR_BORDER_CONTROL ) ),
242     mrFrameSel( rFrameSel ),
243     maILArrows( 16 ),
244     maLeft( FRAMEBORDER_LEFT ),
245     maRight( FRAMEBORDER_RIGHT ),
246     maTop( FRAMEBORDER_TOP ),
247     maBottom( FRAMEBORDER_BOTTOM ),
248     maHor( FRAMEBORDER_HOR ),
249     maVer( FRAMEBORDER_VER ),
250     maTLBR( FRAMEBORDER_TLBR ),
251     maBLTR( FRAMEBORDER_BLTR ),
252     mnFlags( FRAMESEL_OUTER ),
253     mbHor( false ),
254     mbVer( false ),
255     mbTLBR( false ),
256     mbBLTR( false ),
257     mbFullRepaint( true ),
258     mbAutoSelect( true ),
259     mbClicked( false ),
260     mbHCMode( false ),
261     mpAccess( 0 ),
262     maChildVec( 8, static_cast< a11y::AccFrameSelector* >( 0 ) ),
263     mxChildVec( 8 )
264 {
265     FreeResource();
266 
267     maAllBorders.resize( FRAMEBORDERTYPE_COUNT, 0 );
268     maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_LEFT   ) ] = &maLeft;
269     maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_RIGHT  ) ] = &maRight;
270     maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_TOP    ) ] = &maTop;
271     maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_BOTTOM ) ] = &maBottom;
272     maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_HOR    ) ] = &maHor;
273     maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_VER    ) ] = &maVer;
274     maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_TLBR   ) ] = &maTLBR;
275     maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_BLTR   ) ] = &maBLTR;
276 #if OSL_DEBUG_LEVEL >= 2
277     {
278         bool bOk = true;
279         for( FrameBorderCIter aIt( maAllBorders ); bOk && aIt.Is(); bOk = (*aIt != 0), ++aIt );
280         DBG_ASSERT( bOk, "svx::FrameSelectorImpl::FrameSelectorImpl - missing entry in maAllBorders" );
281     }
282 #endif
283     //                             left neighbor     right neighbor     upper neighbor    lower neighbor
284     maLeft.SetKeyboardNeighbors(   FRAMEBORDER_NONE, FRAMEBORDER_TLBR,  FRAMEBORDER_TOP,  FRAMEBORDER_BOTTOM );
285     maRight.SetKeyboardNeighbors(  FRAMEBORDER_BLTR, FRAMEBORDER_NONE,  FRAMEBORDER_TOP,  FRAMEBORDER_BOTTOM );
286     maTop.SetKeyboardNeighbors(    FRAMEBORDER_LEFT, FRAMEBORDER_RIGHT, FRAMEBORDER_NONE, FRAMEBORDER_TLBR );
287     maBottom.SetKeyboardNeighbors( FRAMEBORDER_LEFT, FRAMEBORDER_RIGHT, FRAMEBORDER_BLTR, FRAMEBORDER_NONE );
288     maHor.SetKeyboardNeighbors(    FRAMEBORDER_LEFT, FRAMEBORDER_RIGHT, FRAMEBORDER_TLBR, FRAMEBORDER_BLTR );
289     maVer.SetKeyboardNeighbors(    FRAMEBORDER_TLBR, FRAMEBORDER_BLTR,  FRAMEBORDER_TOP,  FRAMEBORDER_BOTTOM );
290     maTLBR.SetKeyboardNeighbors(   FRAMEBORDER_LEFT, FRAMEBORDER_VER,   FRAMEBORDER_TOP,  FRAMEBORDER_HOR );
291     maBLTR.SetKeyboardNeighbors(   FRAMEBORDER_VER,  FRAMEBORDER_RIGHT, FRAMEBORDER_HOR,  FRAMEBORDER_BOTTOM );
292 }
293 
294 FrameSelectorImpl::~FrameSelectorImpl()
295 {
296     if( mpAccess )
297         mpAccess->Invalidate();
298     for( AccessibleImplVec::iterator aIt = maChildVec.begin(), aEnd = maChildVec.end(); aIt != aEnd; ++aIt )
299         if( *aIt )
300             (*aIt)->Invalidate();
301 }
302 
303 // initialization -------------------------------------------------------------
304 
305 void FrameSelectorImpl::Initialize( FrameSelFlags nFlags )
306 {
307     mnFlags = nFlags;
308 
309     maEnabBorders.clear();
310     for( FrameBorderIter aIt( maAllBorders ); aIt.Is(); ++aIt )
311     {
312         (*aIt)->Enable( mnFlags );
313         if( (*aIt)->IsEnabled() )
314             maEnabBorders.push_back( *aIt );
315     }
316     mbHor = maHor.IsEnabled();
317     mbVer = maVer.IsEnabled();
318     mbTLBR = maTLBR.IsEnabled();
319     mbBLTR = maBLTR.IsEnabled();
320 
321     InitVirtualDevice();
322 }
323 
324 void FrameSelectorImpl::InitColors()
325 {
326     const StyleSettings& rSett = mrFrameSel.GetSettings().GetStyleSettings();
327     maBackCol = rSett.GetFieldColor();
328     mbHCMode = rSett.GetHighContrastMode();
329     maArrowCol = rSett.GetFieldTextColor();
330     maMarkCol.operator=( maBackCol ).Merge( maArrowCol, mbHCMode ? 0x80 : 0xC0 );
331     maHCLineCol = rSett.GetLabelTextColor();
332 }
333 
334 void FrameSelectorImpl::InitArrowImageList()
335 {
336     /* Build the arrow images bitmap with current colors. */
337 	Color pColorAry1[3];
338 	Color pColorAry2[3];
339 	pColorAry1[0] = Color( 0, 0, 0 );
340 	pColorAry2[0] = maArrowCol;       // black -> arrow color
341 	pColorAry1[1] = Color( 0, 255, 0 );
342 	pColorAry2[1] = maMarkCol;        // green -> marker color
343 	pColorAry1[2] = Color( 255, 0, 255 );
344 	pColorAry2[2] = maBackCol;       // magenta -> background
345 
346 	GetRes( SVX_RES( RID_SVXSTR_BORDER_CONTROL ).SetRT( RSC_RESOURCE ) );
347 	maILArrows.InsertFromHorizontalBitmap(
348 		SVX_RES( BMP_FRMSEL_ARROWS ), 16, NULL, pColorAry1, pColorAry2, 3);
349 	FreeResource();
350     DBG_ASSERT( maILArrows.GetImageSize().Height() == maILArrows.GetImageSize().Width(),
351         "svx::FrameSelectorImpl::InitArrowImageList - images are not squarish" );
352     mnArrowSize = maILArrows.GetImageSize().Height();
353 }
354 
355 void FrameSelectorImpl::InitGlobalGeometry()
356 {
357     Size aCtrlSize( mrFrameSel.CalcOutputSize( mrFrameSel.GetSizePixel() ) );
358     /*  nMinSize is the lower of width and height (control will always be squarish).
359         FRAMESEL_GEOM_OUTER is the minimal distance between inner control border
360         and any element. */
361     long nMinSize = Min( aCtrlSize.Width(), aCtrlSize.Height() ) - 2 * FRAMESEL_GEOM_OUTER;
362     /*  nFixedSize is the size all existing elements need in one direction:
363         the diag. arrow, space betw. arrow and frame border, outer frame border,
364         inner frame border, other outer frame border, space betw. frame border
365         and arrow, the other arrow. */
366     long nFixedSize = 2 * mnArrowSize + 2 * FRAMESEL_GEOM_INNER + 3 * FRAMESEL_GEOM_WIDTH;
367     /*  nBetwBordersSize contains the size between an outer and inner frame border (made odd). */
368     long nBetwBordersSize = (((nMinSize - nFixedSize) / 2) - 1) | 1;
369 
370     /*  The final size of the usable area. */
371     mnCtrlSize = 2 * nBetwBordersSize + nFixedSize;
372     maVirDev.SetOutputSizePixel( Size( mnCtrlSize, mnCtrlSize ) );
373 
374     /*  Center the virtual device in the control. */
375     maVirDevPos = Point( (aCtrlSize.Width() - mnCtrlSize) / 2, (aCtrlSize.Height() - mnCtrlSize) / 2 );
376 }
377 
378 void FrameSelectorImpl::InitBorderGeometry()
379 {
380     size_t nCol, nCols, nRow, nRows;
381 
382     // Global border geometry values ------------------------------------------
383 
384     /*  mnLine* is the middle point inside a frame border (i.e. mnLine1 is mid X inside left border). */
385     mnLine1 = mnArrowSize + FRAMESEL_GEOM_INNER + FRAMESEL_GEOM_WIDTH / 2;
386     mnLine2 = mnCtrlSize / 2;
387     mnLine3 = 2 * mnLine2 - mnLine1;
388 
389     // Frame helper array -----------------------------------------------------
390 
391     maArray.Initialize( mbVer ? 2 : 1, mbHor ? 2 : 1 );
392     maArray.SetUseDiagDoubleClipping( true );
393 
394     maArray.SetXOffset( mnLine1 );
395     maArray.SetAllColWidths( (mbVer ? mnLine2 : mnLine3) - mnLine1 );
396 
397     maArray.SetYOffset( mnLine1 );
398     maArray.SetAllRowHeights( (mbHor ? mnLine2 : mnLine3) - mnLine1 );
399 
400     Rectangle aTLRect( maArray.GetCellRect( 0, 0 ) );
401 
402     // Focus polygons ---------------------------------------------------------
403 
404     /*  Width for focus rectangles from center of frame borders. */
405     mnFocusOffs = FRAMESEL_GEOM_WIDTH / 2 + 1;
406 
407     maLeft.AddFocusPolygon(   Rectangle( mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine1 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
408     maVer.AddFocusPolygon(    Rectangle( mnLine2 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine2 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
409     maRight.AddFocusPolygon(  Rectangle( mnLine3 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
410     maTop.AddFocusPolygon(    Rectangle( mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine1 + mnFocusOffs ) );
411     maHor.AddFocusPolygon(    Rectangle( mnLine1 - mnFocusOffs, mnLine2 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine2 + mnFocusOffs ) );
412     maBottom.AddFocusPolygon( Rectangle( mnLine1 - mnFocusOffs, mnLine3 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
413 
414     for( nCol = 0, nCols = maArray.GetColCount(); nCol < nCols; ++nCol )
415     {
416         for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow )
417         {
418             Rectangle aRect( maArray.GetCellRect( nCol, nRow ) );
419             long nDiagFocusOffsX = frame::GetTLDiagOffset( -mnFocusOffs, mnFocusOffs, maArray.GetHorDiagAngle( nCol, nRow ) );
420             long nDiagFocusOffsY = frame::GetTLDiagOffset( -mnFocusOffs, mnFocusOffs, maArray.GetVerDiagAngle( nCol, nRow ) );
421 
422             std::vector< Point > aFocusVec;
423             aFocusVec.push_back( Point( aRect.Left()  - mnFocusOffs,     aRect.Top()    + nDiagFocusOffsY ) );
424             aFocusVec.push_back( Point( aRect.Left()  - mnFocusOffs,     aRect.Top()    - mnFocusOffs     ) );
425             aFocusVec.push_back( Point( aRect.Left()  + nDiagFocusOffsX, aRect.Top()    - mnFocusOffs     ) );
426             aFocusVec.push_back( Point( aRect.Right() + mnFocusOffs,     aRect.Bottom() - nDiagFocusOffsY ) );
427             aFocusVec.push_back( Point( aRect.Right() + mnFocusOffs,     aRect.Bottom() + mnFocusOffs     ) );
428             aFocusVec.push_back( Point( aRect.Right() - nDiagFocusOffsX, aRect.Bottom() + mnFocusOffs     ) );
429             maTLBR.AddFocusPolygon( Polygon( static_cast< sal_uInt16 >( aFocusVec.size() ), &aFocusVec[ 0 ] ) );
430 
431             aFocusVec.clear();
432             aFocusVec.push_back( Point( aRect.Right() + mnFocusOffs,     aRect.Top()    + nDiagFocusOffsY ) );
433             aFocusVec.push_back( Point( aRect.Right() + mnFocusOffs,     aRect.Top()    - mnFocusOffs     ) );
434             aFocusVec.push_back( Point( aRect.Right() - nDiagFocusOffsX, aRect.Top()    - mnFocusOffs     ) );
435             aFocusVec.push_back( Point( aRect.Left()  - mnFocusOffs,     aRect.Bottom() - nDiagFocusOffsY ) );
436             aFocusVec.push_back( Point( aRect.Left()  - mnFocusOffs,     aRect.Bottom() + mnFocusOffs     ) );
437             aFocusVec.push_back( Point( aRect.Left()  + nDiagFocusOffsX, aRect.Bottom() + mnFocusOffs     ) );
438             maBLTR.AddFocusPolygon( Polygon( static_cast< sal_uInt16 >( aFocusVec.size() ), &aFocusVec[ 0 ] ) );
439         }
440     }
441 
442     // Click areas ------------------------------------------------------------
443 
444     for( FrameBorderIter aIt( maAllBorders ); aIt.Is(); ++aIt )
445         (*aIt)->ClearClickArea();
446 
447     /*  Additional space for click area: is added to the space available to draw
448         the frame borders. For instance left frame border:
449         - To left, top, and bottom always big additional space (outer area).
450         - To right: Dependent on existence of inner vertical frame border
451             (if enabled, use less space).
452      */
453     long nClO = FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_OUTER;
454     long nClI = (mbTLBR && mbBLTR) ? (FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_INNER) : nClO;
455     long nClH = mbHor ? nClI : nClO;            // additional space dependent of horizontal inner border
456     long nClV = mbVer ? nClI : nClO;            // additional space dependent of vertical inner border
457 
458     maLeft.AddClickRect(   Rectangle( mnLine1 - nClO, mnLine1 - nClO, mnLine1 + nClV, mnLine3 + nClO ) );
459     maVer.AddClickRect(    Rectangle( mnLine2 - nClI, mnLine1 - nClO, mnLine2 + nClI, mnLine3 + nClO ) );
460     maRight.AddClickRect(  Rectangle( mnLine3 - nClV, mnLine1 - nClO, mnLine3 + nClO, mnLine3 + nClO ) );
461     maTop.AddClickRect(    Rectangle( mnLine1 - nClO, mnLine1 - nClO, mnLine3 + nClO, mnLine1 + nClH ) );
462     maHor.AddClickRect(    Rectangle( mnLine1 - nClO, mnLine2 - nClI, mnLine3 + nClO, mnLine2 + nClI ) );
463     maBottom.AddClickRect( Rectangle( mnLine1 - nClO, mnLine3 - nClH, mnLine3 + nClO, mnLine3 + nClO ) );
464 
465     /*  Diagonal frame borders use the remaining space between outer and inner frame borders. */
466     if( mbTLBR || mbBLTR )
467     {
468         for( nCol = 0, nCols = maArray.GetColCount(); nCol < nCols; ++nCol )
469         {
470             for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow )
471             {
472                 // the usable area between horizonal/vertical frame borders of current quadrant
473                 Rectangle aRect( maArray.GetCellRect( nCol, nRow ) );
474                 aRect.Left() += nClV + 1;
475                 aRect.Right() -= nClV + 1;
476                 aRect.Top() += nClH + 1;
477                 aRect.Bottom() -= nClH + 1;
478 
479                 /*  Both diagonal frame borders enabled. */
480                 if( mbTLBR && mbBLTR )
481                 {
482                     // single areas
483                     Point aMid( aRect.Center() );
484                     maTLBR.AddClickRect( Rectangle( aRect.TopLeft(), aMid ) );
485                     maTLBR.AddClickRect( Rectangle( aMid + Point( 1, 1 ), aRect.BottomRight() ) );
486                     maBLTR.AddClickRect( Rectangle( aRect.Left(), aMid.Y() + 1, aMid.X(), aRect.Bottom() ) );
487                     maBLTR.AddClickRect( Rectangle( aMid.X() + 1, aRect.Top(), aRect.Right(), aMid.Y() ) );
488                     // centered rectangle for both frame borders
489                     Rectangle aMidRect( aRect.TopLeft(), Size( aRect.GetWidth() / 3, aRect.GetHeight() / 3 ) );
490                     aMidRect.Move( (aRect.GetWidth() - aMidRect.GetWidth()) / 2, (aRect.GetHeight() - aMidRect.GetHeight()) / 2 );
491                     maTLBR.AddClickRect( aMidRect );
492                     maBLTR.AddClickRect( aMidRect );
493                 }
494                 /*  One of the diagonal frame borders enabled - use entire rectangle. */
495                 else if( mbTLBR && !mbBLTR )    // top-left to bottom-right only
496                     maTLBR.AddClickRect( aRect );
497                 else if( !mbTLBR && mbBLTR )    // bottom-left to top-right only
498                     maBLTR.AddClickRect( aRect );
499             }
500         }
501     }
502 }
503 
504 void FrameSelectorImpl::InitVirtualDevice()
505 {
506     // initialize resources
507     InitColors();
508     InitArrowImageList();
509 
510     // initialize geometry
511     InitGlobalGeometry();
512     InitBorderGeometry();
513 
514     // correct background around the used area
515     mrFrameSel.SetBackground( Wallpaper( maBackCol ) );
516     DoInvalidate( true );
517 }
518 
519 // frame border access --------------------------------------------------------
520 
521 const FrameBorder& FrameSelectorImpl::GetBorder( FrameBorderType eBorder ) const
522 {
523     size_t nIndex = GetIndexFromFrameBorderType( eBorder );
524     if( nIndex < maAllBorders.size() )
525         return *maAllBorders[ nIndex ];
526     DBG_ERRORFILE( "svx::FrameSelectorImpl::GetBorder - unknown border type" );
527     return maTop;
528 }
529 
530 FrameBorder& FrameSelectorImpl::GetBorderAccess( FrameBorderType eBorder )
531 {
532     return const_cast< FrameBorder& >( GetBorder( eBorder ) );
533 }
534 
535 // drawing --------------------------------------------------------------------
536 
537 void FrameSelectorImpl::DrawBackground()
538 {
539     // clear the area
540     maVirDev.SetLineColor();
541     maVirDev.SetFillColor( maBackCol );
542     maVirDev.DrawRect( Rectangle( Point( 0, 0 ), maVirDev.GetOutputSizePixel() ) );
543 
544     // draw the inner gray (or whatever color) rectangle
545     maVirDev.SetLineColor();
546     maVirDev.SetFillColor( maMarkCol );
547     maVirDev.DrawRect( Rectangle(
548         mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
549 
550     // draw the white space for enabled frame borders
551     PolyPolygon aPPoly;
552     for( FrameBorderCIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
553         (*aIt)->MergeFocusToPolyPolygon( aPPoly );
554     aPPoly.Optimize( POLY_OPTIMIZE_CLOSE );
555     maVirDev.SetLineColor( maBackCol );
556     maVirDev.SetFillColor( maBackCol );
557     maVirDev.DrawPolyPolygon( aPPoly );
558 }
559 
560 void FrameSelectorImpl::DrawArrows( const FrameBorder& rBorder )
561 {
562     DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::DrawArrows - access to disabled border" );
563 
564     long nLinePos = 0;
565     switch( rBorder.GetType() )
566     {
567         case FRAMEBORDER_LEFT:
568         case FRAMEBORDER_TOP:       nLinePos = mnLine1; break;
569         case FRAMEBORDER_VER:
570         case FRAMEBORDER_HOR:       nLinePos = mnLine2; break;
571         case FRAMEBORDER_RIGHT:
572         case FRAMEBORDER_BOTTOM:    nLinePos = mnLine3; break;
573         default: ; //prevent warning
574     }
575     nLinePos -= mnArrowSize / 2;
576 
577     long nTLPos = 0;
578     long nBRPos = mnCtrlSize - mnArrowSize;
579     Point aPos1, aPos2;
580     sal_uInt16 nImgId1 = 0, nImgId2 = 0;
581     switch( rBorder.GetType() )
582     {
583         case FRAMEBORDER_LEFT:
584         case FRAMEBORDER_RIGHT:
585         case FRAMEBORDER_VER:
586             aPos1 = Point( nLinePos, nTLPos ); nImgId1 = 1;
587             aPos2 = Point( nLinePos, nBRPos ); nImgId2 = 2;
588         break;
589 
590         case FRAMEBORDER_TOP:
591         case FRAMEBORDER_BOTTOM:
592         case FRAMEBORDER_HOR:
593             aPos1 = Point( nTLPos, nLinePos ); nImgId1 = 3;
594             aPos2 = Point( nBRPos, nLinePos ); nImgId2 = 4;
595         break;
596 
597         case FRAMEBORDER_TLBR:
598             aPos1 = Point( nTLPos, nTLPos ); nImgId1 = 5;
599             aPos2 = Point( nBRPos, nBRPos ); nImgId2 = 6;
600         break;
601         case FRAMEBORDER_BLTR:
602             aPos1 = Point( nTLPos, nBRPos ); nImgId1 = 7;
603             aPos2 = Point( nBRPos, nTLPos ); nImgId2 = 8;
604         break;
605         default: ; //prevent warning
606     }
607 
608     // Arrow or marker? Do not draw arrows into disabled control.
609     sal_uInt16 nSelectAdd = (mrFrameSel.IsEnabled() && rBorder.IsSelected()) ? 0 : 8;
610     maVirDev.DrawImage( aPos1, maILArrows.GetImage( nImgId1 + nSelectAdd ) );
611     maVirDev.DrawImage( aPos2, maILArrows.GetImage( nImgId2 + nSelectAdd ) );
612 }
613 
614 void FrameSelectorImpl::DrawAllArrows()
615 {
616     for( FrameBorderCIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
617         DrawArrows( **aIt );
618 }
619 
620 Color FrameSelectorImpl::GetDrawLineColor( const Color& rColor ) const
621 {
622     Color aColor( mbHCMode ? maHCLineCol : rColor );
623     if( aColor == maBackCol )
624         aColor.Invert();
625     return aColor;
626 }
627 
628 void FrameSelectorImpl::DrawAllFrameBorders()
629 {
630     // Translate core colors to current UI colors (regards current background and HC mode).
631     for( FrameBorderIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
632     {
633         Color aCoreColor = ((*aIt)->GetState() == FRAMESTATE_DONTCARE) ? maMarkCol : (*aIt)->GetCoreStyle().GetColor();
634         (*aIt)->SetUIColor( GetDrawLineColor( aCoreColor ) );
635     }
636 
637     // Copy all frame border styles to the helper array
638     maArray.SetColumnStyleLeft( 0, maLeft.GetUIStyle() );
639     if( mbVer ) maArray.SetColumnStyleLeft( 1, maVer.GetUIStyle() );
640     maArray.SetColumnStyleRight( mbVer ? 1 : 0, maRight.GetUIStyle() );
641 
642     maArray.SetRowStyleTop( 0, maTop.GetUIStyle() );
643     if( mbHor ) maArray.SetRowStyleTop( 1, maHor.GetUIStyle() );
644     maArray.SetRowStyleBottom( mbHor ? 1 : 0, maBottom.GetUIStyle() );
645 
646     for( size_t nCol = 0; nCol < maArray.GetColCount(); ++nCol )
647         for( size_t nRow = 0; nRow < maArray.GetRowCount(); ++nRow )
648             maArray.SetCellStyleDiag( nCol, nRow, maTLBR.GetUIStyle(), maBLTR.GetUIStyle() );
649 
650     // Let the helper array draw itself
651     maArray.DrawArray( maVirDev );
652 }
653 
654 void FrameSelectorImpl::DrawVirtualDevice()
655 {
656     DrawBackground();
657     DrawAllArrows();
658     DrawAllFrameBorders();
659     mbFullRepaint = false;
660 }
661 
662 void FrameSelectorImpl::CopyVirDevToControl()
663 {
664     if( mbFullRepaint )
665         DrawVirtualDevice();
666     mrFrameSel.DrawBitmap( maVirDevPos, maVirDev.GetBitmap( Point( 0, 0 ), maVirDev.GetOutputSizePixel() ) );
667 }
668 
669 void FrameSelectorImpl::DrawAllTrackingRects()
670 {
671     PolyPolygon aPPoly;
672     if( mrFrameSel.IsAnyBorderSelected() )
673     {
674         for( SelFrameBorderCIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
675             (*aIt)->MergeFocusToPolyPolygon( aPPoly );
676         aPPoly.Move( maVirDevPos.X(), maVirDevPos.Y() );
677     }
678     else
679         // no frame border selected -> draw tracking rectangle around entire control
680         aPPoly.Insert( Polygon( Rectangle( maVirDevPos, maVirDev.GetOutputSizePixel() ) ) );
681 
682     aPPoly.Optimize( POLY_OPTIMIZE_CLOSE );
683     for( sal_uInt16 nIdx = 0, nCount = aPPoly.Count(); nIdx < nCount; ++nIdx )
684         mrFrameSel.InvertTracking( aPPoly.GetObject( nIdx ), SHOWTRACK_SMALL | SHOWTRACK_WINDOW );
685 }
686 
687 Point FrameSelectorImpl::GetDevPosFromMousePos( const Point& rMousePos ) const
688 {
689     return rMousePos - maVirDevPos;
690 }
691 
692 void FrameSelectorImpl::DoInvalidate( bool bFullRepaint )
693 {
694     mbFullRepaint |= bFullRepaint;
695     mrFrameSel.Invalidate( INVALIDATE_NOERASE );
696 }
697 
698 // frame border state and style -----------------------------------------------
699 
700 void FrameSelectorImpl::SetBorderState( FrameBorder& rBorder, FrameBorderState eState )
701 {
702     DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SetBorderState - access to disabled border" );
703     if( eState == FRAMESTATE_SHOW )
704         SetBorderCoreStyle( rBorder, &maCurrStyle );
705     else
706         rBorder.SetState( eState );
707     DoInvalidate( true );
708 }
709 
710 void FrameSelectorImpl::SetBorderCoreStyle( FrameBorder& rBorder, const SvxBorderLine* pStyle )
711 {
712     DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SetBorderCoreStyle - access to disabled border" );
713     rBorder.SetCoreStyle( pStyle );
714     DoInvalidate( true );
715 }
716 
717 void FrameSelectorImpl::ToggleBorderState( FrameBorder& rBorder )
718 {
719     bool bDontCare = mrFrameSel.SupportsDontCareState();
720     switch( rBorder.GetState() )
721     {
722         // same order as tristate check box: visible -> don't care -> hidden
723         case FRAMESTATE_SHOW:
724             SetBorderState( rBorder, bDontCare ? FRAMESTATE_DONTCARE : FRAMESTATE_HIDE );
725         break;
726         case FRAMESTATE_HIDE:
727             SetBorderState( rBorder, FRAMESTATE_SHOW );
728         break;
729         case FRAMESTATE_DONTCARE:
730             SetBorderState( rBorder, FRAMESTATE_HIDE );
731         break;
732     }
733 }
734 
735 // frame border selection -----------------------------------------------------
736 
737 void FrameSelectorImpl::SelectBorder( FrameBorder& rBorder, bool bSelect )
738 {
739     DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SelectBorder - access to disabled border" );
740     rBorder.Select( bSelect );
741     DrawArrows( rBorder );
742     DoInvalidate( false );
743     maSelectHdl.Call( this );
744 }
745 
746 void FrameSelectorImpl::SilentGrabFocus()
747 {
748     bool bOldAuto = mbAutoSelect;
749     mbAutoSelect = false;
750     mrFrameSel.GrabFocus();
751     mbAutoSelect = bOldAuto;
752 }
753 
754 bool FrameSelectorImpl::SelectedBordersEqual() const
755 {
756     bool bEqual = true;
757     SelFrameBorderCIter aIt( maEnabBorders );
758     if( aIt.Is() )
759     {
760         const SvxBorderLine& rFirstStyle = (*aIt)->GetCoreStyle();
761         for( ++aIt; bEqual && aIt.Is(); ++aIt )
762             bEqual = ((*aIt)->GetCoreStyle() == rFirstStyle);
763     }
764     return bEqual;
765 }
766 
767 // ============================================================================
768 // FrameSelector
769 // ============================================================================
770 
771 FrameSelector::FrameSelector( Window* pParent, const ResId& rResId ) :
772     Control( pParent, rResId )
773 {
774     // not in c'tor init list (avoid warning about usage of *this)
775     mxImpl.reset( new FrameSelectorImpl( *this ) );
776     EnableRTL( false ); // #107808# don't mirror the mouse handling
777 }
778 
779 FrameSelector::~FrameSelector()
780 {
781 }
782 
783 void FrameSelector::Initialize( FrameSelFlags nFlags )
784 {
785     mxImpl->Initialize( nFlags );
786 	Show();
787 }
788 
789 // enabled frame borders ------------------------------------------------------
790 
791 bool FrameSelector::IsBorderEnabled( FrameBorderType eBorder ) const
792 {
793     return mxImpl->GetBorder( eBorder ).IsEnabled();
794 }
795 
796 sal_Int32 FrameSelector::GetEnabledBorderCount() const
797 {
798     return static_cast< sal_Int32 >( mxImpl->maEnabBorders.size() );
799 }
800 
801 FrameBorderType FrameSelector::GetEnabledBorderType( sal_Int32 nIndex ) const
802 {
803     FrameBorderType eBorder = FRAMEBORDER_NONE;
804     if( nIndex >= 0 )
805     {
806         size_t nVecIdx = static_cast< size_t >( nIndex );
807         if( nVecIdx < mxImpl->maEnabBorders.size() )
808             eBorder = mxImpl->maEnabBorders[ nVecIdx ]->GetType();
809     }
810     return eBorder;
811 }
812 
813 sal_Int32 FrameSelector::GetEnabledBorderIndex( FrameBorderType eBorder ) const
814 {
815     sal_Int32 nIndex = 0;
816     for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt, ++nIndex )
817         if( (*aIt)->GetType() == eBorder )
818             return nIndex;
819     return -1;
820 }
821 
822 // frame border state and style -----------------------------------------------
823 
824 bool FrameSelector::SupportsDontCareState() const
825 {
826     return (mxImpl->mnFlags & FRAMESEL_DONTCARE) != 0;
827 }
828 
829 FrameBorderState FrameSelector::GetFrameBorderState( FrameBorderType eBorder ) const
830 {
831     return mxImpl->GetBorder( eBorder ).GetState();
832 }
833 
834 const SvxBorderLine* FrameSelector::GetFrameBorderStyle( FrameBorderType eBorder ) const
835 {
836     const SvxBorderLine& rStyle = mxImpl->GetBorder( eBorder ).GetCoreStyle();
837     // rest of the world uses null pointer for invisible frame border
838     return rStyle.GetOutWidth() ? &rStyle : 0;
839 }
840 
841 void FrameSelector::ShowBorder( FrameBorderType eBorder, const SvxBorderLine* pStyle )
842 {
843     mxImpl->SetBorderCoreStyle( mxImpl->GetBorderAccess( eBorder ), pStyle );
844 }
845 
846 void FrameSelector::SetBorderDontCare( FrameBorderType eBorder )
847 {
848     mxImpl->SetBorderState( mxImpl->GetBorderAccess( eBorder ), FRAMESTATE_DONTCARE );
849 }
850 
851 bool FrameSelector::IsAnyBorderVisible() const
852 {
853     bool bIsSet = false;
854     for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !bIsSet && aIt.Is(); ++aIt )
855         bIsSet = ((*aIt)->GetState() == FRAMESTATE_SHOW);
856     return bIsSet;
857 }
858 
859 void FrameSelector::HideAllBorders()
860 {
861     for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
862         mxImpl->SetBorderState( **aIt, FRAMESTATE_HIDE );
863 }
864 
865 bool FrameSelector::GetVisibleWidth( sal_uInt16& rnPrim, sal_uInt16& rnDist, sal_uInt16& rnSecn ) const
866 {
867     VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
868     if( !aIt.Is() )
869         return false;
870 
871     const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
872     bool bFound = true;
873     for( ++aIt; bFound && aIt.Is(); ++aIt )
874         bFound =
875             (rStyle.GetOutWidth() == (*aIt)->GetCoreStyle().GetOutWidth()) &&
876             (rStyle.GetDistance() == (*aIt)->GetCoreStyle().GetDistance()) &&
877             (rStyle.GetInWidth()  == (*aIt)->GetCoreStyle().GetInWidth());
878 
879     if( bFound )
880     {
881         rnPrim = rStyle.GetOutWidth();
882         rnDist = rStyle.GetDistance();
883         rnSecn = rStyle.GetInWidth();
884     }
885     return bFound;
886 }
887 
888 bool FrameSelector::GetVisibleColor( Color& rColor ) const
889 {
890     VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
891     if( !aIt.Is() )
892         return false;
893 
894     const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
895     bool bFound = true;
896     for( ++aIt; bFound && aIt.Is(); ++aIt )
897         bFound = (rStyle.GetColor() == (*aIt)->GetCoreStyle().GetColor());
898 
899     if( bFound )
900         rColor = rStyle.GetColor();
901     return bFound;
902 }
903 
904 // frame border selection -----------------------------------------------------
905 
906 const Link& FrameSelector::GetSelectHdl() const
907 {
908     return mxImpl->maSelectHdl;
909 }
910 
911 void FrameSelector::SetSelectHdl( const Link& rHdl )
912 {
913     mxImpl->maSelectHdl = rHdl;
914 }
915 
916 bool FrameSelector::IsBorderSelected( FrameBorderType eBorder ) const
917 {
918     return mxImpl->GetBorder( eBorder ).IsSelected();
919 }
920 
921 void FrameSelector::SelectBorder( FrameBorderType eBorder, bool bSelect )
922 {
923     mxImpl->SelectBorder( mxImpl->GetBorderAccess( eBorder ), bSelect );
924 }
925 
926 bool FrameSelector::IsAnyBorderSelected() const
927 {
928     // Construct an iterator for selected borders. If it is valid, there is a selected border.
929     return SelFrameBorderCIter( mxImpl->maEnabBorders ).Is();
930 }
931 
932 void FrameSelector::SelectAllBorders( bool bSelect )
933 {
934     for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
935         mxImpl->SelectBorder( **aIt, bSelect );
936 }
937 
938 void FrameSelector::SelectAllVisibleBorders( bool bSelect )
939 {
940     for( VisFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
941         mxImpl->SelectBorder( **aIt, bSelect );
942 }
943 
944 void FrameSelector::SetStyleToSelection( sal_uInt16 nPrim, sal_uInt16 nDist, sal_uInt16 nSecn )
945 {
946     mxImpl->maCurrStyle.SetOutWidth( nPrim );
947     mxImpl->maCurrStyle.SetDistance( nDist );
948     mxImpl->maCurrStyle.SetInWidth( nSecn );
949     for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
950         mxImpl->SetBorderState( **aIt, FRAMESTATE_SHOW );
951 }
952 
953 void FrameSelector::SetColorToSelection( const Color& rColor )
954 {
955     mxImpl->maCurrStyle.SetColor( rColor );
956     for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
957         mxImpl->SetBorderState( **aIt, FRAMESTATE_SHOW );
958 }
959 
960 // accessibility --------------------------------------------------------------
961 
962 Reference< XAccessible > FrameSelector::CreateAccessible()
963 {
964     if( !mxImpl->mxAccess.is() )
965         mxImpl->mxAccess = mxImpl->mpAccess =
966             new a11y::AccFrameSelector( *this, FRAMEBORDER_NONE );
967     return mxImpl->mxAccess;
968 }
969 
970 Reference< XAccessible > FrameSelector::GetChildAccessible( FrameBorderType eBorder )
971 {
972     Reference< XAccessible > xRet;
973     size_t nVecIdx = static_cast< size_t >( eBorder );
974     if( IsBorderEnabled( eBorder ) && (1 <= nVecIdx) && (nVecIdx <= mxImpl->maChildVec.size()) )
975     {
976         --nVecIdx;
977         if( !mxImpl->maChildVec[ nVecIdx ] )
978             mxImpl->mxChildVec[ nVecIdx ] = mxImpl->maChildVec[ nVecIdx ] =
979                 new a11y::AccFrameSelector( *this, eBorder );
980         xRet = mxImpl->mxChildVec[ nVecIdx ];
981     }
982     return xRet;
983 }
984 
985 Reference< XAccessible > FrameSelector::GetChildAccessible( sal_Int32 nIndex )
986 {
987     return GetChildAccessible( GetEnabledBorderType( nIndex ) );
988 }
989 
990 Reference< XAccessible > FrameSelector::GetChildAccessible( const Point& rPos )
991 {
992     Reference< XAccessible > xRet;
993     for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !xRet.is() && aIt.Is(); ++aIt )
994         if( (*aIt)->ContainsClickPoint( rPos ) )
995             xRet = GetChildAccessible( (*aIt)->GetType() );
996     return xRet;
997 }
998 
999 bool FrameSelector::ContainsClickPoint( const Point& rPos ) const
1000 {
1001     bool bContains = false;
1002     for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !bContains && aIt.Is(); ++aIt )
1003         bContains = (*aIt)->ContainsClickPoint( rPos );
1004     return bContains;
1005 }
1006 
1007 Rectangle FrameSelector::GetClickBoundRect( FrameBorderType eBorder ) const
1008 {
1009     Rectangle aRect;
1010     const FrameBorder& rBorder = mxImpl->GetBorder( eBorder );
1011     if( rBorder.IsEnabled() )
1012         aRect = rBorder.GetClickBoundRect();
1013     return aRect;
1014 }
1015 
1016 // virtual functions from base class ------------------------------------------
1017 
1018 void FrameSelector::Paint( const Rectangle& )
1019 {
1020     mxImpl->CopyVirDevToControl();
1021     if( HasFocus() )
1022         mxImpl->DrawAllTrackingRects();
1023 }
1024 
1025 void FrameSelector::MouseButtonDown( const MouseEvent& rMEvt )
1026 {
1027     /*  Mouse handling:
1028         * Click on an unselected frame border:
1029             Set current style/color, make frame border visible, deselect all
1030             other frame borders.
1031         * Click on a selected frame border:
1032             Toggle state of the frame border (visible -> don't care -> hidden),
1033             deselect all other frame borders.
1034         * SHIFT+Click or CTRL+Click on an unselected frame border:
1035             Extend selection, set current style/color to all selected frame
1036             borders independent of the state/style/color of the borders.
1037         * SHIFT+Click or CTRL+Click on a selected frame border:
1038             If all frame borders have same style/color, toggle state of all
1039             borders (see above), otherwise set current style/color to all
1040             borders.
1041         * Click on unused area: Do not modify selection and selected frame
1042             borders.
1043      */
1044 
1045     // #107394# do not auto-select a frame border
1046     mxImpl->SilentGrabFocus();
1047 
1048     if( rMEvt.IsLeft() )
1049     {
1050         Point aPos( mxImpl->GetDevPosFromMousePos( rMEvt.GetPosPixel() ) );
1051         FrameBorderPtrVec aDeselectBorders;
1052 
1053         bool bAnyClicked = false;   // Any frame border clicked?
1054         bool bNewSelected = false;  // Any unselected frame border selected?
1055 
1056         /*  If frame borders are set to "don't care" and the control does not
1057             support this state, hide them on first mouse click.
1058             DR 2004-01-30: Why are the borders set to "don't care" then?!? */
1059         bool bHideDontCare = !mxImpl->mbClicked && !SupportsDontCareState();
1060 
1061         for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1062         {
1063             if( (*aIt)->ContainsClickPoint( aPos ) )
1064             {
1065                 // frame border is clicked
1066                 bAnyClicked = true;
1067                 if( !(*aIt)->IsSelected() )
1068                 {
1069                     bNewSelected = true;
1070                     mxImpl->SelectBorder( **aIt, true );
1071                 }
1072             }
1073             else
1074             {
1075                 // hide a "don't care" frame border only if it is not clicked
1076                 if( bHideDontCare && ((*aIt)->GetState() == FRAMESTATE_DONTCARE) )
1077                     mxImpl->SetBorderState( **aIt, FRAMESTATE_HIDE );
1078 
1079                 // deselect frame borders not clicked (if SHIFT or CTRL are not pressed)
1080                 if( !rMEvt.IsShift() && !rMEvt.IsMod1() )
1081                     aDeselectBorders.push_back( *aIt );
1082             }
1083         }
1084 
1085         if( bAnyClicked )
1086         {
1087             // any valid frame border clicked? -> deselect other frame borders
1088             for( FrameBorderIter aIt( aDeselectBorders ); aIt.Is(); ++aIt )
1089                 mxImpl->SelectBorder( **aIt, false );
1090 
1091             if( bNewSelected || !mxImpl->SelectedBordersEqual() )
1092             {
1093                 // new frame border selected, selection extended, or selected borders different? -> show
1094                 for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1095                     // SetBorderState() sets current style and color to the frame border
1096                     mxImpl->SetBorderState( **aIt, FRAMESTATE_SHOW );
1097             }
1098             else
1099             {
1100                 // all selected frame borders are equal -> toggle state
1101                 for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1102                     mxImpl->ToggleBorderState( **aIt );
1103             }
1104         }
1105     }
1106 }
1107 
1108 void FrameSelector::KeyInput( const KeyEvent& rKEvt )
1109 {
1110     bool bHandled = false;
1111     KeyCode aKeyCode = rKEvt.GetKeyCode();
1112     if( !aKeyCode.GetModifier() )
1113     {
1114         sal_uInt16 nCode = aKeyCode.GetCode();
1115         switch( nCode )
1116         {
1117             case KEY_SPACE:
1118             {
1119                 for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1120                     mxImpl->ToggleBorderState( **aIt );
1121                 bHandled = true;
1122             }
1123             break;
1124 
1125             case KEY_UP:
1126             case KEY_DOWN:
1127             case KEY_LEFT:
1128             case KEY_RIGHT:
1129             {
1130                 if( !mxImpl->maEnabBorders.empty() )
1131                 {
1132                     // start from first selected frame border
1133                     SelFrameBorderCIter aIt( mxImpl->maEnabBorders );
1134                     FrameBorderType eBorder = aIt.Is() ? (*aIt)->GetType() : mxImpl->maEnabBorders.front()->GetType();
1135 
1136                     // search for next enabled frame border
1137                     do
1138                     {
1139                         eBorder = mxImpl->GetBorder( eBorder ).GetKeyboardNeighbor( nCode );
1140                     }
1141                     while( (eBorder != FRAMEBORDER_NONE) && !IsBorderEnabled( eBorder ) );
1142 
1143                     // select the frame border
1144                     if( eBorder != FRAMEBORDER_NONE )
1145                     {
1146                         DeselectAllBorders();
1147                         SelectBorder( eBorder );
1148                     }
1149                 }
1150             }
1151             break;
1152         }
1153     }
1154     if( !bHandled )
1155         Window::KeyInput(rKEvt);
1156 }
1157 
1158 void FrameSelector::GetFocus()
1159 {
1160     // auto-selection of a frame border, if focus reaches control, and nothing is selected
1161     if( mxImpl->mbAutoSelect && !IsAnyBorderSelected() && !mxImpl->maEnabBorders.empty() )
1162         mxImpl->SelectBorder( *mxImpl->maEnabBorders.front(), true );
1163 
1164     mxImpl->DoInvalidate( false );
1165     if( mxImpl->mxAccess.is() )
1166         mxImpl->mpAccess->NotifyFocusListeners( sal_True );
1167     Control::GetFocus();
1168 }
1169 
1170 void FrameSelector::LoseFocus()
1171 {
1172     mxImpl->DoInvalidate( false );
1173     if( mxImpl->mxAccess.is() )
1174         mxImpl->mpAccess->NotifyFocusListeners( sal_False );
1175     Control::LoseFocus();
1176 }
1177 
1178 void FrameSelector::DataChanged( const DataChangedEvent& rDCEvt )
1179 {
1180     Control::DataChanged( rDCEvt );
1181     if( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && (rDCEvt.GetFlags() & SETTINGS_STYLE) )
1182         mxImpl->InitVirtualDevice();
1183 }
1184 
1185 // ============================================================================
1186 
1187 template< typename Cont, typename Iter, typename Pred >
1188 FrameBorderIterBase< Cont, Iter, Pred >::FrameBorderIterBase( container_type& rCont ) :
1189     maIt( rCont.begin() ),
1190     maEnd( rCont.end() )
1191 {
1192     while( Is() && !maPred( *maIt ) ) ++maIt;
1193 }
1194 
1195 template< typename Cont, typename Iter, typename Pred >
1196 FrameBorderIterBase< Cont, Iter, Pred >& FrameBorderIterBase< Cont, Iter, Pred >::operator++()
1197 {
1198     do { ++maIt; } while( Is() && !maPred( *maIt ) );
1199     return *this;
1200 }
1201 
1202 // ============================================================================
1203 
1204 } // namespace svx
1205 
1206