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