fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / svtools / source / brwbox / brwbox2.cxx
blob1ffc334f76db1837cca0a9984828ddb34cad0131
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 <tools/debug.hxx>
21 #include <svtools/brwbox.hxx>
22 #include "datwin.hxx"
23 #include <svtools/colorcfg.hxx>
24 #include <vcl/salgtype.hxx>
25 #include <vcl/settings.hxx>
27 #include <tools/multisel.hxx>
28 #include <tools/fract.hxx>
29 #include <algorithm>
31 using namespace ::com::sun::star::datatransfer;
33 #define getDataWindow() (static_cast<BrowserDataWin*>(pDataWin.get()))
37 void BrowseBox::StartDrag( sal_Int8 /* _nAction */, const Point& /* _rPosPixel */ )
39 // not interested in this event
44 sal_Int8 BrowseBox::AcceptDrop( const AcceptDropEvent& _rEvt )
46 BrowserDataWin* pDataWindow = static_cast<BrowserDataWin*>(pDataWin.get());
47 AcceptDropEvent aTransformed( _rEvt );
48 aTransformed.maPosPixel = pDataWindow->ScreenToOutputPixel( OutputToScreenPixel( _rEvt.maPosPixel ) );
49 return pDataWindow->AcceptDrop( aTransformed );
54 sal_Int8 BrowseBox::ExecuteDrop( const ExecuteDropEvent& _rEvt )
56 BrowserDataWin* pDataWindow = static_cast<BrowserDataWin*>(pDataWin.get());
57 ExecuteDropEvent aTransformed( _rEvt );
58 aTransformed.maPosPixel = pDataWindow->ScreenToOutputPixel( OutputToScreenPixel( _rEvt.maPosPixel ) );
59 return pDataWindow->ExecuteDrop( aTransformed );
64 sal_Int8 BrowseBox::AcceptDrop( const BrowserAcceptDropEvent& )
66 // not interested in this event
67 return DND_ACTION_NONE;
72 sal_Int8 BrowseBox::ExecuteDrop( const BrowserExecuteDropEvent& )
74 // not interested in this event
75 return DND_ACTION_NONE;
80 void* BrowseBox::implGetDataFlavors() const
82 if (static_cast<BrowserDataWin*>(pDataWin.get())->bCallingDropCallback)
83 return &static_cast<BrowserDataWin*>(pDataWin.get())->GetDataFlavorExVector();
84 return &GetDataFlavorExVector();
89 bool BrowseBox::IsDropFormatSupported( SotClipboardFormatId _nFormat )
91 if ( static_cast< BrowserDataWin* >( pDataWin.get() )->bCallingDropCallback )
92 return static_cast< BrowserDataWin* >( pDataWin.get() )->IsDropFormatSupported( _nFormat );
94 return DropTargetHelper::IsDropFormatSupported( _nFormat );
99 bool BrowseBox::IsDropFormatSupported( SotClipboardFormatId _nFormat ) const
101 return const_cast< BrowseBox* >( this )->IsDropFormatSupported( _nFormat );
106 bool BrowseBox::IsDropFormatSupported( const DataFlavor& _rFlavor )
108 if ( static_cast< BrowserDataWin* >( pDataWin.get() )->bCallingDropCallback )
109 return static_cast< BrowserDataWin* >( pDataWin.get() )->IsDropFormatSupported( _rFlavor );
111 return DropTargetHelper::IsDropFormatSupported( _rFlavor );
116 bool BrowseBox::IsDropFormatSupported( const DataFlavor& _rFlavor ) const
118 return const_cast< BrowseBox* >( this )->IsDropFormatSupported( _rFlavor );
123 void BrowseBox::Command( const CommandEvent& rEvt )
125 if ( !getDataWindow()->bInCommand )
126 Control::Command( rEvt );
131 void BrowseBox::StateChanged( StateChangedType nStateChange )
133 Control::StateChanged( nStateChange );
135 if ( StateChangedType::Mirroring == nStateChange )
137 getDataWindow()->EnableRTL( IsRTLEnabled() );
139 HeaderBar* pHeaderBar = getDataWindow()->pHeaderBar;
140 if ( pHeaderBar )
141 pHeaderBar->EnableRTL( IsRTLEnabled() );
142 aHScroll->EnableRTL( IsRTLEnabled() );
143 if( pVScroll )
144 pVScroll->EnableRTL( IsRTLEnabled() );
145 Resize();
147 else if ( StateChangedType::InitShow == nStateChange )
149 bBootstrapped = true; // must be set first!
151 Resize();
152 if ( bMultiSelection )
153 uRow.pSel->SetTotalRange( Range( 0, nRowCount - 1 ) );
154 if ( nRowCount == 0 )
155 nCurRow = BROWSER_ENDOFSELECTION;
156 else if ( nCurRow == BROWSER_ENDOFSELECTION )
157 nCurRow = 0;
160 if ( HasFocus() )
162 bSelectionIsVisible = true;
163 bHasFocus = true;
165 UpdateScrollbars();
166 AutoSizeLastColumn();
167 CursorMoved();
169 else if (StateChangedType::Zoom == nStateChange)
171 pDataWin->SetZoom(GetZoom());
172 HeaderBar* pHeaderBar = getDataWindow()->pHeaderBar;
173 if (pHeaderBar)
174 pHeaderBar->SetZoom(GetZoom());
176 // let the columns calculate their new widths and adjust the header bar
177 for ( size_t nPos = 0; nPos < pCols->size(); ++nPos )
179 (*pCols)[ nPos ]->ZoomChanged(GetZoom());
180 if ( pHeaderBar )
181 pHeaderBar->SetItemSize( (*pCols)[ nPos ]->GetId(), (*pCols)[ nPos ]->Width() );
184 // all our controls have to be repositioned
185 Resize();
187 else if (StateChangedType::Enable == nStateChange)
189 // do we have a handle column?
190 bool bHandleCol = !pCols->empty() && (0 == (*pCols)[ 0 ]->GetId());
191 // do we have a header bar?
192 bool bHeaderBar = (NULL != static_cast<BrowserDataWin&>(GetDataWindow()).pHeaderBar.get());
194 if ( nTitleLines
195 && ( !bHeaderBar
196 || bHandleCol
199 // we draw the text in our header bar in a color dependent on the enabled state. So if this state changed
200 // -> redraw
201 Invalidate(Rectangle(Point(0, 0), Size(GetOutputSizePixel().Width(), GetTitleHeight() - 1)));
207 void BrowseBox::Select()
213 void BrowseBox::DoubleClick( const BrowserMouseEvent & )
219 long BrowseBox::QueryMinimumRowHeight()
221 return CalcZoom( 5 );
226 void BrowseBox::ImplStartTracking()
232 void BrowseBox::ImplTracking()
238 void BrowseBox::ImplEndTracking()
244 void BrowseBox::RowHeightChanged()
250 long BrowseBox::QueryColumnResize( sal_uInt16, long nWidth )
252 return nWidth;
257 void BrowseBox::ColumnResized( sal_uInt16 )
263 void BrowseBox::ColumnMoved( sal_uInt16 )
269 void BrowseBox::StartScroll()
271 DoHideCursor( "StartScroll" );
276 void BrowseBox::EndScroll()
278 UpdateScrollbars();
279 AutoSizeLastColumn();
280 DoShowCursor( "EndScroll" );
285 void BrowseBox::ToggleSelection( bool bForce )
288 // selection highlight-toggling allowed?
289 if ( bHideSelect )
290 return;
291 if ( !bForce &&
292 ( bNotToggleSel || !IsUpdateMode() || !bSelectionIsVisible ) )
293 return;
295 // only highlight painted areas!
296 bNotToggleSel = true;
297 if ( false && !getDataWindow()->bInPaint )
298 pDataWin->Update();
300 // accumulate areas of rows to highlight
301 RectangleList aHighlightList;
302 long nLastRowInRect = 0; // for the CFront
304 // don't highlight handle column
305 BrowserColumn *pFirstCol = pCols->empty() ? NULL : (*pCols)[ 0 ];
306 long nOfsX = (!pFirstCol || pFirstCol->GetId()) ? 0 : pFirstCol->Width();
308 // accumulate old row selection
309 long nBottomRow = nTopRow +
310 pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight();
311 if ( nBottomRow > GetRowCount() && GetRowCount() )
312 nBottomRow = GetRowCount();
313 for ( long nRow = bMultiSelection ? uRow.pSel->FirstSelected() : uRow.nSel;
314 nRow != BROWSER_ENDOFSELECTION && nRow <= nBottomRow;
315 nRow = bMultiSelection ? uRow.pSel->NextSelected() : BROWSER_ENDOFSELECTION )
317 if ( nRow < nTopRow )
318 continue;
320 Rectangle aAddRect(
321 Point( nOfsX, (nRow-nTopRow)*GetDataRowHeight() ),
322 Size( pDataWin->GetSizePixel().Width(), GetDataRowHeight() ) );
323 if ( aHighlightList.size() && nLastRowInRect == ( nRow - 1 ) )
324 aHighlightList[ 0 ]->Union( aAddRect );
325 else
326 aHighlightList.insert( aHighlightList.begin(), new Rectangle( aAddRect ) );
327 nLastRowInRect = nRow;
330 // unhighlight the old selection (if any)
331 for ( size_t i = aHighlightList.size(); i > 0; )
333 Rectangle *pRect = aHighlightList[ --i ];
334 pDataWin->Invalidate( *pRect );
335 delete pRect;
337 aHighlightList.clear();
339 // unhighlight old column selection (if any)
340 for ( long nColId = pColSel ? pColSel->FirstSelected() : BROWSER_ENDOFSELECTION;
341 nColId != BROWSER_ENDOFSELECTION;
342 nColId = pColSel->NextSelected() )
344 Rectangle aRect( GetFieldRectPixel(nCurRow,
345 (*pCols)[ nColId ]->GetId(),
346 false ) );
347 aRect.Left() -= MIN_COLUMNWIDTH;
348 aRect.Right() += MIN_COLUMNWIDTH;
349 aRect.Top() = 0;
350 aRect.Bottom() = pDataWin->GetOutputSizePixel().Height();
351 pDataWin->Invalidate( aRect );
354 bNotToggleSel = false;
359 void BrowseBox::DrawCursor()
361 bool bReallyHide = false;
362 if ( bHideCursor == TRISTATE_INDET )
364 if ( !GetSelectRowCount() && !GetSelectColumnCount() )
365 bReallyHide = true;
367 else if ( bHideCursor == TRISTATE_TRUE )
369 bReallyHide = true;
372 bReallyHide |= !bSelectionIsVisible || !IsUpdateMode() || bScrolling || nCurRow < 0;
374 if (PaintCursorIfHiddenOnce())
375 bReallyHide |= ( GetCursorHideCount() > 1 );
376 else
377 bReallyHide |= ( GetCursorHideCount() > 0 );
379 // no cursor on handle column
380 if ( nCurColId == HandleColumnId )
381 nCurColId = GetColumnId(1);
383 // calculate cursor rectangle
384 Rectangle aCursor;
385 if ( bColumnCursor )
387 aCursor = GetFieldRectPixel( nCurRow, nCurColId, false );
388 aCursor.Left() -= MIN_COLUMNWIDTH;
389 aCursor.Right() += 1;
390 aCursor.Bottom() += 1;
392 else
393 aCursor = Rectangle(
394 Point( ( !pCols->empty() && (*pCols)[ 0 ]->GetId() == 0 ) ?
395 (*pCols)[ 0 ]->Width() : 0,
396 (nCurRow - nTopRow) * GetDataRowHeight() + 1 ),
397 Size( pDataWin->GetOutputSizePixel().Width() + 1,
398 GetDataRowHeight() - 2 ) );
399 if ( bHLines )
401 if ( !bMultiSelection )
402 --aCursor.Top();
403 --aCursor.Bottom();
406 if (m_aCursorColor == COL_TRANSPARENT)
408 // on these platforms, the StarView focus works correctly
409 if ( bReallyHide )
410 static_cast<Control*>(pDataWin.get())->HideFocus();
411 else
412 static_cast<Control*>(pDataWin.get())->ShowFocus( aCursor );
414 else
416 Color rCol = bReallyHide ? pDataWin->GetFillColor() : m_aCursorColor;
417 Color aOldFillColor = pDataWin->GetFillColor();
418 Color aOldLineColor = pDataWin->GetLineColor();
419 pDataWin->SetFillColor();
420 pDataWin->SetLineColor( rCol );
421 pDataWin->DrawRect( aCursor );
422 pDataWin->SetLineColor( aOldLineColor );
423 pDataWin->SetFillColor( aOldFillColor );
429 sal_uLong BrowseBox::GetColumnWidth( sal_uInt16 nId ) const
432 sal_uInt16 nItemPos = GetColumnPos( nId );
433 if ( nItemPos >= pCols->size() )
434 return 0;
435 return (*pCols)[ nItemPos ]->Width();
440 sal_uInt16 BrowseBox::GetColumnId( sal_uInt16 nPos ) const
443 if ( nPos >= pCols->size() )
444 return BROWSER_INVALIDID;
445 return (*pCols)[ nPos ]->GetId();
450 sal_uInt16 BrowseBox::GetColumnPos( sal_uInt16 nId ) const
453 for ( sal_uInt16 nPos = 0; nPos < pCols->size(); ++nPos )
454 if ( (*pCols)[ nPos ]->GetId() == nId )
455 return nPos;
456 return BROWSER_INVALIDID;
461 bool BrowseBox::IsFrozen( sal_uInt16 nColumnId ) const
464 for ( size_t nPos = 0; nPos < pCols->size(); ++nPos )
465 if ( (*pCols)[ nPos ]->GetId() == nColumnId )
466 return (*pCols)[ nPos ]->IsFrozen();
467 return false;
472 void BrowseBox::ExpandRowSelection( const BrowserMouseEvent& rEvt )
475 DoHideCursor( "ExpandRowSelection" );
477 // expand the last selection
478 if ( bMultiSelection )
480 Range aJustifiedRange( aSelRange );
481 aJustifiedRange.Justify();
483 bool bSelectThis = ( bSelect != aJustifiedRange.IsInside( rEvt.GetRow() ) );
485 if ( aJustifiedRange.IsInside( rEvt.GetRow() ) )
487 // down and up
488 while ( rEvt.GetRow() < aSelRange.Max() )
489 { // ZTC/Mac bug - don't put these statements together!
490 SelectRow( aSelRange.Max(), bSelectThis, true );
491 --aSelRange.Max();
493 while ( rEvt.GetRow() > aSelRange.Max() )
494 { // ZTC/Mac bug - don't put these statements together!
495 SelectRow( aSelRange.Max(), bSelectThis, true );
496 ++aSelRange.Max();
499 else
501 // up and down
502 bool bOldSelecting = bSelecting;
503 bSelecting = true;
504 while ( rEvt.GetRow() < aSelRange.Max() )
505 { // ZTC/Mac bug - don't put these statements together!
506 --aSelRange.Max();
507 if ( !IsRowSelected( aSelRange.Max() ) )
509 SelectRow( aSelRange.Max(), bSelectThis, true );
510 bSelect = true;
513 while ( rEvt.GetRow() > aSelRange.Max() )
514 { // ZTC/Mac bug - don't put these statements together!
515 ++aSelRange.Max();
516 if ( !IsRowSelected( aSelRange.Max() ) )
518 SelectRow( aSelRange.Max(), bSelectThis, true );
519 bSelect = true;
522 bSelecting = bOldSelecting;
523 if ( bSelect )
524 Select();
527 else
528 if ( !bMultiSelection || !IsRowSelected( rEvt.GetRow() ) )
529 SelectRow( rEvt.GetRow(), true );
531 GoToRow( rEvt.GetRow(), false );
532 DoShowCursor( "ExpandRowSelection" );
537 void BrowseBox::Resize()
539 if ( !bBootstrapped && IsReallyVisible() )
540 BrowseBox::StateChanged( StateChangedType::InitShow );
541 if ( pCols->empty() )
543 getDataWindow()->bResizeOnPaint = true;
544 return;
546 getDataWindow()->bResizeOnPaint = false;
548 // calc the size of the scrollbars
549 // (we can't ask the scrollbars for their widths cause if we're zoomed they still have to be
550 // resized - which is done in UpdateScrollbars)
551 sal_uLong nSBSize = GetSettings().GetStyleSettings().GetScrollBarSize();
552 if (IsZoom())
553 nSBSize = (sal_uLong)(nSBSize * (double)GetZoom());
555 DoHideCursor( "Resize" );
556 sal_uInt16 nOldVisibleRows = 0;
557 //fdo#42694, post #i111125# GetDataRowHeight() can be 0
558 if (GetDataRowHeight())
559 nOldVisibleRows = (sal_uInt16)(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
561 // did we need a horizontal scroll bar or is there a Control Area?
562 if ( !getDataWindow()->bNoHScroll &&
563 ( ( pCols->size() - FrozenColCount() ) > 1 ) )
564 aHScroll->Show();
565 else
566 aHScroll->Hide();
568 // calculate the size of the data window
569 long nDataHeight = GetOutputSizePixel().Height() - GetTitleHeight();
570 if ( aHScroll->IsVisible() || ( nControlAreaWidth != USHRT_MAX ) )
571 nDataHeight -= nSBSize;
573 long nDataWidth = GetOutputSizePixel().Width();
574 if ( pVScroll->IsVisible() )
575 nDataWidth -= nSBSize;
577 // adjust position and size of data window
578 pDataWin->SetPosSizePixel(
579 Point( 0, GetTitleHeight() ),
580 Size( nDataWidth, nDataHeight ) );
582 sal_uInt16 nVisibleRows = 0;
584 if (GetDataRowHeight())
585 nVisibleRows = (sal_uInt16)(pDataWin->GetOutputSizePixel().Height() / GetDataRowHeight() + 1);
587 // TopRow is unchanged, but the number of visible lines has changed.
588 if ( nVisibleRows != nOldVisibleRows )
589 VisibleRowsChanged(nTopRow, nVisibleRows);
591 UpdateScrollbars();
593 // Control-Area
594 Rectangle aInvalidArea( GetControlArea() );
595 aInvalidArea.Right() = GetOutputSizePixel().Width();
596 aInvalidArea.Left() = 0;
597 Invalidate( aInvalidArea );
599 // external header-bar
600 HeaderBar* pHeaderBar = getDataWindow()->pHeaderBar;
601 if ( pHeaderBar )
603 // take the handle column into account
604 BrowserColumn *pFirstCol = (*pCols)[ 0 ];
605 long nOfsX = pFirstCol->GetId() ? 0 : pFirstCol->Width();
606 pHeaderBar->SetPosSizePixel( Point( nOfsX, 0 ), Size( GetOutputSizePixel().Width() - nOfsX, GetTitleHeight() ) );
609 AutoSizeLastColumn(); // adjust last column width
610 DoShowCursor( "Resize" );
615 void BrowseBox::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect)
618 // initializations
619 if (!bBootstrapped && IsReallyVisible())
620 BrowseBox::StateChanged(StateChangedType::InitShow);
621 if (pCols->empty())
622 return;
624 BrowserColumn *pFirstCol = (*pCols)[ 0 ];
625 bool bHandleCol = pFirstCol && pFirstCol->GetId() == 0;
626 bool bHeaderBar = getDataWindow()->pHeaderBar.get() != NULL;
628 // draw delimitational lines
629 if (!getDataWindow()->bNoHScroll)
630 rRenderContext.DrawLine(Point(0, aHScroll->GetPosPixel().Y()),
631 Point(GetOutputSizePixel().Width(),
632 aHScroll->GetPosPixel().Y()));
634 if (nTitleLines)
636 if (!bHeaderBar)
638 rRenderContext.DrawLine(Point(0, GetTitleHeight() - 1),
639 Point(GetOutputSizePixel().Width(), GetTitleHeight() - 1));
641 else if (bHandleCol)
643 rRenderContext.DrawLine(Point(0, GetTitleHeight() - 1),
644 Point(pFirstCol->Width(), GetTitleHeight() - 1));
648 // Title Bar
649 // If there is a handle column and if the header bar is available, only
650 // take the HandleColumn into account
651 if (nTitleLines && (!bHeaderBar || bHandleCol))
653 // iterate through columns to redraw
654 long nX = 0;
655 size_t nCol;
656 for (nCol = 0; nCol < pCols->size() && nX < rRect.Right(); ++nCol)
658 // skip invisible columns between frozen and scrollable area
659 if (nCol < nFirstCol && !(*pCols)[nCol]->IsFrozen())
660 nCol = nFirstCol;
662 // only the handle column?
663 if (bHeaderBar && bHandleCol && nCol > 0)
664 break;
666 BrowserColumn* pCol = (*pCols)[nCol];
668 // draw the column and increment position
669 if ( pCol->Width() > 4 )
671 ButtonFrame aButtonFrame( Point( nX, 0 ),
672 Size( pCol->Width()-1, GetTitleHeight()-1 ),
673 pCol->Title(), false, false, !IsEnabled());
674 aButtonFrame.Draw(rRenderContext);
675 rRenderContext.DrawLine(Point(nX + pCol->Width() - 1, 0),
676 Point(nX + pCol->Width() - 1, GetTitleHeight() - 1));
678 else
680 rRenderContext.Push(PushFlags::FILLCOLOR);
681 rRenderContext.SetFillColor(Color(COL_BLACK));
682 rRenderContext.DrawRect(Rectangle(Point(nX, 0), Size(pCol->Width(), GetTitleHeight() - 1)));
683 rRenderContext.Pop();
686 // skip column
687 nX += pCol->Width();
690 // retouching
691 if ( !bHeaderBar && nCol == pCols->size() )
693 const StyleSettings &rSettings = rRenderContext.GetSettings().GetStyleSettings();
694 Color aColFace(rSettings.GetFaceColor());
695 rRenderContext.Push(PushFlags::FILLCOLOR | PushFlags::LINECOLOR);
696 rRenderContext.SetFillColor(aColFace);
697 rRenderContext.SetLineColor(aColFace);
698 rRenderContext.DrawRect(Rectangle(Point(nX, 0),
699 Point(rRect.Right(), GetTitleHeight() - 2 )));
700 rRenderContext.Pop();
707 void BrowseBox::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
709 bool bDrawSelection = (nFlags & WINDOW_DRAW_NOSELECTION) == 0;
711 // we need pixel coordinates
712 Size aRealSize = pDev->LogicToPixel(rSize);
713 Point aRealPos = pDev->LogicToPixel(rPos);
715 if ((rSize.Width() < 3) || (rSize.Height() < 3))
716 // we want to have two pixels frame ...
717 return;
719 vcl::Font aFont = GetDataWindow().GetDrawPixelFont( pDev );
720 // the 'normal' painting uses always the data window as device to output to, so we have to calc the new font
721 // relative to the data wins current settings
723 pDev->Push();
724 pDev->SetMapMode();
725 pDev->SetFont( aFont );
727 // draw a frame
728 const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
729 pDev->SetLineColor(rStyleSettings.GetDarkShadowColor());
730 pDev->DrawLine(Point(aRealPos.X(), aRealPos.Y()),
731 Point(aRealPos.X(), aRealPos.Y() + aRealSize.Height() - 1));
732 pDev->DrawLine(Point(aRealPos.X(), aRealPos.Y()),
733 Point(aRealPos.X() + aRealSize.Width() - 1, aRealPos.Y()));
734 pDev->SetLineColor(rStyleSettings.GetShadowColor());
735 pDev->DrawLine(Point(aRealPos.X() + aRealSize.Width() - 1, aRealPos.Y() + 1),
736 Point(aRealPos.X() + aRealSize.Width() - 1, aRealPos.Y() + aRealSize.Height() - 1));
737 pDev->DrawLine(Point(aRealPos.X() + aRealSize.Width() - 1, aRealPos.Y() + aRealSize.Height() - 1),
738 Point(aRealPos.X() + 1, aRealPos.Y() + aRealSize.Height() - 1));
740 HeaderBar* pBar = getDataWindow()->pHeaderBar;
742 // we're drawing onto a foreign device, so we have to fake the DataRowHeight for the subsequent ImplPaintData
743 // (as it is based on the settings of our data window, not the foreign device)
744 if (!nDataRowHeight)
745 ImpGetDataRowHeight();
746 long nHeightLogic = PixelToLogic(Size(0, nDataRowHeight), MAP_10TH_MM).Height();
747 long nForeignHeightPixel = pDev->LogicToPixel(Size(0, nHeightLogic), MAP_10TH_MM).Height();
749 long nOriginalHeight = nDataRowHeight;
750 nDataRowHeight = nForeignHeightPixel;
752 // this counts for the column widths, too
753 size_t nPos;
754 for ( nPos = 0; nPos < pCols->size(); ++nPos )
756 BrowserColumn* pCurrent = (*pCols)[ nPos ];
758 long nWidthLogic = PixelToLogic(Size(pCurrent->Width(), 0), MAP_10TH_MM).Width();
759 long nForeignWidthPixel = pDev->LogicToPixel(Size(nWidthLogic, 0), MAP_10TH_MM).Width();
761 pCurrent->SetWidth(nForeignWidthPixel, GetZoom());
762 if ( pBar )
763 pBar->SetItemSize( pCurrent->GetId(), pCurrent->Width() );
766 // a smaller area for the content
767 ++aRealPos.X();
768 ++aRealPos.Y();
769 aRealSize.Width() -= 2;
770 aRealSize.Height() -= 2;
772 // let the header bar draw itself
773 if ( pBar )
775 // the title height with respect to the font set for the given device
776 long nTitleHeight = PixelToLogic(Size(0, GetTitleHeight()), MAP_10TH_MM).Height();
777 nTitleHeight = pDev->LogicToPixel(Size(0, nTitleHeight), MAP_10TH_MM).Height();
779 BrowserColumn* pFirstCol = !pCols->empty() ? (*pCols)[ 0 ] : NULL;
781 Point aHeaderPos(pFirstCol && (pFirstCol->GetId() == 0) ? pFirstCol->Width() : 0, 0);
782 Size aHeaderSize(aRealSize.Width() - aHeaderPos.X(), nTitleHeight);
784 aHeaderPos += aRealPos;
785 // do this before converting to logics !
787 // the header's draw expects logic coordinates, again
788 aHeaderPos = pDev->PixelToLogic(aHeaderPos);
789 aHeaderSize = pDev->PixelToLogic(aHeaderSize);
791 pBar->Draw(pDev, aHeaderPos, aHeaderSize, nFlags);
793 // draw the "upper left cell" (the intersection between the header bar and the handle column)
794 if (pFirstCol && (pFirstCol->GetId() == 0) && (pFirstCol->Width() > 4))
796 ButtonFrame aButtonFrame( aRealPos,
797 Size( pFirstCol->Width()-1, nTitleHeight-1 ),
798 pFirstCol->Title(), false, false, !IsEnabled());
799 aButtonFrame.Draw( *pDev );
801 pDev->Push( PushFlags::LINECOLOR );
802 pDev->SetLineColor( Color( COL_BLACK ) );
804 pDev->DrawLine( Point( aRealPos.X(), aRealPos.Y() + nTitleHeight-1 ),
805 Point( aRealPos.X() + pFirstCol->Width() - 1, aRealPos.Y() + nTitleHeight-1 ) );
806 pDev->DrawLine( Point( aRealPos.X() + pFirstCol->Width() - 1, aRealPos.Y() ),
807 Point( aRealPos.X() + pFirstCol->Width() - 1, aRealPos.Y() + nTitleHeight-1 ) );
809 pDev->Pop();
812 aRealPos.Y() += aHeaderSize.Height();
813 aRealSize.Height() -= aHeaderSize.Height();
816 // draw our own content (with clipping)
817 vcl::Region aRegion(Rectangle(aRealPos, aRealSize));
818 pDev->SetClipRegion( pDev->PixelToLogic( aRegion ) );
820 // do we have to paint the background
821 bool bBackground = !(nFlags & WINDOW_DRAW_NOBACKGROUND) && GetDataWindow().IsControlBackground();
822 if ( bBackground )
824 Rectangle aRect( aRealPos, aRealSize );
825 pDev->SetFillColor( GetDataWindow().GetControlBackground() );
826 pDev->DrawRect( aRect );
829 ImplPaintData( *pDev, Rectangle( aRealPos, aRealSize ), true, bDrawSelection );
831 // restore the column widths/data row height
832 nDataRowHeight = nOriginalHeight;
833 for ( nPos = 0; nPos < pCols->size(); ++nPos )
835 BrowserColumn* pCurrent = (*pCols)[ nPos ];
837 long nForeignWidthLogic = pDev->PixelToLogic(Size(pCurrent->Width(), 0), MAP_10TH_MM).Width();
838 long nWidthPixel = LogicToPixel(Size(nForeignWidthLogic, 0), MAP_10TH_MM).Width();
840 pCurrent->SetWidth(nWidthPixel, GetZoom());
841 if ( pBar )
842 pBar->SetItemSize( pCurrent->GetId(), pCurrent->Width() );
845 pDev->Pop();
850 void BrowseBox::ImplPaintData(OutputDevice& _rOut, const Rectangle& _rRect, bool _bForeignDevice, bool _bDrawSelections)
852 Point aOverallAreaPos = _bForeignDevice ? _rRect.TopLeft() : Point(0,0);
853 Size aOverallAreaSize = _bForeignDevice ? _rRect.GetSize() : GetDataWindow().GetOutputSizePixel();
854 Point aOverallAreaBRPos = _bForeignDevice ? _rRect.BottomRight() : Point( aOverallAreaSize.Width(), aOverallAreaSize.Height() );
856 long nDataRowHeigt = GetDataRowHeight();
858 // compute relative rows to redraw
859 sal_uLong nRelTopRow = 0;
860 sal_uLong nRelBottomRow = aOverallAreaSize.Height();
861 if (!_bForeignDevice && nDataRowHeigt)
863 nRelTopRow = ((sal_uLong)_rRect.Top() / nDataRowHeigt);
864 nRelBottomRow = (sal_uLong)(_rRect.Bottom()) / nDataRowHeigt;
867 // cache frequently used values
868 Point aPos( aOverallAreaPos.X(), nRelTopRow * nDataRowHeigt + aOverallAreaPos.Y() );
869 _rOut.SetLineColor( Color( COL_WHITE ) );
870 const AllSettings& rAllSets = _rOut.GetSettings();
871 const StyleSettings &rSettings = rAllSets.GetStyleSettings();
872 const Color &rHighlightTextColor = rSettings.GetHighlightTextColor();
873 const Color &rHighlightFillColor = rSettings.GetHighlightColor();
874 Color aOldTextColor = _rOut.GetTextColor();
875 Color aOldFillColor = _rOut.GetFillColor();
876 Color aOldLineColor = _rOut.GetLineColor();
877 long nHLineX = 0 == (*pCols)[ 0 ]->GetId() ? (*pCols)[ 0 ]->Width() : 0;
878 nHLineX += aOverallAreaPos.X();
880 Color aDelimiterLineColor( ::svtools::ColorConfig().GetColorValue( ::svtools::CALCGRID ).nColor );
882 // redraw the invalid fields
883 for ( sal_uLong nRelRow = nRelTopRow;
884 nRelRow <= nRelBottomRow && (sal_uLong)nTopRow+nRelRow < (sal_uLong)nRowCount;
885 ++nRelRow, aPos.Y() += nDataRowHeigt )
887 // get row
888 // check valid area, to be on the safe side:
889 DBG_ASSERT( (sal_uInt16)(nTopRow+nRelRow) < nRowCount, "BrowseBox::ImplPaintData: invalid seek" );
890 if ( (nTopRow+long(nRelRow)) < 0 || (sal_uInt16)(nTopRow+nRelRow) >= nRowCount )
891 continue;
893 // prepare row
894 sal_uLong nRow = nTopRow+nRelRow;
895 if ( !SeekRow( nRow) ) {
896 OSL_FAIL("BrowseBox::ImplPaintData: SeekRow failed");
898 _rOut.SetClipRegion();
899 aPos.X() = aOverallAreaPos.X();
902 // #73325# don't paint the row outside the painting rectangle (DG)
903 // prepare auto-highlight
904 Rectangle aRowRect( Point( _rRect.TopLeft().X(), aPos.Y() ),
905 Size( _rRect.GetSize().Width(), nDataRowHeigt ) );
907 bool bRowSelected = _bDrawSelections
908 && !bHideSelect
909 && IsRowSelected( nRow );
910 if ( bRowSelected )
912 _rOut.SetTextColor( rHighlightTextColor );
913 _rOut.SetFillColor( rHighlightFillColor );
914 _rOut.SetLineColor();
915 _rOut.DrawRect( aRowRect );
918 // iterate through columns to redraw
919 size_t nCol;
920 for ( nCol = 0; nCol < pCols->size(); ++nCol )
922 // get column
923 BrowserColumn *pCol = (*pCols)[ nCol ];
925 // at end of invalid area
926 if ( aPos.X() >= _rRect.Right() )
927 break;
929 // skip invisible columns between frozen and scrollable area
930 if ( nCol < nFirstCol && !pCol->IsFrozen() )
932 nCol = nFirstCol;
933 pCol = (nCol < pCols->size() ) ? (*pCols)[ nCol ] : NULL;
934 if (!pCol)
935 { // FS - 21.05.99 - 66325
936 // actually this has been fixed elsewhere (in the right place),
937 // but let's make sure...
938 OSL_FAIL("BrowseBox::PaintData : nFirstCol is probably invalid !");
939 break;
943 // prepare Column-AutoHighlight
944 bool bColAutoHighlight = _bDrawSelections
945 && bColumnCursor
946 && IsColumnSelected( pCol->GetId() );
947 if ( bColAutoHighlight )
949 _rOut.SetClipRegion();
950 _rOut.SetTextColor( rHighlightTextColor );
951 _rOut.SetFillColor( rHighlightFillColor );
952 _rOut.SetLineColor();
953 Rectangle aFieldRect( aPos,
954 Size( pCol->Width(), nDataRowHeigt ) );
955 _rOut.DrawRect( aFieldRect );
958 if (!m_bFocusOnlyCursor && (pCol->GetId() == GetCurColumnId()) && (nRow == (sal_uLong)GetCurRow()))
959 DrawCursor();
961 // draw a single field.
962 // else something is drawn to, e.g. handle column
963 if (pCol->Width())
965 // clip the column's output to the field area
966 if (_bForeignDevice)
967 { // (not necessary if painting onto the data window)
968 Size aFieldSize(pCol->Width(), nDataRowHeigt);
970 if (aPos.X() + aFieldSize.Width() > aOverallAreaBRPos.X())
971 aFieldSize.Width() = aOverallAreaBRPos.X() - aPos.X();
973 if (aPos.Y() + aFieldSize.Height() > aOverallAreaBRPos.Y() + 1)
975 // for non-handle cols we don't clip vertically : we just don't draw the cell if the line isn't completely visible
976 if (pCol->GetId() != 0)
977 continue;
978 aFieldSize.Height() = aOverallAreaBRPos.Y() + 1 - aPos.Y();
981 vcl::Region aClipToField(Rectangle(aPos, aFieldSize));
982 _rOut.SetClipRegion(aClipToField);
984 pCol->Draw( *this, _rOut, aPos, false );
985 if (_bForeignDevice)
986 _rOut.SetClipRegion();
989 // reset Column-auto-highlight
990 if ( bColAutoHighlight )
992 _rOut.SetTextColor( aOldTextColor );
993 _rOut.SetFillColor( aOldFillColor );
994 _rOut.SetLineColor( aOldLineColor );
997 // skip column
998 aPos.X() += pCol->Width();
1001 // reset auto-highlight
1002 if ( bRowSelected )
1004 _rOut.SetTextColor( aOldTextColor );
1005 _rOut.SetFillColor( aOldFillColor );
1006 _rOut.SetLineColor( aOldLineColor );
1009 if ( bHLines )
1011 // draw horizontal delimitation lines
1012 _rOut.SetClipRegion();
1013 _rOut.Push( PushFlags::LINECOLOR );
1014 _rOut.SetLineColor( aDelimiterLineColor );
1015 long nY = aPos.Y() + nDataRowHeigt - 1;
1016 if (nY <= aOverallAreaBRPos.Y())
1017 _rOut.DrawLine( Point( nHLineX, nY ),
1018 Point( bVLines
1019 ? std::min(long(long(aPos.X()) - 1), aOverallAreaBRPos.X())
1020 : aOverallAreaBRPos.X(),
1021 nY ) );
1022 _rOut.Pop();
1026 if (aPos.Y() > aOverallAreaBRPos.Y() + 1)
1027 aPos.Y() = aOverallAreaBRPos.Y() + 1;
1028 // needed for some of the following drawing
1030 // retouching
1031 _rOut.SetClipRegion();
1032 aOldLineColor = _rOut.GetLineColor();
1033 aOldFillColor = _rOut.GetFillColor();
1034 _rOut.SetFillColor( rSettings.GetFaceColor() );
1035 if ( !pCols->empty() && ( (*pCols)[ 0 ]->GetId() == 0 ) && ( aPos.Y() <= _rRect.Bottom() ) )
1037 // fill rectangle gray below handle column
1038 // DG: fill it only until the end of the drawing rect and not to the end, as this may overpaint handle columns
1039 _rOut.SetLineColor( Color( COL_BLACK ) );
1040 _rOut.DrawRect( Rectangle(
1041 Point( aOverallAreaPos.X() - 1, aPos.Y() - 1 ),
1042 Point( aOverallAreaPos.X() + (*pCols)[ 0 ]->Width() - 1,
1043 _rRect.Bottom() + 1) ) );
1045 _rOut.SetFillColor( aOldFillColor );
1047 // draw vertical delimitational line between frozen and scrollable cols
1048 _rOut.SetLineColor( COL_BLACK );
1049 long nFrozenWidth = GetFrozenWidth()-1;
1050 _rOut.DrawLine( Point( aOverallAreaPos.X() + nFrozenWidth, aPos.Y() ),
1051 Point( aOverallAreaPos.X() + nFrozenWidth, bHLines
1052 ? aPos.Y() - 1
1053 : aOverallAreaBRPos.Y() ) );
1055 // draw vertical delimitational lines?
1056 if ( bVLines )
1058 _rOut.SetLineColor( aDelimiterLineColor );
1059 Point aVertPos( aOverallAreaPos.X() - 1, aOverallAreaPos.Y() );
1060 long nDeltaY = aOverallAreaBRPos.Y();
1061 for ( size_t nCol = 0; nCol < pCols->size(); ++nCol )
1063 // get column
1064 BrowserColumn *pCol = (*pCols)[ nCol ];
1066 // skip invisible columns between frozen and scrollable area
1067 if ( nCol < nFirstCol && !pCol->IsFrozen() )
1069 nCol = nFirstCol;
1070 pCol = (*pCols)[ nCol ];
1073 // skip column
1074 aVertPos.X() += pCol->Width();
1076 // at end of invalid area
1077 // invalid area is first reached when X > Right
1078 // and not >=
1079 if ( aVertPos.X() > _rRect.Right() )
1080 break;
1082 // draw a single line
1083 if ( pCol->GetId() != 0 )
1084 _rOut.DrawLine( aVertPos, Point( aVertPos.X(),
1085 bHLines
1086 ? aPos.Y() - 1
1087 : aPos.Y() + nDeltaY ) );
1091 _rOut.SetLineColor( aOldLineColor );
1094 void BrowseBox::PaintData( vcl::Window& rWin, vcl::RenderContext& rRenderContext, const Rectangle& rRect )
1096 if (!bBootstrapped && IsReallyVisible())
1097 BrowseBox::StateChanged(StateChangedType::InitShow);
1099 // initializations
1100 if (!pCols || pCols->empty() || !rWin.IsUpdateMode())
1101 return;
1102 if (getDataWindow()->bResizeOnPaint)
1103 Resize();
1104 // MI: who was that? Window::Update();
1106 ImplPaintData(rRenderContext, rRect, false, true);
1109 void BrowseBox::UpdateScrollbars()
1112 if ( !bBootstrapped || !IsUpdateMode() )
1113 return;
1115 // protect against recursion
1116 BrowserDataWin *pBDW = static_cast<BrowserDataWin*>( pDataWin.get() );
1117 if ( pBDW->bInUpdateScrollbars )
1119 pBDW->bHadRecursion = true;
1120 return;
1122 pBDW->bInUpdateScrollbars = true;
1124 // the size of the corner window (and the width of the VSB/height of the HSB)
1125 sal_uLong nCornerSize = GetSettings().GetStyleSettings().GetScrollBarSize();
1126 if (IsZoom())
1127 nCornerSize = (sal_uLong)(nCornerSize * (double)GetZoom());
1129 bool bNeedsVScroll = false;
1130 long nMaxRows = 0;
1131 if (GetDataRowHeight())
1133 // needs VScroll?
1134 nMaxRows = (pDataWin->GetSizePixel().Height()) / GetDataRowHeight();
1135 bNeedsVScroll = getDataWindow()->bAutoVScroll
1136 ? nTopRow || ( nRowCount > nMaxRows )
1137 : !getDataWindow()->bNoVScroll;
1139 Size aDataWinSize = pDataWin->GetSizePixel();
1140 if ( !bNeedsVScroll )
1142 if ( pVScroll->IsVisible() )
1144 pVScroll->Hide();
1145 Size aNewSize( aDataWinSize );
1146 aNewSize.Width() = GetOutputSizePixel().Width();
1147 aDataWinSize = aNewSize;
1150 else if ( !pVScroll->IsVisible() )
1152 Size aNewSize( aDataWinSize );
1153 aNewSize.Width() = GetOutputSizePixel().Width() - nCornerSize;
1154 aDataWinSize = aNewSize;
1157 // needs HScroll?
1158 sal_uLong nLastCol = GetColumnAtXPosPixel( aDataWinSize.Width() - 1 );
1160 sal_uInt16 nFrozenCols = FrozenColCount();
1161 bool bNeedsHScroll = getDataWindow()->bAutoHScroll
1162 ? ( nFirstCol > nFrozenCols ) || ( nLastCol <= pCols->size() )
1163 : !getDataWindow()->bNoHScroll;
1164 if ( !bNeedsHScroll )
1166 if ( aHScroll->IsVisible() )
1168 aHScroll->Hide();
1170 aDataWinSize.Height() = GetOutputSizePixel().Height() - GetTitleHeight();
1171 if ( nControlAreaWidth != USHRT_MAX )
1172 aDataWinSize.Height() -= nCornerSize;
1174 else if ( !aHScroll->IsVisible() )
1176 Size aNewSize( aDataWinSize );
1177 aNewSize.Height() = GetOutputSizePixel().Height() - GetTitleHeight() - nCornerSize;
1178 aDataWinSize = aNewSize;
1181 // adjust position and Width of horizontal scrollbar
1182 sal_uLong nHScrX = nControlAreaWidth == USHRT_MAX
1184 : nControlAreaWidth;
1186 aHScroll->SetPosSizePixel(
1187 Point( nHScrX, GetOutputSizePixel().Height() - nCornerSize ),
1188 Size( aDataWinSize.Width() - nHScrX, nCornerSize ) );
1190 // total scrollable columns
1191 short nScrollCols = short(pCols->size()) - (short)nFrozenCols;
1193 // visible columns
1194 short nVisibleHSize = nLastCol == BROWSER_INVALIDID
1195 ? (short)( pCols->size() - nFirstCol )
1196 : (short)( nLastCol - nFirstCol );
1198 short nRange = std::max( nScrollCols, (short)0 );
1199 aHScroll->SetVisibleSize( nVisibleHSize );
1200 aHScroll->SetRange( Range( 0, nRange ));
1201 if ( bNeedsHScroll && !aHScroll->IsVisible() )
1202 aHScroll->Show();
1204 // adjust position and height of vertical scrollbar
1205 pVScroll->SetPageSize( nMaxRows );
1207 if ( nTopRow > nRowCount )
1209 nTopRow = nRowCount - 1;
1210 OSL_FAIL("BrowseBox: nTopRow > nRowCount");
1213 if ( pVScroll->GetThumbPos() != nTopRow )
1214 pVScroll->SetThumbPos( nTopRow );
1215 long nVisibleSize = std::min( std::min( nRowCount, nMaxRows ), long(nRowCount-nTopRow) );
1216 pVScroll->SetVisibleSize( nVisibleSize ? nVisibleSize : 1 );
1217 pVScroll->SetRange( Range( 0, nRowCount ) );
1218 pVScroll->SetPosSizePixel(
1219 Point( aDataWinSize.Width(), GetTitleHeight() ),
1220 Size( nCornerSize, aDataWinSize.Height()) );
1221 long nLclDataRowHeight = GetDataRowHeight();
1222 if ( nLclDataRowHeight > 0 && nRowCount < long( aDataWinSize.Height() / nLclDataRowHeight ) )
1223 ScrollRows( -nTopRow );
1224 if ( bNeedsVScroll && !pVScroll->IsVisible() )
1225 pVScroll->Show();
1227 pDataWin->SetPosSizePixel(
1228 Point( 0, GetTitleHeight() ),
1229 aDataWinSize );
1231 // needs corner-window?
1232 // (do that AFTER positioning BOTH scrollbars)
1233 sal_uLong nActualCorderWidth = 0;
1234 if (aHScroll->IsVisible() && pVScroll && pVScroll->IsVisible() )
1236 // if we have both scrollbars, the corner window fills the point of intersection of these two
1237 nActualCorderWidth = nCornerSize;
1239 else if ( !aHScroll->IsVisible() && ( nControlAreaWidth != USHRT_MAX ) )
1241 // if we have no horizontal scrollbar, but a control area, we need the corner window to
1242 // fill the space between the control are and the right border
1243 nActualCorderWidth = GetOutputSizePixel().Width() - nControlAreaWidth;
1245 if ( nActualCorderWidth )
1247 if ( !getDataWindow()->pCornerWin )
1248 getDataWindow()->pCornerWin = VclPtr<ScrollBarBox>::Create( this, 0 );
1249 getDataWindow()->pCornerWin->SetPosSizePixel(
1250 Point( GetOutputSizePixel().Width() - nActualCorderWidth, aHScroll->GetPosPixel().Y() ),
1251 Size( nActualCorderWidth, nCornerSize ) );
1252 getDataWindow()->pCornerWin->Show();
1254 else
1255 getDataWindow()->pCornerWin.disposeAndClear();
1257 // scroll headerbar, if necessary
1258 if ( getDataWindow()->pHeaderBar )
1260 long nWidth = 0;
1261 for ( size_t nCol = 0;
1262 nCol < pCols->size() && nCol < nFirstCol;
1263 ++nCol )
1265 // not the handle column
1266 if ( (*pCols)[ nCol ]->GetId() )
1267 nWidth += (*pCols)[ nCol ]->Width();
1270 getDataWindow()->pHeaderBar->SetOffset( nWidth );
1273 pBDW->bInUpdateScrollbars = false;
1274 if ( pBDW->bHadRecursion )
1276 pBDW->bHadRecursion = false;
1277 UpdateScrollbars();
1283 void BrowseBox::SetUpdateMode( bool bUpdate )
1286 bool bWasUpdate = IsUpdateMode();
1287 if ( bWasUpdate == bUpdate )
1288 return;
1290 Control::SetUpdateMode( bUpdate );
1291 // If WB_CLIPCHILDREN is st at the BrowseBox (to minimize flicker),
1292 // the data window is not invalidated by SetUpdateMode.
1293 if( bUpdate )
1294 getDataWindow()->Invalidate();
1295 getDataWindow()->SetUpdateMode( bUpdate );
1298 if ( bUpdate )
1300 if ( bBootstrapped )
1302 UpdateScrollbars();
1303 AutoSizeLastColumn();
1305 DoShowCursor( "SetUpdateMode" );
1307 else
1308 DoHideCursor( "SetUpdateMode" );
1313 bool BrowseBox::GetUpdateMode() const
1316 return getDataWindow()->IsUpdateMode();
1321 long BrowseBox::GetFrozenWidth() const
1324 long nWidth = 0;
1325 for ( size_t nCol = 0;
1326 nCol < pCols->size() && (*pCols)[ nCol ]->IsFrozen();
1327 ++nCol )
1328 nWidth += (*pCols)[ nCol ]->Width();
1329 return nWidth;
1334 void BrowseBox::ColumnInserted( sal_uInt16 nPos )
1337 if ( pColSel )
1338 pColSel->Insert( nPos );
1339 UpdateScrollbars();
1344 sal_uInt16 BrowseBox::FrozenColCount() const
1346 sal_uInt16 nCol;
1347 for ( nCol = 0;
1348 nCol < pCols->size() && (*pCols)[ nCol ]->IsFrozen();
1349 ++nCol )
1350 /* empty loop */;
1351 return nCol;
1356 IMPL_LINK(BrowseBox,ScrollHdl,ScrollBar*,pBar)
1359 if ( pBar->GetDelta() == 0 )
1360 return 0;
1362 if ( pBar->GetDelta() < 0 && getDataWindow()->bNoScrollBack )
1364 UpdateScrollbars();
1365 return 0;
1368 if ( pBar == aHScroll.get() )
1369 ScrollColumns( aHScroll->GetDelta() );
1370 if ( pBar == pVScroll )
1371 ScrollRows( pVScroll->GetDelta() );
1373 return 0;
1378 IMPL_LINK_NOARG(BrowseBox, EndScrollHdl)
1381 if ( getDataWindow()->bNoScrollBack )
1383 EndScroll();
1384 return 0;
1387 return 0;
1392 IMPL_LINK( BrowseBox, StartDragHdl, HeaderBar*, pBar )
1394 pBar->SetDragSize( pDataWin->GetOutputSizePixel().Height() );
1395 return 0;
1399 // usually only the first column was resized
1401 void BrowseBox::MouseButtonDown( const MouseEvent& rEvt )
1404 GrabFocus();
1406 // only mouse events in the title-line are supported
1407 const Point &rEvtPos = rEvt.GetPosPixel();
1408 if ( rEvtPos.Y() >= GetTitleHeight() )
1409 return;
1411 long nX = 0;
1412 long nWidth = GetOutputSizePixel().Width();
1413 for ( size_t nCol = 0; nCol < pCols->size() && nX < nWidth; ++nCol )
1415 // is this column visible?
1416 BrowserColumn *pCol = (*pCols)[ nCol ];
1417 if ( pCol->IsFrozen() || nCol >= nFirstCol )
1419 // compute right end of column
1420 long nR = nX + pCol->Width() - 1;
1422 // at the end of a column (and not handle column)?
1423 if ( pCol->GetId() && std::abs( nR - rEvtPos.X() ) < 2 )
1425 // start resizing the column
1426 bResizing = true;
1427 nResizeCol = nCol;
1428 nDragX = nResizeX = rEvtPos.X();
1429 SetPointer( Pointer( PointerStyle::HSplit ) );
1430 CaptureMouse();
1431 pDataWin->DrawLine( Point( nDragX, 0 ),
1432 Point( nDragX, pDataWin->GetSizePixel().Height() ) );
1433 nMinResizeX = nX + MIN_COLUMNWIDTH;
1434 return;
1436 else if ( nX < rEvtPos.X() && nR > rEvtPos.X() )
1438 MouseButtonDown( BrowserMouseEvent(
1439 this, rEvt, -1, nCol, pCol->GetId(), Rectangle() ) );
1440 return;
1442 nX = nR + 1;
1446 // event occurred out of data area
1447 if ( rEvt.IsRight() )
1448 pDataWin->Command(
1449 CommandEvent( Point( 1, LONG_MAX ), CommandEventId::ContextMenu, true ) );
1450 else
1451 SetNoSelection();
1456 void BrowseBox::MouseMove( const MouseEvent& rEvt )
1458 OSL_TRACE( "BrowseBox::MouseMove( MouseEvent )" );
1460 Pointer aNewPointer;
1462 sal_uInt16 nX = 0;
1463 for ( size_t nCol = 0;
1464 nCol < pCols->size() &&
1465 ( nX + (*pCols)[ nCol ]->Width() ) < sal_uInt16(GetOutputSizePixel().Width());
1466 ++nCol )
1467 // is this column visible?
1468 if ( (*pCols)[ nCol ]->IsFrozen() || nCol >= nFirstCol )
1470 // compute right end of column
1471 BrowserColumn *pCol = (*pCols)[ nCol ];
1472 sal_uInt16 nR = (sal_uInt16)(nX + pCol->Width() - 1);
1474 // show resize-pointer?
1475 if ( bResizing || ( pCol->GetId() &&
1476 std::abs( ((long) nR ) - rEvt.GetPosPixel().X() ) < MIN_COLUMNWIDTH ) )
1478 aNewPointer = Pointer( PointerStyle::HSplit );
1479 if ( bResizing )
1481 // delete old auxiliary line
1482 pDataWin->HideTracking() ;
1484 // check allowed width and new delta
1485 nDragX = std::max( rEvt.GetPosPixel().X(), nMinResizeX );
1486 long nDeltaX = nDragX - nResizeX;
1487 sal_uInt16 nId = GetColumnId(nResizeCol);
1488 sal_uLong nOldWidth = GetColumnWidth(nId);
1489 nDragX = QueryColumnResize( GetColumnId(nResizeCol),
1490 nOldWidth + nDeltaX )
1491 + nResizeX - nOldWidth;
1493 // draw new auxiliary line
1494 pDataWin->ShowTracking( Rectangle( Point( nDragX, 0 ),
1495 Size( 1, pDataWin->GetSizePixel().Height() ) ),
1496 SHOWTRACK_SPLIT|SHOWTRACK_WINDOW );
1501 nX = nR + 1;
1504 SetPointer( aNewPointer );
1509 void BrowseBox::MouseButtonUp( const MouseEvent & rEvt )
1512 if ( bResizing )
1514 // delete auxiliary line
1515 pDataWin->HideTracking();
1517 // width changed?
1518 nDragX = std::max( rEvt.GetPosPixel().X(), nMinResizeX );
1519 if ( (nDragX - nResizeX) != (long)(*pCols)[ nResizeCol ]->Width() )
1521 // resize column
1522 long nMaxX = pDataWin->GetSizePixel().Width();
1523 nDragX = std::min( nDragX, nMaxX );
1524 long nDeltaX = nDragX - nResizeX;
1525 sal_uInt16 nId = GetColumnId(nResizeCol);
1526 SetColumnWidth( GetColumnId(nResizeCol), GetColumnWidth(nId) + nDeltaX );
1527 ColumnResized( nId );
1530 // end action
1531 SetPointer( Pointer() );
1532 ReleaseMouse();
1533 bResizing = false;
1535 else
1536 MouseButtonUp( BrowserMouseEvent( static_cast<BrowserDataWin*>(pDataWin.get()),
1537 MouseEvent( Point( rEvt.GetPosPixel().X(),
1538 rEvt.GetPosPixel().Y() - pDataWin->GetPosPixel().Y() ),
1539 rEvt.GetClicks(), rEvt.GetMode(), rEvt.GetButtons(),
1540 rEvt.GetModifier() ) ) );
1545 bool bExtendedMode = false;
1546 bool bFieldMode = false;
1548 void BrowseBox::MouseButtonDown( const BrowserMouseEvent& rEvt )
1551 GrabFocus();
1553 // adjust selection while and after double-click
1554 if ( rEvt.GetClicks() == 2 )
1556 SetNoSelection();
1557 if ( rEvt.GetRow() >= 0 )
1559 GoToRow( rEvt.GetRow() );
1560 SelectRow( rEvt.GetRow(), true, false );
1562 else
1564 if ( bColumnCursor && rEvt.GetColumn() != 0 )
1566 if ( rEvt.GetColumn() < pCols->size() )
1567 SelectColumnPos( rEvt.GetColumn(), true, false);
1570 DoubleClick( rEvt );
1572 // selections
1573 else if ( ( rEvt.GetMode() & ( MouseEventModifiers::SELECT | MouseEventModifiers::SIMPLECLICK ) ) &&
1574 ( bColumnCursor || rEvt.GetRow() >= 0 ) )
1576 if ( rEvt.GetClicks() == 1 )
1578 // initialise flags
1579 bHit = false;
1580 a1stPoint =
1581 a2ndPoint = PixelToLogic( rEvt.GetPosPixel() );
1583 // selection out of range?
1584 if ( rEvt.GetRow() >= nRowCount ||
1585 rEvt.GetColumnId() == BROWSER_INVALIDID )
1587 SetNoSelection();
1588 return;
1591 // while selecting, no cursor
1592 bSelecting = true;
1593 DoHideCursor( "MouseButtonDown" );
1595 // DataRow?
1596 if ( rEvt.GetRow() >= 0 )
1598 // line selection?
1599 if ( rEvt.GetColumnId() == HandleColumnId || !bColumnCursor )
1601 if ( bMultiSelection )
1603 // remove column-selection, if exists
1604 if ( pColSel && pColSel->GetSelectCount() )
1606 ToggleSelection();
1607 if ( bMultiSelection )
1608 uRow.pSel->SelectAll(false);
1609 else
1610 uRow.nSel = BROWSER_ENDOFSELECTION;
1611 if ( pColSel )
1612 pColSel->SelectAll(false);
1613 bSelect = true;
1616 // expanding mode?
1617 if ( rEvt.GetMode() & MouseEventModifiers::RANGESELECT )
1619 // select the further touched rows too
1620 bSelect = true;
1621 ExpandRowSelection( rEvt );
1622 return;
1625 // click in the selected area?
1626 else if ( IsRowSelected( rEvt.GetRow() ) )
1628 // wait for Drag&Drop
1629 bHit = true;
1630 bExtendedMode = bool( rEvt.GetMode() & MouseEventModifiers::MULTISELECT );
1631 return;
1634 // extension mode?
1635 else if ( rEvt.GetMode() & MouseEventModifiers::MULTISELECT )
1637 // determine the new selection range
1638 // and selection/deselection
1639 aSelRange = Range( rEvt.GetRow(), rEvt.GetRow() );
1640 SelectRow( rEvt.GetRow(),
1641 !uRow.pSel->IsSelected( rEvt.GetRow() ) );
1642 bSelect = true;
1643 return;
1647 // select directly
1648 SetNoSelection();
1649 GoToRow( rEvt.GetRow() );
1650 SelectRow( rEvt.GetRow(), true );
1651 aSelRange = Range( rEvt.GetRow(), rEvt.GetRow() );
1652 bSelect = true;
1654 else // Column/Field-Selection
1656 // click in selected column
1657 if ( IsColumnSelected( rEvt.GetColumn() ) ||
1658 IsRowSelected( rEvt.GetRow() ) )
1660 bHit = true;
1661 bFieldMode = true;
1662 return;
1665 SetNoSelection();
1666 GoToRowColumnId( rEvt.GetRow(), rEvt.GetColumnId() );
1667 bSelect = true;
1670 else
1672 if ( bMultiSelection && rEvt.GetColumnId() == HandleColumnId )
1674 // toggle all-selection
1675 if ( uRow.pSel->GetSelectCount() > ( GetRowCount() / 2 ) )
1676 SetNoSelection();
1677 else
1678 SelectAll();
1680 else
1681 SelectColumnId( rEvt.GetColumnId(), true, false );
1684 // turn cursor on again, if necessary
1685 bSelecting = false;
1686 DoShowCursor( "MouseButtonDown" );
1687 if ( bSelect )
1688 Select();
1695 void BrowseBox::MouseButtonUp( const BrowserMouseEvent &rEvt )
1698 // D&D was possible, but did not occur
1699 if ( bHit )
1701 aSelRange = Range( rEvt.GetRow(), rEvt.GetRow() );
1702 if ( bExtendedMode )
1703 SelectRow( rEvt.GetRow(), false );
1704 else
1706 SetNoSelection();
1707 if ( bFieldMode )
1708 GoToRowColumnId( rEvt.GetRow(), rEvt.GetColumnId() );
1709 else
1711 GoToRow( rEvt.GetRow() );
1712 SelectRow( rEvt.GetRow(), true );
1715 bSelect = true;
1716 bExtendedMode = false;
1717 bFieldMode = false;
1718 bHit = false;
1721 // activate cursor
1722 if ( bSelecting )
1724 bSelecting = false;
1725 DoShowCursor( "MouseButtonUp" );
1726 if ( bSelect )
1727 Select();
1733 void BrowseBox::KeyInput( const KeyEvent& rEvt )
1735 if ( !ProcessKey( rEvt ) )
1736 Control::KeyInput( rEvt );
1741 bool BrowseBox::ProcessKey( const KeyEvent& rEvt )
1744 sal_uInt16 nCode = rEvt.GetKeyCode().GetCode();
1745 bool bShift = rEvt.GetKeyCode().IsShift();
1746 bool bCtrl = rEvt.GetKeyCode().IsMod1();
1747 bool bAlt = rEvt.GetKeyCode().IsMod2();
1749 sal_uInt16 nId = BROWSER_NONE;
1751 if ( !bAlt && !bCtrl && !bShift )
1753 switch ( nCode )
1755 case KEY_DOWN: nId = BROWSER_CURSORDOWN; break;
1756 case KEY_UP: nId = BROWSER_CURSORUP; break;
1757 case KEY_HOME: nId = BROWSER_CURSORHOME; break;
1758 case KEY_END: nId = BROWSER_CURSOREND; break;
1759 case KEY_TAB:
1760 if ( !bColumnCursor )
1761 break;
1762 case KEY_RIGHT: nId = BROWSER_CURSORRIGHT; break;
1763 case KEY_LEFT: nId = BROWSER_CURSORLEFT; break;
1764 case KEY_SPACE: nId = BROWSER_SELECT; break;
1766 if ( BROWSER_NONE != nId )
1767 SetNoSelection();
1769 switch ( nCode )
1771 case KEY_PAGEDOWN: nId = BROWSER_CURSORPAGEDOWN; break;
1772 case KEY_PAGEUP: nId = BROWSER_CURSORPAGEUP; break;
1776 if ( !bAlt && !bCtrl && bShift )
1777 switch ( nCode )
1779 case KEY_DOWN: nId = BROWSER_SELECTDOWN; break;
1780 case KEY_UP: nId = BROWSER_SELECTUP; break;
1781 case KEY_TAB:
1782 if ( !bColumnCursor )
1783 break;
1784 nId = BROWSER_CURSORLEFT; break;
1785 case KEY_HOME: nId = BROWSER_SELECTHOME; break;
1786 case KEY_END: nId = BROWSER_SELECTEND; break;
1790 if ( !bAlt && bCtrl && !bShift )
1791 switch ( nCode )
1793 case KEY_DOWN: nId = BROWSER_CURSORDOWN; break;
1794 case KEY_UP: nId = BROWSER_CURSORUP; break;
1795 case KEY_PAGEDOWN: nId = BROWSER_CURSORENDOFFILE; break;
1796 case KEY_PAGEUP: nId = BROWSER_CURSORTOPOFFILE; break;
1797 case KEY_HOME: nId = BROWSER_CURSORTOPOFSCREEN; break;
1798 case KEY_END: nId = BROWSER_CURSORENDOFSCREEN; break;
1799 case KEY_SPACE: nId = BROWSER_ENHANCESELECTION; break;
1800 case KEY_LEFT: nId = BROWSER_MOVECOLUMNLEFT; break;
1801 case KEY_RIGHT: nId = BROWSER_MOVECOLUMNRIGHT; break;
1804 if ( nId != BROWSER_NONE )
1805 Dispatch( nId );
1806 return nId != BROWSER_NONE;
1811 void BrowseBox::Dispatch( sal_uInt16 nId )
1814 long nRowsOnPage = pDataWin->GetSizePixel().Height() / GetDataRowHeight();
1815 bool bDone = false;
1817 switch ( nId )
1819 case BROWSER_SELECTCOLUMN:
1820 if ( ColCount() )
1821 SelectColumnId( GetCurColumnId() );
1822 break;
1824 case BROWSER_CURSORDOWN:
1825 if ( ( GetCurRow() + 1 ) < nRowCount )
1826 bDone = GoToRow( GetCurRow() + 1, false );
1827 break;
1828 case BROWSER_CURSORUP:
1829 if ( GetCurRow() > 0 )
1830 bDone = GoToRow( GetCurRow() - 1, false );
1831 break;
1832 case BROWSER_SELECTHOME:
1833 if ( GetRowCount() )
1835 DoHideCursor( "BROWSER_SELECTHOME" );
1836 for ( long nRow = GetCurRow(); nRow >= 0; --nRow )
1837 SelectRow( nRow );
1838 GoToRow( 0, true );
1839 DoShowCursor( "BROWSER_SELECTHOME" );
1841 break;
1842 case BROWSER_SELECTEND:
1843 if ( GetRowCount() )
1845 DoHideCursor( "BROWSER_SELECTEND" );
1846 long nRows = GetRowCount();
1847 for ( long nRow = GetCurRow(); nRow < nRows; ++nRow )
1848 SelectRow( nRow );
1849 GoToRow( GetRowCount() - 1, true );
1850 DoShowCursor( "BROWSER_SELECTEND" );
1852 break;
1853 case BROWSER_SELECTDOWN:
1855 if ( GetRowCount() && ( GetCurRow() + 1 ) < nRowCount )
1857 // deselect the current row, if it isn't the first
1858 // and there is no other selected row above
1859 long nRow = GetCurRow();
1860 bool bLocalSelect = ( !IsRowSelected( nRow ) ||
1861 GetSelectRowCount() == 1 || IsRowSelected( nRow - 1 ) );
1862 SelectRow( nRow, bLocalSelect, true );
1863 bDone = GoToRow( GetCurRow() + 1, false );
1864 if ( bDone )
1865 SelectRow( GetCurRow(), true, true );
1867 else
1868 bDone = ScrollRows( 1 ) != 0;
1869 break;
1871 case BROWSER_SELECTUP:
1872 if ( GetRowCount() )
1874 // deselect the current row, if it isn't the first
1875 // and there is no other selected row under
1876 long nRow = GetCurRow();
1877 bool bLocalSelect = ( !IsRowSelected( nRow ) ||
1878 GetSelectRowCount() == 1 || IsRowSelected( nRow + 1 ) );
1879 SelectRow( nCurRow, bLocalSelect, true );
1880 bDone = GoToRow( nRow - 1, false );
1881 if ( bDone )
1882 SelectRow( GetCurRow(), true, true );
1884 break;
1885 case BROWSER_CURSORPAGEDOWN:
1886 bDone = ScrollRows( nRowsOnPage );
1887 break;
1888 case BROWSER_CURSORPAGEUP:
1889 bDone = ScrollRows( -nRowsOnPage );
1890 break;
1891 case BROWSER_CURSOREND:
1892 if ( bColumnCursor )
1894 sal_uInt16 nNewId = GetColumnId(ColCount() -1);
1895 bDone = nNewId != HandleColumnId && GoToColumnId( nNewId );
1896 break;
1898 case BROWSER_CURSORENDOFFILE:
1899 bDone = GoToRow( nRowCount - 1, false );
1900 break;
1901 case BROWSER_CURSORRIGHT:
1902 if ( bColumnCursor )
1904 sal_uInt16 nNewPos = GetColumnPos( GetCurColumnId() ) + 1;
1905 sal_uInt16 nNewId = GetColumnId( nNewPos );
1906 if (nNewId != BROWSER_INVALIDID) // At end of row ?
1907 bDone = GoToColumnId( nNewId );
1908 else
1910 sal_uInt16 nColId = GetColumnId(0);
1911 if ( nColId == BROWSER_INVALIDID || nColId == HandleColumnId )
1912 nColId = GetColumnId(1);
1913 if ( GetRowCount() )
1914 bDone = ( nCurRow < GetRowCount() - 1 ) && GoToRowColumnId( nCurRow + 1, nColId );
1915 else if ( ColCount() )
1916 GoToColumnId( nColId );
1919 else
1920 bDone = ScrollColumns( 1 ) != 0;
1921 break;
1922 case BROWSER_CURSORHOME:
1923 if ( bColumnCursor )
1925 sal_uInt16 nNewId = GetColumnId(1);
1926 bDone = (nNewId != HandleColumnId) && GoToColumnId( nNewId );
1927 break;
1929 case BROWSER_CURSORTOPOFFILE:
1930 bDone = GoToRow( 0, false );
1931 break;
1932 case BROWSER_CURSORLEFT:
1933 if ( bColumnCursor )
1935 sal_uInt16 nNewPos = GetColumnPos( GetCurColumnId() ) - 1;
1936 sal_uInt16 nNewId = GetColumnId( nNewPos );
1937 if (nNewId != HandleColumnId)
1938 bDone = GoToColumnId( nNewId );
1939 else
1941 if ( GetRowCount() )
1942 bDone = (nCurRow > 0) && GoToRowColumnId(nCurRow - 1, GetColumnId(ColCount() -1));
1943 else if ( ColCount() )
1944 GoToColumnId( GetColumnId(ColCount() -1) );
1947 else
1948 bDone = ScrollColumns( -1 ) != 0;
1949 break;
1950 case BROWSER_ENHANCESELECTION:
1951 if ( GetRowCount() )
1952 SelectRow( GetCurRow(), !IsRowSelected( GetCurRow() ), true );
1953 bDone = true;
1954 break;
1955 case BROWSER_SELECT:
1956 if ( GetRowCount() )
1957 SelectRow( GetCurRow(), !IsRowSelected( GetCurRow() ), false );
1958 bDone = true;
1959 break;
1960 case BROWSER_MOVECOLUMNLEFT:
1961 case BROWSER_MOVECOLUMNRIGHT:
1962 { // check if column moving is allowed
1963 BrowserHeader* pHeaderBar = getDataWindow()->pHeaderBar;
1964 if ( pHeaderBar && pHeaderBar->IsDragable() )
1966 sal_uInt16 nColId = GetCurColumnId();
1967 bool bColumnSelected = IsColumnSelected(nColId);
1968 sal_uInt16 nNewPos = GetColumnPos(nColId);
1969 bool bMoveAllowed = false;
1970 if ( BROWSER_MOVECOLUMNLEFT == nId && nNewPos > 1 )
1971 --nNewPos,bMoveAllowed = true;
1972 else if ( BROWSER_MOVECOLUMNRIGHT == nId && nNewPos < (ColCount()-1) )
1973 ++nNewPos,bMoveAllowed = true;
1975 if ( bMoveAllowed )
1977 SetColumnPos( nColId, nNewPos );
1978 ColumnMoved( nColId );
1979 MakeFieldVisible(GetCurRow(), nColId, true);
1980 if ( bColumnSelected )
1981 SelectColumnId(nColId);
1985 break;
1988 //! return bDone;
1993 void BrowseBox::SetCursorColor(const Color& _rCol)
1995 if (_rCol == m_aCursorColor)
1996 return;
1998 // ensure the cursor is hidden
1999 DoHideCursor("SetCursorColor");
2000 if (!m_bFocusOnlyCursor)
2001 DoHideCursor("SetCursorColor - force");
2003 m_aCursorColor = _rCol;
2005 if (!m_bFocusOnlyCursor)
2006 DoShowCursor("SetCursorColor - force");
2007 DoShowCursor("SetCursorColor");
2010 Rectangle BrowseBox::calcHeaderRect(bool _bIsColumnBar, bool _bOnScreen)
2012 vcl::Window* pParent = NULL;
2013 if ( !_bOnScreen )
2014 pParent = GetAccessibleParentWindow();
2016 Point aTopLeft;
2017 long nWidth;
2018 long nHeight;
2019 if ( _bIsColumnBar )
2021 nWidth = GetDataWindow().GetOutputSizePixel().Width();
2022 nHeight = GetDataRowHeight();
2024 else
2026 aTopLeft.Y() = GetDataRowHeight();
2027 nWidth = GetColumnWidth(0);
2028 nHeight = GetWindowExtentsRelative( pParent ).GetHeight() - aTopLeft.Y() - GetControlArea().GetSize().B();
2030 aTopLeft += GetWindowExtentsRelative( pParent ).TopLeft();
2031 return Rectangle(aTopLeft,Size(nWidth,nHeight));
2034 Rectangle BrowseBox::calcTableRect(bool _bOnScreen)
2036 vcl::Window* pParent = NULL;
2037 if ( !_bOnScreen )
2038 pParent = GetAccessibleParentWindow();
2040 Rectangle aRect( GetWindowExtentsRelative( pParent ) );
2041 Rectangle aRowBar = calcHeaderRect(false, pParent == NULL);
2043 long nX = aRowBar.Right() - aRect.Left();
2044 long nY = aRowBar.Top() - aRect.Top();
2045 Size aSize(aRect.GetSize());
2047 return Rectangle(aRowBar.TopRight(), Size(aSize.A() - nX, aSize.B() - nY - aHScroll->GetSizePixel().Height()) );
2050 Rectangle BrowseBox::GetFieldRectPixelAbs( sal_Int32 _nRowId, sal_uInt16 _nColId, bool /*_bIsHeader*/, bool _bOnScreen )
2052 vcl::Window* pParent = NULL;
2053 if ( !_bOnScreen )
2054 pParent = GetAccessibleParentWindow();
2056 Rectangle aRect = GetFieldRectPixel(_nRowId,_nColId,_bOnScreen);
2058 Point aTopLeft = aRect.TopLeft();
2059 aTopLeft += GetWindowExtentsRelative( pParent ).TopLeft();
2061 return Rectangle(aTopLeft,aRect.GetSize());
2064 // ------------------------------------------------------------------------- EOF
2066 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */