Bump version to 4.3-4
[LibreOffice.git] / sc / source / ui / view / olinewin.cxx
blob162271b7d7381a051d505ab3419a412f486c5de6
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 .
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"
27 #include "dbfunc.hxx"
28 #include "sc.hrc"
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( Window* pParent, ScOutlineMode eMode, ScViewData* pViewData, ScSplitPos eWhich ) :
42 Window( pParent ),
43 mrViewData( *pViewData ),
44 meWhich( eWhich ),
45 mbHoriz( eMode == SC_OUTLINE_HOR ),
46 mbMirrorEntries( false ), // updated in SetHeaderSize
47 mbMirrorLevels( false ), // updated in SetHeaderSize
48 mpSymbols( NULL ),
49 maLineColor( COL_BLACK ),
50 mnHeaderSize( 0 ),
51 mnHeaderPos( 0 ),
52 mnMainFirstPos( 0 ),
53 mnMainLastPos( 0 ),
54 mbMTActive( false ),
55 mbMTPressed( false ),
56 mnFocusLevel( 0 ),
57 mnFocusEntry( SC_OL_HEADERENTRY ),
58 mbDontDrawFocus( false )
60 EnableRTL( false ); // mirroring is done manually
62 InitSettings();
63 maFocusRect.SetEmpty();
64 SetHeaderSize( 0 );
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()
74 // remove the window from task pane list
75 if( SystemWindow* pSysWin = GetSystemWindow() )
76 if( TaskPaneList* pTaskPaneList = pSysWin->GetTaskPaneList() )
77 pTaskPaneList->RemoveWindow( this );
80 void ScOutlineWindow::SetHeaderSize( long nNewSize )
82 bool bLayoutRTL = GetDoc().IsLayoutRTL( GetTab() );
83 mbMirrorEntries = bLayoutRTL && mbHoriz;
84 mbMirrorLevels = bLayoutRTL && !mbHoriz;
86 bool bNew = (nNewSize != mnHeaderSize);
87 mnHeaderSize = nNewSize;
88 mnHeaderPos = mbMirrorEntries ? (GetOutputSizeEntry() - mnHeaderSize) : 0;
89 mnMainFirstPos = mbMirrorEntries ? 0 : mnHeaderSize;
90 mnMainLastPos = GetOutputSizeEntry() - (mbMirrorEntries ? mnHeaderSize : 0) - 1;
91 if ( bNew )
92 Invalidate();
95 long ScOutlineWindow::GetDepthSize() const
97 long nSize = GetLevelCount() * SC_OL_BITMAPSIZE;
98 if ( nSize > 0 )
99 nSize += 2 * SC_OL_POSOFFSET + 1;
100 return nSize;
103 void ScOutlineWindow::ScrollPixel( long nDiff )
105 HideFocus();
106 mbDontDrawFocus = true;
108 long nStart = mnMainFirstPos;
109 long nEnd = mnMainLastPos;
111 long nInvStart, nInvEnd;
112 if (nDiff < 0)
114 nStart -= nDiff;
115 nInvStart = nEnd + nDiff;
116 nInvEnd = nEnd;
118 else
120 nEnd -= nDiff;
121 nInvStart = nStart;
122 nInvEnd = nStart + nDiff;
125 ScrollRel( nDiff, nStart, nEnd );
126 Invalidate( GetRectangle( 0, nInvStart, GetOutputSizeLevel() - 1, nInvEnd ) );
127 Update();
129 // if focus becomes invisible, move it to next visible button
130 ImplMoveFocusToVisible( nDiff < 0 );
132 mbDontDrawFocus = false;
133 ShowFocus();
136 void ScOutlineWindow::ScrollRel( long nEntryDiff, long nEntryStart, long nEntryEnd )
138 Rectangle aRect( GetRectangle( 0, nEntryStart, GetOutputSizeLevel() - 1, nEntryEnd ) );
139 if ( mbHoriz )
140 Scroll( nEntryDiff, 0, aRect );
141 else
142 Scroll( 0, nEntryDiff, aRect );
145 // internal -------------------------------------------------------------------
147 void ScOutlineWindow::InitSettings()
149 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
150 SetBackground( rStyleSettings.GetFaceColor() );
151 maLineColor = rStyleSettings.GetButtonTextColor();
152 mpSymbols = ScGlobal::GetOutlineSymbols();
153 Invalidate();
156 const ScOutlineArray* ScOutlineWindow::GetOutlineArray() const
158 const ScOutlineTable* pTable = GetDoc().GetOutlineTable( GetTab() );
159 if ( !pTable ) return NULL;
160 return mbHoriz ? pTable->GetColArray() : pTable->GetRowArray();
163 const ScOutlineEntry* ScOutlineWindow::GetOutlineEntry( size_t nLevel, size_t nEntry ) const
165 const ScOutlineArray* pArray = GetOutlineArray();
166 return pArray ? pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) ) : NULL;
169 bool ScOutlineWindow::IsHidden( SCCOLROW nColRowIndex ) const
171 return mbHoriz ?
172 GetDoc().ColHidden(static_cast<SCCOL>(nColRowIndex), GetTab()) :
173 GetDoc().RowHidden(static_cast<SCROW>(nColRowIndex), GetTab());
176 bool ScOutlineWindow::IsFiltered( SCCOLROW nColRowIndex ) const
178 // columns cannot be filtered
179 return !mbHoriz && GetDoc().RowFiltered( static_cast<SCROW>(nColRowIndex), GetTab() );
182 bool ScOutlineWindow::IsFirstVisible( SCCOLROW nColRowIndex ) const
184 bool bAllHidden = true;
185 for ( SCCOLROW nPos = 0; (nPos < nColRowIndex) && bAllHidden; ++nPos )
186 bAllHidden = IsHidden( nPos );
187 return bAllHidden;
190 void ScOutlineWindow::GetVisibleRange( SCCOLROW& rnColRowStart, SCCOLROW& rnColRowEnd ) const
192 if ( mbHoriz )
194 rnColRowStart = mrViewData.GetPosX( WhichH( meWhich ) );
195 rnColRowEnd = rnColRowStart + mrViewData.VisibleCellsX( WhichH( meWhich ) );
197 else
199 rnColRowStart = mrViewData.GetPosY( WhichV( meWhich ) );
200 rnColRowEnd = rnColRowStart + mrViewData.VisibleCellsY( WhichV( meWhich ) );
203 // include collapsed columns/rows in front of visible range
204 while ( (rnColRowStart > 0) && IsHidden( rnColRowStart - 1 ) )
205 --rnColRowStart;
208 Point ScOutlineWindow::GetPoint( long nLevelPos, long nEntryPos ) const
210 return mbHoriz ? Point( nEntryPos, nLevelPos ) : Point( nLevelPos, nEntryPos );
213 Rectangle ScOutlineWindow::GetRectangle(
214 long nLevelStart, long nEntryStart, long nLevelEnd, long nEntryEnd ) const
216 return Rectangle( GetPoint( nLevelStart, nEntryStart ), GetPoint( nLevelEnd, nEntryEnd ) );
219 long ScOutlineWindow::GetOutputSizeLevel() const
221 Size aSize( GetOutputSizePixel() );
222 return mbHoriz ? aSize.Height() : aSize.Width();
225 long ScOutlineWindow::GetOutputSizeEntry() const
227 Size aSize( GetOutputSizePixel() );
228 return mbHoriz ? aSize.Width() : aSize.Height();
231 size_t ScOutlineWindow::GetLevelCount() const
233 const ScOutlineArray* pArray = GetOutlineArray();
234 size_t nLevelCount = pArray ? pArray->GetDepth() : 0;
235 return nLevelCount ? (nLevelCount + 1) : 0;
238 long ScOutlineWindow::GetLevelPos( size_t nLevel ) const
240 // #i51970# must always return the *left* edge of the area used by a level
241 long nPos = static_cast< long >( SC_OL_POSOFFSET + nLevel * SC_OL_BITMAPSIZE );
242 return mbMirrorLevels ? (GetOutputSizeLevel() - nPos - SC_OL_BITMAPSIZE) : nPos;
245 size_t ScOutlineWindow::GetLevelFromPos( long nLevelPos ) const
247 if( mbMirrorLevels ) nLevelPos = GetOutputSizeLevel() - nLevelPos - 1;
248 long nStart = SC_OL_POSOFFSET;
249 if ( nLevelPos < nStart ) return SC_OL_NOLEVEL;
250 size_t nLevel = static_cast< size_t >( (nLevelPos - nStart) / SC_OL_BITMAPSIZE );
251 return (nLevel < GetLevelCount()) ? nLevel : SC_OL_NOLEVEL;
254 long ScOutlineWindow::GetColRowPos( SCCOLROW nColRowIndex ) const
256 long nDocPos = mbHoriz ?
257 mrViewData.GetScrPos( static_cast<SCCOL>(nColRowIndex), 0, meWhich, true ).X() :
258 mrViewData.GetScrPos( 0, static_cast<SCROW>(nColRowIndex), meWhich, true ).Y();
259 return mnMainFirstPos + nDocPos;
262 long ScOutlineWindow::GetHeaderEntryPos() const
264 return mnHeaderPos + (mnHeaderSize - SC_OL_BITMAPSIZE) / 2;
267 bool ScOutlineWindow::GetEntryPos(
268 size_t nLevel, size_t nEntry,
269 long& rnStartPos, long& rnEndPos, long& rnImagePos ) const
271 const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
272 if ( !pEntry || !pEntry->IsVisible() )
273 return false;
275 SCCOLROW nStart = pEntry->GetStart();
276 SCCOLROW nEnd = pEntry->GetEnd();
278 long nEntriesSign = mbMirrorEntries ? -1 : 1;
280 // --- common calculation ---
282 rnStartPos = GetColRowPos( nStart );
283 rnEndPos = GetColRowPos( nEnd + 1 );
285 bool bHidden = IsHidden( nStart );
286 rnImagePos = bHidden ?
287 (rnStartPos - ( SC_OL_BITMAPSIZE / 2 ) * nEntriesSign) :
288 rnStartPos + nEntriesSign;
289 long nCenter = (rnStartPos + rnEndPos - SC_OL_BITMAPSIZE * nEntriesSign +
290 ( mbMirrorEntries ? 1 : 0 )) / 2L;
291 rnImagePos = mbMirrorEntries ? std::max( rnImagePos, nCenter ) : std::min( rnImagePos, nCenter );
293 // --- refinements ---
295 // do not cut leftmost/topmost image
296 if ( bHidden && IsFirstVisible( nStart ) )
297 rnImagePos = rnStartPos;
299 // do not cover previous collapsed image
300 bool bDoNoCover = !bHidden && nEntry;
301 const ScOutlineEntry* pPrevEntry = bDoNoCover ? GetOutlineEntry(nLevel, nEntry - 1) : NULL;
302 if (pPrevEntry)
304 SCCOLROW nPrevEnd = pPrevEntry->GetEnd();
305 if ( (nPrevEnd + 1 == nStart) && IsHidden( nPrevEnd ) )
307 if ( IsFirstVisible( pPrevEntry->GetStart() ) )
308 rnStartPos += SC_OL_BITMAPSIZE * nEntriesSign;
309 else
310 rnStartPos += ( SC_OL_BITMAPSIZE / 2 ) * nEntriesSign;
311 rnImagePos = rnStartPos;
315 // restrict rnStartPos...rnEndPos to valid area
316 rnStartPos = std::max( rnStartPos, mnMainFirstPos );
317 rnEndPos = std::max( rnEndPos, mnMainFirstPos );
319 if ( mbMirrorEntries )
320 rnImagePos -= SC_OL_BITMAPSIZE - 1; // start pos aligns with right edge of bitmap
322 // --- all rows filtered? ---
324 bool bVisible = true;
325 if ( !mbHoriz )
327 bVisible = false;
328 for ( SCCOLROW nRow = nStart; (nRow <= nEnd) && !bVisible; ++nRow )
329 bVisible = !IsFiltered( nRow );
331 return bVisible;
334 bool ScOutlineWindow::GetImagePos( size_t nLevel, size_t nEntry, Point& rPos ) const
336 bool bRet = nLevel < GetLevelCount();
337 if ( bRet )
339 long nLevelPos = GetLevelPos( nLevel );
340 if ( nEntry == SC_OL_HEADERENTRY )
341 rPos = GetPoint( nLevelPos, GetHeaderEntryPos() );
342 else
344 long nStartPos, nEndPos, nImagePos;
345 bRet = GetEntryPos( nLevel, nEntry, nStartPos, nEndPos, nImagePos );
346 rPos = GetPoint( nLevelPos, nImagePos );
349 return bRet;
352 bool ScOutlineWindow::IsButtonVisible( size_t nLevel, size_t nEntry ) const
354 bool bRet = false;
355 if ( nEntry == SC_OL_HEADERENTRY )
356 bRet = (mnHeaderSize > 0) && (nLevel < GetLevelCount());
357 else
359 const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
360 if ( pEntry && pEntry->IsVisible() )
362 SCCOLROW nStart, nEnd;
363 GetVisibleRange( nStart, nEnd );
364 bRet = (nStart <= pEntry->GetStart()) && (pEntry->GetStart() <= nEnd);
367 return bRet;
370 bool ScOutlineWindow::ItemHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry, bool& rbButton ) const
372 const ScOutlineArray* pArray = GetOutlineArray();
373 if ( !pArray ) return false;
375 SCCOLROW nStartIndex, nEndIndex;
376 GetVisibleRange( nStartIndex, nEndIndex );
378 size_t nLevel = GetLevelFromPos( mbHoriz ? rPos.Y() : rPos.X() );
379 if ( nLevel == SC_OL_NOLEVEL )
380 return false;
382 long nEntryMousePos = mbHoriz ? rPos.X() : rPos.Y();
384 // --- level buttons ---
386 if ( mnHeaderSize > 0 )
388 long nImagePos = GetHeaderEntryPos();
389 if ( (nImagePos <= nEntryMousePos) && (nEntryMousePos < nImagePos + SC_OL_BITMAPSIZE) )
391 rnLevel = nLevel;
392 rnEntry = SC_OL_HEADERENTRY;
393 rbButton = true;
394 return true;
398 // --- expand/collapse buttons and expanded lines ---
400 // search outline entries backwards
401 size_t nEntry = pArray->GetCount( sal::static_int_cast<sal_uInt16>(nLevel) );
402 while ( nEntry )
404 --nEntry;
406 const ScOutlineEntry* pEntry = pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel),
407 sal::static_int_cast<sal_uInt16>(nEntry) );
408 SCCOLROW nStart = pEntry->GetStart();
409 SCCOLROW nEnd = pEntry->GetEnd();
411 if ( (nEnd >= nStartIndex) && (nStart <= nEndIndex) )
413 long nStartPos, nEndPos, nImagePos;
414 if ( GetEntryPos( nLevel, nEntry, nStartPos, nEndPos, nImagePos ) )
416 rnLevel = nLevel;
417 rnEntry = nEntry;
419 // button?
420 if ( (nStart >= nStartIndex) && (nImagePos <= nEntryMousePos) && (nEntryMousePos < nImagePos + SC_OL_BITMAPSIZE) )
422 rbButton = true;
423 return true;
426 // line?
427 if ( mbMirrorEntries )
428 ::std::swap( nStartPos, nEndPos ); // in RTL mode, nStartPos is the larger value
429 if ( (nStartPos <= nEntryMousePos) && (nEntryMousePos <= nEndPos) )
431 rbButton = false;
432 return true;
438 return false;
441 bool ScOutlineWindow::ButtonHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry ) const
443 bool bButton;
444 bool bRet = ItemHit( rPos, rnLevel, rnEntry, bButton );
445 return bRet && bButton;
448 bool ScOutlineWindow::LineHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry ) const
450 bool bButton;
451 bool bRet = ItemHit( rPos, rnLevel, rnEntry, bButton );
452 return bRet && !bButton;
455 void ScOutlineWindow::DoFunction( size_t nLevel, size_t nEntry ) const
457 ScDBFunc& rFunc = *mrViewData.GetView();
458 if ( nEntry == SC_OL_HEADERENTRY )
459 rFunc.SelectLevel( mbHoriz, sal::static_int_cast<sal_uInt16>(nLevel) );
460 else
462 const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
463 if ( pEntry )
465 if ( pEntry->IsHidden() )
466 rFunc.ShowOutline( mbHoriz, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
467 else
468 rFunc.HideOutline( mbHoriz, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
473 void ScOutlineWindow::DoExpand( size_t nLevel, size_t nEntry ) const
475 const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
476 if ( pEntry && pEntry->IsHidden() )
477 DoFunction( nLevel, nEntry );
480 void ScOutlineWindow::DoCollapse( size_t nLevel, size_t nEntry ) const
482 const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
483 if ( pEntry && !pEntry->IsHidden() )
484 DoFunction( nLevel, nEntry );
487 void ScOutlineWindow::Resize()
489 Window::Resize();
490 SetHeaderSize( mnHeaderSize ); // recalculates header/group positions
491 if ( !IsFocusButtonVisible() )
493 HideFocus();
494 ShowFocus(); // calculates valid position
498 void ScOutlineWindow::DataChanged( const DataChangedEvent& rDCEvt )
500 if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
501 (rDCEvt.GetFlags() & SETTINGS_STYLE) )
503 InitSettings();
504 Invalidate();
506 Window::DataChanged( rDCEvt );
509 // drawing --------------------------------------------------------------------
511 void ScOutlineWindow::SetEntryAreaClipRegion()
513 SetClipRegion( Region(Rectangle(
514 GetPoint( 0, mnMainFirstPos ),
515 GetPoint( GetOutputSizeLevel() - 1, mnMainLastPos ))));
518 void ScOutlineWindow::DrawLineRel(
519 long nLevelStart, long nEntryStart, long nLevelEnd, long nEntryEnd )
521 DrawLine( GetPoint( nLevelStart, nEntryStart ), GetPoint( nLevelEnd, nEntryEnd ) );
524 void ScOutlineWindow::DrawRectRel(
525 long nLevelStart, long nEntryStart, long nLevelEnd, long nEntryEnd )
527 DrawRect( GetRectangle( nLevelStart, nEntryStart, nLevelEnd, nEntryEnd ) );
530 void ScOutlineWindow::DrawImageRel( long nLevelPos, long nEntryPos, sal_uInt16 nId )
532 OSL_ENSURE( mpSymbols, "ScOutlineWindow::DrawImageRel - no images" );
533 const Image& rImage = mpSymbols->GetImage( nId );
534 SetLineColor();
535 SetFillColor( GetBackground().GetColor() );
536 Point aPos( GetPoint( nLevelPos, nEntryPos ) );
537 DrawRect( Rectangle( aPos, rImage.GetSizePixel() ) );
538 DrawImage( aPos, rImage );
541 void ScOutlineWindow::DrawBorderRel( size_t nLevel, size_t nEntry, bool bPressed )
543 Point aPos;
544 if ( GetImagePos( nLevel, nEntry, aPos ) )
546 OSL_ENSURE( mpSymbols, "ScOutlineWindow::DrawBorderRel - no images" );
547 sal_uInt16 nId = bPressed ? SC_OL_IMAGE_PRESSED : SC_OL_IMAGE_NOTPRESSED;
548 bool bClip = (nEntry != SC_OL_HEADERENTRY);
549 if ( bClip )
550 SetEntryAreaClipRegion();
551 DrawImage( aPos, mpSymbols->GetImage( nId ) );
552 if ( bClip )
553 SetClipRegion();
555 mbMTPressed = bPressed;
558 void ScOutlineWindow::ShowFocus()
560 if ( HasFocus() )
562 // first move to a visible position
563 ImplMoveFocusToVisible( true );
565 if ( IsFocusButtonVisible() )
567 Point aPos;
568 if ( GetImagePos( mnFocusLevel, mnFocusEntry, aPos ) )
570 aPos += Point( 1, 1 );
571 maFocusRect = Rectangle( aPos, Size( SC_OL_BITMAPSIZE - 2, SC_OL_BITMAPSIZE - 2 ) );
572 bool bClip = (mnFocusEntry != SC_OL_HEADERENTRY);
573 if ( bClip )
574 SetEntryAreaClipRegion();
575 InvertTracking( maFocusRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW );
576 if ( bClip )
577 SetClipRegion();
583 void ScOutlineWindow::HideFocus()
585 if ( !maFocusRect.IsEmpty() )
587 bool bClip = (mnFocusEntry != SC_OL_HEADERENTRY);
588 if ( bClip )
589 SetEntryAreaClipRegion();
590 InvertTracking( maFocusRect, SHOWTRACK_SMALL | SHOWTRACK_WINDOW );
591 if ( bClip )
592 SetClipRegion();
593 maFocusRect.SetEmpty();
597 void ScOutlineWindow::Paint( const Rectangle& /* rRect */ )
599 long nEntriesSign = mbMirrorEntries ? -1 : 1;
600 long nLevelsSign = mbMirrorLevels ? -1 : 1;
602 Size aSize = GetOutputSizePixel();
603 long nLevelEnd = (mbHoriz ? aSize.Height() : aSize.Width()) - 1;
604 long nEntryEnd = (mbHoriz ? aSize.Width() : aSize.Height()) - 1;
606 SetLineColor( maLineColor );
607 long nBorderPos = mbMirrorLevels ? 0 : nLevelEnd;
608 DrawLineRel( nBorderPos, 0, nBorderPos, nEntryEnd );
610 const ScOutlineArray* pArray = GetOutlineArray();
611 if ( !pArray ) return;
613 size_t nLevelCount = GetLevelCount();
615 // --- draw header images ---
617 if ( mnHeaderSize > 0 )
619 long nEntryPos = GetHeaderEntryPos();
620 for ( size_t nLevel = 0; nLevel < nLevelCount; ++nLevel )
621 DrawImageRel( GetLevelPos( nLevel ), nEntryPos, static_cast< sal_uInt16 >( nLevel + 1 ) );
623 SetLineColor( maLineColor );
624 long nLinePos = mnHeaderPos + (mbMirrorEntries ? 0 : (mnHeaderSize - 1));
625 DrawLineRel( 0, nLinePos, nLevelEnd, nLinePos );
628 // --- draw lines & collapse/expand images ---
630 SetEntryAreaClipRegion();
632 SCCOLROW nStartIndex, nEndIndex;
633 GetVisibleRange( nStartIndex, nEndIndex );
635 for ( size_t nLevel = 0; nLevel + 1 < nLevelCount; ++nLevel )
637 long nLevelPos = GetLevelPos( nLevel );
638 long nEntryPos1 = 0, nEntryPos2 = 0, nImagePos = 0;
640 size_t nEntryCount = pArray->GetCount( sal::static_int_cast<sal_uInt16>(nLevel) );
641 size_t nEntry;
643 // first draw all lines in the current level
644 SetLineColor();
645 SetFillColor( maLineColor );
646 for ( nEntry = 0; nEntry < nEntryCount; ++nEntry )
648 const ScOutlineEntry* pEntry = pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel),
649 sal::static_int_cast<sal_uInt16>(nEntry) );
650 SCCOLROW nStart = pEntry->GetStart();
651 SCCOLROW nEnd = pEntry->GetEnd();
653 // visible range?
654 bool bDraw = (nEnd >= nStartIndex) && (nStart <= nEndIndex);
655 // find output coordinates
656 if ( bDraw )
657 bDraw = GetEntryPos( nLevel, nEntry, nEntryPos1, nEntryPos2, nImagePos );
658 // draw, if not collapsed
659 if ( bDraw && !pEntry->IsHidden() )
661 if ( nStart >= nStartIndex )
662 nEntryPos1 += nEntriesSign;
663 nEntryPos2 -= 2 * nEntriesSign;
664 long nLinePos = nLevelPos;
665 if ( mbMirrorLevels )
666 nLinePos += SC_OL_BITMAPSIZE - 1; // align with right edge of bitmap
667 DrawRectRel( nLinePos, nEntryPos1, nLinePos + nLevelsSign, nEntryPos2 );
669 if ( nEnd <= nEndIndex )
670 DrawRectRel( nLinePos, nEntryPos2 - nEntriesSign,
671 nLinePos + ( SC_OL_BITMAPSIZE / 3 ) * nLevelsSign, nEntryPos2 );
675 // draw all images in the level from last to first
676 nEntry = nEntryCount;
677 while ( nEntry )
679 --nEntry;
681 const ScOutlineEntry* pEntry = pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel),
682 sal::static_int_cast<sal_uInt16>(nEntry) );
683 SCCOLROW nStart = pEntry->GetStart();
685 // visible range?
686 bool bDraw = (nStartIndex <= nStart) && (nStart <= nEndIndex + 1);
687 // find output coordinates
688 if ( bDraw )
689 bDraw = GetEntryPos( nLevel, nEntry, nEntryPos1, nEntryPos2, nImagePos );
690 // draw, if not hidden by higher levels
691 if ( bDraw )
693 sal_uInt16 nImageId = pEntry->IsHidden() ? SC_OL_IMAGE_PLUS : SC_OL_IMAGE_MINUS;
694 DrawImageRel( nLevelPos, nImagePos, nImageId );
699 SetClipRegion();
701 if ( !mbDontDrawFocus )
702 ShowFocus();
705 // focus ----------------------------------------------------------------------
707 /** Increments or decrements a value and wraps at the specified limits.
708 @return true = value wrapped. */
709 static bool lcl_RotateValue( size_t& rnValue, size_t nMin, size_t nMax, bool bForward )
711 OSL_ENSURE( nMin <= nMax, "lcl_RotateValue - invalid range" );
712 OSL_ENSURE( nMax < static_cast< size_t >( -1 ), "lcl_RotateValue - range overflow" );
713 bool bWrap = false;
714 if ( bForward )
716 if ( rnValue < nMax )
717 ++rnValue;
718 else
720 rnValue = nMin;
721 bWrap = true;
724 else
726 if ( rnValue > nMin )
727 --rnValue;
728 else
730 rnValue = nMax;
731 bWrap = true;
734 return bWrap;
737 bool ScOutlineWindow::IsFocusButtonVisible() const
739 return IsButtonVisible( mnFocusLevel, mnFocusEntry );
742 bool ScOutlineWindow::ImplMoveFocusByEntry( bool bForward, bool bFindVisible )
744 const ScOutlineArray* pArray = GetOutlineArray();
745 if ( !pArray )
746 return false;
748 bool bWrapped = false;
749 size_t nEntryCount = pArray->GetCount( sal::static_int_cast<sal_uInt16>(mnFocusLevel) );
750 // #i29530# entry count may be decreased after changing active sheet
751 if( mnFocusEntry >= nEntryCount )
752 mnFocusEntry = SC_OL_HEADERENTRY;
753 size_t nOldEntry = mnFocusEntry;
757 if ( mnFocusEntry == SC_OL_HEADERENTRY )
759 // move from header to first or last entry
760 if ( nEntryCount > 0 )
761 mnFocusEntry = bForward ? 0 : (nEntryCount - 1);
762 /* wrapped, if forward from right header to first entry,
763 or if backward from left header to last entry */
764 // Header and entries are now always in consistent order,
765 // so there's no need to check for mirroring here.
766 if ( !nEntryCount || !bForward )
767 bWrapped = true;
769 else if ( lcl_RotateValue( mnFocusEntry, 0, nEntryCount - 1, bForward ) )
771 // lcl_RotateValue returns true -> wrapped the entry range -> move to header
772 mnFocusEntry = SC_OL_HEADERENTRY;
773 /* wrapped, if forward from last entry to left header,
774 or if backward from first entry to right header */
775 if ( bForward )
776 bWrapped = true;
779 while ( bFindVisible && !IsFocusButtonVisible() && (nOldEntry != mnFocusEntry) );
781 return bWrapped;
784 bool ScOutlineWindow::ImplMoveFocusByLevel( bool bForward )
786 const ScOutlineArray* pArray = GetOutlineArray();
787 if ( !pArray )
788 return false;
790 bool bWrapped = false;
791 size_t nLevelCount = GetLevelCount();
793 if ( mnFocusEntry == SC_OL_HEADERENTRY )
795 if ( nLevelCount > 0 )
796 bWrapped = lcl_RotateValue( mnFocusLevel, 0, nLevelCount - 1, bForward );
798 else
800 const ScOutlineEntry* pEntry = pArray->GetEntry(
801 mnFocusLevel, mnFocusEntry);
803 if ( pEntry )
805 SCCOLROW nStart = pEntry->GetStart();
806 SCCOLROW nEnd = pEntry->GetEnd();
807 size_t nNewLevel = mnFocusLevel;
808 size_t nNewEntry = 0;
810 bool bFound = false;
811 if ( bForward && (mnFocusLevel + 2 < nLevelCount) )
813 // next level -> find first child entry
814 nNewLevel = mnFocusLevel + 1;
815 bFound = pArray->GetEntryIndexInRange(nNewLevel, nStart, nEnd, nNewEntry);
817 else if ( !bForward && (mnFocusLevel > 0) )
819 // previous level -> find parent entry
820 nNewLevel = mnFocusLevel - 1;
821 bFound = pArray->GetEntryIndex(nNewLevel, nStart, nNewEntry);
824 if ( bFound && IsButtonVisible( nNewLevel, nNewEntry ) )
826 mnFocusLevel = nNewLevel;
827 mnFocusEntry = nNewEntry;
832 return bWrapped;
835 bool ScOutlineWindow::ImplMoveFocusByTabOrder( bool bForward, bool bFindVisible )
837 bool bRet = false;
838 size_t nOldLevel = mnFocusLevel;
839 size_t nOldEntry = mnFocusEntry;
843 /* one level up, if backward from left header,
844 or one level down, if forward from right header */
845 if ( (!bForward) && (mnFocusEntry == SC_OL_HEADERENTRY) )
846 bRet |= ImplMoveFocusByLevel( bForward );
847 // move to next/previous entry
848 bool bWrapInLevel = ImplMoveFocusByEntry( bForward, false );
849 bRet |= bWrapInLevel;
850 /* one level up, if wrapped backward to right header,
851 or one level down, if wrapped forward to right header */
852 if ( bForward && bWrapInLevel )
853 bRet |= ImplMoveFocusByLevel( bForward );
855 while ( bFindVisible && !IsFocusButtonVisible() && ((nOldLevel != mnFocusLevel) || (nOldEntry != mnFocusEntry)) );
857 return bRet;
860 void ScOutlineWindow::ImplMoveFocusToVisible( bool bForward )
862 // first try to find an entry in the same level
863 if ( !IsFocusButtonVisible() )
864 ImplMoveFocusByEntry( bForward, true );
865 // then try to find any other entry
866 if ( !IsFocusButtonVisible() )
867 ImplMoveFocusByTabOrder( bForward, true );
870 void ScOutlineWindow::MoveFocusByEntry( bool bForward )
872 HideFocus();
873 ImplMoveFocusByEntry( bForward, true );
874 ShowFocus();
877 void ScOutlineWindow::MoveFocusByLevel( bool bForward )
879 HideFocus();
880 ImplMoveFocusByLevel( bForward );
881 ShowFocus();
884 void ScOutlineWindow::MoveFocusByTabOrder( bool bForward )
886 HideFocus();
887 ImplMoveFocusByTabOrder( bForward, true );
888 ShowFocus();
891 void ScOutlineWindow::GetFocus()
893 Window::GetFocus();
894 ShowFocus();
897 void ScOutlineWindow::LoseFocus()
899 HideFocus();
900 Window::LoseFocus();
904 // mouse ----------------------------------------------------------------------
906 void ScOutlineWindow::StartMouseTracking( size_t nLevel, size_t nEntry )
908 mbMTActive = true;
909 mnMTLevel = nLevel;
910 mnMTEntry = nEntry;
911 DrawBorderRel( nLevel, nEntry, true );
914 void ScOutlineWindow::EndMouseTracking()
916 if ( mbMTPressed )
917 DrawBorderRel( mnMTLevel, mnMTEntry, false );
918 mbMTActive = false;
921 void ScOutlineWindow::MouseMove( const MouseEvent& rMEvt )
923 if ( IsMouseTracking() )
925 size_t nLevel, nEntry;
926 bool bHit = false;
928 if ( ButtonHit( rMEvt.GetPosPixel(), nLevel, nEntry ) )
929 bHit = (nLevel == mnMTLevel) && (nEntry == mnMTEntry);
931 if ( bHit != mbMTPressed )
932 DrawBorderRel( mnMTLevel, mnMTEntry, bHit );
936 void ScOutlineWindow::MouseButtonUp( const MouseEvent& rMEvt )
938 if ( IsMouseTracking() )
940 EndMouseTracking();
942 size_t nLevel, nEntry;
943 if ( ButtonHit( rMEvt.GetPosPixel(), nLevel, nEntry ) )
944 if ( (nLevel == mnMTLevel) && (nEntry == mnMTEntry) )
945 DoFunction( nLevel, nEntry );
949 void ScOutlineWindow::MouseButtonDown( const MouseEvent& rMEvt )
951 size_t nLevel, nEntry;
952 bool bHit = ButtonHit( rMEvt.GetPosPixel(), nLevel, nEntry );
953 if ( bHit )
954 StartMouseTracking( nLevel, nEntry );
955 else if ( rMEvt.GetClicks() == 2 )
957 bHit = LineHit( rMEvt.GetPosPixel(), nLevel, nEntry );
958 if ( bHit )
959 DoFunction( nLevel, nEntry );
962 // if an item has been hit and window is focused, move focus to this item
963 if ( bHit && HasFocus() )
965 HideFocus();
966 mnFocusLevel = nLevel;
967 mnFocusEntry = nEntry;
968 ShowFocus();
973 // keyboard -------------------------------------------------------------------
975 void ScOutlineWindow::KeyInput( const KeyEvent& rKEvt )
977 const KeyCode& rKCode = rKEvt.GetKeyCode();
978 bool bNoMod = !rKCode.GetModifier();
979 bool bShift = (rKCode.GetModifier() == KEY_SHIFT);
980 bool bCtrl = (rKCode.GetModifier() == KEY_MOD1);
982 sal_uInt16 nCode = rKCode.GetCode();
983 bool bUpDownKey = (nCode == KEY_UP) || (nCode == KEY_DOWN);
984 bool bLeftRightKey = (nCode == KEY_LEFT) || (nCode == KEY_RIGHT);
986 // TAB key
987 if ( (nCode == KEY_TAB) && (bNoMod || bShift) )
988 // move forward without SHIFT key
989 MoveFocusByTabOrder( bNoMod ); // TAB uses logical order, regardless of mirroring
991 // LEFT/RIGHT/UP/DOWN keys
992 else if ( bNoMod && (bUpDownKey || bLeftRightKey) )
994 bool bForward = (nCode == KEY_DOWN) || (nCode == KEY_RIGHT);
995 if ( mbHoriz == bLeftRightKey )
996 // move inside level with LEFT/RIGHT in horizontal and with UP/DOWN in vertical
997 MoveFocusByEntry( bForward != mbMirrorEntries );
998 else
999 // move to next/prev level with LEFT/RIGHT in vertical and with UP/DOWN in horizontal
1000 MoveFocusByLevel( bForward != mbMirrorLevels );
1003 // CTRL + number
1004 else if ( bCtrl && (nCode >= KEY_1) && (nCode <= KEY_9) )
1006 size_t nLevel = static_cast< size_t >( nCode - KEY_1 );
1007 if ( nLevel < GetLevelCount() )
1008 DoFunction( nLevel, SC_OL_HEADERENTRY );
1011 // other key codes
1012 else switch ( rKCode.GetFullCode() )
1014 case KEY_ADD: DoExpand( mnFocusLevel, mnFocusEntry ); break;
1015 case KEY_SUBTRACT: DoCollapse( mnFocusLevel, mnFocusEntry ); break;
1016 case KEY_SPACE:
1017 case KEY_RETURN: DoFunction( mnFocusLevel, mnFocusEntry ); break;
1018 default: Window::KeyInput( rKEvt );
1023 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */