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 <vcl/taskpanelist.hxx>
22 #include <vcl/settings.hxx>
24 #include "olinewin.hxx"
25 #include "olinetab.hxx"
26 #include "document.hxx"
30 const long SC_OL_BITMAPSIZE
= 12;
31 const long SC_OL_POSOFFSET
= 2;
33 const size_t SC_OL_NOLEVEL
= static_cast< size_t >( -1 );
34 const size_t SC_OL_HEADERENTRY
= static_cast< size_t >( -1 );
36 const sal_uInt16 SC_OL_IMAGE_PLUS
= 9;
37 const sal_uInt16 SC_OL_IMAGE_MINUS
= SC_OL_IMAGE_PLUS
+ 1;
38 const sal_uInt16 SC_OL_IMAGE_NOTPRESSED
= SC_OL_IMAGE_MINUS
+ 1;
39 const sal_uInt16 SC_OL_IMAGE_PRESSED
= SC_OL_IMAGE_NOTPRESSED
+ 1;
41 ScOutlineWindow::ScOutlineWindow( vcl::Window
* pParent
, ScOutlineMode eMode
, ScViewData
* pViewData
, ScSplitPos eWhich
) :
43 mrViewData( *pViewData
),
45 mbHoriz( eMode
== SC_OUTLINE_HOR
),
46 mbMirrorEntries( false ), // updated in SetHeaderSize
47 mbMirrorLevels( false ), // updated in SetHeaderSize
49 maLineColor( COL_BLACK
),
57 mnFocusEntry( SC_OL_HEADERENTRY
),
58 mbDontDrawFocus( false )
60 EnableRTL( false ); // mirroring is done manually
63 maFocusRect
.SetEmpty();
66 // insert the window into task pane list for "F6 cycling"
67 if( SystemWindow
* pSysWin
= GetSystemWindow() )
68 if( TaskPaneList
* pTaskPaneList
= pSysWin
->GetTaskPaneList() )
69 pTaskPaneList
->AddWindow( this );
72 ScOutlineWindow::~ScOutlineWindow()
77 void ScOutlineWindow::dispose()
79 // remove the window from task pane list
80 if( SystemWindow
* pSysWin
= GetSystemWindow() )
81 if( TaskPaneList
* pTaskPaneList
= pSysWin
->GetTaskPaneList() )
82 pTaskPaneList
->RemoveWindow( this );
83 vcl::Window::dispose();
86 void ScOutlineWindow::SetHeaderSize( long nNewSize
)
88 bool bLayoutRTL
= GetDoc().IsLayoutRTL( GetTab() );
89 mbMirrorEntries
= bLayoutRTL
&& mbHoriz
;
90 mbMirrorLevels
= bLayoutRTL
&& !mbHoriz
;
92 bool bNew
= (nNewSize
!= mnHeaderSize
);
93 mnHeaderSize
= nNewSize
;
94 mnHeaderPos
= mbMirrorEntries
? (GetOutputSizeEntry() - mnHeaderSize
) : 0;
95 mnMainFirstPos
= mbMirrorEntries
? 0 : mnHeaderSize
;
96 mnMainLastPos
= GetOutputSizeEntry() - (mbMirrorEntries
? mnHeaderSize
: 0) - 1;
101 long ScOutlineWindow::GetDepthSize() const
103 long nSize
= GetLevelCount() * SC_OL_BITMAPSIZE
;
105 nSize
+= 2 * SC_OL_POSOFFSET
+ 1;
109 void ScOutlineWindow::ScrollPixel( long nDiff
)
112 mbDontDrawFocus
= true;
114 long nStart
= mnMainFirstPos
;
115 long nEnd
= mnMainLastPos
;
117 long nInvStart
, nInvEnd
;
121 nInvStart
= nEnd
+ nDiff
;
128 nInvEnd
= nStart
+ nDiff
;
131 ScrollRel( nDiff
, nStart
, nEnd
);
132 Invalidate( GetRectangle( 0, nInvStart
, GetOutputSizeLevel() - 1, nInvEnd
) );
135 // if focus becomes invisible, move it to next visible button
136 ImplMoveFocusToVisible( nDiff
< 0 );
138 mbDontDrawFocus
= false;
142 void ScOutlineWindow::ScrollRel( long nEntryDiff
, long nEntryStart
, long nEntryEnd
)
144 Rectangle
aRect( GetRectangle( 0, nEntryStart
, GetOutputSizeLevel() - 1, nEntryEnd
) );
146 Scroll( nEntryDiff
, 0, aRect
);
148 Scroll( 0, nEntryDiff
, aRect
);
151 // internal -------------------------------------------------------------------
153 void ScOutlineWindow::InitSettings()
155 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
156 SetBackground( rStyleSettings
.GetFaceColor() );
157 maLineColor
= rStyleSettings
.GetButtonTextColor();
158 mpSymbols
= ScGlobal::GetOutlineSymbols();
162 const ScOutlineArray
* ScOutlineWindow::GetOutlineArray() const
164 const ScOutlineTable
* pTable
= GetDoc().GetOutlineTable( GetTab() );
165 if ( !pTable
) return NULL
;
166 return mbHoriz
? &pTable
->GetColArray() : &pTable
->GetRowArray();
169 const ScOutlineEntry
* ScOutlineWindow::GetOutlineEntry( size_t nLevel
, size_t nEntry
) const
171 const ScOutlineArray
* pArray
= GetOutlineArray();
172 return pArray
? pArray
->GetEntry( sal::static_int_cast
<sal_uInt16
>(nLevel
), sal::static_int_cast
<sal_uInt16
>(nEntry
) ) : NULL
;
175 bool ScOutlineWindow::IsHidden( SCCOLROW nColRowIndex
) const
178 GetDoc().ColHidden(static_cast<SCCOL
>(nColRowIndex
), GetTab()) :
179 GetDoc().RowHidden(static_cast<SCROW
>(nColRowIndex
), GetTab());
182 bool ScOutlineWindow::IsFiltered( SCCOLROW nColRowIndex
) const
184 // columns cannot be filtered
185 return !mbHoriz
&& GetDoc().RowFiltered( static_cast<SCROW
>(nColRowIndex
), GetTab() );
188 bool ScOutlineWindow::IsFirstVisible( SCCOLROW nColRowIndex
) const
190 bool bAllHidden
= true;
191 for ( SCCOLROW nPos
= 0; (nPos
< nColRowIndex
) && bAllHidden
; ++nPos
)
192 bAllHidden
= IsHidden( nPos
);
196 void ScOutlineWindow::GetVisibleRange( SCCOLROW
& rnColRowStart
, SCCOLROW
& rnColRowEnd
) const
200 rnColRowStart
= mrViewData
.GetPosX( WhichH( meWhich
) );
201 rnColRowEnd
= rnColRowStart
+ mrViewData
.VisibleCellsX( WhichH( meWhich
) );
205 rnColRowStart
= mrViewData
.GetPosY( WhichV( meWhich
) );
206 rnColRowEnd
= rnColRowStart
+ mrViewData
.VisibleCellsY( WhichV( meWhich
) );
209 // include collapsed columns/rows in front of visible range
210 while ( (rnColRowStart
> 0) && IsHidden( rnColRowStart
- 1 ) )
214 Point
ScOutlineWindow::GetPoint( long nLevelPos
, long nEntryPos
) const
216 return mbHoriz
? Point( nEntryPos
, nLevelPos
) : Point( nLevelPos
, nEntryPos
);
219 Rectangle
ScOutlineWindow::GetRectangle(
220 long nLevelStart
, long nEntryStart
, long nLevelEnd
, long nEntryEnd
) const
222 return Rectangle( GetPoint( nLevelStart
, nEntryStart
), GetPoint( nLevelEnd
, nEntryEnd
) );
225 long ScOutlineWindow::GetOutputSizeLevel() const
227 Size
aSize( GetOutputSizePixel() );
228 return mbHoriz
? aSize
.Height() : aSize
.Width();
231 long ScOutlineWindow::GetOutputSizeEntry() const
233 Size
aSize( GetOutputSizePixel() );
234 return mbHoriz
? aSize
.Width() : aSize
.Height();
237 size_t ScOutlineWindow::GetLevelCount() const
239 const ScOutlineArray
* pArray
= GetOutlineArray();
240 size_t nLevelCount
= pArray
? pArray
->GetDepth() : 0;
241 return nLevelCount
? (nLevelCount
+ 1) : 0;
244 long ScOutlineWindow::GetLevelPos( size_t nLevel
) const
246 // #i51970# must always return the *left* edge of the area used by a level
247 long nPos
= static_cast< long >( SC_OL_POSOFFSET
+ nLevel
* SC_OL_BITMAPSIZE
);
248 return mbMirrorLevels
? (GetOutputSizeLevel() - nPos
- SC_OL_BITMAPSIZE
) : nPos
;
251 size_t ScOutlineWindow::GetLevelFromPos( long nLevelPos
) const
253 if( mbMirrorLevels
) nLevelPos
= GetOutputSizeLevel() - nLevelPos
- 1;
254 long nStart
= SC_OL_POSOFFSET
;
255 if ( nLevelPos
< nStart
) return SC_OL_NOLEVEL
;
256 size_t nLevel
= static_cast< size_t >( (nLevelPos
- nStart
) / SC_OL_BITMAPSIZE
);
257 return (nLevel
< GetLevelCount()) ? nLevel
: SC_OL_NOLEVEL
;
260 long ScOutlineWindow::GetColRowPos( SCCOLROW nColRowIndex
) const
262 long nDocPos
= mbHoriz
?
263 mrViewData
.GetScrPos( static_cast<SCCOL
>(nColRowIndex
), 0, meWhich
, true ).X() :
264 mrViewData
.GetScrPos( 0, static_cast<SCROW
>(nColRowIndex
), meWhich
, true ).Y();
265 return mnMainFirstPos
+ nDocPos
;
268 long ScOutlineWindow::GetHeaderEntryPos() const
270 return mnHeaderPos
+ (mnHeaderSize
- SC_OL_BITMAPSIZE
) / 2;
273 bool ScOutlineWindow::GetEntryPos(
274 size_t nLevel
, size_t nEntry
,
275 long& rnStartPos
, long& rnEndPos
, long& rnImagePos
) const
277 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
278 if ( !pEntry
|| !pEntry
->IsVisible() )
281 SCCOLROW nStart
= pEntry
->GetStart();
282 SCCOLROW nEnd
= pEntry
->GetEnd();
284 long nEntriesSign
= mbMirrorEntries
? -1 : 1;
286 // --- common calculation ---
288 rnStartPos
= GetColRowPos( nStart
);
289 rnEndPos
= GetColRowPos( nEnd
+ 1 );
291 bool bHidden
= IsHidden( nStart
);
292 rnImagePos
= bHidden
?
293 (rnStartPos
- ( SC_OL_BITMAPSIZE
/ 2 ) * nEntriesSign
) :
294 rnStartPos
+ nEntriesSign
;
295 long nCenter
= (rnStartPos
+ rnEndPos
- SC_OL_BITMAPSIZE
* nEntriesSign
+
296 ( mbMirrorEntries
? 1 : 0 )) / 2L;
297 rnImagePos
= mbMirrorEntries
? std::max( rnImagePos
, nCenter
) : std::min( rnImagePos
, nCenter
);
299 // --- refinements ---
301 // do not cut leftmost/topmost image
302 if ( bHidden
&& IsFirstVisible( nStart
) )
303 rnImagePos
= rnStartPos
;
305 // do not cover previous collapsed image
306 bool bDoNoCover
= !bHidden
&& nEntry
;
307 const ScOutlineEntry
* pPrevEntry
= bDoNoCover
? GetOutlineEntry(nLevel
, nEntry
- 1) : NULL
;
310 SCCOLROW nPrevEnd
= pPrevEntry
->GetEnd();
311 if ( (nPrevEnd
+ 1 == nStart
) && IsHidden( nPrevEnd
) )
313 if ( IsFirstVisible( pPrevEntry
->GetStart() ) )
314 rnStartPos
+= SC_OL_BITMAPSIZE
* nEntriesSign
;
316 rnStartPos
+= ( SC_OL_BITMAPSIZE
/ 2 ) * nEntriesSign
;
317 rnImagePos
= rnStartPos
;
321 // restrict rnStartPos...rnEndPos to valid area
322 rnStartPos
= std::max( rnStartPos
, mnMainFirstPos
);
323 rnEndPos
= std::max( rnEndPos
, mnMainFirstPos
);
325 if ( mbMirrorEntries
)
326 rnImagePos
-= SC_OL_BITMAPSIZE
- 1; // start pos aligns with right edge of bitmap
328 // --- all rows filtered? ---
330 bool bVisible
= true;
334 for ( SCCOLROW nRow
= nStart
; (nRow
<= nEnd
) && !bVisible
; ++nRow
)
335 bVisible
= !IsFiltered( nRow
);
340 bool ScOutlineWindow::GetImagePos( size_t nLevel
, size_t nEntry
, Point
& rPos
) const
342 bool bRet
= nLevel
< GetLevelCount();
345 long nLevelPos
= GetLevelPos( nLevel
);
346 if ( nEntry
== SC_OL_HEADERENTRY
)
347 rPos
= GetPoint( nLevelPos
, GetHeaderEntryPos() );
350 long nStartPos
, nEndPos
, nImagePos
;
351 bRet
= GetEntryPos( nLevel
, nEntry
, nStartPos
, nEndPos
, nImagePos
);
352 rPos
= GetPoint( nLevelPos
, nImagePos
);
358 bool ScOutlineWindow::IsButtonVisible( size_t nLevel
, size_t nEntry
) const
361 if ( nEntry
== SC_OL_HEADERENTRY
)
362 bRet
= (mnHeaderSize
> 0) && (nLevel
< GetLevelCount());
365 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
366 if ( pEntry
&& pEntry
->IsVisible() )
368 SCCOLROW nStart
, nEnd
;
369 GetVisibleRange( nStart
, nEnd
);
370 bRet
= (nStart
<= pEntry
->GetStart()) && (pEntry
->GetStart() <= nEnd
);
376 bool ScOutlineWindow::ItemHit( const Point
& rPos
, size_t& rnLevel
, size_t& rnEntry
, bool& rbButton
) const
378 const ScOutlineArray
* pArray
= GetOutlineArray();
379 if ( !pArray
) return false;
381 SCCOLROW nStartIndex
, nEndIndex
;
382 GetVisibleRange( nStartIndex
, nEndIndex
);
384 size_t nLevel
= GetLevelFromPos( mbHoriz
? rPos
.Y() : rPos
.X() );
385 if ( nLevel
== SC_OL_NOLEVEL
)
388 long nEntryMousePos
= mbHoriz
? rPos
.X() : rPos
.Y();
390 // --- level buttons ---
392 if ( mnHeaderSize
> 0 )
394 long nImagePos
= GetHeaderEntryPos();
395 if ( (nImagePos
<= nEntryMousePos
) && (nEntryMousePos
< nImagePos
+ SC_OL_BITMAPSIZE
) )
398 rnEntry
= SC_OL_HEADERENTRY
;
404 // --- expand/collapse buttons and expanded lines ---
406 // search outline entries backwards
407 size_t nEntry
= pArray
->GetCount( sal::static_int_cast
<sal_uInt16
>(nLevel
) );
412 const ScOutlineEntry
* pEntry
= pArray
->GetEntry( sal::static_int_cast
<sal_uInt16
>(nLevel
),
413 sal::static_int_cast
<sal_uInt16
>(nEntry
) );
414 SCCOLROW nStart
= pEntry
->GetStart();
415 SCCOLROW nEnd
= pEntry
->GetEnd();
417 if ( (nEnd
>= nStartIndex
) && (nStart
<= nEndIndex
) )
419 long nStartPos
, nEndPos
, nImagePos
;
420 if ( GetEntryPos( nLevel
, nEntry
, nStartPos
, nEndPos
, nImagePos
) )
426 if ( (nStart
>= nStartIndex
) && (nImagePos
<= nEntryMousePos
) && (nEntryMousePos
< nImagePos
+ SC_OL_BITMAPSIZE
) )
433 if ( mbMirrorEntries
)
434 ::std::swap( nStartPos
, nEndPos
); // in RTL mode, nStartPos is the larger value
435 if ( (nStartPos
<= nEntryMousePos
) && (nEntryMousePos
<= nEndPos
) )
447 bool ScOutlineWindow::ButtonHit( const Point
& rPos
, size_t& rnLevel
, size_t& rnEntry
) const
450 bool bRet
= ItemHit( rPos
, rnLevel
, rnEntry
, bButton
);
451 return bRet
&& bButton
;
454 bool ScOutlineWindow::LineHit( const Point
& rPos
, size_t& rnLevel
, size_t& rnEntry
) const
457 bool bRet
= ItemHit( rPos
, rnLevel
, rnEntry
, bButton
);
458 return bRet
&& !bButton
;
461 void ScOutlineWindow::DoFunction( size_t nLevel
, size_t nEntry
) const
463 ScDBFunc
& rFunc
= *mrViewData
.GetView();
464 if ( nEntry
== SC_OL_HEADERENTRY
)
465 rFunc
.SelectLevel( mbHoriz
, sal::static_int_cast
<sal_uInt16
>(nLevel
) );
468 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
471 if ( pEntry
->IsHidden() )
472 rFunc
.ShowOutline( mbHoriz
, sal::static_int_cast
<sal_uInt16
>(nLevel
), sal::static_int_cast
<sal_uInt16
>(nEntry
) );
474 rFunc
.HideOutline( mbHoriz
, sal::static_int_cast
<sal_uInt16
>(nLevel
), sal::static_int_cast
<sal_uInt16
>(nEntry
) );
479 void ScOutlineWindow::DoExpand( size_t nLevel
, size_t nEntry
) const
481 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
482 if ( pEntry
&& pEntry
->IsHidden() )
483 DoFunction( nLevel
, nEntry
);
486 void ScOutlineWindow::DoCollapse( size_t nLevel
, size_t nEntry
) const
488 const ScOutlineEntry
* pEntry
= GetOutlineEntry( nLevel
, nEntry
);
489 if ( pEntry
&& !pEntry
->IsHidden() )
490 DoFunction( nLevel
, nEntry
);
493 void ScOutlineWindow::Resize()
496 SetHeaderSize( mnHeaderSize
); // recalculates header/group positions
497 if ( !IsFocusButtonVisible() )
500 ShowFocus(); // calculates valid position
504 void ScOutlineWindow::DataChanged( const DataChangedEvent
& rDCEvt
)
506 if ( (rDCEvt
.GetType() == DataChangedEventType::SETTINGS
) &&
507 (rDCEvt
.GetFlags() & AllSettingsFlags::STYLE
) )
512 Window::DataChanged( rDCEvt
);
515 // drawing --------------------------------------------------------------------
517 void ScOutlineWindow::SetEntryAreaClipRegion()
519 SetClipRegion( vcl::Region(Rectangle(
520 GetPoint( 0, mnMainFirstPos
),
521 GetPoint( GetOutputSizeLevel() - 1, mnMainLastPos
))));
524 void ScOutlineWindow::DrawLineRel(
525 long nLevelStart
, long nEntryStart
, long nLevelEnd
, long nEntryEnd
)
527 DrawLine( GetPoint( nLevelStart
, nEntryStart
), GetPoint( nLevelEnd
, nEntryEnd
) );
530 void ScOutlineWindow::DrawRectRel(
531 long nLevelStart
, long nEntryStart
, long nLevelEnd
, long nEntryEnd
)
533 DrawRect( GetRectangle( nLevelStart
, nEntryStart
, nLevelEnd
, nEntryEnd
) );
536 void ScOutlineWindow::DrawImageRel( long nLevelPos
, long nEntryPos
, sal_uInt16 nId
)
538 OSL_ENSURE( mpSymbols
, "ScOutlineWindow::DrawImageRel - no images" );
539 const Image
& rImage
= mpSymbols
->GetImage( nId
);
541 SetFillColor( GetBackground().GetColor() );
542 Point
aPos( GetPoint( nLevelPos
, nEntryPos
) );
543 DrawRect( Rectangle( aPos
, rImage
.GetSizePixel() ) );
544 DrawImage( aPos
, rImage
);
547 void ScOutlineWindow::DrawBorderRel( size_t nLevel
, size_t nEntry
, bool bPressed
)
550 if ( GetImagePos( nLevel
, nEntry
, aPos
) )
552 OSL_ENSURE( mpSymbols
, "ScOutlineWindow::DrawBorderRel - no images" );
553 sal_uInt16 nId
= bPressed
? SC_OL_IMAGE_PRESSED
: SC_OL_IMAGE_NOTPRESSED
;
554 bool bClip
= (nEntry
!= SC_OL_HEADERENTRY
);
556 SetEntryAreaClipRegion();
557 DrawImage( aPos
, mpSymbols
->GetImage( nId
) );
561 mbMTPressed
= bPressed
;
564 void ScOutlineWindow::ShowFocus()
568 // first move to a visible position
569 ImplMoveFocusToVisible( true );
571 if ( IsFocusButtonVisible() )
574 if ( GetImagePos( mnFocusLevel
, mnFocusEntry
, aPos
) )
576 aPos
+= Point( 1, 1 );
577 maFocusRect
= Rectangle( aPos
, Size( SC_OL_BITMAPSIZE
- 2, SC_OL_BITMAPSIZE
- 2 ) );
578 bool bClip
= (mnFocusEntry
!= SC_OL_HEADERENTRY
);
580 SetEntryAreaClipRegion();
581 InvertTracking( maFocusRect
, SHOWTRACK_SMALL
| SHOWTRACK_WINDOW
);
589 void ScOutlineWindow::HideFocus()
591 if ( !maFocusRect
.IsEmpty() )
593 bool bClip
= (mnFocusEntry
!= SC_OL_HEADERENTRY
);
595 SetEntryAreaClipRegion();
596 InvertTracking( maFocusRect
, SHOWTRACK_SMALL
| SHOWTRACK_WINDOW
);
599 maFocusRect
.SetEmpty();
603 void ScOutlineWindow::Paint( vcl::RenderContext
& /*rRenderContext*/, const Rectangle
& /* rRect */ )
605 long nEntriesSign
= mbMirrorEntries
? -1 : 1;
606 long nLevelsSign
= mbMirrorLevels
? -1 : 1;
608 Size aSize
= GetOutputSizePixel();
609 long nLevelEnd
= (mbHoriz
? aSize
.Height() : aSize
.Width()) - 1;
610 long nEntryEnd
= (mbHoriz
? aSize
.Width() : aSize
.Height()) - 1;
612 SetLineColor( maLineColor
);
613 long nBorderPos
= mbMirrorLevels
? 0 : nLevelEnd
;
614 DrawLineRel( nBorderPos
, 0, nBorderPos
, nEntryEnd
);
616 const ScOutlineArray
* pArray
= GetOutlineArray();
617 if ( !pArray
) return;
619 size_t nLevelCount
= GetLevelCount();
621 // --- draw header images ---
623 if ( mnHeaderSize
> 0 )
625 long nEntryPos
= GetHeaderEntryPos();
626 for ( size_t nLevel
= 0; nLevel
< nLevelCount
; ++nLevel
)
627 DrawImageRel( GetLevelPos( nLevel
), nEntryPos
, static_cast< sal_uInt16
>( nLevel
+ 1 ) );
629 SetLineColor( maLineColor
);
630 long nLinePos
= mnHeaderPos
+ (mbMirrorEntries
? 0 : (mnHeaderSize
- 1));
631 DrawLineRel( 0, nLinePos
, nLevelEnd
, nLinePos
);
634 // --- draw lines & collapse/expand images ---
636 SetEntryAreaClipRegion();
638 SCCOLROW nStartIndex
, nEndIndex
;
639 GetVisibleRange( nStartIndex
, nEndIndex
);
641 for ( size_t nLevel
= 0; nLevel
+ 1 < nLevelCount
; ++nLevel
)
643 long nLevelPos
= GetLevelPos( nLevel
);
644 long nEntryPos1
= 0, nEntryPos2
= 0, nImagePos
= 0;
646 size_t nEntryCount
= pArray
->GetCount( sal::static_int_cast
<sal_uInt16
>(nLevel
) );
649 // first draw all lines in the current level
651 SetFillColor( maLineColor
);
652 for ( nEntry
= 0; nEntry
< nEntryCount
; ++nEntry
)
654 const ScOutlineEntry
* pEntry
= pArray
->GetEntry( sal::static_int_cast
<sal_uInt16
>(nLevel
),
655 sal::static_int_cast
<sal_uInt16
>(nEntry
) );
656 SCCOLROW nStart
= pEntry
->GetStart();
657 SCCOLROW nEnd
= pEntry
->GetEnd();
660 bool bDraw
= (nEnd
>= nStartIndex
) && (nStart
<= nEndIndex
);
661 // find output coordinates
663 bDraw
= GetEntryPos( nLevel
, nEntry
, nEntryPos1
, nEntryPos2
, nImagePos
);
664 // draw, if not collapsed
665 if ( bDraw
&& !pEntry
->IsHidden() )
667 if ( nStart
>= nStartIndex
)
668 nEntryPos1
+= nEntriesSign
;
669 nEntryPos2
-= 2 * nEntriesSign
;
670 long nLinePos
= nLevelPos
;
671 if ( mbMirrorLevels
)
672 nLinePos
+= SC_OL_BITMAPSIZE
- 1; // align with right edge of bitmap
673 DrawRectRel( nLinePos
, nEntryPos1
, nLinePos
+ nLevelsSign
, nEntryPos2
);
675 if ( nEnd
<= nEndIndex
)
676 DrawRectRel( nLinePos
, nEntryPos2
- nEntriesSign
,
677 nLinePos
+ ( SC_OL_BITMAPSIZE
/ 3 ) * nLevelsSign
, nEntryPos2
);
681 // draw all images in the level from last to first
682 nEntry
= nEntryCount
;
687 const ScOutlineEntry
* pEntry
= pArray
->GetEntry( sal::static_int_cast
<sal_uInt16
>(nLevel
),
688 sal::static_int_cast
<sal_uInt16
>(nEntry
) );
689 SCCOLROW nStart
= pEntry
->GetStart();
692 bool bDraw
= (nStartIndex
<= nStart
) && (nStart
<= nEndIndex
+ 1);
693 // find output coordinates
695 bDraw
= GetEntryPos( nLevel
, nEntry
, nEntryPos1
, nEntryPos2
, nImagePos
);
696 // draw, if not hidden by higher levels
699 sal_uInt16 nImageId
= pEntry
->IsHidden() ? SC_OL_IMAGE_PLUS
: SC_OL_IMAGE_MINUS
;
700 DrawImageRel( nLevelPos
, nImagePos
, nImageId
);
707 if ( !mbDontDrawFocus
)
711 // focus ----------------------------------------------------------------------
713 /** Increments or decrements a value and wraps at the specified limits.
714 @return true = value wrapped. */
715 static bool lcl_RotateValue( size_t& rnValue
, size_t nMin
, size_t nMax
, bool bForward
)
717 OSL_ENSURE( nMin
<= nMax
, "lcl_RotateValue - invalid range" );
718 OSL_ENSURE( nMax
< static_cast< size_t >( -1 ), "lcl_RotateValue - range overflow" );
722 if ( rnValue
< nMax
)
732 if ( rnValue
> nMin
)
743 bool ScOutlineWindow::IsFocusButtonVisible() const
745 return IsButtonVisible( mnFocusLevel
, mnFocusEntry
);
748 bool ScOutlineWindow::ImplMoveFocusByEntry( bool bForward
, bool bFindVisible
)
750 const ScOutlineArray
* pArray
= GetOutlineArray();
754 bool bWrapped
= false;
755 size_t nEntryCount
= pArray
->GetCount( sal::static_int_cast
<sal_uInt16
>(mnFocusLevel
) );
756 // #i29530# entry count may be decreased after changing active sheet
757 if( mnFocusEntry
>= nEntryCount
)
758 mnFocusEntry
= SC_OL_HEADERENTRY
;
759 size_t nOldEntry
= mnFocusEntry
;
763 if ( mnFocusEntry
== SC_OL_HEADERENTRY
)
765 // move from header to first or last entry
766 if ( nEntryCount
> 0 )
767 mnFocusEntry
= bForward
? 0 : (nEntryCount
- 1);
768 /* wrapped, if forward from right header to first entry,
769 or if backward from left header to last entry */
770 // Header and entries are now always in consistent order,
771 // so there's no need to check for mirroring here.
772 if ( !nEntryCount
|| !bForward
)
775 else if ( lcl_RotateValue( mnFocusEntry
, 0, nEntryCount
- 1, bForward
) )
777 // lcl_RotateValue returns true -> wrapped the entry range -> move to header
778 mnFocusEntry
= SC_OL_HEADERENTRY
;
779 /* wrapped, if forward from last entry to left header,
780 or if backward from first entry to right header */
785 while ( bFindVisible
&& !IsFocusButtonVisible() && (nOldEntry
!= mnFocusEntry
) );
790 bool ScOutlineWindow::ImplMoveFocusByLevel( bool bForward
)
792 const ScOutlineArray
* pArray
= GetOutlineArray();
796 bool bWrapped
= false;
797 size_t nLevelCount
= GetLevelCount();
799 if ( mnFocusEntry
== SC_OL_HEADERENTRY
)
801 if ( nLevelCount
> 0 )
802 bWrapped
= lcl_RotateValue( mnFocusLevel
, 0, nLevelCount
- 1, bForward
);
806 const ScOutlineEntry
* pEntry
= pArray
->GetEntry(
807 mnFocusLevel
, mnFocusEntry
);
811 SCCOLROW nStart
= pEntry
->GetStart();
812 SCCOLROW nEnd
= pEntry
->GetEnd();
813 size_t nNewLevel
= mnFocusLevel
;
814 size_t nNewEntry
= 0;
817 if ( bForward
&& (mnFocusLevel
+ 2 < nLevelCount
) )
819 // next level -> find first child entry
820 nNewLevel
= mnFocusLevel
+ 1;
821 bFound
= pArray
->GetEntryIndexInRange(nNewLevel
, nStart
, nEnd
, nNewEntry
);
823 else if ( !bForward
&& (mnFocusLevel
> 0) )
825 // previous level -> find parent entry
826 nNewLevel
= mnFocusLevel
- 1;
827 bFound
= pArray
->GetEntryIndex(nNewLevel
, nStart
, nNewEntry
);
830 if ( bFound
&& IsButtonVisible( nNewLevel
, nNewEntry
) )
832 mnFocusLevel
= nNewLevel
;
833 mnFocusEntry
= nNewEntry
;
841 bool ScOutlineWindow::ImplMoveFocusByTabOrder( bool bForward
, bool bFindVisible
)
844 size_t nOldLevel
= mnFocusLevel
;
845 size_t nOldEntry
= mnFocusEntry
;
849 /* one level up, if backward from left header,
850 or one level down, if forward from right header */
851 if ( (!bForward
) && (mnFocusEntry
== SC_OL_HEADERENTRY
) )
852 bRet
|= ImplMoveFocusByLevel( bForward
);
853 // move to next/previous entry
854 bool bWrapInLevel
= ImplMoveFocusByEntry( bForward
, false );
855 bRet
|= bWrapInLevel
;
856 /* one level up, if wrapped backward to right header,
857 or one level down, if wrapped forward to right header */
858 if ( bForward
&& bWrapInLevel
)
859 bRet
|= ImplMoveFocusByLevel( bForward
);
861 while ( bFindVisible
&& !IsFocusButtonVisible() && ((nOldLevel
!= mnFocusLevel
) || (nOldEntry
!= mnFocusEntry
)) );
866 void ScOutlineWindow::ImplMoveFocusToVisible( bool bForward
)
868 // first try to find an entry in the same level
869 if ( !IsFocusButtonVisible() )
870 ImplMoveFocusByEntry( bForward
, true );
871 // then try to find any other entry
872 if ( !IsFocusButtonVisible() )
873 ImplMoveFocusByTabOrder( bForward
, true );
876 void ScOutlineWindow::MoveFocusByEntry( bool bForward
)
879 ImplMoveFocusByEntry( bForward
, true );
883 void ScOutlineWindow::MoveFocusByLevel( bool bForward
)
886 ImplMoveFocusByLevel( bForward
);
890 void ScOutlineWindow::MoveFocusByTabOrder( bool bForward
)
893 ImplMoveFocusByTabOrder( bForward
, true );
897 void ScOutlineWindow::GetFocus()
903 void ScOutlineWindow::LoseFocus()
909 // mouse ----------------------------------------------------------------------
911 void ScOutlineWindow::StartMouseTracking( size_t nLevel
, size_t nEntry
)
916 DrawBorderRel( nLevel
, nEntry
, true );
919 void ScOutlineWindow::EndMouseTracking()
922 DrawBorderRel( mnMTLevel
, mnMTEntry
, false );
926 void ScOutlineWindow::MouseMove( const MouseEvent
& rMEvt
)
928 if ( IsMouseTracking() )
930 size_t nLevel
, nEntry
;
933 if ( ButtonHit( rMEvt
.GetPosPixel(), nLevel
, nEntry
) )
934 bHit
= (nLevel
== mnMTLevel
) && (nEntry
== mnMTEntry
);
936 if ( bHit
!= mbMTPressed
)
937 DrawBorderRel( mnMTLevel
, mnMTEntry
, bHit
);
941 void ScOutlineWindow::MouseButtonUp( const MouseEvent
& rMEvt
)
943 if ( IsMouseTracking() )
947 size_t nLevel
, nEntry
;
948 if ( ButtonHit( rMEvt
.GetPosPixel(), nLevel
, nEntry
) )
949 if ( (nLevel
== mnMTLevel
) && (nEntry
== mnMTEntry
) )
950 DoFunction( nLevel
, nEntry
);
954 void ScOutlineWindow::MouseButtonDown( const MouseEvent
& rMEvt
)
956 size_t nLevel
, nEntry
;
957 bool bHit
= ButtonHit( rMEvt
.GetPosPixel(), nLevel
, nEntry
);
959 StartMouseTracking( nLevel
, nEntry
);
960 else if ( rMEvt
.GetClicks() == 2 )
962 bHit
= LineHit( rMEvt
.GetPosPixel(), nLevel
, nEntry
);
964 DoFunction( nLevel
, nEntry
);
967 // if an item has been hit and window is focused, move focus to this item
968 if ( bHit
&& HasFocus() )
971 mnFocusLevel
= nLevel
;
972 mnFocusEntry
= nEntry
;
977 // keyboard -------------------------------------------------------------------
979 void ScOutlineWindow::KeyInput( const KeyEvent
& rKEvt
)
981 const vcl::KeyCode
& rKCode
= rKEvt
.GetKeyCode();
982 bool bNoMod
= !rKCode
.GetModifier();
983 bool bShift
= (rKCode
.GetModifier() == KEY_SHIFT
);
984 bool bCtrl
= (rKCode
.GetModifier() == KEY_MOD1
);
986 sal_uInt16 nCode
= rKCode
.GetCode();
987 bool bUpDownKey
= (nCode
== KEY_UP
) || (nCode
== KEY_DOWN
);
988 bool bLeftRightKey
= (nCode
== KEY_LEFT
) || (nCode
== KEY_RIGHT
);
991 if ( (nCode
== KEY_TAB
) && (bNoMod
|| bShift
) )
992 // move forward without SHIFT key
993 MoveFocusByTabOrder( bNoMod
); // TAB uses logical order, regardless of mirroring
995 // LEFT/RIGHT/UP/DOWN keys
996 else if ( bNoMod
&& (bUpDownKey
|| bLeftRightKey
) )
998 bool bForward
= (nCode
== KEY_DOWN
) || (nCode
== KEY_RIGHT
);
999 if ( mbHoriz
== bLeftRightKey
)
1000 // move inside level with LEFT/RIGHT in horizontal and with UP/DOWN in vertical
1001 MoveFocusByEntry( bForward
!= mbMirrorEntries
);
1003 // move to next/prev level with LEFT/RIGHT in vertical and with UP/DOWN in horizontal
1004 MoveFocusByLevel( bForward
!= mbMirrorLevels
);
1008 else if ( bCtrl
&& (nCode
>= KEY_1
) && (nCode
<= KEY_9
) )
1010 size_t nLevel
= static_cast< size_t >( nCode
- KEY_1
);
1011 if ( nLevel
< GetLevelCount() )
1012 DoFunction( nLevel
, SC_OL_HEADERENTRY
);
1016 else switch ( rKCode
.GetFullCode() )
1018 case KEY_ADD
: DoExpand( mnFocusLevel
, mnFocusEntry
); break;
1019 case KEY_SUBTRACT
: DoCollapse( mnFocusLevel
, mnFocusEntry
); break;
1021 case KEY_RETURN
: DoFunction( mnFocusLevel
, mnFocusEntry
); break;
1022 default: Window::KeyInput( rKEvt
);
1026 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */