/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "taskpane/ScrollPanel.hxx"

#include "taskpane/ControlContainer.hxx"
#include "TaskPaneFocusManager.hxx"
#include "taskpane/TitledControl.hxx"
#include "AccessibleScrollPanel.hxx"

#include <vcl/svapp.hxx>
#include <svtools/valueset.hxx>

namespace sd { namespace toolpanel {

ScrollPanel::ScrollPanel (
    TreeNode* pParent)
    : Control (pParent->GetWindow(), WB_DIALOGCONTROL),
      TreeNode(pParent),
      maScrollWindow(this, WB_DIALOGCONTROL),
      maVerticalScrollBar(this, WB_VERT),
      maHorizontalScrollBar(this, WB_HORZ),
      maScrollBarFiller(this),
      maScrollWindowFiller(&maScrollWindow),
      mbIsRearrangePending(true),
      mbIsLayoutPending(true),
      mnChildrenWidth(0),
      mnVerticalBorder(2),
      mnVerticalGap(3),
      mnHorizontalBorder(2)
{
    Construct();
}

ScrollPanel::ScrollPanel (
    ::Window& i_rParentWindow)
    : Control (&i_rParentWindow, WB_DIALOGCONTROL),
      TreeNode(NULL),
      maScrollWindow(this, WB_DIALOGCONTROL),
      maVerticalScrollBar(this, WB_VERT),
      maHorizontalScrollBar(this, WB_HORZ),
      maScrollBarFiller(this),
      maScrollWindowFiller(&maScrollWindow),
      mbIsRearrangePending(true),
      mbIsLayoutPending(true),
      mnChildrenWidth(0),
      mnVerticalBorder(2),
      mnVerticalGap(3),
      mnHorizontalBorder(2)
{
    Construct();
}

void ScrollPanel::Construct()
{
    SetAccessibleName (
        ::rtl::OUString::createFromAscii("Sub Task Panel"));
    mpControlContainer->SetMultiSelection (true);

    SetBorderStyle (WINDOW_BORDER_NORMAL);
    SetMapMode (MapMode(MAP_PIXEL));

    // To reduce flickering during repaints make the container windows
    // transparent and rely on their children to paint the whole area.
    SetBackground(Wallpaper());
    maScrollWindow.SetBackground(Wallpaper());
    maScrollWindowFiller.SetBackground(
        Application::GetSettings().GetStyleSettings().GetWindowColor());

    maScrollWindow.Show();

    // Initialize the scroll bars.
    maVerticalScrollBar.SetScrollHdl (
        LINK(this, ScrollPanel, ScrollBarHandler));
    maVerticalScrollBar.EnableDrag (TRUE);
    maHorizontalScrollBar.SetScrollHdl (
        LINK(this, ScrollPanel, ScrollBarHandler));
    maHorizontalScrollBar.EnableDrag (TRUE);
}




ScrollPanel::~ScrollPanel (void)
{
    sal_uInt32 nCount = mpControlContainer->GetControlCount();
    for (sal_uInt32 nIndex=0; nIndex<nCount; nIndex++)
    {
        TreeNode* pNode = mpControlContainer->GetControl(nIndex);
        TreeNode* pControl = pNode;
        // When the node has been created as TitledControl then use its
        // control instead of pNode directly.
        TitledControl* pTitledControl = static_cast<TitledControl*>(pNode);
        if (pTitledControl != NULL)
            pControl = pTitledControl->GetControl();

        // Remove this object as listener from the control.
        if (pControl != NULL && pControl->GetWindow()!=NULL)
        {
            pControl->GetWindow()->RemoveEventListener(
                LINK(this,ScrollPanel,WindowEventListener));
        }
    }
    mpControlContainer->DeleteChildren();
}




TitledControl* ScrollPanel::AddControl (
    ::std::auto_ptr<TreeNode> pControl, 
    const String& rTitle,
    ULONG nHelpId)
{
    // We are interested only in the title.  The control itself is
    // managed by the content object.
    TitledControl* pTitledControl = new TitledControl(
        this,
        pControl, 
        rTitle,
        TitledControlStandardClickHandler(GetControlContainer(), ControlContainer::ES_TOGGLE),
        TitleBar::TBT_SUB_CONTROL_HEADLINE);
    pTitledControl->GetTitleBar()->SetHelpId(nHelpId);

    AddControl(::std::auto_ptr<TreeNode>(pTitledControl));
    
    return pTitledControl;
}




void ScrollPanel::AddControl (::std::auto_ptr<TreeNode> pControl)
{
    if (pControl.get() != NULL)
    {
        // Add a window event listener which does two things:
        // 1. Listen for controls being shown or hidden so that the layout
        // can be adapted.
        // 2. Track selection changes in order to make the selected elements
        // visible.
        const Link aWindowListener(LINK(this,ScrollPanel,WindowEventListener));
        OSL_ASSERT(pControl->GetWindow()!=NULL);
        pControl->GetWindow()->AddEventListener(aWindowListener);
        
        TitledControl* pTitledControl = dynamic_cast<TitledControl*>(pControl.get());
        if (pTitledControl != NULL)
        {
            OSL_ASSERT(pTitledControl->GetControl()!=NULL);
            OSL_ASSERT(pTitledControl->GetControl()->GetWindow()!=NULL);
            pTitledControl->GetControl()->GetWindow()->AddEventListener(aWindowListener);
        }

        FocusManager& rFocusManager (FocusManager::Instance());
        int nControlCount (mpControlContainer->GetControlCount());
        // Replace the old links for cycling between first and last child by
        // current ones.
        if (nControlCount > 0)
        {
            ::Window* pFirst = mpControlContainer->GetControl(0)->GetWindow();
            ::Window* pLast = mpControlContainer->GetControl(nControlCount-1)->GetWindow();
            rFocusManager.RemoveLinks(pFirst,pLast);
            rFocusManager.RemoveLinks(pLast,pFirst);

            rFocusManager.RegisterLink(pFirst,pControl->GetWindow(), KEY_UP);
            rFocusManager.RegisterLink(pControl->GetWindow(),pFirst, KEY_DOWN);
        }
        
        
        // Add a down link only for the first control so that when entering
        // the sub tool panel the focus is set to the first control.
        if (nControlCount == 0)
            rFocusManager.RegisterDownLink(GetParent(), pControl->GetWindow());
        rFocusManager.RegisterUpLink(pControl->GetWindow(), GetParent());

        pControl->GetWindow()->SetParent(&maScrollWindow);
        mpControlContainer->AddControl (pControl);
        mpControlContainer->SetExpansionState(
            mpControlContainer->GetControlCount()-1,
            ControlContainer::ES_EXPAND);
    }
}




void ScrollPanel::Paint (const Rectangle& rRect)
{
    if (mbIsRearrangePending)
        Rearrange();
    if (mbIsLayoutPending)
        LayoutChildren();
    ::Window::Paint (rRect);

    // Paint the outer border and the space between every two children.
    Color aOriginalLineColor (maScrollWindow.GetLineColor());
    Color aOriginalFillColor (maScrollWindow.GetFillColor());

    maScrollWindow.SetLineColor ();
    maScrollWindow.SetFillColor (
        GetSettings().GetStyleSettings().GetWindowColor());

    Size aSize (maScrollWindow.GetOutputSizePixel());
    // Paint left and right vertical border.
    Rectangle aVerticalArea (
        Point(0,0), 
        Size(mnHorizontalBorder,aSize.Height()));
    maScrollWindow.DrawRect (aVerticalArea);
    aVerticalArea.Right() += mnHorizontalBorder + mnChildrenWidth - 1;
    aVerticalArea.Left() = aVerticalArea.Right() + mnHorizontalBorder;
    maScrollWindow.DrawRect (aVerticalArea);

    // Paint horizontal stripes.
    Rectangle aStripeArea (
        Point (mnHorizontalBorder,0),
        Size(mnChildrenWidth,0));
    StripeList::const_iterator iStripe;
    for (iStripe=maStripeList.begin(); iStripe!=maStripeList.end(); iStripe++)
    {
        aStripeArea.Top() = iStripe->first;
        aStripeArea.Bottom() = iStripe->second;
        if (aStripeArea.Bottom() < 0)
            continue;
        if (aStripeArea.Top() >= aSize.Height())
            break;
        maScrollWindow.DrawRect (aStripeArea);
    }
    
    maScrollWindow.SetLineColor (aOriginalLineColor);
    maScrollWindow.SetFillColor (aOriginalFillColor);
}




void ScrollPanel::Resize (void)
{
    ::Window::Resize();
    mbIsRearrangePending = true;
    mbIsLayoutPending = true;
}




void ScrollPanel::RequestResize (void)
{
    mbIsRearrangePending = true;
    mbIsLayoutPending = true;
    Invalidate();
}




Size ScrollPanel::GetPreferredSize (void)
{
    return GetRequiredSize();
}




sal_Int32 ScrollPanel::GetPreferredWidth (sal_Int32 )
{
    return GetPreferredSize().Width();
}




sal_Int32 ScrollPanel::GetPreferredHeight (sal_Int32 )
{
    return GetPreferredSize().Height();
}




bool ScrollPanel::IsResizable (void)
{
    return true;
}




::Window* ScrollPanel::GetWindow (void)
{
    return this;
}




sal_Int32 ScrollPanel::GetMinimumWidth (void)
{
    return TreeNode::GetMinimumWidth();
}




void ScrollPanel::ExpandControl (
    TreeNode* pControl,
    bool bExpansionState)
{
    // Toggle expand status.
    pControl->Expand (bExpansionState);

    Rearrange ();
    Invalidate ();
}




bool ScrollPanel::IsVerticalScrollBarVisible (void) const
{
    return maVerticalScrollBar.IsReallyVisible();
}




bool ScrollPanel::IsHorizontalScrollBarVisible (void) const
{
    return maHorizontalScrollBar.IsReallyVisible();
}




ScrollBar& ScrollPanel::GetVerticalScrollBar (void)
{
    return maVerticalScrollBar;
}




ScrollBar& ScrollPanel::GetHorizontalScrollBar (void)
{
    return maHorizontalScrollBar;
}




/** This control shows an expansion bar for every control and in a
    separate area below that expansion area it shows all controls each
    with its title bar.  When there is not enough space then show a
    scroll bar in the control area.
*/
void ScrollPanel::Rearrange (void)
{
    Size aRequiredSize (GetRequiredSize());
    if (aRequiredSize.Width()>0 && aRequiredSize.Height()>0)
    {
        Size aAvailableSize (SetupScrollBars (aRequiredSize));
        maScrollWindow.SetPosSizePixel(
            Point(0,0),
            aAvailableSize);

        // Make the children at least as wide as the sub tool panel.
        if (aRequiredSize.Width() < aAvailableSize.Width())
            aRequiredSize.Width() = aAvailableSize.Width();
        mnChildrenWidth = -2*mnHorizontalBorder;
        if (maHorizontalScrollBar.IsVisible())
            mnChildrenWidth += aRequiredSize.Width();
        else
            mnChildrenWidth += aAvailableSize.Width();
        
        sal_Int32 nChildrenHeight (LayoutChildren());
        maVerticalScrollBar.SetRangeMax (
            nChildrenHeight + mnVerticalBorder);

        mbIsRearrangePending = false;
    }
}




Size ScrollPanel::GetRequiredSize (void)
{
    // First determine the width of the children.  This is the maximum of
    // the current window width and the individual minimum widths of the
    // children. 
    int nChildrenWidth (GetSizePixel().Width());
    unsigned int nCount = mpControlContainer->GetControlCount();
    unsigned int nIndex;
    for (nIndex=0; nIndex<nCount; nIndex++)
    {
        TreeNode* pChild = mpControlContainer->GetControl (nIndex);
        int nMinimumWidth (pChild->GetMinimumWidth());
        if (nMinimumWidth > nChildrenWidth)
            nChildrenWidth = nMinimumWidth;
    }

    // Determine the accumulated width of all children when scaled to the
    // minimum width.
    nChildrenWidth -= 2*mnHorizontalBorder;
    Size aTotalSize (nChildrenWidth, 
        2*mnVerticalBorder + (nCount-1) * mnVerticalGap);
    for (nIndex=0; nIndex<nCount; nIndex++)
    {
        TreeNode* pChild = mpControlContainer->GetControl (nIndex);
        sal_Int32 nHeight = pChild->GetPreferredHeight(nChildrenWidth);
        aTotalSize.Height() += nHeight;
    }

    return aTotalSize;
}




sal_Int32 ScrollPanel::LayoutChildren (void)
{
    maStripeList.clear();

    Point aPosition (maScrollOffset);
    aPosition.X() += mnHorizontalBorder;
    maStripeList.push_back( ::std::pair<int,int>(
        aPosition.Y(),
        aPosition.Y() + mnVerticalBorder - 1));
    aPosition.Y() += mnVerticalBorder;

    // Place the controls one over the other.
    unsigned int nCount (mpControlContainer->GetControlCount());
    for (unsigned int nIndex=0; nIndex<nCount; nIndex++)
    {
        if (nIndex > 0)
        {
            maStripeList.push_back( ::std::pair<int,int>(
                aPosition.Y(),
                aPosition.Y() + mnVerticalGap - 1));
            aPosition.Y() += mnVerticalGap;
        }
        TreeNode* pChild = mpControlContainer->GetControl (nIndex);
        int nControlHeight = pChild->GetPreferredHeight(mnChildrenWidth);
        pChild->GetWindow()->SetPosSizePixel(
            aPosition,
            Size(mnChildrenWidth, nControlHeight));
        aPosition.Y() += nControlHeight;
    }

    // If the children do not cover their parent window completely
    // (regarding the height) we put a filler below that is responsible for
    // painting the remaining space.
    int nWindowHeight = maScrollWindow.GetSizePixel().Height();
    if (aPosition.Y() < nWindowHeight)
    {
        maScrollWindowFiller.SetPosSizePixel (
            aPosition,
            Size(mnChildrenWidth, nWindowHeight-aPosition.Y()));
        maStripeList.push_back( ::std::pair<int,int>(
            aPosition.Y(),
            nWindowHeight-1));
        //        maScrollWindowFiller.Show();
        aPosition.Y() = nWindowHeight;
    }
    else
        maScrollWindowFiller.Hide();

    aPosition.Y() += mnVerticalBorder;
    mbIsLayoutPending = false;

    return aPosition.Y()-maScrollOffset.Y();
}




Size ScrollPanel::SetupScrollBars (const Size& rRequiredSize)
{
    Size aWindowSize (GetSizePixel());
    Size aScrollBarSize (
        maVerticalScrollBar.GetSizePixel().Width(),
        maHorizontalScrollBar.GetSizePixel().Height());
    Size aRemainingSize (aWindowSize);

    // Determine which scroll bars have to be shown.
    bool bShowHorizontal = false;
    if (rRequiredSize.Width() > aWindowSize.Width())
        bShowHorizontal = true;
    bool bShowVertical = false;
    if (rRequiredSize.Height() > aWindowSize.Height())
        bShowVertical = true;
    // Showing one scroll bar may reduce the available size so that the
    // other one has to be shown as well.
    if (bShowHorizontal && ! bShowVertical)
    {
        if ((rRequiredSize.Height() + aScrollBarSize.Height())
            > aWindowSize.Height())
            bShowVertical = true;
    }
    else if (bShowVertical && ! bShowHorizontal)
    {
        if (GetMinimumWidth() + aScrollBarSize.Width() > aWindowSize.Width())
            bShowHorizontal = true;
    }
        
    // Setup the scroll bars.
    aRemainingSize.Width()
        = SetupVerticalScrollBar (bShowVertical, rRequiredSize.Height());
    aRemainingSize.Height()
        = SetupHorizontalScrollBar (bShowHorizontal, rRequiredSize.Width());

    // Place the filler.
    if (bShowHorizontal && bShowVertical)
    {
        maScrollBarFiller.SetPosSizePixel (
            Point(aWindowSize.Width(), aWindowSize.Height()),
            aScrollBarSize);
        maScrollBarFiller.Show();
    }
    else
        maScrollBarFiller.Hide();


    return aRemainingSize;
}




sal_Int32 ScrollPanel::SetupVerticalScrollBar (bool bShow, sal_Int32 nRange)
{
    Size aScrollBarSize (
        maVerticalScrollBar.GetSizePixel().Width(),
        maHorizontalScrollBar.GetSizePixel().Height());
    Size aWindowSize (GetOutputSizePixel());
    sal_Int32 nRemainingWidth (aWindowSize.Width());

    // Setup the verical scroll bar.
    if (bShow)
    {
        int nWidth = aScrollBarSize.Width();
        int nHeight = aWindowSize.Height();
        maVerticalScrollBar.SetPosSizePixel(
            Point(aWindowSize.Width()-nWidth,0),
            Size(nWidth, nHeight));
        maVerticalScrollBar.Show();

        // Set the scroll bar range and thumb size.
        maVerticalScrollBar.SetRangeMin (0);
        maVerticalScrollBar.SetRangeMax (
            nRange + 2*mnVerticalBorder);
        maVerticalScrollBar.SetVisibleSize (aWindowSize.Height());
        // Make page size approx. 10% of visible area.
        maVerticalScrollBar.SetLineSize (aWindowSize.Height()/10);
        // Make page size approx. 100% of visible area.
        maVerticalScrollBar.SetPageSize (aWindowSize.Height());
        // Make sure that thumb is inside the valid range.
        maVerticalScrollBar.SetThumbPos(-maScrollOffset.Y());
        long nMinPos = maVerticalScrollBar.GetRangeMin();
        if (maVerticalScrollBar.GetThumbPos() < nMinPos)
            maVerticalScrollBar.SetThumbPos(nMinPos);
        long nMaxPos = maVerticalScrollBar.GetRangeMax() 
            - maVerticalScrollBar.GetVisibleSize();
        if (maVerticalScrollBar.GetThumbPos() >= nMaxPos)
            maVerticalScrollBar.SetThumbPos(nMaxPos);
        // Set offset to match thumb pos.
        maScrollOffset.Y() = -maVerticalScrollBar.GetThumbPos();

        nRemainingWidth -= aScrollBarSize.Width();
    }
    else
    {
        maVerticalScrollBar.Hide();
        maScrollOffset.Y() = 0;
    }

    return nRemainingWidth;
}




sal_Int32 ScrollPanel::SetupHorizontalScrollBar (bool bShow, sal_Int32 nRange)
{
    Size aScrollBarSize (
        maVerticalScrollBar.GetSizePixel().Width(),
        maHorizontalScrollBar.GetSizePixel().Height());
    Size aWindowSize (GetOutputSizePixel());
    sal_Int32 nRemainingHeight (aWindowSize.Height());

    // Setup the horizontal scroll bar.
    if (bShow)
    {
        int nHeight = aScrollBarSize.Height();
        int nWidth = GetOutputSizePixel().Width();
        maHorizontalScrollBar.SetPosSizePixel(
            Point(0, aWindowSize.Height()-nHeight),
            Size(nWidth,nHeight));
        maHorizontalScrollBar.Show();

        // Set the scroll bar range and thumb size.
        maHorizontalScrollBar.SetRangeMin (0);
        maHorizontalScrollBar.SetRangeMax (
            nRange + 2*mnHorizontalBorder);
        maHorizontalScrollBar.SetVisibleSize (aWindowSize.Width());
        // Make page size approx. 5% of visible area.
        maHorizontalScrollBar.SetLineSize (aWindowSize.Width()/20+1);
        // Make page size approx. 50% of visible area.
        maHorizontalScrollBar.SetPageSize (aWindowSize.Width()/2+1);
        // Make sure that thumb is inside the valid range.
        maHorizontalScrollBar.SetThumbPos(-maScrollOffset.X());
        long nMinPos = maHorizontalScrollBar.GetRangeMin();
        if (maHorizontalScrollBar.GetThumbPos() < nMinPos)
            maHorizontalScrollBar.SetThumbPos(nMinPos);
        long nMaxPos = maHorizontalScrollBar.GetRangeMax() 
            - maHorizontalScrollBar.GetVisibleSize();
        if (maHorizontalScrollBar.GetThumbPos() >= nMaxPos)
            maHorizontalScrollBar.SetThumbPos(nMaxPos);
        // Set offset to match thumb pos.
        maScrollOffset.X() = -maHorizontalScrollBar.GetThumbPos();

        nRemainingHeight -= aScrollBarSize.Height();
    }
    else
    {
        maHorizontalScrollBar.Hide();
        maScrollOffset.X() = 0;
    }

    return nRemainingHeight;
}


IMPL_LINK(ScrollPanel, ScrollBarHandler, ScrollBar*, EMPTYARG)
{
    maScrollOffset.X() -= maHorizontalScrollBar.GetDelta();
    maScrollOffset.Y() -= maVerticalScrollBar.GetDelta();

    // Scrolling is done by moving the child windows up or down.
    mbIsLayoutPending = true;
    Invalidate();
    //    LayoutChildren();

    return 0;
}




long ScrollPanel::Notify( NotifyEvent& rNEvt )
{
    long nRet = FALSE;
    if( rNEvt.GetType() == EVENT_COMMAND )
    {
        // note: dynamic_cast is not possible as GetData() returns a void*
        CommandEvent* pCmdEvent = reinterpret_cast< CommandEvent* >(rNEvt.GetData());
        DBG_ASSERT( pCmdEvent!=0 &&
                    ( pCmdEvent->IsMouseEvent() == TRUE ||
                      pCmdEvent->IsMouseEvent() == FALSE ),
                    "Invalid CommandEvent" );
        if (pCmdEvent)
            switch (pCmdEvent->GetCommand())
            {
                case COMMAND_WHEEL:
                case COMMAND_STARTAUTOSCROLL:
                case COMMAND_AUTOSCROLL:
                {
                    nRet = HandleScrollCommand (*pCmdEvent, &maHorizontalScrollBar, &maVerticalScrollBar);
                    break;
                }
            }
    }

    if( ! nRet )
        nRet = ::Window::Notify( rNEvt );

    return nRet;
}




::com::sun::star::uno::Reference<
    ::com::sun::star::accessibility::XAccessible> ScrollPanel::CreateAccessibleObject (
        const ::com::sun::star::uno::Reference<
        ::com::sun::star::accessibility::XAccessible>& )
{
    return new ::accessibility::AccessibleScrollPanel (
        *this,
        ::rtl::OUString::createFromAscii("Scroll Panel"),
        ::rtl::OUString::createFromAscii("Scroll Panel"));
}




void ScrollPanel::MakeRectangleVisible (
    Rectangle& aRectangle,
    ::Window* pWindow)
{
    if (maVerticalScrollBar.IsVisible() && aRectangle.GetWidth()>0 && aRectangle.GetHeight()>0)
    {
        const Rectangle aRelativeBox (pWindow->GetWindowExtentsRelative(&maScrollWindow));

        aRectangle.Move(
            -maScrollOffset.X() + aRelativeBox.Left(),
            -maScrollOffset.Y() + aRelativeBox.Top());
    
        const int nVisibleHeight (maVerticalScrollBar.GetVisibleSize());
        const int nVisibleTop (maVerticalScrollBar.GetThumbPos());
        if (aRectangle.Bottom() >= nVisibleTop+nVisibleHeight)
            maVerticalScrollBar.DoScroll(aRectangle.Bottom() - nVisibleHeight);
        else if (aRectangle.Top() < nVisibleTop)
            maVerticalScrollBar.DoScroll(aRectangle.Top());
    }
}




IMPL_LINK(ScrollPanel,WindowEventListener,VclSimpleEvent*,pEvent)
{
    VclWindowEvent* pWindowEvent = dynamic_cast<VclWindowEvent*>(pEvent);
    if (pWindowEvent != NULL)
    {
        switch (pWindowEvent->GetId())
        {
            case VCLEVENT_WINDOW_KEYUP:
            case VCLEVENT_WINDOW_MOUSEBUTTONUP:
            {
                // Make the currently selected item visible.
                ValueSet* pControl = dynamic_cast<ValueSet*>(pWindowEvent->GetWindow());
                if (pControl != NULL)
                {
                    // Get the bounding box of the currently selected item
                    // and enlarge this so that the selection frame is
                    // inside as well.
                    Rectangle aBox (pControl->GetItemRect(pControl->GetSelectItemId()));
                    aBox.Top()-=4;
                    aBox.Bottom()+=4;
                    
                    MakeRectangleVisible(aBox, pControl);
                }
            }
            break;
            
            case VCLEVENT_WINDOW_MOUSEBUTTONDOWN:
            {
                // Make the item under the mouse visible.  We need this case
                // for right clicks that open context menus.  For these we
                // only get the mouse down event.  The following mouse up
                // event is sent to the context menu.
                ValueSet* pControl = dynamic_cast<ValueSet*>(pWindowEvent->GetWindow());
                if (pControl != NULL)
                {
                    // Get the bounding box of the item at the mouse
                    // position and enlarge this so that the selection frame
                    // is inside as well.
                    MouseEvent* pMouseEvent
                        = reinterpret_cast<MouseEvent*>(pWindowEvent->GetData());
                    if (pMouseEvent != NULL)
                    {
                        Point aPosition (pMouseEvent->GetPosPixel());
                        Rectangle aBox (pControl->GetItemRect(pControl->GetItemId(aPosition)));
                        aBox.Top()-=4;
                        aBox.Bottom()+=4;
                    
                        MakeRectangleVisible(aBox, pControl);
                    }
                }
            }
            break;
                

            case VCLEVENT_WINDOW_GETFOCUS:
            {
                // Move title bars into the visible area when they get the
                // focus (::Window wise their enclosing TitledControl gets
                // the focus.)
                TitledControl* pTitledControl = dynamic_cast<TitledControl*>(pWindowEvent->GetWindow());
                if (pTitledControl!=NULL && pTitledControl->GetTitleBar()!=NULL)
                {
                    ::Window* pTitleBarWindow = pTitledControl->GetTitleBar()->GetWindow();
                    Rectangle aBox(pTitleBarWindow->GetPosPixel(),pTitleBarWindow->GetSizePixel());
                    MakeRectangleVisible(
                        aBox,
                        pTitleBarWindow);
                }
            }
            break;
                
            case VCLEVENT_WINDOW_SHOW:
            case VCLEVENT_WINDOW_HIDE:
            case VCLEVENT_WINDOW_ACTIVATE:
            case VCLEVENT_WINDOW_RESIZE:
                // Rearrange the children of the scroll panel when one of
                // the children changes its size or visibility.
                RequestResize();
                break;
        }
    }
    return 0;
}




} } // end of namespace ::sd::toolpanel

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
