LCOV - code coverage report
Current view: top level - svtools/source/toolpanel - paneltabbar.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 0 510 0.0 %
Date: 2015-06-13 12:38:46 Functions: 0 73 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : 
      21             : #include <svtools/toolpanel/paneltabbar.hxx>
      22             : #include <svtools/toolpanel/toolpaneldeck.hxx>
      23             : #include <svtools/svtresid.hxx>
      24             : #include <svtools/svtools.hrc>
      25             : 
      26             : #include "tabitemdescriptor.hxx"
      27             : #include "paneltabbarpeer.hxx"
      28             : #include "tabbargeometry.hxx"
      29             : 
      30             : #include <vcl/button.hxx>
      31             : #include <vcl/help.hxx>
      32             : #include <vcl/virdev.hxx>
      33             : #include <vcl/settings.hxx>
      34             : #include <tools/diagnose_ex.h>
      35             : 
      36             : #include <boost/optional.hpp>
      37             : #include <vector>
      38             : 
      39             : // space around an item
      40             : #define ITEM_OUTER_SPACE        2 * 3
      41             : // spacing before and after an item's text
      42             : #define ITEM_TEXT_FLOW_SPACE    5
      43             : // space between item icon and icon text
      44             : #define ITEM_ICON_TEXT_DISTANCE 4
      45             : 
      46             : 
      47             : namespace svt
      48             : {
      49             : 
      50             : 
      51             :     using ::com::sun::star::uno::Reference;
      52             :     using ::com::sun::star::awt::XWindowPeer;
      53             : 
      54             :     typedef sal_uInt16  ItemFlags;
      55             : 
      56             :     #define ITEM_STATE_NORMAL   0x00
      57             :     #define ITEM_STATE_ACTIVE   0x01
      58             :     #define ITEM_STATE_HOVERED  0x02
      59             :     #define ITEM_STATE_FOCUSED  0x04
      60             :     #define ITEM_POSITION_FIRST 0x08
      61             :     #define ITEM_POSITION_LAST  0x10
      62             : 
      63             : 
      64             :     //= helper
      65             : 
      66             :     namespace
      67             :     {
      68           0 :         ControlState lcl_ItemToControlState( const ItemFlags i_nItemFlags )
      69             :         {
      70           0 :             ControlState nState = ControlState::ENABLED;
      71           0 :             if ( i_nItemFlags & ITEM_STATE_FOCUSED )    nState |= ControlState::FOCUSED | ControlState::PRESSED;
      72           0 :             if ( i_nItemFlags & ITEM_STATE_HOVERED )    nState |= ControlState::ROLLOVER;
      73           0 :             if ( i_nItemFlags & ITEM_STATE_ACTIVE )     nState |= ControlState::SELECTED;
      74           0 :             return nState;
      75             :         }
      76             :     }
      77             : 
      78             : 
      79             :     //= ITabBarRenderer
      80             : 
      81           0 :     class SAL_NO_VTABLE ITabBarRenderer
      82             :     {
      83             :     public:
      84             :         /** fills the background of our target device
      85             :         */
      86             :         virtual void        renderBackground() const = 0;
      87             :         virtual Rectangle   calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const = 0;
      88             :         virtual void        preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const = 0;
      89             :         virtual void        postRenderItem( vcl::Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const = 0;
      90             : 
      91             :         // TODO: postRenderItem takes the "real" window, i.e. effectively the tab bar. This is because
      92             :         // DrawSelectionBackground needs to be applied after everything else is painted, and is available at the Window
      93             :         // class, but not at the OutputDevice. This makes the API somewhat weird, as we're now mixing operations on the
      94             :         // target device, done in a normalized geometry, with operations on the window, done in a transformed geometry.
      95             :         // So, we should get rid of postRenderItem completely.
      96             : 
      97             :     protected:
      98           0 :         ~ITabBarRenderer() {}
      99             :     };
     100             :     typedef ::boost::shared_ptr< ITabBarRenderer >  PTabBarRenderer;
     101             : 
     102             : 
     103             :     //= VCLItemRenderer - declaration
     104             : 
     105             :     class VCLItemRenderer : public ITabBarRenderer
     106             :     {
     107             :     public:
     108           0 :         explicit VCLItemRenderer( OutputDevice& i_rTargetDevice )
     109           0 :             :m_rTargetDevice( i_rTargetDevice )
     110             :         {
     111           0 :         }
     112           0 :         virtual ~VCLItemRenderer() {}
     113             : 
     114             :         // ITabBarRenderer
     115             :         virtual void        renderBackground() const SAL_OVERRIDE;
     116             :         virtual Rectangle   calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const SAL_OVERRIDE;
     117             :         virtual void        preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const SAL_OVERRIDE;
     118             :         virtual void        postRenderItem( vcl::Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const SAL_OVERRIDE;
     119             : 
     120             :     protected:
     121           0 :         OutputDevice&   getTargetDevice() const { return m_rTargetDevice; }
     122             : 
     123             :     private:
     124             :         OutputDevice&   m_rTargetDevice;
     125             :     };
     126             : 
     127             : 
     128             :     //= VCLItemRenderer - implementation
     129             : 
     130             : 
     131           0 :     void VCLItemRenderer::renderBackground() const
     132             :     {
     133           0 :         getTargetDevice().DrawRect( Rectangle( Point(), getTargetDevice().GetOutputSizePixel() ) );
     134           0 :     }
     135             : 
     136             : 
     137           0 :     Rectangle VCLItemRenderer::calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const
     138             :     {
     139             :         (void)i_nItemFlags;
     140             :         // no decorations at all
     141           0 :         return i_rContentArea;
     142             :     }
     143             : 
     144             : 
     145           0 :     void VCLItemRenderer::preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const
     146             :     {
     147             :         (void)i_rContentRect;
     148             :         (void)i_nItemFlags;
     149           0 :     }
     150             : 
     151             : 
     152           0 :     void VCLItemRenderer::postRenderItem( vcl::Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const
     153             :     {
     154           0 :         const bool bActive = ( ( i_nItemFlags & ITEM_STATE_ACTIVE ) != 0 );
     155           0 :         const bool bHovered = ( ( i_nItemFlags & ITEM_STATE_HOVERED ) != 0 );
     156           0 :         const bool bFocused = ( ( i_nItemFlags & ITEM_STATE_FOCUSED ) != 0 );
     157           0 :         if ( bActive || bHovered || bFocused )
     158             :         {
     159           0 :             Rectangle aSelectionRect( i_rItemRect );
     160           0 :             aSelectionRect.Left() += ITEM_OUTER_SPACE / 2;
     161           0 :             aSelectionRect.Top() += ITEM_OUTER_SPACE / 2;
     162           0 :             aSelectionRect.Right() -= ITEM_OUTER_SPACE / 2;
     163           0 :             aSelectionRect.Bottom() -= ITEM_OUTER_SPACE / 2;
     164             :             i_rActualWindow.DrawSelectionBackground(
     165             :                 aSelectionRect,
     166           0 :                 ( bHovered || bFocused ) ? ( bActive ? 1 : 2 ) : 0 /* highlight */,
     167             :                 bActive /* check */,
     168             :                 true /* border */,
     169             :                 false /* ext border only */,
     170             :                 0 /* corner radius */,
     171             :                 NULL,
     172             :                 NULL
     173           0 :             );
     174             :         }
     175           0 :     }
     176             : 
     177             : 
     178             :     //= NWFToolboxItemRenderer - declaration
     179             : 
     180             :     class NWFToolboxItemRenderer : public ITabBarRenderer
     181             :     {
     182             :     public:
     183           0 :         explicit NWFToolboxItemRenderer( OutputDevice& i_rTargetDevice )
     184           0 :             :m_rTargetDevice( i_rTargetDevice )
     185             :         {
     186           0 :         }
     187           0 :         virtual ~NWFToolboxItemRenderer() {}
     188             : 
     189             :         // ITabBarRenderer
     190             :         virtual void        renderBackground() const SAL_OVERRIDE;
     191             :         virtual Rectangle   calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const SAL_OVERRIDE;
     192             :         virtual void        preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const SAL_OVERRIDE;
     193             :         virtual void        postRenderItem( vcl::Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const SAL_OVERRIDE;
     194             : 
     195             :     protected:
     196           0 :         OutputDevice&   getTargetDevice() const { return m_rTargetDevice; }
     197             : 
     198             :     private:
     199             :         OutputDevice&   m_rTargetDevice;
     200             :     };
     201             : 
     202             : 
     203             :     //= NWFToolboxItemRenderer - implementation
     204             : 
     205             : 
     206           0 :     void NWFToolboxItemRenderer::renderBackground() const
     207             :     {
     208           0 :         getTargetDevice().DrawRect( Rectangle( Point(), getTargetDevice().GetOutputSizePixel() ) );
     209           0 :     }
     210             : 
     211             : 
     212           0 :     Rectangle NWFToolboxItemRenderer::calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const
     213             :     {
     214             :         // don't ask GetNativeControlRegion, this will not deliver proper results in all cases.
     215             :         // Instead, simply assume that both the content and the bounding region are the same.
     216             : //        const ControlState nState( lcl_ItemToControlState( i_nItemFlags );
     217             : //        const ImplControlValue aControlValue;
     218             : //        bool bNativeOK = m_rTargetWindow.GetNativeControlRegion(
     219             : //            CTRL_TOOLBAR, PART_BUTTON,
     220             : //            i_rContentArea, nState,
     221             : //            aControlValue, OUString(),
     222             : //            aBoundingRegion, aContentRegion
     223             : //        );
     224             :         (void)i_nItemFlags;
     225             :         return Rectangle(
     226           0 :             Point( i_rContentArea.Left() - 1, i_rContentArea.Top() - 1 ),
     227           0 :             Size( i_rContentArea.GetWidth() + 2, i_rContentArea.GetHeight() + 2 )
     228           0 :         );
     229             :     }
     230             : 
     231             : 
     232           0 :     void NWFToolboxItemRenderer::preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const
     233             :     {
     234           0 :         const ControlState nState = lcl_ItemToControlState( i_nItemFlags );
     235             : 
     236           0 :         ImplControlValue aControlValue;
     237           0 :         aControlValue.setTristateVal( ( i_nItemFlags & ITEM_STATE_ACTIVE ) ? BUTTONVALUE_ON : BUTTONVALUE_OFF );
     238             : 
     239           0 :         bool bNativeOK = getTargetDevice().DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON, i_rContentRect, nState, aControlValue, OUString() );
     240             :         (void)bNativeOK;
     241           0 :         OSL_ENSURE( bNativeOK, "NWFToolboxItemRenderer::preRenderItem: inconsistent NWF implementation!" );
     242             :             // IsNativeControlSupported returned true, previously, otherwise we would not be here ...
     243           0 :     }
     244             : 
     245             : 
     246           0 :     void NWFToolboxItemRenderer::postRenderItem( vcl::Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const
     247             :     {
     248             :         (void)i_rActualWindow;
     249             :         (void)i_rItemRect;
     250             :         (void)i_nItemFlags;
     251           0 :     }
     252             : 
     253             : 
     254             : #if defined WNT
     255             :     //= NWFTabItemRenderer - declaration
     256             : 
     257             :     class NWFTabItemRenderer : public ITabBarRenderer
     258             :     {
     259             :     public:
     260             :         explicit NWFTabItemRenderer( OutputDevice& i_rTargetDevice )
     261             :             :m_rTargetDevice( i_rTargetDevice )
     262             :         {
     263             :         }
     264             : 
     265             :         virtual ~NWFTabItemRenderer() {}
     266             : 
     267             :         // ITabBarRenderer
     268             :         virtual void        renderBackground() const SAL_OVERRIDE;
     269             :         virtual Rectangle   calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const SAL_OVERRIDE;
     270             :         virtual void        preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const SAL_OVERRIDE;
     271             :         virtual void        postRenderItem( vcl::Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const SAL_OVERRIDE;
     272             : 
     273             :     protected:
     274             :         OutputDevice&   getTargetDevice() const { return m_rTargetDevice; }
     275             : 
     276             :     private:
     277             :         OutputDevice&   m_rTargetDevice;
     278             :     };
     279             : 
     280             : 
     281             :     //= NWFTabItemRenderer - implementation
     282             : 
     283             : 
     284             :     void NWFTabItemRenderer::renderBackground() const
     285             :     {
     286             :         Rectangle aBackground( Point(), getTargetDevice().GetOutputSizePixel() );
     287             :         getTargetDevice().DrawRect( aBackground );
     288             : 
     289             :         aBackground.Top() = aBackground.Bottom();
     290             :         getTargetDevice().DrawNativeControl( CTRL_TAB_PANE, PART_ENTIRE_CONTROL, aBackground,
     291             :             ControlState::ENABLED, ImplControlValue(), OUString() );
     292             :     }
     293             : 
     294             : 
     295             :     Rectangle NWFTabItemRenderer::calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const
     296             :     {
     297             :         const ControlState nState( lcl_ItemToControlState( i_nItemFlags ) );
     298             : 
     299             :         TabitemValue tiValue(Rectangle(i_rContentArea.Left() + TAB_TABOFFSET_X,
     300             :                                        i_rContentArea.Right() - TAB_TABOFFSET_X,
     301             :                                        i_rContentArea.Top() + TAB_TABOFFSET_Y,
     302             :                                        i_rContentArea.Bottom() - TAB_TABOFFSET_Y));
     303             : 
     304             :         Rectangle aBoundingRegion, aContentRegion;
     305             :         bool bNativeOK = getTargetDevice().GetNativeControlRegion(
     306             :             CTRL_TAB_ITEM, PART_ENTIRE_CONTROL,
     307             :             i_rContentArea, nState,
     308             :             tiValue, OUString(),
     309             :             aBoundingRegion, aContentRegion
     310             :         );
     311             :         (void)bNativeOK;
     312             :         OSL_ENSURE( bNativeOK, "NWFTabItemRenderer::calculateDecorations: GetNativeControlRegion not implemented for CTRL_TAB_ITEM?!" );
     313             : 
     314             :         return aBoundingRegion;
     315             :     }
     316             : 
     317             : 
     318             :     void NWFTabItemRenderer::preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const
     319             :     {
     320             :         const ControlState nState = lcl_ItemToControlState( i_nItemFlags );
     321             : 
     322             :         TabitemValue tiValue(Rectangle(i_rContentRect.Left() + TAB_TABOFFSET_X,
     323             :                                        i_rContentRect.Right() - TAB_TABOFFSET_X,
     324             :                                        i_rContentRect.Top() + TAB_TABOFFSET_Y,
     325             :                                        i_rContentRect.Bottom() - TAB_TABOFFSET_Y));
     326             : 
     327             :         if ( i_nItemFlags & ITEM_POSITION_FIRST )
     328             :             tiValue.mnAlignment |= TabitemFlags::FirstInGroup;
     329             :         if ( i_nItemFlags & ITEM_POSITION_LAST )
     330             :             tiValue.mnAlignment |= TabitemFlags::LastInGroup;
     331             : 
     332             : 
     333             :         bool bNativeOK = getTargetDevice().DrawNativeControl( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, i_rContentRect, nState, tiValue, OUString() );
     334             :         (void)bNativeOK;
     335             :         OSL_ENSURE( bNativeOK, "NWFTabItemRenderer::preRenderItem: inconsistent NWF implementation!" );
     336             :             // IsNativeControlSupported returned true, previously, otherwise we would not be here ...
     337             :     }
     338             : 
     339             : 
     340             :     void NWFTabItemRenderer::postRenderItem( vcl::Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const
     341             :     {
     342             :         (void)i_rActualWindow;
     343             :         (void)i_rItemRect;
     344             :         (void)i_nItemFlags;
     345             :     }
     346             : #endif
     347             : 
     348             :     //= PanelTabBar_Impl
     349             : 
     350             :     class PanelTabBar_Impl : public IToolPanelDeckListener
     351             :     {
     352             :     public:
     353             :         PanelTabBar_Impl(PanelTabBar& i_rTabBar, IToolPanelDeck& i_rPanelDeck,
     354             :                          const TabAlignment i_eAlignment, const TabItemContent i_eItemContent);
     355             : 
     356           0 :         virtual ~PanelTabBar_Impl()
     357           0 :         {
     358           0 :             m_rPanelDeck.RemoveListener(*this);
     359           0 :         }
     360             : 
     361             :         // IToolPanelDeckListener
     362           0 :         virtual void PanelInserted(const PToolPanel& i_pPanel, const size_t i_nPosition) SAL_OVERRIDE
     363             :         {
     364             :             (void) i_pPanel;
     365             :             (void) i_nPosition;
     366           0 :             m_bItemsDirty = true;
     367           0 :             m_rTabBar.Invalidate();
     368             : 
     369           0 :             Relayout();
     370           0 :         }
     371             : 
     372           0 :         virtual void PanelRemoved( const size_t i_nPosition ) SAL_OVERRIDE
     373             :         {
     374           0 :             m_bItemsDirty = true;
     375           0 :             m_rTabBar.Invalidate();
     376             : 
     377           0 :             if ( i_nPosition < m_nScrollPosition )
     378           0 :                 --m_nScrollPosition;
     379             : 
     380           0 :             Relayout();
     381           0 :         }
     382             : 
     383             :         virtual void ActivePanelChanged(const boost::optional<size_t>& i_rOldActive,
     384             :                                         const boost::optional<size_t>& i_rNewActive) SAL_OVERRIDE;
     385             :         virtual void LayouterChanged(const PDeckLayouter& i_rNewLayouter) SAL_OVERRIDE;
     386             :         virtual void Dying() SAL_OVERRIDE;
     387             : 
     388           0 :         void UpdateScrollButtons()
     389             :         {
     390           0 :             m_aScrollBack->Enable(m_nScrollPosition > 0);
     391           0 :             m_aScrollForward->Enable(m_nScrollPosition < m_aItems.size() - 1);
     392           0 :         }
     393             : 
     394             :         void                        Relayout();
     395             :         void                        EnsureItemsCache();
     396             :         boost::optional<size_t>     FindItemForPoint( const Point& i_rPoint ) const;
     397             :         void                        DrawItem(vcl::RenderContext& rRenderContext, const size_t i_nItemIndex, const Rectangle& i_rBoundaries) const;
     398             :         void                        InvalidateItem( const size_t i_nItemIndex, const ItemFlags i_nAdditionalItemFlags = 0 ) const;
     399             :         void                        CopyFromRenderDevice(vcl::RenderContext& rRenderContext, const Rectangle& i_rLogicalRect) const;
     400             :         Rectangle                   GetActualLogicalItemRect( const Rectangle& i_rLogicalItemRect ) const;
     401             :         Rectangle                   GetItemScreenRect( const size_t i_nItemPos ) const;
     402             : 
     403             :         void                        FocusItem( const ::boost::optional< size_t >& i_rItemPos );
     404             : 
     405           0 :         inline bool                 IsVertical() const
     406             :         {
     407           0 :             return  (   ( m_eTabAlignment == TABS_LEFT )
     408           0 :                     ||  ( m_eTabAlignment == TABS_RIGHT )
     409           0 :                     );
     410             :         }
     411             : 
     412             :     protected:
     413             :         DECL_LINK( OnScroll, const PushButton* );
     414             : 
     415             :         void        impl_calcItemRects();
     416             :         Size        impl_calculateItemContentSize( const PToolPanel& i_pPanel, const TabItemContent i_eItemContent ) const;
     417             :         void        impl_renderItemContent(vcl::RenderContext& rRenderContext, const PToolPanel& i_pPanel,
     418             :                                            const Rectangle& i_rContentArea, const TabItemContent i_eItemContent) const;
     419             :         ItemFlags   impl_getItemFlags( const size_t i_nItemIndex ) const;
     420             : 
     421             :     public:
     422             :         PanelTabBar&                m_rTabBar;
     423             :         TabBarGeometry              m_aGeometry;
     424             :         NormalizedArea              m_aNormalizer;
     425             :         TabAlignment                m_eTabAlignment;
     426             :         IToolPanelDeck&             m_rPanelDeck;
     427             : 
     428             :         ScopedVclPtr<VirtualDevice> m_aRenderDevice;
     429             :         PTabBarRenderer             m_pRenderer;
     430             : 
     431             :         boost::optional<size_t>     m_aHoveredItem;
     432             :         boost::optional<size_t>     m_aFocusedItem;
     433             :         bool                        m_bMouseButtonDown;
     434             : 
     435             :         ItemDescriptors             m_aItems;
     436             :         bool                        m_bItemsDirty;
     437             : 
     438             :         VclPtr<PushButton>          m_aScrollBack;
     439             :         VclPtr<PushButton>          m_aScrollForward;
     440             : 
     441             :         size_t                      m_nScrollPosition;
     442             :     };
     443             : 
     444             : 
     445             :     //= helper
     446             : 
     447             :     namespace
     448             :     {
     449             : 
     450             :     #if OSL_DEBUG_LEVEL > 0
     451             :         static void lcl_checkConsistency( const PanelTabBar_Impl& i_rImpl )
     452             :         {
     453             :             if ( !i_rImpl.m_bItemsDirty )
     454             :             {
     455             :                 if ( i_rImpl.m_rPanelDeck.GetPanelCount() != i_rImpl.m_aItems.size() )
     456             :                 {
     457             :                     OSL_FAIL( "lcl_checkConsistency: inconsistent array sizes!" );
     458             :                     return;
     459             :                 }
     460             :                 for ( size_t i = 0; i < i_rImpl.m_rPanelDeck.GetPanelCount(); ++i )
     461             :                 {
     462             :                     if ( i_rImpl.m_rPanelDeck.GetPanel( i ).get() != i_rImpl.m_aItems[i].pPanel.get() )
     463             :                     {
     464             :                         OSL_FAIL( "lcl_checkConsistency: array elements are inconsistent!" );
     465             :                         return;
     466             :                     }
     467             :                 }
     468             :             }
     469             :         }
     470             : 
     471             :         #define DBG_CHECK( data ) \
     472             :             lcl_checkConsistency( data );
     473             :     #else
     474             :         #define DBG_CHECK( data ) \
     475             :             (void)data;
     476             :     #endif
     477             : 
     478             : 
     479             :         class ClipItemRegion
     480             :         {
     481             :         public:
     482           0 :             explicit ClipItemRegion( const PanelTabBar_Impl& i_rImpl )
     483           0 :                 :m_rDevice( i_rImpl.m_rTabBar )
     484             :             {
     485           0 :                 m_rDevice.Push( PushFlags::CLIPREGION );
     486             :                 m_rDevice.SetClipRegion(vcl::Region(
     487             :                     i_rImpl.m_aNormalizer.getTransformed(
     488           0 :                         i_rImpl.m_aGeometry.getItemsRect(),
     489           0 :                         i_rImpl.m_eTabAlignment )));
     490           0 :             }
     491             : 
     492           0 :             ~ClipItemRegion()
     493             :             {
     494           0 :                 m_rDevice.Pop();
     495           0 :             }
     496             : 
     497             :         private:
     498             :             OutputDevice&   m_rDevice;
     499             :         };
     500             :     }
     501             : 
     502             : 
     503             :     //= PanelTabBar_Impl - implementation
     504             : 
     505             : 
     506           0 :     PanelTabBar_Impl::PanelTabBar_Impl( PanelTabBar& i_rTabBar, IToolPanelDeck& i_rPanelDeck, const TabAlignment i_eAlignment, const TabItemContent i_eItemContent )
     507             :         :m_rTabBar( i_rTabBar )
     508             :         ,m_aGeometry( i_eItemContent )
     509             :         ,m_aNormalizer()
     510             :         ,m_eTabAlignment( i_eAlignment )
     511             :         ,m_rPanelDeck( i_rPanelDeck )
     512             :         ,m_aRenderDevice( VclPtr<VirtualDevice>::Create(i_rTabBar) )
     513             :         ,m_pRenderer()
     514             :         ,m_aHoveredItem()
     515             :         ,m_aFocusedItem()
     516             :         ,m_bMouseButtonDown( false )
     517             :         ,m_aItems()
     518             :         ,m_bItemsDirty( true )
     519             :         ,m_aScrollBack( VclPtr<PushButton>::Create(&i_rTabBar, WB_BEVELBUTTON) )
     520             :         ,m_aScrollForward( VclPtr<PushButton>::Create(&i_rTabBar, WB_BEVELBUTTON) )
     521           0 :         ,m_nScrollPosition( 0 )
     522             :     {
     523             : #ifdef WNT
     524             :         if (m_aRenderDevice->IsNativeControlSupported(CTRL_TAB_ITEM, PART_ENTIRE_CONTROL))
     525             :             // this mode requires the NWF framework to be able to render those items onto a virtual
     526             :             // device. For some frameworks (some GTK themes, in particular), this is known to fail.
     527             :             // So, be on the safe side for the moment.
     528             :             m_pRenderer.reset(new NWFTabItemRenderer(*m_aRenderDevice.get()));
     529             :         else
     530             : #endif
     531           0 :         if (m_aRenderDevice->IsNativeControlSupported(CTRL_TOOLBAR, PART_BUTTON))
     532           0 :             m_pRenderer.reset(new NWFToolboxItemRenderer(*m_aRenderDevice.get()));
     533             :         else
     534           0 :             m_pRenderer.reset(new VCLItemRenderer(*m_aRenderDevice.get()));
     535             : 
     536           0 :         m_aRenderDevice->SetLineColor();
     537             : 
     538           0 :         m_rPanelDeck.AddListener( *this );
     539             : 
     540           0 :         m_aScrollBack->SetSymbol( IsVertical() ? SymbolType::ARROW_UP : SymbolType::ARROW_LEFT );
     541           0 :         m_aScrollBack->Show();
     542           0 :         m_aScrollBack->SetClickHdl( LINK( this, PanelTabBar_Impl, OnScroll ) );
     543           0 :         m_aScrollBack->SetAccessibleDescription( SvtResId( STR_SVT_TOOL_PANEL_BUTTON_FWD ).toString() );
     544           0 :         m_aScrollBack->SetAccessibleName( m_aScrollBack->GetAccessibleDescription() );
     545             : 
     546           0 :         m_aScrollForward->SetSymbol( IsVertical() ? SymbolType::ARROW_DOWN : SymbolType::ARROW_RIGHT );
     547           0 :         m_aScrollForward->Show();
     548           0 :         m_aScrollForward->SetClickHdl( LINK( this, PanelTabBar_Impl, OnScroll ) );
     549           0 :         m_aScrollForward->SetAccessibleDescription( SvtResId( STR_SVT_TOOL_PANEL_BUTTON_BACK ).toString() );
     550           0 :         m_aScrollForward->SetAccessibleName( m_aScrollForward->GetAccessibleDescription() );
     551           0 :     }
     552             : 
     553             : 
     554           0 :     void PanelTabBar_Impl::impl_calcItemRects()
     555             :     {
     556           0 :         m_aItems.resize(0);
     557             : 
     558           0 :         Point aCompletePos( m_aGeometry.getFirstItemPosition() );
     559           0 :         Point aIconOnlyPos( aCompletePos );
     560           0 :         Point aTextOnlyPos( aCompletePos );
     561             : 
     562           0 :         for (   size_t i = 0;
     563           0 :                 i < m_rPanelDeck.GetPanelCount();
     564             :                 ++i
     565             :             )
     566             :         {
     567           0 :             PToolPanel pPanel( m_rPanelDeck.GetPanel( i ) );
     568             : 
     569           0 :             ItemDescriptor aItem;
     570           0 :             aItem.pPanel = pPanel;
     571             : 
     572           0 :             const Size aCompleteSize( impl_calculateItemContentSize( pPanel, TABITEM_IMAGE_AND_TEXT ) );
     573           0 :             const Size aIconOnlySize( impl_calculateItemContentSize( pPanel, TABITEM_IMAGE_ONLY ) );
     574           0 :             const Size aTextOnlySize( impl_calculateItemContentSize( pPanel, TABITEM_TEXT_ONLY ) );
     575             : 
     576             :             // TODO: have one method calculating all sizes?
     577             : 
     578             :             // remember the three areas
     579           0 :             aItem.aCompleteArea = Rectangle( aCompletePos, aCompleteSize );
     580           0 :             aItem.aIconOnlyArea = Rectangle( aIconOnlyPos, aIconOnlySize );
     581           0 :             aItem.aTextOnlyArea = Rectangle( aTextOnlyPos, aTextOnlySize );
     582             : 
     583           0 :             m_aItems.push_back( aItem );
     584             : 
     585           0 :             aCompletePos = aItem.aCompleteArea.TopRight();
     586           0 :             aIconOnlyPos = aItem.aIconOnlyArea.TopRight();
     587           0 :             aTextOnlyPos = aItem.aTextOnlyArea.TopRight();
     588           0 :         }
     589             : 
     590           0 :         m_bItemsDirty = false;
     591           0 :     }
     592             : 
     593             : 
     594           0 :     Size PanelTabBar_Impl::impl_calculateItemContentSize( const PToolPanel& i_pPanel, const TabItemContent i_eItemContent ) const
     595             :     {
     596             :         // calculate the size needed for the content
     597             :         OSL_ENSURE( i_eItemContent != TABITEM_AUTO, "PanelTabBar_Impl::impl_calculateItemContentSize: illegal TabItemContent value!" );
     598             : 
     599           0 :         const Image aImage( i_pPanel->GetImage() );
     600           0 :         const bool bUseImage = !!aImage && ( i_eItemContent != TABITEM_TEXT_ONLY );
     601             : 
     602           0 :         const OUString sItemText( i_pPanel->GetDisplayName() );
     603           0 :         const bool bUseText = ( !sItemText.isEmpty() ) && ( i_eItemContent != TABITEM_IMAGE_ONLY );
     604             : 
     605           0 :         Size aItemContentSize;
     606           0 :         if ( bUseImage )
     607             :         {
     608           0 :             aItemContentSize = aImage.GetSizePixel();
     609             :         }
     610             : 
     611           0 :         if ( bUseText )
     612             :         {
     613           0 :             if ( bUseImage )
     614           0 :                 aItemContentSize.Width() += ITEM_ICON_TEXT_DISTANCE;
     615             : 
     616             :             // add space for text
     617           0 :             const Size aTextSize( m_rTabBar.GetCtrlTextWidth( sItemText ), m_rTabBar.GetTextHeight() );
     618           0 :             aItemContentSize.Width() += aTextSize.Width();
     619           0 :             aItemContentSize.Height() = ::std::max( aItemContentSize.Height(), aTextSize.Height() );
     620             : 
     621           0 :             aItemContentSize.Width() += 2 * ITEM_TEXT_FLOW_SPACE;
     622             :         }
     623             : 
     624           0 :         if ( !bUseImage && !bUseText )
     625             :         {
     626             :             // have a minimal size - this is pure heuristics, but if it doesn't suit your needs, then give your panels
     627             :             // a name and or image! :)
     628           0 :             aItemContentSize = Size( 16, 16 );
     629             :         }
     630             : 
     631           0 :         aItemContentSize.Width() += 2 * ITEM_OUTER_SPACE;
     632           0 :         aItemContentSize.Height() += 2 * ITEM_OUTER_SPACE;
     633             : 
     634           0 :         return aItemContentSize;
     635             :     }
     636             : 
     637             : 
     638           0 :     void PanelTabBar_Impl::impl_renderItemContent(vcl::RenderContext& rRenderContext, const PToolPanel& i_pPanel, const Rectangle& i_rContentArea, const TabItemContent i_eItemContent) const
     639             :     {
     640             :         OSL_ENSURE(i_eItemContent != TABITEM_AUTO, "PanelTabBar_Impl::impl_renderItemContent: illegal TabItemContent value!");
     641             : 
     642           0 :         Rectangle aRenderArea(i_rContentArea);
     643           0 :         if (IsVertical())
     644             :         {
     645           0 :             aRenderArea.Top() += ITEM_OUTER_SPACE;
     646             :         }
     647             :         else
     648             :         {
     649           0 :             aRenderArea.Left() += ITEM_OUTER_SPACE;
     650             :         }
     651             : 
     652             :         // draw the image
     653           0 :         const Image aItemImage(i_pPanel->GetImage());
     654           0 :         const Size aImageSize(aItemImage.GetSizePixel());
     655           0 :         const bool bUseImage = !!aItemImage && (i_eItemContent != TABITEM_TEXT_ONLY);
     656             : 
     657           0 :         if (bUseImage)
     658             :         {
     659           0 :             Point aImagePos;
     660           0 :             if (IsVertical())
     661             :             {
     662           0 :                 aImagePos.X() = aRenderArea.Left() + (aRenderArea.GetWidth() - aImageSize.Width()) / 2;
     663           0 :                 aImagePos.Y() = aRenderArea.Top();
     664             :             }
     665             :             else
     666             :             {
     667           0 :                 aImagePos.X() = aRenderArea.Left();
     668           0 :                 aImagePos.Y() = aRenderArea.Top() + (aRenderArea.GetHeight() - aImageSize.Height()) / 2;
     669             :             }
     670           0 :             rRenderContext.DrawImage(aImagePos, aItemImage);
     671             :         }
     672             : 
     673           0 :         const OUString sItemText(i_pPanel->GetDisplayName());
     674           0 :         const bool bUseText = (!sItemText.isEmpty()) && (i_eItemContent != TABITEM_IMAGE_ONLY);
     675             : 
     676           0 :         if (bUseText)
     677             :         {
     678           0 :             if (IsVertical())
     679             :             {
     680           0 :                 if (bUseImage)
     681           0 :                     aRenderArea.Top() += aImageSize.Height() + ITEM_ICON_TEXT_DISTANCE;
     682           0 :                 aRenderArea.Top() += ITEM_TEXT_FLOW_SPACE;
     683             :             }
     684             :             else
     685             :             {
     686           0 :                 if (bUseImage)
     687           0 :                     aRenderArea.Left() += aImageSize.Width() + ITEM_ICON_TEXT_DISTANCE;
     688           0 :                 aRenderArea.Left() += ITEM_TEXT_FLOW_SPACE;
     689             :             }
     690             : 
     691             :             // draw the text
     692           0 :             const Size aTextSize(m_rTabBar.GetCtrlTextWidth(sItemText), rRenderContext.GetTextHeight());
     693           0 :             Point aTextPos(aRenderArea.TopLeft());
     694           0 :             if (IsVertical())
     695             :             {
     696           0 :                 rRenderContext.Push(PushFlags::FONT);
     697             : 
     698           0 :                 vcl::Font aFont(rRenderContext.GetFont());
     699           0 :                 aFont.SetOrientation(2700);
     700           0 :                 aFont.SetVertical(true);
     701           0 :                 rRenderContext.SetFont(aFont);
     702             : 
     703           0 :                 aTextPos.X() += aTextSize.Height();
     704           0 :                 aTextPos.X() += (aRenderArea.GetWidth() - aTextSize.Height()) / 2;
     705             :             }
     706             :             else
     707             :             {
     708           0 :                 aTextPos.Y() += (aRenderArea.GetHeight() - aTextSize.Height()) / 2;
     709             :             }
     710             : 
     711           0 :             rRenderContext.DrawText(aTextPos, sItemText);
     712             : 
     713           0 :             if (IsVertical())
     714             :             {
     715           0 :                 rRenderContext.Pop();
     716             :             }
     717           0 :         }
     718           0 :     }
     719             : 
     720           0 :     void PanelTabBar_Impl::CopyFromRenderDevice(vcl::RenderContext& rRenderContext, const Rectangle& i_rLogicalRect) const
     721             :     {
     722           0 :         BitmapEx aBitmap(m_aRenderDevice->GetBitmapEx(i_rLogicalRect.TopLeft(),
     723           0 :                                                       Size(i_rLogicalRect.GetSize().Width(),
     724           0 :                                                            i_rLogicalRect.GetSize().Height())));
     725           0 :         if (IsVertical())
     726             :         {
     727           0 :             aBitmap.Rotate(2700, COL_BLACK);
     728           0 :             if (m_eTabAlignment == TABS_LEFT)
     729           0 :                 aBitmap.Mirror(BmpMirrorFlags::Horizontal);
     730             :         }
     731           0 :         else if (m_eTabAlignment == TABS_BOTTOM)
     732             :         {
     733           0 :             aBitmap.Mirror(BmpMirrorFlags::Vertical);
     734             :         }
     735             : 
     736           0 :         const Rectangle aActualRect(m_aNormalizer.getTransformed(i_rLogicalRect, m_eTabAlignment));
     737           0 :         rRenderContext.DrawBitmapEx(aActualRect.TopLeft(), aBitmap);
     738           0 :     }
     739             : 
     740             : 
     741           0 :     void PanelTabBar_Impl::InvalidateItem( const size_t i_nItemIndex, const ItemFlags i_nAdditionalItemFlags ) const
     742             :     {
     743           0 :         const ItemDescriptor& rItem( m_aItems[ i_nItemIndex ] );
     744           0 :         const ItemFlags nItemFlags( impl_getItemFlags( i_nItemIndex ) | i_nAdditionalItemFlags );
     745             : 
     746           0 :         const Rectangle aNormalizedContent( GetActualLogicalItemRect( rItem.GetCurrentRect() ) );
     747           0 :         const Rectangle aNormalizedBounds( m_pRenderer->calculateDecorations( aNormalizedContent, nItemFlags ) );
     748             : 
     749           0 :         const Rectangle aActualBounds = m_aNormalizer.getTransformed( aNormalizedBounds, m_eTabAlignment );
     750           0 :         m_rTabBar.Invalidate( aActualBounds );
     751           0 :     }
     752             : 
     753             : 
     754           0 :     ItemFlags PanelTabBar_Impl::impl_getItemFlags( const size_t i_nItemIndex ) const
     755             :     {
     756           0 :         ItemFlags nItemFlags( ITEM_STATE_NORMAL );
     757           0 :         if ( m_aHoveredItem == i_nItemIndex )
     758             :         {
     759           0 :             nItemFlags |= ITEM_STATE_HOVERED;
     760           0 :             if ( m_bMouseButtonDown )
     761           0 :                 nItemFlags |= ITEM_STATE_ACTIVE;
     762             :         }
     763             : 
     764           0 :         if ( m_rPanelDeck.GetActivePanel() == i_nItemIndex )
     765           0 :             nItemFlags |= ITEM_STATE_ACTIVE;
     766             : 
     767           0 :         if ( m_aFocusedItem == i_nItemIndex )
     768           0 :             nItemFlags |= ITEM_STATE_FOCUSED;
     769             : 
     770           0 :         if ( 0 == i_nItemIndex )
     771           0 :             nItemFlags |= ITEM_POSITION_FIRST;
     772             : 
     773           0 :         if ( m_rPanelDeck.GetPanelCount() - 1 == i_nItemIndex )
     774           0 :             nItemFlags |= ITEM_POSITION_LAST;
     775             : 
     776           0 :         return nItemFlags;
     777             :     }
     778             : 
     779             : 
     780           0 :     void PanelTabBar_Impl::DrawItem(vcl::RenderContext& rRenderContext, const size_t i_nItemIndex, const Rectangle& i_rBoundaries) const
     781             :     {
     782           0 :         const ItemDescriptor& rItem(m_aItems[i_nItemIndex]);
     783           0 :         const ItemFlags nItemFlags(impl_getItemFlags(i_nItemIndex));
     784             : 
     785             :         // the normalized bounding and content rect
     786           0 :         const Rectangle aNormalizedContent(GetActualLogicalItemRect(rItem.GetCurrentRect()));
     787           0 :         const Rectangle aNormalizedBounds(m_pRenderer->calculateDecorations(aNormalizedContent, nItemFlags));
     788             : 
     789             :         // check whether the item actually overlaps with the painting area
     790           0 :         if (!i_rBoundaries.IsEmpty())
     791             :         {
     792           0 :             const Rectangle aItemRect(GetActualLogicalItemRect(rItem.GetCurrentRect()));
     793           0 :             if (!aItemRect.IsOver(i_rBoundaries))
     794           0 :                 return;
     795             :         }
     796             : 
     797           0 :         m_rTabBar.SetUpdateMode(false);
     798             : 
     799             :         // the aligned bounding and content rect
     800           0 :         const Rectangle aActualBounds = m_aNormalizer.getTransformed( aNormalizedBounds, m_eTabAlignment );
     801           0 :         const Rectangle aActualContent = m_aNormalizer.getTransformed( aNormalizedContent, m_eTabAlignment );
     802             : 
     803             :         // render item "background" layer
     804           0 :         m_pRenderer->preRenderItem(aNormalizedContent, nItemFlags);
     805             : 
     806             :         // copy from the virtual device to ourself
     807           0 :         CopyFromRenderDevice(rRenderContext, aNormalizedBounds);
     808             : 
     809             :         // render the actual item content
     810           0 :         impl_renderItemContent(rRenderContext, rItem.pPanel, aActualContent, rItem.eContent);
     811             : 
     812             :         // render item "foreground" layer
     813           0 :         m_pRenderer->postRenderItem(m_rTabBar, aActualBounds, nItemFlags);
     814             : 
     815           0 :         m_rTabBar.SetUpdateMode(true);
     816             :     }
     817             : 
     818             : 
     819           0 :     void PanelTabBar_Impl::EnsureItemsCache()
     820             :     {
     821           0 :         if ( !m_bItemsDirty )
     822             :         {
     823             :             DBG_CHECK( *this );
     824           0 :             return;
     825             :         }
     826           0 :         impl_calcItemRects();
     827             :         SAL_WARN_IF( m_bItemsDirty , "svtools", "PanelTabBar_Impl::EnsureItemsCache: cache still dirty!" );
     828             :         DBG_CHECK( *this );
     829             :     }
     830             : 
     831             : 
     832           0 :     void PanelTabBar_Impl::Relayout()
     833             :     {
     834           0 :         EnsureItemsCache();
     835             : 
     836           0 :         const Size aOutputSize( m_rTabBar.GetOutputSizePixel() );
     837           0 :         m_aNormalizer = NormalizedArea( Rectangle( Point(), aOutputSize ), IsVertical() );
     838           0 :         const Size aLogicalOutputSize( m_aNormalizer.getReferenceSize() );
     839             : 
     840             :         // forward actual output size to our render device
     841           0 :         m_aRenderDevice->SetOutputSizePixel( aLogicalOutputSize );
     842             : 
     843             :         // re-calculate the size of the scroll buttons and of the items
     844           0 :         m_aGeometry.relayout( aLogicalOutputSize, m_aItems );
     845             : 
     846           0 :         if ( m_aGeometry.getButtonBackRect().IsEmpty() )
     847             :         {
     848           0 :             m_aScrollBack->Hide();
     849             :         }
     850             :         else
     851             :         {
     852           0 :             const Rectangle aButtonBack( m_aNormalizer.getTransformed( m_aGeometry.getButtonBackRect(), m_eTabAlignment ) );
     853           0 :             m_aScrollBack->SetPosSizePixel( aButtonBack.TopLeft(), aButtonBack.GetSize() );
     854           0 :             m_aScrollBack->Show();
     855             :         }
     856             : 
     857           0 :         if ( m_aGeometry.getButtonForwardRect().IsEmpty() )
     858             :         {
     859           0 :             m_aScrollForward->Hide();
     860             :         }
     861             :         else
     862             :         {
     863           0 :             const Rectangle aButtonForward( m_aNormalizer.getTransformed( m_aGeometry.getButtonForwardRect(), m_eTabAlignment ) );
     864           0 :             m_aScrollForward->SetPosSizePixel( aButtonForward.TopLeft(), aButtonForward.GetSize() );
     865           0 :             m_aScrollForward->Show();
     866             :         }
     867             : 
     868           0 :         UpdateScrollButtons();
     869           0 :     }
     870             : 
     871             : 
     872           0 :     ::boost::optional< size_t > PanelTabBar_Impl::FindItemForPoint( const Point& i_rPoint ) const
     873             :     {
     874           0 :         Point aPoint( IsVertical() ? i_rPoint.Y() : i_rPoint.X(), IsVertical() ? i_rPoint.X() : i_rPoint.Y() );
     875             : 
     876           0 :         if ( !m_aGeometry.getItemsRect().IsInside( aPoint ) )
     877           0 :             return ::boost::optional< size_t >();
     878             : 
     879           0 :         size_t i=0;
     880           0 :         for (   ItemDescriptors::const_iterator item = m_aItems.begin();
     881           0 :                 item != m_aItems.end();
     882             :                 ++item, ++i
     883             :             )
     884             :         {
     885           0 :             Rectangle aItemRect( GetActualLogicalItemRect( item->GetCurrentRect() ) );
     886           0 :             if ( aItemRect.IsInside( aPoint ) )
     887             :             {
     888           0 :                 return ::boost::optional< size_t >( i );
     889             :             }
     890             :         }
     891           0 :         return ::boost::optional< size_t >();
     892             :     }
     893             : 
     894             : 
     895           0 :     Rectangle PanelTabBar_Impl::GetItemScreenRect( const size_t i_nItemPos ) const
     896             :     {
     897           0 :         ENSURE_OR_RETURN( i_nItemPos < m_aItems.size(), "PanelTabBar_Impl::GetItemScreenRect: invalid item pos!", Rectangle() );
     898           0 :         const ItemDescriptor& rItem( m_aItems[ i_nItemPos ] );
     899             :         const Rectangle aItemRect( m_aNormalizer.getTransformed(
     900           0 :             GetActualLogicalItemRect( rItem.GetCurrentRect() ),
     901           0 :             m_eTabAlignment ) );
     902             : 
     903           0 :         const Rectangle aTabBarRect( m_rTabBar.GetWindowExtentsRelative( NULL ) );
     904             :         return Rectangle(
     905           0 :             Point( aTabBarRect.Left() + aItemRect.Left(), aTabBarRect.Top() + aItemRect.Top() ),
     906             :             aItemRect.GetSize()
     907           0 :         );
     908             :     }
     909             : 
     910             : 
     911           0 :     void PanelTabBar_Impl::FocusItem( const ::boost::optional< size_t >& i_rItemPos )
     912             :     {
     913             :         // reset old focus item
     914           0 :         if ( !!m_aFocusedItem )
     915           0 :             InvalidateItem( *m_aFocusedItem );
     916           0 :         m_aFocusedItem.reset();
     917             : 
     918             :         // mark the active icon as focused
     919           0 :         if ( !!i_rItemPos )
     920             :         {
     921           0 :             m_aFocusedItem = i_rItemPos;
     922           0 :             InvalidateItem( *m_aFocusedItem );
     923             :         }
     924           0 :     }
     925             : 
     926             : 
     927           0 :     IMPL_LINK( PanelTabBar_Impl, OnScroll, const PushButton*, i_pButton )
     928             :     {
     929           0 :         if ( i_pButton == m_aScrollBack.get() )
     930             :         {
     931             :             OSL_ENSURE( m_nScrollPosition > 0, "PanelTabBar_Impl::OnScroll: inconsistency!" );
     932           0 :             --m_nScrollPosition;
     933           0 :             m_rTabBar.Invalidate();
     934             :         }
     935           0 :         else if ( i_pButton == m_aScrollForward.get() )
     936             :         {
     937             :             OSL_ENSURE( m_nScrollPosition < m_aItems.size() - 1, "PanelTabBar_Impl::OnScroll: inconsistency!" );
     938           0 :             ++m_nScrollPosition;
     939           0 :             m_rTabBar.Invalidate();
     940             :         }
     941             : 
     942           0 :         UpdateScrollButtons();
     943             : 
     944           0 :         return 0L;
     945             :     }
     946             : 
     947             : 
     948           0 :     Rectangle PanelTabBar_Impl::GetActualLogicalItemRect( const Rectangle& i_rLogicalItemRect ) const
     949             :     {
     950             :         // care for the offset imposed by our geometry, i.e. whether or not we have scroll buttons
     951           0 :         Rectangle aItemRect( i_rLogicalItemRect );
     952           0 :         aItemRect.Move( m_aGeometry.getItemsRect().Left() - m_aGeometry.getButtonBackRect().Left(), 0 );
     953             : 
     954             :         // care for the current scroll position
     955             :         OSL_ENSURE( m_nScrollPosition < m_aItems.size(), "GetActualLogicalItemRect: invalid scroll position!" );
     956           0 :         if ( ( m_nScrollPosition > 0 ) && ( m_nScrollPosition < m_aItems.size() ) )
     957             :         {
     958           0 :             long nOffsetX = m_aItems[ m_nScrollPosition ].GetCurrentRect().Left() - m_aItems[ 0 ].GetCurrentRect().Left();
     959           0 :             long nOffsetY = m_aItems[ m_nScrollPosition ].GetCurrentRect().Top() - m_aItems[ 0 ].GetCurrentRect().Top();
     960           0 :             aItemRect.Move( -nOffsetX, -nOffsetY );
     961             :         }
     962             : 
     963           0 :         return aItemRect;
     964             :     }
     965             : 
     966             : 
     967             :     //= PanelTabBar_Impl
     968             : 
     969             : 
     970           0 :     void PanelTabBar_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive )
     971             :     {
     972           0 :         EnsureItemsCache();
     973             : 
     974           0 :         if ( !!i_rOldActive )
     975           0 :             InvalidateItem( *i_rOldActive, ITEM_STATE_ACTIVE );
     976           0 :         if ( !!i_rNewActive )
     977           0 :             InvalidateItem( *i_rNewActive );
     978           0 :     }
     979             : 
     980             : 
     981           0 :     void PanelTabBar_Impl::LayouterChanged( const PDeckLayouter& i_rNewLayouter )
     982             :     {
     983             :         // not interested in
     984             :         (void)i_rNewLayouter;
     985           0 :     }
     986             : 
     987             : 
     988           0 :     void PanelTabBar_Impl::Dying()
     989             :     {
     990             :         // not interested in - the notifier is a member of this instance here, so we're dying ourself at the moment
     991           0 :     }
     992             : 
     993             : 
     994             :     //= PanelTabBar
     995             : 
     996             : 
     997           0 :     PanelTabBar::PanelTabBar( vcl::Window& i_rParentWindow, IToolPanelDeck& i_rPanelDeck, const TabAlignment i_eAlignment, const TabItemContent i_eItemContent )
     998             :         :Control( &i_rParentWindow, 0 )
     999           0 :         ,m_pImpl( new PanelTabBar_Impl( *this, i_rPanelDeck, i_eAlignment, i_eItemContent ) )
    1000             :     {
    1001           0 :         DBG_CHECK( *m_pImpl );
    1002           0 :     }
    1003             : 
    1004           0 :     PanelTabBar::~PanelTabBar()
    1005             :     {
    1006           0 :         disposeOnce();
    1007           0 :     }
    1008             : 
    1009           0 :     void PanelTabBar::dispose()
    1010             :     {
    1011           0 :         Control::dispose();
    1012           0 :     }
    1013             : 
    1014           0 :     TabItemContent PanelTabBar::GetTabItemContent() const
    1015             :     {
    1016           0 :         return m_pImpl->m_aGeometry.getItemContent();
    1017             :     }
    1018             : 
    1019             : 
    1020           0 :     void PanelTabBar::SetTabItemContent( const TabItemContent& i_eItemContent )
    1021             :     {
    1022           0 :         m_pImpl->m_aGeometry.setItemContent( i_eItemContent );
    1023           0 :         m_pImpl->Relayout();
    1024           0 :         Invalidate();
    1025           0 :     }
    1026             : 
    1027             : 
    1028           0 :     IToolPanelDeck& PanelTabBar::GetPanelDeck() const
    1029             :     {
    1030           0 :         DBG_CHECK( *m_pImpl );
    1031           0 :         return m_pImpl->m_rPanelDeck;
    1032             :     }
    1033             : 
    1034             : 
    1035           0 :     Size PanelTabBar::GetOptimalSize() const
    1036             :     {
    1037           0 :         m_pImpl->EnsureItemsCache();
    1038           0 :         Size aOptimalSize(m_pImpl->m_aGeometry.getOptimalSize(m_pImpl->m_aItems));
    1039           0 :         if ( m_pImpl->IsVertical() )
    1040           0 :             ::std::swap( aOptimalSize.Width(), aOptimalSize.Height() );
    1041           0 :         return aOptimalSize;
    1042             :     }
    1043             : 
    1044             : 
    1045           0 :     void PanelTabBar::Resize()
    1046             :     {
    1047           0 :         Control::Resize();
    1048           0 :         m_pImpl->Relayout();
    1049           0 :     }
    1050             : 
    1051             : 
    1052           0 :     void PanelTabBar::Paint(vcl::RenderContext& rRenderContext, const Rectangle& i_rRect)
    1053             :     {
    1054           0 :         m_pImpl->EnsureItemsCache();
    1055             : 
    1056             :         // background
    1057           0 :         const Rectangle aNormalizedPaintArea(m_pImpl->m_aNormalizer.getNormalized(i_rRect, m_pImpl->m_eTabAlignment));
    1058           0 :         m_pImpl->m_aRenderDevice->Push(PushFlags::CLIPREGION);
    1059           0 :         m_pImpl->m_aRenderDevice->SetClipRegion(vcl::Region(aNormalizedPaintArea));
    1060           0 :         m_pImpl->m_pRenderer->renderBackground();
    1061           0 :         m_pImpl->m_aRenderDevice->Pop();
    1062           0 :         m_pImpl->CopyFromRenderDevice(rRenderContext, aNormalizedPaintArea);
    1063             : 
    1064             :         // ensure the items really paint into their own playground only
    1065           0 :         ClipItemRegion aClipItems(*m_pImpl);
    1066             : 
    1067           0 :         const Rectangle aLogicalPaintRect(m_pImpl->m_aNormalizer.getNormalized(i_rRect, m_pImpl->m_eTabAlignment));
    1068             : 
    1069           0 :         const boost::optional<size_t> aActivePanel(m_pImpl->m_rPanelDeck.GetActivePanel());
    1070           0 :         const boost::optional<size_t> aHoveredPanel(m_pImpl->m_aHoveredItem);
    1071             : 
    1072             :         // items:
    1073             :         // 1. paint all non-active, non-hovered items
    1074           0 :         size_t i = 0;
    1075           0 :         ItemDescriptors::const_iterator item;
    1076           0 :         for (item = m_pImpl->m_aItems.begin(); item != m_pImpl->m_aItems.end(); ++item, ++i)
    1077             :         {
    1078           0 :             if (i == aActivePanel)
    1079           0 :                 continue;
    1080             : 
    1081           0 :             if (aHoveredPanel == i)
    1082           0 :                 continue;
    1083             : 
    1084           0 :             m_pImpl->DrawItem(rRenderContext, i, aLogicalPaintRect);
    1085             :         }
    1086             : 
    1087             :         // 2. paint the item which is hovered, /without/ the mouse button pressed down
    1088           0 :         if (!!aHoveredPanel && !m_pImpl->m_bMouseButtonDown)
    1089           0 :             m_pImpl->DrawItem(rRenderContext, *aHoveredPanel, aLogicalPaintRect);
    1090             : 
    1091             :         // 3. paint the active item
    1092           0 :         if (!!aActivePanel)
    1093           0 :             m_pImpl->DrawItem(rRenderContext, *aActivePanel, aLogicalPaintRect);
    1094             : 
    1095             :         // 4. paint the item which is hovered, /with/ the mouse button pressed down
    1096           0 :         if (!!aHoveredPanel && m_pImpl->m_bMouseButtonDown)
    1097           0 :             m_pImpl->DrawItem(rRenderContext, *aHoveredPanel, aLogicalPaintRect);
    1098           0 :     }
    1099             : 
    1100             : 
    1101           0 :     void PanelTabBar::MouseMove( const MouseEvent& i_rMouseEvent )
    1102             :     {
    1103           0 :         m_pImpl->EnsureItemsCache();
    1104             : 
    1105           0 :         boost::optional< size_t > aOldItem(m_pImpl->m_aHoveredItem);
    1106           0 :         boost::optional< size_t > aNewItem(m_pImpl->FindItemForPoint(i_rMouseEvent.GetPosPixel()));
    1107             : 
    1108           0 :         if (i_rMouseEvent.IsLeaveWindow())
    1109           0 :             aNewItem = boost::optional<size_t>();
    1110             : 
    1111             :         bool const bChanged(
    1112           0 :                 ( !aOldItem && aNewItem )
    1113           0 :                 || ( aOldItem && !aNewItem )
    1114           0 :                 || ( aOldItem && aNewItem && aOldItem != aNewItem ) );
    1115             : 
    1116           0 :         if (bChanged)
    1117             :         {
    1118           0 :             if (aOldItem)
    1119           0 :                 m_pImpl->InvalidateItem( *aOldItem );
    1120             : 
    1121           0 :             m_pImpl->m_aHoveredItem = aNewItem;
    1122             : 
    1123           0 :             if (aNewItem)
    1124           0 :                 m_pImpl->InvalidateItem( *aNewItem );
    1125           0 :         }
    1126           0 :     }
    1127             : 
    1128             : 
    1129           0 :     void PanelTabBar::MouseButtonDown( const MouseEvent& i_rMouseEvent )
    1130             :     {
    1131           0 :         Control::MouseButtonDown( i_rMouseEvent );
    1132             : 
    1133           0 :         if ( !i_rMouseEvent.IsLeft() )
    1134           0 :             return;
    1135             : 
    1136           0 :         m_pImpl->EnsureItemsCache();
    1137             : 
    1138           0 :         ::boost::optional< size_t > aHitItem( m_pImpl->FindItemForPoint( i_rMouseEvent.GetPosPixel() ) );
    1139           0 :         if ( !aHitItem )
    1140           0 :             return;
    1141             : 
    1142           0 :         CaptureMouse();
    1143           0 :         m_pImpl->m_bMouseButtonDown = true;
    1144             : 
    1145           0 :         m_pImpl->InvalidateItem( *aHitItem );
    1146             :     }
    1147             : 
    1148             : 
    1149           0 :     void PanelTabBar::MouseButtonUp( const MouseEvent& i_rMouseEvent )
    1150             :     {
    1151           0 :         Control::MouseButtonUp( i_rMouseEvent );
    1152             : 
    1153           0 :         if ( m_pImpl->m_bMouseButtonDown )
    1154             :         {
    1155           0 :             ::boost::optional< size_t > aHitItem( m_pImpl->FindItemForPoint( i_rMouseEvent.GetPosPixel() ) );
    1156           0 :             if ( !!aHitItem )
    1157             :             {
    1158             :                 // re-draw that item now that we're not in mouse-down mode anymore
    1159           0 :                 m_pImpl->InvalidateItem( *aHitItem );
    1160             :                 // activate the respective panel
    1161           0 :                 m_pImpl->m_rPanelDeck.ActivatePanel( *aHitItem );
    1162             :             }
    1163             : 
    1164             :             OSL_ENSURE( IsMouseCaptured(), "PanelTabBar::MouseButtonUp: inconsistency!" );
    1165           0 :             if ( IsMouseCaptured() )
    1166           0 :                 ReleaseMouse();
    1167           0 :             m_pImpl->m_bMouseButtonDown = false;
    1168             :         }
    1169           0 :     }
    1170             : 
    1171             : 
    1172           0 :     void PanelTabBar::RequestHelp( const HelpEvent& i_rHelpEvent )
    1173             :     {
    1174           0 :         m_pImpl->EnsureItemsCache();
    1175             : 
    1176           0 :         ::boost::optional< size_t > aHelpItem( m_pImpl->FindItemForPoint( ScreenToOutputPixel( i_rHelpEvent.GetMousePosPixel() ) ) );
    1177           0 :         if ( !aHelpItem )
    1178           0 :             return;
    1179             : 
    1180           0 :         const ItemDescriptor& rItem( m_pImpl->m_aItems[ *aHelpItem ] );
    1181           0 :         if ( rItem.eContent != TABITEM_IMAGE_ONLY )
    1182             :             // if the text is displayed for the item, we do not need to show it as tooltip
    1183           0 :             return;
    1184             : 
    1185           0 :         const OUString sItemText( rItem.pPanel->GetDisplayName() );
    1186           0 :         if ( i_rHelpEvent.GetMode() == HelpEventMode::BALLOON )
    1187           0 :             Help::ShowBalloon( this, OutputToScreenPixel( rItem.GetCurrentRect().Center() ), rItem.GetCurrentRect(), sItemText );
    1188             :         else
    1189           0 :             Help::ShowQuickHelp( this, rItem.GetCurrentRect(), sItemText );
    1190             :     }
    1191             : 
    1192             : 
    1193           0 :     void PanelTabBar::GetFocus()
    1194             :     {
    1195           0 :         Control::GetFocus();
    1196           0 :         if ( !m_pImpl->m_aFocusedItem )
    1197           0 :             m_pImpl->FocusItem( m_pImpl->m_rPanelDeck.GetActivePanel() );
    1198           0 :     }
    1199             : 
    1200             : 
    1201           0 :     void PanelTabBar::LoseFocus()
    1202             :     {
    1203           0 :         Control::LoseFocus();
    1204             : 
    1205           0 :         if ( m_pImpl )
    1206             :         {
    1207           0 :             if ( !!m_pImpl->m_aFocusedItem )
    1208           0 :                 m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem );
    1209             : 
    1210           0 :             m_pImpl->m_aFocusedItem.reset();
    1211             :         }
    1212           0 :     }
    1213             : 
    1214             : 
    1215             :     class KeyInputHandler
    1216             :     {
    1217             :     public:
    1218           0 :         KeyInputHandler( Control& i_rControl, const KeyEvent& i_rKeyEvent )
    1219             :             :m_rControl( i_rControl )
    1220             :             ,m_rKeyEvent( i_rKeyEvent )
    1221           0 :             ,m_bHandled( false )
    1222             :         {
    1223           0 :         }
    1224             : 
    1225           0 :         ~KeyInputHandler()
    1226             :         {
    1227           0 :             if ( !m_bHandled )
    1228           0 :                 m_rControl.Control::KeyInput( m_rKeyEvent );
    1229           0 :         }
    1230             : 
    1231           0 :         void   setHandled()
    1232             :         {
    1233           0 :             m_bHandled = true;
    1234           0 :         }
    1235             : 
    1236             :     private:
    1237             :         Control&        m_rControl;
    1238             :         const KeyEvent& m_rKeyEvent;
    1239             :         bool            m_bHandled;
    1240             :     };
    1241             : 
    1242             : 
    1243           0 :     void PanelTabBar::KeyInput( const KeyEvent& i_rKeyEvent )
    1244             :     {
    1245           0 :         KeyInputHandler aKeyInputHandler( *this, i_rKeyEvent );
    1246             : 
    1247           0 :         const vcl::KeyCode& rKeyCode( i_rKeyEvent.GetKeyCode() );
    1248           0 :         if ( rKeyCode.GetModifier() != 0 )
    1249             :             // only interested in mere key presses
    1250           0 :             return;
    1251             : 
    1252             :         // if there are less than 2 panels, we cannot travel them ...
    1253           0 :         const size_t nPanelCount( m_pImpl->m_rPanelDeck.GetPanelCount() );
    1254           0 :         if ( nPanelCount < 2 )
    1255           0 :             return;
    1256             : 
    1257             :         OSL_PRECOND( !!m_pImpl->m_aFocusedItem, "PanelTabBar::KeyInput: we should have a focused item here!" );
    1258             :             // if we get KeyInput events, we should have the focus. In this case, m_aFocusedItem should not be empty,
    1259             :             // except if there are no panels, but then we bail out of this method here earlier ...
    1260             : 
    1261           0 :         bool bFocusNext = false;
    1262           0 :         bool bFocusPrev = false;
    1263             : 
    1264           0 :         switch ( rKeyCode.GetCode() )
    1265             :         {
    1266           0 :         case KEY_UP:    bFocusPrev = true; break;
    1267           0 :         case KEY_DOWN:  bFocusNext = true; break;
    1268             :         case KEY_LEFT:
    1269           0 :             if ( IsRTLEnabled() )
    1270           0 :                 bFocusNext = true;
    1271             :             else
    1272           0 :                 bFocusPrev = true;
    1273           0 :             break;
    1274             :         case KEY_RIGHT:
    1275           0 :             if ( IsRTLEnabled() )
    1276           0 :                 bFocusPrev = true;
    1277             :             else
    1278           0 :                 bFocusNext = true;
    1279           0 :             break;
    1280             :         case KEY_RETURN:
    1281           0 :             m_pImpl->m_rPanelDeck.ActivatePanel( *m_pImpl->m_aFocusedItem );
    1282           0 :             break;
    1283             :         }
    1284             : 
    1285           0 :         if ( !bFocusNext && !bFocusPrev )
    1286           0 :             return;
    1287             : 
    1288           0 :         m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem );
    1289           0 :         if ( bFocusNext )
    1290             :         {
    1291           0 :             m_pImpl->m_aFocusedItem.reset( ( *m_pImpl->m_aFocusedItem + 1 ) % nPanelCount );
    1292             :         }
    1293             :         else
    1294             :         {
    1295           0 :             m_pImpl->m_aFocusedItem.reset( ( *m_pImpl->m_aFocusedItem + nPanelCount - 1 ) % nPanelCount );
    1296             :         }
    1297           0 :         m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem );
    1298             : 
    1299             :         // don't delegate to base class
    1300           0 :         aKeyInputHandler.setHandled();
    1301             :     }
    1302             : 
    1303             : 
    1304           0 :     void PanelTabBar::DataChanged( const DataChangedEvent& i_rDataChanedEvent )
    1305             :     {
    1306           0 :         Control::DataChanged( i_rDataChanedEvent );
    1307             : 
    1308           0 :         if  (   ( i_rDataChanedEvent.GetType() == DataChangedEventType::SETTINGS )
    1309           0 :             &&  ( i_rDataChanedEvent.GetFlags() & AllSettingsFlags::STYLE )
    1310             :             )
    1311             :         {
    1312           0 :             Invalidate();
    1313             :         }
    1314           0 :     }
    1315             : 
    1316             : 
    1317           0 :     bool PanelTabBar::IsVertical() const
    1318             :     {
    1319           0 :         return m_pImpl->IsVertical();
    1320             :     }
    1321             : 
    1322             : 
    1323           0 :     PushButton& PanelTabBar::GetScrollButton( const bool i_bForward )
    1324             :     {
    1325           0 :         return i_bForward ? *m_pImpl->m_aScrollForward.get() : *m_pImpl->m_aScrollBack.get();
    1326             :     }
    1327             : 
    1328             : 
    1329           0 :     ::boost::optional< size_t > PanelTabBar::GetFocusedPanelItem() const
    1330             :     {
    1331           0 :         return m_pImpl->m_aFocusedItem;
    1332             :     }
    1333             : 
    1334             : 
    1335           0 :     void PanelTabBar::FocusPanelItem( const size_t i_nItemPos )
    1336             :     {
    1337           0 :         ENSURE_OR_RETURN_VOID( i_nItemPos < m_pImpl->m_rPanelDeck.GetPanelCount(), "PanelTabBar::FocusPanelItem: illegal item pos!" );
    1338             : 
    1339           0 :         if ( !HasChildPathFocus() )
    1340           0 :             GrabFocus();
    1341             : 
    1342           0 :         m_pImpl->FocusItem( i_nItemPos );
    1343             :         SAL_WARN_IF( !m_pImpl->m_aFocusedItem, "svtools", "PanelTabBar::FocusPanelItem: have the focus, but no focused item?" );
    1344           0 :         if ( !!m_pImpl->m_aFocusedItem )
    1345           0 :             m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem );
    1346           0 :         m_pImpl->m_aFocusedItem.reset( i_nItemPos );
    1347             :     }
    1348             : 
    1349             : 
    1350           0 :     Rectangle PanelTabBar::GetItemScreenRect( const size_t i_nItemPos ) const
    1351             :     {
    1352           0 :         return m_pImpl->GetItemScreenRect( i_nItemPos );
    1353             :     }
    1354             : 
    1355             : 
    1356           0 :     Reference< XWindowPeer > PanelTabBar::GetComponentInterface( bool i_bCreate )
    1357             :     {
    1358           0 :         Reference< XWindowPeer > xWindowPeer( Control::GetComponentInterface( false ) );
    1359           0 :         if ( !xWindowPeer.is() && i_bCreate )
    1360             :         {
    1361           0 :             xWindowPeer.set( new PanelTabBarPeer( *this ) );
    1362           0 :             SetComponentInterface( xWindowPeer );
    1363             :         }
    1364           0 :         return xWindowPeer;
    1365             :     }
    1366             : 
    1367             : 
    1368             : } // namespace svt
    1369             : 
    1370             : 
    1371             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11