1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
22 #include <osl/diagnose.h>
23 #include <tools/debug.hxx>
24 #include <vcl/wall.hxx>
25 #include <vcl/help.hxx>
26 #include <vcl/decoview.hxx>
27 #include <vcl/event.hxx>
28 #include <vcl/svapp.hxx>
29 #include <tools/poly.hxx>
30 #include <vcl/lineinfo.hxx>
31 #include <vcl/i18nhelp.hxx>
32 #include <vcl/mnemonic.hxx>
33 #include <vcl/settings.hxx>
34 #include <vcl/commandevent.hxx>
36 #include <vcl/toolkit/ivctrl.hxx>
37 #include "imivctl.hxx"
41 #include <vcl/idle.hxx>
43 constexpr auto DRAWTEXT_FLAGS_ICON
=
44 DrawTextFlags::Center
| DrawTextFlags::Top
| DrawTextFlags::EndEllipsis
|
45 DrawTextFlags::Clip
| DrawTextFlags::MultiLine
| DrawTextFlags::WordBreak
| DrawTextFlags::Mnemonic
;
47 #define DRAWTEXT_FLAGS_SMALLICON (DrawTextFlags::Left|DrawTextFlags::EndEllipsis|DrawTextFlags::Clip)
49 #define EVENTID_ADJUST_SCROLLBARS (reinterpret_cast<void*>(1))
51 SvxIconChoiceCtrl_Impl::SvxIconChoiceCtrl_Impl(
52 SvtIconChoiceCtrl
* pCurView
,
55 aVerSBar( VclPtr
<ScrollBar
>::Create(pCurView
, WB_DRAG
| WB_VSCROLL
) ),
56 aHorSBar( VclPtr
<ScrollBar
>::Create(pCurView
, WB_DRAG
| WB_HSCROLL
) ),
57 aScrBarBox( VclPtr
<ScrollBarBox
>::Create(pCurView
) ),
58 aDocRectChangedIdle( "svtools::SvxIconChoiceCtrl_Impl aDocRectChangedIdle" ),
59 aVisRectChangedIdle( "svtools::SvxIconChoiceCtrl_Impl aVisRectChangedIdle" ),
60 aImageSize( 32 * pCurView
->GetDPIScaleFactor(), 32 * pCurView
->GetDPIScaleFactor()),
61 pView(pCurView
), nMaxVirtHeight(DEFAULT_MAX_VIRT_HEIGHT
),
62 nFlags(IconChoiceFlags::NONE
), nUserEventAdjustScrBars(nullptr),
63 pCurHighlightFrame(nullptr),
66 SetStyle( nWinStyle
);
67 pImpCursor
.reset( new IcnCursor_Impl( this ) );
68 pGridMap
.reset( new IcnGridMap_Impl( this ) );
70 aVerSBar
->SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl
, ScrollUpDownHdl
) );
71 aHorSBar
->SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl
, ScrollLeftRightHdl
) );
73 nHorSBarHeight
= aHorSBar
->GetSizePixel().Height();
74 nVerSBarWidth
= aVerSBar
->GetSizePixel().Width();
76 aDocRectChangedIdle
.SetPriority( TaskPriority::HIGH_IDLE
);
77 aDocRectChangedIdle
.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl
,DocRectChangedHdl
));
79 aVisRectChangedIdle
.SetPriority( TaskPriority::HIGH_IDLE
);
80 aVisRectChangedIdle
.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl
,VisRectChangedHdl
));
83 Size
gridSize((nWinStyle
& WB_DETAILS
) ? 150 : 140, (nWinStyle
& WB_DETAILS
) ? 26 : 70);
84 if(pView
->GetDPIScaleFactor() > 1)
86 gridSize
.setHeight( gridSize
.Height() * ( pView
->GetDPIScaleFactor()) );
91 SvxIconChoiceCtrl_Impl::~SvxIconChoiceCtrl_Impl()
97 aVerSBar
.disposeAndClear();
98 aHorSBar
.disposeAndClear();
99 aScrBarBox
.disposeAndClear();
102 void SvxIconChoiceCtrl_Impl::Clear( bool bInCtor
)
104 pCurHighlightFrame
= nullptr;
107 bBoundRectsDirty
= false;
115 aVirtOutputSize
.setWidth( 0 );
116 aVirtOutputSize
.setHeight( 0 );
117 Size
aSize( pView
->GetOutputSizePixel() );
118 nMaxVirtHeight
= aSize
.Height() - nHorSBarHeight
;
119 if( nMaxVirtHeight
<= 0 )
120 nMaxVirtHeight
= DEFAULT_MAX_VIRT_HEIGHT
;
121 maZOrderList
.clear();
122 SetOrigin( Point() );
123 pView
->Invalidate(InvalidateFlags::NoChildren
);
131 void SvxIconChoiceCtrl_Impl::SetStyle( WinBits nWinStyle
)
133 nWinBits
= nWinStyle
;
134 nCurTextDrawFlags
= DRAWTEXT_FLAGS_ICON
;
135 if( nWinBits
& (WB_SMALLICON
| WB_DETAILS
) )
136 nCurTextDrawFlags
= DRAWTEXT_FLAGS_SMALLICON
;
139 IMPL_LINK( SvxIconChoiceCtrl_Impl
, ScrollUpDownHdl
, ScrollBar
*, pScrollBar
, void )
141 // arrow up: delta=-1; arrow down: delta=+1
142 Scroll( 0, pScrollBar
->GetDelta() );
145 IMPL_LINK( SvxIconChoiceCtrl_Impl
, ScrollLeftRightHdl
, ScrollBar
*, pScrollBar
, void )
147 // arrow left: delta=-1; arrow right: delta=+1
148 Scroll( pScrollBar
->GetDelta(), 0 );
151 void SvxIconChoiceCtrl_Impl::FontModified()
153 SetDefaultTextSize();
158 void SvxIconChoiceCtrl_Impl::InsertEntry( std::unique_ptr
<SvxIconChoiceCtrlEntry
> pEntry1
, size_t nPos
)
160 auto pEntry
= pEntry1
.get();
162 if ( nPos
< maEntries
.size() ) {
163 maEntries
.insert( maEntries
.begin() + nPos
, std::move(pEntry1
) );
165 maEntries
.push_back( std::move(pEntry1
) );
168 maZOrderList
.push_back( pEntry
);
171 // don't set all bounding rectangles to
172 // 'to be checked', but only the bounding rectangle of the new entry.
173 // Thus, don't call InvalidateBoundingRect!
174 pEntry
->aRect
.SetRight( LONG_MAX
);
175 FindBoundingRect(pEntry
);
176 tools::Rectangle
aOutputArea(GetOutputRect());
177 pGridMap
->OccupyGrids(pEntry
);
178 if (!aOutputArea
.Overlaps(pEntry
->aRect
))
179 return; // is invisible
180 pView
->Invalidate(pEntry
->aRect
);
183 void SvxIconChoiceCtrl_Impl::RemoveEntry(size_t nPos
)
186 maEntries
.erase(maEntries
.begin() + nPos
);
187 RecalcAllBoundingRectsSmart();
190 tools::Rectangle
SvxIconChoiceCtrl_Impl::GetOutputRect() const
192 Point
aOrigin( pView
->GetMapMode().GetOrigin() );
194 return tools::Rectangle( aOrigin
, aOutputSize
);
197 void SvxIconChoiceCtrl_Impl::SelectEntry( SvxIconChoiceCtrlEntry
* pEntry
, bool bSelect
,
203 if ( !( nFlags
& IconChoiceFlags::ClearingSelection
) )
205 nFlags
|= IconChoiceFlags::ClearingSelection
;
206 DeselectAllBut( pEntry
);
207 nFlags
&= ~IconChoiceFlags::ClearingSelection
;
210 if( pEntry
->IsSelected() == bSelect
)
213 SvxIconViewFlags nEntryFlags
= pEntry
->GetFlags();
216 nEntryFlags
|= SvxIconViewFlags::SELECTED
;
217 pEntry
->AssignFlags( nEntryFlags
);
222 nEntryFlags
&= ~SvxIconViewFlags::SELECTED
;
223 pEntry
->AssignFlags( nEntryFlags
);
226 EntrySelected( pEntry
, bSelect
);
229 void SvxIconChoiceCtrl_Impl::EntrySelected(SvxIconChoiceCtrlEntry
* pEntry
, bool bSelect
)
231 // make sure that the cursor is always placed
232 // over the (only) selected entry. (But only if a cursor exists.)
233 if (bSelect
&& pCursor
&& pEntry
!= pCursor
)
240 if (pEntry
== pCursor
)
242 pView
->Invalidate(CalcFocusRect(pEntry
));
243 if (pEntry
== pCursor
)
246 // #i101012# emit vcl event LISTBOX_SELECT only in case that the given entry is selected.
249 CallEventListeners(VclEventId::ListboxSelect
, pEntry
);
253 void SvxIconChoiceCtrl_Impl::ResetVirtSize()
255 aVirtOutputSize
.setWidth( 0 );
256 aVirtOutputSize
.setHeight( 0 );
257 const size_t nCount
= maEntries
.size();
258 for( size_t nCur
= 0; nCur
< nCount
; nCur
++ )
260 SvxIconChoiceCtrlEntry
* pCur
= maEntries
[ nCur
].get();
261 InvalidateBoundingRect(pCur
->aRect
);
264 if( !(nWinBits
& (WB_NOVSCROLL
| WB_NOHSCROLL
)) )
266 Size
aRealOutputSize( pView
->GetOutputSizePixel() );
267 if( aVirtOutputSize
.Width() < aRealOutputSize
.Width() ||
268 aVirtOutputSize
.Height() < aRealOutputSize
.Height() )
270 sal_uLong nGridCount
= IcnGridMap_Impl::GetGridCount(
271 aRealOutputSize
, static_cast<sal_uInt16
>(nGridDX
), static_cast<sal_uInt16
>(nGridDY
) );
272 if( nGridCount
< nCount
)
273 nMaxVirtHeight
= aRealOutputSize
.Height() - nHorSBarHeight
;
282 void SvxIconChoiceCtrl_Impl::AdjustVirtSize( const tools::Rectangle
& rRect
)
284 tools::Long nHeightOffs
= 0;
285 tools::Long nWidthOffs
= 0;
287 if( aVirtOutputSize
.Width() < (rRect
.Right()+LROFFS_WINBORDER
) )
288 nWidthOffs
= (rRect
.Right()+LROFFS_WINBORDER
) - aVirtOutputSize
.Width();
290 if( aVirtOutputSize
.Height() < (rRect
.Bottom()+TBOFFS_WINBORDER
) )
291 nHeightOffs
= (rRect
.Bottom()+TBOFFS_WINBORDER
) - aVirtOutputSize
.Height();
293 if( !(nWidthOffs
|| nHeightOffs
) )
297 aVirtOutputSize
.AdjustWidth(nWidthOffs
);
298 aRange
.Max() = aVirtOutputSize
.Width();
299 aHorSBar
->SetRange( aRange
);
301 aVirtOutputSize
.AdjustHeight(nHeightOffs
);
302 aRange
.Max() = aVirtOutputSize
.Height();
303 aVerSBar
->SetRange( aRange
);
306 pGridMap
->OutputSizeChanged();
311 void SvxIconChoiceCtrl_Impl::Arrange(tools::Long nSetMaxVirtHeight
)
313 if ( nSetMaxVirtHeight
!= 0 )
314 nMaxVirtHeight
= nSetMaxVirtHeight
;
316 nMaxVirtHeight
= aOutputSize
.Height();
321 void SvxIconChoiceCtrl_Impl::ImpArrange()
323 nFlags
|= IconChoiceFlags::Arranging
;
326 bBoundRectsDirty
= false;
327 SetOrigin( Point() );
329 RecalcAllBoundingRectsSmart();
330 // TODO: the invalidation in the detail view should be more intelligent
331 //if( !(nWinBits & WB_DETAILS ))
332 pView
->Invalidate( InvalidateFlags::NoChildren
);
333 nFlags
&= ~IconChoiceFlags::Arranging
;
337 void SvxIconChoiceCtrl_Impl::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
339 #if defined(OV_DRAWGRID)
340 Color
aOldColor (rRenderContext
.GetLineColor());
342 rRenderContext
.SetLineColor( aColor
);
343 Point
aOffs(rRenderContext
.GetMapMode().GetOrigin());
344 Size
aXSize(GetOutputSizePixel());
346 Point
aStart(LROFFS_WINBORDER
, 0);
347 Point
aEnd(LROFFS_WINBORDER
, aXSize
.Height());
350 rRenderContext
.DrawLine(aStart
, aEnd
);
353 Point
aStart(0, TBOFFS_WINBORDER
);
354 Point
aEnd(aXSize
.Width(), TBOFFS_WINBORDER
);
357 rRenderContext
.DrawLine(aStart
, aEnd
);
360 for (tools::Long nDX
= nGridDX
; nDX
<= aXSize
.Width(); nDX
+= nGridDX
)
362 Point
aStart( nDX
+LROFFS_WINBORDER
, 0 );
363 Point
aEnd( nDX
+LROFFS_WINBORDER
, aXSize
.Height());
366 rRenderContext
.DrawLine(aStart
, aEnd
);
368 for (tools::Long nDY
= nGridDY
; nDY
<= aXSize
.Height(); nDY
+= nGridDY
)
370 Point
aStart(0, nDY
+ TBOFFS_WINBORDER
);
371 Point
aEnd(aXSize
.Width(), nDY
+ TBOFFS_WINBORDER
);
374 rRenderContext
.DrawLine(aStart
, aEnd
);
376 rRenderContext
.SetLineColor(aOldColor
);
379 if (!maEntries
.size())
383 // set cursor to item with focus-flag
385 for (sal_Int32 i
= 0; i
< pView
->GetEntryCount() && !bfound
; i
++)
387 SvxIconChoiceCtrlEntry
* pEntry
= pView
->GetEntry(i
);
388 if (pEntry
->IsFocused())
396 pCursor
= maEntries
[ 0 ].get();
399 size_t nCount
= maZOrderList
.size();
403 rRenderContext
.Push(vcl::PushFlags::CLIPREGION
);
404 rRenderContext
.SetClipRegion(vcl::Region(rRect
));
406 std::vector
< SvxIconChoiceCtrlEntry
* > aNewZOrderList
;
407 std::vector
< SvxIconChoiceCtrlEntry
* > aPaintedEntries
;
412 SvxIconChoiceCtrlEntry
* pEntry
= maZOrderList
[nPos
];
413 const tools::Rectangle
& rBoundRect
= GetEntryBoundRect(pEntry
);
414 if (rRect
.Overlaps(rBoundRect
))
416 PaintEntry(pEntry
, rBoundRect
.TopLeft(), rRenderContext
);
417 // set entries to Top if they are being repainted
418 aPaintedEntries
.push_back(pEntry
);
421 aNewZOrderList
.push_back(pEntry
);
426 maZOrderList
= std::move( aNewZOrderList
);
427 maZOrderList
.insert(maZOrderList
.end(), aPaintedEntries
.begin(), aPaintedEntries
.end());
429 rRenderContext
.Pop();
432 void SvxIconChoiceCtrl_Impl::RepaintSelectedEntries()
434 tools::Rectangle
aOutRect(GetOutputRect());
435 for (SvxIconChoiceCtrlEntry
* pEntry
: maZOrderList
)
437 if (pEntry
->GetFlags() & SvxIconViewFlags::SELECTED
)
439 const tools::Rectangle
& rBoundRect
= GetEntryBoundRect(pEntry
);
440 if (aOutRect
.Overlaps(rBoundRect
))
441 pView
->Invalidate(rBoundRect
);
446 void SvxIconChoiceCtrl_Impl::InitScrollBarBox()
448 aScrBarBox
->SetSizePixel( Size(nVerSBarWidth
-1, nHorSBarHeight
-1) );
449 Size
aSize( pView
->GetOutputSizePixel() );
450 aScrBarBox
->SetPosPixel( Point(aSize
.Width()-nVerSBarWidth
+1, aSize
.Height()-nHorSBarHeight
+1));
453 bool SvxIconChoiceCtrl_Impl::MouseButtonDown( const MouseEvent
& rMEvt
)
455 bool bHandled
= true;
456 if( !(nWinBits
& WB_NOPOINTERFOCUS
) )
459 Point
aDocPos( rMEvt
.GetPosPixel() );
460 if(aDocPos
.X()>=aOutputSize
.Width() || aDocPos
.Y()>=aOutputSize
.Height())
463 SvxIconChoiceCtrlEntry
* pEntry
= GetEntry( aDocPos
);
465 MakeEntryVisible(pEntry
);
470 if( rMEvt
.GetClicks() == 2 )
472 DeselectAllBut( pEntry
);
473 SelectEntry( pEntry
, true, false );
479 if( rMEvt
.IsMod2() ) // Alt?
484 DeselectAllBut( pEntry
);
491 bool SvxIconChoiceCtrl_Impl::MouseMove( const MouseEvent
& rMEvt
)
493 if( pView
->IsTracking() )
496 SvxIconChoiceCtrlEntry
* pEntry
= nullptr;
497 if (!rMEvt
.IsLeaveWindow())
499 const Point
aDocPos(pView
->PixelToLogic(rMEvt
.GetPosPixel()));
500 pEntry
= GetEntry(aDocPos
);
502 SetEntryHighlightFrame(pEntry
);
506 void SvxIconChoiceCtrl_Impl::SetCursor_Impl(SvxIconChoiceCtrlEntry
* pNewCursor
)
512 MakeEntryVisible( pNewCursor
);
513 SetCursor( pNewCursor
);
515 SelectEntry( pCursor
, true, false );
516 CallEventListeners( VclEventId::ListboxSelect
, pCursor
);
519 bool SvxIconChoiceCtrl_Impl::KeyInput( const KeyEvent
& rKEvt
)
521 bool bMod2
= rKEvt
.GetKeyCode().IsMod2();
522 sal_Unicode cChar
= rKEvt
.GetCharCode();
523 sal_uLong nPos
= sal_uLong(-1);
524 if ( bMod2
&& cChar
&& IsMnemonicChar( cChar
, nPos
) )
526 // shortcut is clicked
527 SvxIconChoiceCtrlEntry
* pNewCursor
= GetEntry( nPos
);
528 SvxIconChoiceCtrlEntry
* pOldCursor
= pCursor
;
529 if ( pNewCursor
!= pOldCursor
)
530 SetCursor_Impl(pNewCursor
);
535 // no actions with <ALT>
538 bool bKeyUsed
= true;
540 SvxIconChoiceCtrlEntry
* pNewCursor
;
542 sal_uInt16 nCode
= rKEvt
.GetKeyCode().GetCode();
549 MakeEntryVisible( pCursor
);
550 if( nCode
== KEY_UP
|| (rKEvt
.GetKeyCode().IsMod1() && nCode
== KEY_PAGEUP
))
551 pNewCursor
= pImpCursor
->GoUpDown(pCursor
,false);
553 pNewCursor
= pImpCursor
->GoPageUpDown(pCursor
,false);
554 SetCursor_Impl(pNewCursor
);
557 tools::Rectangle
aRect( GetEntryBoundRect( pCursor
) );
560 aRect
.AdjustBottom( -(aRect
.Top()) );
562 MakeVisible( aRect
);
572 if( nCode
== KEY_DOWN
|| (rKEvt
.GetKeyCode().IsMod1() && nCode
== KEY_PAGEDOWN
) )
573 pNewCursor
=pImpCursor
->GoUpDown( pCursor
,true );
575 pNewCursor
=pImpCursor
->GoPageUpDown( pCursor
,true );
576 SetCursor_Impl(pNewCursor
);
583 pNewCursor
=pImpCursor
->GoLeftRight(pCursor
,true );
584 SetCursor_Impl(pNewCursor
);
591 MakeEntryVisible( pCursor
);
592 pNewCursor
= pImpCursor
->GoLeftRight(pCursor
,false );
593 SetCursor_Impl(pNewCursor
);
596 tools::Rectangle
aRect( GetEntryBoundRect(pCursor
));
599 aRect
.AdjustRight( -(aRect
.Left()) );
601 MakeVisible( aRect
);
611 if( rKEvt
.GetKeyCode().IsShift() )
613 if( nFlags
& IconChoiceFlags::AddMode
)
614 nFlags
&= ~IconChoiceFlags::AddMode
;
616 nFlags
|= IconChoiceFlags::AddMode
;
636 pNewCursor
= maEntries
.back().get();
637 SetCursor_Impl(pNewCursor
);
644 pNewCursor
= maEntries
[ 0 ].get();
645 SetCursor_Impl(pNewCursor
);
656 // recalculate TopLeft of scrollbars (but not their sizes!)
657 void SvxIconChoiceCtrl_Impl::PositionScrollBars( tools::Long nRealWidth
, tools::Long nRealHeight
)
659 // horizontal scrollbar
660 Point
aPos( 0, nRealHeight
);
661 aPos
.AdjustY( -nHorSBarHeight
);
663 if( aHorSBar
->GetPosPixel() != aPos
)
664 aHorSBar
->SetPosPixel( aPos
);
666 // vertical scrollbar
667 aPos
.setX( nRealWidth
); aPos
.setY( 0 );
668 aPos
.AdjustX( -nVerSBarWidth
);
672 if( aVerSBar
->GetPosPixel() != aPos
)
673 aVerSBar
->SetPosPixel( aPos
);
676 void SvxIconChoiceCtrl_Impl::AdjustScrollBars()
678 tools::Long nVirtHeight
= aVirtOutputSize
.Height();
679 tools::Long nVirtWidth
= aVirtOutputSize
.Width();
681 Size
aOSize( pView
->GetOutputSizePixel() );
682 tools::Long nRealHeight
= aOSize
.Height();
683 tools::Long nRealWidth
= aOSize
.Width();
685 PositionScrollBars( nRealWidth
, nRealHeight
);
687 const MapMode
& rMapMode
= pView
->GetMapMode();
688 Point
aOrigin( rMapMode
.GetOrigin() );
690 tools::Long nVisibleWidth
;
691 if( nRealWidth
> nVirtWidth
)
692 nVisibleWidth
= nVirtWidth
+ aOrigin
.X();
694 nVisibleWidth
= nRealWidth
;
696 tools::Long nVisibleHeight
;
697 if( nRealHeight
> nVirtHeight
)
698 nVisibleHeight
= nVirtHeight
+ aOrigin
.Y();
700 nVisibleHeight
= nRealHeight
;
702 bool bVerSBar
= ( nWinBits
& WB_VSCROLL
) != 0;
703 bool bHorSBar
= ( nWinBits
& WB_HSCROLL
) != 0;
704 bool bNoVerSBar
= ( nWinBits
& WB_NOVSCROLL
) != 0;
705 bool bNoHorSBar
= ( nWinBits
& WB_NOHSCROLL
) != 0;
707 sal_uInt16 nResult
= 0;
710 // activate vertical scrollbar?
711 if( !bNoVerSBar
&& (bVerSBar
|| ( nVirtHeight
> nVisibleHeight
)) )
714 nRealWidth
-= nVerSBarWidth
;
716 if( nRealWidth
> nVirtWidth
)
717 nVisibleWidth
= nVirtWidth
+ aOrigin
.X();
719 nVisibleWidth
= nRealWidth
;
721 // activate horizontal scrollbar?
722 if( !bNoHorSBar
&& (bHorSBar
|| (nVirtWidth
> nVisibleWidth
)) )
725 nRealHeight
-= nHorSBarHeight
;
727 if( nRealHeight
> nVirtHeight
)
728 nVisibleHeight
= nVirtHeight
+ aOrigin
.Y();
730 nVisibleHeight
= nRealHeight
;
732 // do we need a vertical scrollbar after all?
733 if( !(nResult
& 0x0001) && // only if not already there
734 ( !bNoVerSBar
&& ((nVirtHeight
> nVisibleHeight
) || bVerSBar
)) )
736 nResult
= 3; // both turned on
737 nRealWidth
-= nVerSBarWidth
;
739 if( nRealWidth
> nVirtWidth
)
740 nVisibleWidth
= nVirtWidth
+ aOrigin
.X();
742 nVisibleWidth
= nRealWidth
;
747 // size vertical scrollbar
748 tools::Long nThumb
= aVerSBar
->GetThumbPos();
749 Size
aSize( nVerSBarWidth
, nRealHeight
);
750 aSize
.AdjustHeight(2 );
751 if( aSize
!= aVerSBar
->GetSizePixel() )
752 aVerSBar
->SetSizePixel( aSize
);
753 aVerSBar
->SetVisibleSize( nVisibleHeight
);
754 aVerSBar
->SetPageSize( GetScrollBarPageSize( nVisibleHeight
));
756 if( nResult
& 0x0001 )
758 aVerSBar
->SetThumbPos( nThumb
);
763 aVerSBar
->SetThumbPos( 0 );
767 // size horizontal scrollbar
768 nThumb
= aHorSBar
->GetThumbPos();
769 aSize
.setWidth( nRealWidth
);
770 aSize
.setHeight( nHorSBarHeight
);
771 aSize
.AdjustWidth( 1 );
772 if( nResult
& 0x0001 ) // vertical scrollbar?
774 aSize
.AdjustWidth( 1 );
777 if( aSize
!= aHorSBar
->GetSizePixel() )
778 aHorSBar
->SetSizePixel( aSize
);
779 aHorSBar
->SetVisibleSize( nVisibleWidth
);
780 aHorSBar
->SetPageSize( GetScrollBarPageSize(nVisibleWidth
));
781 if( nResult
& 0x0002 )
783 aHorSBar
->SetThumbPos( nThumb
);
788 aHorSBar
->SetThumbPos( 0 );
792 aOutputSize
.setWidth( nRealWidth
);
793 if( nResult
& 0x0002 ) // horizontal scrollbar ?
794 nRealHeight
++; // because lower border is clipped
795 aOutputSize
.setHeight( nRealHeight
);
797 if( (nResult
& (0x0001|0x0002)) == (0x0001|0x0002) )
803 void SvxIconChoiceCtrl_Impl::Resize()
806 aOutputSize
= pView
->GetOutputSizePixel();
808 pGridMap
->OutputSizeChanged();
810 const Size aSize
= pView
->GetOutputSizePixel();
811 PositionScrollBars( aSize
.Width(), aSize
.Height() );
812 // The scrollbars are shown/hidden asynchronously, so derived classes can
813 // do an Arrange during Resize, without the scrollbars suddenly turning
815 // If an event is already underway, we don't need to send a new one, at least
816 // as long as there is only one event type.
817 if ( ! nUserEventAdjustScrBars
)
818 nUserEventAdjustScrBars
=
819 Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl
, UserEventHdl
),
820 EVENTID_ADJUST_SCROLLBARS
);
825 bool SvxIconChoiceCtrl_Impl::CheckHorScrollBar()
827 if( maZOrderList
.empty() || !aHorSBar
->IsVisible() )
829 const MapMode
& rMapMode
= pView
->GetMapMode();
830 Point
aOrigin( rMapMode
.GetOrigin() );
831 if(!( nWinBits
& WB_HSCROLL
) && !aOrigin
.X() )
833 tools::Long nWidth
= aOutputSize
.Width();
834 const size_t nCount
= maZOrderList
.size();
835 tools::Long nMostRight
= 0;
836 for( size_t nCur
= 0; nCur
< nCount
; nCur
++ )
838 SvxIconChoiceCtrlEntry
* pEntry
= maZOrderList
[ nCur
];
839 tools::Long nRight
= GetEntryBoundRect(pEntry
).Right();
840 if( nRight
> nWidth
)
842 if( nRight
> nMostRight
)
846 aOutputSize
.AdjustHeight(nHorSBarHeight
);
847 aVirtOutputSize
.setWidth( nMostRight
);
848 aHorSBar
->SetThumbPos( 0 );
850 aRange
.Max() = nMostRight
- 1;
851 aHorSBar
->SetRange( aRange
);
852 if( aVerSBar
->IsVisible() )
854 Size
aSize( aVerSBar
->GetSizePixel());
855 aSize
.AdjustHeight(nHorSBarHeight
);
856 aVerSBar
->SetSizePixel( aSize
);
863 bool SvxIconChoiceCtrl_Impl::CheckVerScrollBar()
865 if( maZOrderList
.empty() || !aVerSBar
->IsVisible() )
867 const MapMode
& rMapMode
= pView
->GetMapMode();
868 Point
aOrigin( rMapMode
.GetOrigin() );
869 if(!( nWinBits
& WB_VSCROLL
) && !aOrigin
.Y() )
871 tools::Long nDeepest
= 0;
872 tools::Long nHeight
= aOutputSize
.Height();
873 const size_t nCount
= maZOrderList
.size();
874 for( size_t nCur
= 0; nCur
< nCount
; nCur
++ )
876 SvxIconChoiceCtrlEntry
* pEntry
= maZOrderList
[ nCur
];
877 tools::Long nBottom
= GetEntryBoundRect(pEntry
).Bottom();
878 if( nBottom
> nHeight
)
880 if( nBottom
> nDeepest
)
884 aOutputSize
.AdjustWidth(nVerSBarWidth
);
885 aVirtOutputSize
.setHeight( nDeepest
);
886 aVerSBar
->SetThumbPos( 0 );
888 aRange
.Max() = nDeepest
- 1;
889 aVerSBar
->SetRange( aRange
);
890 if( aHorSBar
->IsVisible() )
892 Size
aSize( aHorSBar
->GetSizePixel());
893 aSize
.AdjustWidth(nVerSBarWidth
);
894 aHorSBar
->SetSizePixel( aSize
);
902 // hides scrollbars if they're unnecessary
903 void SvxIconChoiceCtrl_Impl::CheckScrollBars()
906 if( CheckHorScrollBar() )
908 if( aVerSBar
->IsVisible() && aHorSBar
->IsVisible() )
915 void SvxIconChoiceCtrl_Impl::GetFocus()
917 RepaintSelectedEntries();
920 pCursor
->SetFlags( SvxIconViewFlags::FOCUSED
);
925 void SvxIconChoiceCtrl_Impl::LoseFocus()
928 pCursor
->ClearFlags( SvxIconViewFlags::FOCUSED
);
932 // pView->Invalidate ( aFocus.aRect );
934 RepaintSelectedEntries();
937 // priorities of the emphasis: bSelected
938 void SvxIconChoiceCtrl_Impl::PaintEmphasis(const tools::Rectangle
& rTextRect
,
939 vcl::RenderContext
& rRenderContext
)
941 Color
aOldFillColor(rRenderContext
.GetFillColor());
942 const Color
& rFillColor
= rRenderContext
.GetFont().GetFillColor();
943 rRenderContext
.SetFillColor(rFillColor
);
944 // draw text rectangle
945 if (rFillColor
!= COL_TRANSPARENT
)
946 rRenderContext
.DrawRect(rTextRect
);
948 rRenderContext
.SetFillColor(aOldFillColor
);
952 void SvxIconChoiceCtrl_Impl::PaintItem(const tools::Rectangle
& rRect
,
953 IcnViewFieldType eItem
, SvxIconChoiceCtrlEntry
* pEntry
, sal_uInt16 nPaintFlags
,
954 vcl::RenderContext
& rRenderContext
)
956 if (eItem
== IcnViewFieldType::Text
)
958 if (nWinBits
& WB_DETAILS
)
960 // Vertically center text when the entry is text-only
961 tools::Long
nBoundingHeight(CalcBoundingHeight());
962 tools::Long nStringHeight
= GetItemSize(IcnViewFieldType::Text
).Height();
963 tools::Long nNewY
= (nBoundingHeight
- nStringHeight
) / 2;
964 Point
aRectTL(rRect
.TopLeft().getX(), rRect
.TopLeft().getY() + nNewY
);
965 tools::Rectangle
aTextRect(aRectTL
, rRect
.GetSize());
966 rRenderContext
.DrawText(aTextRect
, pEntry
->GetText(), nCurTextDrawFlags
);
970 rRenderContext
.DrawText(rRect
, pEntry
->GetText(), nCurTextDrawFlags
);
975 Point
aPos(rRect
.TopLeft());
976 if (nPaintFlags
& PAINTFLAG_HOR_CENTERED
)
977 aPos
.AdjustX((rRect
.GetWidth() - aImageSize
.Width()) / 2 );
978 if (nPaintFlags
& PAINTFLAG_VER_CENTERED
)
979 aPos
.AdjustY((rRect
.GetHeight() - aImageSize
.Height()) / 2 );
980 rRenderContext
.DrawImage(aPos
, pEntry
->GetImage());
984 void SvxIconChoiceCtrl_Impl::PaintEntry(SvxIconChoiceCtrlEntry
* pEntry
, const Point
& rPos
, vcl::RenderContext
& rRenderContext
)
986 rRenderContext
.Push(vcl::PushFlags::FONT
| vcl::PushFlags::TEXTCOLOR
);
988 tools::Rectangle
aTextRect(CalcTextRect(pEntry
, &rPos
));
989 tools::Rectangle
aBmpRect(CalcBmpRect(pEntry
, &rPos
));
991 const bool bMouseHovered
= pEntry
== pCurHighlightFrame
;
992 const bool bSelected
= pEntry
->IsSelected();
994 const StyleSettings
& rSettings
= rRenderContext
.GetSettings().GetStyleSettings();
995 vcl::Font
aNewFont(rRenderContext
.GetFont());
997 aNewFont
.SetColor(rSettings
.GetTabHighlightTextColor());
998 else if (bMouseHovered
)
999 aNewFont
.SetColor(rSettings
.GetTabRolloverTextColor());
1001 aNewFont
.SetColor(rSettings
.GetTabTextColor());
1002 rRenderContext
.SetFont(aNewFont
);
1004 bool bResetClipRegion
= false;
1005 if (!rRenderContext
.IsClipRegion() && (aVerSBar
->IsVisible() || aHorSBar
->IsVisible()))
1007 tools::Rectangle
aOutputArea(GetOutputRect());
1008 if (aOutputArea
.Overlaps(aTextRect
) || aOutputArea
.Overlaps(aBmpRect
))
1010 rRenderContext
.SetClipRegion(vcl::Region(aOutputArea
));
1011 bResetClipRegion
= true;
1015 bool bLargeIconMode
= WB_ICON
== ( nWinBits
& VIEWMODE_MASK
);
1016 sal_uInt16 nBmpPaintFlags
= PAINTFLAG_VER_CENTERED
;
1018 nBmpPaintFlags
|= PAINTFLAG_HOR_CENTERED
;
1019 sal_uInt16 nTextPaintFlags
= bLargeIconMode
? PAINTFLAG_HOR_CENTERED
: PAINTFLAG_VER_CENTERED
;
1021 tools::Rectangle
aFocusRect(CalcFocusRect(pEntry
));
1024 = rRenderContext
.IsNativeControlSupported(ControlType::TabItem
, ControlPart::Entire
);
1027 ControlState nState
= ControlState::ENABLED
;
1029 nState
|= ControlState::SELECTED
;
1030 if (pEntry
->IsFocused())
1031 nState
|= ControlState::FOCUSED
;
1033 nState
|= ControlState::ROLLOVER
;
1035 TabitemValue
tiValue(aFocusRect
, TabBarPosition::Left
);
1036 bNativeOK
= rRenderContext
.DrawNativeControl(ControlType::TabItem
, ControlPart::Entire
,
1037 aFocusRect
, nState
, tiValue
, OUString());
1043 vcl::RenderTools::DrawSelectionBackground(
1044 rRenderContext
, *pView
, aFocusRect
, pView
->HasFocus() ? 1 : 2, false, false, false);
1046 PaintEmphasis(aTextRect
, rRenderContext
);
1048 if (pEntry
->IsFocused())
1049 DrawFocusRect(rRenderContext
, pEntry
);
1051 // highlight mouse-hovered entry
1053 DrawHighlightFrame(rRenderContext
, aFocusRect
);
1056 PaintItem(aBmpRect
, IcnViewFieldType::Image
, pEntry
, nBmpPaintFlags
, rRenderContext
);
1058 // Move text a bit to the right for native controls due to potential tab mark (applies to text-only entries)
1059 if (bNativeOK
&& (nWinBits
& WB_DETAILS
))
1060 aTextRect
.SetPos(Point(aTextRect
.GetPos().X() + TAB_MARK_WIDTH
, aTextRect
.GetPos().Y()));
1062 PaintItem(aTextRect
, IcnViewFieldType::Text
, pEntry
, nTextPaintFlags
, rRenderContext
);
1064 rRenderContext
.Pop();
1065 if (bResetClipRegion
)
1066 rRenderContext
.SetClipRegion();
1069 SvxIconChoiceCtrlEntry
* SvxIconChoiceCtrl_Impl::GetEntry( const Point
& rDocPos
)
1071 CheckBoundingRects();
1072 // search through z-order list from the end
1073 size_t nCount
= maZOrderList
.size();
1077 SvxIconChoiceCtrlEntry
* pEntry
= maZOrderList
[ nCount
];
1078 tools::Rectangle
aBoundingRect(GetEntryBoundRect(pEntry
));
1079 if( aBoundingRect
.Contains( rDocPos
) )
1085 void SvxIconChoiceCtrl_Impl::MakeEntryVisible(SvxIconChoiceCtrlEntry
* pEntry
)
1087 const tools::Rectangle
& rRect
= GetEntryBoundRect( pEntry
);
1091 const tools::Rectangle
& SvxIconChoiceCtrl_Impl::GetEntryBoundRect( SvxIconChoiceCtrlEntry
* pEntry
)
1093 if( !IsBoundingRectValid( pEntry
->aRect
))
1094 FindBoundingRect( pEntry
);
1095 return pEntry
->aRect
;
1098 tools::Rectangle
SvxIconChoiceCtrl_Impl::CalcBmpRect( SvxIconChoiceCtrlEntry
* pEntry
, const Point
* pPos
)
1100 tools::Rectangle aBound
= GetEntryBoundRect( pEntry
);
1102 aBound
.SetPos( *pPos
);
1103 Point
aPos( aBound
.TopLeft() );
1105 switch( nWinBits
& VIEWMODE_MASK
)
1109 aPos
.AdjustX(( aBound
.GetWidth() - aImageSize
.Width() ) / 2 );
1110 return tools::Rectangle( aPos
, aImageSize
);
1114 return tools::Rectangle(aPos
, Size(0,0));
1116 aPos
.AdjustY(( aBound
.GetHeight() - aImageSize
.Height() ) / 2 );
1117 //TODO: determine horizontal distance to bounding rectangle
1118 return tools::Rectangle( aPos
, aImageSize
);
1121 assert(false && "IconView: Viewmode not set");
1126 tools::Rectangle
SvxIconChoiceCtrl_Impl::CalcTextRect( SvxIconChoiceCtrlEntry
* pEntry
,
1127 const Point
* pEntryPos
)
1129 const tools::Rectangle
aMaxTextRect( CalcMaxTextRect( pEntry
) );
1130 tools::Rectangle
aBound( GetEntryBoundRect( pEntry
) );
1132 aBound
.SetPos( *pEntryPos
);
1134 const OUString aEntryText
= pEntry
->GetText();
1135 tools::Rectangle aTextRect
= pView
->GetTextRect( aMaxTextRect
, aEntryText
, nCurTextDrawFlags
);
1137 Size
aTextSize( aTextRect
.GetSize() );
1139 Point
aPos( aBound
.TopLeft() );
1140 tools::Long nBoundWidth
= aBound
.GetWidth();
1141 tools::Long nBoundHeight
= aBound
.GetHeight();
1143 switch( nWinBits
& VIEWMODE_MASK
)
1146 aPos
.AdjustY(aImageSize
.Height() );
1147 aPos
.AdjustY(VER_DIST_BMP_STRING
);
1148 aPos
.AdjustX((nBoundWidth
- aTextSize
.Width()) / 2 );
1155 aPos
.AdjustX(aImageSize
.Width() );
1156 aPos
.AdjustX(HOR_DIST_BMP_STRING
);
1157 aPos
.AdjustY((nBoundHeight
- aTextSize
.Height()) / 2 );
1160 return tools::Rectangle( aPos
, aTextSize
);
1164 tools::Long
SvxIconChoiceCtrl_Impl::CalcBoundingWidth() const
1166 tools::Long nStringWidth
= GetItemSize( IcnViewFieldType::Text
).Width();
1167 tools::Long nWidth
= 0;
1169 switch( nWinBits
& VIEWMODE_MASK
)
1172 nWidth
= std::max( nStringWidth
, aImageSize
.Width() );
1176 nWidth
= nStringWidth
;
1180 nWidth
= aImageSize
.Width();
1181 nWidth
+= HOR_DIST_BMP_STRING
;
1182 nWidth
+= nStringWidth
;
1188 tools::Long
SvxIconChoiceCtrl_Impl::CalcBoundingHeight() const
1190 tools::Long nStringHeight
= GetItemSize(IcnViewFieldType::Text
).Height();
1191 tools::Long nHeight
= 0;
1193 switch( nWinBits
& VIEWMODE_MASK
)
1196 nHeight
= aImageSize
.Height();
1197 nHeight
+= VER_DIST_BMP_STRING
;
1198 nHeight
+= nStringHeight
;
1202 nHeight
= nStringHeight
+ 2 * VERT_TEXT_PADDING
;;
1206 nHeight
= std::max( aImageSize
.Height(), nStringHeight
);
1209 if( nHeight
> nMaxBoundHeight
)
1211 const_cast<SvxIconChoiceCtrl_Impl
*>(this)->nMaxBoundHeight
= nHeight
;
1212 const_cast<SvxIconChoiceCtrl_Impl
*>(this)->aHorSBar
->SetLineSize( GetScrollBarLineSize() );
1213 const_cast<SvxIconChoiceCtrl_Impl
*>(this)->aVerSBar
->SetLineSize( GetScrollBarLineSize() );
1218 Size
SvxIconChoiceCtrl_Impl::CalcBoundingSize() const
1220 return Size( CalcBoundingWidth(), CalcBoundingHeight() );
1223 void SvxIconChoiceCtrl_Impl::RecalcAllBoundingRectsSmart()
1225 nMaxBoundHeight
= 0;
1226 maZOrderList
.clear();
1228 SvxIconChoiceCtrlEntry
* pEntry
;
1229 const size_t nCount
= maEntries
.size();
1231 for( nCur
= 0; nCur
< nCount
; nCur
++ )
1233 pEntry
= maEntries
[ nCur
].get();
1234 if( IsBoundingRectValid( pEntry
->aRect
))
1236 Size
aBoundSize( pEntry
->aRect
.GetSize() );
1237 if( aBoundSize
.Height() > nMaxBoundHeight
)
1238 nMaxBoundHeight
= aBoundSize
.Height();
1241 FindBoundingRect( pEntry
);
1242 maZOrderList
.push_back( pEntry
);
1247 void SvxIconChoiceCtrl_Impl::FindBoundingRect( SvxIconChoiceCtrlEntry
* pEntry
)
1250 Point
aPos(pGridMap
->GetGridRect(pGridMap
->GetUnoccupiedGrid()).TopLeft());
1252 tools::Rectangle
aGridRect(aPos
, Size(nGridDX
, nGridDY
));
1253 pEntry
->aRect
= aGridRect
;
1254 AdjustVirtSize( pEntry
->aRect
);
1255 pGridMap
->OccupyGrids( pEntry
);
1259 void SvxIconChoiceCtrl_Impl::SetCursor( SvxIconChoiceCtrlEntry
* pEntry
)
1261 if( pEntry
== pCursor
)
1263 if (pCursor
&& !pCursor
->IsSelected())
1264 SelectEntry( pCursor
, true );
1267 ShowCursor( false );
1268 SvxIconChoiceCtrlEntry
* pOldCursor
= pCursor
;
1272 pOldCursor
->ClearFlags( SvxIconViewFlags::FOCUSED
);
1273 SelectEntry(pOldCursor
, false); // deselect old cursor
1278 pCursor
->SetFlags( SvxIconViewFlags::FOCUSED
);
1279 SelectEntry(pCursor
, true);
1285 void SvxIconChoiceCtrl_Impl::ShowCursor( bool bShow
)
1287 if( !pCursor
|| !bShow
|| !pView
->HasFocus() )
1292 tools::Rectangle
aRect ( CalcFocusRect( pCursor
) );
1293 /*pView->*/ShowFocus( aRect
);
1296 bool SvxIconChoiceCtrl_Impl::HandleScrollCommand( const CommandEvent
& rCmd
)
1298 tools::Rectangle
aDocRect( Point(), aVirtOutputSize
);
1299 tools::Rectangle
aVisRect( GetOutputRect() );
1300 if( aVisRect
.Contains( aDocRect
))
1302 Size
aDocSize( aDocRect
.GetSize() );
1303 Size
aVisSize( aVisRect
.GetSize() );
1304 bool bHor
= aDocSize
.Width() > aVisSize
.Width();
1305 bool bVer
= aDocSize
.Height() > aVisSize
.Height();
1307 tools::Long nScrollDX
= 0, nScrollDY
= 0;
1309 switch( rCmd
.GetCommand() )
1311 case CommandEventId::StartAutoScroll
:
1313 pView
->EndTracking();
1314 StartAutoScrollFlags nScrollFlags
= StartAutoScrollFlags::NONE
;
1316 nScrollFlags
|= StartAutoScrollFlags::Horz
;
1318 nScrollFlags
|= StartAutoScrollFlags::Vert
;
1319 if( nScrollFlags
!= StartAutoScrollFlags::NONE
)
1321 pView
->StartAutoScroll( nScrollFlags
);
1327 case CommandEventId::Wheel
:
1329 const CommandWheelData
* pData
= rCmd
.GetWheelData();
1330 if( pData
&& (CommandWheelMode::SCROLL
== pData
->GetMode()) && !pData
->IsHorz() )
1332 double nScrollLines
= pData
->GetScrollLines();
1333 if( nScrollLines
== COMMAND_WHEEL_PAGESCROLL
)
1335 nScrollDY
= GetScrollBarPageSize( aVisSize
.Width() );
1336 if( pData
->GetDelta() < 0 )
1341 nScrollDY
= pData
->GetNotchDelta() * static_cast<tools::Long
>(nScrollLines
);
1342 nScrollDY
*= GetScrollBarLineSize();
1348 case CommandEventId::AutoScroll
:
1350 const CommandScrollData
* pData
= rCmd
.GetAutoScrollData();
1353 nScrollDX
= pData
->GetDeltaX() * GetScrollBarLineSize();
1354 nScrollDY
= pData
->GetDeltaY() * GetScrollBarLineSize();
1362 if( nScrollDX
|| nScrollDY
)
1364 aVisRect
.AdjustTop( -nScrollDY
);
1365 aVisRect
.AdjustBottom( -nScrollDY
);
1366 aVisRect
.AdjustLeft( -nScrollDX
);
1367 aVisRect
.AdjustRight( -nScrollDX
);
1368 MakeVisible( aVisRect
);
1375 void SvxIconChoiceCtrl_Impl::Command( const CommandEvent
& rCEvt
)
1377 // scroll mouse event?
1378 if( (rCEvt
.GetCommand() == CommandEventId::Wheel
) ||
1379 (rCEvt
.GetCommand() == CommandEventId::StartAutoScroll
) ||
1380 (rCEvt
.GetCommand() == CommandEventId::AutoScroll
) )
1382 if( HandleScrollCommand( rCEvt
) )
1387 void SvxIconChoiceCtrl_Impl::ToTop( SvxIconChoiceCtrlEntry
* pEntry
)
1389 if( maZOrderList
.empty() || pEntry
== maZOrderList
.back())
1392 auto it
= std::find(maZOrderList
.begin(), maZOrderList
.end(), pEntry
);
1393 if (it
!= maZOrderList
.end())
1395 maZOrderList
.erase( it
);
1396 maZOrderList
.push_back( pEntry
);
1400 void SvxIconChoiceCtrl_Impl::ClipAtVirtOutRect( tools::Rectangle
& rRect
) const
1402 if( rRect
.Bottom() >= aVirtOutputSize
.Height() )
1403 rRect
.SetBottom( aVirtOutputSize
.Height() - 1 );
1404 if( rRect
.Right() >= aVirtOutputSize
.Width() )
1405 rRect
.SetRight( aVirtOutputSize
.Width() - 1 );
1406 if( rRect
.Top() < 0 )
1408 if( rRect
.Left() < 0 )
1412 // rRect: area of the document (in document coordinates) that we want to make
1414 // bScrBar == true: rectangle was calculated because of a scrollbar event
1416 void SvxIconChoiceCtrl_Impl::MakeVisible( const tools::Rectangle
& rRect
, bool bScrBar
)
1418 tools::Rectangle
aVirtRect( rRect
);
1419 ClipAtVirtOutRect( aVirtRect
);
1420 Point
aOrigin( pView
->GetMapMode().GetOrigin() );
1421 // convert to document coordinate
1423 tools::Rectangle
aOutputArea( GetOutputRect() );
1424 if( aOutputArea
.Contains( aVirtRect
) )
1425 return; // is already visible
1428 if( aVirtRect
.Top() < aOutputArea
.Top() )
1430 // scroll up (nDy < 0)
1431 nDy
= aVirtRect
.Top() - aOutputArea
.Top();
1433 else if( aVirtRect
.Bottom() > aOutputArea
.Bottom() )
1435 // scroll down (nDy > 0)
1436 nDy
= aVirtRect
.Bottom() - aOutputArea
.Bottom();
1441 tools::Long nDx
= 0;
1443 // no horizontal scrolling needed in list mode
1444 if (!(nWinBits
& WB_DETAILS
))
1446 if( aVirtRect
.Left() < aOutputArea
.Left() )
1448 // scroll to the left (nDx < 0)
1449 nDx
= aVirtRect
.Left() - aOutputArea
.Left();
1451 else if( aVirtRect
.Right() > aOutputArea
.Right() )
1453 // scroll to the right (nDx > 0)
1454 nDx
= aVirtRect
.Right() - aOutputArea
.Right();
1458 aOrigin
.AdjustX(nDx
);
1459 aOrigin
.AdjustY(nDy
);
1460 aOutputArea
.SetPos( aOrigin
);
1462 pView
->PaintImmediately();
1465 // invert origin for SV (so we can scroll/paint using document coordinates)
1467 SetOrigin( aOrigin
);
1469 bool bScrollable
= pView
->GetBackground().IsScrollable();
1473 // scroll in reverse direction!
1474 pView
->Scroll( -nDx
, -nDy
, aOutputArea
,
1475 ScrollFlags::NoChildren
| ScrollFlags::UseClipRegion
| ScrollFlags::Clip
);
1478 pView
->Invalidate(InvalidateFlags::NoChildren
);
1480 if( aHorSBar
->IsVisible() || aVerSBar
->IsVisible() )
1486 if(aHorSBar
->IsVisible() && aHorSBar
->GetThumbPos() != aOrigin
.X())
1487 aHorSBar
->SetThumbPos( aOrigin
.X() );
1488 if(aVerSBar
->IsVisible() && aVerSBar
->GetThumbPos() != aOrigin
.Y())
1489 aVerSBar
->SetThumbPos( aOrigin
.Y() );
1495 // check if we still need scrollbars
1498 pView
->PaintImmediately();
1500 // If the requested area can not be made completely visible, the
1501 // Vis-Rect-Changed handler is called in any case. This case may occur e.g.
1502 // if only few pixels of the lower border are invisible, but a scrollbar has
1503 // a larger line size.
1507 void SvxIconChoiceCtrl_Impl::DeselectAllBut( SvxIconChoiceCtrlEntry
const * pThisEntryNot
)
1509 // TODO: work through z-order list, if necessary!
1511 size_t nCount
= maEntries
.size();
1512 for( size_t nCur
= 0; nCur
< nCount
; nCur
++ )
1514 SvxIconChoiceCtrlEntry
* pEntry
= maEntries
[ nCur
].get();
1515 if( pEntry
!= pThisEntryNot
&& pEntry
->IsSelected() )
1516 SelectEntry( pEntry
, false, true );
1518 nFlags
&= ~IconChoiceFlags::AddMode
;
1521 Size
SvxIconChoiceCtrl_Impl::GetMinGrid() const
1523 Size
aTextSize( pView
->GetTextWidth( u
"XXX"_ustr
), pView
->GetTextHeight() );
1524 if (nWinBits
& WB_DETAILS
)
1525 return Size(aTextSize
.Width(), aTextSize
.Height());
1527 Size
aMinSize( aImageSize
);
1528 aMinSize
.AdjustWidth(2 * LROFFS_BOUND
);
1529 if( nWinBits
& WB_ICON
)
1531 aMinSize
.AdjustHeight(VER_DIST_BMP_STRING
);
1532 aMinSize
.AdjustHeight(aTextSize
.Height() );
1536 aMinSize
.AdjustWidth(HOR_DIST_BMP_STRING
);
1537 aMinSize
.AdjustWidth(aTextSize
.Width() );
1542 void SvxIconChoiceCtrl_Impl::SetGrid( const Size
& rSize
)
1544 Size
aSize( rSize
);
1545 Size
aMinSize( GetMinGrid() );
1546 if( aSize
.Width() < aMinSize
.Width() )
1547 aSize
.setWidth( aMinSize
.Width() );
1548 if( aSize
.Height() < aMinSize
.Height() )
1549 aSize
.setHeight( aMinSize
.Height() );
1551 nGridDX
= aSize
.Width();
1552 nGridDY
= aSize
.Height();
1553 SetDefaultTextSize();
1556 // Calculates the maximum size that the text rectangle may use within its
1557 // bounding rectangle.
1559 tools::Rectangle
SvxIconChoiceCtrl_Impl::CalcMaxTextRect( const SvxIconChoiceCtrlEntry
* pEntry
) const
1561 assert(IsBoundingRectValid(pEntry
->aRect
) && "Bounding rect for entry hasn't been calculated yet.");
1562 tools::Rectangle aBoundRect
= pEntry
->aRect
;
1564 tools::Rectangle
aBmpRect( const_cast<SvxIconChoiceCtrl_Impl
*>(this)->CalcBmpRect(
1565 const_cast<SvxIconChoiceCtrlEntry
*>(pEntry
) ) );
1566 if( nWinBits
& WB_ICON
)
1568 aBoundRect
.SetTop( aBmpRect
.Bottom() );
1569 aBoundRect
.AdjustTop(VER_DIST_BMP_STRING
);
1570 if( aBoundRect
.Top() > aBoundRect
.Bottom())
1571 aBoundRect
.SetTop( aBoundRect
.Bottom() );
1572 aBoundRect
.AdjustLeft(LROFFS_BOUND
);
1573 aBoundRect
.AdjustLeft( 1 );
1574 aBoundRect
.AdjustRight( -(LROFFS_BOUND
) );
1575 aBoundRect
.AdjustRight( -1 );
1576 if( aBoundRect
.Left() > aBoundRect
.Right())
1577 aBoundRect
.SetLeft( aBoundRect
.Right() );
1579 else if (nWinBits
& WB_SMALLICON
)
1581 aBoundRect
.SetLeft( aBmpRect
.Right() );
1582 aBoundRect
.AdjustLeft(HOR_DIST_BMP_STRING
);
1583 aBoundRect
.AdjustRight( -(LROFFS_BOUND
) );
1584 if( aBoundRect
.Left() > aBoundRect
.Right() )
1585 aBoundRect
.SetLeft( aBoundRect
.Right() );
1586 tools::Long nHeight
= aBoundRect
.GetSize().Height();
1587 nHeight
= nHeight
- aDefaultTextSize
.Height();
1589 aBoundRect
.AdjustTop(nHeight
);
1590 aBoundRect
.AdjustBottom( -nHeight
);
1595 void SvxIconChoiceCtrl_Impl::SetDefaultTextSize()
1597 tools::Long nDY
= nGridDY
;
1598 nDY
-= aImageSize
.Height();
1599 nDY
-= VER_DIST_BMP_STRING
;
1603 tools::Long nDX
= nGridDX
;
1604 nDX
-= 2 * LROFFS_BOUND
;
1609 tools::Long nHeight
= pView
->GetTextHeight();
1612 if(pView
->GetDPIScaleFactor() > 1)
1616 aDefaultTextSize
= Size(nDX
, nDY
);
1619 // The deltas are the offsets by which the view is moved on the document.
1620 // left, up: offsets < 0
1621 // right, down: offsets > 0
1622 void SvxIconChoiceCtrl_Impl::Scroll( tools::Long nDeltaX
, tools::Long nDeltaY
)
1624 const MapMode
& rMapMode
= pView
->GetMapMode();
1625 Point
aOrigin( rMapMode
.GetOrigin() );
1626 // convert to document coordinate
1628 aOrigin
.AdjustY(nDeltaY
);
1629 aOrigin
.AdjustX(nDeltaX
);
1630 tools::Rectangle
aRect( aOrigin
, aOutputSize
);
1631 MakeVisible( aRect
, true/*bScrollBar*/ );
1635 const Size
& SvxIconChoiceCtrl_Impl::GetItemSize( IcnViewFieldType eItem
) const
1637 if (eItem
== IcnViewFieldType::Text
)
1638 return aDefaultTextSize
;
1639 return aImageSize
; // IcnViewFieldType::Image
1642 tools::Rectangle
SvxIconChoiceCtrl_Impl::CalcFocusRect( SvxIconChoiceCtrlEntry
* pEntry
)
1644 tools::Rectangle
aBoundRect( GetEntryBoundRect( pEntry
) );
1646 // Remove left margin
1647 if (nWinBits
& WB_DETAILS
)
1648 aBoundRect
.SetPos(Point(0, aBoundRect
.GetPos().Y()));
1653 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl
, VisRectChangedHdl
, Timer
*, void)
1655 aVisRectChangedIdle
.Stop();
1658 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl
, DocRectChangedHdl
, Timer
*, void)
1660 aDocRectChangedIdle
.Stop();
1663 // Draw my own focusrect, because the focusrect of the outputdevice has got the inverted color
1664 // of the background. But what will we see, if the backgroundcolor is gray ? - We will see
1665 // a gray focusrect on a gray background !!!
1667 void SvxIconChoiceCtrl_Impl::ShowFocus ( tools::Rectangle
const & rRect
)
1669 Color
aBkgColor(pView
->GetBackground().GetColor());
1671 sal_uInt16 nColor
= ( aBkgColor
.GetRed() + aBkgColor
.GetGreen() + aBkgColor
.GetBlue() ) / 3;
1673 aPenColor
= COL_BLACK
;
1675 aPenColor
= COL_WHITE
;
1677 aFocus
.aPenColor
= aPenColor
;
1678 aFocus
.aRect
= rRect
;
1681 void SvxIconChoiceCtrl_Impl::DrawFocusRect(vcl::RenderContext
& rRenderContext
, SvxIconChoiceCtrlEntry
* pEntry
)
1683 tools::Rectangle
aRect (CalcFocusRect(pEntry
));
1686 rRenderContext
.SetLineColor(aFocus
.aPenColor
);
1687 rRenderContext
.SetFillColor();
1688 tools::Polygon
aPolygon (aFocus
.aRect
);
1690 LineInfo
aLineInfo(LineStyle::Dash
);
1692 aLineInfo
.SetDashLen(1);
1693 aLineInfo
.SetDotLen(1);
1694 aLineInfo
.SetDistance(1);
1695 aLineInfo
.SetDotCount(1);
1697 rRenderContext
.DrawPolyLine(aPolygon
, aLineInfo
);
1700 bool SvxIconChoiceCtrl_Impl::IsMnemonicChar( sal_Unicode cChar
, sal_uLong
& rPos
) const
1703 const vcl::I18nHelper
& rI18nHelper
= Application::GetSettings().GetUILocaleI18nHelper();
1704 size_t nEntryCount
= GetEntryCount();
1705 for ( size_t i
= 0; i
< nEntryCount
; ++i
)
1707 if ( rI18nHelper
.MatchMnemonic( GetEntry( i
)->GetText(), cChar
) )
1719 IMPL_LINK(SvxIconChoiceCtrl_Impl
, UserEventHdl
, void*, nId
, void )
1721 if( nId
== EVENTID_ADJUST_SCROLLBARS
)
1723 nUserEventAdjustScrBars
= nullptr;
1728 void SvxIconChoiceCtrl_Impl::CancelUserEvents()
1730 if( nUserEventAdjustScrBars
)
1732 Application::RemoveUserEvent( nUserEventAdjustScrBars
);
1733 nUserEventAdjustScrBars
= nullptr;
1737 SvxIconChoiceCtrlEntry
* SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry() const
1739 size_t nCount
= maEntries
.size();
1740 for( size_t nCur
= 0; nCur
< nCount
; nCur
++ )
1742 SvxIconChoiceCtrlEntry
* pEntry
= maEntries
[ nCur
].get();
1743 if( pEntry
->IsSelected() )
1751 sal_Int32
SvxIconChoiceCtrl_Impl::GetEntryListPos( SvxIconChoiceCtrlEntry
const * pEntry
) const
1753 auto it
= std::find_if(maEntries
.begin(), maEntries
.end(),
1754 [pEntry
](auto& rIt
) { return rIt
.get() == pEntry
; });
1755 if (it
!= maEntries
.end())
1756 return std::distance(maEntries
.begin(), it
);
1761 void SvxIconChoiceCtrl_Impl::InitSettings()
1763 const StyleSettings
& rStyleSettings
= pView
->GetSettings().GetStyleSettings();
1765 // unit (from settings) is Point
1766 vcl::Font
aFont( rStyleSettings
.GetFieldFont() );
1767 aFont
.SetColor( rStyleSettings
.GetWindowTextColor() );
1768 pView
->SetPointFont( aFont
);
1769 SetDefaultTextSize();
1771 pView
->SetTextColor( rStyleSettings
.GetFieldTextColor() );
1772 pView
->SetTextFillColor();
1774 pView
->SetBackground( rStyleSettings
.GetFieldColor());
1776 tools::Long nScrBarSize
= rStyleSettings
.GetScrollBarSize();
1777 if( nScrBarSize
== nHorSBarHeight
&& nScrBarSize
== nVerSBarWidth
)
1780 nHorSBarHeight
= nScrBarSize
;
1781 Size
aSize( aHorSBar
->GetSizePixel() );
1782 aSize
.setHeight( nScrBarSize
);
1784 aHorSBar
->SetSizePixel( aSize
);
1786 nVerSBarWidth
= nScrBarSize
;
1787 aSize
= aVerSBar
->GetSizePixel();
1788 aSize
.setWidth( nScrBarSize
);
1790 aVerSBar
->SetSizePixel( aSize
);
1792 Size
aOSize(pView
->GetOutputSizePixel());
1793 PositionScrollBars( aOSize
.Width(), aOSize
.Height() );
1797 bool SvxIconChoiceCtrl_Impl::RequestHelp( const HelpEvent
& rHEvt
)
1799 if ( !(rHEvt
.GetMode() & HelpEventMode::QUICK
) )
1802 Point
aPos( pView
->ScreenToOutputPixel(rHEvt
.GetMousePosPixel() ) );
1803 aPos
-= pView
->GetMapMode().GetOrigin();
1804 SvxIconChoiceCtrlEntry
* pEntry
= GetEntry( aPos
);
1809 OUString sQuickHelpText
= pEntry
->GetQuickHelpText();
1810 tools::Rectangle
aTextRect(CalcTextRect(pEntry
, nullptr));
1811 const OUString aEntryText
= pEntry
->GetText();
1812 if ( ( !aTextRect
.Contains( aPos
) || aEntryText
.isEmpty() ) && sQuickHelpText
.isEmpty() )
1815 tools::Rectangle
aOptTextRect( aTextRect
);
1816 aOptTextRect
.SetBottom( LONG_MAX
);
1817 DrawTextFlags nNewFlags
= nCurTextDrawFlags
;
1818 nNewFlags
&= ~DrawTextFlags( DrawTextFlags::Clip
| DrawTextFlags::EndEllipsis
);
1819 aOptTextRect
= pView
->GetTextRect( aOptTextRect
, aEntryText
, nNewFlags
);
1820 if ( aOptTextRect
!= aTextRect
|| !sQuickHelpText
.isEmpty() )
1822 //aTextRect.Right() = aTextRect.Left() + aRealSize.Width() + 4;
1823 Point
aPt( aOptTextRect
.TopLeft() );
1824 aPt
+= pView
->GetMapMode().GetOrigin();
1825 aPt
= pView
->OutputToScreenPixel( aPt
);
1826 // subtract border of tooltip help
1829 aOptTextRect
.SetPos( aPt
);
1831 if ( !sQuickHelpText
.isEmpty() )
1832 sHelpText
= sQuickHelpText
;
1834 sHelpText
= aEntryText
;
1835 Help::ShowQuickHelp(pView
, aOptTextRect
, sHelpText
, QuickHelpFlags::Left
| QuickHelpFlags::VCenter
);
1841 void SvxIconChoiceCtrl_Impl::DrawHighlightFrame(vcl::RenderContext
& rRenderContext
,
1842 const tools::Rectangle
& rRect
)
1844 DecorationView
aDecoView(&rRenderContext
);
1845 aDecoView
.DrawHighlightFrame(rRect
);
1848 void SvxIconChoiceCtrl_Impl::SetEntryHighlightFrame(SvxIconChoiceCtrlEntry
* pEntry
)
1850 if( pEntry
== pCurHighlightFrame
)
1853 if (pCurHighlightFrame
)
1855 tools::Rectangle
aInvalidationRect(GetEntryBoundRect(pCurHighlightFrame
));
1856 aInvalidationRect
.expand(5);
1857 pCurHighlightFrame
= nullptr;
1858 pView
->Invalidate(aInvalidationRect
);
1861 pCurHighlightFrame
= pEntry
;
1864 tools::Rectangle
aInvalidationRect(GetEntryBoundRect(pEntry
));
1865 aInvalidationRect
.expand(5);
1866 pView
->Invalidate(aInvalidationRect
);
1870 void SvxIconChoiceCtrl_Impl::SetOrigin( const Point
& rPos
)
1872 MapMode
aMapMode( pView
->GetMapMode() );
1873 aMapMode
.SetOrigin( rPos
);
1874 pView
->SetMapMode( aMapMode
);
1877 void SvxIconChoiceCtrl_Impl::CallEventListeners( VclEventId nEvent
, void* pData
)
1879 pView
->CallImplEventListeners( nEvent
, pData
);
1883 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */