Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / dialog / frmsel.cxx
blobc49807a7bbbe075faa8e54d529dccf904fa8a370
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_wasm_strip.h>
22 #include <sal/config.h>
24 #include <o3tl/safeint.hxx>
25 #include <svx/frmsel.hxx>
26 #include <vcl/event.hxx>
27 #include <sal/log.hxx>
28 #include <tools/debug.hxx>
29 #include <svtools/colorcfg.hxx>
31 #include <algorithm>
32 #include <math.h>
34 #include <frmselimpl.hxx>
35 #include <AccessibleFrameSelector.hxx>
36 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
37 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
38 #include <vcl/settings.hxx>
39 #include <vcl/svapp.hxx>
40 #include <drawinglayer/processor2d/processor2dtools.hxx>
41 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
43 #include <bitmaps.hlst>
45 using namespace ::com::sun::star;
46 using namespace ::editeng;
48 namespace svx {
50 using ::com::sun::star::uno::Reference;
51 using ::com::sun::star::uno::Any;
52 using ::com::sun::star::accessibility::XAccessible;
53 using namespace ::com::sun::star::accessibility;
55 // global functions from framebordertype.hxx
57 FrameBorderType GetFrameBorderTypeFromIndex( size_t nIndex )
59 DBG_ASSERT( nIndex < o3tl::make_unsigned(FRAMEBORDERTYPE_COUNT),
60 "svx::GetFrameBorderTypeFromIndex - invalid index" );
61 return static_cast< FrameBorderType >( nIndex + 1 );
64 size_t GetIndexFromFrameBorderType( FrameBorderType eBorder )
66 DBG_ASSERT( eBorder != FrameBorderType::NONE,
67 "svx::GetIndexFromFrameBorderType - invalid frame border type" );
68 return static_cast< size_t >( eBorder ) - 1;
71 namespace
74 /** Space between outer control border and any graphical element of the control. */
75 const tools::Long FRAMESEL_GEOM_OUTER = 2;
77 /** Space between arrows and usable inner area. */
78 const tools::Long FRAMESEL_GEOM_INNER = 3;
80 /** Maximum width to draw a frame border style. */
81 const tools::Long FRAMESEL_GEOM_WIDTH = 9;
83 /** Additional margin for click area of outer lines. */
84 const tools::Long FRAMESEL_GEOM_ADD_CLICK_OUTER = 5;
86 /** Additional margin for click area of inner lines. */
87 const tools::Long FRAMESEL_GEOM_ADD_CLICK_INNER = 2;
90 /** Returns the corresponding flag for a frame border. */
91 FrameSelFlags lclGetFlagFromType( FrameBorderType eBorder )
93 switch( eBorder )
95 case FrameBorderType::Left: return FrameSelFlags::Left;
96 case FrameBorderType::Right: return FrameSelFlags::Right;
97 case FrameBorderType::Top: return FrameSelFlags::Top;
98 case FrameBorderType::Bottom: return FrameSelFlags::Bottom;
99 case FrameBorderType::Horizontal: return FrameSelFlags::InnerHorizontal;
100 case FrameBorderType::Vertical: return FrameSelFlags::InnerVertical;
101 case FrameBorderType::TLBR: return FrameSelFlags::DiagonalTLBR;
102 case FrameBorderType::BLTR: return FrameSelFlags::DiagonalBLTR;
103 case FrameBorderType::NONE : break;
105 return FrameSelFlags::NONE;
108 /** Merges the rSource polypolygon into the rDest polypolygon. */
109 void lclPolyPolyUnion( tools::PolyPolygon& rDest, const tools::PolyPolygon& rSource )
111 const tools::PolyPolygon aTmp( rDest );
112 aTmp.GetUnion( rSource, rDest );
115 } // namespace
117 FrameBorder::FrameBorder( FrameBorderType eType ) :
118 meType( eType ),
119 meState( FrameBorderState::Hide ),
120 meKeyLeft( FrameBorderType::NONE ),
121 meKeyRight( FrameBorderType::NONE ),
122 meKeyTop( FrameBorderType::NONE ),
123 meKeyBottom( FrameBorderType::NONE ),
124 mbEnabled( false ),
125 mbSelected( false )
129 void FrameBorder::Enable( FrameSelFlags nFlags )
131 mbEnabled = bool(nFlags & lclGetFlagFromType( meType ));
132 if( !mbEnabled )
133 SetState( FrameBorderState::Hide );
136 void FrameBorder::SetCoreStyle( const SvxBorderLine* pStyle )
138 if( pStyle )
139 maCoreStyle = *pStyle;
140 else
141 maCoreStyle = SvxBorderLine();
143 // from twips to points
144 maUIStyle.Set( &maCoreStyle, FrameBorder::GetDefaultPatternScale(), FRAMESEL_GEOM_WIDTH );
145 meState = maUIStyle.IsUsed() ? FrameBorderState::Show : FrameBorderState::Hide;
148 void FrameBorder::SetState( FrameBorderState eState )
150 meState = eState;
151 switch( meState )
153 case FrameBorderState::Show:
154 SAL_WARN( "svx.dialog", "svx::FrameBorder::SetState - use SetCoreStyle to make border visible" );
155 break;
156 case FrameBorderState::Hide:
157 maCoreStyle = SvxBorderLine();
158 maUIStyle.Clear();
159 break;
160 case FrameBorderState::DontCare:
161 maCoreStyle = SvxBorderLine();
162 maUIStyle = frame::Style(3, 0, 0, SvxBorderLineStyle::SOLID, FrameBorder::GetDefaultPatternScale()); //OBJ_FRAMESTYLE_DONTCARE
163 break;
167 void FrameBorder::AddFocusPolygon( const tools::Polygon& rFocus )
169 lclPolyPolyUnion( maFocusArea, rFocus );
172 void FrameBorder::MergeFocusToPolyPolygon( tools::PolyPolygon& rPPoly ) const
174 lclPolyPolyUnion( rPPoly, maFocusArea );
177 void FrameBorder::AddClickRect( const tools::Rectangle& rRect )
179 lclPolyPolyUnion( maClickArea, tools::Polygon( rRect ) );
182 bool FrameBorder::ContainsClickPoint( const Point& rPos ) const
184 return vcl::Region( maClickArea ).Contains( rPos );
187 tools::Rectangle FrameBorder::GetClickBoundRect() const
189 return maClickArea.GetBoundRect();
192 void FrameBorder::SetKeyboardNeighbors(
193 FrameBorderType eLeft, FrameBorderType eRight, FrameBorderType eTop, FrameBorderType eBottom )
195 meKeyLeft = eLeft;
196 meKeyRight = eRight;
197 meKeyTop = eTop;
198 meKeyBottom = eBottom;
201 FrameBorderType FrameBorder::GetKeyboardNeighbor( sal_uInt16 nKeyCode ) const
203 FrameBorderType eBorder = FrameBorderType::NONE;
204 switch( nKeyCode )
206 case KEY_LEFT: eBorder = meKeyLeft; break;
207 case KEY_RIGHT: eBorder = meKeyRight; break;
208 case KEY_UP: eBorder = meKeyTop; break;
209 case KEY_DOWN: eBorder = meKeyBottom; break;
210 default: SAL_WARN( "svx.dialog", "svx::FrameBorder::GetKeyboardNeighbor - unknown key code" );
212 return eBorder;
215 FrameSelectorImpl::FrameSelectorImpl( FrameSelector& rFrameSel ) :
216 mrFrameSel( rFrameSel ),
217 mpVirDev( VclPtr<VirtualDevice>::Create() ),
218 maLeft( FrameBorderType::Left ),
219 maRight( FrameBorderType::Right ),
220 maTop( FrameBorderType::Top ),
221 maBottom( FrameBorderType::Bottom ),
222 maHor( FrameBorderType::Horizontal ),
223 maVer( FrameBorderType::Vertical ),
224 maTLBR( FrameBorderType::TLBR ),
225 maBLTR( FrameBorderType::BLTR ),
226 mnFlags( FrameSelFlags::Outer ),
227 mnCtrlSize( 0 ),
228 mnArrowSize( 0 ),
229 mnLine1( 0 ),
230 mnLine2( 0 ),
231 mnLine3( 0 ),
232 mnFocusOffs( 0 ),
233 mbHor( false ),
234 mbVer( false ),
235 mbTLBR( false ),
236 mbBLTR( false ),
237 mbFullRepaint( true ),
238 mbAutoSelect( true ),
239 mbHCMode( false )
240 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
241 ,maChildVec( 8 )
242 #endif
244 maAllBorders.resize( FRAMEBORDERTYPE_COUNT, nullptr );
245 maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Left ) ] = &maLeft;
246 maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Right ) ] = &maRight;
247 maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Top ) ] = &maTop;
248 maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Bottom ) ] = &maBottom;
249 maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Horizontal ) ] = &maHor;
250 maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::Vertical ) ] = &maVer;
251 maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::TLBR ) ] = &maTLBR;
252 maAllBorders[ GetIndexFromFrameBorderType( FrameBorderType::BLTR ) ] = &maBLTR;
253 #if OSL_DEBUG_LEVEL >= 2
255 bool bOk = true;
256 for( FrameBorderCIter aIt( maAllBorders ); bOk && aIt.Is(); bOk = (*aIt != 0), ++aIt );
257 DBG_ASSERT( bOk, "svx::FrameSelectorImpl::FrameSelectorImpl - missing entry in maAllBorders" );
259 #endif
260 // left neighbor right neighbor upper neighbor lower neighbor
261 maLeft.SetKeyboardNeighbors( FrameBorderType::NONE, FrameBorderType::TLBR, FrameBorderType::Top, FrameBorderType::Bottom );
262 maRight.SetKeyboardNeighbors( FrameBorderType::BLTR, FrameBorderType::NONE, FrameBorderType::Top, FrameBorderType::Bottom );
263 maTop.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Right, FrameBorderType::NONE, FrameBorderType::TLBR );
264 maBottom.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Right, FrameBorderType::BLTR, FrameBorderType::NONE );
265 maHor.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Right, FrameBorderType::TLBR, FrameBorderType::BLTR );
266 maVer.SetKeyboardNeighbors( FrameBorderType::TLBR, FrameBorderType::BLTR, FrameBorderType::Top, FrameBorderType::Bottom );
267 maTLBR.SetKeyboardNeighbors( FrameBorderType::Left, FrameBorderType::Vertical, FrameBorderType::Top, FrameBorderType::Horizontal );
268 maBLTR.SetKeyboardNeighbors( FrameBorderType::Vertical, FrameBorderType::Right, FrameBorderType::Horizontal, FrameBorderType::Bottom );
270 Initialize(mnFlags);
273 FrameSelectorImpl::~FrameSelectorImpl()
275 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
276 for( auto& rpChild : maChildVec )
277 if( rpChild.is() )
279 rpChild->Invalidate();
280 rpChild->dispose();
282 #endif
285 // initialization
286 void FrameSelectorImpl::Initialize( FrameSelFlags nFlags )
288 mnFlags = nFlags;
290 maEnabBorders.clear();
291 for( FrameBorderIter aIt( maAllBorders ); aIt.Is(); ++aIt )
293 (*aIt)->Enable( mnFlags );
294 if( (*aIt)->IsEnabled() )
295 maEnabBorders.push_back( *aIt );
297 mbHor = maHor.IsEnabled();
298 mbVer = maVer.IsEnabled();
299 mbTLBR = maTLBR.IsEnabled();
300 mbBLTR = maBLTR.IsEnabled();
302 InitVirtualDevice();
305 void FrameSelectorImpl::InitColors()
307 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
308 svtools::ColorConfig aColorConfig;
309 maBackCol = aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
310 mbHCMode = rSettings.GetHighContrastMode();
311 maArrowCol = aColorConfig.GetColorValue(svtools::DOCBOUNDARIES).nColor;
312 maMarkCol = aColorConfig.GetColorValue(svtools::TABLEBOUNDARIES).nColor;
313 maHCLineCol = COL_BLACK;
316 constexpr rtl::OUStringConstExpr aImageIds[] =
318 RID_SVXBMP_FRMSEL_ARROW1,
319 RID_SVXBMP_FRMSEL_ARROW2,
320 RID_SVXBMP_FRMSEL_ARROW3,
321 RID_SVXBMP_FRMSEL_ARROW4,
322 RID_SVXBMP_FRMSEL_ARROW5,
323 RID_SVXBMP_FRMSEL_ARROW6,
324 RID_SVXBMP_FRMSEL_ARROW7,
325 RID_SVXBMP_FRMSEL_ARROW8,
326 RID_SVXBMP_FRMSEL_ARROW9,
327 RID_SVXBMP_FRMSEL_ARROW10,
328 RID_SVXBMP_FRMSEL_ARROW11,
329 RID_SVXBMP_FRMSEL_ARROW12,
330 RID_SVXBMP_FRMSEL_ARROW13,
331 RID_SVXBMP_FRMSEL_ARROW14,
332 RID_SVXBMP_FRMSEL_ARROW15,
333 RID_SVXBMP_FRMSEL_ARROW16
336 void FrameSelectorImpl::InitArrowImageList()
338 maArrows.clear();
340 /* Build the arrow images bitmap with current colors. */
341 Color pColorAry1[3];
342 Color pColorAry2[3];
343 pColorAry1[0] = Color( 0, 0, 0 );
344 pColorAry2[0] = maArrowCol; // black -> arrow color
345 pColorAry1[1] = Color( 0, 255, 0 );
346 pColorAry2[1] = maMarkCol; // green -> marker color
347 pColorAry1[2] = Color( 255, 0, 255 );
348 pColorAry2[2] = maBackCol; // magenta -> background
350 assert(SAL_N_ELEMENTS(aImageIds) == 16);
351 for (size_t i = 0; i < SAL_N_ELEMENTS(aImageIds); ++i)
353 BitmapEx aBmpEx { OUString(aImageIds[i]) };
354 aBmpEx.Replace(pColorAry1, pColorAry2, 3);
355 maArrows.emplace_back(aBmpEx);
357 assert(maArrows.size() == 16);
359 mnArrowSize = maArrows[0].GetSizePixel().Height();
362 void FrameSelectorImpl::InitGlobalGeometry()
364 Size aCtrlSize(mrFrameSel.GetOutputSizePixel());
365 /* nMinSize is the lower of width and height (control will always be squarish).
366 FRAMESEL_GEOM_OUTER is the minimal distance between inner control border
367 and any element. */
368 tools::Long nMinSize = std::min( aCtrlSize.Width(), aCtrlSize.Height() ) - 2 * FRAMESEL_GEOM_OUTER;
369 /* nFixedSize is the size all existing elements need in one direction:
370 the diag. arrow, space betw. arrow and frame border, outer frame border,
371 inner frame border, other outer frame border, space betw. frame border
372 and arrow, the other arrow. */
373 tools::Long nFixedSize = 2 * mnArrowSize + 2 * FRAMESEL_GEOM_INNER + 3 * FRAMESEL_GEOM_WIDTH;
374 /* nBetwBordersSize contains the size between an outer and inner frame border (made odd). */
375 tools::Long nBetwBordersSize = (((nMinSize - nFixedSize) / 2) - 1) | 1;
377 /* The final size of the usable area. At least do not get negative */
378 mnCtrlSize = 2 * nBetwBordersSize + nFixedSize;
379 mnCtrlSize = std::max(mnCtrlSize, static_cast<tools::Long>(0));
380 mpVirDev->SetOutputSizePixel( Size( mnCtrlSize, mnCtrlSize ) );
382 /* Center the virtual device in the control. */
383 maVirDevPos = Point( (aCtrlSize.Width() - mnCtrlSize) / 2, (aCtrlSize.Height() - mnCtrlSize) / 2 );
386 void FrameSelectorImpl::InitBorderGeometry()
388 size_t nCol, nCols, nRow, nRows;
390 // Global border geometry values
391 /* mnLine* is the middle point inside a frame border (i.e. mnLine1 is mid X inside left border). */
392 mnLine1 = mnArrowSize + FRAMESEL_GEOM_INNER + FRAMESEL_GEOM_WIDTH / 2;
393 mnLine2 = mnCtrlSize / 2;
394 mnLine3 = 2 * mnLine2 - mnLine1;
396 // Frame helper array
397 maArray.Initialize( mbVer ? 2 : 1, mbHor ? 2 : 1 );
399 maArray.SetXOffset( mnLine1 );
400 maArray.SetAllColWidths( (mbVer ? mnLine2 : mnLine3) - mnLine1 );
402 maArray.SetYOffset( mnLine1 );
403 maArray.SetAllRowHeights( (mbHor ? mnLine2 : mnLine3) - mnLine1 );
405 // Focus polygons
406 /* Width for focus rectangles from center of frame borders. */
407 mnFocusOffs = FRAMESEL_GEOM_WIDTH / 2 + 1;
409 maLeft.ClearFocusArea();
410 maVer.ClearFocusArea();
411 maRight.ClearFocusArea();
412 maTop.ClearFocusArea();
413 maHor.ClearFocusArea();
414 maBottom.ClearFocusArea();
416 maLeft.AddFocusPolygon( tools::Rectangle( mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine1 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
417 maVer.AddFocusPolygon( tools::Rectangle( mnLine2 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine2 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
418 maRight.AddFocusPolygon( tools::Rectangle( mnLine3 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
419 maTop.AddFocusPolygon( tools::Rectangle( mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine1 + mnFocusOffs ) );
420 maHor.AddFocusPolygon( tools::Rectangle( mnLine1 - mnFocusOffs, mnLine2 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine2 + mnFocusOffs ) );
421 maBottom.AddFocusPolygon( tools::Rectangle( mnLine1 - mnFocusOffs, mnLine3 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
423 maTLBR.ClearFocusArea();
424 maBLTR.ClearFocusArea();
426 for( nCol = 0, nCols = maArray.GetColCount(); nCol < nCols; ++nCol )
428 for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow )
430 const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow ));
431 const tools::Rectangle aRect(
432 basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()),
433 basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY()));
434 const double fHorDiagAngle(atan2(fabs(aCellRange.getHeight()), fabs(aCellRange.getWidth())));
435 const double fVerDiagAngle(fHorDiagAngle > 0.0 ? M_PI_2 - fHorDiagAngle : 0.0);
436 const tools::Long nDiagFocusOffsX(basegfx::fround(-mnFocusOffs / tan(fHorDiagAngle) + mnFocusOffs / sin(fHorDiagAngle)));
437 const tools::Long nDiagFocusOffsY(basegfx::fround(-mnFocusOffs / tan(fVerDiagAngle) + mnFocusOffs / sin(fVerDiagAngle)));
439 std::vector< Point > aFocusVec;
440 aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Top() + nDiagFocusOffsY );
441 aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Top() - mnFocusOffs );
442 aFocusVec.emplace_back( aRect.Left() + nDiagFocusOffsX, aRect.Top() - mnFocusOffs );
443 aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Bottom() - nDiagFocusOffsY );
444 aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Bottom() + mnFocusOffs );
445 aFocusVec.emplace_back( aRect.Right() - nDiagFocusOffsX, aRect.Bottom() + mnFocusOffs );
446 maTLBR.AddFocusPolygon( tools::Polygon( static_cast< sal_uInt16 >( aFocusVec.size() ), aFocusVec.data() ) );
448 aFocusVec.clear();
449 aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Top() + nDiagFocusOffsY );
450 aFocusVec.emplace_back( aRect.Right() + mnFocusOffs, aRect.Top() - mnFocusOffs );
451 aFocusVec.emplace_back( aRect.Right() - nDiagFocusOffsX, aRect.Top() - mnFocusOffs );
452 aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Bottom() - nDiagFocusOffsY );
453 aFocusVec.emplace_back( aRect.Left() - mnFocusOffs, aRect.Bottom() + mnFocusOffs );
454 aFocusVec.emplace_back( aRect.Left() + nDiagFocusOffsX, aRect.Bottom() + mnFocusOffs );
455 maBLTR.AddFocusPolygon( tools::Polygon( static_cast< sal_uInt16 >( aFocusVec.size() ), aFocusVec.data() ) );
459 // Click areas
460 for( FrameBorderIter aIt( maAllBorders ); aIt.Is(); ++aIt )
461 (*aIt)->ClearClickArea();
463 /* Additional space for click area: is added to the space available to draw
464 the frame borders. For instance left frame border:
465 - To left, top, and bottom always big additional space (outer area).
466 - To right: Dependent on existence of inner vertical frame border
467 (if enabled, use less space).
469 tools::Long nClO = FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_OUTER;
470 tools::Long nClI = (mbTLBR && mbBLTR) ? (FRAMESEL_GEOM_WIDTH / 2 + FRAMESEL_GEOM_ADD_CLICK_INNER) : nClO;
471 tools::Long nClH = mbHor ? nClI : nClO; // additional space dependent of horizontal inner border
472 tools::Long nClV = mbVer ? nClI : nClO; // additional space dependent of vertical inner border
474 maLeft.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine1 - nClO, mnLine1 + nClV, mnLine3 + nClO ) );
475 maVer.AddClickRect( tools::Rectangle( mnLine2 - nClI, mnLine1 - nClO, mnLine2 + nClI, mnLine3 + nClO ) );
476 maRight.AddClickRect( tools::Rectangle( mnLine3 - nClV, mnLine1 - nClO, mnLine3 + nClO, mnLine3 + nClO ) );
477 maTop.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine1 - nClO, mnLine3 + nClO, mnLine1 + nClH ) );
478 maHor.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine2 - nClI, mnLine3 + nClO, mnLine2 + nClI ) );
479 maBottom.AddClickRect( tools::Rectangle( mnLine1 - nClO, mnLine3 - nClH, mnLine3 + nClO, mnLine3 + nClO ) );
481 /* Diagonal frame borders use the remaining space between outer and inner frame borders. */
482 if( !(mbTLBR || mbBLTR) )
483 return;
485 for( nCol = 0, nCols = maArray.GetColCount(); nCol < nCols; ++nCol )
487 for( nRow = 0, nRows = maArray.GetRowCount(); nRow < nRows; ++nRow )
489 // the usable area between horizontal/vertical frame borders of current quadrant
490 const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow ));
491 const tools::Rectangle aRect(
492 basegfx::fround(aCellRange.getMinX()) + nClV + 1, basegfx::fround(aCellRange.getMinY()) + nClH + 1,
493 basegfx::fround(aCellRange.getMaxX()) - nClV + 1, basegfx::fround(aCellRange.getMaxY()) - nClH + 1);
495 /* Both diagonal frame borders enabled. */
496 if( mbTLBR && mbBLTR )
498 // single areas
499 Point aMid( aRect.Center() );
500 maTLBR.AddClickRect( tools::Rectangle( aRect.TopLeft(), aMid ) );
501 maTLBR.AddClickRect( tools::Rectangle( aMid + Point( 1, 1 ), aRect.BottomRight() ) );
502 maBLTR.AddClickRect( tools::Rectangle( aRect.Left(), aMid.Y() + 1, aMid.X(), aRect.Bottom() ) );
503 maBLTR.AddClickRect( tools::Rectangle( aMid.X() + 1, aRect.Top(), aRect.Right(), aMid.Y() ) );
504 // centered rectangle for both frame borders
505 tools::Rectangle aMidRect( aRect.TopLeft(), Size( aRect.GetWidth() / 3, aRect.GetHeight() / 3 ) );
506 aMidRect.Move( (aRect.GetWidth() - aMidRect.GetWidth()) / 2, (aRect.GetHeight() - aMidRect.GetHeight()) / 2 );
507 maTLBR.AddClickRect( aMidRect );
508 maBLTR.AddClickRect( aMidRect );
510 /* One of the diagonal frame borders enabled - use entire rectangle. */
511 else if( mbTLBR && !mbBLTR ) // top-left to bottom-right only
512 maTLBR.AddClickRect( aRect );
513 else if( !mbTLBR && mbBLTR ) // bottom-left to top-right only
514 maBLTR.AddClickRect( aRect );
519 void FrameSelectorImpl::InitVirtualDevice()
521 // initialize resources
522 InitColors();
523 InitArrowImageList();
525 sizeChanged();
528 void FrameSelectorImpl::sizeChanged()
530 // initialize geometry
531 InitGlobalGeometry();
532 InitBorderGeometry();
534 DoInvalidate( true );
537 // frame border access
538 const FrameBorder& FrameSelectorImpl::GetBorder( FrameBorderType eBorder ) const
540 size_t nIndex = GetIndexFromFrameBorderType( eBorder );
541 if( nIndex < maAllBorders.size() )
542 return *maAllBorders[ nIndex ];
543 SAL_WARN( "svx.dialog", "svx::FrameSelectorImpl::GetBorder - unknown border type" );
544 return maTop;
547 FrameBorder& FrameSelectorImpl::GetBorderAccess( FrameBorderType eBorder )
549 return const_cast< FrameBorder& >( GetBorder( eBorder ) );
552 // drawing
553 void FrameSelectorImpl::DrawBackground()
555 // clear the area
556 mpVirDev->SetLineColor();
557 mpVirDev->SetFillColor( maBackCol );
558 mpVirDev->DrawRect( tools::Rectangle( Point( 0, 0 ), mpVirDev->GetOutputSizePixel() ) );
560 // draw the inner gray (or whatever color) rectangle
561 mpVirDev->SetLineColor();
562 mpVirDev->SetFillColor( maMarkCol );
563 mpVirDev->DrawRect( tools::Rectangle(
564 mnLine1 - mnFocusOffs, mnLine1 - mnFocusOffs, mnLine3 + mnFocusOffs, mnLine3 + mnFocusOffs ) );
566 // draw the white space for enabled frame borders
567 tools::PolyPolygon aPPoly;
568 for( FrameBorderCIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
569 (*aIt)->MergeFocusToPolyPolygon( aPPoly );
570 aPPoly.Optimize( PolyOptimizeFlags::CLOSE );
571 mpVirDev->SetLineColor( maBackCol );
572 mpVirDev->SetFillColor( maBackCol );
573 mpVirDev->DrawPolyPolygon( aPPoly );
576 void FrameSelectorImpl::DrawArrows( const FrameBorder& rBorder )
578 DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::DrawArrows - access to disabled border" );
580 tools::Long nLinePos = 0;
581 switch( rBorder.GetType() )
583 case FrameBorderType::Left:
584 case FrameBorderType::Top: nLinePos = mnLine1; break;
585 case FrameBorderType::Vertical:
586 case FrameBorderType::Horizontal: nLinePos = mnLine2; break;
587 case FrameBorderType::Right:
588 case FrameBorderType::Bottom: nLinePos = mnLine3; break;
589 default: ; //prevent warning
591 nLinePos -= mnArrowSize / 2;
593 tools::Long nTLPos = 0;
594 tools::Long nBRPos = mnCtrlSize - mnArrowSize;
595 Point aPos1, aPos2;
596 int nImgIndex1 = -1, nImgIndex2 = -1;
597 switch( rBorder.GetType() )
599 case FrameBorderType::Left:
600 case FrameBorderType::Right:
601 case FrameBorderType::Vertical:
602 aPos1 = Point( nLinePos, nTLPos ); nImgIndex1 = 0;
603 aPos2 = Point( nLinePos, nBRPos ); nImgIndex2 = 1;
604 break;
606 case FrameBorderType::Top:
607 case FrameBorderType::Bottom:
608 case FrameBorderType::Horizontal:
609 aPos1 = Point( nTLPos, nLinePos ); nImgIndex1 = 2;
610 aPos2 = Point( nBRPos, nLinePos ); nImgIndex2 = 3;
611 break;
613 case FrameBorderType::TLBR:
614 aPos1 = Point( nTLPos, nTLPos ); nImgIndex1 = 4;
615 aPos2 = Point( nBRPos, nBRPos ); nImgIndex2 = 5;
616 break;
617 case FrameBorderType::BLTR:
618 aPos1 = Point( nTLPos, nBRPos ); nImgIndex1 = 6;
619 aPos2 = Point( nBRPos, nTLPos ); nImgIndex2 = 7;
620 break;
621 default: ; //prevent warning
624 // Arrow or marker? Do not draw arrows into disabled control.
625 sal_uInt16 nSelectAdd = (mrFrameSel.IsEnabled() && rBorder.IsSelected()) ? 0 : 8;
626 if (nImgIndex1 >= 0)
627 mpVirDev->DrawImage(aPos1, maArrows[nImgIndex1 + nSelectAdd]);
628 if (nImgIndex2 >= 0)
629 mpVirDev->DrawImage(aPos2, maArrows[nImgIndex2 + nSelectAdd]);
632 Color FrameSelectorImpl::GetDrawLineColor( const Color& rColor ) const
634 Color aColor( mbHCMode ? maHCLineCol : rColor );
635 if( aColor == maBackCol )
636 aColor.Invert();
637 return aColor;
640 void FrameSelectorImpl::DrawAllFrameBorders()
642 // Translate core colors to current UI colors (regards current background and HC mode).
643 for( FrameBorderIter aIt( maEnabBorders ); aIt.Is(); ++aIt )
645 Color aCoreColorPrim = ((*aIt)->GetState() == FrameBorderState::DontCare) ? maMarkCol : (*aIt)->GetCoreStyle().GetColorOut();
646 Color aCoreColorSecn = ((*aIt)->GetState() == FrameBorderState::DontCare) ? maMarkCol : (*aIt)->GetCoreStyle().GetColorIn();
647 (*aIt)->SetUIColorPrim( GetDrawLineColor( aCoreColorPrim ) );
648 (*aIt)->SetUIColorSecn( GetDrawLineColor( aCoreColorSecn ) );
651 // Copy all frame border styles to the helper array
652 maArray.SetColumnStyleLeft( 0, maLeft.GetUIStyle() );
653 if( mbVer ) maArray.SetColumnStyleLeft( 1, maVer.GetUIStyle() );
655 // Invert the style for the right line
656 const frame::Style rRightStyle = maRight.GetUIStyle( );
657 frame::Style rInvertedRight( rRightStyle.GetColorPrim(),
658 rRightStyle.GetColorSecn(), rRightStyle.GetColorGap(),
659 rRightStyle.UseGapColor(),
660 rRightStyle.Secn(), rRightStyle.Dist(), rRightStyle.Prim( ),
661 rRightStyle.Type( ), rRightStyle.PatternScale() );
662 maArray.SetColumnStyleRight( mbVer ? 1 : 0, rInvertedRight );
664 maArray.SetRowStyleTop( 0, maTop.GetUIStyle() );
665 if( mbHor )
667 // Invert the style for the hor line to match the real borders
668 const frame::Style rHorStyle = maHor.GetUIStyle();
669 frame::Style rInvertedHor( rHorStyle.GetColorPrim(),
670 rHorStyle.GetColorSecn(), rHorStyle.GetColorGap(),
671 rHorStyle.UseGapColor(),
672 rHorStyle.Secn(), rHorStyle.Dist(), rHorStyle.Prim( ),
673 rHorStyle.Type(), rHorStyle.PatternScale() );
674 maArray.SetRowStyleTop( 1, rInvertedHor );
677 // Invert the style for the bottom line
678 const frame::Style rBottomStyle = maBottom.GetUIStyle( );
679 frame::Style rInvertedBottom( rBottomStyle.GetColorPrim(),
680 rBottomStyle.GetColorSecn(), rBottomStyle.GetColorGap(),
681 rBottomStyle.UseGapColor(),
682 rBottomStyle.Secn(), rBottomStyle.Dist(), rBottomStyle.Prim( ),
683 rBottomStyle.Type(), rBottomStyle.PatternScale() );
684 maArray.SetRowStyleBottom( mbHor ? 1 : 0, rInvertedBottom );
686 for( sal_Int32 nCol = 0; nCol < maArray.GetColCount(); ++nCol )
687 for( sal_Int32 nRow = 0; nRow < maArray.GetRowCount(); ++nRow )
688 maArray.SetCellStyleDiag( nCol, nRow, maTLBR.GetUIStyle(), maBLTR.GetUIStyle() );
690 // This is used in the dialog/control for 'Border' attributes. When using
691 // the original paint below instead of primitives, the advantage currently
692 // is the correct visualization of diagonal line(s) including overlaying,
693 // but the rest is bad. Since the edit views use primitives and the preview
694 // should be 'real' I opt for also changing this to primitives. I will
695 // keep the old solution and add a switch (above) based on a static bool so
696 // that interested people may test this out in the debugger.
697 // This is one more hint to enhance the primitive visualization further to
698 // support diagonals better - that's the way to go.
699 const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
700 std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
701 drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
702 *mpVirDev,
703 aNewViewInformation2D));
705 pProcessor2D->process(maArray.CreateB2DPrimitiveArray());
706 pProcessor2D.reset();
709 void FrameSelectorImpl::DrawVirtualDevice()
711 DrawBackground();
712 for(FrameBorderCIter aIt(maEnabBorders); aIt.Is(); ++aIt)
713 DrawArrows(**aIt);
714 DrawAllFrameBorders();
715 mbFullRepaint = false;
718 void FrameSelectorImpl::CopyVirDevToControl(vcl::RenderContext& rRenderContext)
720 if (mbFullRepaint)
721 DrawVirtualDevice();
722 rRenderContext.DrawBitmapEx(maVirDevPos, mpVirDev->GetBitmapEx(Point(0, 0), mpVirDev->GetOutputSizePixel()));
725 void FrameSelectorImpl::DrawAllTrackingRects(vcl::RenderContext& rRenderContext)
727 tools::PolyPolygon aPPoly;
728 if (mrFrameSel.IsAnyBorderSelected())
730 for(SelFrameBorderCIter aIt( maEnabBorders ); aIt.Is(); ++aIt)
731 (*aIt)->MergeFocusToPolyPolygon(aPPoly);
732 aPPoly.Move(maVirDevPos.X(), maVirDevPos.Y());
734 else
735 // no frame border selected -> draw tracking rectangle around entire control
736 aPPoly.Insert( tools::Polygon(tools::Rectangle(maVirDevPos, mpVirDev->GetOutputSizePixel())));
738 aPPoly.Optimize(PolyOptimizeFlags::CLOSE);
740 for(sal_uInt16 nIdx = 0, nCount = aPPoly.Count(); nIdx < nCount; ++nIdx)
741 rRenderContext.Invert(aPPoly.GetObject(nIdx), InvertFlags::TrackFrame);
744 Point FrameSelectorImpl::GetDevPosFromMousePos( const Point& rMousePos ) const
746 return rMousePos - maVirDevPos;
749 void FrameSelectorImpl::DoInvalidate( bool bFullRepaint )
751 mbFullRepaint |= bFullRepaint;
752 mrFrameSel.Invalidate();
755 // frame border state and style
756 void FrameSelectorImpl::SetBorderState( FrameBorder& rBorder, FrameBorderState eState )
758 DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SetBorderState - access to disabled border" );
759 Any aOld;
760 Any aNew;
761 Any& rMod = eState == FrameBorderState::Show ? aNew : aOld;
762 rMod <<= AccessibleStateType::CHECKED;
764 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
765 rtl::Reference< a11y::AccFrameSelectorChild > xRet;
766 size_t nVecIdx = static_cast< size_t >( rBorder.GetType() );
767 if( GetBorder(rBorder.GetType()).IsEnabled() && (1 <= nVecIdx) && (nVecIdx <= maChildVec.size()) )
768 xRet = maChildVec[ --nVecIdx ].get();
769 #endif
771 if( eState == FrameBorderState::Show )
772 SetBorderCoreStyle( rBorder, &maCurrStyle );
773 else
774 rBorder.SetState( eState );
776 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
777 if (xRet.is())
778 xRet->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOld, aNew );
779 #endif
781 DoInvalidate( true );
784 void FrameSelectorImpl::SetBorderCoreStyle( FrameBorder& rBorder, const SvxBorderLine* pStyle )
786 DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SetBorderCoreStyle - access to disabled border" );
787 rBorder.SetCoreStyle( pStyle );
788 DoInvalidate( true );
791 void FrameSelectorImpl::ToggleBorderState( FrameBorder& rBorder )
793 bool bDontCare = mrFrameSel.SupportsDontCareState();
794 switch( rBorder.GetState() )
796 // same order as tristate check box: visible -> don't care -> hidden
797 case FrameBorderState::Show:
798 SetBorderState( rBorder, bDontCare ? FrameBorderState::DontCare : FrameBorderState::Hide );
799 break;
800 case FrameBorderState::Hide:
801 SetBorderState( rBorder, FrameBorderState::Show );
802 break;
803 case FrameBorderState::DontCare:
804 SetBorderState( rBorder, FrameBorderState::Hide );
805 break;
809 // frame border selection
810 void FrameSelectorImpl::SelectBorder( FrameBorder& rBorder, bool bSelect )
812 DBG_ASSERT( rBorder.IsEnabled(), "svx::FrameSelectorImpl::SelectBorder - access to disabled border" );
813 rBorder.Select( bSelect );
814 DrawArrows( rBorder );
815 DoInvalidate( false );
818 void FrameSelectorImpl::SilentGrabFocus()
820 bool bOldAuto = mbAutoSelect;
821 mbAutoSelect = false;
822 mrFrameSel.GrabFocus();
823 mbAutoSelect = bOldAuto;
826 bool FrameSelectorImpl::SelectedBordersEqual() const
828 bool bEqual = true;
829 SelFrameBorderCIter aIt( maEnabBorders );
830 if( aIt.Is() )
832 const SvxBorderLine& rFirstStyle = (*aIt)->GetCoreStyle();
833 for( ++aIt; bEqual && aIt.Is(); ++aIt )
834 bEqual = ((*aIt)->GetCoreStyle() == rFirstStyle);
836 return bEqual;
839 FrameSelector::FrameSelector()
843 void FrameSelector::SetDrawingArea(weld::DrawingArea* pDrawingArea)
845 CustomWidgetController::SetDrawingArea(pDrawingArea);
846 mxImpl.reset( new FrameSelectorImpl( *this ) );
847 Size aPrefSize = pDrawingArea->get_ref_device().LogicToPixel(Size(61, 65), MapMode(MapUnit::MapAppFont));
848 pDrawingArea->set_size_request(aPrefSize.Width(), aPrefSize.Height());
849 EnableRTL( false ); // #107808# don't mirror the mouse handling
852 FrameSelector::~FrameSelector()
854 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
855 if( mxAccess.is() )
856 mxAccess->Invalidate();
857 #endif
860 void FrameSelector::Initialize( FrameSelFlags nFlags )
862 mxImpl->Initialize( nFlags );
863 Show();
866 // enabled frame borders
867 bool FrameSelector::IsBorderEnabled( FrameBorderType eBorder ) const
869 return mxImpl->GetBorder( eBorder ).IsEnabled();
872 sal_Int32 FrameSelector::GetEnabledBorderCount() const
874 return static_cast< sal_Int32 >( mxImpl->maEnabBorders.size() );
877 FrameBorderType FrameSelector::GetEnabledBorderType( sal_Int32 nIndex ) const
879 FrameBorderType eBorder = FrameBorderType::NONE;
880 if( nIndex >= 0 )
882 size_t nVecIdx = static_cast< size_t >( nIndex );
883 if( nVecIdx < mxImpl->maEnabBorders.size() )
884 eBorder = mxImpl->maEnabBorders[ nVecIdx ]->GetType();
886 return eBorder;
889 // frame border state and style
890 bool FrameSelector::SupportsDontCareState() const
892 return bool(mxImpl->mnFlags & FrameSelFlags::DontCare);
895 FrameBorderState FrameSelector::GetFrameBorderState( FrameBorderType eBorder ) const
897 return mxImpl->GetBorder( eBorder ).GetState();
900 const SvxBorderLine* FrameSelector::GetFrameBorderStyle( FrameBorderType eBorder ) const
902 const SvxBorderLine& rStyle = mxImpl->GetBorder( eBorder ).GetCoreStyle();
903 // rest of the world uses null pointer for invisible frame border
904 return rStyle.GetOutWidth() ? &rStyle : nullptr;
907 void FrameSelector::ShowBorder( FrameBorderType eBorder, const SvxBorderLine* pStyle )
909 mxImpl->SetBorderCoreStyle( mxImpl->GetBorderAccess( eBorder ), pStyle );
912 void FrameSelector::SetBorderDontCare( FrameBorderType eBorder )
914 mxImpl->SetBorderState( mxImpl->GetBorderAccess( eBorder ), FrameBorderState::DontCare );
917 bool FrameSelector::IsAnyBorderVisible() const
919 bool bIsSet = false;
920 for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !bIsSet && aIt.Is(); ++aIt )
921 bIsSet = ((*aIt)->GetState() == FrameBorderState::Show);
922 return bIsSet;
925 void FrameSelector::HideAllBorders()
927 for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
928 mxImpl->SetBorderState( **aIt, FrameBorderState::Hide );
931 bool FrameSelector::GetVisibleWidth( tools::Long& rnWidth, SvxBorderLineStyle& rnStyle ) const
933 VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
934 if( !aIt.Is() )
935 return false;
937 const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
938 bool bFound = true;
939 for( ++aIt; bFound && aIt.Is(); ++aIt )
941 bFound =
942 (rStyle.GetWidth() == (*aIt)->GetCoreStyle().GetWidth()) &&
943 (rStyle.GetBorderLineStyle() ==
944 (*aIt)->GetCoreStyle().GetBorderLineStyle());
947 if( bFound )
949 rnWidth = rStyle.GetWidth();
950 rnStyle = rStyle.GetBorderLineStyle();
952 return bFound;
955 bool FrameSelector::GetVisibleColor( Color& rColor ) const
957 VisFrameBorderCIter aIt( mxImpl->maEnabBorders );
958 if( !aIt.Is() )
959 return false;
961 const SvxBorderLine& rStyle = (*aIt)->GetCoreStyle();
962 bool bFound = true;
963 for( ++aIt; bFound && aIt.Is(); ++aIt )
964 bFound = (rStyle.GetColor() == (*aIt)->GetCoreStyle().GetColor());
966 if( bFound )
967 rColor = rStyle.GetColor();
968 return bFound;
971 // frame border selection
972 const Link<LinkParamNone*,void>& FrameSelector::GetSelectHdl() const
974 return mxImpl->maSelectHdl;
977 void FrameSelector::SetSelectHdl( const Link<LinkParamNone*,void>& rHdl )
979 mxImpl->maSelectHdl = rHdl;
982 bool FrameSelector::IsBorderSelected( FrameBorderType eBorder ) const
984 return mxImpl->GetBorder( eBorder ).IsSelected();
987 void FrameSelector::SelectBorder( FrameBorderType eBorder )
989 mxImpl->SelectBorder( mxImpl->GetBorderAccess( eBorder ), true/*bSelect*/ );
990 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
991 // MT: bFireFox as API parameter is ugly...
992 // if (bFocus)
994 rtl::Reference< a11y::AccFrameSelectorChild > xRet = GetChildAccessible(eBorder);
995 if (xRet.is())
997 Any aOldValue, aNewValue;
998 aNewValue <<= AccessibleStateType::FOCUSED;
999 xRet->NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue );
1002 #endif
1005 bool FrameSelector::IsAnyBorderSelected() const
1007 // Construct an iterator for selected borders. If it is valid, there is a selected border.
1008 return SelFrameBorderCIter( mxImpl->maEnabBorders ).Is();
1011 void FrameSelector::SelectAllBorders( bool bSelect )
1013 for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1014 mxImpl->SelectBorder( **aIt, bSelect );
1017 void FrameSelector::SelectAllVisibleBorders()
1019 for( VisFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1020 mxImpl->SelectBorder( **aIt, true/*bSelect*/ );
1023 void FrameSelector::SetStyleToSelection( tools::Long nWidth, SvxBorderLineStyle nStyle )
1025 mxImpl->maCurrStyle.SetBorderLineStyle( nStyle );
1026 mxImpl->maCurrStyle.SetWidth( nWidth );
1027 for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1028 mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
1031 void FrameSelector::SetColorToSelection(const Color& rColor, model::ComplexColor const& rComplexColor)
1033 mxImpl->maCurrStyle.SetColor(rColor);
1034 mxImpl->maCurrStyle.setComplexColor(rComplexColor);
1036 for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1037 mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
1040 SvxBorderLineStyle FrameSelector::getCurrentStyleLineStyle() const
1042 return mxImpl->maCurrStyle.GetBorderLineStyle();
1045 // accessibility
1046 Reference< XAccessible > FrameSelector::CreateAccessible()
1048 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1049 if( !mxAccess.is() )
1050 mxAccess = new a11y::AccFrameSelector(*this);
1051 #endif
1052 return mxAccess;
1055 rtl::Reference< a11y::AccFrameSelectorChild > FrameSelector::GetChildAccessible( FrameBorderType eBorder )
1057 rtl::Reference< a11y::AccFrameSelectorChild > xRet;
1058 size_t nVecIdx = static_cast< size_t >( eBorder );
1059 if( IsBorderEnabled( eBorder ) && (1 <= nVecIdx) && (nVecIdx <= mxImpl->maChildVec.size()) )
1061 --nVecIdx;
1062 if( !mxImpl->maChildVec[ nVecIdx ].is() )
1063 mxImpl->maChildVec[ nVecIdx ] = new a11y::AccFrameSelectorChild( *this, eBorder );
1064 xRet = mxImpl->maChildVec[ nVecIdx ].get();
1066 return xRet;
1069 Reference< XAccessible > FrameSelector::GetChildAccessible( sal_Int32 nIndex )
1071 return GetChildAccessible( GetEnabledBorderType( nIndex ) );
1074 Reference< XAccessible > FrameSelector::GetChildAccessible( const Point& rPos )
1076 Reference< XAccessible > xRet;
1077 for( FrameBorderCIter aIt( mxImpl->maEnabBorders ); !xRet.is() && aIt.Is(); ++aIt )
1078 if( (*aIt)->ContainsClickPoint( rPos ) )
1079 xRet = GetChildAccessible( (*aIt)->GetType() ).get();
1080 return xRet;
1083 tools::Rectangle FrameSelector::GetClickBoundRect( FrameBorderType eBorder ) const
1085 tools::Rectangle aRect;
1086 const FrameBorder& rBorder = mxImpl->GetBorder( eBorder );
1087 if( rBorder.IsEnabled() )
1088 aRect = rBorder.GetClickBoundRect();
1089 return aRect;
1092 // virtual functions from base class
1093 void FrameSelector::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
1095 mxImpl->CopyVirDevToControl(rRenderContext);
1096 if (HasFocus())
1097 mxImpl->DrawAllTrackingRects(rRenderContext);
1100 bool FrameSelector::MouseButtonDown( const MouseEvent& rMEvt )
1102 /* Mouse handling:
1103 * Click on an unselected frame border:
1104 Set current style/color, make frame border visible, deselect all
1105 other frame borders.
1106 * Click on a selected frame border:
1107 Toggle state of the frame border (visible -> don't care -> hidden),
1108 deselect all other frame borders.
1109 * SHIFT+Click or CTRL+Click on an unselected frame border:
1110 Extend selection, set current style/color to all selected frame
1111 borders independent of the state/style/color of the borders.
1112 * SHIFT+Click or CTRL+Click on a selected frame border:
1113 If all frame borders have same style/color, toggle state of all
1114 borders (see above), otherwise set current style/color to all
1115 borders.
1116 * Click on unused area: Do not modify selection and selected frame
1117 borders.
1120 // #107394# do not auto-select a frame border
1121 mxImpl->SilentGrabFocus();
1123 if( rMEvt.IsLeft() )
1125 Point aPos( mxImpl->GetDevPosFromMousePos( rMEvt.GetPosPixel() ) );
1126 FrameBorderPtrVec aDeselectBorders;
1128 bool bAnyClicked = false; // Any frame border clicked?
1129 bool bNewSelected = false; // Any unselected frame border selected?
1131 /* If frame borders are set to "don't care" and the control does not
1132 support this state, hide them on first mouse click.
1133 DR 2004-01-30: Why are the borders set to "don't care" then?!? */
1134 bool bHideDontCare = !SupportsDontCareState();
1136 for( FrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1138 if( (*aIt)->ContainsClickPoint( aPos ) )
1140 // frame border is clicked
1141 bAnyClicked = true;
1142 if( !(*aIt)->IsSelected() )
1144 bNewSelected = true;
1145 //mxImpl->SelectBorder( **aIt, true );
1146 SelectBorder((**aIt).GetType());
1149 else
1151 // hide a "don't care" frame border only if it is not clicked
1152 if( bHideDontCare && ((*aIt)->GetState() == FrameBorderState::DontCare) )
1153 mxImpl->SetBorderState( **aIt, FrameBorderState::Hide );
1155 // deselect frame borders not clicked (if SHIFT or CTRL are not pressed)
1156 if( !rMEvt.IsShift() && !rMEvt.IsMod1() )
1157 aDeselectBorders.push_back( *aIt );
1161 if( bAnyClicked )
1163 // any valid frame border clicked? -> deselect other frame borders
1164 for( FrameBorderIter aIt( aDeselectBorders ); aIt.Is(); ++aIt )
1165 mxImpl->SelectBorder( **aIt, false );
1167 if( bNewSelected || !mxImpl->SelectedBordersEqual() )
1169 // new frame border selected, selection extended, or selected borders different? -> show
1170 for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1171 // SetBorderState() sets current style and color to the frame border
1172 mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
1174 else
1176 // all selected frame borders are equal -> toggle state
1177 for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1178 mxImpl->ToggleBorderState( **aIt );
1181 GetSelectHdl().Call( nullptr );
1185 return true;
1188 bool FrameSelector::KeyInput( const KeyEvent& rKEvt )
1190 bool bHandled = false;
1191 vcl::KeyCode aKeyCode = rKEvt.GetKeyCode();
1192 if( !aKeyCode.GetModifier() )
1194 sal_uInt16 nCode = aKeyCode.GetCode();
1195 switch( nCode )
1197 case KEY_SPACE:
1199 for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1200 mxImpl->ToggleBorderState( **aIt );
1201 bHandled = true;
1203 break;
1205 case KEY_UP:
1206 case KEY_DOWN:
1207 case KEY_LEFT:
1208 case KEY_RIGHT:
1210 if( !mxImpl->maEnabBorders.empty() )
1212 // start from first selected frame border
1213 SelFrameBorderCIter aIt( mxImpl->maEnabBorders );
1214 FrameBorderType eBorder = aIt.Is() ? (*aIt)->GetType() : mxImpl->maEnabBorders.front()->GetType();
1216 // search for next enabled frame border
1219 eBorder = mxImpl->GetBorder( eBorder ).GetKeyboardNeighbor( nCode );
1221 while( (eBorder != FrameBorderType::NONE) && !IsBorderEnabled( eBorder ) );
1223 // select the frame border
1224 if( eBorder != FrameBorderType::NONE )
1226 DeselectAllBorders();
1227 SelectBorder( eBorder );
1229 bHandled = true;
1232 break;
1235 if (bHandled)
1236 return true;
1237 return CustomWidgetController::KeyInput(rKEvt);
1240 void FrameSelector::GetFocus()
1242 // auto-selection of a frame border, if focus reaches control, and nothing is selected
1243 if( mxImpl->mbAutoSelect && !IsAnyBorderSelected() && !mxImpl->maEnabBorders.empty() )
1244 mxImpl->SelectBorder( *mxImpl->maEnabBorders.front(), true );
1246 mxImpl->DoInvalidate( false );
1247 if (IsAnyBorderSelected())
1249 FrameBorderType borderType = FrameBorderType::NONE;
1250 if (mxImpl->maLeft.IsSelected())
1251 borderType = FrameBorderType::Left;
1252 else if (mxImpl->maRight.IsSelected())
1253 borderType = FrameBorderType::Right;
1254 else if (mxImpl->maTop.IsSelected())
1255 borderType = FrameBorderType::Top;
1256 else if (mxImpl->maBottom.IsSelected())
1257 borderType = FrameBorderType::Bottom;
1258 else if (mxImpl->maHor.IsSelected())
1259 borderType = FrameBorderType::Horizontal;
1260 else if (mxImpl->maVer.IsSelected())
1261 borderType = FrameBorderType::Vertical;
1262 else if (mxImpl->maTLBR.IsSelected())
1263 borderType = FrameBorderType::TLBR;
1264 else if (mxImpl->maBLTR.IsSelected())
1265 borderType = FrameBorderType::BLTR;
1266 SelectBorder(borderType);
1268 for( SelFrameBorderIter aIt( mxImpl->maEnabBorders ); aIt.Is(); ++aIt )
1269 mxImpl->SetBorderState( **aIt, FrameBorderState::Show );
1270 CustomWidgetController::GetFocus();
1273 void FrameSelector::LoseFocus()
1275 mxImpl->DoInvalidate( false );
1276 CustomWidgetController::LoseFocus();
1279 void FrameSelector::StyleUpdated()
1281 mxImpl->InitVirtualDevice();
1282 CustomWidgetController::StyleUpdated();
1285 void FrameSelector::Resize()
1287 CustomWidgetController::Resize();
1288 mxImpl->sizeChanged();
1291 template< typename Cont, typename Iter, typename Pred >
1292 FrameBorderIterBase< Cont, Iter, Pred >::FrameBorderIterBase( container_type& rCont ) :
1293 maIt( rCont.begin() ),
1294 maEnd( rCont.end() )
1296 while( Is() && !maPred( *maIt ) ) ++maIt;
1299 template< typename Cont, typename Iter, typename Pred >
1300 FrameBorderIterBase< Cont, Iter, Pred >& FrameBorderIterBase< Cont, Iter, Pred >::operator++()
1302 do { ++maIt; } while( Is() && !maPred( *maIt ) );
1303 return *this;
1308 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */