LCOV - code coverage report
Current view: top level - svtools/source/toolpanel - paneltabbar.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1 506 0.2 %
Date: 2014-11-03 Functions: 2 74 2.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10