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