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

Generated by: LCOV version 1.10