1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/svapp.hxx>
21 #include <tools/debug.hxx>
22 #include <iconview.hxx>
23 #include "iconviewimpl.hxx"
25 IconViewImpl::IconViewImpl( SvTreeListBox
* pTreeListBox
, SvTreeList
* pTreeList
, WinBits nWinStyle
)
26 : SvImpLBox( pTreeListBox
, pTreeList
, nWinStyle
)
30 void IconViewImpl::CursorUp()
35 SvTreeListEntry
* pPrevFirstToDraw
= m_pStartEntry
;
37 for(short i
= 0; i
< m_pView
->GetColumnsCount() && pPrevFirstToDraw
; i
++)
38 pPrevFirstToDraw
= m_pView
->PrevVisible(pPrevFirstToDraw
);
40 if( !pPrevFirstToDraw
)
43 m_nFlags
&= ~LBoxFlags::Filling
;
44 long nEntryHeight
= m_pView
->GetEntryHeight();
47 m_pStartEntry
= pPrevFirstToDraw
;
48 tools::Rectangle
aArea( GetVisibleArea() );
49 aArea
.AdjustBottom( -nEntryHeight
);
50 m_pView
->Scroll( 0, nEntryHeight
, aArea
, ScrollFlags::NoChildren
);
53 m_pView
->NotifyScrolled();
56 void IconViewImpl::CursorDown()
61 SvTreeListEntry
* pNextFirstToDraw
= m_pStartEntry
;
63 for(short i
= 0; i
< m_pView
->GetColumnsCount(); i
++)
64 pNextFirstToDraw
= m_pView
->NextVisible(pNextFirstToDraw
);
66 if( pNextFirstToDraw
)
68 m_nFlags
&= ~LBoxFlags::Filling
;
71 m_pStartEntry
= pNextFirstToDraw
;
72 tools::Rectangle
aArea( GetVisibleArea() );
73 m_pView
->Scroll( 0, -(m_pView
->GetEntryHeight()), aArea
, ScrollFlags::NoChildren
);
76 m_pView
->NotifyScrolled();
80 void IconViewImpl::PageDown( sal_uInt16 nDelta
)
82 sal_uInt16 nRealDelta
= nDelta
* m_pView
->GetColumnsCount();
90 SvTreeListEntry
* pNext
= m_pView
->NextVisible(m_pStartEntry
, nRealDelta
);
91 if( pNext
== m_pStartEntry
)
96 m_nFlags
&= ~LBoxFlags::Filling
;
98 m_pStartEntry
= pNext
;
100 if( nRealDelta
>= m_nVisibleCount
)
102 m_pView
->Invalidate( GetVisibleArea() );
107 tools::Rectangle
aArea( GetVisibleArea() );
108 long nScroll
= m_pView
->GetEntryHeight() * static_cast<long>(nRealDelta
);
111 m_pView
->Scroll( 0, nScroll
, aArea
, ScrollFlags::NoChildren
);
113 m_pView
->NotifyScrolled();
119 void IconViewImpl::PageUp( sal_uInt16 nDelta
)
121 sal_uInt16 nRealDelta
= nDelta
* m_pView
->GetColumnsCount();
128 SvTreeListEntry
* pPrev
= m_pView
->PrevVisible(m_pStartEntry
, nRealDelta
);
129 if( pPrev
== m_pStartEntry
)
132 m_nFlags
&= ~LBoxFlags::Filling
;
136 m_pStartEntry
= pPrev
;
137 if( nRealDelta
>= m_nVisibleCount
)
139 m_pView
->Invalidate( GetVisibleArea() );
144 long nEntryHeight
= m_pView
->GetEntryHeight();
145 tools::Rectangle
aArea( GetVisibleArea() );
147 m_pView
->Scroll( 0, nEntryHeight
*nRealDelta
, aArea
, ScrollFlags::NoChildren
);
149 m_pView
->NotifyScrolled();
155 void IconViewImpl::KeyDown( bool bPageDown
)
157 if( !m_aVerSBar
->IsVisible() )
162 nDelta
= m_aVerSBar
->GetPageSize();
166 long nThumbPos
= m_aVerSBar
->GetThumbPos();
171 m_nFlags
&= ~LBoxFlags::Filling
;
174 m_aVerSBar
->SetThumbPos( nThumbPos
+nDelta
);
176 PageDown( static_cast<short>(nDelta
) );
183 void IconViewImpl::KeyUp( bool bPageUp
)
185 if( !m_aVerSBar
->IsVisible() )
190 nDelta
= m_aVerSBar
->GetPageSize();
194 long nThumbPos
= m_aVerSBar
->GetThumbPos();
196 if( nThumbPos
< nDelta
)
202 m_nFlags
&= ~LBoxFlags::Filling
;
205 m_aVerSBar
->SetThumbPos( nThumbPos
- nDelta
);
207 PageUp( static_cast<short>(nDelta
) );
214 long IconViewImpl::GetEntryLine( SvTreeListEntry
* pEntry
) const
217 return -1; // invisible position
219 long nFirstVisPos
= m_pView
->GetVisiblePos( m_pStartEntry
);
220 long nEntryVisPos
= m_pView
->GetVisiblePos( pEntry
);
221 nFirstVisPos
= nEntryVisPos
- nFirstVisPos
;
226 Point
IconViewImpl::GetEntryPosition( SvTreeListEntry
* pEntry
) const
228 const int pos
= m_pView
->GetAbsPos( pEntry
);
230 return Point( ( pos
% m_pView
->GetColumnsCount() ) * m_pView
->GetEntryWidth(),
231 ( pos
/ m_pView
->GetColumnsCount() ) * m_pView
->GetEntryHeight() );
234 SvTreeListEntry
* IconViewImpl::GetClickedEntry( const Point
& rPoint
) const
236 DBG_ASSERT( m_pView
->GetModel(), "IconViewImpl::GetClickedEntry: how can this ever happen?" );
237 if ( !m_pView
->GetModel() )
239 if( m_pView
->GetEntryCount() == 0 || !m_pStartEntry
|| !m_pView
->GetEntryHeight() || !m_pView
->GetEntryWidth())
242 sal_uInt16 nY
= static_cast<sal_uInt16
>(rPoint
.Y() / m_pView
->GetEntryHeight() );
243 sal_uInt16 nX
= static_cast<sal_uInt16
>(rPoint
.X() / m_pView
->GetEntryWidth() );
244 sal_uInt16 nTemp
= nY
* m_pView
->GetColumnsCount() + nX
;
246 SvTreeListEntry
* pEntry
= m_pView
->NextVisible(m_pStartEntry
, nTemp
);
251 bool IconViewImpl::IsEntryInView( SvTreeListEntry
* pEntry
) const
254 if( !m_pView
->IsEntryVisible(pEntry
) )
257 long nY
= GetEntryLine( pEntry
) / m_pView
->GetColumnsCount() * m_pView
->GetEntryHeight();
261 long nMax
= m_nVisibleCount
/ m_pView
->GetColumnsCount() * m_pView
->GetEntryHeight();
265 long nStart
= GetEntryLine( pEntry
) - GetEntryLine( m_pStartEntry
);
269 void IconViewImpl::AdjustScrollBars( Size
& rSize
)
271 long nEntryHeight
= m_pView
->GetEntryHeight();
275 sal_uInt16 nResult
= 0;
277 Size
aOSize( m_pView
->Control::GetOutputSizePixel() );
279 const WinBits nWindowStyle
= m_pView
->GetStyle();
280 bool bVerSBar
= ( nWindowStyle
& WB_VSCROLL
) != 0;
282 // number of entries that are not collapsed
283 sal_uLong nTotalCount
= m_pView
->GetVisibleCount();
285 // number of entries visible within the view
286 m_nVisibleCount
= aOSize
.Height() / nEntryHeight
* m_pView
->GetColumnsCount();
288 long nRows
= ( nTotalCount
/ m_pView
->GetColumnsCount() ) + 1;
290 // do we need a vertical scrollbar?
291 if( bVerSBar
|| nTotalCount
> m_nVisibleCount
)
296 PositionScrollBars( aOSize
, nResult
);
298 // adapt Range, VisibleRange etc.
300 // refresh output size, in case we have to scroll
301 tools::Rectangle aRect
;
302 aRect
.SetSize( aOSize
);
303 m_aSelEng
.SetVisibleArea( aRect
);
305 // vertical scrollbar
306 if( !m_bInVScrollHdl
)
308 m_aVerSBar
->SetPageSize( nTotalCount
);
309 m_aVerSBar
->SetVisibleSize( nTotalCount
- nRows
);
313 m_nFlags
|= LBoxFlags::EndScrollSetVisSize
;
316 if( nResult
& 0x0001 )
324 // returns 0 if position is just past the last entry
325 SvTreeListEntry
* IconViewImpl::GetEntry( const Point
& rPoint
) const
327 if( (m_pView
->GetEntryCount() == 0) || !m_pStartEntry
||
328 (rPoint
.Y() > m_aOutputSize
.Height())
329 || !m_pView
->GetEntryHeight()
330 || !m_pView
->GetEntryWidth())
333 sal_uInt16 nClickedEntry
= static_cast<sal_uInt16
>(rPoint
.Y() / m_pView
->GetEntryHeight() * m_pView
->GetColumnsCount() + rPoint
.X() / m_pView
->GetEntryWidth() );
334 sal_uInt16 nTemp
= nClickedEntry
;
335 SvTreeListEntry
* pEntry
= m_pView
->NextVisible(m_pStartEntry
, nTemp
);
336 if( nTemp
!= nClickedEntry
)
341 void IconViewImpl::SyncVerThumb()
345 long nEntryPos
= m_pView
->GetVisiblePos( m_pStartEntry
);
346 m_aVerSBar
->SetThumbPos( nEntryPos
);
349 m_aVerSBar
->SetThumbPos( 0 );
352 void IconViewImpl::UpdateAll( bool bInvalidateCompleteView
)
354 FindMostRight( nullptr );
355 m_aVerSBar
->SetRange( Range( 0, m_pView
->GetVisibleCount() ) );
359 if( m_bSimpleTravel
&& m_pCursor
&& m_pView
->HasFocus() )
360 m_pView
->Select( m_pCursor
);
362 if( bInvalidateCompleteView
)
363 m_pView
->Invalidate();
365 m_pView
->Invalidate( GetVisibleArea() );
368 void IconViewImpl::Paint(vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
)
370 if (!m_pView
->GetVisibleCount())
373 m_nFlags
|= LBoxFlags::InPaint
;
375 if (m_nFlags
& LBoxFlags::Filling
)
377 SvTreeListEntry
* pFirst
= m_pView
->First();
378 if (pFirst
!= m_pStartEntry
)
381 m_pStartEntry
= m_pView
->First();
382 m_aVerSBar
->SetThumbPos( 0 );
385 m_nCurUserEvent
= Application::PostUserEvent(LINK(this, SvImpLBox
, MyUserEvent
),
386 reinterpret_cast<void*>(1));
393 m_pStartEntry
= m_pView
->First();
396 long nRectHeight
= rRect
.GetHeight();
397 long nRectWidth
= rRect
.GetWidth();
398 long nEntryHeight
= m_pView
->GetEntryHeight();
399 long nEntryWidth
= m_pView
->GetEntryWidth();
401 // calculate area for the entries we want to draw
402 sal_uInt16 nStartId
= static_cast<sal_uInt16
>(rRect
.Top() / nEntryHeight
* m_pView
->GetColumnsCount() + (rRect
.Left() / nEntryWidth
));
403 sal_uInt16 nCount
= static_cast<sal_uInt16
>(( nRectHeight
/ nEntryHeight
+ 1 ) * nRectWidth
/ nEntryWidth
);
404 nCount
+= 2; // don't miss an entry
406 long nY
= nStartId
/ m_pView
->GetColumnsCount() * nEntryHeight
;
408 SvTreeListEntry
* pEntry
= m_pStartEntry
;
409 while (nStartId
&& pEntry
)
411 pEntry
= m_pView
->NextVisible(pEntry
);
415 vcl::Region
aClipRegion(GetClipRegionRect());
417 if (!m_pCursor
&& !mbNoAutoCurEntry
)
419 // do not select if multiselection or explicit set
420 bool bNotSelect
= (m_aSelEng
.GetSelectionMode() == SelectionMode::Multiple
) || ((m_nStyle
& WB_NOINITIALSELECTION
) == WB_NOINITIALSELECTION
);
421 SetCursor(m_pStartEntry
, bNotSelect
);
424 for(sal_uInt16 n
= 0; n
< nCount
&& pEntry
; n
++)
426 static_cast<IconView
*>(m_pView
.get())->PaintEntry(*pEntry
, nX
, nY
, rRenderContext
);
429 if(nX
+ m_pView
->GetEntryWidth() > nEntryWidth
* m_pView
->GetColumnsCount())
434 pEntry
= m_pView
->NextVisible(pEntry
);
437 m_nFlags
&= ~LBoxFlags::DeselectAll
;
438 rRenderContext
.SetClipRegion();
439 m_nFlags
&= ~LBoxFlags::InPaint
;
442 void IconViewImpl::InvalidateEntry( long nId
) const
444 if( m_nFlags
& LBoxFlags::InPaint
)
447 tools::Rectangle
aRect( GetVisibleArea() );
448 long nMaxBottom
= aRect
.Bottom();
449 aRect
.SetTop( nId
/ m_pView
->GetColumnsCount() * m_pView
->GetEntryHeight() );
450 aRect
.SetBottom( aRect
.Top() ); aRect
.AdjustBottom(m_pView
->GetEntryHeight() );
452 if( aRect
.Top() > nMaxBottom
)
454 if( aRect
.Bottom() > nMaxBottom
)
455 aRect
.SetBottom( nMaxBottom
);
456 m_pView
->Invalidate( aRect
);
459 bool IconViewImpl::KeyInput( const KeyEvent
& rKEvt
)
461 const vcl::KeyCode
& rKeyCode
= rKEvt
.GetKeyCode();
463 if( rKeyCode
.IsMod2() )
464 return false; // don't evaluate Alt key
466 m_nFlags
&= ~LBoxFlags::Filling
;
469 m_pCursor
= m_pStartEntry
;
473 sal_uInt16 aCode
= rKeyCode
.GetCode();
475 bool bShift
= rKeyCode
.IsShift();
476 bool bMod1
= rKeyCode
.IsMod1();
478 SvTreeListEntry
* pNewCursor
;
480 bool bHandled
= true;
483 long nColumns
= m_pView
->GetColumnsCount();
488 if( !IsEntryInView( m_pCursor
) )
489 MakeVisible( m_pCursor
);
491 pNewCursor
= m_pCursor
;
494 pNewCursor
= m_pView
->PrevVisible(pNewCursor
);
495 } while( pNewCursor
&& !IsSelectable(pNewCursor
) );
497 // if there is no next entry, take the current one
498 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
501 pNewCursor
= m_pCursor
;
503 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
504 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
505 if( !IsEntryInView( pNewCursor
) )
510 if( !IsEntryInView( m_pCursor
) )
511 MakeVisible( m_pCursor
);
513 pNewCursor
= m_pCursor
;
516 pNewCursor
= m_pView
->NextVisible(pNewCursor
);
517 } while( pNewCursor
&& !IsSelectable(pNewCursor
) );
519 // if there is no next entry, take the current one
520 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
522 if ( !pNewCursor
&& m_pCursor
)
523 pNewCursor
= m_pCursor
;
527 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
528 if( IsEntryInView( pNewCursor
) )
529 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
533 m_pView
->Select( m_pCursor
, false );
535 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
539 KeyDown( false ); // because scrollbar range might still
545 if( !IsEntryInView( m_pCursor
) )
546 MakeVisible( m_pCursor
);
548 pNewCursor
= m_pCursor
;
549 for( i
= 0; i
< nColumns
&& pNewCursor
; i
++)
553 pNewCursor
= m_pView
->PrevVisible(pNewCursor
);
554 } while( pNewCursor
&& !IsSelectable(pNewCursor
) );
557 // if there is no next entry, take the current one
558 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
560 if ( !pNewCursor
&& m_pCursor
)
561 pNewCursor
= m_pCursor
;
565 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
566 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
567 if( !IsEntryInView( pNewCursor
) )
575 if( !IsEntryInView( m_pCursor
) )
576 MakeVisible( m_pCursor
);
578 pNewCursor
= m_pCursor
;
579 for( i
= 0; i
< nColumns
&& pNewCursor
; i
++)
583 pNewCursor
= m_pView
->NextVisible(pNewCursor
);
584 } while( pNewCursor
&& !IsSelectable(pNewCursor
) );
587 // if there is no next entry, take the current one
588 // this ensures that in case of _one_ entry in the list, this entry is selected when pressing
590 if ( !pNewCursor
&& m_pCursor
)
591 pNewCursor
= m_pCursor
;
595 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
596 if( IsEntryInView( pNewCursor
) )
597 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
601 m_pView
->Select( m_pCursor
, false );
603 SetCursor( pNewCursor
, bMod1
); // no selection, when Ctrl is on
607 KeyDown( false ); // because scrollbar range might still
614 m_pView
->aDoubleClickHdl
.Call( m_pView
);
622 pNewCursor
= m_pView
->GetModel()->Last();
624 while( pNewCursor
&& !IsSelectable(pNewCursor
) )
626 pNewCursor
= m_pView
->PrevVisible(pNewCursor
);
629 m_pStartEntry
= pNewCursor
;
631 while( m_pStartEntry
&& m_pView
->GetAbsPos( m_pStartEntry
) % m_pView
->GetColumnsCount() != 0 )
633 m_pStartEntry
= m_pView
->PrevVisible(m_pStartEntry
);
636 if( pNewCursor
&& pNewCursor
!= m_pCursor
)
638 // SelAllDestrAnch( false );
639 m_aSelEng
.CursorPosChanging( bShift
, bMod1
);
640 SetCursor( pNewCursor
);
657 return SvImpLBox::KeyInput( rKEvt
);
662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */