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/builderfactory.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 : namespace
64 : {
65 :
66 : /** Space between outer control border and any graphical element of the control. */
67 : const long FRAMESEL_GEOM_OUTER = 2;
68 :
69 : /** Space between arrows and usable inner area. */
70 : const long FRAMESEL_GEOM_INNER = 3;
71 :
72 : /** Maximum width to draw a frame border style. */
73 : const long FRAMESEL_GEOM_WIDTH = 9;
74 :
75 : /** Additional margin for click area of outer lines. */
76 : const long FRAMESEL_GEOM_ADD_CLICK_OUTER = 5;
77 :
78 : /** Additional margin for click area of inner lines. */
79 : const long FRAMESEL_GEOM_ADD_CLICK_INNER = 2;
80 :
81 :
82 : /** Returns the corresponding flag for a frame border. */
83 0 : FrameSelFlags lclGetFlagFromType( FrameBorderType eBorder )
84 : {
85 0 : switch( eBorder )
86 : {
87 0 : case FRAMEBORDER_LEFT: return FRAMESEL_LEFT;
88 0 : case FRAMEBORDER_RIGHT: return FRAMESEL_RIGHT;
89 0 : case FRAMEBORDER_TOP: return FRAMESEL_TOP;
90 0 : case FRAMEBORDER_BOTTOM: return FRAMESEL_BOTTOM;
91 0 : case FRAMEBORDER_HOR: return FRAMESEL_INNER_HOR;
92 0 : case FRAMEBORDER_VER: return FRAMESEL_INNER_VER;
93 0 : case FRAMEBORDER_TLBR: return FRAMESEL_DIAG_TLBR;
94 0 : case FRAMEBORDER_BLTR: return FRAMESEL_DIAG_BLTR;
95 0 : case FRAMEBORDER_NONE : break;
96 : }
97 0 : return FRAMESEL_NONE;
98 : }
99 :
100 : /** Merges the rSource polypolygon into the rDest polypolygon. */
101 0 : inline void lclPolyPolyUnion( tools::PolyPolygon& rDest, const tools::PolyPolygon& rSource )
102 : {
103 0 : const tools::PolyPolygon aTmp( rDest );
104 0 : aTmp.GetUnion( rSource, rDest );
105 0 : }
106 :
107 : } // namespace
108 :
109 0 : FrameBorder::FrameBorder( FrameBorderType eType ) :
110 : meType( eType ),
111 : meState( FRAMESTATE_HIDE ),
112 : meKeyLeft( FRAMEBORDER_NONE ),
113 : meKeyRight( FRAMEBORDER_NONE ),
114 : meKeyTop( FRAMEBORDER_NONE ),
115 : meKeyBottom( FRAMEBORDER_NONE ),
116 : mbEnabled( false ),
117 0 : mbSelected( false )
118 : {
119 0 : }
120 :
121 0 : void FrameBorder::Enable( FrameSelFlags nFlags )
122 : {
123 0 : mbEnabled = (nFlags & lclGetFlagFromType( meType )) != 0;
124 0 : if( !mbEnabled )
125 0 : SetState( FRAMESTATE_HIDE );
126 0 : }
127 :
128 0 : void FrameBorder::SetCoreStyle( const SvxBorderLine* pStyle )
129 : {
130 0 : if( pStyle )
131 0 : maCoreStyle = *pStyle;
132 : else
133 0 : maCoreStyle = SvxBorderLine();
134 :
135 : // from twips to points
136 0 : maUIStyle.Set( maCoreStyle, 0.05, FRAMESEL_GEOM_WIDTH );
137 0 : meState = maUIStyle.Prim() ? FRAMESTATE_SHOW : FRAMESTATE_HIDE;
138 0 : }
139 :
140 0 : void FrameBorder::SetState( FrameBorderState eState )
141 : {
142 0 : meState = eState;
143 0 : switch( meState )
144 : {
145 : case FRAMESTATE_SHOW:
146 : SAL_WARN( "svx.dialog", "svx::FrameBorder::SetState - use SetCoreStyle to make border visible" );
147 0 : break;
148 : case FRAMESTATE_HIDE:
149 0 : maCoreStyle = SvxBorderLine();
150 0 : maUIStyle.Clear();
151 0 : break;
152 : case FRAMESTATE_DONTCARE:
153 0 : maCoreStyle = SvxBorderLine();
154 0 : maUIStyle = frame::Style(3, 0, 0, table::BorderLineStyle::SOLID); //OBJ_FRAMESTYLE_DONTCARE
155 0 : break;
156 : }
157 0 : }
158 :
159 0 : void FrameBorder::AddFocusPolygon( const Polygon& rFocus )
160 : {
161 0 : lclPolyPolyUnion( maFocusArea, rFocus );
162 0 : }
163 :
164 0 : void FrameBorder::MergeFocusToPolyPolygon( tools::PolyPolygon& rPPoly ) const
165 : {
166 0 : lclPolyPolyUnion( rPPoly, maFocusArea );
167 0 : }
168 :
169 0 : void FrameBorder::AddClickRect( const Rectangle& rRect )
170 : {
171 0 : lclPolyPolyUnion( maClickArea, Polygon( rRect ) );
172 0 : }
173 :
174 0 : bool FrameBorder::ContainsClickPoint( const Point& rPos ) const
175 : {
176 0 : return vcl::Region( maClickArea ).IsInside( rPos );
177 : }
178 :
179 0 : Rectangle FrameBorder::GetClickBoundRect() const
180 : {
181 0 : return maClickArea.GetBoundRect();
182 : }
183 :
184 0 : void FrameBorder::SetKeyboardNeighbors(
185 : FrameBorderType eLeft, FrameBorderType eRight, FrameBorderType eTop, FrameBorderType eBottom )
186 : {
187 0 : meKeyLeft = eLeft;
188 0 : meKeyRight = eRight;
189 0 : meKeyTop = eTop;
190 0 : meKeyBottom = eBottom;
191 0 : }
192 :
193 0 : FrameBorderType FrameBorder::GetKeyboardNeighbor( sal_uInt16 nKeyCode ) const
194 : {
195 0 : FrameBorderType eBorder = FRAMEBORDER_NONE;
196 0 : switch( nKeyCode )
197 : {
198 0 : case KEY_LEFT: eBorder = meKeyLeft; break;
199 0 : case KEY_RIGHT: eBorder = meKeyRight; break;
200 0 : case KEY_UP: eBorder = meKeyTop; break;
201 0 : case KEY_DOWN: eBorder = meKeyBottom; break;
202 : default: SAL_WARN( "svx.dialog", "svx::FrameBorder::GetKeyboardNeighbor - unknown key code" );
203 : }
204 0 : return eBorder;
205 : }
206 :
207 0 : FrameSelectorImpl::FrameSelectorImpl( FrameSelector& rFrameSel ) :
208 0 : Resource( SVX_RES( RID_SVXSTR_BORDER_CONTROL ) ),
209 : mrFrameSel( rFrameSel ),
210 : mpVirDev( VclPtr<VirtualDevice>::Create() ),
211 : maILArrows( 16 ),
212 : maLeft( FRAMEBORDER_LEFT ),
213 : maRight( FRAMEBORDER_RIGHT ),
214 : maTop( FRAMEBORDER_TOP ),
215 : maBottom( FRAMEBORDER_BOTTOM ),
216 : maHor( FRAMEBORDER_HOR ),
217 : maVer( FRAMEBORDER_VER ),
218 : maTLBR( FRAMEBORDER_TLBR ),
219 : maBLTR( FRAMEBORDER_BLTR ),
220 : mnFlags( FRAMESEL_OUTER ),
221 : mnCtrlSize( 0 ),
222 : mnArrowSize( 0 ),
223 : mnLine1( 0 ),
224 : mnLine2( 0 ),
225 : mnLine3( 0 ),
226 : mnFocusOffs( 0 ),
227 : mbHor( false ),
228 : mbVer( false ),
229 : mbTLBR( false ),
230 : mbBLTR( false ),
231 : mbFullRepaint( true ),
232 : mbAutoSelect( true ),
233 : mbClicked( false ),
234 : mbHCMode( false ),
235 : mpAccess( 0 ),
236 : maChildVec( 8, static_cast< a11y::AccFrameSelector* >( 0 ) ),
237 0 : mxChildVec( 8 )
238 : {
239 0 : FreeResource();
240 :
241 0 : maAllBorders.resize( FRAMEBORDERTYPE_COUNT, 0 );
242 0 : maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_LEFT ) ] = &maLeft;
243 0 : maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_RIGHT ) ] = &maRight;
244 0 : maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_TOP ) ] = &maTop;
245 0 : maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_BOTTOM ) ] = &maBottom;
246 0 : maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_HOR ) ] = &maHor;
247 0 : maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_VER ) ] = &maVer;
248 0 : maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_TLBR ) ] = &maTLBR;
249 0 : maAllBorders[ GetIndexFromFrameBorderType( FRAMEBORDER_BLTR ) ] = &maBLTR;
250 : #if OSL_DEBUG_LEVEL >= 2
251 : {
252 : bool bOk = true;
253 : for( FrameBorderCIter aIt( maAllBorders ); bOk && aIt.Is(); bOk = (*aIt != 0), ++aIt );
254 : DBG_ASSERT( bOk, "svx::FrameSelectorImpl::FrameSelectorImpl - missing entry in maAllBorders" );
255 : }
256 : #endif
257 : // left neighbor right neighbor upper neighbor lower neighbor
258 0 : maLeft.SetKeyboardNeighbors( FRAMEBORDER_NONE, FRAMEBORDER_TLBR, FRAMEBORDER_TOP, FRAMEBORDER_BOTTOM );
259 0 : maRight.SetKeyboardNeighbors( FRAMEBORDER_BLTR, FRAMEBORDER_NONE, FRAMEBORDER_TOP, FRAMEBORDER_BOTTOM );
260 0 : maTop.SetKeyboardNeighbors( FRAMEBORDER_LEFT, FRAMEBORDER_RIGHT, FRAMEBORDER_NONE, FRAMEBORDER_TLBR );
261 0 : maBottom.SetKeyboardNeighbors( FRAMEBORDER_LEFT, FRAMEBORDER_RIGHT, FRAMEBORDER_BLTR, FRAMEBORDER_NONE );
262 0 : maHor.SetKeyboardNeighbors( FRAMEBORDER_LEFT, FRAMEBORDER_RIGHT, FRAMEBORDER_TLBR, FRAMEBORDER_BLTR );
263 0 : maVer.SetKeyboardNeighbors( FRAMEBORDER_TLBR, FRAMEBORDER_BLTR, FRAMEBORDER_TOP, FRAMEBORDER_BOTTOM );
264 0 : maTLBR.SetKeyboardNeighbors( FRAMEBORDER_LEFT, FRAMEBORDER_VER, FRAMEBORDER_TOP, FRAMEBORDER_HOR );
265 0 : maBLTR.SetKeyboardNeighbors( FRAMEBORDER_VER, FRAMEBORDER_RIGHT, FRAMEBORDER_HOR, FRAMEBORDER_BOTTOM );
266 :
267 0 : Initialize(mnFlags);
268 0 : }
269 :
270 0 : FrameSelectorImpl::~FrameSelectorImpl()
271 :
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& rSettings = mrFrameSel.GetSettings().GetStyleSettings();
303 0 : maBackCol = rSettings.GetFieldColor();
304 0 : mbHCMode = rSettings.GetHighContrastMode();
305 0 : maArrowCol = rSettings.GetFieldTextColor();
306 0 : maMarkCol.operator=(maBackCol).Merge(maArrowCol, mbHCMode ? 0x80 : 0xC0);
307 0 : maHCLineCol = rSettings.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 : mpVirDev->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 : mpVirDev->SetLineColor();
521 0 : mpVirDev->SetFillColor( maBackCol );
522 0 : mpVirDev->DrawRect( Rectangle( Point( 0, 0 ), mpVirDev->GetOutputSizePixel() ) );
523 :
524 : // draw the inner gray (or whatever color) rectangle
525 0 : mpVirDev->SetLineColor();
526 0 : mpVirDev->SetFillColor( maMarkCol );
527 0 : mpVirDev->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( PolyOptimizeFlags::CLOSE );
535 0 : mpVirDev->SetLineColor( maBackCol );
536 0 : mpVirDev->SetFillColor( maBackCol );
537 0 : mpVirDev->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 : mpVirDev->DrawImage( aPos1, maILArrows.GetImage( nImgId1 + nSelectAdd ) );
591 0 : mpVirDev->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( *mpVirDev.get() );
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(vcl::RenderContext& rRenderContext)
671 : {
672 0 : if (mbFullRepaint)
673 0 : DrawVirtualDevice();
674 0 : rRenderContext.DrawBitmap(maVirDevPos, mpVirDev->GetBitmap(Point(0, 0), mpVirDev->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, mpVirDev->GetOutputSizePixel())));
689 :
690 0 : aPPoly.Optimize(PolyOptimizeFlags::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( InvalidateFlags::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 : FrameSelector::~FrameSelector()
793 : {
794 0 : disposeOnce();
795 0 : }
796 :
797 0 : VCL_BUILDER_DECL_FACTORY(SvxFrameSelector)
798 : {
799 : (void)rMap;
800 0 : rRet = VclPtr<FrameSelector>::Create(pParent);
801 0 : }
802 :
803 0 : void FrameSelector::Initialize( FrameSelFlags nFlags )
804 : {
805 0 : mxImpl->Initialize( nFlags );
806 0 : Show();
807 0 : }
808 :
809 : // enabled frame borders
810 0 : bool FrameSelector::IsBorderEnabled( FrameBorderType eBorder ) const
811 : {
812 0 : return mxImpl->GetBorder( eBorder ).IsEnabled();
813 : }
814 :
815 0 : sal_Int32 FrameSelector::GetEnabledBorderCount() const
816 : {
817 0 : return static_cast< sal_Int32 >( mxImpl->maEnabBorders.size() );
818 : }
819 :
820 0 : FrameBorderType FrameSelector::GetEnabledBorderType( sal_Int32 nIndex ) const
821 : {
822 0 : FrameBorderType eBorder = FRAMEBORDER_NONE;
823 0 : if( nIndex >= 0 )
824 : {
825 0 : size_t nVecIdx = static_cast< size_t >( nIndex );
826 0 : if( nVecIdx < mxImpl->maEnabBorders.size() )
827 0 : eBorder = mxImpl->maEnabBorders[ nVecIdx ]->GetType();
828 : }
829 0 : return eBorder;
830 : }
831 :
832 0 : sal_Int32 FrameSelector::GetEnabledBorderIndex( FrameBorderType eBorder ) const
833 : {
834 0 : sal_Int32 nIndex = 0;
835 0 : for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt, ++nIndex )
836 0 : if( (*aIt)->GetType() == eBorder )
837 0 : return nIndex;
838 0 : return -1;
839 : }
840 :
841 : // frame border state and style
842 0 : bool FrameSelector::SupportsDontCareState() const
843 : {
844 0 : return (mxImpl->mnFlags & FRAMESEL_DONTCARE) != 0;
845 : }
846 :
847 0 : FrameBorderState FrameSelector::GetFrameBorderState( FrameBorderType eBorder ) const
848 : {
849 0 : return mxImpl->GetBorder( eBorder ).GetState();
850 : }
851 :
852 0 : const SvxBorderLine* FrameSelector::GetFrameBorderStyle( FrameBorderType eBorder ) const
853 : {
854 0 : const SvxBorderLine& rStyle = mxImpl->GetBorder( eBorder ).GetCoreStyle();
855 : // rest of the world uses null pointer for invisible frame border
856 0 : return rStyle.GetOutWidth() ? &rStyle : 0;
857 : }
858 :
859 0 : void FrameSelector::ShowBorder( FrameBorderType eBorder, const SvxBorderLine* pStyle )
860 : {
861 0 : mxImpl->SetBorderCoreStyle( mxImpl->GetBorderAccess( eBorder ), pStyle );
862 0 : }
863 :
864 0 : void FrameSelector::SetBorderDontCare( FrameBorderType eBorder )
865 : {
866 0 : mxImpl->SetBorderState( mxImpl->GetBorderAccess( eBorder ), FRAMESTATE_DONTCARE );
867 0 : }
868 :
869 0 : bool FrameSelector::IsAnyBorderVisible() const
870 : {
871 0 : bool bIsSet = false;
872 0 : for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !bIsSet && aIt.Is(); ++aIt )
873 0 : bIsSet = ((*aIt)->GetState() == FRAMESTATE_SHOW);
874 0 : return bIsSet;
875 : }
876 :
877 0 : void FrameSelector::HideAllBorders()
878 : {
879 0 : for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
880 0 : mxImpl->SetBorderState( **aIt, FRAMESTATE_HIDE );
881 0 : }
882 :
883 0 : bool FrameSelector::GetVisibleWidth( long& rnWidth, SvxBorderStyle& rnStyle ) const
884 : {
885 0 : VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
886 0 : if( !aIt.Is() )
887 0 : return false;
888 :
889 0 : const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
890 0 : bool bFound = true;
891 0 : for( ++aIt; bFound && aIt.Is(); ++aIt )
892 : {
893 : bFound =
894 0 : (rStyle.GetWidth() == (*aIt)->GetCoreStyle().GetWidth()) &&
895 0 : (rStyle.GetBorderLineStyle() ==
896 0 : (*aIt)->GetCoreStyle().GetBorderLineStyle());
897 : }
898 :
899 0 : if( bFound )
900 : {
901 0 : rnWidth = rStyle.GetWidth();
902 0 : rnStyle = rStyle.GetBorderLineStyle();
903 : }
904 0 : return bFound;
905 : }
906 :
907 0 : bool FrameSelector::GetVisibleColor( Color& rColor ) const
908 : {
909 0 : VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
910 0 : if( !aIt.Is() )
911 0 : return false;
912 :
913 0 : const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
914 0 : bool bFound = true;
915 0 : for( ++aIt; bFound && aIt.Is(); ++aIt )
916 0 : bFound = (rStyle.GetColor() == (*aIt)->GetCoreStyle().GetColor());
917 :
918 0 : if( bFound )
919 0 : rColor = rStyle.GetColor();
920 0 : return bFound;
921 : }
922 :
923 : // frame border selection
924 0 : const Link<>& FrameSelector::GetSelectHdl() const
925 : {
926 0 : return mxImpl->maSelectHdl;
927 : }
928 :
929 0 : void FrameSelector::SetSelectHdl( const Link<>& rHdl )
930 : {
931 0 : mxImpl->maSelectHdl = rHdl;
932 0 : }
933 :
934 0 : bool FrameSelector::IsBorderSelected( FrameBorderType eBorder ) const
935 : {
936 0 : return mxImpl->GetBorder( eBorder ).IsSelected();
937 : }
938 :
939 0 : void FrameSelector::SelectBorder( FrameBorderType eBorder, bool bSelect /*, bool bFocus */ )
940 : {
941 0 : mxImpl->SelectBorder( mxImpl->GetBorderAccess( eBorder ), bSelect );
942 : // MT: bFireFox as API parameter is ugly...
943 : // if (bFocus)
944 : {
945 0 : Reference< XAccessible > xRet = GetChildAccessible(eBorder);
946 0 : a11y::AccFrameSelector* pFrameSelector = static_cast<a11y::AccFrameSelector*>(xRet.get());
947 0 : if (pFrameSelector)
948 : {
949 0 : Any aOldValue, aNewValue;
950 0 : aNewValue <<= AccessibleStateType::FOCUSED;
951 0 : pFrameSelector->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
952 0 : }
953 : }
954 0 : }
955 :
956 0 : bool FrameSelector::IsAnyBorderSelected() const
957 : {
958 : // Construct an iterator for selected borders. If it is valid, there is a selected border.
959 0 : return SelFrameBorderCIter( mxImpl->maEnabBorders ).Is();
960 : }
961 :
962 0 : void FrameSelector::SelectAllBorders( bool bSelect )
963 : {
964 0 : for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
965 0 : mxImpl->SelectBorder( **aIt, bSelect );
966 0 : }
967 :
968 0 : void FrameSelector::SelectAllVisibleBorders( bool bSelect )
969 : {
970 0 : for( VisFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
971 0 : mxImpl->SelectBorder( **aIt, bSelect );
972 0 : }
973 :
974 0 : void FrameSelector::SetStyleToSelection( long nWidth, SvxBorderStyle nStyle )
975 : {
976 0 : mxImpl->maCurrStyle.SetBorderLineStyle( nStyle );
977 0 : mxImpl->maCurrStyle.SetWidth( nWidth );
978 0 : for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
979 0 : mxImpl->SetBorderState( **aIt, FRAMESTATE_SHOW );
980 0 : }
981 :
982 0 : void FrameSelector::SetColorToSelection( const Color& rColor )
983 : {
984 0 : mxImpl->maCurrStyle.SetColor( rColor );
985 0 : for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
986 0 : mxImpl->SetBorderState( **aIt, FRAMESTATE_SHOW );
987 0 : }
988 :
989 : // accessibility
990 0 : Reference< XAccessible > FrameSelector::CreateAccessible()
991 : {
992 0 : if( !mxImpl->mxAccess.is() )
993 0 : mxImpl->mxAccess = mxImpl->mpAccess =
994 0 : new a11y::AccFrameSelector( *this, FRAMEBORDER_NONE );
995 0 : return mxImpl->mxAccess;
996 : }
997 :
998 0 : Reference< XAccessible > FrameSelector::GetChildAccessible( FrameBorderType eBorder )
999 : {
1000 0 : Reference< XAccessible > xRet;
1001 0 : size_t nVecIdx = static_cast< size_t >( eBorder );
1002 0 : if( IsBorderEnabled( eBorder ) && (1 <= nVecIdx) && (nVecIdx <= mxImpl->maChildVec.size()) )
1003 : {
1004 0 : --nVecIdx;
1005 0 : if( !mxImpl->maChildVec[ nVecIdx ] )
1006 0 : mxImpl->mxChildVec[ nVecIdx ] = mxImpl->maChildVec[ nVecIdx ] =
1007 0 : new a11y::AccFrameSelector( *this, eBorder );
1008 0 : xRet = mxImpl->mxChildVec[ nVecIdx ];
1009 : }
1010 0 : return xRet;
1011 : }
1012 :
1013 0 : Reference< XAccessible > FrameSelector::GetChildAccessible( sal_Int32 nIndex )
1014 : {
1015 0 : return GetChildAccessible( GetEnabledBorderType( nIndex ) );
1016 : }
1017 :
1018 0 : Reference< XAccessible > FrameSelector::GetChildAccessible( const Point& rPos )
1019 : {
1020 0 : Reference< XAccessible > xRet;
1021 0 : for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !xRet.is() && aIt.Is(); ++aIt )
1022 0 : if( (*aIt)->ContainsClickPoint( rPos ) )
1023 0 : xRet = GetChildAccessible( (*aIt)->GetType() );
1024 0 : return xRet;
1025 : }
1026 :
1027 0 : bool FrameSelector::ContainsClickPoint( const Point& rPos ) const
1028 : {
1029 0 : bool bContains = false;
1030 0 : for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !bContains && aIt.Is(); ++aIt )
1031 0 : bContains = (*aIt)->ContainsClickPoint( rPos );
1032 0 : return bContains;
1033 : }
1034 :
1035 0 : Rectangle FrameSelector::GetClickBoundRect( FrameBorderType eBorder ) const
1036 : {
1037 0 : Rectangle aRect;
1038 0 : const FrameBorder& rBorder = mxImpl->GetBorder( eBorder );
1039 0 : if( rBorder.IsEnabled() )
1040 0 : aRect = rBorder.GetClickBoundRect();
1041 0 : return aRect;
1042 : }
1043 :
1044 : // virtual functions from base class
1045 0 : void FrameSelector::Paint(vcl::RenderContext& rRenderContext, const Rectangle&)
1046 : {
1047 0 : mxImpl->CopyVirDevToControl(rRenderContext);
1048 0 : if (HasFocus())
1049 0 : mxImpl->DrawAllTrackingRects();
1050 0 : }
1051 :
1052 0 : void FrameSelector::MouseButtonDown( const MouseEvent& rMEvt )
1053 : {
1054 : /* Mouse handling:
1055 : * Click on an unselected frame border:
1056 : Set current style/color, make frame border visible, deselect all
1057 : other frame borders.
1058 : * Click on a selected frame border:
1059 : Toggle state of the frame border (visible -> don't care -> hidden),
1060 : deselect all other frame borders.
1061 : * SHIFT+Click or CTRL+Click on an unselected frame border:
1062 : Extend selection, set current style/color to all selected frame
1063 : borders independent of the state/style/color of the borders.
1064 : * SHIFT+Click or CTRL+Click on a selected frame border:
1065 : If all frame borders have same style/color, toggle state of all
1066 : borders (see above), otherwise set current style/color to all
1067 : borders.
1068 : * Click on unused area: Do not modify selection and selected frame
1069 : borders.
1070 : */
1071 :
1072 : // #107394# do not auto-select a frame border
1073 0 : mxImpl->SilentGrabFocus();
1074 :
1075 0 : if( rMEvt.IsLeft() )
1076 : {
1077 0 : Point aPos( mxImpl->GetDevPosFromMousePos( rMEvt.GetPosPixel() ) );
1078 0 : FrameBorderPtrVec aDeselectBorders;
1079 :
1080 0 : bool bAnyClicked = false; // Any frame border clicked?
1081 0 : bool bNewSelected = false; // Any unselected frame border selected?
1082 :
1083 : /* If frame borders are set to "don't care" and the control does not
1084 : support this state, hide them on first mouse click.
1085 : DR 2004-01-30: Why are the borders set to "don't care" then?!? */
1086 0 : bool bHideDontCare = !mxImpl->mbClicked && !SupportsDontCareState();
1087 :
1088 0 : for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1089 : {
1090 0 : if( (*aIt)->ContainsClickPoint( aPos ) )
1091 : {
1092 : // frame border is clicked
1093 0 : bAnyClicked = true;
1094 0 : if( !(*aIt)->IsSelected() )
1095 : {
1096 0 : bNewSelected = true;
1097 : //mxImpl->SelectBorder( **aIt, true );
1098 0 : SelectBorder((**aIt).GetType(), true);
1099 : }
1100 : }
1101 : else
1102 : {
1103 : // hide a "don't care" frame border only if it is not clicked
1104 0 : if( bHideDontCare && ((*aIt)->GetState() == FRAMESTATE_DONTCARE) )
1105 0 : mxImpl->SetBorderState( **aIt, FRAMESTATE_HIDE );
1106 :
1107 : // deselect frame borders not clicked (if SHIFT or CTRL are not pressed)
1108 0 : if( !rMEvt.IsShift() && !rMEvt.IsMod1() )
1109 0 : aDeselectBorders.push_back( *aIt );
1110 : }
1111 : }
1112 :
1113 0 : if( bAnyClicked )
1114 : {
1115 : // any valid frame border clicked? -> deselect other frame borders
1116 0 : for( FrameBorderIter aIt( aDeselectBorders ); aIt.Is(); ++aIt )
1117 0 : mxImpl->SelectBorder( **aIt, false );
1118 :
1119 0 : if( bNewSelected || !mxImpl->SelectedBordersEqual() )
1120 : {
1121 : // new frame border selected, selection extended, or selected borders different? -> show
1122 0 : for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1123 : // SetBorderState() sets current style and color to the frame border
1124 0 : mxImpl->SetBorderState( **aIt, FRAMESTATE_SHOW );
1125 : }
1126 : else
1127 : {
1128 : // all selected frame borders are equal -> toggle state
1129 0 : for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1130 0 : mxImpl->ToggleBorderState( **aIt );
1131 : }
1132 :
1133 0 : GetSelectHdl().Call( this );
1134 0 : }
1135 : }
1136 0 : }
1137 :
1138 0 : void FrameSelector::KeyInput( const KeyEvent& rKEvt )
1139 : {
1140 0 : bool bHandled = false;
1141 0 : vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1142 0 : if( !aKeyCode.GetModifier() )
1143 : {
1144 0 : sal_uInt16 nCode = aKeyCode.GetCode();
1145 0 : switch( nCode )
1146 : {
1147 : case KEY_SPACE:
1148 : {
1149 0 : for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1150 0 : mxImpl->ToggleBorderState( **aIt );
1151 0 : bHandled = true;
1152 : }
1153 0 : break;
1154 :
1155 : case KEY_UP:
1156 : case KEY_DOWN:
1157 : case KEY_LEFT:
1158 : case KEY_RIGHT:
1159 : {
1160 0 : if( !mxImpl->maEnabBorders.empty() )
1161 : {
1162 : // start from first selected frame border
1163 0 : SelFrameBorderCIter aIt( mxImpl->maEnabBorders );
1164 0 : FrameBorderType eBorder = aIt.Is() ? (*aIt)->GetType() : mxImpl->maEnabBorders.front()->GetType();
1165 :
1166 : // search for next enabled frame border
1167 0 : do
1168 : {
1169 0 : eBorder = mxImpl->GetBorder( eBorder ).GetKeyboardNeighbor( nCode );
1170 : }
1171 0 : while( (eBorder != FRAMEBORDER_NONE) && !IsBorderEnabled( eBorder ) );
1172 :
1173 : // select the frame border
1174 0 : if( eBorder != FRAMEBORDER_NONE )
1175 : {
1176 0 : DeselectAllBorders();
1177 0 : SelectBorder( eBorder );
1178 : }
1179 : }
1180 : }
1181 0 : break;
1182 : }
1183 : }
1184 0 : if( !bHandled )
1185 0 : Window::KeyInput(rKEvt);
1186 0 : }
1187 :
1188 0 : void FrameSelector::GetFocus()
1189 : {
1190 : // auto-selection of a frame border, if focus reaches control, and nothing is selected
1191 0 : if( mxImpl->mbAutoSelect && !IsAnyBorderSelected() && !mxImpl->maEnabBorders.empty() )
1192 0 : mxImpl->SelectBorder( *mxImpl->maEnabBorders.front(), true );
1193 :
1194 0 : mxImpl->DoInvalidate( false );
1195 0 : if( mxImpl->mxAccess.is() )
1196 0 : mxImpl->mpAccess->NotifyFocusListeners( true );
1197 0 : if (IsAnyBorderSelected())
1198 : {
1199 0 : FrameBorderType borderType = FRAMEBORDER_NONE;
1200 0 : if (mxImpl->maLeft.IsSelected())
1201 0 : borderType = FRAMEBORDER_LEFT;
1202 0 : else if (mxImpl->maRight.IsSelected())
1203 0 : borderType = FRAMEBORDER_RIGHT;
1204 0 : else if (mxImpl->maTop.IsSelected())
1205 0 : borderType = FRAMEBORDER_TOP;
1206 0 : else if (mxImpl->maBottom.IsSelected())
1207 0 : borderType = FRAMEBORDER_BOTTOM;
1208 0 : else if (mxImpl->maHor.IsSelected())
1209 0 : borderType = FRAMEBORDER_HOR;
1210 0 : else if (mxImpl->maVer.IsSelected())
1211 0 : borderType = FRAMEBORDER_VER;
1212 0 : else if (mxImpl->maTLBR.IsSelected())
1213 0 : borderType = FRAMEBORDER_TLBR;
1214 0 : else if (mxImpl->maBLTR.IsSelected())
1215 0 : borderType = FRAMEBORDER_BLTR;
1216 0 : SelectBorder(borderType);
1217 : }
1218 0 : for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1219 0 : mxImpl->SetBorderState( **aIt, FRAMESTATE_SHOW );
1220 0 : Control::GetFocus();
1221 0 : }
1222 :
1223 0 : void FrameSelector::LoseFocus()
1224 : {
1225 0 : mxImpl->DoInvalidate( false );
1226 0 : if( mxImpl->mxAccess.is() )
1227 0 : mxImpl->mpAccess->NotifyFocusListeners( false );
1228 0 : Control::LoseFocus();
1229 0 : }
1230 :
1231 0 : void FrameSelector::DataChanged( const DataChangedEvent& rDCEvt )
1232 : {
1233 0 : Control::DataChanged( rDCEvt );
1234 0 : if( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
1235 0 : mxImpl->InitVirtualDevice();
1236 0 : }
1237 :
1238 0 : void FrameSelector::Resize()
1239 : {
1240 0 : Control::Resize();
1241 0 : mxImpl->sizeChanged();
1242 0 : }
1243 :
1244 0 : Size FrameSelector::GetOptimalSize() const
1245 : {
1246 0 : return LogicToPixel(Size(61, 65), MAP_APPFONT);
1247 : }
1248 :
1249 :
1250 :
1251 : template< typename Cont, typename Iter, typename Pred >
1252 0 : FrameBorderIterBase< Cont, Iter, Pred >::FrameBorderIterBase( container_type& rCont ) :
1253 : maIt( rCont.begin() ),
1254 0 : maEnd( rCont.end() )
1255 : {
1256 0 : while( Is() && !maPred( *maIt ) ) ++maIt;
1257 0 : }
1258 :
1259 : template< typename Cont, typename Iter, typename Pred >
1260 0 : FrameBorderIterBase< Cont, Iter, Pred >& FrameBorderIterBase< Cont, Iter, Pred >::operator++()
1261 : {
1262 0 : do { ++maIt; } while( Is() && !maPred( *maIt ) );
1263 0 : return *this;
1264 : }
1265 :
1266 :
1267 :
1268 390 : }
1269 :
1270 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|