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