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