nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / control / imivctl1.cxx
blob4f4ae02cdfaabd721e5b0f36de8ca17e0630b01d
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 contnr SvxIconChoiceCtrl_Impl AutoArrange" ),
60 aDocRectChangedIdle ( "svtools contnr SvxIconChoiceCtrl_Impl DocRectChanged" ),
61 aVisRectChangedIdle ( "svtools contnr SvxIconChoiceCtrl_Impl VisRectChanged" ),
62 aCallSelectHdlIdle ( "svtools contnr SvxIconChoiceCtrl_Impl CallSelectHdl" ),
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));
84 aAutoArrangeIdle.SetDebugName( "svtools::SvxIconChoiceCtrl_Impl aAutoArrangeIdle" );
86 aCallSelectHdlIdle.SetPriority( TaskPriority::LOWEST );
87 aCallSelectHdlIdle.SetInvokeHandler( LINK(this,SvxIconChoiceCtrl_Impl,CallSelectHdlHdl));
88 aCallSelectHdlIdle.SetDebugName( "svtools::SvxIconChoiceCtrl_Impl aCallSelectHdlIdle" );
90 aDocRectChangedIdle.SetPriority( TaskPriority::HIGH_IDLE );
91 aDocRectChangedIdle.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl,DocRectChangedHdl));
92 aDocRectChangedIdle.SetDebugName( "svtools::SvxIconChoiceCtrl_Impl aDocRectChangedIdle" );
94 aVisRectChangedIdle.SetPriority( TaskPriority::HIGH_IDLE );
95 aVisRectChangedIdle.SetInvokeHandler(LINK(this,SvxIconChoiceCtrl_Impl,VisRectChangedHdl));
96 aVisRectChangedIdle.SetDebugName( "svtools::SvxIconChoiceCtrl_Impl aVisRectChangedIdle" );
98 Clear( true );
99 Size gridSize(100,70);
100 if(pView->GetDPIScaleFactor() > 1)
102 gridSize.setHeight( gridSize.Height() * ( pView->GetDPIScaleFactor()) );
104 SetGrid(gridSize);
107 SvxIconChoiceCtrl_Impl::~SvxIconChoiceCtrl_Impl()
109 Clear(false);
110 CancelUserEvents();
111 pImpCursor.reset();
112 pGridMap.reset();
113 ClearSelectedRectList();
114 m_pColumns.reset();
115 aVerSBar.disposeAndClear();
116 aHorSBar.disposeAndClear();
117 aScrBarBox.disposeAndClear();
120 void SvxIconChoiceCtrl_Impl::Clear( bool bInCtor )
122 nSelectionCount = 0;
123 pCurHighlightFrame = nullptr;
124 CancelUserEvents();
125 ShowCursor( false );
126 bBoundRectsDirty = false;
127 nMaxBoundHeight = 0;
129 pCursor = nullptr;
130 if( !bInCtor )
132 pImpCursor->Clear();
133 pGridMap->Clear();
134 aVirtOutputSize.setWidth( 0 );
135 aVirtOutputSize.setHeight( 0 );
136 Size aSize( pView->GetOutputSizePixel() );
137 nMaxVirtWidth = aSize.Width() - nVerSBarWidth;
138 if( nMaxVirtWidth <= 0 )
139 nMaxVirtWidth = DEFAULT_MAX_VIRT_WIDTH;
140 nMaxVirtHeight = aSize.Height() - nHorSBarHeight;
141 if( nMaxVirtHeight <= 0 )
142 nMaxVirtHeight = DEFAULT_MAX_VIRT_HEIGHT;
143 maZOrderList.clear();
144 SetOrigin( Point() );
145 if( bUpdateMode )
146 pView->Invalidate(InvalidateFlags::NoChildren);
148 AdjustScrollBars();
149 maEntries.clear();
150 DocRectChanged();
151 VisRectChanged();
154 void SvxIconChoiceCtrl_Impl::SetStyle( WinBits nWinStyle )
156 nWinBits = nWinStyle;
157 nCurTextDrawFlags = DRAWTEXT_FLAGS_ICON;
158 if( nWinBits & (WB_SMALLICON | WB_DETAILS) )
159 nCurTextDrawFlags = DRAWTEXT_FLAGS_SMALLICON;
160 if( nWinBits & WB_NOSELECTION )
161 eSelectionMode = SelectionMode::NONE;
162 if( !(nWinStyle & (WB_ALIGN_TOP | WB_ALIGN_LEFT)))
163 nWinBits |= WB_ALIGN_LEFT;
164 if( nWinStyle & WB_DETAILS )
166 if (!m_pColumns)
167 SetColumn( 0, SvxIconChoiceCtrlColumnInfo() );
171 IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollUpDownHdl, ScrollBar*, pScrollBar, void )
173 // arrow up: delta=-1; arrow down: delta=+1
174 Scroll( 0, pScrollBar->GetDelta() );
177 IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl, ScrollBar*, pScrollBar, void )
179 // arrow left: delta=-1; arrow right: delta=+1
180 Scroll( pScrollBar->GetDelta(), 0 );
183 void SvxIconChoiceCtrl_Impl::FontModified()
185 SetDefaultTextSize();
186 ShowCursor( false );
187 ShowCursor( true );
190 void SvxIconChoiceCtrl_Impl::InsertEntry( std::unique_ptr<SvxIconChoiceCtrlEntry> pEntry1, size_t nPos)
192 auto pEntry = pEntry1.get();
194 if ( nPos < maEntries.size() ) {
195 maEntries.insert( maEntries.begin() + nPos, std::move(pEntry1) );
196 } else {
197 maEntries.push_back( std::move(pEntry1) );
200 if( pHead )
201 pEntry->SetBacklink( pHead->pblink );
203 if( (nFlags & IconChoiceFlags::EntryListPosValid) && nPos >= maEntries.size() - 1 )
204 pEntry->nPos = maEntries.size() - 1;
205 else
206 nFlags &= ~IconChoiceFlags::EntryListPosValid;
208 maZOrderList.push_back( pEntry );
209 pImpCursor->Clear();
211 // If the UpdateMode is true, don't set all bounding rectangles to
212 // 'to be checked', but only the bounding rectangle of the new entry.
213 // Thus, don't call InvalidateBoundingRect!
214 pEntry->aRect.SetRight( LONG_MAX );
215 if( bUpdateMode )
217 FindBoundingRect( pEntry );
218 tools::Rectangle aOutputArea( GetOutputRect() );
219 pGridMap->OccupyGrids( pEntry );
220 if( !aOutputArea.IsOver( pEntry->aRect ) )
221 return; // is invisible
222 pView->Invalidate( pEntry->aRect );
224 else
225 InvalidateBoundingRect( pEntry->aRect );
228 void SvxIconChoiceCtrl_Impl::RemoveEntry(size_t nPos)
230 pImpCursor->Clear();
231 maEntries.erase(maEntries.begin() + nPos);
232 RecalcAllBoundingRectsSmart();
235 tools::Rectangle SvxIconChoiceCtrl_Impl::GetOutputRect() const
237 Point aOrigin( pView->GetMapMode().GetOrigin() );
238 aOrigin *= -1;
239 return tools::Rectangle( aOrigin, aOutputSize );
242 void SvxIconChoiceCtrl_Impl::SetListPositions()
244 if( nFlags & IconChoiceFlags::EntryListPosValid )
245 return;
247 size_t nCount = maEntries.size();
248 for( size_t nCur = 0; nCur < nCount; nCur++ )
250 maEntries[ nCur ]->nPos = nCur;
252 nFlags |= IconChoiceFlags::EntryListPosValid;
255 void SvxIconChoiceCtrl_Impl::SelectEntry( SvxIconChoiceCtrlEntry* pEntry, bool bSelect,
256 bool bAdd )
258 if( eSelectionMode == SelectionMode::NONE )
259 return;
261 if( !bAdd )
263 if ( !( nFlags & IconChoiceFlags::ClearingSelection ) )
265 nFlags |= IconChoiceFlags::ClearingSelection;
266 DeselectAllBut( pEntry );
267 nFlags &= ~IconChoiceFlags::ClearingSelection;
270 if( pEntry->IsSelected() == bSelect )
271 return;
273 pHdlEntry = pEntry;
274 SvxIconViewFlags nEntryFlags = pEntry->GetFlags();
275 if( bSelect )
277 nEntryFlags |= SvxIconViewFlags::SELECTED;
278 pEntry->AssignFlags( nEntryFlags );
279 nSelectionCount++;
280 CallSelectHandler();
282 else
284 nEntryFlags &= ~SvxIconViewFlags::SELECTED;
285 pEntry->AssignFlags( nEntryFlags );
286 nSelectionCount--;
287 CallSelectHandler();
289 EntrySelected( pEntry, bSelect );
292 void SvxIconChoiceCtrl_Impl::EntrySelected(SvxIconChoiceCtrlEntry* pEntry, bool bSelect)
294 // When using SingleSelection, make sure that the cursor is always placed
295 // over the (only) selected entry. (But only if a cursor exists.)
296 if (bSelect && pCursor &&
297 eSelectionMode == SelectionMode::Single &&
298 pEntry != pCursor)
300 SetCursor(pEntry);
303 // Not when dragging though, else the loop in SelectRect doesn't work
304 // correctly!
305 if (!(nFlags & IconChoiceFlags::SelectingRect))
306 ToTop(pEntry);
307 if (bUpdateMode)
309 if (pEntry == pCursor)
310 ShowCursor(false);
311 pView->Invalidate(CalcFocusRect(pEntry));
312 if (pEntry == pCursor)
313 ShowCursor(true);
316 // #i101012# emit vcl event LISTBOX_SELECT only in case that the given entry is selected.
317 if (bSelect)
319 CallEventListeners(VclEventId::ListboxSelect, pEntry);
323 void SvxIconChoiceCtrl_Impl::ResetVirtSize()
325 aVirtOutputSize.setWidth( 0 );
326 aVirtOutputSize.setHeight( 0 );
327 const size_t nCount = maEntries.size();
328 for( size_t nCur = 0; nCur < nCount; nCur++ )
330 SvxIconChoiceCtrlEntry* pCur = maEntries[ nCur ].get();
331 pCur->ClearFlags( SvxIconViewFlags::POS_MOVED );
332 if( pCur->IsPosLocked() )
334 // adapt (among others) VirtSize
335 if( !IsBoundingRectValid( pCur->aRect ) )
336 FindBoundingRect( pCur );
337 else
338 AdjustVirtSize( pCur->aRect );
340 else
341 InvalidateBoundingRect( pCur->aRect );
344 if( !(nWinBits & (WB_NOVSCROLL | WB_NOHSCROLL)) )
346 Size aRealOutputSize( pView->GetOutputSizePixel() );
347 if( aVirtOutputSize.Width() < aRealOutputSize.Width() ||
348 aVirtOutputSize.Height() < aRealOutputSize.Height() )
350 sal_uLong nGridCount = IcnGridMap_Impl::GetGridCount(
351 aRealOutputSize, static_cast<sal_uInt16>(nGridDX), static_cast<sal_uInt16>(nGridDY) );
352 if( nGridCount < nCount )
354 if( nWinBits & WB_ALIGN_TOP )
355 nMaxVirtWidth = aRealOutputSize.Width() - nVerSBarWidth;
356 else // WB_ALIGN_LEFT
357 nMaxVirtHeight = aRealOutputSize.Height() - nHorSBarHeight;
362 pImpCursor->Clear();
363 pGridMap->Clear();
364 VisRectChanged();
367 void SvxIconChoiceCtrl_Impl::AdjustVirtSize( const tools::Rectangle& rRect )
369 tools::Long nHeightOffs = 0;
370 tools::Long nWidthOffs = 0;
372 if( aVirtOutputSize.Width() < (rRect.Right()+LROFFS_WINBORDER) )
373 nWidthOffs = (rRect.Right()+LROFFS_WINBORDER) - aVirtOutputSize.Width();
375 if( aVirtOutputSize.Height() < (rRect.Bottom()+TBOFFS_WINBORDER) )
376 nHeightOffs = (rRect.Bottom()+TBOFFS_WINBORDER) - aVirtOutputSize.Height();
378 if( !(nWidthOffs || nHeightOffs) )
379 return;
381 Range aRange;
382 aVirtOutputSize.AdjustWidth(nWidthOffs );
383 aRange.Max() = aVirtOutputSize.Width();
384 aHorSBar->SetRange( aRange );
386 aVirtOutputSize.AdjustHeight(nHeightOffs );
387 aRange.Max() = aVirtOutputSize.Height();
388 aVerSBar->SetRange( aRange );
390 pImpCursor->Clear();
391 pGridMap->OutputSizeChanged();
392 AdjustScrollBars();
393 DocRectChanged();
396 void SvxIconChoiceCtrl_Impl::InitPredecessors()
398 DBG_ASSERT(!pHead,"SvxIconChoiceCtrl_Impl::InitPredecessors() >> Already initialized");
399 size_t nCount = maEntries.size();
400 if( nCount )
402 SvxIconChoiceCtrlEntry* pPrev = maEntries[ 0 ].get();
403 for( size_t nCur = 1; nCur <= nCount; nCur++ )
405 pPrev->ClearFlags( SvxIconViewFlags::POS_LOCKED | SvxIconViewFlags::POS_MOVED );
407 SvxIconChoiceCtrlEntry* pNext;
408 if( nCur == nCount )
409 pNext = maEntries[ 0 ].get();
410 else
411 pNext = maEntries[ nCur ].get();
412 pPrev->pflink = pNext;
413 pNext->pblink = pPrev;
414 pPrev = pNext;
416 pHead = maEntries[ 0 ].get();
418 else
419 pHead = nullptr;
422 void SvxIconChoiceCtrl_Impl::ClearPredecessors()
424 if( pHead )
426 size_t nCount = maEntries.size();
427 for( size_t nCur = 0; nCur < nCount; nCur++ )
429 SvxIconChoiceCtrlEntry* pCur = maEntries[ nCur ].get();
430 pCur->pflink = nullptr;
431 pCur->pblink = nullptr;
433 pHead = nullptr;
437 void SvxIconChoiceCtrl_Impl::Arrange( bool bKeepPredecessors, tools::Long nSetMaxVirtWidth, tools::Long nSetMaxVirtHeight )
439 if ( nSetMaxVirtWidth != 0 )
440 nMaxVirtWidth = nSetMaxVirtWidth;
441 else
442 nMaxVirtWidth = aOutputSize.Width();
444 if ( nSetMaxVirtHeight != 0 )
445 nMaxVirtHeight = nSetMaxVirtHeight;
446 else
447 nMaxVirtHeight = aOutputSize.Height();
449 ImpArrange( bKeepPredecessors );
452 void SvxIconChoiceCtrl_Impl::ImpArrange( bool bKeepPredecessors )
454 static Point aEmptyPoint;
456 bool bOldUpdate = bUpdateMode;
457 tools::Rectangle aCurOutputArea( GetOutputRect() );
458 if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint )
459 bUpdateMode = false;
460 aAutoArrangeIdle.Stop();
461 nFlags |= IconChoiceFlags::Arranging;
462 ShowCursor( false );
463 ResetVirtSize();
464 if( !bKeepPredecessors )
465 ClearPredecessors();
466 bBoundRectsDirty = false;
467 SetOrigin( Point() );
468 VisRectChanged();
469 RecalcAllBoundingRectsSmart();
470 // TODO: the invalidation in the detail view should be more intelligent
471 //if( !(nWinBits & WB_DETAILS ))
472 pView->Invalidate( InvalidateFlags::NoChildren );
473 nFlags &= ~IconChoiceFlags::Arranging;
474 if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint )
476 MakeVisible( aCurOutputArea );
477 SetUpdateMode( bOldUpdate );
479 ShowCursor( true );
482 void SvxIconChoiceCtrl_Impl::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
484 #if defined(OV_DRAWGRID)
485 Color aOldColor (rRenderContext.GetLineColor());
486 Color aCOL_BLACK);
487 rRenderContext.SetLineColor( aColor );
488 Point aOffs(rRenderContext.GetMapMode().GetOrigin());
489 Size aXSize(GetOutputSizePixel());
491 Point aStart(LROFFS_WINBORDER, 0);
492 Point aEnd(LROFFS_WINBORDER, aXSize.Height());
493 aStart -= aOffs;
494 aEnd -= aOffs;
495 rRenderContext.DrawLine(aStart, aEnd);
498 Point aStart(0, TBOFFS_WINBORDER);
499 Point aEnd(aXSize.Width(), TBOFFS_WINBORDER);
500 aStart -= aOffs;
501 aEnd -= aOffs;
502 rRenderContext.DrawLine(aStart, aEnd);
505 for (tools::Long nDX = nGridDX; nDX <= aXSize.Width(); nDX += nGridDX)
507 Point aStart( nDX+LROFFS_WINBORDER, 0 );
508 Point aEnd( nDX+LROFFS_WINBORDER, aXSize.Height());
509 aStart -= aOffs;
510 aEnd -= aOffs;
511 rRenderContext.DrawLine(aStart, aEnd);
513 for (tools::Long nDY = nGridDY; nDY <= aXSize.Height(); nDY += nGridDY)
515 Point aStart(0, nDY + TBOFFS_WINBORDER);
516 Point aEnd(aXSize.Width(), nDY + TBOFFS_WINBORDER);
517 aStart -= aOffs;
518 aEnd -= aOffs;
519 rRenderContext.DrawLine(aStart, aEnd);
521 rRenderContext.SetLineColor(aOldColor);
522 #endif
524 if (!maEntries.size())
525 return;
526 if (!pCursor)
528 // set cursor to item with focus-flag
529 bool bfound = false;
530 for (sal_Int32 i = 0; i < pView->GetEntryCount() && !bfound; i++)
532 SvxIconChoiceCtrlEntry* pEntry = pView->GetEntry(i);
533 if (pEntry->IsFocused())
535 pCursor = pEntry;
536 bfound = true;
540 if (!bfound)
541 pCursor = maEntries[ 0 ].get();
544 size_t nCount = maZOrderList.size();
545 if (!nCount)
546 return;
548 rRenderContext.Push(PushFlags::CLIPREGION);
549 rRenderContext.SetClipRegion(vcl::Region(rRect));
551 std::vector< SvxIconChoiceCtrlEntry* > aNewZOrderList;
552 std::vector< SvxIconChoiceCtrlEntry* > aPaintedEntries;
554 size_t nPos = 0;
555 while(nCount)
557 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[nPos];
558 const tools::Rectangle& rBoundRect = GetEntryBoundRect(pEntry);
559 if (rRect.IsOver(rBoundRect))
561 PaintEntry(pEntry, rBoundRect.TopLeft(), rRenderContext);
562 // set entries to Top if they are being repainted
563 aPaintedEntries.push_back(pEntry);
565 else
566 aNewZOrderList.push_back(pEntry);
568 nCount--;
569 nPos++;
571 maZOrderList = std::move( aNewZOrderList );
572 maZOrderList.insert(maZOrderList.end(), aPaintedEntries.begin(), aPaintedEntries.end());
574 rRenderContext.Pop();
577 void SvxIconChoiceCtrl_Impl::RepaintSelectedEntries()
579 const size_t nCount = maZOrderList.size();
580 if (!nCount)
581 return;
583 tools::Rectangle aOutRect(GetOutputRect());
584 for (size_t nCur = 0; nCur < nCount; nCur++)
586 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[nCur];
587 if (pEntry->GetFlags() & SvxIconViewFlags::SELECTED)
589 const tools::Rectangle& rBoundRect = GetEntryBoundRect(pEntry);
590 if (aOutRect.IsOver(rBoundRect))
591 pView->Invalidate(rBoundRect);
596 void SvxIconChoiceCtrl_Impl::InitScrollBarBox()
598 aScrBarBox->SetSizePixel( Size(nVerSBarWidth-1, nHorSBarHeight-1) );
599 Size aSize( pView->GetOutputSizePixel() );
600 aScrBarBox->SetPosPixel( Point(aSize.Width()-nVerSBarWidth+1, aSize.Height()-nHorSBarHeight+1));
603 bool SvxIconChoiceCtrl_Impl::MouseButtonDown( const MouseEvent& rMEvt)
605 bool bHandled = true;
606 bHighlightFramePressed = false;
607 bool bGotFocus = (!pView->HasFocus() && !(nWinBits & WB_NOPOINTERFOCUS));
608 if( !(nWinBits & WB_NOPOINTERFOCUS) )
609 pView->GrabFocus();
611 Point aDocPos( rMEvt.GetPosPixel() );
612 if(aDocPos.X()>=aOutputSize.Width() || aDocPos.Y()>=aOutputSize.Height())
613 return false;
614 ToDocPos( aDocPos );
615 SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, true );
616 if( pEntry )
617 MakeEntryVisible( pEntry, false );
619 if( rMEvt.IsShift() && eSelectionMode != SelectionMode::Single )
621 if( pEntry )
622 SetCursor_Impl( pCursor, pEntry, rMEvt.IsMod1(), rMEvt.IsShift() );
623 return true;
626 if( pAnchor && (rMEvt.IsShift() || rMEvt.IsMod1())) // keyboard selection?
628 DBG_ASSERT(eSelectionMode != SelectionMode::Single,"Invalid selection mode");
629 if( rMEvt.IsMod1() )
630 nFlags |= IconChoiceFlags::AddMode;
632 if( rMEvt.IsShift() )
634 tools::Rectangle aRect( GetEntryBoundRect( pAnchor ));
635 if( pEntry )
636 aRect.Union( GetEntryBoundRect( pEntry ) );
637 else
639 tools::Rectangle aTempRect( aDocPos, Size(1,1));
640 aRect.Union( aTempRect );
642 aCurSelectionRect = aRect;
643 SelectRect( aRect, bool(nFlags & IconChoiceFlags::AddMode), &aSelectedRectList );
645 else if( rMEvt.IsMod1() )
647 AddSelectedRect( aCurSelectionRect );
648 pAnchor = nullptr;
649 aCurSelectionRect.SetPos( aDocPos );
652 if( !pEntry && !(nWinBits & WB_NODRAGSELECTION))
653 pView->StartTracking( StartTrackingFlags::ScrollRepeat );
654 return true;
656 else
658 if( !pEntry )
660 if( eSelectionMode == SelectionMode::Multiple )
662 if( !rMEvt.IsMod1() ) // Ctrl
664 if( !bGotFocus )
666 SetNoSelection();
667 ClearSelectedRectList();
670 else
671 nFlags |= IconChoiceFlags::AddMode;
672 aCurSelectionRect.SetPos( aDocPos );
673 pView->StartTracking( StartTrackingFlags::ScrollRepeat );
675 else
676 bHandled = false;
677 return bHandled;
680 bool bSelected = pEntry->IsSelected();
682 if( rMEvt.GetClicks() == 2 )
684 DeselectAllBut( pEntry );
685 SelectEntry( pEntry, true, false );
686 pHdlEntry = pEntry;
687 pView->ClickIcon();
689 else
691 // Inplace-Editing ?
692 if( rMEvt.IsMod2() ) // Alt?
695 else if( eSelectionMode == SelectionMode::Single )
697 DeselectAllBut( pEntry );
698 SetCursor( pEntry );
700 else if( eSelectionMode == SelectionMode::NONE )
702 if( rMEvt.IsLeft() && (nWinBits & WB_HIGHLIGHTFRAME) )
704 pCurHighlightFrame = nullptr; // force repaint of frame
705 bHighlightFramePressed = true;
706 SetEntryHighlightFrame( pEntry, true );
709 else
711 if( !rMEvt.GetModifier() && rMEvt.IsLeft() )
713 if( !bSelected )
715 DeselectAllBut( pEntry );
716 SetCursor( pEntry );
717 SelectEntry( pEntry, true, false );
719 else
721 // deselect only in the Up, if the Move happened via D&D!
722 nFlags |= IconChoiceFlags::DownDeselect;
725 else if( rMEvt.IsMod1() )
726 nFlags |= IconChoiceFlags::DownCtrl;
729 return bHandled;
732 bool SvxIconChoiceCtrl_Impl::MouseButtonUp( const MouseEvent& rMEvt )
734 bool bHandled = false;
735 if( rMEvt.IsRight() && (nFlags & (IconChoiceFlags::DownCtrl | IconChoiceFlags::DownDeselect) ))
737 nFlags &= ~IconChoiceFlags(IconChoiceFlags::DownCtrl | IconChoiceFlags::DownDeselect);
738 bHandled = true;
741 Point aDocPos( rMEvt.GetPosPixel() );
742 ToDocPos( aDocPos );
743 SvxIconChoiceCtrlEntry* pDocEntry = GetEntry( aDocPos );
744 if( pDocEntry )
746 if( nFlags & IconChoiceFlags::DownCtrl )
748 // Ctrl & MultiSelection
749 ToggleSelection( pDocEntry );
750 SetCursor( pDocEntry );
751 bHandled = true;
753 else if( nFlags & IconChoiceFlags::DownDeselect )
755 DeselectAllBut( pDocEntry );
756 SetCursor( pDocEntry );
757 SelectEntry( pDocEntry, true, false );
758 bHandled = true;
762 nFlags &= ~IconChoiceFlags(IconChoiceFlags::DownCtrl | IconChoiceFlags::DownDeselect);
764 if((nWinBits & WB_HIGHLIGHTFRAME) && bHighlightFramePressed && pCurHighlightFrame)
766 bHandled = true;
767 SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame;
768 pCurHighlightFrame = nullptr; // force repaint of frame
769 bHighlightFramePressed = false;
770 SetEntryHighlightFrame( pEntry, true );
772 pHdlEntry = pCurHighlightFrame;
773 pView->ClickIcon();
775 // set focus on Icon
776 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
777 SetCursor_Impl( pOldCursor, pHdlEntry, false, false );
779 pHdlEntry = nullptr;
781 return bHandled;
784 bool SvxIconChoiceCtrl_Impl::MouseMove( const MouseEvent& rMEvt )
786 const Point aDocPos( pView->PixelToLogic(rMEvt.GetPosPixel()) );
788 if( pView->IsTracking() )
789 return false;
790 else if( nWinBits & WB_HIGHLIGHTFRAME )
792 SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, true );
793 SetEntryHighlightFrame( pEntry, false );
795 else
796 return false;
797 return true;
800 void SvxIconChoiceCtrl_Impl::SetCursor_Impl( SvxIconChoiceCtrlEntry* pOldCursor,
801 SvxIconChoiceCtrlEntry* pNewCursor, bool bMod1, bool bShift )
803 if( !pNewCursor )
804 return;
806 SvxIconChoiceCtrlEntry* pFilterEntry = nullptr;
807 bool bDeselectAll = false;
808 if( eSelectionMode != SelectionMode::Single )
810 if( !bMod1 && !bShift )
811 bDeselectAll = true;
812 else if( bShift && !bMod1 && !pAnchor )
814 bDeselectAll = true;
815 pFilterEntry = pOldCursor;
818 if( bDeselectAll )
819 DeselectAllBut( pFilterEntry );
820 ShowCursor( false );
821 MakeEntryVisible( pNewCursor );
822 SetCursor( pNewCursor );
823 if( bMod1 && !bShift )
825 if( pAnchor )
827 AddSelectedRect( pAnchor, pOldCursor );
828 pAnchor = nullptr;
831 else if( bShift )
833 if( !pAnchor )
834 pAnchor = pOldCursor;
835 if ( nWinBits & WB_ALIGN_LEFT )
836 SelectRange( pAnchor, pNewCursor, bool(nFlags & IconChoiceFlags::AddMode) );
837 else
838 SelectRect(pAnchor,pNewCursor, bool(nFlags & IconChoiceFlags::AddMode), &aSelectedRectList);
840 else
842 SelectEntry( pCursor, true, false );
843 aCurSelectionRect = GetEntryBoundRect( pCursor );
844 CallEventListeners( VclEventId::ListboxSelect, pCursor );
848 bool SvxIconChoiceCtrl_Impl::KeyInput( const KeyEvent& rKEvt )
850 bool bMod2 = rKEvt.GetKeyCode().IsMod2();
851 sal_Unicode cChar = rKEvt.GetCharCode();
852 sal_uLong nPos = sal_uLong(-1);
853 if ( bMod2 && cChar && IsMnemonicChar( cChar, nPos ) )
855 // shortcut is clicked
856 SvxIconChoiceCtrlEntry* pNewCursor = GetEntry( nPos );
857 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
858 if ( pNewCursor != pOldCursor )
859 SetCursor_Impl( pOldCursor, pNewCursor, false, false );
860 return true;
863 if ( bMod2 )
864 // no actions with <ALT>
865 return false;
867 bool bKeyUsed = true;
868 bool bMod1 = rKEvt.GetKeyCode().IsMod1();
869 bool bShift = rKEvt.GetKeyCode().IsShift();
871 if( eSelectionMode == SelectionMode::Single || eSelectionMode == SelectionMode::NONE)
873 bShift = false;
874 bMod1 = false;
877 if( bMod1 )
878 nFlags |= IconChoiceFlags::AddMode;
880 SvxIconChoiceCtrlEntry* pNewCursor;
881 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
883 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
884 switch( nCode )
886 case KEY_UP:
887 case KEY_PAGEUP:
888 if( pCursor )
890 MakeEntryVisible( pCursor );
891 if( nCode == KEY_UP )
892 pNewCursor = pImpCursor->GoUpDown(pCursor,false);
893 else
894 pNewCursor = pImpCursor->GoPageUpDown(pCursor,false);
895 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
896 if( !pNewCursor )
898 tools::Rectangle aRect( GetEntryBoundRect( pCursor ) );
899 if( aRect.Top())
901 aRect.AdjustBottom( -(aRect.Top()) );
902 aRect.SetTop( 0 );
903 MakeVisible( aRect );
907 break;
909 case KEY_DOWN:
910 case KEY_PAGEDOWN:
911 if( pCursor )
913 if( nCode == KEY_DOWN )
914 pNewCursor=pImpCursor->GoUpDown( pCursor,true );
915 else
916 pNewCursor=pImpCursor->GoPageUpDown( pCursor,true );
917 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
919 break;
921 case KEY_RIGHT:
922 if( pCursor )
924 pNewCursor=pImpCursor->GoLeftRight(pCursor,true );
925 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
927 break;
929 case KEY_LEFT:
930 if( pCursor )
932 MakeEntryVisible( pCursor );
933 pNewCursor = pImpCursor->GoLeftRight(pCursor,false );
934 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
935 if( !pNewCursor )
937 tools::Rectangle aRect( GetEntryBoundRect(pCursor));
938 if( aRect.Left() )
940 aRect.AdjustRight( -(aRect.Left()) );
941 aRect.SetLeft( 0 );
942 MakeVisible( aRect );
946 break;
948 case KEY_F2:
949 if( bMod1 || bShift )
950 bKeyUsed = false;
951 break;
953 case KEY_F8:
954 if( rKEvt.GetKeyCode().IsShift() )
956 if( nFlags & IconChoiceFlags::AddMode )
957 nFlags &= ~IconChoiceFlags::AddMode;
958 else
959 nFlags |= IconChoiceFlags::AddMode;
961 else
962 bKeyUsed = false;
963 break;
965 case KEY_SPACE:
966 if( pCursor && eSelectionMode != SelectionMode::Single )
968 if( !bMod1 )
970 //SelectAll( false );
971 SetNoSelection();
972 ClearSelectedRectList();
974 // click Icon with spacebar
975 SetEntryHighlightFrame( GetCurEntry(), true );
976 pView->ClickIcon();
977 pHdlEntry = pCurHighlightFrame;
978 pCurHighlightFrame=nullptr;
980 else
981 ToggleSelection( pCursor );
983 break;
985 #ifdef DBG_UTIL
986 case KEY_F10:
987 if( rKEvt.GetKeyCode().IsShift() )
989 if( pCursor )
990 pView->SetEntryTextMode( SvxIconChoiceCtrlTextMode::Full, pCursor );
992 if( rKEvt.GetKeyCode().IsMod1() )
994 if( pCursor )
995 pView->SetEntryTextMode( SvxIconChoiceCtrlTextMode::Short, pCursor );
997 break;
998 #endif
1000 case KEY_ADD:
1001 case KEY_DIVIDE :
1002 case KEY_A:
1003 if( bMod1 && (eSelectionMode != SelectionMode::Single))
1004 SelectAll();
1005 else
1006 bKeyUsed = false;
1007 break;
1009 case KEY_SUBTRACT:
1010 case KEY_COMMA :
1011 if( bMod1 )
1012 SetNoSelection();
1013 else
1014 bKeyUsed = false;
1015 break;
1017 case KEY_RETURN:
1018 if( !bMod1 )
1019 bKeyUsed = false;
1020 break;
1022 case KEY_END:
1023 if( pCursor )
1025 pNewCursor = maEntries.back().get();
1026 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
1028 break;
1030 case KEY_HOME:
1031 if( pCursor )
1033 pNewCursor = maEntries[ 0 ].get();
1034 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift );
1036 break;
1038 default:
1039 bKeyUsed = false;
1042 return bKeyUsed;
1045 // recalculate TopLeft of scrollbars (but not their sizes!)
1046 void SvxIconChoiceCtrl_Impl::PositionScrollBars( tools::Long nRealWidth, tools::Long nRealHeight )
1048 // horizontal scrollbar
1049 Point aPos( 0, nRealHeight );
1050 aPos.AdjustY( -nHorSBarHeight );
1052 if( aHorSBar->GetPosPixel() != aPos )
1053 aHorSBar->SetPosPixel( aPos );
1055 // vertical scrollbar
1056 aPos.setX( nRealWidth ); aPos.setY( 0 );
1057 aPos.AdjustX( -nVerSBarWidth );
1058 aPos.AdjustX( 1 );
1059 aPos.AdjustY( -1 );
1061 if( aVerSBar->GetPosPixel() != aPos )
1062 aVerSBar->SetPosPixel( aPos );
1065 void SvxIconChoiceCtrl_Impl::AdjustScrollBars()
1067 tools::Long nVirtHeight = aVirtOutputSize.Height();
1068 tools::Long nVirtWidth = aVirtOutputSize.Width();
1070 Size aOSize( pView->Control::GetOutputSizePixel() );
1071 tools::Long nRealHeight = aOSize.Height();
1072 tools::Long nRealWidth = aOSize.Width();
1074 PositionScrollBars( nRealWidth, nRealHeight );
1076 const MapMode& rMapMode = pView->GetMapMode();
1077 Point aOrigin( rMapMode.GetOrigin() );
1079 tools::Long nVisibleWidth;
1080 if( nRealWidth > nVirtWidth )
1081 nVisibleWidth = nVirtWidth + aOrigin.X();
1082 else
1083 nVisibleWidth = nRealWidth;
1085 tools::Long nVisibleHeight;
1086 if( nRealHeight > nVirtHeight )
1087 nVisibleHeight = nVirtHeight + aOrigin.Y();
1088 else
1089 nVisibleHeight = nRealHeight;
1091 bool bVerSBar = ( nWinBits & WB_VSCROLL ) != 0;
1092 bool bHorSBar = ( nWinBits & WB_HSCROLL ) != 0;
1093 bool bNoVerSBar = ( nWinBits & WB_NOVSCROLL ) != 0;
1094 bool bNoHorSBar = ( nWinBits & WB_NOHSCROLL ) != 0;
1096 sal_uInt16 nResult = 0;
1097 if( nVirtHeight )
1099 // activate vertical scrollbar?
1100 if( !bNoVerSBar && (bVerSBar || ( nVirtHeight > nVisibleHeight)) )
1102 nResult = 0x0001;
1103 nRealWidth -= nVerSBarWidth;
1105 if( nRealWidth > nVirtWidth )
1106 nVisibleWidth = nVirtWidth + aOrigin.X();
1107 else
1108 nVisibleWidth = nRealWidth;
1110 // activate horizontal scrollbar?
1111 if( !bNoHorSBar && (bHorSBar || (nVirtWidth > nVisibleWidth)) )
1113 nResult |= 0x0002;
1114 nRealHeight -= nHorSBarHeight;
1116 if( nRealHeight > nVirtHeight )
1117 nVisibleHeight = nVirtHeight + aOrigin.Y();
1118 else
1119 nVisibleHeight = nRealHeight;
1121 // do we need a vertical scrollbar after all?
1122 if( !(nResult & 0x0001) && // only if not already there
1123 ( !bNoVerSBar && ((nVirtHeight > nVisibleHeight) || bVerSBar)) )
1125 nResult = 3; // both turned on
1126 nRealWidth -= nVerSBarWidth;
1128 if( nRealWidth > nVirtWidth )
1129 nVisibleWidth = nVirtWidth + aOrigin.X();
1130 else
1131 nVisibleWidth = nRealWidth;
1136 // size vertical scrollbar
1137 tools::Long nThumb = aVerSBar->GetThumbPos();
1138 Size aSize( nVerSBarWidth, nRealHeight );
1139 aSize.AdjustHeight(2 );
1140 if( aSize != aVerSBar->GetSizePixel() )
1141 aVerSBar->SetSizePixel( aSize );
1142 aVerSBar->SetVisibleSize( nVisibleHeight );
1143 aVerSBar->SetPageSize( GetScrollBarPageSize( nVisibleHeight ));
1145 if( nResult & 0x0001 )
1147 aVerSBar->SetThumbPos( nThumb );
1148 aVerSBar->Show();
1150 else
1152 aVerSBar->SetThumbPos( 0 );
1153 aVerSBar->Hide();
1156 // size horizontal scrollbar
1157 nThumb = aHorSBar->GetThumbPos();
1158 aSize.setWidth( nRealWidth );
1159 aSize.setHeight( nHorSBarHeight );
1160 aSize.AdjustWidth( 1 );
1161 if( nResult & 0x0001 ) // vertical scrollbar?
1163 aSize.AdjustWidth( 1 );
1164 nRealWidth++;
1166 if( aSize != aHorSBar->GetSizePixel() )
1167 aHorSBar->SetSizePixel( aSize );
1168 aHorSBar->SetVisibleSize( nVisibleWidth );
1169 aHorSBar->SetPageSize( GetScrollBarPageSize(nVisibleWidth ));
1170 if( nResult & 0x0002 )
1172 aHorSBar->SetThumbPos( nThumb );
1173 aHorSBar->Show();
1175 else
1177 aHorSBar->SetThumbPos( 0 );
1178 aHorSBar->Hide();
1181 aOutputSize.setWidth( nRealWidth );
1182 if( nResult & 0x0002 ) // horizontal scrollbar ?
1183 nRealHeight++; // because lower border is clipped
1184 aOutputSize.setHeight( nRealHeight );
1186 if( (nResult & (0x0001|0x0002)) == (0x0001|0x0002) )
1187 aScrBarBox->Show();
1188 else
1189 aScrBarBox->Hide();
1192 void SvxIconChoiceCtrl_Impl::Resize()
1194 InitScrollBarBox();
1195 aOutputSize = pView->GetOutputSizePixel();
1196 pImpCursor->Clear();
1197 pGridMap->OutputSizeChanged();
1199 const Size& rSize = pView->Control::GetOutputSizePixel();
1200 PositionScrollBars( rSize.Width(), rSize.Height() );
1201 // The scrollbars are shown/hidden asynchronously, so derived classes can
1202 // do an Arrange during Resize, without the scrollbars suddenly turning
1203 // on and off again.
1204 // If an event is already underway, we don't need to send a new one, at least
1205 // as long as there is only one event type.
1206 if ( ! nUserEventAdjustScrBars )
1207 nUserEventAdjustScrBars =
1208 Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl, UserEventHdl),
1209 EVENTID_ADJUST_SCROLLBARS);
1211 VisRectChanged();
1214 bool SvxIconChoiceCtrl_Impl::CheckHorScrollBar()
1216 if( maZOrderList.empty() || !aHorSBar->IsVisible() )
1217 return false;
1218 const MapMode& rMapMode = pView->GetMapMode();
1219 Point aOrigin( rMapMode.GetOrigin() );
1220 if(!( nWinBits & WB_HSCROLL) && !aOrigin.X() )
1222 tools::Long nWidth = aOutputSize.Width();
1223 const size_t nCount = maZOrderList.size();
1224 tools::Long nMostRight = 0;
1225 for( size_t nCur = 0; nCur < nCount; nCur++ )
1227 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[ nCur ];
1228 tools::Long nRight = GetEntryBoundRect(pEntry).Right();
1229 if( nRight > nWidth )
1230 return false;
1231 if( nRight > nMostRight )
1232 nMostRight = nRight;
1234 aHorSBar->Hide();
1235 aOutputSize.AdjustHeight(nHorSBarHeight );
1236 aVirtOutputSize.setWidth( nMostRight );
1237 aHorSBar->SetThumbPos( 0 );
1238 Range aRange;
1239 aRange.Max() = nMostRight - 1;
1240 aHorSBar->SetRange( aRange );
1241 if( aVerSBar->IsVisible() )
1243 Size aSize( aVerSBar->GetSizePixel());
1244 aSize.AdjustHeight(nHorSBarHeight );
1245 aVerSBar->SetSizePixel( aSize );
1247 return true;
1249 return false;
1252 bool SvxIconChoiceCtrl_Impl::CheckVerScrollBar()
1254 if( maZOrderList.empty() || !aVerSBar->IsVisible() )
1255 return false;
1256 const MapMode& rMapMode = pView->GetMapMode();
1257 Point aOrigin( rMapMode.GetOrigin() );
1258 if(!( nWinBits & WB_VSCROLL) && !aOrigin.Y() )
1260 tools::Long nDeepest = 0;
1261 tools::Long nHeight = aOutputSize.Height();
1262 const size_t nCount = maZOrderList.size();
1263 for( size_t nCur = 0; nCur < nCount; nCur++ )
1265 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[ nCur ];
1266 tools::Long nBottom = GetEntryBoundRect(pEntry).Bottom();
1267 if( nBottom > nHeight )
1268 return false;
1269 if( nBottom > nDeepest )
1270 nDeepest = nBottom;
1272 aVerSBar->Hide();
1273 aOutputSize.AdjustWidth(nVerSBarWidth );
1274 aVirtOutputSize.setHeight( nDeepest );
1275 aVerSBar->SetThumbPos( 0 );
1276 Range aRange;
1277 aRange.Max() = nDeepest - 1;
1278 aVerSBar->SetRange( aRange );
1279 if( aHorSBar->IsVisible() )
1281 Size aSize( aHorSBar->GetSizePixel());
1282 aSize.AdjustWidth(nVerSBarWidth );
1283 aHorSBar->SetSizePixel( aSize );
1285 return true;
1287 return false;
1291 // hides scrollbars if they're unnecessary
1292 void SvxIconChoiceCtrl_Impl::CheckScrollBars()
1294 CheckVerScrollBar();
1295 if( CheckHorScrollBar() )
1296 CheckVerScrollBar();
1297 if( aVerSBar->IsVisible() && aHorSBar->IsVisible() )
1298 aScrBarBox->Show();
1299 else
1300 aScrBarBox->Hide();
1304 void SvxIconChoiceCtrl_Impl::GetFocus()
1306 RepaintSelectedEntries();
1307 if( pCursor )
1309 pCursor->SetFlags( SvxIconViewFlags::FOCUSED );
1310 ShowCursor( true );
1314 void SvxIconChoiceCtrl_Impl::LoseFocus()
1316 if( pCursor )
1317 pCursor->ClearFlags( SvxIconViewFlags::FOCUSED );
1318 ShowCursor( false );
1320 // HideFocus ();
1321 // pView->Invalidate ( aFocus.aRect );
1323 RepaintSelectedEntries();
1326 void SvxIconChoiceCtrl_Impl::SetUpdateMode( bool bUpdate )
1328 if( bUpdate != bUpdateMode )
1330 bUpdateMode = bUpdate;
1331 if( bUpdate )
1333 AdjustScrollBars();
1334 pImpCursor->Clear();
1335 pGridMap->Clear();
1336 pView->Invalidate(InvalidateFlags::NoChildren);
1341 // priorities of the emphasis: bSelected
1342 void SvxIconChoiceCtrl_Impl::PaintEmphasis(const tools::Rectangle& rTextRect, bool bSelected,
1343 vcl::RenderContext& rRenderContext)
1345 Color aOldFillColor(rRenderContext.GetFillColor());
1347 bool bSolidTextRect = false;
1349 if (!bSelected)
1351 const Color& rFillColor = rRenderContext.GetFont().GetFillColor();
1352 rRenderContext.SetFillColor(rFillColor);
1353 if (rFillColor != COL_TRANSPARENT)
1354 bSolidTextRect = true;
1357 // draw text rectangle
1358 if (bSolidTextRect)
1360 rRenderContext.DrawRect(rTextRect);
1363 rRenderContext.SetFillColor(aOldFillColor);
1367 void SvxIconChoiceCtrl_Impl::PaintItem(const tools::Rectangle& rRect,
1368 IcnViewFieldType eItem, SvxIconChoiceCtrlEntry* pEntry, sal_uInt16 nPaintFlags,
1369 vcl::RenderContext& rRenderContext )
1371 if (eItem == IcnViewFieldType::Text)
1373 OUString aText = SvtIconChoiceCtrl::GetEntryText(pEntry);
1375 rRenderContext.DrawText(rRect, aText, nCurTextDrawFlags);
1377 if (pEntry->IsFocused())
1379 tools::Rectangle aRect (CalcFocusRect(pEntry));
1380 ShowFocus(aRect);
1381 DrawFocusRect(rRenderContext);
1384 else
1386 Point aPos(rRect.TopLeft());
1387 if (nPaintFlags & PAINTFLAG_HOR_CENTERED)
1388 aPos.AdjustX((rRect.GetWidth() - aImageSize.Width()) / 2 );
1389 if (nPaintFlags & PAINTFLAG_VER_CENTERED)
1390 aPos.AdjustY((rRect.GetHeight() - aImageSize.Height()) / 2 );
1391 SvtIconChoiceCtrl::DrawEntryImage(pEntry, aPos, rRenderContext);
1395 void SvxIconChoiceCtrl_Impl::PaintEntry(SvxIconChoiceCtrlEntry* pEntry, const Point& rPos, vcl::RenderContext& rRenderContext)
1397 bool bSelected = false;
1399 if (eSelectionMode != SelectionMode::NONE)
1400 bSelected = pEntry->IsSelected();
1402 rRenderContext.Push(PushFlags::FONT | PushFlags::TEXTCOLOR);
1404 OUString aEntryText(SvtIconChoiceCtrl::GetEntryText(pEntry));
1405 tools::Rectangle aTextRect(CalcTextRect(pEntry, &rPos, &aEntryText));
1406 tools::Rectangle aBmpRect(CalcBmpRect(pEntry, &rPos));
1408 bool bShowSelection = (bSelected && (eSelectionMode != SelectionMode::NONE));
1410 bool bActiveSelection = (0 != (nWinBits & WB_NOHIDESELECTION)) || pView->HasFocus();
1412 if (bShowSelection)
1414 const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings();
1415 vcl::Font aNewFont(rRenderContext.GetFont());
1417 // font fill colors that are attributed "hard" need corresponding "hard"
1418 // attributed highlight colors
1419 if ((nWinBits & WB_NOHIDESELECTION) || pView->HasFocus())
1420 aNewFont.SetFillColor(rSettings.GetHighlightColor());
1421 else
1422 aNewFont.SetFillColor(rSettings.GetDeactiveColor());
1424 Color aWinCol = rSettings.GetWindowTextColor();
1425 if (!bActiveSelection && rSettings.GetFaceColor().IsBright() == aWinCol.IsBright())
1426 aNewFont.SetColor(rSettings.GetWindowTextColor());
1427 else
1428 aNewFont.SetColor(rSettings.GetHighlightTextColor());
1430 rRenderContext.SetFont(aNewFont);
1432 rRenderContext.SetFillColor(rRenderContext.GetBackground().GetColor());
1433 rRenderContext.DrawRect(CalcFocusRect(pEntry));
1434 rRenderContext.SetFillColor();
1437 bool bResetClipRegion = false;
1438 if (!rRenderContext.IsClipRegion() && (aVerSBar->IsVisible() || aHorSBar->IsVisible()))
1440 tools::Rectangle aOutputArea(GetOutputRect());
1441 if (aOutputArea.IsOver(aTextRect) || aOutputArea.IsOver(aBmpRect))
1443 rRenderContext.SetClipRegion(vcl::Region(aOutputArea));
1444 bResetClipRegion = true;
1448 bool bLargeIconMode = WB_ICON == ( nWinBits & VIEWMODE_MASK );
1449 sal_uInt16 nBmpPaintFlags = PAINTFLAG_VER_CENTERED;
1450 if (bLargeIconMode)
1451 nBmpPaintFlags |= PAINTFLAG_HOR_CENTERED;
1452 sal_uInt16 nTextPaintFlags = bLargeIconMode ? PAINTFLAG_HOR_CENTERED : PAINTFLAG_VER_CENTERED;
1454 PaintEmphasis(aTextRect, bSelected, rRenderContext);
1456 if ( bShowSelection )
1457 vcl::RenderTools::DrawSelectionBackground(rRenderContext, *pView, CalcFocusRect(pEntry),
1458 bActiveSelection ? 1 : 2, false, true, false);
1461 PaintItem(aBmpRect, IcnViewFieldType::Image, pEntry, nBmpPaintFlags, rRenderContext);
1463 PaintItem(aTextRect, IcnViewFieldType::Text, pEntry, nTextPaintFlags, rRenderContext);
1465 // draw highlight frame
1466 if (pEntry == pCurHighlightFrame)
1467 DrawHighlightFrame(rRenderContext, CalcFocusRect(pEntry));
1469 rRenderContext.Pop();
1470 if (bResetClipRegion)
1471 rRenderContext.SetClipRegion();
1474 void SvxIconChoiceCtrl_Impl::SetEntryPos( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos )
1476 ShowCursor( false );
1477 tools::Rectangle aBoundRect( GetEntryBoundRect( pEntry ));
1478 pView->Invalidate( aBoundRect );
1479 ToTop( pEntry );
1480 if( !IsAutoArrange() )
1482 bool bAdjustVirtSize = false;
1483 if( rPos != aBoundRect.TopLeft() )
1485 Point aGridOffs(
1486 pEntry->aGridRect.TopLeft() - pEntry->aRect.TopLeft() );
1487 pImpCursor->Clear();
1488 pGridMap->Clear();
1489 aBoundRect.SetPos( rPos );
1490 pEntry->aRect = aBoundRect;
1491 pEntry->aGridRect.SetPos( rPos + aGridOffs );
1492 bAdjustVirtSize = true;
1494 if( bAdjustVirtSize )
1495 AdjustVirtSize( pEntry->aRect );
1497 pView->Invalidate( pEntry->aRect );
1498 pGridMap->OccupyGrids( pEntry );
1500 else
1502 SvxIconChoiceCtrlEntry* pPrev = FindEntryPredecessor( pEntry, rPos );
1503 SetEntryPredecessor( pEntry, pPrev );
1504 aAutoArrangeIdle.Start();
1506 ShowCursor( true );
1509 void SvxIconChoiceCtrl_Impl::SetNoSelection()
1511 // block recursive calls via SelectEntry
1512 if( !(nFlags & IconChoiceFlags::ClearingSelection ))
1514 nFlags |= IconChoiceFlags::ClearingSelection;
1515 DeselectAllBut( nullptr );
1516 nFlags &= ~IconChoiceFlags::ClearingSelection;
1520 SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetEntry( const Point& rDocPos, bool bHit )
1522 CheckBoundingRects();
1523 // search through z-order list from the end
1524 size_t nCount = maZOrderList.size();
1525 while( nCount )
1527 nCount--;
1528 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[ nCount ];
1529 if( pEntry->aRect.IsInside( rDocPos ) )
1531 if( bHit )
1533 tools::Rectangle aRect = CalcBmpRect( pEntry );
1534 aRect.AdjustTop( -3 );
1535 aRect.AdjustBottom(3 );
1536 aRect.AdjustLeft( -3 );
1537 aRect.AdjustRight(3 );
1538 if( aRect.IsInside( rDocPos ) )
1539 return pEntry;
1540 aRect = CalcTextRect( pEntry );
1541 if( aRect.IsInside( rDocPos ) )
1542 return pEntry;
1544 else
1545 return pEntry;
1548 return nullptr;
1551 void SvxIconChoiceCtrl_Impl::MakeEntryVisible( SvxIconChoiceCtrlEntry* pEntry, bool bBound )
1553 if ( bBound )
1555 const tools::Rectangle& rRect = GetEntryBoundRect( pEntry );
1556 MakeVisible( rRect );
1558 else
1560 tools::Rectangle aRect = CalcBmpRect( pEntry );
1561 aRect.Union( CalcTextRect( pEntry ) );
1562 aRect.AdjustTop(TBOFFS_BOUND );
1563 aRect.AdjustBottom(TBOFFS_BOUND );
1564 aRect.AdjustLeft(LROFFS_BOUND );
1565 aRect.AdjustRight(LROFFS_BOUND );
1566 MakeVisible( aRect );
1570 const tools::Rectangle& SvxIconChoiceCtrl_Impl::GetEntryBoundRect( SvxIconChoiceCtrlEntry* pEntry )
1572 if( !IsBoundingRectValid( pEntry->aRect ))
1573 FindBoundingRect( pEntry );
1574 return pEntry->aRect;
1577 tools::Rectangle SvxIconChoiceCtrl_Impl::CalcBmpRect( SvxIconChoiceCtrlEntry* pEntry, const Point* pPos )
1579 tools::Rectangle aBound = GetEntryBoundRect( pEntry );
1580 if( pPos )
1581 aBound.SetPos( *pPos );
1582 Point aPos( aBound.TopLeft() );
1584 switch( nWinBits & VIEWMODE_MASK )
1586 case WB_ICON:
1588 aPos.AdjustX(( aBound.GetWidth() - aImageSize.Width() ) / 2 );
1589 return tools::Rectangle( aPos, aImageSize );
1592 case WB_SMALLICON:
1593 case WB_DETAILS:
1594 aPos.AdjustY(( aBound.GetHeight() - aImageSize.Height() ) / 2 );
1595 //TODO: determine horizontal distance to bounding rectangle
1596 return tools::Rectangle( aPos, aImageSize );
1598 default:
1599 OSL_FAIL("IconView: Viewmode not set");
1600 return aBound;
1604 tools::Rectangle SvxIconChoiceCtrl_Impl::CalcTextRect( SvxIconChoiceCtrlEntry* pEntry,
1605 const Point* pEntryPos, const OUString* pStr )
1607 OUString aEntryText;
1608 if( !pStr )
1609 aEntryText = SvtIconChoiceCtrl::GetEntryText( pEntry );
1610 else
1611 aEntryText = *pStr;
1613 const tools::Rectangle aMaxTextRect( CalcMaxTextRect( pEntry ) );
1614 tools::Rectangle aBound( GetEntryBoundRect( pEntry ) );
1615 if( pEntryPos )
1616 aBound.SetPos( *pEntryPos );
1618 tools::Rectangle aTextRect = pView->GetTextRect( aMaxTextRect, aEntryText, nCurTextDrawFlags );
1620 Size aTextSize( aTextRect.GetSize() );
1622 Point aPos( aBound.TopLeft() );
1623 tools::Long nBoundWidth = aBound.GetWidth();
1624 tools::Long nBoundHeight = aBound.GetHeight();
1626 switch( nWinBits & VIEWMODE_MASK )
1628 case WB_ICON:
1629 aPos.AdjustY(aImageSize.Height() );
1630 aPos.AdjustY(VER_DIST_BMP_STRING );
1631 aPos.AdjustX((nBoundWidth - aTextSize.Width()) / 2 );
1632 break;
1634 case WB_SMALLICON:
1635 case WB_DETAILS:
1636 aPos.AdjustX(aImageSize.Width() );
1637 aPos.AdjustX(HOR_DIST_BMP_STRING );
1638 aPos.AdjustY((nBoundHeight - aTextSize.Height()) / 2 );
1639 break;
1641 return tools::Rectangle( aPos, aTextSize );
1645 tools::Long SvxIconChoiceCtrl_Impl::CalcBoundingWidth() const
1647 tools::Long nStringWidth = GetItemSize( IcnViewFieldType::Text ).Width();
1648 tools::Long nWidth = 0;
1650 switch( nWinBits & VIEWMODE_MASK )
1652 case WB_ICON:
1653 nWidth = std::max( nStringWidth, aImageSize.Width() );
1654 break;
1656 case WB_SMALLICON:
1657 case WB_DETAILS:
1658 nWidth = aImageSize.Width();
1659 nWidth += HOR_DIST_BMP_STRING;
1660 nWidth += nStringWidth;
1661 break;
1663 return nWidth;
1666 tools::Long SvxIconChoiceCtrl_Impl::CalcBoundingHeight() const
1668 tools::Long nStringHeight = GetItemSize(IcnViewFieldType::Text).Height();
1669 tools::Long nHeight = 0;
1671 switch( nWinBits & VIEWMODE_MASK )
1673 case WB_ICON:
1674 nHeight = aImageSize.Height();
1675 nHeight += VER_DIST_BMP_STRING;
1676 nHeight += nStringHeight;
1677 break;
1679 case WB_SMALLICON:
1680 case WB_DETAILS:
1681 nHeight = std::max( aImageSize.Height(), nStringHeight );
1682 break;
1684 if( nHeight > nMaxBoundHeight )
1686 const_cast<SvxIconChoiceCtrl_Impl*>(this)->nMaxBoundHeight = nHeight;
1687 const_cast<SvxIconChoiceCtrl_Impl*>(this)->aHorSBar->SetLineSize( GetScrollBarLineSize() );
1688 const_cast<SvxIconChoiceCtrl_Impl*>(this)->aVerSBar->SetLineSize( GetScrollBarLineSize() );
1690 return nHeight;
1693 Size SvxIconChoiceCtrl_Impl::CalcBoundingSize() const
1695 return Size( CalcBoundingWidth(), CalcBoundingHeight() );
1698 void SvxIconChoiceCtrl_Impl::RecalcAllBoundingRectsSmart()
1700 nMaxBoundHeight = 0;
1701 maZOrderList.clear();
1702 size_t nCur;
1703 SvxIconChoiceCtrlEntry* pEntry;
1704 const size_t nCount = maEntries.size();
1706 if( !IsAutoArrange() || !pHead )
1708 for( nCur = 0; nCur < nCount; nCur++ )
1710 pEntry = maEntries[ nCur ].get();
1711 if( IsBoundingRectValid( pEntry->aRect ))
1713 Size aBoundSize( pEntry->aRect.GetSize() );
1714 if( aBoundSize.Height() > nMaxBoundHeight )
1715 nMaxBoundHeight = aBoundSize.Height();
1717 else
1718 FindBoundingRect( pEntry );
1719 maZOrderList.push_back( pEntry );
1722 else
1724 nCur = 0;
1725 pEntry = pHead;
1726 while( nCur != nCount )
1728 DBG_ASSERT(pEntry->pflink&&pEntry->pblink,"SvxIconChoiceCtrl_Impl::RecalcAllBoundingRect > Bad link(s)");
1729 if( IsBoundingRectValid( pEntry->aRect ))
1731 Size aBoundSize( pEntry->aRect.GetSize() );
1732 if( aBoundSize.Height() > nMaxBoundHeight )
1733 nMaxBoundHeight = aBoundSize.Height();
1735 else
1736 FindBoundingRect( pEntry );
1737 maZOrderList.push_back( pEntry );
1738 pEntry = pEntry->pflink;
1739 nCur++;
1742 AdjustScrollBars();
1745 void SvxIconChoiceCtrl_Impl::FindBoundingRect( SvxIconChoiceCtrlEntry* pEntry )
1747 DBG_ASSERT(!pEntry->IsPosLocked(),"Locked entry pos in FindBoundingRect");
1748 if( pEntry->IsPosLocked() && IsBoundingRectValid( pEntry->aRect) )
1750 AdjustVirtSize( pEntry->aRect );
1751 return;
1753 Size aSize( CalcBoundingSize() );
1754 Point aPos(pGridMap->GetGridRect(pGridMap->GetUnoccupiedGrid()).TopLeft());
1755 SetBoundingRect_Impl( pEntry, aPos, aSize );
1758 void SvxIconChoiceCtrl_Impl::SetBoundingRect_Impl( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos,
1759 const Size& /*rBoundingSize*/ )
1761 tools::Rectangle aGridRect( rPos, Size(nGridDX, nGridDY) );
1762 pEntry->aGridRect = aGridRect;
1763 Center( pEntry );
1764 AdjustVirtSize( pEntry->aRect );
1765 pGridMap->OccupyGrids( pEntry );
1769 void SvxIconChoiceCtrl_Impl::SetCursor( SvxIconChoiceCtrlEntry* pEntry )
1771 if( pEntry == pCursor )
1773 if( pCursor && eSelectionMode == SelectionMode::Single &&
1774 !pCursor->IsSelected() )
1775 SelectEntry( pCursor, true );
1776 return;
1778 ShowCursor( false );
1779 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
1780 pCursor = pEntry;
1781 if( pOldCursor )
1783 pOldCursor->ClearFlags( SvxIconViewFlags::FOCUSED );
1784 if( eSelectionMode == SelectionMode::Single )
1785 SelectEntry( pOldCursor, false ); // deselect old cursor
1787 if( pCursor )
1789 ToTop( pCursor );
1790 pCursor->SetFlags( SvxIconViewFlags::FOCUSED );
1791 if( eSelectionMode == SelectionMode::Single )
1792 SelectEntry( pCursor, true );
1793 ShowCursor( true );
1798 void SvxIconChoiceCtrl_Impl::ShowCursor( bool bShow )
1800 if( !pCursor || !bShow || !pView->HasFocus() )
1802 pView->HideFocus();
1803 return;
1805 tools::Rectangle aRect ( CalcFocusRect( pCursor ) );
1806 /*pView->*/ShowFocus( aRect );
1810 void SvxIconChoiceCtrl_Impl::HideDDIcon()
1812 pView->PaintImmediately();
1815 bool SvxIconChoiceCtrl_Impl::HandleScrollCommand( const CommandEvent& rCmd )
1817 tools::Rectangle aDocRect( Point(), aVirtOutputSize );
1818 tools::Rectangle aVisRect( GetOutputRect() );
1819 if( aVisRect.IsInside( aDocRect ))
1820 return false;
1821 Size aDocSize( aDocRect.GetSize() );
1822 Size aVisSize( aVisRect.GetSize() );
1823 bool bHor = aDocSize.Width() > aVisSize.Width();
1824 bool bVer = aDocSize.Height() > aVisSize.Height();
1826 tools::Long nScrollDX = 0, nScrollDY = 0;
1828 switch( rCmd.GetCommand() )
1830 case CommandEventId::StartAutoScroll:
1832 pView->EndTracking();
1833 StartAutoScrollFlags nScrollFlags = StartAutoScrollFlags::NONE;
1834 if( bHor )
1835 nScrollFlags |= StartAutoScrollFlags::Horz;
1836 if( bVer )
1837 nScrollFlags |= StartAutoScrollFlags::Vert;
1838 if( nScrollFlags != StartAutoScrollFlags::NONE )
1840 pView->StartAutoScroll( nScrollFlags );
1841 return true;
1844 break;
1846 case CommandEventId::Wheel:
1848 const CommandWheelData* pData = rCmd.GetWheelData();
1849 if( pData && (CommandWheelMode::SCROLL == pData->GetMode()) && !pData->IsHorz() )
1851 sal_uLong nScrollLines = pData->GetScrollLines();
1852 if( nScrollLines == COMMAND_WHEEL_PAGESCROLL )
1854 nScrollDY = GetScrollBarPageSize( aVisSize.Width() );
1855 if( pData->GetDelta() < 0 )
1856 nScrollDY *= -1;
1858 else
1860 nScrollDY = pData->GetNotchDelta() * static_cast<tools::Long>(nScrollLines);
1861 nScrollDY *= GetScrollBarLineSize();
1865 break;
1867 case CommandEventId::AutoScroll:
1869 const CommandScrollData* pData = rCmd.GetAutoScrollData();
1870 if( pData )
1872 nScrollDX = pData->GetDeltaX() * GetScrollBarLineSize();
1873 nScrollDY = pData->GetDeltaY() * GetScrollBarLineSize();
1876 break;
1878 default: break;
1881 if( nScrollDX || nScrollDY )
1883 aVisRect.AdjustTop( -nScrollDY );
1884 aVisRect.AdjustBottom( -nScrollDY );
1885 aVisRect.AdjustLeft( -nScrollDX );
1886 aVisRect.AdjustRight( -nScrollDX );
1887 MakeVisible( aVisRect );
1888 return true;
1890 return false;
1894 void SvxIconChoiceCtrl_Impl::Command( const CommandEvent& rCEvt )
1896 // scroll mouse event?
1897 if( (rCEvt.GetCommand() == CommandEventId::Wheel) ||
1898 (rCEvt.GetCommand() == CommandEventId::StartAutoScroll) ||
1899 (rCEvt.GetCommand() == CommandEventId::AutoScroll) )
1901 if( HandleScrollCommand( rCEvt ) )
1902 return;
1906 void SvxIconChoiceCtrl_Impl::ToTop( SvxIconChoiceCtrlEntry* pEntry )
1908 if( maZOrderList.empty() || pEntry == maZOrderList.back())
1909 return;
1911 auto it = std::find(maZOrderList.begin(), maZOrderList.end(), pEntry);
1912 if (it != maZOrderList.end())
1914 maZOrderList.erase( it );
1915 maZOrderList.push_back( pEntry );
1919 void SvxIconChoiceCtrl_Impl::ClipAtVirtOutRect( tools::Rectangle& rRect ) const
1921 if( rRect.Bottom() >= aVirtOutputSize.Height() )
1922 rRect.SetBottom( aVirtOutputSize.Height() - 1 );
1923 if( rRect.Right() >= aVirtOutputSize.Width() )
1924 rRect.SetRight( aVirtOutputSize.Width() - 1 );
1925 if( rRect.Top() < 0 )
1926 rRect.SetTop( 0 );
1927 if( rRect.Left() < 0 )
1928 rRect.SetLeft( 0 );
1931 // rRect: area of the document (in document coordinates) that we want to make
1932 // visible
1933 // bScrBar == true: rectangle was calculated because of a scrollbar event
1935 void SvxIconChoiceCtrl_Impl::MakeVisible( const tools::Rectangle& rRect, bool bScrBar )
1937 tools::Rectangle aVirtRect( rRect );
1938 ClipAtVirtOutRect( aVirtRect );
1939 Point aOrigin( pView->GetMapMode().GetOrigin() );
1940 // convert to document coordinate
1941 aOrigin *= -1;
1942 tools::Rectangle aOutputArea( GetOutputRect() );
1943 if( aOutputArea.IsInside( aVirtRect ) )
1944 return; // is already visible
1946 tools::Long nDy;
1947 if( aVirtRect.Top() < aOutputArea.Top() )
1949 // scroll up (nDy < 0)
1950 nDy = aVirtRect.Top() - aOutputArea.Top();
1952 else if( aVirtRect.Bottom() > aOutputArea.Bottom() )
1954 // scroll down (nDy > 0)
1955 nDy = aVirtRect.Bottom() - aOutputArea.Bottom();
1957 else
1958 nDy = 0;
1960 tools::Long nDx;
1961 if( aVirtRect.Left() < aOutputArea.Left() )
1963 // scroll to the left (nDx < 0)
1964 nDx = aVirtRect.Left() - aOutputArea.Left();
1966 else if( aVirtRect.Right() > aOutputArea.Right() )
1968 // scroll to the right (nDx > 0)
1969 nDx = aVirtRect.Right() - aOutputArea.Right();
1971 else
1972 nDx = 0;
1974 aOrigin.AdjustX(nDx );
1975 aOrigin.AdjustY(nDy );
1976 aOutputArea.SetPos( aOrigin );
1977 if( GetUpdateMode() )
1979 HideDDIcon();
1980 pView->PaintImmediately();
1981 ShowCursor( false );
1984 // invert origin for SV (so we can scroll/paint using document coordinates)
1985 aOrigin *= -1;
1986 SetOrigin( aOrigin );
1988 bool bScrollable = pView->GetBackground().IsScrollable();
1990 if( bScrollable && GetUpdateMode() )
1992 // scroll in reverse direction!
1993 pView->Control::Scroll( -nDx, -nDy, aOutputArea,
1994 ScrollFlags::NoChildren | ScrollFlags::UseClipRegion | ScrollFlags::Clip );
1996 else
1997 pView->Invalidate(InvalidateFlags::NoChildren);
1999 if( aHorSBar->IsVisible() || aVerSBar->IsVisible() )
2001 if( !bScrBar )
2003 aOrigin *= -1;
2004 // correct thumbs
2005 if(aHorSBar->IsVisible() && aHorSBar->GetThumbPos() != aOrigin.X())
2006 aHorSBar->SetThumbPos( aOrigin.X() );
2007 if(aVerSBar->IsVisible() && aVerSBar->GetThumbPos() != aOrigin.Y())
2008 aVerSBar->SetThumbPos( aOrigin.Y() );
2012 if( GetUpdateMode() )
2013 ShowCursor( true );
2015 // check if we still need scrollbars
2016 CheckScrollBars();
2017 if( bScrollable && GetUpdateMode() )
2018 pView->PaintImmediately();
2020 // If the requested area can not be made completely visible, the
2021 // Vis-Rect-Changed handler is called in any case. This case may occur e.g.
2022 // if only few pixels of the lower border are invisible, but a scrollbar has
2023 // a larger line size.
2024 VisRectChanged();
2027 sal_Int32 SvxIconChoiceCtrl_Impl::GetSelectionCount() const
2029 if( (nWinBits & WB_HIGHLIGHTFRAME) && pCurHighlightFrame )
2030 return 1;
2031 return nSelectionCount;
2034 void SvxIconChoiceCtrl_Impl::ToggleSelection( SvxIconChoiceCtrlEntry* pEntry )
2036 bool bSel;
2037 bSel = !pEntry->IsSelected();
2038 SelectEntry( pEntry, bSel, true );
2041 void SvxIconChoiceCtrl_Impl::DeselectAllBut( SvxIconChoiceCtrlEntry const * pThisEntryNot )
2043 ClearSelectedRectList();
2045 // TODO: work through z-order list, if necessary!
2047 size_t nCount = maEntries.size();
2048 for( size_t nCur = 0; nCur < nCount; nCur++ )
2050 SvxIconChoiceCtrlEntry* pEntry = maEntries[ nCur ].get();
2051 if( pEntry != pThisEntryNot && pEntry->IsSelected() )
2052 SelectEntry( pEntry, false, true );
2054 pAnchor = nullptr;
2055 nFlags &= ~IconChoiceFlags::AddMode;
2058 Size SvxIconChoiceCtrl_Impl::GetMinGrid() const
2060 Size aMinSize( aImageSize );
2061 aMinSize.AdjustWidth(2 * LROFFS_BOUND );
2062 aMinSize.AdjustHeight(TBOFFS_BOUND ); // single offset is enough (FileDlg)
2063 Size aTextSize( pView->GetTextWidth( "XXX" ), pView->GetTextHeight() );
2064 if( nWinBits & WB_ICON )
2066 aMinSize.AdjustHeight(VER_DIST_BMP_STRING );
2067 aMinSize.AdjustHeight(aTextSize.Height() );
2069 else
2071 aMinSize.AdjustWidth(HOR_DIST_BMP_STRING );
2072 aMinSize.AdjustWidth(aTextSize.Width() );
2074 return aMinSize;
2077 void SvxIconChoiceCtrl_Impl::SetGrid( const Size& rSize )
2079 Size aSize( rSize );
2080 Size aMinSize( GetMinGrid() );
2081 if( aSize.Width() < aMinSize.Width() )
2082 aSize.setWidth( aMinSize.Width() );
2083 if( aSize.Height() < aMinSize.Height() )
2084 aSize.setHeight( aMinSize.Height() );
2086 nGridDX = aSize.Width();
2087 // HACK: Detail mode is not yet fully implemented, this workaround makes it
2088 // fly with a single column
2089 if( nWinBits & WB_DETAILS )
2091 const SvxIconChoiceCtrlColumnInfo* pCol = GetColumn( 0 );
2092 if( pCol )
2093 const_cast<SvxIconChoiceCtrlColumnInfo*>(pCol)->SetWidth( nGridDX );
2095 nGridDY = aSize.Height();
2096 SetDefaultTextSize();
2099 // Calculates the maximum size that the text rectangle may use within its
2100 // bounding rectangle. In WB_ICON mode with SvxIconChoiceCtrlTextMode::Full, Bottom is set to
2101 // LONG_MAX.
2103 tools::Rectangle SvxIconChoiceCtrl_Impl::CalcMaxTextRect( const SvxIconChoiceCtrlEntry* pEntry ) const
2105 tools::Rectangle aBoundRect;
2106 // avoid infinite recursion: don't calculate the bounding rectangle here
2107 if( IsBoundingRectValid( pEntry->aRect ) )
2108 aBoundRect = pEntry->aRect;
2109 else
2110 aBoundRect = pEntry->aGridRect;
2112 tools::Rectangle aBmpRect( const_cast<SvxIconChoiceCtrl_Impl*>(this)->CalcBmpRect(
2113 const_cast<SvxIconChoiceCtrlEntry*>(pEntry) ) );
2114 if( nWinBits & WB_ICON )
2116 aBoundRect.SetTop( aBmpRect.Bottom() );
2117 aBoundRect.AdjustTop(VER_DIST_BMP_STRING );
2118 if( aBoundRect.Top() > aBoundRect.Bottom())
2119 aBoundRect.SetTop( aBoundRect.Bottom() );
2120 aBoundRect.AdjustLeft(LROFFS_BOUND );
2121 aBoundRect.AdjustLeft( 1 );
2122 aBoundRect.AdjustRight( -(LROFFS_BOUND) );
2123 aBoundRect.AdjustRight( -1 );
2124 if( aBoundRect.Left() > aBoundRect.Right())
2125 aBoundRect.SetLeft( aBoundRect.Right() );
2126 if( pEntry->GetTextMode() == SvxIconChoiceCtrlTextMode::Full )
2127 aBoundRect.SetBottom( LONG_MAX );
2129 else
2131 aBoundRect.SetLeft( aBmpRect.Right() );
2132 aBoundRect.AdjustLeft(HOR_DIST_BMP_STRING );
2133 aBoundRect.AdjustRight( -(LROFFS_BOUND) );
2134 if( aBoundRect.Left() > aBoundRect.Right() )
2135 aBoundRect.SetLeft( aBoundRect.Right() );
2136 tools::Long nHeight = aBoundRect.GetSize().Height();
2137 nHeight = nHeight - aDefaultTextSize.Height();
2138 nHeight /= 2;
2139 aBoundRect.AdjustTop(nHeight );
2140 aBoundRect.AdjustBottom( -nHeight );
2142 return aBoundRect;
2145 void SvxIconChoiceCtrl_Impl::SetDefaultTextSize()
2147 tools::Long nDY = nGridDY;
2148 nDY -= aImageSize.Height();
2149 nDY -= VER_DIST_BMP_STRING;
2150 nDY -= 2 * TBOFFS_BOUND;
2151 if (nDY <= 0)
2152 nDY = 2;
2154 tools::Long nDX = nGridDX;
2155 nDX -= 2 * LROFFS_BOUND;
2156 nDX -= 2;
2157 if (nDX <= 0)
2158 nDX = 2;
2160 tools::Long nHeight = pView->GetTextHeight();
2161 if (nDY < nHeight)
2162 nDY = nHeight;
2163 if(pView->GetDPIScaleFactor() > 1)
2165 nDY*=2;
2167 aDefaultTextSize = Size(nDX, nDY);
2171 void SvxIconChoiceCtrl_Impl::Center( SvxIconChoiceCtrlEntry* pEntry ) const
2173 pEntry->aRect = pEntry->aGridRect;
2174 Size aSize( CalcBoundingSize() );
2175 if( nWinBits & WB_ICON )
2177 // center horizontally
2178 tools::Long nBorder = pEntry->aGridRect.GetWidth() - aSize.Width();
2179 pEntry->aRect.AdjustLeft(nBorder / 2 );
2180 pEntry->aRect.AdjustRight( -(nBorder / 2) );
2182 // center vertically
2183 pEntry->aRect.SetBottom( pEntry->aRect.Top() + aSize.Height() );
2187 // The deltas are the offsets by which the view is moved on the document.
2188 // left, up: offsets < 0
2189 // right, down: offsets > 0
2190 void SvxIconChoiceCtrl_Impl::Scroll( tools::Long nDeltaX, tools::Long nDeltaY )
2192 const MapMode& rMapMode = pView->GetMapMode();
2193 Point aOrigin( rMapMode.GetOrigin() );
2194 // convert to document coordinate
2195 aOrigin *= -1;
2196 aOrigin.AdjustY(nDeltaY );
2197 aOrigin.AdjustX(nDeltaX );
2198 tools::Rectangle aRect( aOrigin, aOutputSize );
2199 MakeVisible( aRect, true/*bScrollBar*/ );
2203 const Size& SvxIconChoiceCtrl_Impl::GetItemSize( IcnViewFieldType eItem ) const
2205 if (eItem == IcnViewFieldType::Text)
2206 return aDefaultTextSize;
2207 return aImageSize; // IcnViewFieldType::Image
2210 tools::Rectangle SvxIconChoiceCtrl_Impl::CalcFocusRect( SvxIconChoiceCtrlEntry* pEntry )
2212 tools::Rectangle aTextRect( CalcTextRect( pEntry ) );
2213 tools::Rectangle aBoundRect( GetEntryBoundRect( pEntry ) );
2214 return tools::Rectangle(
2215 aBoundRect.Left(), aBoundRect.Top() - 1, aBoundRect.Right() - 1,
2216 aTextRect.Bottom() + 1);
2219 // the hot spot is the inner 50% of the rectangle
2220 static tools::Rectangle GetHotSpot( const tools::Rectangle& rRect )
2222 tools::Rectangle aResult( rRect );
2223 aResult.Justify();
2224 Size aSize( rRect.GetSize() );
2225 tools::Long nDelta = aSize.Width() / 4;
2226 aResult.AdjustLeft(nDelta );
2227 aResult.AdjustRight( -nDelta );
2228 nDelta = aSize.Height() / 4;
2229 aResult.AdjustTop(nDelta );
2230 aResult.AdjustBottom( -nDelta );
2231 return aResult;
2234 void SvxIconChoiceCtrl_Impl::SelectRect( SvxIconChoiceCtrlEntry* pEntry1, SvxIconChoiceCtrlEntry* pEntry2,
2235 bool bAdd, std::vector<tools::Rectangle>* pOtherRects )
2237 DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr");
2238 tools::Rectangle aRect( GetEntryBoundRect( pEntry1 ) );
2239 aRect.Union( GetEntryBoundRect( pEntry2 ) );
2240 SelectRect( aRect, bAdd, pOtherRects );
2243 void SvxIconChoiceCtrl_Impl::SelectRect( const tools::Rectangle& rRect, bool bAdd,
2244 std::vector<tools::Rectangle>* pOtherRects )
2246 aCurSelectionRect = rRect;
2247 if( maZOrderList.empty() )
2248 return;
2250 // set flag, so ToTop won't be called in Select
2251 bool bAlreadySelectingRect(nFlags & IconChoiceFlags::SelectingRect);
2252 nFlags |= IconChoiceFlags::SelectingRect;
2254 CheckBoundingRects();
2255 pView->PaintImmediately();
2256 const size_t nCount = maZOrderList.size();
2258 tools::Rectangle aRect( rRect );
2259 aRect.Justify();
2260 bool bCalcOverlap = (bAdd && pOtherRects && !pOtherRects->empty());
2262 bool bResetClipRegion = false;
2263 if( !pView->IsClipRegion() )
2265 bResetClipRegion = true;
2266 pView->SetClipRegion(vcl::Region(GetOutputRect()));
2269 for( size_t nPos = 0; nPos < nCount; nPos++ )
2271 SvxIconChoiceCtrlEntry* pEntry = maZOrderList[ nPos ];
2273 if( !IsBoundingRectValid( pEntry->aRect ))
2274 FindBoundingRect( pEntry );
2275 tools::Rectangle aBoundRect( GetHotSpot( pEntry->aRect ) );
2276 bool bSelected = pEntry->IsSelected();
2278 bool bOverlaps;
2279 if( bCalcOverlap )
2280 bOverlaps = IsOver( pOtherRects, aBoundRect );
2281 else
2282 bOverlaps = false;
2283 bool bOver = aRect.IsOver( aBoundRect );
2285 if( bOver && !bOverlaps )
2287 // is inside the new selection rectangle and outside of any old one
2288 // => select
2289 if( !bSelected )
2290 SelectEntry( pEntry, true, true );
2292 else if( !bAdd )
2294 // is outside of the selection rectangle
2295 // => deselect
2296 if( bSelected )
2297 SelectEntry( pEntry, false, true );
2299 else if (bOverlaps)
2301 // The entry is inside an old (=>span multiple rectangles with Ctrl)
2302 // selection rectangle.
2304 // There is still a bug here! The selection status of an entry in a
2305 // previous rectangle has to be restored, if it was touched by the
2306 // current selection rectangle but is not inside it any more.
2307 // For simplicity's sake, let's assume that all entries in the old
2308 // rectangles were correctly selected. It is wrong to just deselect
2309 // the intersection.
2310 // Possible solution: remember a snapshot of the selection before
2311 // spanning the rectangle.
2312 if( aBoundRect.IsOver( rRect))
2314 // deselect intersection between old rectangles and current rectangle
2315 if( bSelected )
2316 SelectEntry( pEntry, false, true );
2318 else
2320 // select entry of an old rectangle
2321 if( !bSelected )
2322 SelectEntry( pEntry, true, true );
2325 else if( !bOver && bSelected )
2327 // this entry is completely outside the rectangle => deselect it
2328 SelectEntry( pEntry, false, true );
2332 if( !bAlreadySelectingRect )
2333 nFlags &= ~IconChoiceFlags::SelectingRect;
2335 pView->PaintImmediately();
2336 if( bResetClipRegion )
2337 pView->SetClipRegion();
2340 void SvxIconChoiceCtrl_Impl::SelectRange(
2341 SvxIconChoiceCtrlEntry const * pStart,
2342 SvxIconChoiceCtrlEntry const * pEnd,
2343 bool bAdd )
2345 sal_uLong nFront = GetEntryListPos( pStart );
2346 sal_uLong nBack = GetEntryListPos( pEnd );
2347 sal_uLong nFirst = std::min( nFront, nBack );
2348 sal_uLong nLast = std::max( nFront, nBack );
2349 sal_uLong i;
2350 SvxIconChoiceCtrlEntry* pEntry;
2352 if ( ! bAdd )
2354 // deselect everything before the first entry if not in
2355 // adding mode
2356 for ( i=0; i<nFirst; i++ )
2358 pEntry = GetEntry( i );
2359 if( pEntry->IsSelected() )
2360 SelectEntry( pEntry, false, true );
2364 // select everything between nFirst and nLast
2365 for ( i=nFirst; i<=nLast; i++ )
2367 pEntry = GetEntry( i );
2368 if( ! pEntry->IsSelected() )
2369 SelectEntry( pEntry, true, true );
2372 if ( ! bAdd )
2374 // deselect everything behind the last entry if not in
2375 // adding mode
2376 sal_uLong nEnd = GetEntryCount();
2377 for ( ; i<nEnd; i++ )
2379 pEntry = GetEntry( i );
2380 if( pEntry->IsSelected() )
2381 SelectEntry( pEntry, false, true );
2386 bool SvxIconChoiceCtrl_Impl::IsOver( std::vector<tools::Rectangle>* pRectList, const tools::Rectangle& rBoundRect )
2388 const sal_uInt16 nCount = pRectList->size();
2389 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
2391 tools::Rectangle& rRect = (*pRectList)[ nCur ];
2392 if( rBoundRect.IsOver( rRect ))
2393 return true;
2395 return false;
2398 void SvxIconChoiceCtrl_Impl::AddSelectedRect( SvxIconChoiceCtrlEntry* pEntry1,
2399 SvxIconChoiceCtrlEntry* pEntry2 )
2401 DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr");
2402 tools::Rectangle aRect( GetEntryBoundRect( pEntry1 ) );
2403 aRect.Union( GetEntryBoundRect( pEntry2 ) );
2404 AddSelectedRect( aRect );
2407 void SvxIconChoiceCtrl_Impl::AddSelectedRect( const tools::Rectangle& rRect )
2409 tools::Rectangle newRect = rRect;
2410 newRect.Justify();
2411 aSelectedRectList.push_back( newRect );
2414 void SvxIconChoiceCtrl_Impl::ClearSelectedRectList()
2416 aSelectedRectList.clear();
2419 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl, AutoArrangeHdl, Timer *, void)
2421 aAutoArrangeIdle.Stop();
2422 Arrange( IsAutoArrange(), 0, 0 );
2425 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl, VisRectChangedHdl, Timer *, void)
2427 aVisRectChangedIdle.Stop();
2430 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl, DocRectChangedHdl, Timer *, void)
2432 aDocRectChangedIdle.Stop();
2435 #ifdef DBG_UTIL
2436 void SvxIconChoiceCtrl_Impl::SetEntryTextMode( SvxIconChoiceCtrlTextMode eMode, SvxIconChoiceCtrlEntry* pEntry )
2438 if( !pEntry )
2440 if( eTextMode != eMode )
2442 eTextMode = eMode;
2443 Arrange( true, 0, 0 );
2446 else
2448 if( pEntry->eTextMode != eMode )
2450 pEntry->eTextMode = eMode;
2451 InvalidateEntry( pEntry );
2452 pView->Invalidate( GetEntryBoundRect( pEntry ) );
2453 AdjustVirtSize( pEntry->aRect );
2457 #endif
2459 // Draw my own focusrect, because the focusrect of the outputdevice has got the inverted color
2460 // of the background. But what will we see, if the backgroundcolor is gray ? - We will see
2461 // a gray focusrect on a gray background !!!
2463 void SvxIconChoiceCtrl_Impl::ShowFocus ( tools::Rectangle const & rRect )
2465 Color aBkgColor(pView->GetBackground().GetColor());
2466 Color aPenColor;
2467 sal_uInt16 nColor = ( aBkgColor.GetRed() + aBkgColor.GetGreen() + aBkgColor.GetBlue() ) / 3;
2468 if (nColor > 128)
2469 aPenColor = COL_BLACK;
2470 else
2471 aPenColor = COL_WHITE;
2473 aFocus.aPenColor = aPenColor;
2474 aFocus.aRect = rRect;
2477 void SvxIconChoiceCtrl_Impl::DrawFocusRect(vcl::RenderContext& rRenderContext)
2479 rRenderContext.SetLineColor(aFocus.aPenColor);
2480 rRenderContext.SetFillColor();
2481 tools::Polygon aPolygon (aFocus.aRect);
2483 LineInfo aLineInfo(LineStyle::Dash);
2485 aLineInfo.SetDashLen(1);
2486 aLineInfo.SetDotLen(1);
2487 aLineInfo.SetDistance(1);
2488 aLineInfo.SetDotCount(1);
2490 rRenderContext.DrawPolyLine(aPolygon, aLineInfo);
2493 bool SvxIconChoiceCtrl_Impl::IsMnemonicChar( sal_Unicode cChar, sal_uLong& rPos ) const
2495 bool bRet = false;
2496 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
2497 size_t nEntryCount = GetEntryCount();
2498 for ( size_t i = 0; i < nEntryCount; ++i )
2500 if ( rI18nHelper.MatchMnemonic( GetEntry( i )->GetText(), cChar ) )
2502 bRet = true;
2503 rPos = i;
2504 break;
2508 return bRet;
2512 IMPL_LINK(SvxIconChoiceCtrl_Impl, UserEventHdl, void*, nId, void )
2514 if( nId == EVENTID_ADJUST_SCROLLBARS )
2516 nUserEventAdjustScrBars = nullptr;
2517 AdjustScrollBars();
2519 else if( nId == EVENTID_SHOW_CURSOR )
2521 ShowCursor( true );
2525 void SvxIconChoiceCtrl_Impl::CancelUserEvents()
2527 if( nUserEventAdjustScrBars )
2529 Application::RemoveUserEvent( nUserEventAdjustScrBars );
2530 nUserEventAdjustScrBars = nullptr;
2534 void SvxIconChoiceCtrl_Impl::InvalidateEntry( SvxIconChoiceCtrlEntry* pEntry )
2536 if( pEntry == pCursor )
2537 ShowCursor( false );
2538 pView->Invalidate( pEntry->aRect );
2539 Center( pEntry );
2540 pView->Invalidate( pEntry->aRect );
2541 if( pEntry == pCursor )
2542 ShowCursor( true );
2545 SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry() const
2547 if( !GetSelectionCount() )
2548 return nullptr;
2550 if( (nWinBits & WB_HIGHLIGHTFRAME) && (eSelectionMode == SelectionMode::NONE) )
2552 return pCurHighlightFrame;
2555 size_t nCount = maEntries.size();
2556 if( !pHead )
2558 for( size_t nCur = 0; nCur < nCount; nCur++ )
2560 SvxIconChoiceCtrlEntry* pEntry = maEntries[ nCur ].get();
2561 if( pEntry->IsSelected() )
2563 return pEntry;
2567 else
2569 SvxIconChoiceCtrlEntry* pEntry = pHead;
2570 while( nCount-- )
2572 if( pEntry->IsSelected() )
2574 return pEntry;
2576 pEntry = pEntry->pflink;
2577 if( nCount && pEntry == pHead )
2579 OSL_FAIL("SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry > infinite loop!");
2580 return nullptr;
2584 return nullptr;
2587 void SvxIconChoiceCtrl_Impl::SelectAll()
2589 size_t nCount = maEntries.size();
2590 for( size_t nCur = 0; nCur < nCount; nCur++ )
2592 SvxIconChoiceCtrlEntry* pEntry = maEntries[ nCur ].get();
2593 SelectEntry( pEntry, true/*bSelect*/, true );
2595 nFlags &= ~IconChoiceFlags::AddMode;
2596 pAnchor = nullptr;
2602 sal_Int32 SvxIconChoiceCtrl_Impl::GetEntryListPos( SvxIconChoiceCtrlEntry const * pEntry ) const
2604 if( !(nFlags & IconChoiceFlags::EntryListPosValid ))
2605 const_cast<SvxIconChoiceCtrl_Impl*>(this)->SetListPositions();
2606 return pEntry->nPos;
2609 void SvxIconChoiceCtrl_Impl::InitSettings()
2611 const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings();
2613 // unit (from settings) is Point
2614 vcl::Font aFont( rStyleSettings.GetFieldFont() );
2615 aFont.SetColor( rStyleSettings.GetWindowTextColor() );
2616 pView->SetPointFont( aFont );
2617 SetDefaultTextSize();
2619 pView->SetTextColor( rStyleSettings.GetFieldTextColor() );
2620 pView->SetTextFillColor();
2622 pView->SetBackground( rStyleSettings.GetFieldColor());
2624 tools::Long nScrBarSize = rStyleSettings.GetScrollBarSize();
2625 if( nScrBarSize == nHorSBarHeight && nScrBarSize == nVerSBarWidth )
2626 return;
2628 nHorSBarHeight = nScrBarSize;
2629 Size aSize( aHorSBar->GetSizePixel() );
2630 aSize.setHeight( nScrBarSize );
2631 aHorSBar->Hide();
2632 aHorSBar->SetSizePixel( aSize );
2634 nVerSBarWidth = nScrBarSize;
2635 aSize = aVerSBar->GetSizePixel();
2636 aSize.setWidth( nScrBarSize );
2637 aVerSBar->Hide();
2638 aVerSBar->SetSizePixel( aSize );
2640 Size aOSize( pView->Control::GetOutputSizePixel() );
2641 PositionScrollBars( aOSize.Width(), aOSize.Height() );
2642 AdjustScrollBars();
2645 void SvxIconChoiceCtrl_Impl::SetPositionMode( SvxIconChoiceCtrlPositionMode eMode )
2647 if( eMode == ePositionMode )
2648 return;
2650 SvxIconChoiceCtrlPositionMode eOldMode = ePositionMode;
2651 ePositionMode = eMode;
2652 size_t nCount = maEntries.size();
2654 if( eOldMode == SvxIconChoiceCtrlPositionMode::AutoArrange )
2656 // when positioning moved entries "hard", there are problems with
2657 // unwanted overlaps, as these entries aren't taken into account in
2658 // Arrange.
2659 if( maEntries.size() )
2660 aAutoArrangeIdle.Start();
2661 return;
2664 if( ePositionMode == SvxIconChoiceCtrlPositionMode::AutoArrange )
2666 for( size_t nCur = 0; nCur < nCount; nCur++ )
2668 SvxIconChoiceCtrlEntry* pEntry = maEntries[ nCur ].get();
2669 if( pEntry->GetFlags() & SvxIconViewFlags(SvxIconViewFlags::POS_LOCKED | SvxIconViewFlags::POS_MOVED))
2670 SetEntryPos(pEntry, GetEntryBoundRect( pEntry ).TopLeft());
2673 if( maEntries.size() )
2674 aAutoArrangeIdle.Start();
2678 void SvxIconChoiceCtrl_Impl::SetEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry,
2679 SvxIconChoiceCtrlEntry* pPredecessor )
2681 if( !IsAutoArrange() )
2682 return;
2684 if( pEntry == pPredecessor )
2685 return;
2687 sal_uLong nPos1 = GetEntryListPos( pEntry );
2688 if( !pHead )
2690 if( pPredecessor )
2692 sal_uLong nPos2 = GetEntryListPos( pPredecessor );
2693 if( nPos1 == (nPos2 + 1) )
2694 return; // is already the predecessor
2696 else if( !nPos1 )
2697 return;
2699 InitPredecessors();
2702 if( !pPredecessor && pHead == pEntry )
2703 return; // is already the first one
2705 bool bSetHead = false;
2706 if( !pPredecessor )
2708 bSetHead = true;
2709 pPredecessor = pHead->pblink;
2711 if( pEntry == pHead )
2713 pHead = pHead->pflink;
2714 bSetHead = false;
2716 if( pEntry != pPredecessor )
2718 pEntry->Unlink();
2719 pEntry->SetBacklink( pPredecessor );
2721 if( bSetHead )
2722 pHead = pEntry;
2723 aAutoArrangeIdle.Start();
2726 SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::FindEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry,
2727 const Point& rPosTopLeft )
2729 Point aPos( rPosTopLeft ); //TopLeft
2730 tools::Rectangle aCenterRect( CalcBmpRect( pEntry, &aPos ));
2731 Point aNewPos( aCenterRect.Center() );
2732 GridId nGrid = GetPredecessorGrid( aNewPos );
2733 size_t nCount = maEntries.size();
2734 if( nGrid == GRID_NOT_FOUND )
2735 return nullptr;
2736 if( nGrid >= nCount )
2737 nGrid = nCount - 1;
2738 if( !pHead )
2739 return maEntries[ nGrid ].get();
2741 SvxIconChoiceCtrlEntry* pCur = pHead; // Grid 0
2742 // TODO: go through list from the end if nGrid > nCount/2
2743 for( GridId nCur = 0; nCur < nGrid; nCur++ )
2744 pCur = pCur->pflink;
2746 return pCur;
2749 GridId SvxIconChoiceCtrl_Impl::GetPredecessorGrid( const Point& rPos) const
2751 Point aPos( rPos );
2752 aPos.AdjustX( -(LROFFS_WINBORDER) );
2753 aPos.AdjustY( -(TBOFFS_WINBORDER) );
2754 tools::Long nMaxCol = aVirtOutputSize.Width() / nGridDX;
2755 if( nMaxCol )
2756 nMaxCol--;
2757 tools::Long nGridX = aPos.X() / nGridDX;
2758 if( nGridX > nMaxCol )
2759 nGridX = nMaxCol;
2760 tools::Long nGridY = aPos.Y() / nGridDY;
2761 tools::Long nGridsX = aOutputSize.Width() / nGridDX;
2762 GridId nGrid = (nGridY * nGridsX) + nGridX;
2763 tools::Long nMiddle = (nGridX * nGridDX) + (nGridDX / 2);
2764 if( rPos.X() < nMiddle )
2766 if( !nGrid )
2767 nGrid = GRID_NOT_FOUND;
2768 else
2769 nGrid--;
2771 return nGrid;
2774 bool SvxIconChoiceCtrl_Impl::RequestHelp( const HelpEvent& rHEvt )
2776 if ( !(rHEvt.GetMode() & HelpEventMode::QUICK ) )
2777 return false;
2779 Point aPos( pView->ScreenToOutputPixel(rHEvt.GetMousePosPixel() ) );
2780 aPos -= pView->GetMapMode().GetOrigin();
2781 SvxIconChoiceCtrlEntry* pEntry = GetEntry( aPos, true );
2783 if ( !pEntry )
2784 return false;
2786 OUString sQuickHelpText = pEntry->GetQuickHelpText();
2787 OUString aEntryText( SvtIconChoiceCtrl::GetEntryText( pEntry ) );
2788 tools::Rectangle aTextRect( CalcTextRect( pEntry, nullptr, &aEntryText ) );
2789 if ( ( !aTextRect.IsInside( aPos ) || aEntryText.isEmpty() ) && sQuickHelpText.isEmpty() )
2790 return false;
2792 tools::Rectangle aOptTextRect( aTextRect );
2793 aOptTextRect.SetBottom( LONG_MAX );
2794 DrawTextFlags nNewFlags = nCurTextDrawFlags;
2795 nNewFlags &= ~DrawTextFlags( DrawTextFlags::Clip | DrawTextFlags::EndEllipsis );
2796 aOptTextRect = pView->GetTextRect( aOptTextRect, aEntryText, nNewFlags );
2797 if ( aOptTextRect != aTextRect || !sQuickHelpText.isEmpty() )
2799 //aTextRect.Right() = aTextRect.Left() + aRealSize.Width() + 4;
2800 Point aPt( aOptTextRect.TopLeft() );
2801 aPt += pView->GetMapMode().GetOrigin();
2802 aPt = pView->OutputToScreenPixel( aPt );
2803 // subtract border of tooltip help
2804 aPt.AdjustY( -1 );
2805 aPt.AdjustX( -3 );
2806 aOptTextRect.SetPos( aPt );
2807 OUString sHelpText;
2808 if ( !sQuickHelpText.isEmpty() )
2809 sHelpText = sQuickHelpText;
2810 else
2811 sHelpText = aEntryText;
2812 Help::ShowQuickHelp( static_cast<vcl::Window*>(pView), aOptTextRect, sHelpText, QuickHelpFlags::Left | QuickHelpFlags::VCenter );
2815 return true;
2818 void SvxIconChoiceCtrl_Impl::SetColumn( sal_uInt16 nIndex, const SvxIconChoiceCtrlColumnInfo& rInfo)
2820 if (!m_pColumns)
2821 m_pColumns.reset(new SvxIconChoiceCtrlColumnInfoMap);
2823 SvxIconChoiceCtrlColumnInfo* pInfo = new SvxIconChoiceCtrlColumnInfo( rInfo );
2824 m_pColumns->insert(std::make_pair(nIndex, std::unique_ptr<SvxIconChoiceCtrlColumnInfo>(pInfo)));
2826 // HACK: Detail mode is not yet fully implemented, this workaround makes it
2827 // fly with a single column
2828 if( !nIndex && (nWinBits & WB_DETAILS) )
2829 nGridDX = pInfo->GetWidth();
2831 if( GetUpdateMode() )
2832 Arrange( IsAutoArrange(), 0, 0 );
2835 const SvxIconChoiceCtrlColumnInfo* SvxIconChoiceCtrl_Impl::GetColumn( sal_uInt16 nIndex ) const
2837 if (!m_pColumns)
2838 return nullptr;
2839 auto const it = m_pColumns->find( nIndex );
2840 if (it == m_pColumns->end())
2841 return nullptr;
2842 return it->second.get();
2845 void SvxIconChoiceCtrl_Impl::DrawHighlightFrame(vcl::RenderContext& rRenderContext, const tools::Rectangle& rBmpRect)
2847 tools::Rectangle aBmpRect(rBmpRect);
2848 tools::Long nBorder = 2;
2849 if (aImageSize.Width() < 32)
2850 nBorder = 1;
2851 aBmpRect.AdjustRight(nBorder );
2852 aBmpRect.AdjustLeft( -nBorder );
2853 aBmpRect.AdjustBottom(nBorder );
2854 aBmpRect.AdjustTop( -nBorder );
2856 DecorationView aDecoView(&rRenderContext);
2857 DrawHighlightFrameStyle nDecoFlags;
2858 if (bHighlightFramePressed)
2859 nDecoFlags = DrawHighlightFrameStyle::In;
2860 else
2861 nDecoFlags = DrawHighlightFrameStyle::Out;
2862 aDecoView.DrawHighlightFrame(aBmpRect, nDecoFlags);
2865 void SvxIconChoiceCtrl_Impl::SetEntryHighlightFrame( SvxIconChoiceCtrlEntry* pEntry,
2866 bool bKeepHighlightFlags )
2868 if( pEntry == pCurHighlightFrame )
2869 return;
2871 if( !bKeepHighlightFlags )
2872 bHighlightFramePressed = false;
2874 if (pCurHighlightFrame)
2876 tools::Rectangle aInvalidationRect(GetEntryBoundRect(pCurHighlightFrame));
2877 aInvalidationRect.expand(5);
2878 pCurHighlightFrame = nullptr;
2879 pView->Invalidate(aInvalidationRect);
2882 pCurHighlightFrame = pEntry;
2883 if (pEntry)
2885 tools::Rectangle aInvalidationRect(GetEntryBoundRect(pEntry));
2886 aInvalidationRect.expand(5);
2887 pView->Invalidate(aInvalidationRect);
2891 void SvxIconChoiceCtrl_Impl::CallSelectHandler()
2893 // When single-click mode is active, the selection handler should be called
2894 // synchronously, as the selection is automatically taken away once the
2895 // mouse cursor doesn't touch the object any more. Else, we might run into
2896 // missing calls to Select if the object is selected from a mouse movement,
2897 // because when starting the timer, the mouse cursor might have already left
2898 // the object.
2899 // In special cases (=>SfxFileDialog!), synchronous calls can be forced via
2900 // WB_NOASYNCSELECTHDL.
2901 if( nWinBits & (WB_NOASYNCSELECTHDL | WB_HIGHLIGHTFRAME) )
2903 pHdlEntry = nullptr;
2904 pView->ClickIcon();
2905 //pView->Select();
2907 else
2908 aCallSelectHdlIdle.Start();
2911 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl, CallSelectHdlHdl, Timer *, void)
2913 pHdlEntry = nullptr;
2914 pView->ClickIcon();
2915 //pView->Select();
2918 void SvxIconChoiceCtrl_Impl::SetOrigin( const Point& rPos )
2920 MapMode aMapMode( pView->GetMapMode() );
2921 aMapMode.SetOrigin( rPos );
2922 pView->SetMapMode( aMapMode );
2925 void SvxIconChoiceCtrl_Impl::CallEventListeners( VclEventId nEvent, void* pData )
2927 pView->CallImplEventListeners( nEvent, pData );
2931 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */