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