bump product version to 7.6.3.2-android
[LibreOffice.git] / vcl / source / control / imivctl1.cxx
blobae297a82e107042769935a1b9cc535c99e231d2c
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 .
21 #include <limits.h>
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"
39 #include <algorithm>
40 #include <memory>
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_SHOW_CURSOR (reinterpret_cast<void*>(1))
50 #define EVENTID_ADJUST_SCROLLBARS (reinterpret_cast<void*>(2))
52 SvxIconChoiceCtrl_Impl::SvxIconChoiceCtrl_Impl(
53 SvtIconChoiceCtrl* pCurView,
54 WinBits nWinStyle
55 ) :
56 aVerSBar( VclPtr<ScrollBar>::Create(pCurView, WB_DRAG | WB_VSCROLL) ),
57 aHorSBar( VclPtr<ScrollBar>::Create(pCurView, WB_DRAG | WB_HSCROLL) ),
58 aScrBarBox( VclPtr<ScrollBarBox>::Create(pCurView) ),
59 aAutoArrangeIdle( "svtools::SvxIconChoiceCtrl_Impl aAutoArrangeIdle" ),
60 aDocRectChangedIdle( "svtools::SvxIconChoiceCtrl_Impl aDocRectChangedIdle" ),
61 aVisRectChangedIdle( "svtools::SvxIconChoiceCtrl_Impl aVisRectChangedIdle" ),
62 aCallSelectHdlIdle( "svtools::SvxIconChoiceCtrl_Impl aCallSelectHdlIdle" ),
63 aImageSize( 32 * pCurView->GetDPIScaleFactor(), 32 * pCurView->GetDPIScaleFactor()),
64 pView(pCurView), nMaxVirtWidth(DEFAULT_MAX_VIRT_WIDTH), nMaxVirtHeight(DEFAULT_MAX_VIRT_HEIGHT),
65 nFlags(IconChoiceFlags::NONE), nUserEventAdjustScrBars(nullptr),
66 pCurHighlightFrame(nullptr), bHighlightFramePressed(false), pHead(nullptr), pCursor(nullptr),
67 pHdlEntry(nullptr),
68 pAnchor(nullptr), eTextMode(SvxIconChoiceCtrlTextMode::Short),
69 eSelectionMode(SelectionMode::Multiple), ePositionMode(SvxIconChoiceCtrlPositionMode::Free),
70 bUpdateMode(true)
72 SetStyle( nWinStyle );
73 pImpCursor.reset( new IcnCursor_Impl( this ) );
74 pGridMap.reset( new IcnGridMap_Impl( this ) );
76 aVerSBar->SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, ScrollUpDownHdl ) );
77 aHorSBar->SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl ) );
79 nHorSBarHeight = aHorSBar->GetSizePixel().Height();
80 nVerSBarWidth = aVerSBar->GetSizePixel().Width();
82 aAutoArrangeIdle.SetPriority( TaskPriority::HIGH_IDLE );
83 aAutoArrangeIdle.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl,AutoArrangeHdl));
85 aCallSelectHdlIdle.SetPriority( TaskPriority::LOWEST );
86 aCallSelectHdlIdle.SetInvokeHandler( LINK(this,SvxIconChoiceCtrl_Impl,CallSelectHdlHdl));
88 aDocRectChangedIdle.SetPriority( TaskPriority::HIGH_IDLE );
89 aDocRectChangedIdle.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl,DocRectChangedHdl));
91 aVisRectChangedIdle.SetPriority( TaskPriority::HIGH_IDLE );
92 aVisRectChangedIdle.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl,VisRectChangedHdl));
94 Clear( true );
95 Size gridSize(100,70);
96 if(pView->GetDPIScaleFactor() > 1)
98 gridSize.setHeight( gridSize.Height() * ( pView->GetDPIScaleFactor()) );
100 SetGrid(gridSize);
103 SvxIconChoiceCtrl_Impl::~SvxIconChoiceCtrl_Impl()
105 Clear(false);
106 CancelUserEvents();
107 pImpCursor.reset();
108 pGridMap.reset();
109 ClearSelectedRectList();
110 m_pColumns.reset();
111 aVerSBar.disposeAndClear();
112 aHorSBar.disposeAndClear();
113 aScrBarBox.disposeAndClear();
116 void SvxIconChoiceCtrl_Impl::Clear( bool bInCtor )
118 nSelectionCount = 0;
119 pCurHighlightFrame = nullptr;
120 CancelUserEvents();
121 ShowCursor( false );
122 bBoundRectsDirty = false;
123 nMaxBoundHeight = 0;
125 pCursor = nullptr;
126 if( !bInCtor )
128 pImpCursor->Clear();
129 pGridMap->Clear();
130 aVirtOutputSize.setWidth( 0 );
131 aVirtOutputSize.setHeight( 0 );
132 Size aSize( pView->GetOutputSizePixel() );
133 nMaxVirtWidth = aSize.Width() - nVerSBarWidth;
134 if( nMaxVirtWidth <= 0 )
135 nMaxVirtWidth = DEFAULT_MAX_VIRT_WIDTH;
136 nMaxVirtHeight = aSize.Height() - nHorSBarHeight;
137 if( nMaxVirtHeight <= 0 )
138 nMaxVirtHeight = DEFAULT_MAX_VIRT_HEIGHT;
139 maZOrderList.clear();
140 SetOrigin( Point() );
141 if( bUpdateMode )
142 pView->Invalidate(InvalidateFlags::NoChildren);
144 AdjustScrollBars();
145 maEntries.clear();
146 DocRectChanged();
147 VisRectChanged();
150 void SvxIconChoiceCtrl_Impl::SetStyle( WinBits nWinStyle )
152 nWinBits = nWinStyle;
153 nCurTextDrawFlags = DRAWTEXT_FLAGS_ICON;
154 if( nWinBits & (WB_SMALLICON | WB_DETAILS) )
155 nCurTextDrawFlags = DRAWTEXT_FLAGS_SMALLICON;
156 if( nWinBits & WB_NOSELECTION )
157 eSelectionMode = SelectionMode::NONE;
158 if( !(nWinStyle & (WB_ALIGN_TOP | WB_ALIGN_LEFT)))
159 nWinBits |= WB_ALIGN_LEFT;
160 if( nWinStyle & WB_DETAILS )
162 if (!m_pColumns)
163 SetColumn( 0, SvxIconChoiceCtrlColumnInfo() );
167 IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollUpDownHdl, ScrollBar*, pScrollBar, void )
169 // arrow up: delta=-1; arrow down: delta=+1
170 Scroll( 0, pScrollBar->GetDelta() );
173 IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl, ScrollBar*, pScrollBar, void )
175 // arrow left: delta=-1; arrow right: delta=+1
176 Scroll( pScrollBar->GetDelta(), 0 );
179 void SvxIconChoiceCtrl_Impl::FontModified()
181 SetDefaultTextSize();
182 ShowCursor( false );
183 ShowCursor( true );
186 void SvxIconChoiceCtrl_Impl::InsertEntry( std::unique_ptr<SvxIconChoiceCtrlEntry> pEntry1, size_t nPos)
188 auto pEntry = pEntry1.get();
190 if ( nPos < maEntries.size() ) {
191 maEntries.insert( maEntries.begin() + nPos, std::move(pEntry1) );
192 } else {
193 maEntries.push_back( std::move(pEntry1) );
196 if( pHead )
197 pEntry->SetBacklink( pHead->pblink );
199 if( (nFlags & IconChoiceFlags::EntryListPosValid) && nPos >= maEntries.size() - 1 )
200 pEntry->nPos = maEntries.size() - 1;
201 else
202 nFlags &= ~IconChoiceFlags::EntryListPosValid;
204 maZOrderList.push_back( pEntry );
205 pImpCursor->Clear();
207 // If the UpdateMode is true, don't set all bounding rectangles to
208 // 'to be checked', but only the bounding rectangle of the new entry.
209 // Thus, don't call InvalidateBoundingRect!
210 pEntry->aRect.SetRight( LONG_MAX );
211 if( bUpdateMode )
213 FindBoundingRect( pEntry );
214 tools::Rectangle aOutputArea( GetOutputRect() );
215 pGridMap->OccupyGrids( pEntry );
216 if( !aOutputArea.Overlaps( pEntry->aRect ) )
217 return; // is invisible
218 pView->Invalidate( pEntry->aRect );
220 else
221 InvalidateBoundingRect( pEntry->aRect );
224 void SvxIconChoiceCtrl_Impl::RemoveEntry(size_t nPos)
226 pImpCursor->Clear();
227 maEntries.erase(maEntries.begin() + nPos);
228 RecalcAllBoundingRectsSmart();
231 tools::Rectangle SvxIconChoiceCtrl_Impl::GetOutputRect() const
233 Point aOrigin( pView->GetMapMode().GetOrigin() );
234 aOrigin *= -1;
235 return tools::Rectangle( aOrigin, aOutputSize );
238 void SvxIconChoiceCtrl_Impl::SetListPositions()
240 if( nFlags & IconChoiceFlags::EntryListPosValid )
241 return;
243 size_t nCount = maEntries.size();
244 for( size_t nCur = 0; nCur < nCount; nCur++ )
246 maEntries[ nCur ]->nPos = nCur;
248 nFlags |= IconChoiceFlags::EntryListPosValid;
251 void SvxIconChoiceCtrl_Impl::SelectEntry( SvxIconChoiceCtrlEntry* pEntry, bool bSelect,
252 bool bAdd )
254 if( eSelectionMode == SelectionMode::NONE )
255 return;
257 if( !bAdd )
259 if ( !( nFlags & IconChoiceFlags::ClearingSelection ) )
261 nFlags |= IconChoiceFlags::ClearingSelection;
262 DeselectAllBut( pEntry );
263 nFlags &= ~IconChoiceFlags::ClearingSelection;
266 if( pEntry->IsSelected() == bSelect )
267 return;
269 pHdlEntry = pEntry;
270 SvxIconViewFlags nEntryFlags = pEntry->GetFlags();
271 if( bSelect )
273 nEntryFlags |= SvxIconViewFlags::SELECTED;
274 pEntry->AssignFlags( nEntryFlags );
275 nSelectionCount++;
276 CallSelectHandler();
278 else
280 nEntryFlags &= ~SvxIconViewFlags::SELECTED;
281 pEntry->AssignFlags( nEntryFlags );
282 nSelectionCount--;
283 CallSelectHandler();
285 EntrySelected( pEntry, bSelect );
288 void SvxIconChoiceCtrl_Impl::EntrySelected(SvxIconChoiceCtrlEntry* pEntry, bool bSelect)
290 // When using SingleSelection, make sure that the cursor is always placed
291 // over the (only) selected entry. (But only if a cursor exists.)
292 if (bSelect && pCursor &&
293 eSelectionMode == SelectionMode::Single &&
294 pEntry != pCursor)
296 SetCursor(pEntry);
299 // Not when dragging though, else the loop in SelectRect doesn't work
300 // correctly!
301 if (!(nFlags & IconChoiceFlags::SelectingRect))
302 ToTop(pEntry);
303 if (bUpdateMode)
305 if (pEntry == pCursor)
306 ShowCursor(false);
307 pView->Invalidate(CalcFocusRect(pEntry));
308 if (pEntry == pCursor)
309 ShowCursor(true);
312 // #i101012# emit vcl event LISTBOX_SELECT only in case that the given entry is selected.
313 if (bSelect)
315 CallEventListeners(VclEventId::ListboxSelect, pEntry);
319 void SvxIconChoiceCtrl_Impl::ResetVirtSize()
321 aVirtOutputSize.setWidth( 0 );
322 aVirtOutputSize.setHeight( 0 );
323 const size_t nCount = maEntries.size();
324 for( size_t nCur = 0; nCur < nCount; nCur++ )
326 SvxIconChoiceCtrlEntry* pCur = maEntries[ nCur ].get();
327 pCur->ClearFlags( SvxIconViewFlags::POS_MOVED );
328 if( pCur->IsPosLocked() )
330 // adapt (among others) VirtSize
331 if( !IsBoundingRectValid( pCur->aRect ) )
332 FindBoundingRect( pCur );
333 else
334 AdjustVirtSize( pCur->aRect );
336 else
337 InvalidateBoundingRect( pCur->aRect );
340 if( !(nWinBits & (WB_NOVSCROLL | WB_NOHSCROLL)) )
342 Size aRealOutputSize( pView->GetOutputSizePixel() );
343 if( aVirtOutputSize.Width() < aRealOutputSize.Width() ||
344 aVirtOutputSize.Height() < aRealOutputSize.Height() )
346 sal_uLong nGridCount = IcnGridMap_Impl::GetGridCount(
347 aRealOutputSize, static_cast<sal_uInt16>(nGridDX), static_cast<sal_uInt16>(nGridDY) );
348 if( nGridCount < nCount )
350 if( nWinBits & WB_ALIGN_TOP )
351 nMaxVirtWidth = aRealOutputSize.Width() - nVerSBarWidth;
352 else // WB_ALIGN_LEFT
353 nMaxVirtHeight = aRealOutputSize.Height() - nHorSBarHeight;
358 pImpCursor->Clear();
359 pGridMap->Clear();
360 VisRectChanged();
363 void SvxIconChoiceCtrl_Impl::AdjustVirtSize( const tools::Rectangle& rRect )
365 tools::Long nHeightOffs = 0;
366 tools::Long nWidthOffs = 0;
368 if( aVirtOutputSize.Width() < (rRect.Right()+LROFFS_WINBORDER) )
369 nWidthOffs = (rRect.Right()+LROFFS_WINBORDER) - aVirtOutputSize.Width();
371 if( aVirtOutputSize.Height() < (rRect.Bottom()+TBOFFS_WINBORDER) )
372 nHeightOffs = (rRect.Bottom()+TBOFFS_WINBORDER) - aVirtOutputSize.Height();
374 if( !(nWidthOffs || nHeightOffs) )
375 return;
377 Range aRange;
378 aVirtOutputSize.AdjustWidth(nWidthOffs );
379 aRange.Max() = aVirtOutputSize.Width();
380 aHorSBar->SetRange( aRange );
382 aVirtOutputSize.AdjustHeight(nHeightOffs );
383 aRange.Max() = aVirtOutputSize.Height();
384 aVerSBar->SetRange( aRange );
386 pImpCursor->Clear();
387 pGridMap->OutputSizeChanged();
388 AdjustScrollBars();
389 DocRectChanged();
392 void SvxIconChoiceCtrl_Impl::InitPredecessors()
394 DBG_ASSERT(!pHead,"SvxIconChoiceCtrl_Impl::InitPredecessors() >> Already initialized");
395 size_t nCount = maEntries.size();
396 if( nCount )
398 SvxIconChoiceCtrlEntry* pPrev = maEntries[ 0 ].get();
399 for( size_t nCur = 1; nCur <= nCount; nCur++ )
401 pPrev->ClearFlags( SvxIconViewFlags::POS_LOCKED | SvxIconViewFlags::POS_MOVED );
403 SvxIconChoiceCtrlEntry* pNext;
404 if( nCur == nCount )
405 pNext = maEntries[ 0 ].get();
406 else
407 pNext = maEntries[ nCur ].get();
408 pPrev->pflink = pNext;
409 pNext->pblink = pPrev;
410 pPrev = pNext;
412 pHead = maEntries[ 0 ].get();
414 else
415 pHead = nullptr;
418 void SvxIconChoiceCtrl_Impl::ClearPredecessors()
420 if( pHead )
422 size_t nCount = maEntries.size();
423 for( size_t nCur = 0; nCur < nCount; nCur++ )
425 SvxIconChoiceCtrlEntry* pCur = maEntries[ nCur ].get();
426 pCur->pflink = nullptr;
427 pCur->pblink = nullptr;
429 pHead = nullptr;
433 void SvxIconChoiceCtrl_Impl::Arrange( bool bKeepPredecessors, tools::Long nSetMaxVirtWidth, tools::Long nSetMaxVirtHeight )
435 if ( nSetMaxVirtWidth != 0 )
436 nMaxVirtWidth = nSetMaxVirtWidth;
437 else
438 nMaxVirtWidth = aOutputSize.Width();
440 if ( nSetMaxVirtHeight != 0 )
441 nMaxVirtHeight = nSetMaxVirtHeight;
442 else
443 nMaxVirtHeight = aOutputSize.Height();
445 ImpArrange( bKeepPredecessors );
448 void SvxIconChoiceCtrl_Impl::ImpArrange( bool bKeepPredecessors )
450 static const Point aEmptyPoint;
452 bool bOldUpdate = bUpdateMode;
453 tools::Rectangle aCurOutputArea( GetOutputRect() );
454 if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint )
455 bUpdateMode = false;
456 aAutoArrangeIdle.Stop();
457 nFlags |= IconChoiceFlags::Arranging;
458 ShowCursor( false );
459 ResetVirtSize();
460 if( !bKeepPredecessors )
461 ClearPredecessors();
462 bBoundRectsDirty = false;
463 SetOrigin( Point() );
464 VisRectChanged();
465 RecalcAllBoundingRectsSmart();
466 // TODO: the invalidation in the detail view should be more intelligent
467 //if( !(nWinBits & WB_DETAILS ))
468 pView->Invalidate( InvalidateFlags::NoChildren );
469 nFlags &= ~IconChoiceFlags::Arranging;
470 if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint )
472 MakeVisible( aCurOutputArea );
473 SetUpdateMode( bOldUpdate );
475 ShowCursor( true );
478 void SvxIconChoiceCtrl_Impl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
480 #if defined(OV_DRAWGRID)
481 Color aOldColor (rRenderContext.GetLineColor());
482 Color aCOL_BLACK);
483 rRenderContext.SetLineColor( aColor );
484 Point aOffs(rRenderContext.GetMapMode().GetOrigin());
485 Size aXSize(GetOutputSizePixel());
487 Point aStart(LROFFS_WINBORDER, 0);
488 Point aEnd(LROFFS_WINBORDER, aXSize.Height());
489 aStart -= aOffs;
490 aEnd -= aOffs;
491 rRenderContext.DrawLine(aStart, aEnd);
494 Point aStart(0, TBOFFS_WINBORDER);
495 Point aEnd(aXSize.Width(), TBOFFS_WINBORDER);
496 aStart -= aOffs;
497 aEnd -= aOffs;
498 rRenderContext.DrawLine(aStart, aEnd);
501 for (tools::Long nDX = nGridDX; nDX <= aXSize.Width(); nDX += nGridDX)
503 Point aStart( nDX+LROFFS_WINBORDER, 0 );
504 Point aEnd( nDX+LROFFS_WINBORDER, aXSize.Height());
505 aStart -= aOffs;
506 aEnd -= aOffs;
507 rRenderContext.DrawLine(aStart, aEnd);
509 for (tools::Long nDY = nGridDY; nDY <= aXSize.Height(); nDY += nGridDY)
511 Point aStart(0, nDY + TBOFFS_WINBORDER);
512 Point aEnd(aXSize.Width(), nDY + TBOFFS_WINBORDER);
513 aStart -= aOffs;
514 aEnd -= aOffs;
515 rRenderContext.DrawLine(aStart, aEnd);
517 rRenderContext.SetLineColor(aOldColor);
518 #endif
520 if (!maEntries.size())
521 return;
522 if (!pCursor)
524 // set cursor to item with focus-flag
525 bool bfound = false;
526 for (sal_Int32 i = 0; i < pView->GetEntryCount() && !bfound; i++)
528 SvxIconChoiceCtrlEntry* pEntry = pView->GetEntry(i);
529 if (pEntry->IsFocused())
531 pCursor = pEntry;
532 bfound = true;
536 if (!bfound)
537 pCursor = maEntries[ 0 ].get();
540 size_t nCount = maZOrderList.size();
541 if (!nCount)
542 return;
544 rRenderContext.Push(vcl::PushFlags::CLIPREGION);
545 rRenderContext.SetClipRegion(vcl::Region(rRect));
547 std::vector< SvxIconChoiceCtrlEntry* > aNewZOrderList;
548 std::vector< SvxIconChoiceCtrlEntry* > aPaintedEntries;
550 size_t nPos = 0;
551 while(nCount)
553 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[nPos];
554 const tools::Rectangle& rBoundRect = GetEntryBoundRect(pEntry);
555 if (rRect.Overlaps(rBoundRect))
557 PaintEntry(pEntry, rBoundRect.TopLeft(), rRenderContext);
558 // set entries to Top if they are being repainted
559 aPaintedEntries.push_back(pEntry);
561 else
562 aNewZOrderList.push_back(pEntry);
564 nCount--;
565 nPos++;
567 maZOrderList = std::move( aNewZOrderList );
568 maZOrderList.insert(maZOrderList.end(), aPaintedEntries.begin(), aPaintedEntries.end());
570 rRenderContext.Pop();
573 void SvxIconChoiceCtrl_Impl::RepaintSelectedEntries()
575 const size_t nCount = maZOrderList.size();
576 if (!nCount)
577 return;
579 tools::Rectangle aOutRect(GetOutputRect());
580 for (size_t nCur = 0; nCur < nCount; nCur++)
582 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[nCur];
583 if (pEntry->GetFlags() & SvxIconViewFlags::SELECTED)
585 const tools::Rectangle& rBoundRect = GetEntryBoundRect(pEntry);
586 if (aOutRect.Overlaps(rBoundRect))
587 pView->Invalidate(rBoundRect);
592 void SvxIconChoiceCtrl_Impl::InitScrollBarBox()
594 aScrBarBox->SetSizePixel( Size(nVerSBarWidth-1, nHorSBarHeight-1) );
595 Size aSize( pView->GetOutputSizePixel() );
596 aScrBarBox->SetPosPixel( Point(aSize.Width()-nVerSBarWidth+1, aSize.Height()-nHorSBarHeight+1));
599 bool SvxIconChoiceCtrl_Impl::MouseButtonDown( const MouseEvent& rMEvt)
601 bool bHandled = true;
602 bHighlightFramePressed = false;
603 bool bGotFocus = (!pView->HasFocus() && !(nWinBits & WB_NOPOINTERFOCUS));
604 if( !(nWinBits & WB_NOPOINTERFOCUS) )
605 pView->GrabFocus();
607 Point aDocPos( rMEvt.GetPosPixel() );
608 if(aDocPos.X()>=aOutputSize.Width() || aDocPos.Y()>=aOutputSize.Height())
609 return false;
610 ToDocPos( aDocPos );
611 SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, true );
612 if( pEntry )
613 MakeEntryVisible( pEntry, false );
615 if( rMEvt.IsShift() && eSelectionMode != SelectionMode::Single )
617 if( pEntry )
618 SetCursor_Impl( pCursor, pEntry, rMEvt.IsMod1(), rMEvt.IsShift() );
619 return true;
622 if( pAnchor && (rMEvt.IsShift() || rMEvt.IsMod1())) // keyboard selection?
624 DBG_ASSERT(eSelectionMode != SelectionMode::Single,"Invalid selection mode");
625 if( rMEvt.IsMod1() )
626 nFlags |= IconChoiceFlags::AddMode;
628 if( rMEvt.IsShift() )
630 tools::Rectangle aRect( GetEntryBoundRect( pAnchor ));
631 if( pEntry )
632 aRect.Union( GetEntryBoundRect( pEntry ) );
633 else
635 tools::Rectangle aTempRect( aDocPos, Size(1,1));
636 aRect.Union( aTempRect );
638 aCurSelectionRect = aRect;
639 SelectRect( aRect, bool(nFlags & IconChoiceFlags::AddMode), &aSelectedRectList );
641 else if( rMEvt.IsMod1() )
643 AddSelectedRect( aCurSelectionRect );
644 pAnchor = nullptr;
645 aCurSelectionRect.SetPos( aDocPos );
648 if( !pEntry && !(nWinBits & WB_NODRAGSELECTION))
649 pView->StartTracking( StartTrackingFlags::ScrollRepeat );
650 return true;
652 else
654 if( !pEntry )
656 if( eSelectionMode == SelectionMode::Multiple )
658 if( !rMEvt.IsMod1() ) // Ctrl
660 if( !bGotFocus )
662 SetNoSelection();
663 ClearSelectedRectList();
666 else
667 nFlags |= IconChoiceFlags::AddMode;
668 aCurSelectionRect.SetPos( aDocPos );
669 pView->StartTracking( StartTrackingFlags::ScrollRepeat );
671 else
672 bHandled = false;
673 return bHandled;
676 bool bSelected = pEntry->IsSelected();
678 if( rMEvt.GetClicks() == 2 )
680 DeselectAllBut( pEntry );
681 SelectEntry( pEntry, true, false );
682 pHdlEntry = pEntry;
683 pView->ClickIcon();
685 else
687 // Inplace-Editing ?
688 if( rMEvt.IsMod2() ) // Alt?
691 else if( eSelectionMode == SelectionMode::Single )
693 DeselectAllBut( pEntry );
694 SetCursor( pEntry );
696 else if( eSelectionMode == SelectionMode::NONE )
698 if( rMEvt.IsLeft() && (nWinBits & WB_HIGHLIGHTFRAME) )
700 pCurHighlightFrame = nullptr; // force repaint of frame
701 bHighlightFramePressed = true;
702 SetEntryHighlightFrame( pEntry, true );
705 else
707 if( !rMEvt.GetModifier() && rMEvt.IsLeft() )
709 if( !bSelected )
711 DeselectAllBut( pEntry );
712 SetCursor( pEntry );
713 SelectEntry( pEntry, true, false );
715 else
717 // deselect only in the Up, if the Move happened via D&D!
718 nFlags |= IconChoiceFlags::DownDeselect;
721 else if( rMEvt.IsMod1() )
722 nFlags |= IconChoiceFlags::DownCtrl;
725 return bHandled;
728 bool SvxIconChoiceCtrl_Impl::MouseButtonUp( const MouseEvent& rMEvt )
730 bool bHandled = false;
731 if( rMEvt.IsRight() && (nFlags & (IconChoiceFlags::DownCtrl | IconChoiceFlags::DownDeselect) ))
733 nFlags &= ~IconChoiceFlags(IconChoiceFlags::DownCtrl | IconChoiceFlags::DownDeselect);
734 bHandled = true;
737 Point aDocPos( rMEvt.GetPosPixel() );
738 ToDocPos( aDocPos );
739 SvxIconChoiceCtrlEntry* pDocEntry = GetEntry( aDocPos );
740 if( pDocEntry )
742 if( nFlags & IconChoiceFlags::DownCtrl )
744 // Ctrl & MultiSelection
745 ToggleSelection( pDocEntry );
746 SetCursor( pDocEntry );
747 bHandled = true;
749 else if( nFlags & IconChoiceFlags::DownDeselect )
751 DeselectAllBut( pDocEntry );
752 SetCursor( pDocEntry );
753 SelectEntry( pDocEntry, true, false );
754 bHandled = true;
758 nFlags &= ~IconChoiceFlags(IconChoiceFlags::DownCtrl | IconChoiceFlags::DownDeselect);
760 if((nWinBits & WB_HIGHLIGHTFRAME) && bHighlightFramePressed && pCurHighlightFrame)
762 bHandled = true;
763 SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame;
764 pCurHighlightFrame = nullptr; // force repaint of frame
765 bHighlightFramePressed = false;
766 SetEntryHighlightFrame( pEntry, true );
768 pHdlEntry = pCurHighlightFrame;
769 pView->ClickIcon();
771 // set focus on Icon
772 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
773 SetCursor_Impl( pOldCursor, pHdlEntry, false, false );
775 pHdlEntry = nullptr;
777 return bHandled;
780 bool SvxIconChoiceCtrl_Impl::MouseMove( const MouseEvent& rMEvt )
782 const Point aDocPos( pView->PixelToLogic(rMEvt.GetPosPixel()) );
784 if( pView->IsTracking() )
785 return false;
786 else if( nWinBits & WB_HIGHLIGHTFRAME )
788 SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, true );
789 SetEntryHighlightFrame( pEntry, false );
791 else
792 return false;
793 return true;
796 void SvxIconChoiceCtrl_Impl::SetCursor_Impl( SvxIconChoiceCtrlEntry* pOldCursor,
797 SvxIconChoiceCtrlEntry* pNewCursor, bool bMod1, bool bShift )
799 if( !pNewCursor )
800 return;
802 SvxIconChoiceCtrlEntry* pFilterEntry = nullptr;
803 bool bDeselectAll = false;
804 if( eSelectionMode != SelectionMode::Single )
806 if( !bMod1 && !bShift )
807 bDeselectAll = true;
808 else if( bShift && !bMod1 && !pAnchor )
810 bDeselectAll = true;
811 pFilterEntry = pOldCursor;
814 if( bDeselectAll )
815 DeselectAllBut( pFilterEntry );
816 ShowCursor( false );
817 MakeEntryVisible( pNewCursor );
818 SetCursor( pNewCursor );
819 if( bMod1 && !bShift )
821 if( pAnchor )
823 AddSelectedRect( pAnchor, pOldCursor );
824 pAnchor = nullptr;
827 else if( bShift )
829 if( !pAnchor )
830 pAnchor = pOldCursor;
831 if ( nWinBits & WB_ALIGN_LEFT )
832 SelectRange( pAnchor, pNewCursor, bool(nFlags & IconChoiceFlags::AddMode) );
833 else
834 SelectRect(pAnchor,pNewCursor, bool(nFlags & IconChoiceFlags::AddMode), &aSelectedRectList);
836 else
838 SelectEntry( pCursor, true, false );
839 aCurSelectionRect = GetEntryBoundRect( pCursor );
840 CallEventListeners( VclEventId::ListboxSelect, pCursor );
844 bool SvxIconChoiceCtrl_Impl::KeyInput( const KeyEvent& rKEvt )
846 bool bMod2 = rKEvt.GetKeyCode().IsMod2();
847 sal_Unicode cChar = rKEvt.GetCharCode();
848 sal_uLong nPos = sal_uLong(-1);
849 if ( bMod2 && cChar && IsMnemonicChar( cChar, nPos ) )
851 // shortcut is clicked
852 SvxIconChoiceCtrlEntry* pNewCursor = GetEntry( nPos );
853 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
854 if ( pNewCursor != pOldCursor )
855 SetCursor_Impl( pOldCursor, pNewCursor, false, false );
856 return true;
859 if ( bMod2 )
860 // no actions with <ALT>
861 return false;
863 bool bKeyUsed = true;
864 bool bMod1 = rKEvt.GetKeyCode().IsMod1();
865 bool bShift = rKEvt.GetKeyCode().IsShift();
867 if( eSelectionMode == SelectionMode::Single || eSelectionMode == SelectionMode::NONE)
869 bShift = false;
870 bMod1 = false;
873 if( bMod1 )
874 nFlags |= IconChoiceFlags::AddMode;
876 SvxIconChoiceCtrlEntry* pNewCursor;
877 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
879 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
880 switch( nCode )
882 case KEY_UP:
883 case KEY_PAGEUP:
884 if( pCursor )
886 MakeEntryVisible( pCursor );
887 if( nCode == KEY_UP )
888 pNewCursor = pImpCursor->GoUpDown(pCursor,false);
889 else
890 pNewCursor = pImpCursor->GoPageUpDown(pCursor,false);
891 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
892 if( !pNewCursor )
894 tools::Rectangle aRect( GetEntryBoundRect( pCursor ) );
895 if( aRect.Top())
897 aRect.AdjustBottom( -(aRect.Top()) );
898 aRect.SetTop( 0 );
899 MakeVisible( aRect );
903 break;
905 case KEY_DOWN:
906 case KEY_PAGEDOWN:
907 if( pCursor )
909 if( nCode == KEY_DOWN )
910 pNewCursor=pImpCursor->GoUpDown( pCursor,true );
911 else
912 pNewCursor=pImpCursor->GoPageUpDown( pCursor,true );
913 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
915 break;
917 case KEY_RIGHT:
918 if( pCursor )
920 pNewCursor=pImpCursor->GoLeftRight(pCursor,true );
921 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
923 break;
925 case KEY_LEFT:
926 if( pCursor )
928 MakeEntryVisible( pCursor );
929 pNewCursor = pImpCursor->GoLeftRight(pCursor,false );
930 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
931 if( !pNewCursor )
933 tools::Rectangle aRect( GetEntryBoundRect(pCursor));
934 if( aRect.Left() )
936 aRect.AdjustRight( -(aRect.Left()) );
937 aRect.SetLeft( 0 );
938 MakeVisible( aRect );
942 break;
944 case KEY_F2:
945 if( bMod1 || bShift )
946 bKeyUsed = false;
947 break;
949 case KEY_F8:
950 if( rKEvt.GetKeyCode().IsShift() )
952 if( nFlags & IconChoiceFlags::AddMode )
953 nFlags &= ~IconChoiceFlags::AddMode;
954 else
955 nFlags |= IconChoiceFlags::AddMode;
957 else
958 bKeyUsed = false;
959 break;
961 case KEY_SPACE:
962 if( pCursor && eSelectionMode != SelectionMode::Single )
964 if( !bMod1 )
966 //SelectAll( false );
967 SetNoSelection();
968 ClearSelectedRectList();
970 // click Icon with spacebar
971 SetEntryHighlightFrame( GetCurEntry(), true );
972 pView->ClickIcon();
973 pHdlEntry = pCurHighlightFrame;
974 pCurHighlightFrame=nullptr;
976 else
977 ToggleSelection( pCursor );
979 break;
981 #ifdef DBG_UTIL
982 case KEY_F10:
983 if( rKEvt.GetKeyCode().IsShift() )
985 if( pCursor )
986 pView->SetEntryTextMode( SvxIconChoiceCtrlTextMode::Full, pCursor );
988 if( rKEvt.GetKeyCode().IsMod1() )
990 if( pCursor )
991 pView->SetEntryTextMode( SvxIconChoiceCtrlTextMode::Short, pCursor );
993 break;
994 #endif
996 case KEY_ADD:
997 case KEY_DIVIDE :
998 case KEY_A:
999 if( bMod1 && (eSelectionMode != SelectionMode::Single))
1000 SelectAll();
1001 else
1002 bKeyUsed = false;
1003 break;
1005 case KEY_SUBTRACT:
1006 case KEY_COMMA :
1007 if( bMod1 )
1008 SetNoSelection();
1009 else
1010 bKeyUsed = false;
1011 break;
1013 case KEY_RETURN:
1014 if( !bMod1 )
1015 bKeyUsed = false;
1016 break;
1018 case KEY_END:
1019 if( pCursor )
1021 pNewCursor = maEntries.back().get();
1022 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
1024 break;
1026 case KEY_HOME:
1027 if( pCursor )
1029 pNewCursor = maEntries[ 0 ].get();
1030 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
1032 break;
1034 default:
1035 bKeyUsed = false;
1038 return bKeyUsed;
1041 // recalculate TopLeft of scrollbars (but not their sizes!)
1042 void SvxIconChoiceCtrl_Impl::PositionScrollBars( tools::Long nRealWidth, tools::Long nRealHeight )
1044 // horizontal scrollbar
1045 Point aPos( 0, nRealHeight );
1046 aPos.AdjustY( -nHorSBarHeight );
1048 if( aHorSBar->GetPosPixel() != aPos )
1049 aHorSBar->SetPosPixel( aPos );
1051 // vertical scrollbar
1052 aPos.setX( nRealWidth ); aPos.setY( 0 );
1053 aPos.AdjustX( -nVerSBarWidth );
1054 aPos.AdjustX( 1 );
1055 aPos.AdjustY( -1 );
1057 if( aVerSBar->GetPosPixel() != aPos )
1058 aVerSBar->SetPosPixel( aPos );
1061 void SvxIconChoiceCtrl_Impl::AdjustScrollBars()
1063 tools::Long nVirtHeight = aVirtOutputSize.Height();
1064 tools::Long nVirtWidth = aVirtOutputSize.Width();
1066 Size aOSize( pView->Control::GetOutputSizePixel() );
1067 tools::Long nRealHeight = aOSize.Height();
1068 tools::Long nRealWidth = aOSize.Width();
1070 PositionScrollBars( nRealWidth, nRealHeight );
1072 const MapMode& rMapMode = pView->GetMapMode();
1073 Point aOrigin( rMapMode.GetOrigin() );
1075 tools::Long nVisibleWidth;
1076 if( nRealWidth > nVirtWidth )
1077 nVisibleWidth = nVirtWidth + aOrigin.X();
1078 else
1079 nVisibleWidth = nRealWidth;
1081 tools::Long nVisibleHeight;
1082 if( nRealHeight > nVirtHeight )
1083 nVisibleHeight = nVirtHeight + aOrigin.Y();
1084 else
1085 nVisibleHeight = nRealHeight;
1087 bool bVerSBar = ( nWinBits & WB_VSCROLL ) != 0;
1088 bool bHorSBar = ( nWinBits & WB_HSCROLL ) != 0;
1089 bool bNoVerSBar = ( nWinBits & WB_NOVSCROLL ) != 0;
1090 bool bNoHorSBar = ( nWinBits & WB_NOHSCROLL ) != 0;
1092 sal_uInt16 nResult = 0;
1093 if( nVirtHeight )
1095 // activate vertical scrollbar?
1096 if( !bNoVerSBar && (bVerSBar || ( nVirtHeight > nVisibleHeight)) )
1098 nResult = 0x0001;
1099 nRealWidth -= nVerSBarWidth;
1101 if( nRealWidth > nVirtWidth )
1102 nVisibleWidth = nVirtWidth + aOrigin.X();
1103 else
1104 nVisibleWidth = nRealWidth;
1106 // activate horizontal scrollbar?
1107 if( !bNoHorSBar && (bHorSBar || (nVirtWidth > nVisibleWidth)) )
1109 nResult |= 0x0002;
1110 nRealHeight -= nHorSBarHeight;
1112 if( nRealHeight > nVirtHeight )
1113 nVisibleHeight = nVirtHeight + aOrigin.Y();
1114 else
1115 nVisibleHeight = nRealHeight;
1117 // do we need a vertical scrollbar after all?
1118 if( !(nResult & 0x0001) && // only if not already there
1119 ( !bNoVerSBar && ((nVirtHeight > nVisibleHeight) || bVerSBar)) )
1121 nResult = 3; // both turned on
1122 nRealWidth -= nVerSBarWidth;
1124 if( nRealWidth > nVirtWidth )
1125 nVisibleWidth = nVirtWidth + aOrigin.X();
1126 else
1127 nVisibleWidth = nRealWidth;
1132 // size vertical scrollbar
1133 tools::Long nThumb = aVerSBar->GetThumbPos();
1134 Size aSize( nVerSBarWidth, nRealHeight );
1135 aSize.AdjustHeight(2 );
1136 if( aSize != aVerSBar->GetSizePixel() )
1137 aVerSBar->SetSizePixel( aSize );
1138 aVerSBar->SetVisibleSize( nVisibleHeight );
1139 aVerSBar->SetPageSize( GetScrollBarPageSize( nVisibleHeight ));
1141 if( nResult & 0x0001 )
1143 aVerSBar->SetThumbPos( nThumb );
1144 aVerSBar->Show();
1146 else
1148 aVerSBar->SetThumbPos( 0 );
1149 aVerSBar->Hide();
1152 // size horizontal scrollbar
1153 nThumb = aHorSBar->GetThumbPos();
1154 aSize.setWidth( nRealWidth );
1155 aSize.setHeight( nHorSBarHeight );
1156 aSize.AdjustWidth( 1 );
1157 if( nResult & 0x0001 ) // vertical scrollbar?
1159 aSize.AdjustWidth( 1 );
1160 nRealWidth++;
1162 if( aSize != aHorSBar->GetSizePixel() )
1163 aHorSBar->SetSizePixel( aSize );
1164 aHorSBar->SetVisibleSize( nVisibleWidth );
1165 aHorSBar->SetPageSize( GetScrollBarPageSize(nVisibleWidth ));
1166 if( nResult & 0x0002 )
1168 aHorSBar->SetThumbPos( nThumb );
1169 aHorSBar->Show();
1171 else
1173 aHorSBar->SetThumbPos( 0 );
1174 aHorSBar->Hide();
1177 aOutputSize.setWidth( nRealWidth );
1178 if( nResult & 0x0002 ) // horizontal scrollbar ?
1179 nRealHeight++; // because lower border is clipped
1180 aOutputSize.setHeight( nRealHeight );
1182 if( (nResult & (0x0001|0x0002)) == (0x0001|0x0002) )
1183 aScrBarBox->Show();
1184 else
1185 aScrBarBox->Hide();
1188 void SvxIconChoiceCtrl_Impl::Resize()
1190 InitScrollBarBox();
1191 aOutputSize = pView->GetOutputSizePixel();
1192 pImpCursor->Clear();
1193 pGridMap->OutputSizeChanged();
1195 const Size& rSize = pView->Control::GetOutputSizePixel();
1196 PositionScrollBars( rSize.Width(), rSize.Height() );
1197 // The scrollbars are shown/hidden asynchronously, so derived classes can
1198 // do an Arrange during Resize, without the scrollbars suddenly turning
1199 // on and off again.
1200 // If an event is already underway, we don't need to send a new one, at least
1201 // as long as there is only one event type.
1202 if ( ! nUserEventAdjustScrBars )
1203 nUserEventAdjustScrBars =
1204 Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl, UserEventHdl),
1205 EVENTID_ADJUST_SCROLLBARS);
1207 VisRectChanged();
1210 bool SvxIconChoiceCtrl_Impl::CheckHorScrollBar()
1212 if( maZOrderList.empty() || !aHorSBar->IsVisible() )
1213 return false;
1214 const MapMode& rMapMode = pView->GetMapMode();
1215 Point aOrigin( rMapMode.GetOrigin() );
1216 if(!( nWinBits & WB_HSCROLL) && !aOrigin.X() )
1218 tools::Long nWidth = aOutputSize.Width();
1219 const size_t nCount = maZOrderList.size();
1220 tools::Long nMostRight = 0;
1221 for( size_t nCur = 0; nCur < nCount; nCur++ )
1223 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[ nCur ];
1224 tools::Long nRight = GetEntryBoundRect(pEntry).Right();
1225 if( nRight > nWidth )
1226 return false;
1227 if( nRight > nMostRight )
1228 nMostRight = nRight;
1230 aHorSBar->Hide();
1231 aOutputSize.AdjustHeight(nHorSBarHeight );
1232 aVirtOutputSize.setWidth( nMostRight );
1233 aHorSBar->SetThumbPos( 0 );
1234 Range aRange;
1235 aRange.Max() = nMostRight - 1;
1236 aHorSBar->SetRange( aRange );
1237 if( aVerSBar->IsVisible() )
1239 Size aSize( aVerSBar->GetSizePixel());
1240 aSize.AdjustHeight(nHorSBarHeight );
1241 aVerSBar->SetSizePixel( aSize );
1243 return true;
1245 return false;
1248 bool SvxIconChoiceCtrl_Impl::CheckVerScrollBar()
1250 if( maZOrderList.empty() || !aVerSBar->IsVisible() )
1251 return false;
1252 const MapMode& rMapMode = pView->GetMapMode();
1253 Point aOrigin( rMapMode.GetOrigin() );
1254 if(!( nWinBits & WB_VSCROLL) && !aOrigin.Y() )
1256 tools::Long nDeepest = 0;
1257 tools::Long nHeight = aOutputSize.Height();
1258 const size_t nCount = maZOrderList.size();
1259 for( size_t nCur = 0; nCur < nCount; nCur++ )
1261 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[ nCur ];
1262 tools::Long nBottom = GetEntryBoundRect(pEntry).Bottom();
1263 if( nBottom > nHeight )
1264 return false;
1265 if( nBottom > nDeepest )
1266 nDeepest = nBottom;
1268 aVerSBar->Hide();
1269 aOutputSize.AdjustWidth(nVerSBarWidth );
1270 aVirtOutputSize.setHeight( nDeepest );
1271 aVerSBar->SetThumbPos( 0 );
1272 Range aRange;
1273 aRange.Max() = nDeepest - 1;
1274 aVerSBar->SetRange( aRange );
1275 if( aHorSBar->IsVisible() )
1277 Size aSize( aHorSBar->GetSizePixel());
1278 aSize.AdjustWidth(nVerSBarWidth );
1279 aHorSBar->SetSizePixel( aSize );
1281 return true;
1283 return false;
1287 // hides scrollbars if they're unnecessary
1288 void SvxIconChoiceCtrl_Impl::CheckScrollBars()
1290 CheckVerScrollBar();
1291 if( CheckHorScrollBar() )
1292 CheckVerScrollBar();
1293 if( aVerSBar->IsVisible() && aHorSBar->IsVisible() )
1294 aScrBarBox->Show();
1295 else
1296 aScrBarBox->Hide();
1300 void SvxIconChoiceCtrl_Impl::GetFocus()
1302 RepaintSelectedEntries();
1303 if( pCursor )
1305 pCursor->SetFlags( SvxIconViewFlags::FOCUSED );
1306 ShowCursor( true );
1310 void SvxIconChoiceCtrl_Impl::LoseFocus()
1312 if( pCursor )
1313 pCursor->ClearFlags( SvxIconViewFlags::FOCUSED );
1314 ShowCursor( false );
1316 // HideFocus ();
1317 // pView->Invalidate ( aFocus.aRect );
1319 RepaintSelectedEntries();
1322 void SvxIconChoiceCtrl_Impl::SetUpdateMode( bool bUpdate )
1324 if( bUpdate != bUpdateMode )
1326 bUpdateMode = bUpdate;
1327 if( bUpdate )
1329 AdjustScrollBars();
1330 pImpCursor->Clear();
1331 pGridMap->Clear();
1332 pView->Invalidate(InvalidateFlags::NoChildren);
1337 // priorities of the emphasis: bSelected
1338 void SvxIconChoiceCtrl_Impl::PaintEmphasis(const tools::Rectangle& rTextRect, bool bSelected,
1339 vcl::RenderContext& rRenderContext)
1341 Color aOldFillColor(rRenderContext.GetFillColor());
1343 bool bSolidTextRect = false;
1345 if (!bSelected)
1347 const Color& rFillColor = rRenderContext.GetFont().GetFillColor();
1348 rRenderContext.SetFillColor(rFillColor);
1349 if (rFillColor != COL_TRANSPARENT)
1350 bSolidTextRect = true;
1353 // draw text rectangle
1354 if (bSolidTextRect)
1356 rRenderContext.DrawRect(rTextRect);
1359 rRenderContext.SetFillColor(aOldFillColor);
1363 void SvxIconChoiceCtrl_Impl::PaintItem(const tools::Rectangle& rRect,
1364 IcnViewFieldType eItem, SvxIconChoiceCtrlEntry* pEntry, sal_uInt16 nPaintFlags,
1365 vcl::RenderContext& rRenderContext )
1367 if (eItem == IcnViewFieldType::Text)
1369 OUString aText = SvtIconChoiceCtrl::GetEntryText(pEntry);
1371 rRenderContext.DrawText(rRect, aText, nCurTextDrawFlags);
1373 if (pEntry->IsFocused())
1375 tools::Rectangle aRect (CalcFocusRect(pEntry));
1376 ShowFocus(aRect);
1377 DrawFocusRect(rRenderContext);
1380 else
1382 Point aPos(rRect.TopLeft());
1383 if (nPaintFlags & PAINTFLAG_HOR_CENTERED)
1384 aPos.AdjustX((rRect.GetWidth() - aImageSize.Width()) / 2 );
1385 if (nPaintFlags & PAINTFLAG_VER_CENTERED)
1386 aPos.AdjustY((rRect.GetHeight() - aImageSize.Height()) / 2 );
1387 SvtIconChoiceCtrl::DrawEntryImage(pEntry, aPos, rRenderContext);
1391 void SvxIconChoiceCtrl_Impl::PaintEntry(SvxIconChoiceCtrlEntry* pEntry, const Point& rPos, vcl::RenderContext& rRenderContext)
1393 bool bSelected = false;
1395 if (eSelectionMode != SelectionMode::NONE)
1396 bSelected = pEntry->IsSelected();
1398 rRenderContext.Push(vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
1400 OUString aEntryText(SvtIconChoiceCtrl::GetEntryText(pEntry));
1401 tools::Rectangle aTextRect(CalcTextRect(pEntry, &rPos, &aEntryText));
1402 tools::Rectangle aBmpRect(CalcBmpRect(pEntry, &rPos));
1404 bool bShowSelection = (bSelected && (eSelectionMode != SelectionMode::NONE));
1406 bool bActiveSelection = (0 != (nWinBits & WB_NOHIDESELECTION)) || pView->HasFocus();
1408 if (bShowSelection)
1410 const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings();
1411 vcl::Font aNewFont(rRenderContext.GetFont());
1413 // font fill colors that are attributed "hard" need corresponding "hard"
1414 // attributed highlight colors
1415 if ((nWinBits & WB_NOHIDESELECTION) || pView->HasFocus())
1416 aNewFont.SetFillColor(rSettings.GetHighlightColor());
1417 else
1418 aNewFont.SetFillColor(rSettings.GetDeactiveColor());
1420 Color aWinCol = rSettings.GetWindowTextColor();
1421 if (!bActiveSelection && rSettings.GetFaceColor().IsBright() == aWinCol.IsBright())
1422 aNewFont.SetColor(rSettings.GetWindowTextColor());
1423 else
1424 aNewFont.SetColor(rSettings.GetHighlightTextColor());
1426 rRenderContext.SetFont(aNewFont);
1428 rRenderContext.SetFillColor(rRenderContext.GetBackground().GetColor());
1429 rRenderContext.DrawRect(CalcFocusRect(pEntry));
1430 rRenderContext.SetFillColor();
1433 bool bResetClipRegion = false;
1434 if (!rRenderContext.IsClipRegion() && (aVerSBar->IsVisible() || aHorSBar->IsVisible()))
1436 tools::Rectangle aOutputArea(GetOutputRect());
1437 if (aOutputArea.Overlaps(aTextRect) || aOutputArea.Overlaps(aBmpRect))
1439 rRenderContext.SetClipRegion(vcl::Region(aOutputArea));
1440 bResetClipRegion = true;
1444 bool bLargeIconMode = WB_ICON == ( nWinBits & VIEWMODE_MASK );
1445 sal_uInt16 nBmpPaintFlags = PAINTFLAG_VER_CENTERED;
1446 if (bLargeIconMode)
1447 nBmpPaintFlags |= PAINTFLAG_HOR_CENTERED;
1448 sal_uInt16 nTextPaintFlags = bLargeIconMode ? PAINTFLAG_HOR_CENTERED : PAINTFLAG_VER_CENTERED;
1450 PaintEmphasis(aTextRect, bSelected, rRenderContext);
1452 if ( bShowSelection )
1453 vcl::RenderTools::DrawSelectionBackground(rRenderContext, *pView, CalcFocusRect(pEntry),
1454 bActiveSelection ? 1 : 2, false, true, false);
1457 PaintItem(aBmpRect, IcnViewFieldType::Image, pEntry, nBmpPaintFlags, rRenderContext);
1459 PaintItem(aTextRect, IcnViewFieldType::Text, pEntry, nTextPaintFlags, rRenderContext);
1461 // draw highlight frame
1462 if (pEntry == pCurHighlightFrame)
1463 DrawHighlightFrame(rRenderContext, CalcFocusRect(pEntry));
1465 rRenderContext.Pop();
1466 if (bResetClipRegion)
1467 rRenderContext.SetClipRegion();
1470 void SvxIconChoiceCtrl_Impl::SetEntryPos( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos )
1472 ShowCursor( false );
1473 tools::Rectangle aBoundRect( GetEntryBoundRect( pEntry ));
1474 pView->Invalidate( aBoundRect );
1475 ToTop( pEntry );
1476 if( !IsAutoArrange() )
1478 bool bAdjustVirtSize = false;
1479 if( rPos != aBoundRect.TopLeft() )
1481 Point aGridOffs(
1482 pEntry->aGridRect.TopLeft() - pEntry->aRect.TopLeft() );
1483 pImpCursor->Clear();
1484 pGridMap->Clear();
1485 aBoundRect.SetPos( rPos );
1486 pEntry->aRect = aBoundRect;
1487 pEntry->aGridRect.SetPos( rPos + aGridOffs );
1488 bAdjustVirtSize = true;
1490 if( bAdjustVirtSize )
1491 AdjustVirtSize( pEntry->aRect );
1493 pView->Invalidate( pEntry->aRect );
1494 pGridMap->OccupyGrids( pEntry );
1496 else
1498 SvxIconChoiceCtrlEntry* pPrev = FindEntryPredecessor( pEntry, rPos );
1499 SetEntryPredecessor( pEntry, pPrev );
1500 aAutoArrangeIdle.Start();
1502 ShowCursor( true );
1505 void SvxIconChoiceCtrl_Impl::SetNoSelection()
1507 // block recursive calls via SelectEntry
1508 if( !(nFlags & IconChoiceFlags::ClearingSelection ))
1510 nFlags |= IconChoiceFlags::ClearingSelection;
1511 DeselectAllBut( nullptr );
1512 nFlags &= ~IconChoiceFlags::ClearingSelection;
1516 SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetEntry( const Point& rDocPos, bool bHit )
1518 CheckBoundingRects();
1519 // search through z-order list from the end
1520 size_t nCount = maZOrderList.size();
1521 while( nCount )
1523 nCount--;
1524 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[ nCount ];
1525 if( pEntry->aRect.Contains( rDocPos ) )
1527 if( bHit )
1529 tools::Rectangle aRect = CalcBmpRect( pEntry );
1530 aRect.AdjustTop( -3 );
1531 aRect.AdjustBottom(3 );
1532 aRect.AdjustLeft( -3 );
1533 aRect.AdjustRight(3 );
1534 if( aRect.Contains( rDocPos ) )
1535 return pEntry;
1536 aRect = CalcTextRect( pEntry );
1537 if( aRect.Contains( rDocPos ) )
1538 return pEntry;
1540 else
1541 return pEntry;
1544 return nullptr;
1547 void SvxIconChoiceCtrl_Impl::MakeEntryVisible( SvxIconChoiceCtrlEntry* pEntry, bool bBound )
1549 if ( bBound )
1551 const tools::Rectangle& rRect = GetEntryBoundRect( pEntry );
1552 MakeVisible( rRect );
1554 else
1556 tools::Rectangle aRect = CalcBmpRect( pEntry );
1557 aRect.Union( CalcTextRect( pEntry ) );
1558 aRect.AdjustTop(TBOFFS_BOUND );
1559 aRect.AdjustBottom(TBOFFS_BOUND );
1560 aRect.AdjustLeft(LROFFS_BOUND );
1561 aRect.AdjustRight(LROFFS_BOUND );
1562 MakeVisible( aRect );
1566 const tools::Rectangle& SvxIconChoiceCtrl_Impl::GetEntryBoundRect( SvxIconChoiceCtrlEntry* pEntry )
1568 if( !IsBoundingRectValid( pEntry->aRect ))
1569 FindBoundingRect( pEntry );
1570 return pEntry->aRect;
1573 tools::Rectangle SvxIconChoiceCtrl_Impl::CalcBmpRect( SvxIconChoiceCtrlEntry* pEntry, const Point* pPos )
1575 tools::Rectangle aBound = GetEntryBoundRect( pEntry );
1576 if( pPos )
1577 aBound.SetPos( *pPos );
1578 Point aPos( aBound.TopLeft() );
1580 switch( nWinBits & VIEWMODE_MASK )
1582 case WB_ICON:
1584 aPos.AdjustX(( aBound.GetWidth() - aImageSize.Width() ) / 2 );
1585 return tools::Rectangle( aPos, aImageSize );
1588 case WB_SMALLICON:
1589 case WB_DETAILS:
1590 aPos.AdjustY(( aBound.GetHeight() - aImageSize.Height() ) / 2 );
1591 //TODO: determine horizontal distance to bounding rectangle
1592 return tools::Rectangle( aPos, aImageSize );
1594 default:
1595 OSL_FAIL("IconView: Viewmode not set");
1596 return aBound;
1600 tools::Rectangle SvxIconChoiceCtrl_Impl::CalcTextRect( SvxIconChoiceCtrlEntry* pEntry,
1601 const Point* pEntryPos, const OUString* pStr )
1603 OUString aEntryText;
1604 if( !pStr )
1605 aEntryText = SvtIconChoiceCtrl::GetEntryText( pEntry );
1606 else
1607 aEntryText = *pStr;
1609 const tools::Rectangle aMaxTextRect( CalcMaxTextRect( pEntry ) );
1610 tools::Rectangle aBound( GetEntryBoundRect( pEntry ) );
1611 if( pEntryPos )
1612 aBound.SetPos( *pEntryPos );
1614 tools::Rectangle aTextRect = pView->GetTextRect( aMaxTextRect, aEntryText, nCurTextDrawFlags );
1616 Size aTextSize( aTextRect.GetSize() );
1618 Point aPos( aBound.TopLeft() );
1619 tools::Long nBoundWidth = aBound.GetWidth();
1620 tools::Long nBoundHeight = aBound.GetHeight();
1622 switch( nWinBits & VIEWMODE_MASK )
1624 case WB_ICON:
1625 aPos.AdjustY(aImageSize.Height() );
1626 aPos.AdjustY(VER_DIST_BMP_STRING );
1627 aPos.AdjustX((nBoundWidth - aTextSize.Width()) / 2 );
1628 break;
1630 case WB_SMALLICON:
1631 case WB_DETAILS:
1632 aPos.AdjustX(aImageSize.Width() );
1633 aPos.AdjustX(HOR_DIST_BMP_STRING );
1634 aPos.AdjustY((nBoundHeight - aTextSize.Height()) / 2 );
1635 break;
1637 return tools::Rectangle( aPos, aTextSize );
1641 tools::Long SvxIconChoiceCtrl_Impl::CalcBoundingWidth() const
1643 tools::Long nStringWidth = GetItemSize( IcnViewFieldType::Text ).Width();
1644 tools::Long nWidth = 0;
1646 switch( nWinBits & VIEWMODE_MASK )
1648 case WB_ICON:
1649 nWidth = std::max( nStringWidth, aImageSize.Width() );
1650 break;
1652 case WB_SMALLICON:
1653 case WB_DETAILS:
1654 nWidth = aImageSize.Width();
1655 nWidth += HOR_DIST_BMP_STRING;
1656 nWidth += nStringWidth;
1657 break;
1659 return nWidth;
1662 tools::Long SvxIconChoiceCtrl_Impl::CalcBoundingHeight() const
1664 tools::Long nStringHeight = GetItemSize(IcnViewFieldType::Text).Height();
1665 tools::Long nHeight = 0;
1667 switch( nWinBits & VIEWMODE_MASK )
1669 case WB_ICON:
1670 nHeight = aImageSize.Height();
1671 nHeight += VER_DIST_BMP_STRING;
1672 nHeight += nStringHeight;
1673 break;
1675 case WB_SMALLICON:
1676 case WB_DETAILS:
1677 nHeight = std::max( aImageSize.Height(), nStringHeight );
1678 break;
1680 if( nHeight > nMaxBoundHeight )
1682 const_cast<SvxIconChoiceCtrl_Impl*>(this)->nMaxBoundHeight = nHeight;
1683 const_cast<SvxIconChoiceCtrl_Impl*>(this)->aHorSBar->SetLineSize( GetScrollBarLineSize() );
1684 const_cast<SvxIconChoiceCtrl_Impl*>(this)->aVerSBar->SetLineSize( GetScrollBarLineSize() );
1686 return nHeight;
1689 Size SvxIconChoiceCtrl_Impl::CalcBoundingSize() const
1691 return Size( CalcBoundingWidth(), CalcBoundingHeight() );
1694 void SvxIconChoiceCtrl_Impl::RecalcAllBoundingRectsSmart()
1696 nMaxBoundHeight = 0;
1697 maZOrderList.clear();
1698 size_t nCur;
1699 SvxIconChoiceCtrlEntry* pEntry;
1700 const size_t nCount = maEntries.size();
1702 if( !IsAutoArrange() || !pHead )
1704 for( nCur = 0; nCur < nCount; nCur++ )
1706 pEntry = maEntries[ nCur ].get();
1707 if( IsBoundingRectValid( pEntry->aRect ))
1709 Size aBoundSize( pEntry->aRect.GetSize() );
1710 if( aBoundSize.Height() > nMaxBoundHeight )
1711 nMaxBoundHeight = aBoundSize.Height();
1713 else
1714 FindBoundingRect( pEntry );
1715 maZOrderList.push_back( pEntry );
1718 else
1720 nCur = 0;
1721 pEntry = pHead;
1722 while( nCur != nCount )
1724 DBG_ASSERT(pEntry->pflink&&pEntry->pblink,"SvxIconChoiceCtrl_Impl::RecalcAllBoundingRect > Bad link(s)");
1725 if( IsBoundingRectValid( pEntry->aRect ))
1727 Size aBoundSize( pEntry->aRect.GetSize() );
1728 if( aBoundSize.Height() > nMaxBoundHeight )
1729 nMaxBoundHeight = aBoundSize.Height();
1731 else
1732 FindBoundingRect( pEntry );
1733 maZOrderList.push_back( pEntry );
1734 pEntry = pEntry->pflink;
1735 nCur++;
1738 AdjustScrollBars();
1741 void SvxIconChoiceCtrl_Impl::FindBoundingRect( SvxIconChoiceCtrlEntry* pEntry )
1743 DBG_ASSERT(!pEntry->IsPosLocked(),"Locked entry pos in FindBoundingRect");
1744 if( pEntry->IsPosLocked() && IsBoundingRectValid( pEntry->aRect) )
1746 AdjustVirtSize( pEntry->aRect );
1747 return;
1749 Size aSize( CalcBoundingSize() );
1750 Point aPos(pGridMap->GetGridRect(pGridMap->GetUnoccupiedGrid()).TopLeft());
1751 SetBoundingRect_Impl( pEntry, aPos, aSize );
1754 void SvxIconChoiceCtrl_Impl::SetBoundingRect_Impl( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos,
1755 const Size& /*rBoundingSize*/ )
1757 tools::Rectangle aGridRect( rPos, Size(nGridDX, nGridDY) );
1758 pEntry->aGridRect = aGridRect;
1759 Center( pEntry );
1760 AdjustVirtSize( pEntry->aRect );
1761 pGridMap->OccupyGrids( pEntry );
1765 void SvxIconChoiceCtrl_Impl::SetCursor( SvxIconChoiceCtrlEntry* pEntry )
1767 if( pEntry == pCursor )
1769 if( pCursor && eSelectionMode == SelectionMode::Single &&
1770 !pCursor->IsSelected() )
1771 SelectEntry( pCursor, true );
1772 return;
1774 ShowCursor( false );
1775 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
1776 pCursor = pEntry;
1777 if( pOldCursor )
1779 pOldCursor->ClearFlags( SvxIconViewFlags::FOCUSED );
1780 if( eSelectionMode == SelectionMode::Single )
1781 SelectEntry( pOldCursor, false ); // deselect old cursor
1783 if( pCursor )
1785 ToTop( pCursor );
1786 pCursor->SetFlags( SvxIconViewFlags::FOCUSED );
1787 if( eSelectionMode == SelectionMode::Single )
1788 SelectEntry( pCursor, true );
1789 ShowCursor( true );
1794 void SvxIconChoiceCtrl_Impl::ShowCursor( bool bShow )
1796 if( !pCursor || !bShow || !pView->HasFocus() )
1798 pView->HideFocus();
1799 return;
1801 tools::Rectangle aRect ( CalcFocusRect( pCursor ) );
1802 /*pView->*/ShowFocus( aRect );
1806 void SvxIconChoiceCtrl_Impl::HideDDIcon()
1808 pView->PaintImmediately();
1811 bool SvxIconChoiceCtrl_Impl::HandleScrollCommand( const CommandEvent& rCmd )
1813 tools::Rectangle aDocRect( Point(), aVirtOutputSize );
1814 tools::Rectangle aVisRect( GetOutputRect() );
1815 if( aVisRect.Contains( aDocRect ))
1816 return false;
1817 Size aDocSize( aDocRect.GetSize() );
1818 Size aVisSize( aVisRect.GetSize() );
1819 bool bHor = aDocSize.Width() > aVisSize.Width();
1820 bool bVer = aDocSize.Height() > aVisSize.Height();
1822 tools::Long nScrollDX = 0, nScrollDY = 0;
1824 switch( rCmd.GetCommand() )
1826 case CommandEventId::StartAutoScroll:
1828 pView->EndTracking();
1829 StartAutoScrollFlags nScrollFlags = StartAutoScrollFlags::NONE;
1830 if( bHor )
1831 nScrollFlags |= StartAutoScrollFlags::Horz;
1832 if( bVer )
1833 nScrollFlags |= StartAutoScrollFlags::Vert;
1834 if( nScrollFlags != StartAutoScrollFlags::NONE )
1836 pView->StartAutoScroll( nScrollFlags );
1837 return true;
1840 break;
1842 case CommandEventId::Wheel:
1844 const CommandWheelData* pData = rCmd.GetWheelData();
1845 if( pData && (CommandWheelMode::SCROLL == pData->GetMode()) && !pData->IsHorz() )
1847 sal_uLong nScrollLines = pData->GetScrollLines();
1848 if( nScrollLines == COMMAND_WHEEL_PAGESCROLL )
1850 nScrollDY = GetScrollBarPageSize( aVisSize.Width() );
1851 if( pData->GetDelta() < 0 )
1852 nScrollDY *= -1;
1854 else
1856 nScrollDY = pData->GetNotchDelta() * static_cast<tools::Long>(nScrollLines);
1857 nScrollDY *= GetScrollBarLineSize();
1861 break;
1863 case CommandEventId::AutoScroll:
1865 const CommandScrollData* pData = rCmd.GetAutoScrollData();
1866 if( pData )
1868 nScrollDX = pData->GetDeltaX() * GetScrollBarLineSize();
1869 nScrollDY = pData->GetDeltaY() * GetScrollBarLineSize();
1872 break;
1874 default: break;
1877 if( nScrollDX || nScrollDY )
1879 aVisRect.AdjustTop( -nScrollDY );
1880 aVisRect.AdjustBottom( -nScrollDY );
1881 aVisRect.AdjustLeft( -nScrollDX );
1882 aVisRect.AdjustRight( -nScrollDX );
1883 MakeVisible( aVisRect );
1884 return true;
1886 return false;
1890 void SvxIconChoiceCtrl_Impl::Command( const CommandEvent& rCEvt )
1892 // scroll mouse event?
1893 if( (rCEvt.GetCommand() == CommandEventId::Wheel) ||
1894 (rCEvt.GetCommand() == CommandEventId::StartAutoScroll) ||
1895 (rCEvt.GetCommand() == CommandEventId::AutoScroll) )
1897 if( HandleScrollCommand( rCEvt ) )
1898 return;
1902 void SvxIconChoiceCtrl_Impl::ToTop( SvxIconChoiceCtrlEntry* pEntry )
1904 if( maZOrderList.empty() || pEntry == maZOrderList.back())
1905 return;
1907 auto it = std::find(maZOrderList.begin(), maZOrderList.end(), pEntry);
1908 if (it != maZOrderList.end())
1910 maZOrderList.erase( it );
1911 maZOrderList.push_back( pEntry );
1915 void SvxIconChoiceCtrl_Impl::ClipAtVirtOutRect( tools::Rectangle& rRect ) const
1917 if( rRect.Bottom() >= aVirtOutputSize.Height() )
1918 rRect.SetBottom( aVirtOutputSize.Height() - 1 );
1919 if( rRect.Right() >= aVirtOutputSize.Width() )
1920 rRect.SetRight( aVirtOutputSize.Width() - 1 );
1921 if( rRect.Top() < 0 )
1922 rRect.SetTop( 0 );
1923 if( rRect.Left() < 0 )
1924 rRect.SetLeft( 0 );
1927 // rRect: area of the document (in document coordinates) that we want to make
1928 // visible
1929 // bScrBar == true: rectangle was calculated because of a scrollbar event
1931 void SvxIconChoiceCtrl_Impl::MakeVisible( const tools::Rectangle& rRect, bool bScrBar )
1933 tools::Rectangle aVirtRect( rRect );
1934 ClipAtVirtOutRect( aVirtRect );
1935 Point aOrigin( pView->GetMapMode().GetOrigin() );
1936 // convert to document coordinate
1937 aOrigin *= -1;
1938 tools::Rectangle aOutputArea( GetOutputRect() );
1939 if( aOutputArea.Contains( aVirtRect ) )
1940 return; // is already visible
1942 tools::Long nDy;
1943 if( aVirtRect.Top() < aOutputArea.Top() )
1945 // scroll up (nDy < 0)
1946 nDy = aVirtRect.Top() - aOutputArea.Top();
1948 else if( aVirtRect.Bottom() > aOutputArea.Bottom() )
1950 // scroll down (nDy > 0)
1951 nDy = aVirtRect.Bottom() - aOutputArea.Bottom();
1953 else
1954 nDy = 0;
1956 tools::Long nDx;
1957 if( aVirtRect.Left() < aOutputArea.Left() )
1959 // scroll to the left (nDx < 0)
1960 nDx = aVirtRect.Left() - aOutputArea.Left();
1962 else if( aVirtRect.Right() > aOutputArea.Right() )
1964 // scroll to the right (nDx > 0)
1965 nDx = aVirtRect.Right() - aOutputArea.Right();
1967 else
1968 nDx = 0;
1970 aOrigin.AdjustX(nDx );
1971 aOrigin.AdjustY(nDy );
1972 aOutputArea.SetPos( aOrigin );
1973 if( GetUpdateMode() )
1975 HideDDIcon();
1976 pView->PaintImmediately();
1977 ShowCursor( false );
1980 // invert origin for SV (so we can scroll/paint using document coordinates)
1981 aOrigin *= -1;
1982 SetOrigin( aOrigin );
1984 bool bScrollable = pView->GetBackground().IsScrollable();
1986 if( bScrollable && GetUpdateMode() )
1988 // scroll in reverse direction!
1989 pView->Control::Scroll( -nDx, -nDy, aOutputArea,
1990 ScrollFlags::NoChildren | ScrollFlags::UseClipRegion | ScrollFlags::Clip );
1992 else
1993 pView->Invalidate(InvalidateFlags::NoChildren);
1995 if( aHorSBar->IsVisible() || aVerSBar->IsVisible() )
1997 if( !bScrBar )
1999 aOrigin *= -1;
2000 // correct thumbs
2001 if(aHorSBar->IsVisible() && aHorSBar->GetThumbPos() != aOrigin.X())
2002 aHorSBar->SetThumbPos( aOrigin.X() );
2003 if(aVerSBar->IsVisible() && aVerSBar->GetThumbPos() != aOrigin.Y())
2004 aVerSBar->SetThumbPos( aOrigin.Y() );
2008 if( GetUpdateMode() )
2009 ShowCursor( true );
2011 // check if we still need scrollbars
2012 CheckScrollBars();
2013 if( bScrollable && GetUpdateMode() )
2014 pView->PaintImmediately();
2016 // If the requested area can not be made completely visible, the
2017 // Vis-Rect-Changed handler is called in any case. This case may occur e.g.
2018 // if only few pixels of the lower border are invisible, but a scrollbar has
2019 // a larger line size.
2020 VisRectChanged();
2023 sal_Int32 SvxIconChoiceCtrl_Impl::GetSelectionCount() const
2025 if( (nWinBits & WB_HIGHLIGHTFRAME) && pCurHighlightFrame )
2026 return 1;
2027 return nSelectionCount;
2030 void SvxIconChoiceCtrl_Impl::ToggleSelection( SvxIconChoiceCtrlEntry* pEntry )
2032 bool bSel;
2033 bSel = !pEntry->IsSelected();
2034 SelectEntry( pEntry, bSel, true );
2037 void SvxIconChoiceCtrl_Impl::DeselectAllBut( SvxIconChoiceCtrlEntry const * pThisEntryNot )
2039 ClearSelectedRectList();
2041 // TODO: work through z-order list, if necessary!
2043 size_t nCount = maEntries.size();
2044 for( size_t nCur = 0; nCur < nCount; nCur++ )
2046 SvxIconChoiceCtrlEntry* pEntry = maEntries[ nCur ].get();
2047 if( pEntry != pThisEntryNot && pEntry->IsSelected() )
2048 SelectEntry( pEntry, false, true );
2050 pAnchor = nullptr;
2051 nFlags &= ~IconChoiceFlags::AddMode;
2054 Size SvxIconChoiceCtrl_Impl::GetMinGrid() const
2056 Size aMinSize( aImageSize );
2057 aMinSize.AdjustWidth(2 * LROFFS_BOUND );
2058 aMinSize.AdjustHeight(TBOFFS_BOUND ); // single offset is enough (FileDlg)
2059 Size aTextSize( pView->GetTextWidth( "XXX" ), pView->GetTextHeight() );
2060 if( nWinBits & WB_ICON )
2062 aMinSize.AdjustHeight(VER_DIST_BMP_STRING );
2063 aMinSize.AdjustHeight(aTextSize.Height() );
2065 else
2067 aMinSize.AdjustWidth(HOR_DIST_BMP_STRING );
2068 aMinSize.AdjustWidth(aTextSize.Width() );
2070 return aMinSize;
2073 void SvxIconChoiceCtrl_Impl::SetGrid( const Size& rSize )
2075 Size aSize( rSize );
2076 Size aMinSize( GetMinGrid() );
2077 if( aSize.Width() < aMinSize.Width() )
2078 aSize.setWidth( aMinSize.Width() );
2079 if( aSize.Height() < aMinSize.Height() )
2080 aSize.setHeight( aMinSize.Height() );
2082 nGridDX = aSize.Width();
2083 // HACK: Detail mode is not yet fully implemented, this workaround makes it
2084 // fly with a single column
2085 if( nWinBits & WB_DETAILS )
2087 const SvxIconChoiceCtrlColumnInfo* pCol = GetColumn( 0 );
2088 if( pCol )
2089 const_cast<SvxIconChoiceCtrlColumnInfo*>(pCol)->SetWidth( nGridDX );
2091 nGridDY = aSize.Height();
2092 SetDefaultTextSize();
2095 // Calculates the maximum size that the text rectangle may use within its
2096 // bounding rectangle. In WB_ICON mode with SvxIconChoiceCtrlTextMode::Full, Bottom is set to
2097 // LONG_MAX.
2099 tools::Rectangle SvxIconChoiceCtrl_Impl::CalcMaxTextRect( const SvxIconChoiceCtrlEntry* pEntry ) const
2101 tools::Rectangle aBoundRect;
2102 // avoid infinite recursion: don't calculate the bounding rectangle here
2103 if( IsBoundingRectValid( pEntry->aRect ) )
2104 aBoundRect = pEntry->aRect;
2105 else
2106 aBoundRect = pEntry->aGridRect;
2108 tools::Rectangle aBmpRect( const_cast<SvxIconChoiceCtrl_Impl*>(this)->CalcBmpRect(
2109 const_cast<SvxIconChoiceCtrlEntry*>(pEntry) ) );
2110 if( nWinBits & WB_ICON )
2112 aBoundRect.SetTop( aBmpRect.Bottom() );
2113 aBoundRect.AdjustTop(VER_DIST_BMP_STRING );
2114 if( aBoundRect.Top() > aBoundRect.Bottom())
2115 aBoundRect.SetTop( aBoundRect.Bottom() );
2116 aBoundRect.AdjustLeft(LROFFS_BOUND );
2117 aBoundRect.AdjustLeft( 1 );
2118 aBoundRect.AdjustRight( -(LROFFS_BOUND) );
2119 aBoundRect.AdjustRight( -1 );
2120 if( aBoundRect.Left() > aBoundRect.Right())
2121 aBoundRect.SetLeft( aBoundRect.Right() );
2122 if( pEntry->GetTextMode() == SvxIconChoiceCtrlTextMode::Full )
2123 aBoundRect.SetBottom( LONG_MAX );
2125 else
2127 aBoundRect.SetLeft( aBmpRect.Right() );
2128 aBoundRect.AdjustLeft(HOR_DIST_BMP_STRING );
2129 aBoundRect.AdjustRight( -(LROFFS_BOUND) );
2130 if( aBoundRect.Left() > aBoundRect.Right() )
2131 aBoundRect.SetLeft( aBoundRect.Right() );
2132 tools::Long nHeight = aBoundRect.GetSize().Height();
2133 nHeight = nHeight - aDefaultTextSize.Height();
2134 nHeight /= 2;
2135 aBoundRect.AdjustTop(nHeight );
2136 aBoundRect.AdjustBottom( -nHeight );
2138 return aBoundRect;
2141 void SvxIconChoiceCtrl_Impl::SetDefaultTextSize()
2143 tools::Long nDY = nGridDY;
2144 nDY -= aImageSize.Height();
2145 nDY -= VER_DIST_BMP_STRING;
2146 nDY -= 2 * TBOFFS_BOUND;
2147 if (nDY <= 0)
2148 nDY = 2;
2150 tools::Long nDX = nGridDX;
2151 nDX -= 2 * LROFFS_BOUND;
2152 nDX -= 2;
2153 if (nDX <= 0)
2154 nDX = 2;
2156 tools::Long nHeight = pView->GetTextHeight();
2157 if (nDY < nHeight)
2158 nDY = nHeight;
2159 if(pView->GetDPIScaleFactor() > 1)
2161 nDY*=2;
2163 aDefaultTextSize = Size(nDX, nDY);
2167 void SvxIconChoiceCtrl_Impl::Center( SvxIconChoiceCtrlEntry* pEntry ) const
2169 pEntry->aRect = pEntry->aGridRect;
2170 Size aSize( CalcBoundingSize() );
2171 if( nWinBits & WB_ICON )
2173 // center horizontally
2174 tools::Long nBorder = pEntry->aGridRect.GetWidth() - aSize.Width();
2175 pEntry->aRect.AdjustLeft(nBorder / 2 );
2176 pEntry->aRect.AdjustRight( -(nBorder / 2) );
2178 // center vertically
2179 pEntry->aRect.SetBottom( pEntry->aRect.Top() + aSize.Height() );
2183 // The deltas are the offsets by which the view is moved on the document.
2184 // left, up: offsets < 0
2185 // right, down: offsets > 0
2186 void SvxIconChoiceCtrl_Impl::Scroll( tools::Long nDeltaX, tools::Long nDeltaY )
2188 const MapMode& rMapMode = pView->GetMapMode();
2189 Point aOrigin( rMapMode.GetOrigin() );
2190 // convert to document coordinate
2191 aOrigin *= -1;
2192 aOrigin.AdjustY(nDeltaY );
2193 aOrigin.AdjustX(nDeltaX );
2194 tools::Rectangle aRect( aOrigin, aOutputSize );
2195 MakeVisible( aRect, true/*bScrollBar*/ );
2199 const Size& SvxIconChoiceCtrl_Impl::GetItemSize( IcnViewFieldType eItem ) const
2201 if (eItem == IcnViewFieldType::Text)
2202 return aDefaultTextSize;
2203 return aImageSize; // IcnViewFieldType::Image
2206 tools::Rectangle SvxIconChoiceCtrl_Impl::CalcFocusRect( SvxIconChoiceCtrlEntry* pEntry )
2208 tools::Rectangle aTextRect( CalcTextRect( pEntry ) );
2209 tools::Rectangle aBoundRect( GetEntryBoundRect( pEntry ) );
2210 return tools::Rectangle(
2211 aBoundRect.Left(), aBoundRect.Top() - 1, aBoundRect.Right() - 1,
2212 aTextRect.Bottom() + 1);
2215 // the hot spot is the inner 50% of the rectangle
2216 static tools::Rectangle GetHotSpot( const tools::Rectangle& rRect )
2218 tools::Rectangle aResult( rRect );
2219 aResult.Normalize();
2220 Size aSize( rRect.GetSize() );
2221 tools::Long nDelta = aSize.Width() / 4;
2222 aResult.AdjustLeft(nDelta );
2223 aResult.AdjustRight( -nDelta );
2224 nDelta = aSize.Height() / 4;
2225 aResult.AdjustTop(nDelta );
2226 aResult.AdjustBottom( -nDelta );
2227 return aResult;
2230 void SvxIconChoiceCtrl_Impl::SelectRect( SvxIconChoiceCtrlEntry* pEntry1, SvxIconChoiceCtrlEntry* pEntry2,
2231 bool bAdd, std::vector<tools::Rectangle>* pOtherRects )
2233 DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr");
2234 tools::Rectangle aRect( GetEntryBoundRect( pEntry1 ) );
2235 aRect.Union( GetEntryBoundRect( pEntry2 ) );
2236 SelectRect( aRect, bAdd, pOtherRects );
2239 void SvxIconChoiceCtrl_Impl::SelectRect( const tools::Rectangle& rRect, bool bAdd,
2240 std::vector<tools::Rectangle>* pOtherRects )
2242 aCurSelectionRect = rRect;
2243 if( maZOrderList.empty() )
2244 return;
2246 // set flag, so ToTop won't be called in Select
2247 bool bAlreadySelectingRect(nFlags & IconChoiceFlags::SelectingRect);
2248 nFlags |= IconChoiceFlags::SelectingRect;
2250 CheckBoundingRects();
2251 pView->PaintImmediately();
2252 const size_t nCount = maZOrderList.size();
2254 tools::Rectangle aRect( rRect );
2255 aRect.Normalize();
2256 bool bCalcOverlap = (bAdd && pOtherRects && !pOtherRects->empty());
2258 bool bResetClipRegion = false;
2259 if( !pView->GetOutDev()->IsClipRegion() )
2261 bResetClipRegion = true;
2262 pView->GetOutDev()->SetClipRegion(vcl::Region(GetOutputRect()));
2265 for( size_t nPos = 0; nPos < nCount; nPos++ )
2267 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[ nPos ];
2269 if( !IsBoundingRectValid( pEntry->aRect ))
2270 FindBoundingRect( pEntry );
2271 tools::Rectangle aBoundRect( GetHotSpot( pEntry->aRect ) );
2272 bool bSelected = pEntry->IsSelected();
2274 bool bOverlaps;
2275 if( bCalcOverlap )
2276 bOverlaps = IsOver( pOtherRects, aBoundRect );
2277 else
2278 bOverlaps = false;
2279 bool bOver = aRect.Overlaps( aBoundRect );
2281 if( bOver && !bOverlaps )
2283 // is inside the new selection rectangle and outside of any old one
2284 // => select
2285 if( !bSelected )
2286 SelectEntry( pEntry, true, true );
2288 else if( !bAdd )
2290 // is outside of the selection rectangle
2291 // => deselect
2292 if( bSelected )
2293 SelectEntry( pEntry, false, true );
2295 else if (bOverlaps)
2297 // The entry is inside an old (=>span multiple rectangles with Ctrl)
2298 // selection rectangle.
2300 // There is still a bug here! The selection status of an entry in a
2301 // previous rectangle has to be restored, if it was touched by the
2302 // current selection rectangle but is not inside it any more.
2303 // For simplicity's sake, let's assume that all entries in the old
2304 // rectangles were correctly selected. It is wrong to just deselect
2305 // the intersection.
2306 // Possible solution: remember a snapshot of the selection before
2307 // spanning the rectangle.
2308 if( aBoundRect.Overlaps( rRect))
2310 // deselect intersection between old rectangles and current rectangle
2311 if( bSelected )
2312 SelectEntry( pEntry, false, true );
2314 else
2316 // select entry of an old rectangle
2317 if( !bSelected )
2318 SelectEntry( pEntry, true, true );
2321 else if( !bOver && bSelected )
2323 // this entry is completely outside the rectangle => deselect it
2324 SelectEntry( pEntry, false, true );
2328 if( !bAlreadySelectingRect )
2329 nFlags &= ~IconChoiceFlags::SelectingRect;
2331 pView->PaintImmediately();
2332 if( bResetClipRegion )
2333 pView->GetOutDev()->SetClipRegion();
2336 void SvxIconChoiceCtrl_Impl::SelectRange(
2337 SvxIconChoiceCtrlEntry const * pStart,
2338 SvxIconChoiceCtrlEntry const * pEnd,
2339 bool bAdd )
2341 sal_uLong nFront = GetEntryListPos( pStart );
2342 sal_uLong nBack = GetEntryListPos( pEnd );
2343 sal_uLong nFirst = std::min( nFront, nBack );
2344 sal_uLong nLast = std::max( nFront, nBack );
2345 sal_uLong i;
2346 SvxIconChoiceCtrlEntry* pEntry;
2348 if ( ! bAdd )
2350 // deselect everything before the first entry if not in
2351 // adding mode
2352 for ( i=0; i<nFirst; i++ )
2354 pEntry = GetEntry( i );
2355 if( pEntry->IsSelected() )
2356 SelectEntry( pEntry, false, true );
2360 // select everything between nFirst and nLast
2361 for ( i=nFirst; i<=nLast; i++ )
2363 pEntry = GetEntry( i );
2364 if( ! pEntry->IsSelected() )
2365 SelectEntry( pEntry, true, true );
2368 if ( ! bAdd )
2370 // deselect everything behind the last entry if not in
2371 // adding mode
2372 sal_uLong nEnd = GetEntryCount();
2373 for ( ; i<nEnd; i++ )
2375 pEntry = GetEntry( i );
2376 if( pEntry->IsSelected() )
2377 SelectEntry( pEntry, false, true );
2382 bool SvxIconChoiceCtrl_Impl::IsOver( std::vector<tools::Rectangle>* pRectList, const tools::Rectangle& rBoundRect )
2384 const sal_uInt16 nCount = pRectList->size();
2385 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
2387 tools::Rectangle& rRect = (*pRectList)[ nCur ];
2388 if( rBoundRect.Overlaps( rRect ))
2389 return true;
2391 return false;
2394 void SvxIconChoiceCtrl_Impl::AddSelectedRect( SvxIconChoiceCtrlEntry* pEntry1,
2395 SvxIconChoiceCtrlEntry* pEntry2 )
2397 DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr");
2398 tools::Rectangle aRect( GetEntryBoundRect( pEntry1 ) );
2399 aRect.Union( GetEntryBoundRect( pEntry2 ) );
2400 AddSelectedRect( aRect );
2403 void SvxIconChoiceCtrl_Impl::AddSelectedRect( const tools::Rectangle& rRect )
2405 tools::Rectangle newRect = rRect;
2406 newRect.Normalize();
2407 aSelectedRectList.push_back( newRect );
2410 void SvxIconChoiceCtrl_Impl::ClearSelectedRectList()
2412 aSelectedRectList.clear();
2415 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl, AutoArrangeHdl, Timer *, void)
2417 aAutoArrangeIdle.Stop();
2418 Arrange( IsAutoArrange(), 0, 0 );
2421 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl, VisRectChangedHdl, Timer *, void)
2423 aVisRectChangedIdle.Stop();
2426 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl, DocRectChangedHdl, Timer *, void)
2428 aDocRectChangedIdle.Stop();
2431 #ifdef DBG_UTIL
2432 void SvxIconChoiceCtrl_Impl::SetEntryTextMode( SvxIconChoiceCtrlTextMode eMode, SvxIconChoiceCtrlEntry* pEntry )
2434 if( !pEntry )
2436 if( eTextMode != eMode )
2438 eTextMode = eMode;
2439 Arrange( true, 0, 0 );
2442 else
2444 if( pEntry->eTextMode != eMode )
2446 pEntry->eTextMode = eMode;
2447 InvalidateEntry( pEntry );
2448 pView->Invalidate( GetEntryBoundRect( pEntry ) );
2449 AdjustVirtSize( pEntry->aRect );
2453 #endif
2455 // Draw my own focusrect, because the focusrect of the outputdevice has got the inverted color
2456 // of the background. But what will we see, if the backgroundcolor is gray ? - We will see
2457 // a gray focusrect on a gray background !!!
2459 void SvxIconChoiceCtrl_Impl::ShowFocus ( tools::Rectangle const & rRect )
2461 Color aBkgColor(pView->GetBackground().GetColor());
2462 Color aPenColor;
2463 sal_uInt16 nColor = ( aBkgColor.GetRed() + aBkgColor.GetGreen() + aBkgColor.GetBlue() ) / 3;
2464 if (nColor > 128)
2465 aPenColor = COL_BLACK;
2466 else
2467 aPenColor = COL_WHITE;
2469 aFocus.aPenColor = aPenColor;
2470 aFocus.aRect = rRect;
2473 void SvxIconChoiceCtrl_Impl::DrawFocusRect(vcl::RenderContext& rRenderContext)
2475 rRenderContext.SetLineColor(aFocus.aPenColor);
2476 rRenderContext.SetFillColor();
2477 tools::Polygon aPolygon (aFocus.aRect);
2479 LineInfo aLineInfo(LineStyle::Dash);
2481 aLineInfo.SetDashLen(1);
2482 aLineInfo.SetDotLen(1);
2483 aLineInfo.SetDistance(1);
2484 aLineInfo.SetDotCount(1);
2486 rRenderContext.DrawPolyLine(aPolygon, aLineInfo);
2489 bool SvxIconChoiceCtrl_Impl::IsMnemonicChar( sal_Unicode cChar, sal_uLong& rPos ) const
2491 bool bRet = false;
2492 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
2493 size_t nEntryCount = GetEntryCount();
2494 for ( size_t i = 0; i < nEntryCount; ++i )
2496 if ( rI18nHelper.MatchMnemonic( GetEntry( i )->GetText(), cChar ) )
2498 bRet = true;
2499 rPos = i;
2500 break;
2504 return bRet;
2508 IMPL_LINK(SvxIconChoiceCtrl_Impl, UserEventHdl, void*, nId, void )
2510 if( nId == EVENTID_ADJUST_SCROLLBARS )
2512 nUserEventAdjustScrBars = nullptr;
2513 AdjustScrollBars();
2515 else if( nId == EVENTID_SHOW_CURSOR )
2517 ShowCursor( true );
2521 void SvxIconChoiceCtrl_Impl::CancelUserEvents()
2523 if( nUserEventAdjustScrBars )
2525 Application::RemoveUserEvent( nUserEventAdjustScrBars );
2526 nUserEventAdjustScrBars = nullptr;
2530 void SvxIconChoiceCtrl_Impl::InvalidateEntry( SvxIconChoiceCtrlEntry* pEntry )
2532 if( pEntry == pCursor )
2533 ShowCursor( false );
2534 pView->Invalidate( pEntry->aRect );
2535 Center( pEntry );
2536 pView->Invalidate( pEntry->aRect );
2537 if( pEntry == pCursor )
2538 ShowCursor( true );
2541 SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry() const
2543 if( !GetSelectionCount() )
2544 return nullptr;
2546 if( (nWinBits & WB_HIGHLIGHTFRAME) && (eSelectionMode == SelectionMode::NONE) )
2548 return pCurHighlightFrame;
2551 size_t nCount = maEntries.size();
2552 if( !pHead )
2554 for( size_t nCur = 0; nCur < nCount; nCur++ )
2556 SvxIconChoiceCtrlEntry* pEntry = maEntries[ nCur ].get();
2557 if( pEntry->IsSelected() )
2559 return pEntry;
2563 else
2565 SvxIconChoiceCtrlEntry* pEntry = pHead;
2566 while( nCount-- )
2568 if( pEntry->IsSelected() )
2570 return pEntry;
2572 pEntry = pEntry->pflink;
2573 if( nCount && pEntry == pHead )
2575 OSL_FAIL("SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry > infinite loop!");
2576 return nullptr;
2580 return nullptr;
2583 void SvxIconChoiceCtrl_Impl::SelectAll()
2585 size_t nCount = maEntries.size();
2586 for( size_t nCur = 0; nCur < nCount; nCur++ )
2588 SvxIconChoiceCtrlEntry* pEntry = maEntries[ nCur ].get();
2589 SelectEntry( pEntry, true/*bSelect*/, true );
2591 nFlags &= ~IconChoiceFlags::AddMode;
2592 pAnchor = nullptr;
2598 sal_Int32 SvxIconChoiceCtrl_Impl::GetEntryListPos( SvxIconChoiceCtrlEntry const * pEntry ) const
2600 if( !(nFlags & IconChoiceFlags::EntryListPosValid ))
2601 const_cast<SvxIconChoiceCtrl_Impl*>(this)->SetListPositions();
2602 return pEntry->nPos;
2605 void SvxIconChoiceCtrl_Impl::InitSettings()
2607 const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings();
2609 // unit (from settings) is Point
2610 vcl::Font aFont( rStyleSettings.GetFieldFont() );
2611 aFont.SetColor( rStyleSettings.GetWindowTextColor() );
2612 pView->SetPointFont( aFont );
2613 SetDefaultTextSize();
2615 pView->SetTextColor( rStyleSettings.GetFieldTextColor() );
2616 pView->SetTextFillColor();
2618 pView->SetBackground( rStyleSettings.GetFieldColor());
2620 tools::Long nScrBarSize = rStyleSettings.GetScrollBarSize();
2621 if( nScrBarSize == nHorSBarHeight && nScrBarSize == nVerSBarWidth )
2622 return;
2624 nHorSBarHeight = nScrBarSize;
2625 Size aSize( aHorSBar->GetSizePixel() );
2626 aSize.setHeight( nScrBarSize );
2627 aHorSBar->Hide();
2628 aHorSBar->SetSizePixel( aSize );
2630 nVerSBarWidth = nScrBarSize;
2631 aSize = aVerSBar->GetSizePixel();
2632 aSize.setWidth( nScrBarSize );
2633 aVerSBar->Hide();
2634 aVerSBar->SetSizePixel( aSize );
2636 Size aOSize( pView->Control::GetOutputSizePixel() );
2637 PositionScrollBars( aOSize.Width(), aOSize.Height() );
2638 AdjustScrollBars();
2641 void SvxIconChoiceCtrl_Impl::SetPositionMode( SvxIconChoiceCtrlPositionMode eMode )
2643 if( eMode == ePositionMode )
2644 return;
2646 SvxIconChoiceCtrlPositionMode eOldMode = ePositionMode;
2647 ePositionMode = eMode;
2648 size_t nCount = maEntries.size();
2650 if( eOldMode == SvxIconChoiceCtrlPositionMode::AutoArrange )
2652 // when positioning moved entries "hard", there are problems with
2653 // unwanted overlaps, as these entries aren't taken into account in
2654 // Arrange.
2655 if( maEntries.size() )
2656 aAutoArrangeIdle.Start();
2657 return;
2660 if( ePositionMode == SvxIconChoiceCtrlPositionMode::AutoArrange )
2662 for( size_t nCur = 0; nCur < nCount; nCur++ )
2664 SvxIconChoiceCtrlEntry* pEntry = maEntries[ nCur ].get();
2665 if( pEntry->GetFlags() & SvxIconViewFlags(SvxIconViewFlags::POS_LOCKED | SvxIconViewFlags::POS_MOVED))
2666 SetEntryPos(pEntry, GetEntryBoundRect( pEntry ).TopLeft());
2669 if( maEntries.size() )
2670 aAutoArrangeIdle.Start();
2674 void SvxIconChoiceCtrl_Impl::SetEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry,
2675 SvxIconChoiceCtrlEntry* pPredecessor )
2677 if( !IsAutoArrange() )
2678 return;
2680 if( pEntry == pPredecessor )
2681 return;
2683 sal_uLong nPos1 = GetEntryListPos( pEntry );
2684 if( !pHead )
2686 if( pPredecessor )
2688 sal_uLong nPos2 = GetEntryListPos( pPredecessor );
2689 if( nPos1 == (nPos2 + 1) )
2690 return; // is already the predecessor
2692 else if( !nPos1 )
2693 return;
2695 InitPredecessors();
2698 if( !pPredecessor && pHead == pEntry )
2699 return; // is already the first one
2701 bool bSetHead = false;
2702 if( !pPredecessor )
2704 bSetHead = true;
2705 pPredecessor = pHead->pblink;
2707 if( pEntry == pHead )
2709 pHead = pHead->pflink;
2710 bSetHead = false;
2712 if( pEntry != pPredecessor )
2714 pEntry->Unlink();
2715 pEntry->SetBacklink( pPredecessor );
2717 if( bSetHead )
2718 pHead = pEntry;
2719 aAutoArrangeIdle.Start();
2722 SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::FindEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry,
2723 const Point& rPosTopLeft )
2725 Point aPos( rPosTopLeft ); //TopLeft
2726 tools::Rectangle aCenterRect( CalcBmpRect( pEntry, &aPos ));
2727 Point aNewPos( aCenterRect.Center() );
2728 GridId nGrid = GetPredecessorGrid( aNewPos );
2729 size_t nCount = maEntries.size();
2730 if( nGrid == GRID_NOT_FOUND )
2731 return nullptr;
2732 if( nGrid >= nCount )
2733 nGrid = nCount - 1;
2734 if( !pHead )
2735 return maEntries[ nGrid ].get();
2737 SvxIconChoiceCtrlEntry* pCur = pHead; // Grid 0
2738 // TODO: go through list from the end if nGrid > nCount/2
2739 for( GridId nCur = 0; nCur < nGrid; nCur++ )
2740 pCur = pCur->pflink;
2742 return pCur;
2745 GridId SvxIconChoiceCtrl_Impl::GetPredecessorGrid( const Point& rPos) const
2747 Point aPos( rPos );
2748 aPos.AdjustX( -(LROFFS_WINBORDER) );
2749 aPos.AdjustY( -(TBOFFS_WINBORDER) );
2750 tools::Long nMaxCol = aVirtOutputSize.Width() / nGridDX;
2751 if( nMaxCol )
2752 nMaxCol--;
2753 tools::Long nGridX = aPos.X() / nGridDX;
2754 if( nGridX > nMaxCol )
2755 nGridX = nMaxCol;
2756 tools::Long nGridY = aPos.Y() / nGridDY;
2757 tools::Long nGridsX = aOutputSize.Width() / nGridDX;
2758 GridId nGrid = (nGridY * nGridsX) + nGridX;
2759 tools::Long nMiddle = (nGridX * nGridDX) + (nGridDX / 2);
2760 if( rPos.X() < nMiddle )
2762 if( !nGrid )
2763 nGrid = GRID_NOT_FOUND;
2764 else
2765 nGrid--;
2767 return nGrid;
2770 bool SvxIconChoiceCtrl_Impl::RequestHelp( const HelpEvent& rHEvt )
2772 if ( !(rHEvt.GetMode() & HelpEventMode::QUICK ) )
2773 return false;
2775 Point aPos( pView->ScreenToOutputPixel(rHEvt.GetMousePosPixel() ) );
2776 aPos -= pView->GetMapMode().GetOrigin();
2777 SvxIconChoiceCtrlEntry* pEntry = GetEntry( aPos, true );
2779 if ( !pEntry )
2780 return false;
2782 OUString sQuickHelpText = pEntry->GetQuickHelpText();
2783 OUString aEntryText( SvtIconChoiceCtrl::GetEntryText( pEntry ) );
2784 tools::Rectangle aTextRect( CalcTextRect( pEntry, nullptr, &aEntryText ) );
2785 if ( ( !aTextRect.Contains( aPos ) || aEntryText.isEmpty() ) && sQuickHelpText.isEmpty() )
2786 return false;
2788 tools::Rectangle aOptTextRect( aTextRect );
2789 aOptTextRect.SetBottom( LONG_MAX );
2790 DrawTextFlags nNewFlags = nCurTextDrawFlags;
2791 nNewFlags &= ~DrawTextFlags( DrawTextFlags::Clip | DrawTextFlags::EndEllipsis );
2792 aOptTextRect = pView->GetTextRect( aOptTextRect, aEntryText, nNewFlags );
2793 if ( aOptTextRect != aTextRect || !sQuickHelpText.isEmpty() )
2795 //aTextRect.Right() = aTextRect.Left() + aRealSize.Width() + 4;
2796 Point aPt( aOptTextRect.TopLeft() );
2797 aPt += pView->GetMapMode().GetOrigin();
2798 aPt = pView->OutputToScreenPixel( aPt );
2799 // subtract border of tooltip help
2800 aPt.AdjustY( -1 );
2801 aPt.AdjustX( -3 );
2802 aOptTextRect.SetPos( aPt );
2803 OUString sHelpText;
2804 if ( !sQuickHelpText.isEmpty() )
2805 sHelpText = sQuickHelpText;
2806 else
2807 sHelpText = aEntryText;
2808 Help::ShowQuickHelp( static_cast<vcl::Window*>(pView), aOptTextRect, sHelpText, QuickHelpFlags::Left | QuickHelpFlags::VCenter );
2811 return true;
2814 void SvxIconChoiceCtrl_Impl::SetColumn( sal_uInt16 nIndex, const SvxIconChoiceCtrlColumnInfo& rInfo)
2816 if (!m_pColumns)
2817 m_pColumns.reset(new SvxIconChoiceCtrlColumnInfoMap);
2819 SvxIconChoiceCtrlColumnInfo* pInfo = new SvxIconChoiceCtrlColumnInfo( rInfo );
2820 m_pColumns->insert(std::make_pair(nIndex, std::unique_ptr<SvxIconChoiceCtrlColumnInfo>(pInfo)));
2822 // HACK: Detail mode is not yet fully implemented, this workaround makes it
2823 // fly with a single column
2824 if( !nIndex && (nWinBits & WB_DETAILS) )
2825 nGridDX = pInfo->GetWidth();
2827 if( GetUpdateMode() )
2828 Arrange( IsAutoArrange(), 0, 0 );
2831 const SvxIconChoiceCtrlColumnInfo* SvxIconChoiceCtrl_Impl::GetColumn( sal_uInt16 nIndex ) const
2833 if (!m_pColumns)
2834 return nullptr;
2835 auto const it = m_pColumns->find( nIndex );
2836 if (it == m_pColumns->end())
2837 return nullptr;
2838 return it->second.get();
2841 void SvxIconChoiceCtrl_Impl::DrawHighlightFrame(vcl::RenderContext& rRenderContext, const tools::Rectangle& rBmpRect)
2843 tools::Rectangle aBmpRect(rBmpRect);
2844 tools::Long nBorder = 2;
2845 if (aImageSize.Width() < 32)
2846 nBorder = 1;
2847 aBmpRect.AdjustRight(nBorder );
2848 aBmpRect.AdjustLeft( -nBorder );
2849 aBmpRect.AdjustBottom(nBorder );
2850 aBmpRect.AdjustTop( -nBorder );
2852 DecorationView aDecoView(&rRenderContext);
2853 DrawHighlightFrameStyle nDecoFlags;
2854 if (bHighlightFramePressed)
2855 nDecoFlags = DrawHighlightFrameStyle::In;
2856 else
2857 nDecoFlags = DrawHighlightFrameStyle::Out;
2858 aDecoView.DrawHighlightFrame(aBmpRect, nDecoFlags);
2861 void SvxIconChoiceCtrl_Impl::SetEntryHighlightFrame( SvxIconChoiceCtrlEntry* pEntry,
2862 bool bKeepHighlightFlags )
2864 if( pEntry == pCurHighlightFrame )
2865 return;
2867 if( !bKeepHighlightFlags )
2868 bHighlightFramePressed = false;
2870 if (pCurHighlightFrame)
2872 tools::Rectangle aInvalidationRect(GetEntryBoundRect(pCurHighlightFrame));
2873 aInvalidationRect.expand(5);
2874 pCurHighlightFrame = nullptr;
2875 pView->Invalidate(aInvalidationRect);
2878 pCurHighlightFrame = pEntry;
2879 if (pEntry)
2881 tools::Rectangle aInvalidationRect(GetEntryBoundRect(pEntry));
2882 aInvalidationRect.expand(5);
2883 pView->Invalidate(aInvalidationRect);
2887 void SvxIconChoiceCtrl_Impl::CallSelectHandler()
2889 // When single-click mode is active, the selection handler should be called
2890 // synchronously, as the selection is automatically taken away once the
2891 // mouse cursor doesn't touch the object any more. Else, we might run into
2892 // missing calls to Select if the object is selected from a mouse movement,
2893 // because when starting the timer, the mouse cursor might have already left
2894 // the object.
2895 // In special cases (=>SfxFileDialog!), synchronous calls can be forced via
2896 // WB_NOASYNCSELECTHDL.
2897 if( nWinBits & (WB_NOASYNCSELECTHDL | WB_HIGHLIGHTFRAME) )
2899 pHdlEntry = nullptr;
2900 pView->ClickIcon();
2901 //pView->Select();
2903 else
2904 aCallSelectHdlIdle.Start();
2907 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl, CallSelectHdlHdl, Timer *, void)
2909 pHdlEntry = nullptr;
2910 pView->ClickIcon();
2911 //pView->Select();
2914 void SvxIconChoiceCtrl_Impl::SetOrigin( const Point& rPos )
2916 MapMode aMapMode( pView->GetMapMode() );
2917 aMapMode.SetOrigin( rPos );
2918 pView->SetMapMode( aMapMode );
2921 void SvxIconChoiceCtrl_Impl::CallEventListeners( VclEventId nEvent, void* pData )
2923 pView->CallImplEventListeners( nEvent, pData );
2927 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */