Bump version to 5.0-14
[LibreOffice.git] / svtools / source / contnr / imivctl1.cxx
blob6b4d02ca2c3e514cc0459b511824689154e8f200
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 <tools/debug.hxx>
23 #include <vcl/wall.hxx>
24 #include <vcl/help.hxx>
25 #include <vcl/decoview.hxx>
26 #include <vcl/svapp.hxx>
27 #include <tools/poly.hxx>
28 #include <vcl/lineinfo.hxx>
29 #include <vcl/i18nhelp.hxx>
30 #include <vcl/mnemonic.hxx>
31 #include <vcl/controllayout.hxx>
32 #include <vcl/settings.hxx>
34 #include <svtools/ivctrl.hxx>
35 #include "imivctl.hxx"
36 #include <svtools/svmedit.hxx>
38 #include <algorithm>
39 #include <boost/scoped_ptr.hpp>
40 #include <vcl/idle.hxx>
42 #define IMPICNVIEW_ACC_RETURN 1
43 #define IMPICNVIEW_ACC_ESCAPE 2
45 #define DRAWTEXT_FLAGS_ICON \
46 ( DrawTextFlags::Center | DrawTextFlags::Top | DrawTextFlags::EndEllipsis | \
47 DrawTextFlags::Clip | DrawTextFlags::MultiLine | DrawTextFlags::WordBreak | DrawTextFlags::Mnemonic )
49 #define DRAWTEXT_FLAGS_SMALLICON (DrawTextFlags::Left|DrawTextFlags::EndEllipsis|DrawTextFlags::Clip)
51 #define EVENTID_SHOW_CURSOR (reinterpret_cast<void*>(1))
52 #define EVENTID_ADJUST_SCROLLBARS (reinterpret_cast<void*>(2))
54 static bool bEndScrollInvalidate = true;
56 class IcnViewEdit_Impl : public MultiLineEdit
58 Link<> aCallBackHdl;
59 Accelerator aAccReturn;
60 Accelerator aAccEscape;
61 Idle aIdle;
62 bool bCanceled;
63 bool bAlreadyInCallback;
64 bool bGrabFocus;
66 void CallCallBackHdl_Impl();
67 DECL_LINK_TYPED(Timeout_Impl, Idle *, void);
68 DECL_LINK( ReturnHdl_Impl, Accelerator * );
69 DECL_LINK( EscapeHdl_Impl, Accelerator * );
71 public:
73 IcnViewEdit_Impl(
74 SvtIconChoiceCtrl* pParent,
75 const Point& rPos,
76 const Size& rSize,
77 const OUString& rData,
78 const Link<>& rNotifyEditEnd );
80 virtual ~IcnViewEdit_Impl();
81 virtual void dispose() SAL_OVERRIDE;
82 virtual void KeyInput( const KeyEvent& rKEvt ) SAL_OVERRIDE;
83 virtual bool PreNotify( NotifyEvent& rNEvt ) SAL_OVERRIDE;
84 bool EditingCanceled() const { return bCanceled; }
85 void StopEditing( bool bCancel = false );
86 bool IsGrabFocus() const { return bGrabFocus; }
89 SvxIconChoiceCtrl_Impl::SvxIconChoiceCtrl_Impl(
90 SvtIconChoiceCtrl* pCurView,
91 WinBits nWinStyle
92 ) :
93 aEntries( this ),
94 aVerSBar( VclPtr<ScrollBar>::Create(pCurView, WB_DRAG | WB_VSCROLL) ),
95 aHorSBar( VclPtr<ScrollBar>::Create(pCurView, WB_DRAG | WB_HSCROLL) ),
96 aScrBarBox( VclPtr<ScrollBarBox>::Create(pCurView) ),
97 aImageSize( 32, 32 ),
98 pColumns( 0 )
100 bChooseWithCursor = false;
101 pEntryPaintDev = 0;
102 pCurEditedEntry = 0;
103 pCurHighlightFrame = 0;
104 pEdit = 0;
105 pAnchor = 0;
106 pPrevDropTarget = 0;
107 pHdlEntry = 0;
108 pHead = NULL;
109 pCursor = NULL;
110 bUpdateMode = true;
111 bEntryEditingEnabled = false;
112 bHighlightFramePressed = false;
113 eSelectionMode = MULTIPLE_SELECTION;
114 pView = pCurView;
115 pZOrderList = new SvxIconChoiceCtrlEntryList_impl();
116 ePositionMode = IcnViewPositionModeFree;
117 SetStyle( nWinStyle );
118 nFlags = 0;
119 nUserEventAdjustScrBars = 0;
120 nUserEventShowCursor = 0;
121 nMaxVirtWidth = DEFAULT_MAX_VIRT_WIDTH;
122 nMaxVirtHeight = DEFAULT_MAX_VIRT_HEIGHT;
123 pDDRefEntry = 0;
124 pDDDev = 0;
125 pDDBufDev = 0;
126 pDDTempDev = 0;
127 eTextMode = IcnShowTextShort;
128 pImpCursor = new IcnCursor_Impl( this );
129 pGridMap = new IcnGridMap_Impl( this );
131 aVerSBar->SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, ScrollUpDownHdl ) );
132 aHorSBar->SetScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl ) );
133 Link<> aEndScrollHdl( LINK( this, SvxIconChoiceCtrl_Impl, EndScrollHdl ) );
134 aVerSBar->SetEndScrollHdl( aEndScrollHdl );
135 aHorSBar->SetEndScrollHdl( aEndScrollHdl );
137 nHorSBarHeight = aHorSBar->GetSizePixel().Height();
138 nVerSBarWidth = aVerSBar->GetSizePixel().Width();
140 aEditIdle.SetPriority( SchedulerPriority::LOWEST );
141 aEditIdle.SetIdleHdl(LINK(this,SvxIconChoiceCtrl_Impl,EditTimeoutHdl));
142 aAutoArrangeIdle.SetPriority( SchedulerPriority::LOW );
143 aAutoArrangeIdle.SetIdleHdl(LINK(this,SvxIconChoiceCtrl_Impl,AutoArrangeHdl));
144 aCallSelectHdlIdle.SetPriority( SchedulerPriority::LOWEST );
145 aCallSelectHdlIdle.SetIdleHdl( LINK(this,SvxIconChoiceCtrl_Impl,CallSelectHdlHdl));
147 aDocRectChangedIdle.SetPriority( SchedulerPriority::MEDIUM );
148 aDocRectChangedIdle.SetIdleHdl(LINK(this,SvxIconChoiceCtrl_Impl,DocRectChangedHdl));
149 aVisRectChangedIdle.SetPriority( SchedulerPriority::MEDIUM );
150 aVisRectChangedIdle.SetIdleHdl(LINK(this,SvxIconChoiceCtrl_Impl,VisRectChangedHdl));
152 Clear( true );
154 SetGrid( Size(100, 70) );
157 SvxIconChoiceCtrl_Impl::~SvxIconChoiceCtrl_Impl()
159 pCurEditedEntry = 0;
160 pEdit.disposeAndClear();
161 Clear();
162 StopEditTimer();
163 CancelUserEvents();
164 delete pZOrderList;
165 delete pImpCursor;
166 delete pGridMap;
167 pDDDev.disposeAndClear();
168 pDDBufDev.disposeAndClear();
169 pDDTempDev.disposeAndClear();
170 pEntryPaintDev.disposeAndClear();
171 ClearSelectedRectList();
172 ClearColumnList();
173 aVerSBar.disposeAndClear();
174 aHorSBar.disposeAndClear();
175 aScrBarBox.disposeAndClear();
178 void SvxIconChoiceCtrl_Impl::Clear( bool bInCtor )
180 StopEntryEditing( true );
181 nSelectionCount = 0;
182 pCurHighlightFrame = 0;
183 StopEditTimer();
184 CancelUserEvents();
185 ShowCursor( false );
186 bBoundRectsDirty = false;
187 nMaxBoundHeight = 0;
189 nFlags &= ~(F_PAINTED | F_MOVED_ENTRIES);
190 pCursor = 0;
191 if( !bInCtor )
193 pImpCursor->Clear();
194 pGridMap->Clear();
195 aVirtOutputSize.Width() = 0;
196 aVirtOutputSize.Height() = 0;
197 Size aSize( pView->GetOutputSizePixel() );
198 nMaxVirtWidth = aSize.Width() - nVerSBarWidth;
199 if( nMaxVirtWidth <= 0 )
200 nMaxVirtWidth = DEFAULT_MAX_VIRT_WIDTH;
201 nMaxVirtHeight = aSize.Height() - nHorSBarHeight;
202 if( nMaxVirtHeight <= 0 )
203 nMaxVirtHeight = DEFAULT_MAX_VIRT_HEIGHT;
204 pZOrderList->clear();
205 SetOrigin( Point() );
206 if( bUpdateMode )
207 pView->Invalidate(INVALIDATE_NOCHILDREN);
209 AdjustScrollBars();
210 size_t nCount = aEntries.size();
211 for( size_t nCur = 0; nCur < nCount; nCur++ )
213 SvxIconChoiceCtrlEntry* pCur = aEntries[ nCur ];
214 delete pCur;
216 aEntries.clear();
217 DocRectChanged();
218 VisRectChanged();
221 void SvxIconChoiceCtrl_Impl::SetStyle( WinBits nWinStyle )
223 nWinBits = nWinStyle;
224 nCurTextDrawFlags = DRAWTEXT_FLAGS_ICON;
225 if( nWinBits & (WB_SMALLICON | WB_DETAILS) )
226 nCurTextDrawFlags = DRAWTEXT_FLAGS_SMALLICON;
227 if( nWinBits & WB_NOSELECTION )
228 eSelectionMode = NO_SELECTION;
229 if( !(nWinStyle & (WB_ALIGN_TOP | WB_ALIGN_LEFT)))
230 nWinBits |= WB_ALIGN_LEFT;
231 if( (nWinStyle & WB_DETAILS))
233 if( !pColumns )
234 SetColumn( 0, SvxIconChoiceCtrlColumnInfo( 0, 100, IcnViewAlignLeft ));
238 IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollUpDownHdl, ScrollBar*, pScrollBar )
240 StopEntryEditing( true );
241 // arrow up: delta=-1; arrow down: delta=+1
242 Scroll( 0, pScrollBar->GetDelta(), true );
243 bEndScrollInvalidate = true;
244 return 0;
247 IMPL_LINK( SvxIconChoiceCtrl_Impl, ScrollLeftRightHdl, ScrollBar*, pScrollBar )
249 StopEntryEditing( true );
250 // arrow left: delta=-1; arrow right: delta=+1
251 Scroll( pScrollBar->GetDelta(), 0, true );
252 bEndScrollInvalidate = true;
253 return 0;
256 IMPL_STATIC_LINK_NOARG(SvxIconChoiceCtrl_Impl, EndScrollHdl)
258 return 0;
261 void SvxIconChoiceCtrl_Impl::FontModified()
263 StopEditTimer();
264 pDDDev.disposeAndClear();
265 pDDBufDev.disposeAndClear();
266 pDDTempDev.disposeAndClear();
267 pEntryPaintDev.disposeAndClear();
268 SetDefaultTextSize();
269 ShowCursor( false );
270 ShowCursor( true );
273 void SvxIconChoiceCtrl_Impl::InsertEntry( SvxIconChoiceCtrlEntry* pEntry, size_t nPos,
274 const Point* pPos )
276 StopEditTimer();
277 aEntries.insert( nPos, pEntry );
278 if( (nFlags & F_ENTRYLISTPOS_VALID) && nPos >= aEntries.size() - 1 )
279 pEntry->nPos = aEntries.size() - 1;
280 else
281 nFlags &= ~F_ENTRYLISTPOS_VALID;
283 pZOrderList->push_back( pEntry );
284 pImpCursor->Clear();
285 if( pPos )
287 Size aSize( CalcBoundingSize( pEntry ) );
288 SetBoundingRect_Impl( pEntry, *pPos, aSize );
289 SetEntryPos( pEntry, *pPos, false, true, true /*keep grid map*/ );
290 pEntry->nFlags |= SvxIconViewFlags::POS_MOVED;
291 SetEntriesMoved( true );
293 else
295 // If the UpdateMode is true, don't set all bounding rectangles to
296 // 'to be checked', but only the bounding rectangle of the new entry.
297 // Thus, don't call InvalidateBoundingRect!
298 pEntry->aRect.Right() = LONG_MAX;
299 if( bUpdateMode )
301 FindBoundingRect( pEntry );
302 Rectangle aOutputArea( GetOutputRect() );
303 pGridMap->OccupyGrids( pEntry );
304 if( !aOutputArea.IsOver( pEntry->aRect ) )
305 return; // is invisible
306 pView->Invalidate( pEntry->aRect );
308 else
309 InvalidateBoundingRect( pEntry->aRect );
313 void SvxIconChoiceCtrl_Impl::CreateAutoMnemonics( MnemonicGenerator* _pGenerator )
315 boost::scoped_ptr< MnemonicGenerator > pAutoDeleteOwnGenerator;
316 if ( !_pGenerator )
318 _pGenerator = new MnemonicGenerator;
319 pAutoDeleteOwnGenerator.reset( _pGenerator );
322 sal_uLong nEntryCount = GetEntryCount();
323 sal_uLong i;
325 // insert texts in generator
326 for( i = 0; i < nEntryCount; ++i )
328 DBG_ASSERT( GetEntry( i ), "-SvxIconChoiceCtrl_Impl::CreateAutoMnemonics(): more expected than provided!" );
330 _pGenerator->RegisterMnemonic( GetEntry( i )->GetText() );
333 // exchange texts with generated mnemonics
334 for( i = 0; i < nEntryCount; ++i )
336 SvxIconChoiceCtrlEntry* pEntry = GetEntry( i );
337 OUString aTxt = pEntry->GetText();
339 OUString aNewText = _pGenerator->CreateMnemonic( aTxt );
340 if( aNewText != aTxt )
341 pEntry->SetText( aNewText );
345 Rectangle SvxIconChoiceCtrl_Impl::GetOutputRect() const
347 Point aOrigin( pView->GetMapMode().GetOrigin() );
348 aOrigin *= -1;
349 return Rectangle( aOrigin, aOutputSize );
352 void SvxIconChoiceCtrl_Impl::SetListPositions()
354 if( nFlags & F_ENTRYLISTPOS_VALID )
355 return;
357 size_t nCount = aEntries.size();
358 for( size_t nCur = 0; nCur < nCount; nCur++ )
360 SvxIconChoiceCtrlEntry* pEntry = aEntries[ nCur ];
361 pEntry->nPos = nCur;
363 nFlags |= F_ENTRYLISTPOS_VALID;
366 void SvxIconChoiceCtrl_Impl::SelectEntry( SvxIconChoiceCtrlEntry* pEntry, bool bSelect,
367 bool bCallHdl, bool bAdd, bool bSyncPaint )
369 if( eSelectionMode == NO_SELECTION )
370 return;
372 if( !bAdd )
374 if ( 0 == ( nFlags & F_CLEARING_SELECTION ) )
376 nFlags |= F_CLEARING_SELECTION;
377 DeselectAllBut( pEntry, true );
378 nFlags &= ~F_CLEARING_SELECTION;
381 if( pEntry->IsSelected() != bSelect )
383 pHdlEntry = pEntry;
384 SvxIconViewFlags nEntryFlags = pEntry->GetFlags();
385 if( bSelect )
387 nEntryFlags |= SvxIconViewFlags::SELECTED;
388 pEntry->AssignFlags( nEntryFlags );
389 nSelectionCount++;
390 if( bCallHdl )
391 CallSelectHandler( pEntry );
393 else
395 nEntryFlags &= ~( SvxIconViewFlags::SELECTED);
396 pEntry->AssignFlags( nEntryFlags );
397 nSelectionCount--;
398 if( bCallHdl )
399 CallSelectHandler( 0 );
401 EntrySelected( pEntry, bSelect, bSyncPaint );
405 void SvxIconChoiceCtrl_Impl::EntrySelected(SvxIconChoiceCtrlEntry* pEntry, bool bSelect, bool /*bSyncPaint*/)
407 // When using SingleSelection, make sure that the cursor is always placed
408 // over the (only) selected entry. (But only if a cursor exists.)
409 if (bSelect && pCursor &&
410 eSelectionMode == SINGLE_SELECTION &&
411 pEntry != pCursor)
413 SetCursor(pEntry);
416 // Not when dragging though, else the loop in SelectRect doesn't work
417 // correctly!
418 if (!(nFlags & F_SELECTING_RECT))
419 ToTop(pEntry);
420 if (bUpdateMode)
422 if (pEntry == pCursor)
423 ShowCursor(false);
424 pView->Invalidate(CalcFocusRect(pEntry));
425 if (pEntry == pCursor)
426 ShowCursor(true);
429 // #i101012# emit vcl event LISTBOX_SELECT only in case that the given entry is selected.
430 if (bSelect)
432 CallEventListeners(VCLEVENT_LISTBOX_SELECT, pEntry);
436 void SvxIconChoiceCtrl_Impl::ResetVirtSize()
438 StopEditTimer();
439 aVirtOutputSize.Width() = 0;
440 aVirtOutputSize.Height() = 0;
441 const size_t nCount = aEntries.size();
442 for( size_t nCur = 0; nCur < nCount; nCur++ )
444 SvxIconChoiceCtrlEntry* pCur = aEntries[ nCur ];
445 pCur->ClearFlags( SvxIconViewFlags::POS_MOVED );
446 if( pCur->IsPosLocked() )
448 // adapt (among others) VirtSize
449 if( !IsBoundingRectValid( pCur->aRect ) )
450 FindBoundingRect( pCur );
451 else
452 AdjustVirtSize( pCur->aRect );
454 else
455 InvalidateBoundingRect( pCur->aRect );
458 if( !(nWinBits & (WB_NOVSCROLL | WB_NOHSCROLL)) )
460 Size aRealOutputSize( pView->GetOutputSizePixel() );
461 if( aVirtOutputSize.Width() < aRealOutputSize.Width() ||
462 aVirtOutputSize.Height() < aRealOutputSize.Height() )
464 sal_uLong nGridCount = IcnGridMap_Impl::GetGridCount(
465 aRealOutputSize, (sal_uInt16)nGridDX, (sal_uInt16)nGridDY );
466 if( nGridCount < nCount )
468 if( nWinBits & WB_ALIGN_TOP )
469 nMaxVirtWidth = aRealOutputSize.Width() - nVerSBarWidth;
470 else // WB_ALIGN_LEFT
471 nMaxVirtHeight = aRealOutputSize.Height() - nHorSBarHeight;
476 pImpCursor->Clear();
477 pGridMap->Clear();
478 VisRectChanged();
481 void SvxIconChoiceCtrl_Impl::AdjustVirtSize( const Rectangle& rRect )
483 long nHeightOffs = 0;
484 long nWidthOffs = 0;
486 if( aVirtOutputSize.Width() < (rRect.Right()+LROFFS_WINBORDER) )
487 nWidthOffs = (rRect.Right()+LROFFS_WINBORDER) - aVirtOutputSize.Width();
489 if( aVirtOutputSize.Height() < (rRect.Bottom()+TBOFFS_WINBORDER) )
490 nHeightOffs = (rRect.Bottom()+TBOFFS_WINBORDER) - aVirtOutputSize.Height();
492 if( nWidthOffs || nHeightOffs )
494 Range aRange;
495 aVirtOutputSize.Width() += nWidthOffs;
496 aRange.Max() = aVirtOutputSize.Width();
497 aHorSBar->SetRange( aRange );
499 aVirtOutputSize.Height() += nHeightOffs;
500 aRange.Max() = aVirtOutputSize.Height();
501 aVerSBar->SetRange( aRange );
503 pImpCursor->Clear();
504 pGridMap->OutputSizeChanged();
505 AdjustScrollBars();
506 DocRectChanged();
510 void SvxIconChoiceCtrl_Impl::InitPredecessors()
512 DBG_ASSERT(!pHead,"SvxIconChoiceCtrl_Impl::InitPredecessors() >> Already initialized");
513 size_t nCount = aEntries.size();
514 if( nCount )
516 SvxIconChoiceCtrlEntry* pPrev = aEntries[ 0 ];
517 for( size_t nCur = 1; nCur <= nCount; nCur++ )
519 pPrev->ClearFlags( SvxIconViewFlags::POS_LOCKED | SvxIconViewFlags::POS_MOVED |
520 SvxIconViewFlags::PRED_SET);
522 SvxIconChoiceCtrlEntry* pNext;
523 if( nCur == nCount )
524 pNext = aEntries[ 0 ];
525 else
526 pNext = aEntries[ nCur ];
527 pPrev->pflink = pNext;
528 pNext->pblink = pPrev;
529 pPrev = pNext;
531 pHead = aEntries[ 0 ];
533 else
534 pHead = 0;
535 nFlags &= ~F_MOVED_ENTRIES;
538 void SvxIconChoiceCtrl_Impl::ClearPredecessors()
540 if( pHead )
542 size_t nCount = aEntries.size();
543 for( size_t nCur = 0; nCur < nCount; nCur++ )
545 SvxIconChoiceCtrlEntry* pCur = aEntries[ nCur ];
546 pCur->pflink = 0;
547 pCur->pblink = 0;
548 pCur->ClearFlags( SvxIconViewFlags::PRED_SET );
550 pHead = 0;
554 void SvxIconChoiceCtrl_Impl::Arrange( bool bKeepPredecessors, long nSetMaxVirtWidth, long nSetMaxVirtHeight )
556 if ( nSetMaxVirtWidth != 0 )
557 nMaxVirtWidth = nSetMaxVirtWidth;
558 else
559 nMaxVirtWidth = aOutputSize.Width();
561 if ( nSetMaxVirtHeight != 0 )
562 nMaxVirtHeight = nSetMaxVirtHeight;
563 else
564 nMaxVirtHeight = aOutputSize.Height();
566 ImpArrange( bKeepPredecessors );
569 void SvxIconChoiceCtrl_Impl::ImpArrange( bool bKeepPredecessors )
571 static Point aEmptyPoint;
573 bool bOldUpdate = bUpdateMode;
574 Rectangle aCurOutputArea( GetOutputRect() );
575 if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint )
576 bUpdateMode = false;
577 aAutoArrangeIdle.Stop();
578 nFlags &= ~F_MOVED_ENTRIES;
579 nFlags |= F_ARRANGING;
580 StopEditTimer();
581 ShowCursor( false );
582 ResetVirtSize();
583 if( !bKeepPredecessors )
584 ClearPredecessors();
585 bBoundRectsDirty = false;
586 SetOrigin( Point() );
587 VisRectChanged();
588 RecalcAllBoundingRectsSmart();
589 // TODO: the invalidation in the detail view should be more intelligent
590 //if( !(nWinBits & WB_DETAILS ))
591 pView->Invalidate( INVALIDATE_NOCHILDREN );
592 nFlags &= ~F_ARRANGING;
593 if( (nWinBits & WB_SMART_ARRANGE) && aCurOutputArea.TopLeft() != aEmptyPoint )
595 MakeVisible( aCurOutputArea );
596 SetUpdateMode( bOldUpdate );
598 ShowCursor( true );
601 void SvxIconChoiceCtrl_Impl::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
603 bEndScrollInvalidate = false;
605 #if defined(OV_DRAWGRID)
606 Color aOldColor (rRenderContext.GetLineColor());
607 Color aColor(COL_BLACK);
608 rRenderContext.SetLineColor( aColor );
609 Point aOffs(rRenderContext.GetMapMode().GetOrigin());
610 Size aXSize(GetOutputSizePixel());
612 Point aStart(LROFFS_WINBORDER, 0);
613 Point aEnd(LROFFS_WINBORDER, aXSize.Height());
614 aStart -= aOffs;
615 aEnd -= aOffs;
616 rRenderContext.DrawLine(aStart, aEnd);
619 Point aStart(0, TBOFFS_WINBORDER);
620 Point aEnd(aXSize.Width(), TBOFFS_WINBORDER);
621 aStart -= aOffs;
622 aEnd -= aOffs;
623 rRenderContext.DrawLine(aStart, aEnd);
626 for (long nDX = nGridDX; nDX <= aXSize.Width(); nDX += nGridDX)
628 Point aStart( nDX+LROFFS_WINBORDER, 0 );
629 Point aEnd( nDX+LROFFS_WINBORDER, aXSize.Height());
630 aStart -= aOffs;
631 aEnd -= aOffs;
632 rRenderContext.DrawLine(aStart, aEnd);
634 for (long nDY = nGridDY; nDY <= aXSize.Height(); nDY += nGridDY)
636 Point aStart(0, nDY + TBOFFS_WINBORDER);
637 Point aEnd(aXSize.Width(), nDY + TBOFFS_WINBORDER);
638 aStart -= aOffs;
639 aEnd -= aOffs;
640 rRenderContext.DrawLine(aStart, aEnd);
642 rRenderContext.SetLineColor(aOldColor);
643 #endif
644 nFlags |= F_PAINTED;
646 if (!aEntries.size())
647 return;
648 if (!pCursor)
650 // set cursor to item with focus-flag
651 bool bfound = false;
652 for (sal_uLong i = 0; i < pView->GetEntryCount() && !bfound; i++)
654 SvxIconChoiceCtrlEntry* pEntry = pView->GetEntry (i);
655 if (pEntry->IsFocused())
657 pCursor = pEntry;
658 bfound = true;
662 if (!bfound)
663 pCursor = aEntries[ 0 ];
666 size_t nCount = pZOrderList->size();
667 if (!nCount)
668 return;
670 rRenderContext.Push(PushFlags::CLIPREGION);
671 rRenderContext.SetClipRegion(vcl::Region(rRect));
673 SvxIconChoiceCtrlEntryList_impl* pNewZOrderList = new SvxIconChoiceCtrlEntryList_impl();
674 boost::scoped_ptr<SvxIconChoiceCtrlEntryList_impl> pPaintedEntries(new SvxIconChoiceCtrlEntryList_impl());
676 size_t nPos = 0;
677 while(nCount)
679 SvxIconChoiceCtrlEntry* pEntry = (*pZOrderList)[nPos];
680 const Rectangle& rBoundRect = GetEntryBoundRect(pEntry);
681 if (rRect.IsOver(rBoundRect))
683 PaintEntry(pEntry, rBoundRect.TopLeft(), rRenderContext, true);
684 // set entries to Top if they are being repainted
685 pPaintedEntries->push_back(pEntry);
687 else
688 pNewZOrderList->push_back(pEntry);
690 nCount--;
691 nPos++;
693 delete pZOrderList;
694 pZOrderList = pNewZOrderList;
695 nCount = pPaintedEntries->size();
696 if (nCount)
698 for (size_t nCur = 0; nCur < nCount; nCur++)
699 pZOrderList->push_back((*pPaintedEntries)[nCur]);
701 pPaintedEntries.reset();
703 rRenderContext.Pop();
706 void SvxIconChoiceCtrl_Impl::RepaintEntries(SvxIconViewFlags nEntryFlagsMask)
708 const size_t nCount = pZOrderList->size();
709 if (!nCount)
710 return;
712 Rectangle aOutRect(GetOutputRect());
713 for (size_t nCur = 0; nCur < nCount; nCur++)
715 SvxIconChoiceCtrlEntry* pEntry = (*pZOrderList)[nCur];
716 if (pEntry->GetFlags() & nEntryFlagsMask)
718 const Rectangle& rBoundRect = GetEntryBoundRect(pEntry);
719 if (aOutRect.IsOver(rBoundRect))
720 pView->Invalidate(rBoundRect);
725 void SvxIconChoiceCtrl_Impl::InitScrollBarBox()
727 aScrBarBox->SetSizePixel( Size(nVerSBarWidth-1, nHorSBarHeight-1) );
728 Size aSize( pView->GetOutputSizePixel() );
729 aScrBarBox->SetPosPixel( Point(aSize.Width()-nVerSBarWidth+1, aSize.Height()-nHorSBarHeight+1));
732 bool SvxIconChoiceCtrl_Impl::MouseButtonDown( const MouseEvent& rMEvt)
734 bool bHandled = true;
735 bHighlightFramePressed = false;
736 StopEditTimer();
737 bool bGotFocus = (!pView->HasFocus() && !(nWinBits & WB_NOPOINTERFOCUS));
738 if( !(nWinBits & WB_NOPOINTERFOCUS) )
739 pView->GrabFocus();
741 Point aDocPos( rMEvt.GetPosPixel() );
742 if(aDocPos.X()>=aOutputSize.Width() || aDocPos.Y()>=aOutputSize.Height())
743 return false;
744 ToDocPos( aDocPos );
745 SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, true );
746 if( pEntry )
747 MakeEntryVisible( pEntry, false );
749 if( rMEvt.IsShift() && eSelectionMode != SINGLE_SELECTION )
751 if( pEntry )
752 SetCursor_Impl( pCursor, pEntry, rMEvt.IsMod1(), rMEvt.IsShift(), true);
753 return true;
756 if( pAnchor && (rMEvt.IsShift() || rMEvt.IsMod1())) // keyboard selection?
758 DBG_ASSERT(eSelectionMode != SINGLE_SELECTION,"Invalid selection mode");
759 if( rMEvt.IsMod1() )
760 nFlags |= F_ADD_MODE;
762 if( rMEvt.IsShift() )
764 Rectangle aRect( GetEntryBoundRect( pAnchor ));
765 if( pEntry )
766 aRect.Union( GetEntryBoundRect( pEntry ) );
767 else
769 Rectangle aTempRect( aDocPos, Size(1,1));
770 aRect.Union( aTempRect );
772 aCurSelectionRect = aRect;
773 SelectRect( aRect, (nFlags & F_ADD_MODE)!=0, &aSelectedRectList );
775 else if( rMEvt.IsMod1() )
777 AddSelectedRect( aCurSelectionRect );
778 pAnchor = 0;
779 aCurSelectionRect.SetPos( aDocPos );
782 if( !pEntry && !(nWinBits & WB_NODRAGSELECTION))
783 pView->StartTracking( STARTTRACK_SCROLLREPEAT );
784 return true;
786 else
788 if( !pEntry )
790 if( eSelectionMode == MULTIPLE_SELECTION )
792 if( !rMEvt.IsMod1() ) // Ctrl
794 if( !bGotFocus )
796 SetNoSelection();
797 ClearSelectedRectList();
800 else
801 nFlags |= F_ADD_MODE;
802 aCurSelectionRect.SetPos( aDocPos );
803 pView->StartTracking( STARTTRACK_SCROLLREPEAT );
805 else
806 bHandled = false;
807 return bHandled;
810 bool bSelected = pEntry->IsSelected();
811 bool bEditingEnabled = IsEntryEditingEnabled();
813 if( rMEvt.GetClicks() == 2 )
815 DeselectAllBut( pEntry );
816 SelectEntry( pEntry, true, true, false, true );
817 pHdlEntry = pEntry;
818 pView->ClickIcon();
820 else
822 // Inplace-Editing ?
823 if( rMEvt.IsMod2() ) // Alt?
825 if( bEntryEditingEnabled && pEntry &&
826 pEntry->IsSelected())
828 EditEntry( pEntry );
831 else if( eSelectionMode == SINGLE_SELECTION )
833 DeselectAllBut( pEntry );
834 SetCursor( pEntry );
835 if( bEditingEnabled && bSelected && !rMEvt.GetModifier() &&
836 rMEvt.IsLeft() && IsTextHit( pEntry, aDocPos ) )
838 nFlags |= F_START_EDITTIMER_IN_MOUSEUP;
841 else if( eSelectionMode == NO_SELECTION )
843 if( rMEvt.IsLeft() && (nWinBits & WB_HIGHLIGHTFRAME) )
845 pCurHighlightFrame = 0; // force repaint of frame
846 bHighlightFramePressed = true;
847 SetEntryHighlightFrame( pEntry, true );
850 else
852 if( !rMEvt.GetModifier() && rMEvt.IsLeft() )
854 if( !bSelected )
856 DeselectAllBut( pEntry, true /* paint synchronously */ );
857 SetCursor( pEntry );
858 SelectEntry( pEntry, true, true, false, true );
860 else
862 // deselect only in the Up, if the Move happened via D&D!
863 nFlags |= F_DOWN_DESELECT;
864 if( bEditingEnabled && IsTextHit( pEntry, aDocPos ) &&
865 rMEvt.IsLeft())
867 nFlags |= F_START_EDITTIMER_IN_MOUSEUP;
871 else if( rMEvt.IsMod1() )
872 nFlags |= F_DOWN_CTRL;
875 return bHandled;
878 bool SvxIconChoiceCtrl_Impl::MouseButtonUp( const MouseEvent& rMEvt )
880 bool bHandled = false;
881 if( rMEvt.IsRight() && (nFlags & (F_DOWN_CTRL | F_DOWN_DESELECT) ))
883 nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT);
884 bHandled = true;
887 Point aDocPos( rMEvt.GetPosPixel() );
888 ToDocPos( aDocPos );
889 SvxIconChoiceCtrlEntry* pDocEntry = GetEntry( aDocPos );
890 if( pDocEntry )
892 if( nFlags & F_DOWN_CTRL )
894 // Ctrl & MultiSelection
895 ToggleSelection( pDocEntry );
896 SetCursor( pDocEntry );
897 bHandled = true;
899 else if( nFlags & F_DOWN_DESELECT )
901 DeselectAllBut( pDocEntry );
902 SetCursor( pDocEntry );
903 SelectEntry( pDocEntry, true, true, false, true );
904 bHandled = true;
908 nFlags &= ~(F_DOWN_CTRL | F_DOWN_DESELECT);
909 if( nFlags & F_START_EDITTIMER_IN_MOUSEUP )
911 bHandled = true;
912 StartEditTimer();
913 nFlags &= ~F_START_EDITTIMER_IN_MOUSEUP;
916 if((nWinBits & WB_HIGHLIGHTFRAME) && bHighlightFramePressed && pCurHighlightFrame)
918 bHandled = true;
919 SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame;
920 pCurHighlightFrame = 0; // force repaint of frame
921 bHighlightFramePressed = false;
922 SetEntryHighlightFrame( pEntry, true );
924 pHdlEntry = pCurHighlightFrame;
925 pView->ClickIcon();
927 // set focus on Icon
928 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
929 SetCursor_Impl( pOldCursor, pHdlEntry, false, false, true );
931 pHdlEntry = 0;
933 return bHandled;
936 bool SvxIconChoiceCtrl_Impl::MouseMove( const MouseEvent& rMEvt )
938 const Point aDocPos( pView->PixelToLogic(rMEvt.GetPosPixel()) );
940 if( pView->IsTracking() )
941 return false;
942 else if( nWinBits & WB_HIGHLIGHTFRAME )
944 SvxIconChoiceCtrlEntry* pEntry = GetEntry( aDocPos, true );
945 SetEntryHighlightFrame( pEntry );
947 else
948 return false;
949 return true;
952 void SvxIconChoiceCtrl_Impl::SetCursor_Impl( SvxIconChoiceCtrlEntry* pOldCursor,
953 SvxIconChoiceCtrlEntry* pNewCursor, bool bMod1, bool bShift, bool bPaintSync )
955 if( pNewCursor )
957 SvxIconChoiceCtrlEntry* pFilterEntry = 0;
958 bool bDeselectAll = false;
959 if( eSelectionMode != SINGLE_SELECTION )
961 if( !bMod1 && !bShift )
962 bDeselectAll = true;
963 else if( bShift && !bMod1 && !pAnchor )
965 bDeselectAll = true;
966 pFilterEntry = pOldCursor;
969 if( bDeselectAll )
970 DeselectAllBut( pFilterEntry, bPaintSync );
971 ShowCursor( false );
972 MakeEntryVisible( pNewCursor );
973 SetCursor( pNewCursor );
974 if( bMod1 && !bShift )
976 if( pAnchor )
978 AddSelectedRect( pAnchor, pOldCursor );
979 pAnchor = 0;
982 else if( bShift )
984 if( !pAnchor )
985 pAnchor = pOldCursor;
986 if ( nWinBits & WB_ALIGN_LEFT )
987 SelectRange( pAnchor, pNewCursor, (nFlags & F_ADD_MODE)!=0 );
988 else
989 SelectRect(pAnchor,pNewCursor,(nFlags & F_ADD_MODE)!=0,&aSelectedRectList);
991 else
993 SelectEntry( pCursor, true, true, false, bPaintSync );
994 aCurSelectionRect = GetEntryBoundRect( pCursor );
995 CallEventListeners( VCLEVENT_LISTBOX_SELECT, pCursor );
1000 bool SvxIconChoiceCtrl_Impl::KeyInput( const KeyEvent& rKEvt )
1002 StopEditTimer();
1004 bool bMod2 = rKEvt.GetKeyCode().IsMod2();
1005 sal_Unicode cChar = rKEvt.GetCharCode();
1006 sal_uLong nPos = (sal_uLong)-1;
1007 if ( bMod2 && cChar && IsMnemonicChar( cChar, nPos ) )
1009 // shortcut is clicked
1010 SvxIconChoiceCtrlEntry* pNewCursor = GetEntry( nPos );
1011 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
1012 if ( pNewCursor != pOldCursor )
1013 SetCursor_Impl( pOldCursor, pNewCursor, false, false, false );
1014 return true;
1017 if ( bMod2 )
1018 // no actions with <ALT>
1019 return false;
1021 bool bKeyUsed = true;
1022 bool bMod1 = rKEvt.GetKeyCode().IsMod1();
1023 bool bShift = rKEvt.GetKeyCode().IsShift();
1025 if( eSelectionMode == SINGLE_SELECTION || eSelectionMode == NO_SELECTION)
1027 bShift = false;
1028 bMod1 = false;
1031 if( bMod1 )
1032 nFlags |= F_ADD_MODE;
1034 SvxIconChoiceCtrlEntry* pNewCursor;
1035 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
1037 sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
1038 switch( nCode )
1040 case KEY_UP:
1041 case KEY_PAGEUP:
1042 if( pCursor )
1044 MakeEntryVisible( pCursor );
1045 if( nCode == KEY_UP )
1046 pNewCursor = pImpCursor->GoUpDown(pCursor,false);
1047 else
1048 pNewCursor = pImpCursor->GoPageUpDown(pCursor,false);
1049 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, true );
1050 if( !pNewCursor )
1052 Rectangle aRect( GetEntryBoundRect( pCursor ) );
1053 if( aRect.Top())
1055 aRect.Bottom() -= aRect.Top();
1056 aRect.Top() = 0;
1057 MakeVisible( aRect );
1061 if ( bChooseWithCursor && pNewCursor != NULL )
1063 pHdlEntry = pNewCursor;//GetCurEntry();
1064 pCurHighlightFrame = pHdlEntry;
1065 pView->ClickIcon();
1066 pCurHighlightFrame = NULL;
1069 break;
1071 case KEY_DOWN:
1072 case KEY_PAGEDOWN:
1073 if( pCursor )
1075 if( nCode == KEY_DOWN )
1076 pNewCursor=pImpCursor->GoUpDown( pCursor,true );
1077 else
1078 pNewCursor=pImpCursor->GoPageUpDown( pCursor,true );
1079 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, true );
1081 if ( bChooseWithCursor && pNewCursor != NULL)
1083 pHdlEntry = pNewCursor;//GetCurEntry();
1084 pCurHighlightFrame = pHdlEntry;
1085 pView->ClickIcon();
1086 pCurHighlightFrame = NULL;
1089 break;
1091 case KEY_RIGHT:
1092 if( pCursor )
1094 pNewCursor=pImpCursor->GoLeftRight(pCursor,true );
1095 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, true );
1097 break;
1099 case KEY_LEFT:
1100 if( pCursor )
1102 MakeEntryVisible( pCursor );
1103 pNewCursor = pImpCursor->GoLeftRight(pCursor,false );
1104 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, true );
1105 if( !pNewCursor )
1107 Rectangle aRect( GetEntryBoundRect(pCursor));
1108 if( aRect.Left() )
1110 aRect.Right() -= aRect.Left();
1111 aRect.Left() = 0;
1112 MakeVisible( aRect );
1116 break;
1118 case KEY_F2:
1119 if( !bMod1 && !bShift )
1120 EditTimeoutHdl( 0 );
1121 else
1122 bKeyUsed = false;
1123 break;
1125 case KEY_F8:
1126 if( rKEvt.GetKeyCode().IsShift() )
1128 if( nFlags & F_ADD_MODE )
1129 nFlags &= (~F_ADD_MODE);
1130 else
1131 nFlags |= F_ADD_MODE;
1133 else
1134 bKeyUsed = false;
1135 break;
1137 case KEY_SPACE:
1138 if( pCursor && eSelectionMode != SINGLE_SELECTION )
1140 if( !bMod1 )
1142 //SelectAll( false );
1143 SetNoSelection();
1144 ClearSelectedRectList();
1146 // click Icon with spacebar
1147 SetEntryHighlightFrame( GetCurEntry(), true );
1148 pView->ClickIcon();
1149 pHdlEntry = pCurHighlightFrame;
1150 pCurHighlightFrame=0;
1152 else
1153 ToggleSelection( pCursor );
1155 break;
1157 #ifdef DBG_UTIL
1158 case KEY_F10:
1159 if( rKEvt.GetKeyCode().IsShift() )
1161 if( pCursor )
1162 pView->SetEntryTextMode( IcnShowTextFull, pCursor );
1164 if( rKEvt.GetKeyCode().IsMod1() )
1166 if( pCursor )
1167 pView->SetEntryTextMode( IcnShowTextShort, pCursor );
1169 break;
1170 #endif
1172 case KEY_ADD:
1173 case KEY_DIVIDE :
1174 case KEY_A:
1175 if( bMod1 && (eSelectionMode != SINGLE_SELECTION))
1176 SelectAll( true );
1177 else
1178 bKeyUsed = false;
1179 break;
1181 case KEY_SUBTRACT:
1182 case KEY_COMMA :
1183 if( bMod1 )
1184 SetNoSelection();
1185 else
1186 bKeyUsed = false;
1187 break;
1189 case KEY_RETURN:
1190 if( bMod1 )
1192 if( pCursor && bEntryEditingEnabled )
1193 /*pView->*/EditEntry( pCursor );
1195 else
1196 bKeyUsed = false;
1197 break;
1199 case KEY_END:
1200 if( pCursor )
1202 pNewCursor = aEntries[ aEntries.size() - 1 ];
1203 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, true );
1205 break;
1207 case KEY_HOME:
1208 if( pCursor )
1210 pNewCursor = aEntries[ 0 ];
1211 SetCursor_Impl( pOldCursor, pNewCursor, bMod1, bShift, true );
1213 break;
1215 default:
1216 bKeyUsed = false;
1219 return bKeyUsed;
1222 // recalculate TopLeft of scrollbars (but not their sizes!)
1223 void SvxIconChoiceCtrl_Impl::PositionScrollBars( long nRealWidth, long nRealHeight )
1225 // horizontal scrollbar
1226 Point aPos( 0, nRealHeight );
1227 aPos.Y() -= nHorSBarHeight;
1229 if( aHorSBar->GetPosPixel() != aPos )
1230 aHorSBar->SetPosPixel( aPos );
1232 // vertical scrollbar
1233 aPos.X() = nRealWidth; aPos.Y() = 0;
1234 aPos.X() -= nVerSBarWidth;
1235 aPos.X()++;
1236 aPos.Y()--;
1238 if( aVerSBar->GetPosPixel() != aPos )
1239 aVerSBar->SetPosPixel( aPos );
1242 void SvxIconChoiceCtrl_Impl::AdjustScrollBars( bool )
1244 long nVirtHeight = aVirtOutputSize.Height();
1245 long nVirtWidth = aVirtOutputSize.Width();
1247 Size aOSize( pView->Control::GetOutputSizePixel() );
1248 long nRealHeight = aOSize.Height();
1249 long nRealWidth = aOSize.Width();
1251 PositionScrollBars( nRealWidth, nRealHeight );
1253 const MapMode& rMapMode = pView->GetMapMode();
1254 Point aOrigin( rMapMode.GetOrigin() );
1256 long nVisibleWidth;
1257 if( nRealWidth > nVirtWidth )
1258 nVisibleWidth = nVirtWidth + aOrigin.X();
1259 else
1260 nVisibleWidth = nRealWidth;
1262 long nVisibleHeight;
1263 if( nRealHeight > nVirtHeight )
1264 nVisibleHeight = nVirtHeight + aOrigin.Y();
1265 else
1266 nVisibleHeight = nRealHeight;
1268 bool bVerSBar = ( nWinBits & WB_VSCROLL ) != 0;
1269 bool bHorSBar = ( nWinBits & WB_HSCROLL ) != 0;
1270 bool bNoVerSBar = ( nWinBits & WB_NOVSCROLL ) != 0;
1271 bool bNoHorSBar = ( nWinBits & WB_NOHSCROLL ) != 0;
1273 sal_uInt16 nResult = 0;
1274 if( nVirtHeight )
1276 // activate vertical scrollbar?
1277 if( !bNoVerSBar && (bVerSBar || ( nVirtHeight > nVisibleHeight)) )
1279 nResult = 0x0001;
1280 nRealWidth -= nVerSBarWidth;
1282 if( nRealWidth > nVirtWidth )
1283 nVisibleWidth = nVirtWidth + aOrigin.X();
1284 else
1285 nVisibleWidth = nRealWidth;
1287 nFlags |= F_HOR_SBARSIZE_WITH_VBAR;
1289 // activate horizontal scrollbar?
1290 if( !bNoHorSBar && (bHorSBar || (nVirtWidth > nVisibleWidth)) )
1292 nResult |= 0x0002;
1293 nRealHeight -= nHorSBarHeight;
1295 if( nRealHeight > nVirtHeight )
1296 nVisibleHeight = nVirtHeight + aOrigin.Y();
1297 else
1298 nVisibleHeight = nRealHeight;
1300 // do we need a vertical scrollbar after all?
1301 if( !(nResult & 0x0001) && // only if not already there
1302 ( !bNoVerSBar && ((nVirtHeight > nVisibleHeight) || bVerSBar)) )
1304 nResult = 3; // both turned on
1305 nRealWidth -= nVerSBarWidth;
1307 if( nRealWidth > nVirtWidth )
1308 nVisibleWidth = nVirtWidth + aOrigin.X();
1309 else
1310 nVisibleWidth = nRealWidth;
1312 nFlags |= F_VER_SBARSIZE_WITH_HBAR;
1317 // size vertical scrollbar
1318 long nThumb = aVerSBar->GetThumbPos();
1319 Size aSize( nVerSBarWidth, nRealHeight );
1320 aSize.Height() += 2;
1321 if( aSize != aVerSBar->GetSizePixel() )
1322 aVerSBar->SetSizePixel( aSize );
1323 aVerSBar->SetVisibleSize( nVisibleHeight );
1324 aVerSBar->SetPageSize( GetScrollBarPageSize( nVisibleHeight ));
1326 if( nResult & 0x0001 )
1328 aVerSBar->SetThumbPos( nThumb );
1329 aVerSBar->Show();
1331 else
1333 aVerSBar->SetThumbPos( 0 );
1334 aVerSBar->Hide();
1337 // size horizontal scrollbar
1338 nThumb = aHorSBar->GetThumbPos();
1339 aSize.Width() = nRealWidth;
1340 aSize.Height() = nHorSBarHeight;
1341 aSize.Width()++;
1342 if( nResult & 0x0001 ) // vertical scrollbar?
1344 aSize.Width()++;
1345 nRealWidth++;
1347 if( aSize != aHorSBar->GetSizePixel() )
1348 aHorSBar->SetSizePixel( aSize );
1349 aHorSBar->SetVisibleSize( nVisibleWidth );
1350 aHorSBar->SetPageSize( GetScrollBarPageSize(nVisibleWidth ));
1351 if( nResult & 0x0002 )
1353 aHorSBar->SetThumbPos( nThumb );
1354 aHorSBar->Show();
1356 else
1358 aHorSBar->SetThumbPos( 0 );
1359 aHorSBar->Hide();
1362 aOutputSize.Width() = nRealWidth;
1363 if( nResult & 0x0002 ) // horizontal scrollbar ?
1364 nRealHeight++; // because lower border is clipped
1365 aOutputSize.Height() = nRealHeight;
1367 if( (nResult & (0x0001|0x0002)) == (0x0001|0x0002) )
1368 aScrBarBox->Show();
1369 else
1370 aScrBarBox->Hide();
1373 void SvxIconChoiceCtrl_Impl::Resize()
1375 StopEditTimer();
1376 InitScrollBarBox();
1377 aOutputSize = pView->GetOutputSizePixel();
1378 pImpCursor->Clear();
1379 pGridMap->OutputSizeChanged();
1381 const Size& rSize = pView->Control::GetOutputSizePixel();
1382 PositionScrollBars( rSize.Width(), rSize.Height() );
1383 // The scrollbars are shown/hidden asynchronously, so derived classes can
1384 // do an Arrange during Resize, without the scrollbars suddenly turning
1385 // on and off again.
1386 // If an event is already underway, we don't need to send a new one, at least
1387 // as long as there is only one event type.
1388 if ( ! nUserEventAdjustScrBars )
1389 nUserEventAdjustScrBars =
1390 Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl, UserEventHdl),
1391 EVENTID_ADJUST_SCROLLBARS);
1393 VisRectChanged();
1396 bool SvxIconChoiceCtrl_Impl::CheckHorScrollBar()
1398 if( !pZOrderList || !aHorSBar->IsVisible() )
1399 return false;
1400 const MapMode& rMapMode = pView->GetMapMode();
1401 Point aOrigin( rMapMode.GetOrigin() );
1402 if(!( nWinBits & WB_HSCROLL) && !aOrigin.X() )
1404 long nWidth = aOutputSize.Width();
1405 const size_t nCount = pZOrderList->size();
1406 long nMostRight = 0;
1407 for( size_t nCur = 0; nCur < nCount; nCur++ )
1409 SvxIconChoiceCtrlEntry* pEntry = (*pZOrderList)[ nCur ];
1410 long nRight = GetEntryBoundRect(pEntry).Right();
1411 if( nRight > nWidth )
1412 return false;
1413 if( nRight > nMostRight )
1414 nMostRight = nRight;
1416 aHorSBar->Hide();
1417 aOutputSize.Height() += nHorSBarHeight;
1418 aVirtOutputSize.Width() = nMostRight;
1419 aHorSBar->SetThumbPos( 0 );
1420 Range aRange;
1421 aRange.Max() = nMostRight - 1;
1422 aHorSBar->SetRange( aRange );
1423 if( aVerSBar->IsVisible() )
1425 Size aSize( aVerSBar->GetSizePixel());
1426 aSize.Height() += nHorSBarHeight;
1427 aVerSBar->SetSizePixel( aSize );
1429 return true;
1431 return false;
1434 bool SvxIconChoiceCtrl_Impl::CheckVerScrollBar()
1436 if( !pZOrderList || !aVerSBar->IsVisible() )
1437 return false;
1438 const MapMode& rMapMode = pView->GetMapMode();
1439 Point aOrigin( rMapMode.GetOrigin() );
1440 if(!( nWinBits & WB_VSCROLL) && !aOrigin.Y() )
1442 long nDeepest = 0;
1443 long nHeight = aOutputSize.Height();
1444 const size_t nCount = pZOrderList->size();
1445 for( size_t nCur = 0; nCur < nCount; nCur++ )
1447 SvxIconChoiceCtrlEntry* pEntry = (*pZOrderList)[ nCur ];
1448 long nBottom = GetEntryBoundRect(pEntry).Bottom();
1449 if( nBottom > nHeight )
1450 return false;
1451 if( nBottom > nDeepest )
1452 nDeepest = nBottom;
1454 aVerSBar->Hide();
1455 aOutputSize.Width() += nVerSBarWidth;
1456 aVirtOutputSize.Height() = nDeepest;
1457 aVerSBar->SetThumbPos( 0 );
1458 Range aRange;
1459 aRange.Max() = nDeepest - 1;
1460 aVerSBar->SetRange( aRange );
1461 if( aHorSBar->IsVisible() )
1463 Size aSize( aHorSBar->GetSizePixel());
1464 aSize.Width() += nVerSBarWidth;
1465 aHorSBar->SetSizePixel( aSize );
1467 return true;
1469 return false;
1473 // hides scrollbars if they're unnecessary
1474 void SvxIconChoiceCtrl_Impl::CheckScrollBars()
1476 CheckVerScrollBar();
1477 if( CheckHorScrollBar() )
1478 CheckVerScrollBar();
1479 if( aVerSBar->IsVisible() && aHorSBar->IsVisible() )
1480 aScrBarBox->Show();
1481 else
1482 aScrBarBox->Hide();
1486 void SvxIconChoiceCtrl_Impl::GetFocus()
1488 RepaintEntries( SvxIconViewFlags::SELECTED );
1489 if( pCursor )
1491 pCursor->SetFlags( SvxIconViewFlags::FOCUSED );
1492 ShowCursor( true );
1496 void SvxIconChoiceCtrl_Impl::LoseFocus()
1498 StopEditTimer();
1499 if( pCursor )
1500 pCursor->ClearFlags( SvxIconViewFlags::FOCUSED );
1501 ShowCursor( false );
1503 // HideFocus ();
1504 // pView->Invalidate ( aFocus.aRect );
1506 RepaintEntries( SvxIconViewFlags::SELECTED );
1509 void SvxIconChoiceCtrl_Impl::SetUpdateMode( bool bUpdate )
1511 if( bUpdate != bUpdateMode )
1513 bUpdateMode = bUpdate;
1514 if( bUpdate )
1516 AdjustScrollBars();
1517 pImpCursor->Clear();
1518 pGridMap->Clear();
1519 pView->Invalidate(INVALIDATE_NOCHILDREN);
1524 // priorities of the emphasis: bDropTarget => bCursored => bSelected
1525 void SvxIconChoiceCtrl_Impl::PaintEmphasis(const Rectangle& rTextRect, const Rectangle& rImageRect, bool bSelected,
1526 bool bDropTarget, bool bCursored, vcl::RenderContext& rRenderContext, bool bIsBackgroundPainted)
1528 static Color aTransparent(COL_TRANSPARENT);
1530 const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings();
1531 Color aOldFillColor(rRenderContext.GetFillColor());
1533 bool bSolidTextRect = false;
1534 bool bSolidImageRect = false;
1536 if(bDropTarget && (eSelectionMode != NO_SELECTION))
1538 rRenderContext.SetFillColor(rSettings.GetHighlightColor());
1539 bSolidTextRect = true;
1540 bSolidImageRect = true;
1542 else
1544 if (!bSelected || bCursored)
1546 const Color& rFillColor = rRenderContext.GetFont().GetFillColor();
1547 rRenderContext.SetFillColor(rFillColor);
1548 if (rFillColor != aTransparent)
1549 bSolidTextRect = true;
1553 // draw text rectangle
1554 if (!bSolidTextRect)
1556 if (!bIsBackgroundPainted)
1557 rRenderContext.Erase(rTextRect);
1559 else
1561 Color aOldLineColor;
1562 if (bCursored)
1564 aOldLineColor = rRenderContext.GetLineColor();
1565 rRenderContext.SetLineColor(Color(COL_GRAY));
1567 rRenderContext.DrawRect(rTextRect);
1568 if (bCursored)
1569 rRenderContext.SetLineColor(aOldLineColor);
1572 // draw image rectangle
1573 if (!bSolidImageRect)
1575 if (!bIsBackgroundPainted)
1576 rRenderContext.Erase(rImageRect);
1579 rRenderContext.SetFillColor(aOldFillColor);
1583 void SvxIconChoiceCtrl_Impl::PaintItem(const Rectangle& rRect,
1584 IcnViewFieldType eItem, SvxIconChoiceCtrlEntry* pEntry, sal_uInt16 nPaintFlags,
1585 vcl::RenderContext& rRenderContext, const OUString* pStr, vcl::ControlLayoutData* _pLayoutData )
1587 if (eItem == IcnViewFieldTypeText)
1589 OUString aText;
1590 if (!pStr)
1591 aText = SvtIconChoiceCtrl::GetEntryText(pEntry, false);
1592 else
1593 aText = *pStr;
1595 if (_pLayoutData)
1597 rRenderContext.DrawText(rRect, aText, nCurTextDrawFlags, &_pLayoutData->m_aUnicodeBoundRects, &_pLayoutData->m_aDisplayText);
1599 else
1601 Color aOldFontColor = rRenderContext.GetTextColor();
1602 if (pView->AutoFontColor())
1604 Color aBkgColor(rRenderContext.GetBackground().GetColor());
1605 Color aFontColor;
1606 sal_uInt16 nColor = (aBkgColor.GetRed() + aBkgColor.GetGreen() + aBkgColor.GetBlue()) / 3;
1607 if (nColor > 127)
1608 aFontColor.SetColor(COL_BLACK);
1609 else
1610 aFontColor.SetColor(COL_WHITE);
1611 rRenderContext.SetTextColor(aFontColor);
1614 rRenderContext.DrawText(rRect, aText, nCurTextDrawFlags);
1616 if (pView->AutoFontColor())
1617 rRenderContext.SetTextColor(aOldFontColor);
1619 if (pEntry->IsFocused())
1621 Rectangle aRect (CalcFocusRect(pEntry));
1622 ShowFocus(aRect);
1623 DrawFocusRect(rRenderContext);
1627 else
1629 Point aPos(rRect.TopLeft());
1630 if (nPaintFlags & PAINTFLAG_HOR_CENTERED)
1631 aPos.X() += (rRect.GetWidth() - aImageSize.Width()) / 2;
1632 if (nPaintFlags & PAINTFLAG_VER_CENTERED)
1633 aPos.Y() += (rRect.GetHeight() - aImageSize.Height()) / 2;
1634 SvtIconChoiceCtrl::DrawEntryImage(pEntry, aPos, rRenderContext);
1638 void SvxIconChoiceCtrl_Impl::PaintEntry(SvxIconChoiceCtrlEntry* pEntry, const Point& rPos, vcl::RenderContext& rRenderContext, bool bIsBackgroundPainted)
1640 bool bSelected = false;
1642 if (eSelectionMode != NO_SELECTION)
1643 bSelected = pEntry->IsSelected();
1645 bool bCursored = pEntry->IsCursored();
1646 bool bDropTarget = pEntry->IsDropTarget();
1647 bool bNoEmphasis = pEntry->IsBlockingEmphasis();
1649 rRenderContext.Push(PushFlags::FONT | PushFlags::TEXTCOLOR);
1651 OUString aEntryText(SvtIconChoiceCtrl::GetEntryText(pEntry, false));
1652 Rectangle aTextRect(CalcTextRect(pEntry, &rPos, false, &aEntryText));
1653 Rectangle aBmpRect(CalcBmpRect(pEntry, &rPos));
1655 bool bShowSelection = ((bSelected && !bCursored) && !bNoEmphasis && (eSelectionMode != NO_SELECTION));
1657 bool bActiveSelection = (0 != (nWinBits & WB_NOHIDESELECTION)) || pView->HasFocus();
1659 if (bShowSelection)
1661 const StyleSettings& rSettings = rRenderContext.GetSettings().GetStyleSettings();
1662 vcl::Font aNewFont(rRenderContext.GetFont());
1664 // font fill colors that are attributed "hard" need corresponding "hard"
1665 // attributed highlight colors
1666 if ((nWinBits & WB_NOHIDESELECTION) || pView->HasFocus())
1667 aNewFont.SetFillColor(rSettings.GetHighlightColor());
1668 else
1669 aNewFont.SetFillColor(rSettings.GetDeactiveColor());
1671 Color aWinCol = rSettings.GetWindowTextColor();
1672 if (!bActiveSelection && rSettings.GetFaceColor().IsBright() == aWinCol.IsBright())
1673 aNewFont.SetColor(rSettings.GetWindowTextColor());
1674 else
1675 aNewFont.SetColor(rSettings.GetHighlightTextColor());
1677 rRenderContext.SetFont(aNewFont);
1679 rRenderContext.SetFillColor(rRenderContext.GetBackground().GetColor());
1680 rRenderContext.DrawRect(CalcFocusRect(pEntry));
1681 rRenderContext.SetFillColor();
1684 bool bResetClipRegion = false;
1685 if (!rRenderContext.IsClipRegion() && (aVerSBar->IsVisible() || aHorSBar->IsVisible()))
1687 Rectangle aOutputArea(GetOutputRect());
1688 if (aOutputArea.IsOver(aTextRect) || aOutputArea.IsOver(aBmpRect))
1690 rRenderContext.SetClipRegion(vcl::Region(aOutputArea));
1691 bResetClipRegion = true;
1695 bool bLargeIconMode = WB_ICON == ( nWinBits & (VIEWMODE_MASK) );
1696 sal_uInt16 nBmpPaintFlags = PAINTFLAG_VER_CENTERED;
1697 if (bLargeIconMode)
1698 nBmpPaintFlags |= PAINTFLAG_HOR_CENTERED;
1699 sal_uInt16 nTextPaintFlags = bLargeIconMode ? PAINTFLAG_HOR_CENTERED : PAINTFLAG_VER_CENTERED;
1701 if( !bNoEmphasis )
1702 PaintEmphasis(aTextRect, aBmpRect, bSelected, bDropTarget, bCursored, rRenderContext, bIsBackgroundPainted);
1704 if ( bShowSelection )
1705 vcl::RenderTools::DrawSelectionBackground(rRenderContext, *pView.get(), CalcFocusRect(pEntry),
1706 bActiveSelection ? 1 : 2, false, true, false);
1709 PaintItem(aBmpRect, IcnViewFieldTypeImage, pEntry, nBmpPaintFlags, rRenderContext);
1711 PaintItem(aTextRect, IcnViewFieldTypeText, pEntry, nTextPaintFlags, rRenderContext);
1713 // draw highlight frame
1714 if (pEntry == pCurHighlightFrame && !bNoEmphasis)
1715 DrawHighlightFrame(rRenderContext, CalcFocusRect(pEntry), false);
1717 rRenderContext.Pop();
1718 if (bResetClipRegion)
1719 rRenderContext.SetClipRegion();
1722 void SvxIconChoiceCtrl_Impl::SetEntryPos( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos,
1723 bool bAdjustAtGrid, bool bCheckScrollBars, bool bKeepGridMap )
1725 ShowCursor( false );
1726 Rectangle aBoundRect( GetEntryBoundRect( pEntry ));
1727 pView->Invalidate( aBoundRect );
1728 ToTop( pEntry );
1729 if( !IsAutoArrange() )
1731 bool bAdjustVirtSize = false;
1732 if( rPos != aBoundRect.TopLeft() )
1734 Point aGridOffs(
1735 pEntry->aGridRect.TopLeft() - pEntry->aRect.TopLeft() );
1736 pImpCursor->Clear();
1737 if( !bKeepGridMap )
1738 pGridMap->Clear();
1739 aBoundRect.SetPos( rPos );
1740 pEntry->aRect = aBoundRect;
1741 pEntry->aGridRect.SetPos( rPos + aGridOffs );
1742 bAdjustVirtSize = true;
1744 if( bAdjustAtGrid )
1746 if( bAdjustVirtSize )
1748 // By aligning the (in some cases newly positioned) entry, it
1749 // can become completely visible again, so that maybe we don't
1750 // need a scrollbar after all. To avoid suddenly turning the
1751 // scrollbar(s) on and then off again, we use the aligned
1752 // bounding rectangle of the entry to enlarge the virtual
1753 // output size. The virtual size has to be adapted, because
1754 // AdjustEntryAtGrid depends on it.
1755 const Rectangle& rBoundRect = GetEntryBoundRect( pEntry );
1756 Rectangle aCenterRect( CalcBmpRect( pEntry, 0 ));
1757 Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) );
1758 Rectangle aNewBoundRect( aNewPos, pEntry->aRect.GetSize());
1759 AdjustVirtSize( aNewBoundRect );
1760 bAdjustVirtSize = false;
1762 AdjustEntryAtGrid( pEntry );
1763 ToTop( pEntry );
1765 if( bAdjustVirtSize )
1766 AdjustVirtSize( pEntry->aRect );
1768 if( bCheckScrollBars && bUpdateMode )
1769 CheckScrollBars();
1771 pView->Invalidate( pEntry->aRect );
1772 pGridMap->OccupyGrids( pEntry );
1774 else
1776 SvxIconChoiceCtrlEntry* pPrev = FindEntryPredecessor( pEntry, rPos );
1777 SetEntryPredecessor( pEntry, pPrev );
1778 aAutoArrangeIdle.Start();
1780 ShowCursor( true );
1783 void SvxIconChoiceCtrl_Impl::SetNoSelection()
1785 // block recursive calls via SelectEntry
1786 if( !(nFlags & F_CLEARING_SELECTION ))
1788 nFlags |= F_CLEARING_SELECTION;
1789 DeselectAllBut( 0, true );
1790 nFlags &= ~F_CLEARING_SELECTION;
1794 SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetEntry( const Point& rDocPos, bool bHit )
1796 CheckBoundingRects();
1797 // search through z-order list from the end
1798 size_t nCount = pZOrderList->size();
1799 while( nCount )
1801 nCount--;
1802 SvxIconChoiceCtrlEntry* pEntry = (*pZOrderList)[ nCount ];
1803 if( pEntry->aRect.IsInside( rDocPos ) )
1805 if( bHit )
1807 Rectangle aRect = CalcBmpRect( pEntry );
1808 aRect.Top() -= 3;
1809 aRect.Bottom() += 3;
1810 aRect.Left() -= 3;
1811 aRect.Right() += 3;
1812 if( aRect.IsInside( rDocPos ) )
1813 return pEntry;
1814 aRect = CalcTextRect( pEntry );
1815 if( aRect.IsInside( rDocPos ) )
1816 return pEntry;
1818 else
1819 return pEntry;
1822 return 0;
1825 void SvxIconChoiceCtrl_Impl::MakeEntryVisible( SvxIconChoiceCtrlEntry* pEntry, bool bBound )
1827 if ( bBound )
1829 const Rectangle& rRect = GetEntryBoundRect( pEntry );
1830 MakeVisible( rRect );
1832 else
1834 Rectangle aRect = CalcBmpRect( pEntry );
1835 aRect.Union( CalcTextRect( pEntry ) );
1836 aRect.Top() += TBOFFS_BOUND;
1837 aRect.Bottom() += TBOFFS_BOUND;
1838 aRect.Left() += LROFFS_BOUND;
1839 aRect.Right() += LROFFS_BOUND;
1840 MakeVisible( aRect );
1844 const Rectangle& SvxIconChoiceCtrl_Impl::GetEntryBoundRect( SvxIconChoiceCtrlEntry* pEntry )
1846 if( !IsBoundingRectValid( pEntry->aRect ))
1847 FindBoundingRect( pEntry );
1848 return pEntry->aRect;
1851 Rectangle SvxIconChoiceCtrl_Impl::CalcBmpRect( SvxIconChoiceCtrlEntry* pEntry, const Point* pPos )
1853 Rectangle aBound = GetEntryBoundRect( pEntry );
1854 if( pPos )
1855 aBound.SetPos( *pPos );
1856 Point aPos( aBound.TopLeft() );
1858 switch( nWinBits & (VIEWMODE_MASK) )
1860 case WB_ICON:
1862 aPos.X() += ( aBound.GetWidth() - aImageSize.Width() ) / 2;
1863 return Rectangle( aPos, aImageSize );
1866 case WB_SMALLICON:
1867 case WB_DETAILS:
1868 aPos.Y() += ( aBound.GetHeight() - aImageSize.Height() ) / 2;
1869 //TODO: determine horizontal distance to bounding rectangle
1870 return Rectangle( aPos, aImageSize );
1872 default:
1873 OSL_FAIL("IconView: Viewmode not set");
1874 return aBound;
1878 Rectangle SvxIconChoiceCtrl_Impl::CalcTextRect( SvxIconChoiceCtrlEntry* pEntry,
1879 const Point* pEntryPos, bool bEdit, const OUString* pStr )
1881 OUString aEntryText;
1882 if( !pStr )
1883 aEntryText = SvtIconChoiceCtrl::GetEntryText( pEntry, bEdit );
1884 else
1885 aEntryText = *pStr;
1887 const Rectangle aMaxTextRect( CalcMaxTextRect( pEntry ) );
1888 Rectangle aBound( GetEntryBoundRect( pEntry ) );
1889 if( pEntryPos )
1890 aBound.SetPos( *pEntryPos );
1892 Rectangle aTextRect( aMaxTextRect );
1893 if( !bEdit )
1894 aTextRect = pView->GetTextRect( aTextRect, aEntryText, nCurTextDrawFlags );
1896 Size aTextSize( aTextRect.GetSize() );
1898 Point aPos( aBound.TopLeft() );
1899 long nBoundWidth = aBound.GetWidth();
1900 long nBoundHeight = aBound.GetHeight();
1902 switch( nWinBits & (VIEWMODE_MASK) )
1904 case WB_ICON:
1905 aPos.Y() += aImageSize.Height();
1906 aPos.Y() += VER_DIST_BMP_STRING;
1907 // at little more space when editing
1908 if( bEdit )
1910 // +20%
1911 long nMinWidth = (( (aImageSize.Width()*10) / 100 ) * 2 ) +
1912 aImageSize.Width();
1913 if( nMinWidth > nBoundWidth )
1914 nMinWidth = nBoundWidth;
1916 if( aTextSize.Width() < nMinWidth )
1917 aTextSize.Width() = nMinWidth;
1919 // when editing, overlap with the area below is allowed
1920 Size aOptSize = aMaxTextRect.GetSize();
1921 if( aOptSize.Height() > aTextSize.Height() )
1922 aTextSize.Height() = aOptSize.Height();
1924 aPos.X() += (nBoundWidth - aTextSize.Width()) / 2;
1925 break;
1927 case WB_SMALLICON:
1928 case WB_DETAILS:
1929 aPos.X() += aImageSize.Width();
1930 aPos.X() += HOR_DIST_BMP_STRING;
1931 aPos.Y() += (nBoundHeight - aTextSize.Height()) / 2;
1932 break;
1934 return Rectangle( aPos, aTextSize );
1938 long SvxIconChoiceCtrl_Impl::CalcBoundingWidth( SvxIconChoiceCtrlEntry* pEntry ) const
1940 long nStringWidth = GetItemSize( pEntry, IcnViewFieldTypeText ).Width();
1941 // nStringWidth += 2*LROFFS_TEXT;
1942 long nWidth = 0;
1944 switch( nWinBits & (VIEWMODE_MASK) )
1946 case WB_ICON:
1947 nWidth = std::max( nStringWidth, aImageSize.Width() );
1948 break;
1950 case WB_SMALLICON:
1951 case WB_DETAILS:
1952 nWidth = aImageSize.Width();
1953 nWidth += HOR_DIST_BMP_STRING;
1954 nWidth += nStringWidth;
1955 break;
1957 return nWidth;
1960 long SvxIconChoiceCtrl_Impl::CalcBoundingHeight( SvxIconChoiceCtrlEntry* pEntry ) const
1962 long nStringHeight = GetItemSize( pEntry, IcnViewFieldTypeText).Height();
1963 long nHeight = 0;
1965 switch( nWinBits & (VIEWMODE_MASK) )
1967 case WB_ICON:
1968 nHeight = aImageSize.Height();
1969 nHeight += VER_DIST_BMP_STRING;
1970 nHeight += nStringHeight;
1971 break;
1973 case WB_SMALLICON:
1974 case WB_DETAILS:
1975 nHeight = std::max( aImageSize.Height(), nStringHeight );
1976 break;
1978 if( nHeight > nMaxBoundHeight )
1980 const_cast<SvxIconChoiceCtrl_Impl*>(this)->nMaxBoundHeight = nHeight;
1981 const_cast<SvxIconChoiceCtrl_Impl*>(this)->aHorSBar->SetLineSize( GetScrollBarLineSize() );
1982 const_cast<SvxIconChoiceCtrl_Impl*>(this)->aVerSBar->SetLineSize( GetScrollBarLineSize() );
1984 return nHeight;
1987 Size SvxIconChoiceCtrl_Impl::CalcBoundingSize( SvxIconChoiceCtrlEntry* pEntry ) const
1989 return Size( CalcBoundingWidth( pEntry ),
1990 CalcBoundingHeight( pEntry ) );
1993 void SvxIconChoiceCtrl_Impl::RecalcAllBoundingRectsSmart()
1995 nMaxBoundHeight = 0;
1996 pZOrderList->clear();
1997 size_t nCur;
1998 SvxIconChoiceCtrlEntry* pEntry;
1999 const size_t nCount = aEntries.size();
2001 if( !IsAutoArrange() || !pHead )
2003 for( nCur = 0; nCur < nCount; nCur++ )
2005 pEntry = aEntries[ nCur ];
2006 if( IsBoundingRectValid( pEntry->aRect ))
2008 Size aBoundSize( pEntry->aRect.GetSize() );
2009 if( aBoundSize.Height() > nMaxBoundHeight )
2010 nMaxBoundHeight = aBoundSize.Height();
2012 else
2013 FindBoundingRect( pEntry );
2014 pZOrderList->push_back( pEntry );
2017 else
2019 nCur = 0;
2020 pEntry = pHead;
2021 while( nCur != nCount )
2023 DBG_ASSERT(pEntry->pflink&&pEntry->pblink,"SvxIconChoiceCtrl_Impl::RecalcAllBoundingRect > Bad link(s)");
2024 if( IsBoundingRectValid( pEntry->aRect ))
2026 Size aBoundSize( pEntry->aRect.GetSize() );
2027 if( aBoundSize.Height() > nMaxBoundHeight )
2028 nMaxBoundHeight = aBoundSize.Height();
2030 else
2031 FindBoundingRect( pEntry );
2032 pZOrderList->push_back( pEntry );
2033 pEntry = pEntry->pflink;
2034 nCur++;
2037 AdjustScrollBars();
2040 void SvxIconChoiceCtrl_Impl::FindBoundingRect( SvxIconChoiceCtrlEntry* pEntry )
2042 DBG_ASSERT(!pEntry->IsPosLocked(),"Locked entry pos in FindBoundingRect");
2043 if( pEntry->IsPosLocked() && IsBoundingRectValid( pEntry->aRect) )
2045 AdjustVirtSize( pEntry->aRect );
2046 return;
2048 Size aSize( CalcBoundingSize( pEntry ) );
2049 Point aPos(pGridMap->GetGridRect(pGridMap->GetUnoccupiedGrid(true)).TopLeft());
2050 SetBoundingRect_Impl( pEntry, aPos, aSize );
2053 void SvxIconChoiceCtrl_Impl::SetBoundingRect_Impl( SvxIconChoiceCtrlEntry* pEntry, const Point& rPos,
2054 const Size& /*rBoundingSize*/ )
2056 Rectangle aGridRect( rPos, Size(nGridDX, nGridDY) );
2057 pEntry->aGridRect = aGridRect;
2058 Center( pEntry );
2059 AdjustVirtSize( pEntry->aRect );
2060 pGridMap->OccupyGrids( pEntry );
2064 void SvxIconChoiceCtrl_Impl::SetCursor( SvxIconChoiceCtrlEntry* pEntry, bool bSyncSingleSelection,
2065 bool bShowFocusAsync )
2067 if( pEntry == pCursor )
2069 if( pCursor && eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection &&
2070 !pCursor->IsSelected() )
2071 SelectEntry( pCursor, true, true );
2072 return;
2074 ShowCursor( false );
2075 SvxIconChoiceCtrlEntry* pOldCursor = pCursor;
2076 pCursor = pEntry;
2077 if( pOldCursor )
2079 pOldCursor->ClearFlags( SvxIconViewFlags::FOCUSED );
2080 if( eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection )
2081 SelectEntry( pOldCursor, false, true ); // deselect old cursor
2083 if( pCursor )
2085 ToTop( pCursor );
2086 pCursor->SetFlags( SvxIconViewFlags::FOCUSED );
2087 if( eSelectionMode == SINGLE_SELECTION && bSyncSingleSelection )
2088 SelectEntry( pCursor, true, true );
2089 if( !bShowFocusAsync )
2090 ShowCursor( true );
2091 else
2093 if( !nUserEventShowCursor )
2094 nUserEventShowCursor =
2095 Application::PostUserEvent( LINK( this, SvxIconChoiceCtrl_Impl, UserEventHdl),
2096 EVENTID_SHOW_CURSOR );
2102 void SvxIconChoiceCtrl_Impl::ShowCursor( bool bShow )
2104 if( !pCursor || !bShow || !pView->HasFocus() )
2106 pView->HideFocus();
2107 return;
2109 Rectangle aRect ( CalcFocusRect( pCursor ) );
2110 /*pView->*/ShowFocus( aRect );
2114 void SvxIconChoiceCtrl_Impl::HideDDIcon()
2116 pView->Update();
2117 ImpHideDDIcon();
2118 pDDBufDev = pDDDev;
2119 pDDDev = 0;
2122 void SvxIconChoiceCtrl_Impl::ImpHideDDIcon()
2124 if( pDDDev )
2126 Size aSize( pDDDev->GetOutputSizePixel() );
2127 // restore pView
2128 pView->DrawOutDev( aDDLastRectPos, aSize, Point(), aSize, *pDDDev );
2132 bool SvxIconChoiceCtrl_Impl::HandleScrollCommand( const CommandEvent& rCmd )
2134 Rectangle aDocRect( GetDocumentRect() );
2135 Rectangle aVisRect( GetVisibleRect() );
2136 if( aVisRect.IsInside( aDocRect ))
2137 return false;
2138 Size aDocSize( aDocRect.GetSize() );
2139 Size aVisSize( aVisRect.GetSize() );
2140 bool bHor = aDocSize.Width() > aVisSize.Width();
2141 bool bVer = aDocSize.Height() > aVisSize.Height();
2143 long nScrollDX = 0, nScrollDY = 0;
2145 switch( rCmd.GetCommand() )
2147 case CommandEventId::StartAutoScroll:
2149 pView->EndTracking();
2150 sal_uInt16 nScrollFlags = 0;
2151 if( bHor )
2152 nScrollFlags |= AUTOSCROLL_HORZ;
2153 if( bVer )
2154 nScrollFlags |= AUTOSCROLL_VERT;
2155 if( nScrollFlags )
2157 pView->StartAutoScroll( nScrollFlags );
2158 return true;
2161 break;
2163 case CommandEventId::Wheel:
2165 const CommandWheelData* pData = rCmd.GetWheelData();
2166 if( pData && (CommandWheelMode::SCROLL == pData->GetMode()) && !pData->IsHorz() )
2168 sal_uLong nScrollLines = pData->GetScrollLines();
2169 if( nScrollLines == COMMAND_WHEEL_PAGESCROLL )
2171 nScrollDY = GetScrollBarPageSize( aVisSize.Width() );
2172 if( pData->GetDelta() < 0 )
2173 nScrollDY *= -1;
2175 else
2177 nScrollDY = pData->GetNotchDelta() * (long)nScrollLines;
2178 nScrollDY *= GetScrollBarLineSize();
2182 break;
2184 case CommandEventId::AutoScroll:
2186 const CommandScrollData* pData = rCmd.GetAutoScrollData();
2187 if( pData )
2189 nScrollDX = pData->GetDeltaX() * GetScrollBarLineSize();
2190 nScrollDY = pData->GetDeltaY() * GetScrollBarLineSize();
2193 break;
2195 default: break;
2198 if( nScrollDX || nScrollDY )
2200 aVisRect.Top() -= nScrollDY;
2201 aVisRect.Bottom() -= nScrollDY;
2202 aVisRect.Left() -= nScrollDX;
2203 aVisRect.Right() -= nScrollDX;
2204 MakeVisible( aVisRect );
2205 return true;
2207 return false;
2211 void SvxIconChoiceCtrl_Impl::Command( const CommandEvent& rCEvt )
2213 // scroll mouse event?
2214 if( (rCEvt.GetCommand() == CommandEventId::Wheel) ||
2215 (rCEvt.GetCommand() == CommandEventId::StartAutoScroll) ||
2216 (rCEvt.GetCommand() == CommandEventId::AutoScroll) )
2218 if( HandleScrollCommand( rCEvt ) )
2219 return;
2223 void SvxIconChoiceCtrl_Impl::ToTop( SvxIconChoiceCtrlEntry* pEntry )
2225 if( !pZOrderList->empty()
2226 && pEntry != pZOrderList->back()
2228 for(
2229 SvxIconChoiceCtrlEntryList_impl::iterator it = pZOrderList->begin();
2230 it != pZOrderList->end();
2231 ++it
2233 if ( *it == pEntry )
2235 pZOrderList->erase( it );
2236 pZOrderList->push_back( pEntry );
2237 break;
2243 void SvxIconChoiceCtrl_Impl::ClipAtVirtOutRect( Rectangle& rRect ) const
2245 if( rRect.Bottom() >= aVirtOutputSize.Height() )
2246 rRect.Bottom() = aVirtOutputSize.Height() - 1;
2247 if( rRect.Right() >= aVirtOutputSize.Width() )
2248 rRect.Right() = aVirtOutputSize.Width() - 1;
2249 if( rRect.Top() < 0 )
2250 rRect.Top() = 0;
2251 if( rRect.Left() < 0 )
2252 rRect.Left() = 0;
2255 // rRect: area of the document (in document coordinates) that we want to make
2256 // visible
2257 // bScrBar == true: rectangle was calculated because of a scrollbar event
2259 void SvxIconChoiceCtrl_Impl::MakeVisible( const Rectangle& rRect, bool bScrBar,
2260 bool bCallRectChangedHdl )
2262 Rectangle aVirtRect( rRect );
2263 ClipAtVirtOutRect( aVirtRect );
2264 Point aOrigin( pView->GetMapMode().GetOrigin() );
2265 // convert to document coordinate
2266 aOrigin *= -1;
2267 Rectangle aOutputArea( GetOutputRect() );
2268 if( aOutputArea.IsInside( aVirtRect ) )
2269 return; // is already visible
2271 long nDy;
2272 if( aVirtRect.Top() < aOutputArea.Top() )
2274 // scroll up (nDy < 0)
2275 nDy = aVirtRect.Top() - aOutputArea.Top();
2277 else if( aVirtRect.Bottom() > aOutputArea.Bottom() )
2279 // scroll down (nDy > 0)
2280 nDy = aVirtRect.Bottom() - aOutputArea.Bottom();
2282 else
2283 nDy = 0;
2285 long nDx;
2286 if( aVirtRect.Left() < aOutputArea.Left() )
2288 // scroll to the left (nDx < 0)
2289 nDx = aVirtRect.Left() - aOutputArea.Left();
2291 else if( aVirtRect.Right() > aOutputArea.Right() )
2293 // scroll to the right (nDx > 0)
2294 nDx = aVirtRect.Right() - aOutputArea.Right();
2296 else
2297 nDx = 0;
2299 aOrigin.X() += nDx;
2300 aOrigin.Y() += nDy;
2301 aOutputArea.SetPos( aOrigin );
2302 if( GetUpdateMode() )
2304 HideDDIcon();
2305 pView->Update();
2306 ShowCursor( false );
2309 // invert origin for SV (so we can scroll/paint using document coordinates)
2310 aOrigin *= -1;
2311 SetOrigin( aOrigin );
2313 bool bScrollable = pView->GetBackground().IsScrollable();
2315 if( bScrollable && GetUpdateMode() )
2317 // scroll in reverse direction!
2318 pView->Control::Scroll( -nDx, -nDy, aOutputArea,
2319 SCROLL_NOCHILDREN | SCROLL_USECLIPREGION | SCROLL_CLIP );
2321 else
2322 pView->Invalidate(INVALIDATE_NOCHILDREN);
2324 if( aHorSBar->IsVisible() || aVerSBar->IsVisible() )
2326 if( !bScrBar )
2328 aOrigin *= -1;
2329 // correct thumbs
2330 if(aHorSBar->IsVisible() && aHorSBar->GetThumbPos() != aOrigin.X())
2331 aHorSBar->SetThumbPos( aOrigin.X() );
2332 if(aVerSBar->IsVisible() && aVerSBar->GetThumbPos() != aOrigin.Y())
2333 aVerSBar->SetThumbPos( aOrigin.Y() );
2337 if( GetUpdateMode() )
2338 ShowCursor( true );
2340 // check if we still need scrollbars
2341 CheckScrollBars();
2342 if( bScrollable && GetUpdateMode() )
2343 pView->Update();
2345 // If the requested area can not be made completely visible, the
2346 // Vis-Rect-Changed handler is called in any case. This case may occur e.g.
2347 // if only few pixels of the lower border are invisible, but a scrollbar has
2348 // a larger line size.
2349 if( bCallRectChangedHdl || GetOutputRect() != rRect )
2350 VisRectChanged();
2353 sal_uLong SvxIconChoiceCtrl_Impl::GetSelectionCount() const
2355 if( (nWinBits & WB_HIGHLIGHTFRAME) && pCurHighlightFrame )
2356 return 1;
2357 return nSelectionCount;
2360 void SvxIconChoiceCtrl_Impl::ToggleSelection( SvxIconChoiceCtrlEntry* pEntry )
2362 bool bSel;
2363 if( pEntry->IsSelected() )
2364 bSel = false;
2365 else
2366 bSel = true;
2367 SelectEntry( pEntry, bSel, true, true );
2370 void SvxIconChoiceCtrl_Impl::DeselectAllBut( SvxIconChoiceCtrlEntry* pThisEntryNot,
2371 bool bPaintSync )
2373 ClearSelectedRectList();
2375 // TODO: work through z-order list, if necessary!
2377 size_t nCount = aEntries.size();
2378 for( size_t nCur = 0; nCur < nCount; nCur++ )
2380 SvxIconChoiceCtrlEntry* pEntry = aEntries[ nCur ];
2381 if( pEntry != pThisEntryNot && pEntry->IsSelected() )
2382 SelectEntry( pEntry, false, true, true, bPaintSync );
2384 pAnchor = 0;
2385 nFlags &= (~F_ADD_MODE);
2388 Size SvxIconChoiceCtrl_Impl::GetMinGrid() const
2390 Size aMinSize( aImageSize );
2391 aMinSize.Width() += 2 * LROFFS_BOUND;
2392 aMinSize.Height() += TBOFFS_BOUND; // single offset is enough (FileDlg)
2393 OUString aStrDummy( "XXX" );
2394 Size aTextSize( pView->GetTextWidth( aStrDummy ), pView->GetTextHeight() );
2395 if( nWinBits & WB_ICON )
2397 aMinSize.Height() += VER_DIST_BMP_STRING;
2398 aMinSize.Height() += aTextSize.Height();
2400 else
2402 aMinSize.Width() += HOR_DIST_BMP_STRING;
2403 aMinSize.Width() += aTextSize.Width();
2405 return aMinSize;
2408 void SvxIconChoiceCtrl_Impl::SetGrid( const Size& rSize )
2410 Size aSize( rSize );
2411 Size aMinSize( GetMinGrid() );
2412 if( aSize.Width() < aMinSize.Width() )
2413 aSize.Width() = aMinSize.Width();
2414 if( aSize.Height() < aMinSize.Height() )
2415 aSize.Height() = aMinSize.Height();
2417 nGridDX = aSize.Width();
2418 // HACK: Detail mode is not yet fully implemented, this workaround makes it
2419 // fly with a single column
2420 if( nWinBits & WB_DETAILS )
2422 const SvxIconChoiceCtrlColumnInfo* pCol = GetColumn( 0 );
2423 if( pCol )
2424 const_cast<SvxIconChoiceCtrlColumnInfo*>(pCol)->SetWidth( nGridDX );
2426 nGridDY = aSize.Height();
2427 SetDefaultTextSize();
2430 // Calculates the maximum size that the text rectangle may use within its
2431 // bounding rectangle. In WB_ICON mode with IcnShowTextFull, Bottom is set to
2432 // LONG_MAX.
2434 Rectangle SvxIconChoiceCtrl_Impl::CalcMaxTextRect( const SvxIconChoiceCtrlEntry* pEntry ) const
2436 Rectangle aBoundRect;
2437 // avoid infinite recursion: don't calculate the bounding rectangle here
2438 if( IsBoundingRectValid( pEntry->aRect ) )
2439 aBoundRect = pEntry->aRect;
2440 else
2441 aBoundRect = pEntry->aGridRect;
2443 Rectangle aBmpRect( const_cast<SvxIconChoiceCtrl_Impl*>(this)->CalcBmpRect(
2444 const_cast<SvxIconChoiceCtrlEntry*>(pEntry) ) );
2445 if( nWinBits & WB_ICON )
2447 aBoundRect.Top() = aBmpRect.Bottom();
2448 aBoundRect.Top() += VER_DIST_BMP_STRING;
2449 if( aBoundRect.Top() > aBoundRect.Bottom())
2450 aBoundRect.Top() = aBoundRect.Bottom();
2451 aBoundRect.Left() += LROFFS_BOUND;
2452 aBoundRect.Left()++;
2453 aBoundRect.Right() -= LROFFS_BOUND;
2454 aBoundRect.Right()--;
2455 if( aBoundRect.Left() > aBoundRect.Right())
2456 aBoundRect.Left() = aBoundRect.Right();
2457 if( GetEntryTextModeSmart( pEntry ) == IcnShowTextFull )
2458 aBoundRect.Bottom() = LONG_MAX;
2460 else
2462 aBoundRect.Left() = aBmpRect.Right();
2463 aBoundRect.Left() += HOR_DIST_BMP_STRING;
2464 aBoundRect.Right() -= LROFFS_BOUND;
2465 if( aBoundRect.Left() > aBoundRect.Right() )
2466 aBoundRect.Left() = aBoundRect.Right();
2467 long nHeight = aBoundRect.GetSize().Height();
2468 nHeight = nHeight - aDefaultTextSize.Height();
2469 nHeight /= 2;
2470 aBoundRect.Top() += nHeight;
2471 aBoundRect.Bottom() -= nHeight;
2473 return aBoundRect;
2476 void SvxIconChoiceCtrl_Impl::SetDefaultTextSize()
2478 long nDY = nGridDY;
2479 nDY -= aImageSize.Height();
2480 nDY -= VER_DIST_BMP_STRING;
2481 nDY -= 2 * TBOFFS_BOUND;
2482 if (nDY <= 0)
2483 nDY = 2;
2485 long nDX = nGridDX;
2486 nDX -= 2 * LROFFS_BOUND;
2487 nDX -= 2;
2488 if (nDX <= 0)
2489 nDX = 2;
2491 long nHeight = pView->GetTextHeight();
2492 if (nDY < nHeight)
2493 nDY = nHeight;
2494 aDefaultTextSize = Size(nDX, nDY);
2498 void SvxIconChoiceCtrl_Impl::Center( SvxIconChoiceCtrlEntry* pEntry ) const
2500 pEntry->aRect = pEntry->aGridRect;
2501 Size aSize( CalcBoundingSize( pEntry ) );
2502 if( nWinBits & WB_ICON )
2504 // center horizontally
2505 long nBorder = pEntry->aGridRect.GetWidth() - aSize.Width();
2506 pEntry->aRect.Left() += nBorder / 2;
2507 pEntry->aRect.Right() -= nBorder / 2;
2509 // center vertically
2510 pEntry->aRect.Bottom() = pEntry->aRect.Top() + aSize.Height();
2514 // The deltas are the offsets by which the view is moved on the document.
2515 // left, up: offsets < 0
2516 // right, down: offsets > 0
2517 void SvxIconChoiceCtrl_Impl::Scroll( long nDeltaX, long nDeltaY, bool bScrollBar )
2519 const MapMode& rMapMode = pView->GetMapMode();
2520 Point aOrigin( rMapMode.GetOrigin() );
2521 // convert to document coordinate
2522 aOrigin *= -1;
2523 aOrigin.Y() += nDeltaY;
2524 aOrigin.X() += nDeltaX;
2525 Rectangle aRect( aOrigin, aOutputSize );
2526 MakeVisible( aRect, bScrollBar );
2530 const Size& SvxIconChoiceCtrl_Impl::GetItemSize( SvxIconChoiceCtrlEntry*,
2531 IcnViewFieldType eItem ) const
2533 if (eItem == IcnViewFieldTypeText)
2534 return aDefaultTextSize;
2535 return aImageSize;
2538 Rectangle SvxIconChoiceCtrl_Impl::CalcFocusRect( SvxIconChoiceCtrlEntry* pEntry )
2540 Rectangle aTextRect( CalcTextRect( pEntry ) );
2541 Rectangle aBoundRect( GetEntryBoundRect( pEntry ) );
2542 return Rectangle(
2543 aBoundRect.Left(), aBoundRect.Top() - 1, aBoundRect.Right() - 1,
2544 aTextRect.Bottom() + 1);
2547 // the hot spot is the inner 50% of the rectangle
2548 static Rectangle GetHotSpot( const Rectangle& rRect )
2550 Rectangle aResult( rRect );
2551 aResult.Justify();
2552 Size aSize( rRect.GetSize() );
2553 long nDelta = aSize.Width() / 4;
2554 aResult.Left() += nDelta;
2555 aResult.Right() -= nDelta;
2556 nDelta = aSize.Height() / 4;
2557 aResult.Top() += nDelta;
2558 aResult.Bottom() -= nDelta;
2559 return aResult;
2562 void SvxIconChoiceCtrl_Impl::SelectRect( SvxIconChoiceCtrlEntry* pEntry1, SvxIconChoiceCtrlEntry* pEntry2,
2563 bool bAdd, std::vector<Rectangle*>* pOtherRects )
2565 DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr");
2566 Rectangle aRect( GetEntryBoundRect( pEntry1 ) );
2567 aRect.Union( GetEntryBoundRect( pEntry2 ) );
2568 SelectRect( aRect, bAdd, pOtherRects );
2571 void SvxIconChoiceCtrl_Impl::SelectRect( const Rectangle& rRect, bool bAdd,
2572 std::vector<Rectangle*>* pOtherRects )
2574 aCurSelectionRect = rRect;
2575 if( !pZOrderList || !pZOrderList->size() )
2576 return;
2578 // set flag, so ToTop won't be called in Select
2579 bool bAlreadySelectingRect = (nFlags & F_SELECTING_RECT) != 0;
2580 nFlags |= F_SELECTING_RECT;
2582 CheckBoundingRects();
2583 pView->Update();
2584 const size_t nCount = pZOrderList->size();
2586 Rectangle aRect( rRect );
2587 aRect.Justify();
2588 bool bCalcOverlap = (bAdd && pOtherRects && !pOtherRects->empty());
2590 bool bResetClipRegion = false;
2591 if( !pView->IsClipRegion() )
2593 bResetClipRegion = true;
2594 pView->SetClipRegion(vcl::Region(GetOutputRect()));
2597 for( size_t nPos = 0; nPos < nCount; nPos++ )
2599 SvxIconChoiceCtrlEntry* pEntry = (*pZOrderList)[ nPos ];
2601 if( !IsBoundingRectValid( pEntry->aRect ))
2602 FindBoundingRect( pEntry );
2603 Rectangle aBoundRect( GetHotSpot( pEntry->aRect ) );
2604 bool bSelected = pEntry->IsSelected();
2606 bool bOverlaps;
2607 if( bCalcOverlap )
2608 bOverlaps = IsOver( pOtherRects, aBoundRect );
2609 else
2610 bOverlaps = false;
2611 bool bOver = aRect.IsOver( aBoundRect );
2613 if( bOver && !bOverlaps )
2615 // is inside the new selection rectangle and outside of any old one
2616 // => select
2617 if( !bSelected )
2618 SelectEntry( pEntry, true, true, true );
2620 else if( !bAdd )
2622 // is outside of the selection rectangle
2623 // => deselect
2624 if( bSelected )
2625 SelectEntry( pEntry, false, true, true );
2627 else if( bAdd && bOverlaps )
2629 // The entry is inside an old (=>span multiple rectangles with Ctrl)
2630 // selection rectangle.
2632 // There is still a bug here! The selection status of an entry in a
2633 // previous rectangle has to be restored, if it was touched by the
2634 // current selection rectangle but is not inside it any more.
2635 // For simplicity's sake, let's assume that all entries in the old
2636 // rectangles were correctly selected. It is wrong to just deselect
2637 // the intersection.
2638 // Possible solution: remember a snapshot of the selection before
2639 // spanning the rectangle.
2640 if( aBoundRect.IsOver( rRect))
2642 // deselect intersection between old rectangles and current rectangle
2643 if( bSelected )
2644 SelectEntry( pEntry, false, true, true );
2646 else
2648 // select entry of an old rectangle
2649 if( !bSelected )
2650 SelectEntry( pEntry, true, true, true );
2653 else if( !bOver && bSelected )
2655 // this entry is completely outside the rectangle => deselect it
2656 SelectEntry( pEntry, false, true, true );
2660 if( !bAlreadySelectingRect )
2661 nFlags &= ~F_SELECTING_RECT;
2663 pView->Update();
2664 if( bResetClipRegion )
2665 pView->SetClipRegion();
2668 void SvxIconChoiceCtrl_Impl::SelectRange(
2669 SvxIconChoiceCtrlEntry* pStart,
2670 SvxIconChoiceCtrlEntry* pEnd,
2671 bool bAdd )
2673 sal_uLong nFront = GetEntryListPos( pStart );
2674 sal_uLong nBack = GetEntryListPos( pEnd );
2675 sal_uLong nFirst = std::min( nFront, nBack );
2676 sal_uLong nLast = std::max( nFront, nBack );
2677 sal_uLong i;
2678 SvxIconChoiceCtrlEntry* pEntry;
2680 if ( ! bAdd )
2682 // deselect everything before the first entry if not in
2683 // adding mode
2684 for ( i=0; i<nFirst; i++ )
2686 pEntry = GetEntry( i );
2687 if( pEntry->IsSelected() )
2688 SelectEntry( pEntry, false, true, true, true );
2692 // select everything between nFirst and nLast
2693 for ( i=nFirst; i<=nLast; i++ )
2695 pEntry = GetEntry( i );
2696 if( ! pEntry->IsSelected() )
2697 SelectEntry( pEntry, true, true, true, true );
2700 if ( ! bAdd )
2702 // deselect everything behind the last entry if not in
2703 // adding mode
2704 sal_uLong nEnd = GetEntryCount();
2705 for ( ; i<nEnd; i++ )
2707 pEntry = GetEntry( i );
2708 if( pEntry->IsSelected() )
2709 SelectEntry( pEntry, false, true, true, true );
2714 bool SvxIconChoiceCtrl_Impl::IsOver( std::vector<Rectangle*>* pRectList, const Rectangle& rBoundRect )
2716 const sal_uInt16 nCount = pRectList->size();
2717 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
2719 Rectangle* pRect = (*pRectList)[ nCur ];
2720 if( rBoundRect.IsOver( *pRect ))
2721 return true;
2723 return false;
2726 void SvxIconChoiceCtrl_Impl::AddSelectedRect( SvxIconChoiceCtrlEntry* pEntry1,
2727 SvxIconChoiceCtrlEntry* pEntry2 )
2729 DBG_ASSERT(pEntry1 && pEntry2,"SelectEntry: Invalid Entry-Ptr");
2730 Rectangle aRect( GetEntryBoundRect( pEntry1 ) );
2731 aRect.Union( GetEntryBoundRect( pEntry2 ) );
2732 AddSelectedRect( aRect );
2735 void SvxIconChoiceCtrl_Impl::AddSelectedRect( const Rectangle& rRect )
2737 Rectangle* pRect = new Rectangle( rRect );
2738 pRect->Justify();
2739 aSelectedRectList.push_back( pRect );
2742 void SvxIconChoiceCtrl_Impl::ClearSelectedRectList()
2744 const sal_uInt16 nCount = aSelectedRectList.size();
2745 for( sal_uInt16 nCur = 0; nCur < nCount; nCur++ )
2747 Rectangle* pRect = aSelectedRectList[ nCur ];
2748 delete pRect;
2750 aSelectedRectList.clear();
2753 IMPL_LINK_NOARG_TYPED(SvxIconChoiceCtrl_Impl, AutoArrangeHdl, Idle *, void)
2755 aAutoArrangeIdle.Stop();
2756 Arrange( IsAutoArrange() );
2759 IMPL_LINK_NOARG_TYPED(SvxIconChoiceCtrl_Impl, VisRectChangedHdl, Idle *, void)
2761 aVisRectChangedIdle.Stop();
2762 pView->VisibleRectChanged();
2765 IMPL_LINK_NOARG_TYPED(SvxIconChoiceCtrl_Impl, DocRectChangedHdl, Idle *, void)
2767 aDocRectChangedIdle.Stop();
2768 pView->DocumentRectChanged();
2771 bool SvxIconChoiceCtrl_Impl::IsTextHit( SvxIconChoiceCtrlEntry* pEntry, const Point& rDocPos )
2773 Rectangle aRect( CalcTextRect( pEntry ));
2774 if( aRect.IsInside( rDocPos ) )
2775 return true;
2776 return false;
2779 IMPL_LINK_NOARG_TYPED(SvxIconChoiceCtrl_Impl, EditTimeoutHdl, Idle *, void)
2781 SvxIconChoiceCtrlEntry* pEntry = GetCurEntry();
2782 if( bEntryEditingEnabled && pEntry &&
2783 pEntry->IsSelected())
2785 EditEntry( pEntry );
2791 // Function to align entries to the grid
2794 // pStart == 0: align all entries
2795 // else: align all entries of the row from pStart on (including pStart)
2796 void SvxIconChoiceCtrl_Impl::AdjustEntryAtGrid( SvxIconChoiceCtrlEntry* pStart )
2798 IconChoiceMap aLists;
2799 pImpCursor->CreateGridAjustData( aLists, pStart );
2800 for (IconChoiceMap::const_iterator iter = aLists.begin();
2801 iter != aLists.end(); ++iter)
2803 AdjustAtGrid(iter->second, pStart);
2805 IcnCursor_Impl::DestroyGridAdjustData( aLists );
2806 CheckScrollBars();
2809 // align a row, might expand width, doesn't break the line
2810 void SvxIconChoiceCtrl_Impl::AdjustAtGrid( const SvxIconChoiceCtrlEntryPtrVec& rRow, SvxIconChoiceCtrlEntry* pStart )
2812 if( rRow.empty() )
2813 return;
2815 bool bGo;
2816 if( !pStart )
2817 bGo = true;
2818 else
2819 bGo = false;
2821 long nCurRight = 0;
2822 for( sal_uInt16 nCur = 0; nCur < rRow.size(); nCur++ )
2824 SvxIconChoiceCtrlEntry* pCur = rRow[ nCur ];
2825 if( !bGo && pCur == pStart )
2826 bGo = true;
2828 // SvIcnVwDataEntry* pViewData = ICNVIEWDATA(pCur);
2829 // Decisive (for our eye) is the bitmap, else, the entry might jump too
2830 // much within long texts.
2831 const Rectangle& rBoundRect = GetEntryBoundRect( pCur );
2832 Rectangle aCenterRect( CalcBmpRect( pCur, 0 ));
2833 if( bGo && !pCur->IsPosLocked() )
2835 long nWidth = aCenterRect.GetSize().Width();
2836 Point aNewPos( AdjustAtGrid( aCenterRect, rBoundRect ) );
2837 while( aNewPos.X() < nCurRight )
2838 aNewPos.X() += nGridDX;
2839 if( aNewPos != rBoundRect.TopLeft() )
2841 SetEntryPos( pCur, aNewPos );
2842 pCur->SetFlags( SvxIconViewFlags::POS_MOVED );
2843 nFlags |= F_MOVED_ENTRIES;
2845 nCurRight = aNewPos.X() + nWidth;
2847 else
2849 nCurRight = rBoundRect.Right();
2854 // Aligns a rectangle to the grid, but doesn't guarantee that the new position
2855 // is vacant. The position can be used for SetEntryPos. The CenterRect describes
2856 // a part of the bounding rectangle that is used for calculating the target
2857 // rectangle.
2858 Point SvxIconChoiceCtrl_Impl::AdjustAtGrid( const Rectangle& rCenterRect,
2859 const Rectangle& rBoundRect ) const
2861 Point aPos( rCenterRect.TopLeft() );
2862 Size aSize( rCenterRect.GetSize() );
2864 aPos.X() -= LROFFS_WINBORDER;
2865 aPos.Y() -= TBOFFS_WINBORDER;
2867 // align (the center of the rectangle is the reference)
2868 short nGridX = (short)((aPos.X()+(aSize.Width()/2)) / nGridDX);
2869 short nGridY = (short)((aPos.Y()+(aSize.Height()/2)) / nGridDY);
2870 aPos.X() = nGridX * nGridDX;
2871 aPos.Y() = nGridY * nGridDY;
2872 // horizontal center
2873 aPos.X() += (nGridDX - rBoundRect.GetSize().Width() ) / 2;
2875 aPos.X() += LROFFS_WINBORDER;
2876 aPos.Y() += TBOFFS_WINBORDER;
2878 return aPos;
2881 #ifdef DBG_UTIL
2882 void SvxIconChoiceCtrl_Impl::SetEntryTextMode( SvxIconChoiceCtrlTextMode eMode, SvxIconChoiceCtrlEntry* pEntry )
2884 if( !pEntry )
2886 if( eTextMode != eMode )
2888 if( eTextMode == IcnShowTextDontKnow )
2889 eTextMode = IcnShowTextShort;
2890 eTextMode = eMode;
2891 Arrange( true );
2894 else
2896 if( pEntry->eTextMode != eMode )
2898 pEntry->eTextMode = eMode;
2899 InvalidateEntry( pEntry );
2900 pView->Invalidate( GetEntryBoundRect( pEntry ) );
2901 AdjustVirtSize( pEntry->aRect );
2905 #endif
2907 SvxIconChoiceCtrlTextMode SvxIconChoiceCtrl_Impl::GetEntryTextModeSmart( const SvxIconChoiceCtrlEntry* pEntry ) const
2909 DBG_ASSERT(pEntry,"GetEntryTextModeSmart: Entry not set");
2910 SvxIconChoiceCtrlTextMode eMode = pEntry->GetTextMode();
2911 if( eMode == IcnShowTextDontKnow )
2912 return eTextMode;
2913 return eMode;
2918 // Draw my own focusrect, because the focusrect of the outputdevice has got the inverted color
2919 // of the background. But what will we see, if the backgroundcolor is gray ? - We will see
2920 // a gray focusrect on a gray background !!!
2922 void SvxIconChoiceCtrl_Impl::ShowFocus ( Rectangle& rRect )
2924 Color aBkgColor(pView->GetBackground().GetColor());
2925 Color aPenColor;
2926 sal_uInt16 nColor = ( aBkgColor.GetRed() + aBkgColor.GetGreen() + aBkgColor.GetBlue() ) / 3;
2927 if (nColor > 128)
2928 aPenColor.SetColor(COL_BLACK);
2929 else
2930 aPenColor.SetColor(COL_WHITE);
2932 aFocus.bOn = true;
2933 aFocus.aPenColor = aPenColor;
2934 aFocus.aRect = rRect;
2937 void SvxIconChoiceCtrl_Impl::DrawFocusRect(vcl::RenderContext& rRenderContext)
2939 rRenderContext.SetLineColor(aFocus.aPenColor);
2940 rRenderContext.SetFillColor();
2941 Polygon aPolygon (aFocus.aRect);
2943 LineInfo aLineInfo(LINE_DASH);
2945 aLineInfo.SetDashLen(1);
2946 aLineInfo.SetDotLen(1L);
2947 aLineInfo.SetDistance(1L);
2948 aLineInfo.SetDotCount(1);
2950 rRenderContext.DrawPolyLine(aPolygon, aLineInfo);
2953 bool SvxIconChoiceCtrl_Impl::IsMnemonicChar( sal_Unicode cChar, sal_uLong& rPos ) const
2955 bool bRet = false;
2956 const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetUILocaleI18nHelper();
2957 size_t nEntryCount = GetEntryCount();
2958 for ( size_t i = 0; i < nEntryCount; ++i )
2960 if ( rI18nHelper.MatchMnemonic( GetEntry( i )->GetText(), cChar ) )
2962 bRet = true;
2963 rPos = i;
2964 break;
2968 return bRet;
2974 IMPL_LINK(SvxIconChoiceCtrl_Impl, UserEventHdl, void*, nId )
2976 if( nId == EVENTID_ADJUST_SCROLLBARS )
2978 nUserEventAdjustScrBars = 0;
2979 AdjustScrollBars();
2981 else if( nId == EVENTID_SHOW_CURSOR )
2983 nUserEventShowCursor = 0;
2984 ShowCursor( true );
2986 return 0;
2989 void SvxIconChoiceCtrl_Impl::CancelUserEvents()
2991 if( nUserEventAdjustScrBars )
2993 Application::RemoveUserEvent( nUserEventAdjustScrBars );
2994 nUserEventAdjustScrBars = 0;
2996 if( nUserEventShowCursor )
2998 Application::RemoveUserEvent( nUserEventShowCursor );
2999 nUserEventShowCursor = 0;
3003 void SvxIconChoiceCtrl_Impl::InvalidateEntry( SvxIconChoiceCtrlEntry* pEntry )
3005 if( pEntry == pCursor )
3006 ShowCursor( false );
3007 pView->Invalidate( pEntry->aRect );
3008 Center( pEntry );
3009 pView->Invalidate( pEntry->aRect );
3010 if( pEntry == pCursor )
3011 ShowCursor( true );
3014 void SvxIconChoiceCtrl_Impl::EditEntry( SvxIconChoiceCtrlEntry* pEntry )
3016 DBG_ASSERT(pEntry,"EditEntry: Entry not set");
3017 if( !pEntry )
3018 return;
3020 StopEntryEditing( true );
3021 pEdit.disposeAndClear();
3022 SetNoSelection();
3024 pCurEditedEntry = pEntry;
3025 OUString aEntryText( SvtIconChoiceCtrl::GetEntryText( pEntry, true ) );
3026 Rectangle aRect( CalcTextRect( pEntry, 0, true, &aEntryText ) );
3027 MakeVisible( aRect );
3028 Point aPos( aRect.TopLeft() );
3029 aPos = pView->GetPixelPos( aPos );
3030 aRect.SetPos( aPos );
3031 pView->HideFocus();
3032 pEdit = VclPtr<IcnViewEdit_Impl>::Create(
3034 pView,
3035 aRect.TopLeft(),
3036 aRect.GetSize(),
3037 aEntryText,
3038 LINK( this, SvxIconChoiceCtrl_Impl, TextEditEndedHdl ) );
3041 IMPL_LINK_NOARG(SvxIconChoiceCtrl_Impl, TextEditEndedHdl)
3043 DBG_ASSERT(pEdit,"TextEditEnded: pEdit not set");
3044 if( !pEdit )
3046 pCurEditedEntry = 0;
3047 return 0;
3049 DBG_ASSERT(pCurEditedEntry,"TextEditEnded: pCurEditedEntry not set");
3051 if( !pCurEditedEntry )
3053 pEdit->Hide();
3054 if( pEdit->IsGrabFocus() )
3055 pView->GrabFocus();
3056 return 0;
3059 OUString aText;
3060 if ( !pEdit->EditingCanceled() )
3061 aText = pEdit->GetText();
3062 else
3063 aText = pEdit->GetSavedValue();
3065 InvalidateEntry( pCurEditedEntry );
3066 if( !GetSelectionCount() )
3067 SelectEntry( pCurEditedEntry, true );
3069 pEdit->Hide();
3070 if( pEdit->IsGrabFocus() )
3071 pView->GrabFocus();
3072 // The edit can not be deleted here, because it is not within a handler. It
3073 // will be deleted in the dtor or in the next EditEntry.
3074 pCurEditedEntry = 0;
3075 return 0;
3078 void SvxIconChoiceCtrl_Impl::StopEntryEditing( bool bCancel )
3080 if( pEdit )
3081 pEdit->StopEditing( bCancel );
3084 SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry( sal_uLong& rPos ) const
3086 if( !GetSelectionCount() )
3087 return 0;
3089 if( (nWinBits & WB_HIGHLIGHTFRAME) && (eSelectionMode == NO_SELECTION) )
3091 rPos = pView->GetEntryListPos( pCurHighlightFrame );
3092 return pCurHighlightFrame;
3095 size_t nCount = aEntries.size();
3096 if( !pHead )
3098 for( size_t nCur = 0; nCur < nCount; nCur++ )
3100 SvxIconChoiceCtrlEntry* pEntry = aEntries[ nCur ];
3101 if( pEntry->IsSelected() )
3103 rPos = nCur;
3104 return pEntry;
3108 else
3110 SvxIconChoiceCtrlEntry* pEntry = pHead;
3111 while( nCount-- )
3113 if( pEntry->IsSelected() )
3115 rPos = GetEntryListPos( pEntry );
3116 return pEntry;
3118 pEntry = pEntry->pflink;
3119 if( nCount && pEntry == pHead )
3121 OSL_FAIL("SvxIconChoiceCtrl_Impl::GetFirstSelectedEntry > infinite loop!");
3122 return 0;
3126 return 0;
3129 void SvxIconChoiceCtrl_Impl::SelectAll( bool bSelect, bool bPaint )
3131 bPaint = true;
3133 size_t nCount = aEntries.size();
3134 for( size_t nCur = 0; nCur < nCount && (bSelect || GetSelectionCount() ); nCur++ )
3136 SvxIconChoiceCtrlEntry* pEntry = aEntries[ nCur ];
3137 SelectEntry( pEntry, bSelect, true, true, bPaint );
3139 nFlags &= (~F_ADD_MODE);
3140 pAnchor = 0;
3143 IcnViewEdit_Impl::IcnViewEdit_Impl( SvtIconChoiceCtrl* pParent, const Point& rPos,
3144 const Size& rSize, const OUString& rData, const Link<>& rNotifyEditEnd ) :
3145 MultiLineEdit( pParent, (pParent->GetStyle() & WB_ICON) ? WB_CENTER : WB_LEFT),
3146 aCallBackHdl( rNotifyEditEnd ),
3147 bCanceled( false ),
3148 bAlreadyInCallback( false ),
3149 bGrabFocus( false )
3151 // FIXME: Outside of Paint Hierarchy
3152 vcl::Font aFont(pParent->GetPointFont(*this));
3153 aFont.SetTransparent( false );
3154 SetControlFont(aFont);
3155 SetControlBackground(aFont.GetFillColor());
3156 SetControlForeground(aFont.GetColor());
3157 SetPosPixel(rPos);
3158 SetSizePixel(CalcAdjustedSize(rSize));
3159 SetText(rData);
3160 SaveValue();
3162 aAccReturn.InsertItem( IMPICNVIEW_ACC_RETURN, vcl::KeyCode(KEY_RETURN) );
3163 aAccEscape.InsertItem( IMPICNVIEW_ACC_ESCAPE, vcl::KeyCode(KEY_ESCAPE) );
3165 aAccReturn.SetActivateHdl( LINK( this, IcnViewEdit_Impl, ReturnHdl_Impl) );
3166 aAccEscape.SetActivateHdl( LINK( this, IcnViewEdit_Impl, EscapeHdl_Impl) );
3167 Application::InsertAccel( &aAccReturn);//, ACCEL_ALWAYS );
3168 Application::InsertAccel( &aAccEscape);//, ACCEL_ALWAYS );
3169 Show();
3170 GrabFocus();
3173 IcnViewEdit_Impl::~IcnViewEdit_Impl()
3175 disposeOnce();
3178 void IcnViewEdit_Impl::dispose()
3180 if( !bAlreadyInCallback )
3182 Application::RemoveAccel( &aAccReturn );
3183 Application::RemoveAccel( &aAccEscape );
3185 MultiLineEdit::dispose();
3188 void IcnViewEdit_Impl::CallCallBackHdl_Impl()
3190 aIdle.Stop();
3191 if ( !bAlreadyInCallback )
3193 bAlreadyInCallback = true;
3194 Application::RemoveAccel( &aAccReturn );
3195 Application::RemoveAccel( &aAccEscape );
3196 Hide();
3197 aCallBackHdl.Call( this );
3201 IMPL_LINK_NOARG_TYPED(IcnViewEdit_Impl, Timeout_Impl, Idle *, void)
3203 CallCallBackHdl_Impl();
3206 IMPL_LINK( IcnViewEdit_Impl, ReturnHdl_Impl, Accelerator*, )
3208 bCanceled = false;
3209 bGrabFocus = true;
3210 CallCallBackHdl_Impl();
3211 return 1;
3214 IMPL_LINK( IcnViewEdit_Impl, EscapeHdl_Impl, Accelerator*, )
3216 bCanceled = true;
3217 bGrabFocus = true;
3218 CallCallBackHdl_Impl();
3219 return 1;
3222 void IcnViewEdit_Impl::KeyInput( const KeyEvent& rKEvt )
3224 vcl::KeyCode aCode = rKEvt.GetKeyCode();
3225 sal_uInt16 nCode = aCode.GetCode();
3227 switch ( nCode )
3229 case KEY_ESCAPE:
3230 bCanceled = true;
3231 bGrabFocus = true;
3232 CallCallBackHdl_Impl();
3233 break;
3235 case KEY_RETURN:
3236 bCanceled = false;
3237 bGrabFocus = true;
3238 CallCallBackHdl_Impl();
3239 break;
3241 default:
3242 MultiLineEdit::KeyInput( rKEvt );
3246 bool IcnViewEdit_Impl::PreNotify( NotifyEvent& rNEvt )
3248 if( rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS )
3250 if ( !bAlreadyInCallback &&
3251 ((!Application::GetFocusWindow()) || !IsChild(Application::GetFocusWindow())))
3253 bCanceled = false;
3254 aIdle.SetPriority(SchedulerPriority::REPAINT);
3255 aIdle.SetIdleHdl(LINK(this,IcnViewEdit_Impl,Timeout_Impl));
3256 aIdle.Start();
3259 return false;
3262 void IcnViewEdit_Impl::StopEditing( bool bCancel )
3264 if ( !bAlreadyInCallback )
3266 bCanceled = bCancel;
3267 CallCallBackHdl_Impl();
3271 sal_uLong SvxIconChoiceCtrl_Impl::GetEntryListPos( SvxIconChoiceCtrlEntry* pEntry ) const
3273 if( !(nFlags & F_ENTRYLISTPOS_VALID ))
3274 const_cast<SvxIconChoiceCtrl_Impl*>(this)->SetListPositions();
3275 return pEntry->nPos;
3278 void SvxIconChoiceCtrl_Impl::InitSettings()
3280 const StyleSettings& rStyleSettings = pView->GetSettings().GetStyleSettings();
3282 // unit (from settings) is Point
3283 vcl::Font aFont( rStyleSettings.GetFieldFont() );
3284 aFont.SetColor( rStyleSettings.GetWindowTextColor() );
3285 pView->SetPointFont( aFont );
3286 SetDefaultTextSize();
3288 pView->SetTextColor( rStyleSettings.GetFieldTextColor() );
3289 pView->SetTextFillColor();
3291 pView->SetBackground( rStyleSettings.GetFieldColor());
3293 long nScrBarSize = rStyleSettings.GetScrollBarSize();
3294 if( nScrBarSize != nHorSBarHeight || nScrBarSize != nVerSBarWidth )
3296 nHorSBarHeight = nScrBarSize;
3297 Size aSize( aHorSBar->GetSizePixel() );
3298 aSize.Height() = nScrBarSize;
3299 aHorSBar->Hide();
3300 aHorSBar->SetSizePixel( aSize );
3302 nVerSBarWidth = nScrBarSize;
3303 aSize = aVerSBar->GetSizePixel();
3304 aSize.Width() = nScrBarSize;
3305 aVerSBar->Hide();
3306 aVerSBar->SetSizePixel( aSize );
3308 Size aOSize( pView->Control::GetOutputSizePixel() );
3309 PositionScrollBars( aOSize.Width(), aOSize.Height() );
3310 AdjustScrollBars();
3314 EntryList_Impl::EntryList_Impl( SvxIconChoiceCtrl_Impl* pOwner ) :
3315 _pOwner( pOwner )
3317 _pOwner->pHead = 0;
3320 EntryList_Impl::~EntryList_Impl()
3322 _pOwner->pHead = 0;
3325 void EntryList_Impl::clear()
3327 _pOwner->pHead = 0;
3328 maIconChoiceCtrlEntryList.clear();
3331 void EntryList_Impl::insert( size_t nPos, SvxIconChoiceCtrlEntry* pEntry )
3333 if ( nPos < maIconChoiceCtrlEntryList.size() ) {
3334 maIconChoiceCtrlEntryList.insert( maIconChoiceCtrlEntryList.begin() + nPos, pEntry );
3335 } else {
3336 maIconChoiceCtrlEntryList.push_back( pEntry );
3338 if( _pOwner->pHead )
3339 pEntry->SetBacklink( _pOwner->pHead->pblink );
3342 void SvxIconChoiceCtrl_Impl::SetPositionMode( SvxIconChoiceCtrlPositionMode eMode )
3344 if( eMode == ePositionMode )
3345 return;
3347 SvxIconChoiceCtrlPositionMode eOldMode = ePositionMode;
3348 ePositionMode = eMode;
3349 size_t nCount = aEntries.size();
3351 if( eOldMode == IcnViewPositionModeAutoArrange )
3353 // when positioning moved entries "hard", there are problems with
3354 // unwanted overlaps, as these entries aren't taken into account in
3355 // Arrange.
3356 if( aEntries.size() )
3357 aAutoArrangeIdle.Start();
3358 return;
3361 if( ePositionMode == IcnViewPositionModeAutoArrange )
3363 for( size_t nCur = 0; nCur < nCount; nCur++ )
3365 SvxIconChoiceCtrlEntry* pEntry = aEntries[ nCur ];
3366 if( pEntry->GetFlags() & SvxIconViewFlags(SvxIconViewFlags::POS_LOCKED | SvxIconViewFlags::POS_MOVED))
3367 SetEntryPos(pEntry, GetEntryBoundRect( pEntry ).TopLeft());
3370 if( aEntries.size() )
3371 aAutoArrangeIdle.Start();
3373 else if( ePositionMode == IcnViewPositionModeAutoAdjust )
3375 AdjustEntryAtGrid( 0 );
3379 void SvxIconChoiceCtrl_Impl::SetEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry,
3380 SvxIconChoiceCtrlEntry* pPredecessor )
3382 if( !IsAutoArrange() )
3383 return;
3385 if( pEntry == pPredecessor )
3386 return;
3388 sal_uLong nPos1 = GetEntryListPos( pEntry );
3389 if( !pHead )
3391 if( pPredecessor )
3393 sal_uLong nPos2 = GetEntryListPos( pPredecessor );
3394 if( nPos1 == (nPos2 + 1) )
3395 return; // is already the predecessor
3397 else if( !nPos1 )
3398 return;
3401 if( !pHead )
3402 InitPredecessors();
3404 if( !pPredecessor && pHead == pEntry )
3405 return; // is already the first one
3407 bool bSetHead = false;
3408 if( !pPredecessor )
3410 bSetHead = true;
3411 pPredecessor = pHead->pblink;
3413 if( pEntry == pHead )
3415 pHead = pHead->pflink;
3416 bSetHead = false;
3418 if( pEntry != pPredecessor )
3420 pEntry->Unlink();
3421 pEntry->SetBacklink( pPredecessor );
3423 if( bSetHead )
3424 pHead = pEntry;
3425 pEntry->SetFlags( SvxIconViewFlags::PRED_SET );
3426 aAutoArrangeIdle.Start();
3429 SvxIconChoiceCtrlEntry* SvxIconChoiceCtrl_Impl::FindEntryPredecessor( SvxIconChoiceCtrlEntry* pEntry,
3430 const Point& rPosTopLeft )
3432 Point aPos( rPosTopLeft ); //TopLeft
3433 Rectangle aCenterRect( CalcBmpRect( pEntry, &aPos ));
3434 Point aNewPos( aCenterRect.Center() );
3435 sal_uLong nGrid = GetPredecessorGrid( aNewPos );
3436 size_t nCount = aEntries.size();
3437 if( nGrid == ULONG_MAX )
3438 return 0;
3439 if( nGrid >= nCount )
3440 nGrid = nCount - 1;
3441 if( !pHead )
3442 return aEntries[ nGrid ];
3444 SvxIconChoiceCtrlEntry* pCur = pHead; // Grid 0
3445 // TODO: go through list from the end if nGrid > nCount/2
3446 for( sal_uLong nCur = 0; nCur < nGrid; nCur++ )
3447 pCur = pCur->pflink;
3449 return pCur;
3452 sal_uLong SvxIconChoiceCtrl_Impl::GetPredecessorGrid( const Point& rPos) const
3454 Point aPos( rPos );
3455 aPos.X() -= LROFFS_WINBORDER;
3456 aPos.Y() -= TBOFFS_WINBORDER;
3457 long nMaxCol = aVirtOutputSize.Width() / nGridDX;
3458 if( nMaxCol )
3459 nMaxCol--;
3460 long nGridX = aPos.X() / nGridDX;
3461 if( nGridX > nMaxCol )
3462 nGridX = nMaxCol;
3463 long nGridY = aPos.Y() / nGridDY;
3464 long nGridsX = aOutputSize.Width() / nGridDX;
3465 sal_uLong nGrid = (nGridY * nGridsX) + nGridX;
3466 long nMiddle = (nGridX * nGridDX) + (nGridDX / 2);
3467 if( rPos.X() < nMiddle )
3469 if( !nGrid )
3470 nGrid = ULONG_MAX;
3471 else
3472 nGrid--;
3474 return nGrid;
3477 bool SvxIconChoiceCtrl_Impl::RequestHelp( const HelpEvent& rHEvt )
3479 if ( !(rHEvt.GetMode() & HelpEventMode::QUICK ) )
3480 return false;
3482 Point aPos( pView->ScreenToOutputPixel(rHEvt.GetMousePosPixel() ) );
3483 aPos -= pView->GetMapMode().GetOrigin();
3484 SvxIconChoiceCtrlEntry* pEntry = GetEntry( aPos, true );
3486 if ( !pEntry )
3487 return false;
3489 OUString sQuickHelpText = pEntry->GetQuickHelpText();
3490 OUString aEntryText( SvtIconChoiceCtrl::GetEntryText( pEntry, false ) );
3491 Rectangle aTextRect( CalcTextRect( pEntry, 0, false, &aEntryText ) );
3492 if ( ( !aTextRect.IsInside( aPos ) || aEntryText.isEmpty() ) && sQuickHelpText.isEmpty() )
3493 return false;
3495 Rectangle aOptTextRect( aTextRect );
3496 aOptTextRect.Bottom() = LONG_MAX;
3497 DrawTextFlags nNewFlags = nCurTextDrawFlags;
3498 nNewFlags &= ~DrawTextFlags( DrawTextFlags::Clip | DrawTextFlags::EndEllipsis );
3499 aOptTextRect = pView->GetTextRect( aOptTextRect, aEntryText, nNewFlags );
3500 if ( aOptTextRect != aTextRect || !sQuickHelpText.isEmpty() )
3502 //aTextRect.Right() = aTextRect.Left() + aRealSize.Width() + 4;
3503 Point aPt( aOptTextRect.TopLeft() );
3504 aPt += pView->GetMapMode().GetOrigin();
3505 aPt = pView->OutputToScreenPixel( aPt );
3506 // subtract border of tooltip help
3507 aPt.Y() -= 1;
3508 aPt.X() -= 3;
3509 aOptTextRect.SetPos( aPt );
3510 OUString sHelpText;
3511 if ( !sQuickHelpText.isEmpty() )
3512 sHelpText = sQuickHelpText;
3513 else
3514 sHelpText = aEntryText;
3515 Help::ShowQuickHelp( (vcl::Window*)pView, aOptTextRect, sHelpText, QuickHelpFlags::Left | QuickHelpFlags::VCenter );
3518 return true;
3521 void SvxIconChoiceCtrl_Impl::ClearColumnList()
3523 if( !pColumns )
3524 return;
3526 pColumns->clear();
3527 DELETEZ(pColumns);
3530 void SvxIconChoiceCtrl_Impl::SetColumn( sal_uInt16 nIndex, const SvxIconChoiceCtrlColumnInfo& rInfo)
3532 if( !pColumns )
3533 pColumns = new SvxIconChoiceCtrlColumnInfoMap;
3535 SvxIconChoiceCtrlColumnInfo* pInfo = new SvxIconChoiceCtrlColumnInfo( rInfo );
3536 pColumns->insert( nIndex, pInfo );
3538 // HACK: Detail mode is not yet fully implemented, this workaround makes it
3539 // fly with a single column
3540 if( !nIndex && (nWinBits & WB_DETAILS) )
3541 nGridDX = pInfo->GetWidth();
3543 if( GetUpdateMode() )
3544 Arrange( IsAutoArrange() );
3547 const SvxIconChoiceCtrlColumnInfo* SvxIconChoiceCtrl_Impl::GetColumn( sal_uInt16 nIndex ) const
3549 if (!pColumns)
3550 return 0;
3551 SvxIconChoiceCtrlColumnInfoMap::const_iterator it = pColumns->find( nIndex );
3552 if( it == pColumns->end() )
3553 return 0;
3554 return it->second;
3557 void SvxIconChoiceCtrl_Impl::DrawHighlightFrame(vcl::RenderContext& rRenderContext, const Rectangle& rBmpRect, bool bHide)
3559 Rectangle aBmpRect(rBmpRect);
3560 long nBorder = 2;
3561 if (aImageSize.Width() < 32)
3562 nBorder = 1;
3563 aBmpRect.Right() += nBorder;
3564 aBmpRect.Left() -= nBorder;
3565 aBmpRect.Bottom() += nBorder;
3566 aBmpRect.Top() -= nBorder;
3568 if (bHide)
3569 pView->Invalidate(aBmpRect);
3570 else
3572 DecorationView aDecoView(&rRenderContext);
3573 DrawHighlightFrameStyle nDecoFlags;
3574 if (bHighlightFramePressed)
3575 nDecoFlags = DrawHighlightFrameStyle::In;
3576 else
3577 nDecoFlags = DrawHighlightFrameStyle::Out;
3578 aDecoView.DrawHighlightFrame(aBmpRect, nDecoFlags, true/*bTestBackground*/);
3582 void SvxIconChoiceCtrl_Impl::SetEntryHighlightFrame( SvxIconChoiceCtrlEntry* pEntry,
3583 bool bKeepHighlightFlags )
3585 if( pEntry == pCurHighlightFrame )
3586 return;
3588 if( !bKeepHighlightFlags )
3589 bHighlightFramePressed = false;
3591 if (pCurHighlightFrame)
3593 Rectangle aInvalidationRect(GetEntryBoundRect(pCurHighlightFrame));
3594 aInvalidationRect.expand(5);
3595 pCurHighlightFrame = nullptr;
3596 pView->Invalidate(aInvalidationRect);
3599 pCurHighlightFrame = pEntry;
3600 if (pEntry)
3602 Rectangle aInvalidationRect(GetEntryBoundRect(pEntry));
3603 aInvalidationRect.expand(5);
3604 pView->Invalidate(aInvalidationRect);
3608 void SvxIconChoiceCtrl_Impl::HideEntryHighlightFrame()
3610 if( !pCurHighlightFrame )
3611 return;
3613 SvxIconChoiceCtrlEntry* pEntry = pCurHighlightFrame;
3614 pCurHighlightFrame = nullptr;
3615 Rectangle aInvalidationRect(GetEntryBoundRect(pEntry));
3616 aInvalidationRect.expand(5);
3617 pView->Invalidate(aInvalidationRect);
3620 void SvxIconChoiceCtrl_Impl::CallSelectHandler( SvxIconChoiceCtrlEntry* )
3622 // When single-click mode is active, the selection handler should be called
3623 // synchronously, as the selection is automatically taken away once the
3624 // mouse cursor doesn't touch the object any more. Else, we might run into
3625 // missing calls to Select if the object is selected from a mouse movement,
3626 // because when starting the timer, the mouse cursor might have already left
3627 // the object.
3628 // In special cases (=>SfxFileDialog!), synchronous calls can be forced via
3629 // WB_NOASYNCSELECTHDL.
3630 if( nWinBits & (WB_NOASYNCSELECTHDL | WB_HIGHLIGHTFRAME) )
3632 pHdlEntry = 0;
3633 pView->ClickIcon();
3634 //pView->Select();
3636 else
3637 aCallSelectHdlIdle.Start();
3640 IMPL_LINK_NOARG_TYPED(SvxIconChoiceCtrl_Impl, CallSelectHdlHdl, Idle *, void)
3642 pHdlEntry = 0;
3643 pView->ClickIcon();
3644 //pView->Select();
3647 void SvxIconChoiceCtrl_Impl::SetOrigin( const Point& rPos )
3649 MapMode aMapMode( pView->GetMapMode() );
3650 aMapMode.SetOrigin( rPos );
3651 pView->SetMapMode( aMapMode );
3654 void SvxIconChoiceCtrl_Impl::CallEventListeners( sal_uLong nEvent, void* pData )
3656 pView->CallImplEventListeners( nEvent, pData );
3660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */