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