LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/svtools/source/toolpanel - paneltabbar.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 1 534 0.2 %
Date: 2013-07-09 Functions: 2 81 2.5 %
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           0 :                 ( 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, 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, 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(), 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, 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, 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           0 :             return  (   ( m_eTabAlignment == TABS_LEFT )
     397           0 :                     ||  ( 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             :                 m_rDevice.SetClipRegion(Region(
     475             :                     i_rImpl.m_aNormalizer.getTransformed(
     476           0 :                         i_rImpl.m_aGeometry.getItemsRect(),
     477           0 :                         i_rImpl.m_eTabAlignment )));
     478           0 :             }
     479             : 
     480           0 :             ~ClipItemRegion()
     481             :             {
     482           0 :                 m_rDevice.Pop();
     483           0 :             }
     484             : 
     485             :         private:
     486             :             OutputDevice&   m_rDevice;
     487             :         };
     488             :     }
     489             : 
     490             :     //==================================================================================================================
     491             :     //= PanelTabBar_Impl - implementation
     492             :     //==================================================================================================================
     493             :     //------------------------------------------------------------------------------------------------------------------
     494           0 :     PanelTabBar_Impl::PanelTabBar_Impl( PanelTabBar& i_rTabBar, IToolPanelDeck& i_rPanelDeck, const TabAlignment i_eAlignment, const TabItemContent i_eItemContent )
     495             :         :m_rTabBar( i_rTabBar )
     496             :         ,m_aGeometry( i_eItemContent )
     497             :         ,m_aNormalizer()
     498             :         ,m_eTabAlignment( i_eAlignment )
     499             :         ,m_rPanelDeck( i_rPanelDeck )
     500             :         ,m_aRenderDevice( i_rTabBar )
     501             :         ,m_pRenderer()
     502             :         ,m_aHoveredItem()
     503             :         ,m_aFocusedItem()
     504             :         ,m_bMouseButtonDown( false )
     505             :         ,m_aItems()
     506             :         ,m_bItemsDirty( true )
     507             :         ,m_aScrollBack( &i_rTabBar, WB_BEVELBUTTON )
     508             :         ,m_aScrollForward( &i_rTabBar, WB_BEVELBUTTON )
     509           0 :         ,m_nScrollPosition( 0 )
     510             :     {
     511             : #ifdef WNT
     512             :         if ( m_aRenderDevice.IsNativeControlSupported( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL ) )
     513             :             // this mode requires the NWF framework to be able to render those items onto a virtual
     514             :             // device. For some frameworks (some GTK themes, in particular), this is known to fail.
     515             :             // So, be on the safe side for the moment.
     516             :             m_pRenderer.reset( new NWFTabItemRenderer( m_aRenderDevice ) );
     517             :         else
     518             : #endif
     519           0 :         if ( m_aRenderDevice.IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) )
     520           0 :             m_pRenderer.reset( new NWFToolboxItemRenderer( m_aRenderDevice ) );
     521             :         else
     522           0 :             m_pRenderer.reset( new VCLItemRenderer( m_aRenderDevice ) );
     523             : 
     524           0 :         m_aRenderDevice.SetLineColor();
     525             : 
     526           0 :         m_rPanelDeck.AddListener( *this );
     527             : 
     528           0 :         m_aScrollBack.SetSymbol( IsVertical() ? SYMBOL_ARROW_UP : SYMBOL_ARROW_LEFT );
     529           0 :         m_aScrollBack.Show();
     530           0 :         m_aScrollBack.SetClickHdl( LINK( this, PanelTabBar_Impl, OnScroll ) );
     531           0 :         m_aScrollBack.SetAccessibleDescription( SvtResId( STR_SVT_TOOL_PANEL_BUTTON_FWD ).toString() );
     532           0 :         m_aScrollBack.SetAccessibleName( m_aScrollBack.GetAccessibleDescription() );
     533             : 
     534           0 :         m_aScrollForward.SetSymbol( IsVertical() ? SYMBOL_ARROW_DOWN : SYMBOL_ARROW_RIGHT );
     535           0 :         m_aScrollForward.Show();
     536           0 :         m_aScrollForward.SetClickHdl( LINK( this, PanelTabBar_Impl, OnScroll ) );
     537           0 :         m_aScrollForward.SetAccessibleDescription( SvtResId( STR_SVT_TOOL_PANEL_BUTTON_BACK ).toString() );
     538           0 :         m_aScrollForward.SetAccessibleName( m_aScrollForward.GetAccessibleDescription() );
     539           0 :     }
     540             : 
     541             :     //------------------------------------------------------------------------------------------------------------------
     542           0 :     void PanelTabBar_Impl::impl_calcItemRects()
     543             :     {
     544           0 :         m_aItems.resize(0);
     545             : 
     546           0 :         Point aCompletePos( m_aGeometry.getFirstItemPosition() );
     547           0 :         Point aIconOnlyPos( aCompletePos );
     548           0 :         Point aTextOnlyPos( aCompletePos );
     549             : 
     550           0 :         for (   size_t i = 0;
     551           0 :                 i < m_rPanelDeck.GetPanelCount();
     552             :                 ++i
     553             :             )
     554             :         {
     555           0 :             PToolPanel pPanel( m_rPanelDeck.GetPanel( i ) );
     556             : 
     557           0 :             ItemDescriptor aItem;
     558           0 :             aItem.pPanel = pPanel;
     559             : 
     560           0 :             const Size aCompleteSize( impl_calculateItemContentSize( pPanel, TABITEM_IMAGE_AND_TEXT ) );
     561           0 :             const Size aIconOnlySize( impl_calculateItemContentSize( pPanel, TABITEM_IMAGE_ONLY ) );
     562           0 :             const Size aTextOnlySize( impl_calculateItemContentSize( pPanel, TABITEM_TEXT_ONLY ) );
     563             : 
     564             :             // TODO: have one method calculating all sizes?
     565             : 
     566             :             // remember the three areas
     567           0 :             aItem.aCompleteArea = Rectangle( aCompletePos, aCompleteSize );
     568           0 :             aItem.aIconOnlyArea = Rectangle( aIconOnlyPos, aIconOnlySize );
     569           0 :             aItem.aTextOnlyArea = Rectangle( aTextOnlyPos, aTextOnlySize );
     570             : 
     571           0 :             m_aItems.push_back( aItem );
     572             : 
     573           0 :             aCompletePos = aItem.aCompleteArea.TopRight();
     574           0 :             aIconOnlyPos = aItem.aIconOnlyArea.TopRight();
     575           0 :             aTextOnlyPos = aItem.aTextOnlyArea.TopRight();
     576           0 :         }
     577             : 
     578           0 :         m_bItemsDirty = false;
     579           0 :     }
     580             : 
     581             :     //------------------------------------------------------------------------------------------------------------------
     582           0 :     Size PanelTabBar_Impl::impl_calculateItemContentSize( const PToolPanel& i_pPanel, const TabItemContent i_eItemContent ) const
     583             :     {
     584             :         // calculate the size needed for the content
     585             :         OSL_ENSURE( i_eItemContent != TABITEM_AUTO, "PanelTabBar_Impl::impl_calculateItemContentSize: illegal TabItemContent value!" );
     586             : 
     587           0 :         const Image aImage( i_pPanel->GetImage() );
     588           0 :         const bool bUseImage = !!aImage && ( i_eItemContent != TABITEM_TEXT_ONLY );
     589             : 
     590           0 :         const OUString sItemText( i_pPanel->GetDisplayName() );
     591           0 :         const bool bUseText = ( !sItemText.isEmpty() ) && ( i_eItemContent != TABITEM_IMAGE_ONLY );
     592             : 
     593           0 :         Size aItemContentSize;
     594           0 :         if ( bUseImage )
     595             :         {
     596           0 :             aItemContentSize = aImage.GetSizePixel();
     597             :         }
     598             : 
     599           0 :         if ( bUseText )
     600             :         {
     601           0 :             if ( bUseImage )
     602           0 :                 aItemContentSize.Width() += ITEM_ICON_TEXT_DISTANCE;
     603             : 
     604             :             // add space for text
     605           0 :             const Size aTextSize( m_rTabBar.GetCtrlTextWidth( sItemText ), m_rTabBar.GetTextHeight() );
     606           0 :             aItemContentSize.Width() += aTextSize.Width();
     607           0 :             aItemContentSize.Height() = ::std::max( aItemContentSize.Height(), aTextSize.Height() );
     608             : 
     609           0 :             aItemContentSize.Width() += 2 * ITEM_TEXT_FLOW_SPACE;
     610             :         }
     611             : 
     612           0 :         if ( !bUseImage && !bUseText )
     613             :         {
     614             :             // have a minimal size - this is pure heuristics, but if it doesn't suit your needs, then give your panels
     615             :             // a name and or image! :)
     616           0 :             aItemContentSize = Size( 16, 16 );
     617             :         }
     618             : 
     619           0 :         aItemContentSize.Width() += 2 * ITEM_OUTER_SPACE;
     620           0 :         aItemContentSize.Height() += 2 * ITEM_OUTER_SPACE;
     621             : 
     622           0 :         return aItemContentSize;
     623             :     }
     624             : 
     625             :     //------------------------------------------------------------------------------------------------------------------
     626           0 :     void PanelTabBar_Impl::impl_renderItemContent( const PToolPanel& i_pPanel, const Rectangle& i_rContentArea, const TabItemContent i_eItemContent ) const
     627             :     {
     628             :         OSL_ENSURE( i_eItemContent != TABITEM_AUTO, "PanelTabBar_Impl::impl_renderItemContent: illegal TabItemContent value!" );
     629             : 
     630           0 :         Rectangle aRenderArea( i_rContentArea );
     631           0 :         if ( IsVertical() )
     632             :         {
     633           0 :             aRenderArea.Top() += ITEM_OUTER_SPACE;
     634             :         }
     635             :         else
     636             :         {
     637           0 :             aRenderArea.Left() += ITEM_OUTER_SPACE;
     638             :         }
     639             : 
     640             :         // draw the image
     641           0 :         const Image aItemImage( i_pPanel->GetImage() );
     642           0 :         const Size aImageSize( aItemImage.GetSizePixel() );
     643           0 :         const bool bUseImage = !!aItemImage && ( i_eItemContent != TABITEM_TEXT_ONLY );
     644             : 
     645           0 :         if ( bUseImage )
     646             :         {
     647           0 :             Point aImagePos;
     648           0 :             if ( IsVertical() )
     649             :             {
     650           0 :                 aImagePos.X() = aRenderArea.Left() + ( aRenderArea.GetWidth() - aImageSize.Width() ) / 2;
     651           0 :                 aImagePos.Y() = aRenderArea.Top();
     652             :             }
     653             :             else
     654             :             {
     655           0 :                 aImagePos.X() = aRenderArea.Left();
     656           0 :                 aImagePos.Y() = aRenderArea.Top() + ( aRenderArea.GetHeight() - aImageSize.Height() ) / 2;
     657             :             }
     658           0 :             m_rTabBar.DrawImage( aImagePos, aItemImage );
     659             :         }
     660             : 
     661           0 :         const OUString sItemText( i_pPanel->GetDisplayName() );
     662           0 :         const bool bUseText = ( !sItemText.isEmpty() ) && ( i_eItemContent != TABITEM_IMAGE_ONLY );
     663             : 
     664           0 :         if ( bUseText )
     665             :         {
     666           0 :             if ( IsVertical() )
     667             :             {
     668           0 :                 if ( bUseImage )
     669           0 :                     aRenderArea.Top() += aImageSize.Height() + ITEM_ICON_TEXT_DISTANCE;
     670           0 :                 aRenderArea.Top() += ITEM_TEXT_FLOW_SPACE;
     671             :             }
     672             :             else
     673             :             {
     674           0 :                 if ( bUseImage )
     675           0 :                     aRenderArea.Left() += aImageSize.Width() + ITEM_ICON_TEXT_DISTANCE;
     676           0 :                 aRenderArea.Left() += ITEM_TEXT_FLOW_SPACE;
     677             :             }
     678             : 
     679             :             // draw the text
     680           0 :             const Size aTextSize( m_rTabBar.GetCtrlTextWidth( sItemText ), m_rTabBar.GetTextHeight() );
     681           0 :             Point aTextPos( aRenderArea.TopLeft() );
     682           0 :             if ( IsVertical() )
     683             :             {
     684           0 :                 m_rTabBar.Push( PUSH_FONT );
     685             : 
     686           0 :                 Font aFont( m_rTabBar.GetFont() );
     687           0 :                 aFont.SetOrientation( 2700 );
     688           0 :                 aFont.SetVertical( sal_True );
     689           0 :                 m_rTabBar.SetFont( aFont );
     690             : 
     691           0 :                 aTextPos.X() += aTextSize.Height();
     692           0 :                 aTextPos.X() += ( aRenderArea.GetWidth() - aTextSize.Height() ) / 2;
     693             :             }
     694             :             else
     695             :             {
     696           0 :                 aTextPos.Y() += ( aRenderArea.GetHeight() - aTextSize.Height() ) / 2;
     697             :             }
     698             : 
     699           0 :             m_rTabBar.DrawText( aTextPos, sItemText );
     700             : 
     701           0 :             if ( IsVertical() )
     702             :             {
     703           0 :                 m_rTabBar.Pop();
     704             :             }
     705           0 :         }
     706           0 :     }
     707             : 
     708             :     //------------------------------------------------------------------------------------------------------------------
     709           0 :     void PanelTabBar_Impl::CopyFromRenderDevice( const Rectangle& i_rLogicalRect ) const
     710             :     {
     711             :         BitmapEx aBitmap( m_aRenderDevice.GetBitmapEx(
     712             :             i_rLogicalRect.TopLeft(),
     713             :             Size(
     714           0 :                 i_rLogicalRect.GetSize().Width(),
     715           0 :                 i_rLogicalRect.GetSize().Height()
     716             :             )
     717           0 :         ) );
     718           0 :         if ( IsVertical() )
     719             :         {
     720           0 :             aBitmap.Rotate( 2700, COL_BLACK );
     721           0 :             if ( m_eTabAlignment == TABS_LEFT )
     722           0 :                 aBitmap.Mirror( BMP_MIRROR_HORZ );
     723             :         }
     724           0 :         else if ( m_eTabAlignment == TABS_BOTTOM )
     725             :         {
     726           0 :             aBitmap.Mirror( BMP_MIRROR_VERT );
     727             :         }
     728             : 
     729           0 :         const Rectangle aActualRect( m_aNormalizer.getTransformed( i_rLogicalRect, m_eTabAlignment ) );
     730           0 :         m_rTabBar.DrawBitmapEx( aActualRect.TopLeft(), aBitmap );
     731           0 :     }
     732             : 
     733             :     //------------------------------------------------------------------------------------------------------------------
     734           0 :     void PanelTabBar_Impl::InvalidateItem( const size_t i_nItemIndex, const ItemFlags i_nAdditionalItemFlags ) const
     735             :     {
     736           0 :         const ItemDescriptor& rItem( m_aItems[ i_nItemIndex ] );
     737           0 :         const ItemFlags nItemFlags( impl_getItemFlags( i_nItemIndex ) | i_nAdditionalItemFlags );
     738             : 
     739           0 :         const Rectangle aNormalizedContent( GetActualLogicalItemRect( rItem.GetCurrentRect() ) );
     740           0 :         const Rectangle aNormalizedBounds( m_pRenderer->calculateDecorations( aNormalizedContent, nItemFlags ) );
     741             : 
     742           0 :         const Rectangle aActualBounds = m_aNormalizer.getTransformed( aNormalizedBounds, m_eTabAlignment );
     743           0 :         m_rTabBar.Invalidate( aActualBounds );
     744           0 :     }
     745             : 
     746             :     //------------------------------------------------------------------------------------------------------------------
     747           0 :     ItemFlags PanelTabBar_Impl::impl_getItemFlags( const size_t i_nItemIndex ) const
     748             :     {
     749           0 :         ItemFlags nItemFlags( ITEM_STATE_NORMAL );
     750           0 :         if ( m_aHoveredItem == i_nItemIndex )
     751             :         {
     752           0 :             nItemFlags |= ITEM_STATE_HOVERED;
     753           0 :             if ( m_bMouseButtonDown )
     754           0 :                 nItemFlags |= ITEM_STATE_ACTIVE;
     755             :         }
     756             : 
     757           0 :         if ( m_rPanelDeck.GetActivePanel() == i_nItemIndex )
     758           0 :             nItemFlags |= ITEM_STATE_ACTIVE;
     759             : 
     760           0 :         if ( m_aFocusedItem == i_nItemIndex )
     761           0 :             nItemFlags |= ITEM_STATE_FOCUSED;
     762             : 
     763           0 :         if ( 0 == i_nItemIndex )
     764           0 :             nItemFlags |= ITEM_POSITION_FIRST;
     765             : 
     766           0 :         if ( m_rPanelDeck.GetPanelCount() - 1 == i_nItemIndex )
     767           0 :             nItemFlags |= ITEM_POSITION_LAST;
     768             : 
     769           0 :         return nItemFlags;
     770             :     }
     771             : 
     772             :     //------------------------------------------------------------------------------------------------------------------
     773           0 :     void PanelTabBar_Impl::DrawItem( const size_t i_nItemIndex, const Rectangle& i_rBoundaries ) const
     774             :     {
     775           0 :         const ItemDescriptor& rItem( m_aItems[ i_nItemIndex ] );
     776           0 :         const ItemFlags nItemFlags( impl_getItemFlags( i_nItemIndex ) );
     777             : 
     778             :         // the normalized bounding and content rect
     779           0 :         const Rectangle aNormalizedContent( GetActualLogicalItemRect( rItem.GetCurrentRect() ) );
     780           0 :         const Rectangle aNormalizedBounds( m_pRenderer->calculateDecorations( aNormalizedContent, nItemFlags ) );
     781             : 
     782             :         // check whether the item actually overlaps with the painting area
     783           0 :         if ( !i_rBoundaries.IsEmpty() )
     784             :         {
     785           0 :             const Rectangle aItemRect( GetActualLogicalItemRect( rItem.GetCurrentRect() ) );
     786           0 :             if ( !aItemRect.IsOver( i_rBoundaries ) )
     787           0 :                 return;
     788             :         }
     789             : 
     790           0 :         m_rTabBar.SetUpdateMode( sal_False );
     791             : 
     792             :         // the aligned bounding and content rect
     793           0 :         const Rectangle aActualBounds = m_aNormalizer.getTransformed( aNormalizedBounds, m_eTabAlignment );
     794           0 :         const Rectangle aActualContent = m_aNormalizer.getTransformed( aNormalizedContent, m_eTabAlignment );
     795             : 
     796             :         // render item "background" layer
     797           0 :         m_pRenderer->preRenderItem( aNormalizedContent, nItemFlags );
     798             : 
     799             :         // copy from the virtual device to ourself
     800           0 :         CopyFromRenderDevice( aNormalizedBounds );
     801             : 
     802             :         // render the actual item content
     803           0 :         impl_renderItemContent( rItem.pPanel, aActualContent, rItem.eContent );
     804             : 
     805             :         // render item "foreground" layer
     806           0 :         m_pRenderer->postRenderItem( m_rTabBar, aActualBounds, nItemFlags );
     807             : 
     808           0 :         m_rTabBar.SetUpdateMode( sal_True );
     809             :     }
     810             : 
     811             :     //------------------------------------------------------------------------------------------------------------------
     812           0 :     void PanelTabBar_Impl::EnsureItemsCache()
     813             :     {
     814           0 :         if ( m_bItemsDirty == false )
     815             :         {
     816             :             DBG_CHECK( *this );
     817           0 :             return;
     818             :         }
     819           0 :         impl_calcItemRects();
     820             :         OSL_POSTCOND( m_bItemsDirty == false, "PanelTabBar_Impl::EnsureItemsCache: cache still dirty!" );
     821             :         DBG_CHECK( *this );
     822             :     }
     823             : 
     824             :     //------------------------------------------------------------------------------------------------------------------
     825           0 :     void PanelTabBar_Impl::Relayout()
     826             :     {
     827           0 :         EnsureItemsCache();
     828             : 
     829           0 :         const Size aOutputSize( m_rTabBar.GetOutputSizePixel() );
     830           0 :         m_aNormalizer = NormalizedArea( Rectangle( Point(), aOutputSize ), IsVertical() );
     831           0 :         const Size aLogicalOutputSize( m_aNormalizer.getReferenceSize() );
     832             : 
     833             :         // forward actual output size to our render device
     834           0 :         m_aRenderDevice.SetOutputSizePixel( aLogicalOutputSize );
     835             : 
     836             :         // re-calculate the size of the scroll buttons and of the items
     837           0 :         m_aGeometry.relayout( aLogicalOutputSize, m_aItems );
     838             : 
     839           0 :         if ( m_aGeometry.getButtonBackRect().IsEmpty() )
     840             :         {
     841           0 :             m_aScrollBack.Hide();
     842             :         }
     843             :         else
     844             :         {
     845           0 :             const Rectangle aButtonBack( m_aNormalizer.getTransformed( m_aGeometry.getButtonBackRect(), m_eTabAlignment ) );
     846           0 :             m_aScrollBack.SetPosSizePixel( aButtonBack.TopLeft(), aButtonBack.GetSize() );
     847           0 :             m_aScrollBack.Show();
     848             :         }
     849             : 
     850           0 :         if ( m_aGeometry.getButtonForwardRect().IsEmpty() )
     851             :         {
     852           0 :             m_aScrollForward.Hide();
     853             :         }
     854             :         else
     855             :         {
     856           0 :             const Rectangle aButtonForward( m_aNormalizer.getTransformed( m_aGeometry.getButtonForwardRect(), m_eTabAlignment ) );
     857           0 :             m_aScrollForward.SetPosSizePixel( aButtonForward.TopLeft(), aButtonForward.GetSize() );
     858           0 :             m_aScrollForward.Show();
     859             :         }
     860             : 
     861           0 :         UpdateScrollButtons();
     862           0 :     }
     863             : 
     864             :     //------------------------------------------------------------------------------------------------------------------
     865           0 :     ::boost::optional< size_t > PanelTabBar_Impl::FindItemForPoint( const Point& i_rPoint ) const
     866             :     {
     867           0 :         Point aPoint( IsVertical() ? i_rPoint.Y() : i_rPoint.X(), IsVertical() ? i_rPoint.X() : i_rPoint.Y() );
     868             : 
     869           0 :         if ( !m_aGeometry.getItemsRect().IsInside( aPoint ) )
     870           0 :             return ::boost::optional< size_t >();
     871             : 
     872           0 :         size_t i=0;
     873           0 :         for (   ItemDescriptors::const_iterator item = m_aItems.begin();
     874           0 :                 item != m_aItems.end();
     875             :                 ++item, ++i
     876             :             )
     877             :         {
     878           0 :             Rectangle aItemRect( GetActualLogicalItemRect( item->GetCurrentRect() ) );
     879           0 :             if ( aItemRect.IsInside( aPoint ) )
     880             :             {
     881           0 :                 return ::boost::optional< size_t >( i );
     882             :             }
     883             :         }
     884           0 :         return ::boost::optional< size_t >();
     885             :     }
     886             : 
     887             :     //------------------------------------------------------------------------------------------------------------------
     888           0 :     Rectangle PanelTabBar_Impl::GetItemScreenRect( const size_t i_nItemPos ) const
     889             :     {
     890           0 :         ENSURE_OR_RETURN( i_nItemPos < m_aItems.size(), "PanelTabBar_Impl::GetItemScreenRect: invalid item pos!", Rectangle() );
     891           0 :         const ItemDescriptor& rItem( m_aItems[ i_nItemPos ] );
     892             :         const Rectangle aItemRect( m_aNormalizer.getTransformed(
     893           0 :             GetActualLogicalItemRect( rItem.GetCurrentRect() ),
     894           0 :             m_eTabAlignment ) );
     895             : 
     896           0 :         const Rectangle aTabBarRect( m_rTabBar.GetWindowExtentsRelative( NULL ) );
     897             :         return Rectangle(
     898           0 :             Point( aTabBarRect.Left() + aItemRect.Left(), aTabBarRect.Top() + aItemRect.Top() ),
     899             :             aItemRect.GetSize()
     900           0 :         );
     901             :     }
     902             : 
     903             :     //------------------------------------------------------------------------------------------------------------------
     904           0 :     void PanelTabBar_Impl::FocusItem( const ::boost::optional< size_t >& i_rItemPos )
     905             :     {
     906             :         // reset old focus item
     907           0 :         if ( !!m_aFocusedItem )
     908           0 :             InvalidateItem( *m_aFocusedItem );
     909           0 :         m_aFocusedItem.reset();
     910             : 
     911             :         // mark the active icon as focused
     912           0 :         if ( !!i_rItemPos )
     913             :         {
     914           0 :             m_aFocusedItem = i_rItemPos;
     915           0 :             InvalidateItem( *m_aFocusedItem );
     916             :         }
     917           0 :     }
     918             : 
     919             :     //------------------------------------------------------------------------------------------------------------------
     920           0 :     IMPL_LINK( PanelTabBar_Impl, OnScroll, const PushButton*, i_pButton )
     921             :     {
     922           0 :         if ( i_pButton == &m_aScrollBack )
     923             :         {
     924             :             OSL_ENSURE( m_nScrollPosition > 0, "PanelTabBar_Impl::OnScroll: inconsistency!" );
     925           0 :             --m_nScrollPosition;
     926           0 :             m_rTabBar.Invalidate();
     927             :         }
     928           0 :         else if ( i_pButton == &m_aScrollForward )
     929             :         {
     930             :             OSL_ENSURE( m_nScrollPosition < m_aItems.size() - 1, "PanelTabBar_Impl::OnScroll: inconsistency!" );
     931           0 :             ++m_nScrollPosition;
     932           0 :             m_rTabBar.Invalidate();
     933             :         }
     934             : 
     935           0 :         UpdateScrollButtons();
     936             : 
     937           0 :         return 0L;
     938             :     }
     939             : 
     940             :     //------------------------------------------------------------------------------------------------------------------
     941           0 :     Rectangle PanelTabBar_Impl::GetActualLogicalItemRect( const Rectangle& i_rLogicalItemRect ) const
     942             :     {
     943             :         // care for the offset imposed by our geometry, i.e. whether or not we have scroll buttons
     944           0 :         Rectangle aItemRect( i_rLogicalItemRect );
     945           0 :         aItemRect.Move( m_aGeometry.getItemsRect().Left() - m_aGeometry.getButtonBackRect().Left(), 0 );
     946             : 
     947             :         // care for the current scroll position
     948             :         OSL_ENSURE( m_nScrollPosition < m_aItems.size(), "GetActualLogicalItemRect: invalid scroll position!" );
     949           0 :         if ( ( m_nScrollPosition > 0 ) && ( m_nScrollPosition < m_aItems.size() ) )
     950             :         {
     951           0 :             long nOffsetX = m_aItems[ m_nScrollPosition ].GetCurrentRect().Left() - m_aItems[ 0 ].GetCurrentRect().Left();
     952           0 :             long nOffsetY = m_aItems[ m_nScrollPosition ].GetCurrentRect().Top() - m_aItems[ 0 ].GetCurrentRect().Top();
     953           0 :             aItemRect.Move( -nOffsetX, -nOffsetY );
     954             :         }
     955             : 
     956           0 :         return aItemRect;
     957             :     }
     958             : 
     959             :     //==================================================================================================================
     960             :     //= PanelTabBar_Impl
     961             :     //==================================================================================================================
     962             :     //------------------------------------------------------------------------------------------------------------------
     963           0 :     void PanelTabBar_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive )
     964             :     {
     965           0 :         EnsureItemsCache();
     966             : 
     967           0 :         if ( !!i_rOldActive )
     968           0 :             InvalidateItem( *i_rOldActive, ITEM_STATE_ACTIVE );
     969           0 :         if ( !!i_rNewActive )
     970           0 :             InvalidateItem( *i_rNewActive );
     971           0 :     }
     972             : 
     973             :     //------------------------------------------------------------------------------------------------------------------
     974           0 :     void PanelTabBar_Impl::LayouterChanged( const PDeckLayouter& i_rNewLayouter )
     975             :     {
     976             :         // not interested in
     977             :         (void)i_rNewLayouter;
     978           0 :     }
     979             : 
     980             :     //------------------------------------------------------------------------------------------------------------------
     981           0 :     void PanelTabBar_Impl::Dying()
     982             :     {
     983             :         // not interested in - the notifier is a member of this instance here, so we're dying ourself at the moment
     984           0 :     }
     985             : 
     986             :     //==================================================================================================================
     987             :     //= PanelTabBar
     988             :     //==================================================================================================================
     989             :     //------------------------------------------------------------------------------------------------------------------
     990           0 :     PanelTabBar::PanelTabBar( Window& i_rParentWindow, IToolPanelDeck& i_rPanelDeck, const TabAlignment i_eAlignment, const TabItemContent i_eItemContent )
     991             :         :Control( &i_rParentWindow, 0 )
     992           0 :         ,m_pImpl( new PanelTabBar_Impl( *this, i_rPanelDeck, i_eAlignment, i_eItemContent ) )
     993             :     {
     994           0 :         DBG_CHECK( *m_pImpl );
     995           0 :     }
     996             : 
     997             :     //------------------------------------------------------------------------------------------------------------------
     998           0 :     PanelTabBar::~PanelTabBar()
     999             :     {
    1000           0 :     }
    1001             : 
    1002             :     //------------------------------------------------------------------------------------------------------------------
    1003           0 :     TabItemContent PanelTabBar::GetTabItemContent() const
    1004             :     {
    1005           0 :         return m_pImpl->m_aGeometry.getItemContent();
    1006             :     }
    1007             : 
    1008             :     //------------------------------------------------------------------------------------------------------------------
    1009           0 :     void PanelTabBar::SetTabItemContent( const TabItemContent& i_eItemContent )
    1010             :     {
    1011           0 :         m_pImpl->m_aGeometry.setItemContent( i_eItemContent );
    1012           0 :         m_pImpl->Relayout();
    1013           0 :         Invalidate();
    1014           0 :     }
    1015             : 
    1016             :     //------------------------------------------------------------------------------------------------------------------
    1017           0 :     IToolPanelDeck& PanelTabBar::GetPanelDeck() const
    1018             :     {
    1019           0 :         DBG_CHECK( *m_pImpl );
    1020           0 :         return m_pImpl->m_rPanelDeck;
    1021             :     }
    1022             : 
    1023             :     //------------------------------------------------------------------------------------------------------------------
    1024           0 :     Size PanelTabBar::GetOptimalSize() const
    1025             :     {
    1026           0 :         m_pImpl->EnsureItemsCache();
    1027           0 :         Size aOptimalSize(m_pImpl->m_aGeometry.getOptimalSize(m_pImpl->m_aItems));
    1028           0 :         if ( m_pImpl->IsVertical() )
    1029           0 :             ::std::swap( aOptimalSize.Width(), aOptimalSize.Height() );
    1030           0 :         return aOptimalSize;
    1031             :     }
    1032             : 
    1033             :     //------------------------------------------------------------------------------------------------------------------
    1034           0 :     void PanelTabBar::Resize()
    1035             :     {
    1036           0 :         Control::Resize();
    1037           0 :         m_pImpl->Relayout();
    1038           0 :     }
    1039             : 
    1040             :     //------------------------------------------------------------------------------------------------------------------
    1041           0 :     void PanelTabBar::Paint( const Rectangle& i_rRect )
    1042             :     {
    1043           0 :         m_pImpl->EnsureItemsCache();
    1044             : 
    1045             :         // background
    1046           0 :         const Rectangle aNormalizedPaintArea( m_pImpl->m_aNormalizer.getNormalized( i_rRect, m_pImpl->m_eTabAlignment ) );
    1047           0 :         m_pImpl->m_aRenderDevice.Push( PUSH_CLIPREGION );
    1048           0 :         m_pImpl->m_aRenderDevice.SetClipRegion(Region(aNormalizedPaintArea));
    1049           0 :         m_pImpl->m_pRenderer->renderBackground();
    1050           0 :         m_pImpl->m_aRenderDevice.Pop();
    1051           0 :         m_pImpl->CopyFromRenderDevice( aNormalizedPaintArea );
    1052             : 
    1053             :         // ensure the items really paint into their own playground only
    1054           0 :         ClipItemRegion aClipItems( *m_pImpl );
    1055             : 
    1056           0 :         const Rectangle aLogicalPaintRect( m_pImpl->m_aNormalizer.getNormalized( i_rRect, m_pImpl->m_eTabAlignment ) );
    1057             : 
    1058           0 :         const ::boost::optional< size_t > aActivePanel( m_pImpl->m_rPanelDeck.GetActivePanel() );
    1059           0 :         const ::boost::optional< size_t > aHoveredPanel( m_pImpl->m_aHoveredItem );
    1060             : 
    1061             :         // items:
    1062             :         // 1. paint all non-active, non-hovered items
    1063           0 :         size_t i=0;
    1064           0 :         for (   ItemDescriptors::const_iterator item = m_pImpl->m_aItems.begin();
    1065           0 :                 item != m_pImpl->m_aItems.end();
    1066             :                 ++item, ++i
    1067             :             )
    1068             :         {
    1069           0 :             if ( i == aActivePanel )
    1070           0 :                 continue;
    1071             : 
    1072           0 :             if ( aHoveredPanel == i )
    1073           0 :                 continue;
    1074             : 
    1075           0 :             m_pImpl->DrawItem( i, aLogicalPaintRect );
    1076             :         }
    1077             : 
    1078             :         // 2. paint the item which is hovered, /without/ the mouse button pressed down
    1079           0 :         if ( !!aHoveredPanel && !m_pImpl->m_bMouseButtonDown )
    1080           0 :             m_pImpl->DrawItem( *aHoveredPanel, aLogicalPaintRect );
    1081             : 
    1082             :         // 3. paint the active item
    1083           0 :         if ( !!aActivePanel )
    1084           0 :             m_pImpl->DrawItem( *aActivePanel, aLogicalPaintRect );
    1085             : 
    1086             :         // 4. paint the item which is hovered, /with/ the mouse button pressed down
    1087           0 :         if ( !!aHoveredPanel && m_pImpl->m_bMouseButtonDown )
    1088           0 :             m_pImpl->DrawItem( *aHoveredPanel, aLogicalPaintRect );
    1089           0 :     }
    1090             : 
    1091             :     //------------------------------------------------------------------------------------------------------------------
    1092           0 :     void PanelTabBar::MouseMove( const MouseEvent& i_rMouseEvent )
    1093             :     {
    1094           0 :         m_pImpl->EnsureItemsCache();
    1095             : 
    1096           0 :         ::boost::optional< size_t > aOldItem( m_pImpl->m_aHoveredItem );
    1097           0 :         ::boost::optional< size_t > aNewItem( m_pImpl->FindItemForPoint( i_rMouseEvent.GetPosPixel() ) );
    1098             : 
    1099           0 :         if  ( i_rMouseEvent.IsLeaveWindow() )
    1100           0 :             aNewItem = ::boost::optional< size_t >();
    1101             : 
    1102             :         bool const bChanged(
    1103           0 :                 ( !aOldItem && aNewItem )
    1104           0 :                 || ( aOldItem && !aNewItem )
    1105           0 :                 || ( aOldItem && aNewItem && aOldItem != aNewItem ) )
    1106             :             ;
    1107           0 :         if ( bChanged )
    1108             :         {
    1109           0 :             if ( aOldItem )
    1110           0 :                 m_pImpl->InvalidateItem( *aOldItem );
    1111             : 
    1112           0 :             m_pImpl->m_aHoveredItem = aNewItem;
    1113             : 
    1114           0 :             if ( aNewItem )
    1115           0 :                 m_pImpl->InvalidateItem( *aNewItem );
    1116           0 :         }
    1117           0 :     }
    1118             : 
    1119             :     //------------------------------------------------------------------------------------------------------------------
    1120           0 :     void PanelTabBar::MouseButtonDown( const MouseEvent& i_rMouseEvent )
    1121             :     {
    1122           0 :         Control::MouseButtonDown( i_rMouseEvent );
    1123             : 
    1124           0 :         if ( !i_rMouseEvent.IsLeft() )
    1125           0 :             return;
    1126             : 
    1127           0 :         m_pImpl->EnsureItemsCache();
    1128             : 
    1129           0 :         ::boost::optional< size_t > aHitItem( m_pImpl->FindItemForPoint( i_rMouseEvent.GetPosPixel() ) );
    1130           0 :         if ( !aHitItem )
    1131           0 :             return;
    1132             : 
    1133           0 :         CaptureMouse();
    1134           0 :         m_pImpl->m_bMouseButtonDown = true;
    1135             : 
    1136           0 :         m_pImpl->InvalidateItem( *aHitItem );
    1137             :     }
    1138             : 
    1139             :     //------------------------------------------------------------------------------------------------------------------
    1140           0 :     void PanelTabBar::MouseButtonUp( const MouseEvent& i_rMouseEvent )
    1141             :     {
    1142           0 :         Control::MouseButtonUp( i_rMouseEvent );
    1143             : 
    1144           0 :         if ( m_pImpl->m_bMouseButtonDown )
    1145             :         {
    1146           0 :             ::boost::optional< size_t > aHitItem( m_pImpl->FindItemForPoint( i_rMouseEvent.GetPosPixel() ) );
    1147           0 :             if ( !!aHitItem )
    1148             :             {
    1149             :                 // re-draw that item now that we're not in mouse-down mode anymore
    1150           0 :                 m_pImpl->InvalidateItem( *aHitItem );
    1151             :                 // activate the respective panel
    1152           0 :                 m_pImpl->m_rPanelDeck.ActivatePanel( *aHitItem );
    1153             :             }
    1154             : 
    1155             :             OSL_ENSURE( IsMouseCaptured(), "PanelTabBar::MouseButtonUp: inconsistency!" );
    1156           0 :             if ( IsMouseCaptured() )
    1157           0 :                 ReleaseMouse();
    1158           0 :             m_pImpl->m_bMouseButtonDown = false;
    1159             :         }
    1160           0 :     }
    1161             : 
    1162             :     //------------------------------------------------------------------------------------------------------------------
    1163           0 :     void PanelTabBar::RequestHelp( const HelpEvent& i_rHelpEvent )
    1164             :     {
    1165           0 :         m_pImpl->EnsureItemsCache();
    1166             : 
    1167           0 :         ::boost::optional< size_t > aHelpItem( m_pImpl->FindItemForPoint( ScreenToOutputPixel( i_rHelpEvent.GetMousePosPixel() ) ) );
    1168           0 :         if ( !aHelpItem )
    1169           0 :             return;
    1170             : 
    1171           0 :         const ItemDescriptor& rItem( m_pImpl->m_aItems[ *aHelpItem ] );
    1172           0 :         if ( rItem.eContent != TABITEM_IMAGE_ONLY )
    1173             :             // if the text is displayed for the item, we do not need to show it as tooltip
    1174           0 :             return;
    1175             : 
    1176           0 :         const OUString sItemText( rItem.pPanel->GetDisplayName() );
    1177           0 :         if ( i_rHelpEvent.GetMode() == HELPMODE_BALLOON )
    1178           0 :             Help::ShowBalloon( this, OutputToScreenPixel( rItem.GetCurrentRect().Center() ), rItem.GetCurrentRect(), sItemText );
    1179             :         else
    1180           0 :             Help::ShowQuickHelp( this, rItem.GetCurrentRect(), sItemText );
    1181             :     }
    1182             : 
    1183             :     //------------------------------------------------------------------------------------------------------------------
    1184           0 :     void PanelTabBar::GetFocus()
    1185             :     {
    1186           0 :         Control::GetFocus();
    1187           0 :         if ( !m_pImpl->m_aFocusedItem )
    1188           0 :             m_pImpl->FocusItem( m_pImpl->m_rPanelDeck.GetActivePanel() );
    1189           0 :     }
    1190             : 
    1191             :     //------------------------------------------------------------------------------------------------------------------
    1192           0 :     void PanelTabBar::LoseFocus()
    1193             :     {
    1194           0 :         Control::LoseFocus();
    1195             : 
    1196           0 :         if ( !!m_pImpl->m_aFocusedItem )
    1197             :         {
    1198           0 :             m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem );
    1199             :         }
    1200             : 
    1201           0 :         m_pImpl->m_aFocusedItem.reset();
    1202           0 :     }
    1203             : 
    1204             :     //------------------------------------------------------------------------------------------------------------------
    1205             :     class KeyInputHandler
    1206             :     {
    1207             :     public:
    1208           0 :         KeyInputHandler( Control& i_rControl, const KeyEvent& i_rKeyEvent )
    1209             :             :m_rControl( i_rControl )
    1210             :             ,m_rKeyEvent( i_rKeyEvent )
    1211           0 :             ,m_bHandled( false )
    1212             :         {
    1213           0 :         }
    1214             : 
    1215           0 :         ~KeyInputHandler()
    1216             :         {
    1217           0 :             if ( !m_bHandled )
    1218           0 :                 m_rControl.Control::KeyInput( m_rKeyEvent );
    1219           0 :         }
    1220             : 
    1221           0 :         void   setHandled()
    1222             :         {
    1223           0 :             m_bHandled = true;
    1224           0 :         }
    1225             : 
    1226             :     private:
    1227             :         Control&        m_rControl;
    1228             :         const KeyEvent& m_rKeyEvent;
    1229             :         bool            m_bHandled;
    1230             :     };
    1231             : 
    1232             :     //------------------------------------------------------------------------------------------------------------------
    1233           0 :     void PanelTabBar::KeyInput( const KeyEvent& i_rKeyEvent )
    1234             :     {
    1235           0 :         KeyInputHandler aKeyInputHandler( *this, i_rKeyEvent );
    1236             : 
    1237           0 :         const KeyCode& rKeyCode( i_rKeyEvent.GetKeyCode() );
    1238           0 :         if ( rKeyCode.GetModifier() != 0 )
    1239             :             // only interested in mere key presses
    1240           0 :             return;
    1241             : 
    1242             :         // if there are less than 2 panels, we cannot travel them ...
    1243           0 :         const size_t nPanelCount( m_pImpl->m_rPanelDeck.GetPanelCount() );
    1244           0 :         if ( nPanelCount < 2 )
    1245           0 :             return;
    1246             : 
    1247             :         OSL_PRECOND( !!m_pImpl->m_aFocusedItem, "PanelTabBar::KeyInput: we should have a focused item here!" );
    1248             :             // if we get KeyInput events, we should have the focus. In this case, m_aFocusedItem should not be empty,
    1249             :             // except if there are no panels, but then we bail out of this method here earlier ...
    1250             : 
    1251           0 :         bool bFocusNext = false;
    1252           0 :         bool bFocusPrev = false;
    1253             : 
    1254           0 :         switch ( rKeyCode.GetCode() )
    1255             :         {
    1256           0 :         case KEY_UP:    bFocusPrev = true; break;
    1257           0 :         case KEY_DOWN:  bFocusNext = true; break;
    1258             :         case KEY_LEFT:
    1259           0 :             if ( IsRTLEnabled() )
    1260           0 :                 bFocusNext = true;
    1261             :             else
    1262           0 :                 bFocusPrev = true;
    1263           0 :             break;
    1264             :         case KEY_RIGHT:
    1265           0 :             if ( IsRTLEnabled() )
    1266           0 :                 bFocusPrev = true;
    1267             :             else
    1268           0 :                 bFocusNext = true;
    1269           0 :             break;
    1270             :         case KEY_RETURN:
    1271           0 :             m_pImpl->m_rPanelDeck.ActivatePanel( *m_pImpl->m_aFocusedItem );
    1272           0 :             break;
    1273             :         }
    1274             : 
    1275           0 :         if ( !bFocusNext && !bFocusPrev )
    1276           0 :             return;
    1277             : 
    1278           0 :         m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem );
    1279           0 :         if ( bFocusNext )
    1280             :         {
    1281           0 :             m_pImpl->m_aFocusedItem.reset( ( *m_pImpl->m_aFocusedItem + 1 ) % nPanelCount );
    1282             :         }
    1283             :         else
    1284             :         {
    1285           0 :             m_pImpl->m_aFocusedItem.reset( ( *m_pImpl->m_aFocusedItem + nPanelCount - 1 ) % nPanelCount );
    1286             :         }
    1287           0 :         m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem );
    1288             : 
    1289             :         // don't delegate to base class
    1290           0 :         aKeyInputHandler.setHandled();
    1291             :     }
    1292             : 
    1293             :     //------------------------------------------------------------------------------------------------------------------
    1294           0 :     void PanelTabBar::DataChanged( const DataChangedEvent& i_rDataChanedEvent )
    1295             :     {
    1296           0 :         Control::DataChanged( i_rDataChanedEvent );
    1297             : 
    1298           0 :         if  (   ( i_rDataChanedEvent.GetType() == DATACHANGED_SETTINGS )
    1299           0 :             &&  ( ( i_rDataChanedEvent.GetFlags() & SETTINGS_STYLE ) != 0 )
    1300             :             )
    1301             :         {
    1302           0 :             Invalidate();
    1303             :         }
    1304           0 :     }
    1305             : 
    1306             :     //------------------------------------------------------------------------------------------------------------------
    1307           0 :     bool PanelTabBar::IsVertical() const
    1308             :     {
    1309           0 :         return m_pImpl->IsVertical();
    1310             :     }
    1311             : 
    1312             :     //------------------------------------------------------------------------------------------------------------------
    1313           0 :     PushButton& PanelTabBar::GetScrollButton( const bool i_bForward )
    1314             :     {
    1315           0 :         return i_bForward ? m_pImpl->m_aScrollForward : m_pImpl->m_aScrollBack;
    1316             :     }
    1317             : 
    1318             :     //------------------------------------------------------------------------------------------------------------------
    1319           0 :     ::boost::optional< size_t > PanelTabBar::GetFocusedPanelItem() const
    1320             :     {
    1321           0 :         return m_pImpl->m_aFocusedItem;
    1322             :     }
    1323             : 
    1324             :     //------------------------------------------------------------------------------------------------------------------
    1325           0 :     void PanelTabBar::FocusPanelItem( const size_t i_nItemPos )
    1326             :     {
    1327           0 :         ENSURE_OR_RETURN_VOID( i_nItemPos < m_pImpl->m_rPanelDeck.GetPanelCount(), "PanelTabBar::FocusPanelItem: illegal item pos!" );
    1328             : 
    1329           0 :         if ( !HasChildPathFocus() )
    1330           0 :             GrabFocus();
    1331             : 
    1332           0 :         m_pImpl->FocusItem( i_nItemPos );
    1333             :         OSL_POSTCOND( !!m_pImpl->m_aFocusedItem, "PanelTabBar::FocusPanelItem: have the focus, but no focused item?" );
    1334           0 :         if ( !!m_pImpl->m_aFocusedItem )
    1335           0 :             m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem );
    1336           0 :         m_pImpl->m_aFocusedItem.reset( i_nItemPos );
    1337             :     }
    1338             : 
    1339             :     //------------------------------------------------------------------------------------------------------------------
    1340           0 :     Rectangle PanelTabBar::GetItemScreenRect( const size_t i_nItemPos ) const
    1341             :     {
    1342           0 :         return m_pImpl->GetItemScreenRect( i_nItemPos );
    1343             :     }
    1344             : 
    1345             :     //------------------------------------------------------------------------------------------------------------------
    1346           0 :     Reference< XWindowPeer > PanelTabBar::GetComponentInterface( sal_Bool i_bCreate )
    1347             :     {
    1348           0 :         Reference< XWindowPeer > xWindowPeer( Control::GetComponentInterface( sal_False ) );
    1349           0 :         if ( !xWindowPeer.is() && i_bCreate )
    1350             :         {
    1351           0 :             xWindowPeer.set( new PanelTabBarPeer( *this ) );
    1352           0 :             SetComponentInterface( xWindowPeer );
    1353             :         }
    1354           0 :         return xWindowPeer;
    1355             :     }
    1356             : 
    1357             : //........................................................................
    1358         465 : } // namespace svt
    1359             : //........................................................................
    1360             : 
    1361             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10