1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <svtools/toolpanel/paneltabbar.hxx>
22 #include <svtools/toolpanel/toolpaneldeck.hxx>
23 #include <svtools/svtresid.hxx>
24 #include <svtools/svtools.hrc>
26 #include "tabitemdescriptor.hxx"
27 #include "paneltabbarpeer.hxx"
28 #include "tabbargeometry.hxx"
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>
36 #include <boost/optional.hpp>
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
51 using ::com::sun::star::uno::Reference
;
52 using ::com::sun::star::awt::XWindowPeer
;
54 typedef sal_uInt16 ItemFlags
;
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
68 ControlState
lcl_ItemToControlState( const ItemFlags i_nItemFlags
)
70 ControlState nState
= ControlState::ENABLED
;
71 if ( i_nItemFlags
& ITEM_STATE_FOCUSED
) nState
|= ControlState::FOCUSED
| ControlState::PRESSED
;
72 if ( i_nItemFlags
& ITEM_STATE_HOVERED
) nState
|= ControlState::ROLLOVER
;
73 if ( i_nItemFlags
& ITEM_STATE_ACTIVE
) nState
|= ControlState::SELECTED
;
81 class SAL_NO_VTABLE ITabBarRenderer
84 /** fills the background of our target device
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;
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.
100 typedef ::boost::shared_ptr
< ITabBarRenderer
> PTabBarRenderer
;
103 //= VCLItemRenderer - declaration
105 class VCLItemRenderer
: public ITabBarRenderer
108 VCLItemRenderer( OutputDevice
& i_rTargetDevice
)
109 :m_rTargetDevice( i_rTargetDevice
)
112 virtual ~VCLItemRenderer() {}
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
;
121 OutputDevice
& getTargetDevice() const { return m_rTargetDevice
; }
124 OutputDevice
& m_rTargetDevice
;
128 //= VCLItemRenderer - implementation
131 void VCLItemRenderer::renderBackground() const
133 getTargetDevice().DrawRect( Rectangle( Point(), getTargetDevice().GetOutputSizePixel() ) );
137 Rectangle
VCLItemRenderer::calculateDecorations( const Rectangle
& i_rContentArea
, const ItemFlags i_nItemFlags
) const
140 // no decorations at all
141 return i_rContentArea
;
145 void VCLItemRenderer::preRenderItem( const Rectangle
& i_rContentRect
, const ItemFlags i_nItemFlags
) const
147 (void)i_rContentRect
;
152 void VCLItemRenderer::postRenderItem( vcl::Window
& i_rActualWindow
, const Rectangle
& i_rItemRect
, const ItemFlags i_nItemFlags
) const
154 const bool bActive
= ( ( i_nItemFlags
& ITEM_STATE_ACTIVE
) != 0 );
155 const bool bHovered
= ( ( i_nItemFlags
& ITEM_STATE_HOVERED
) != 0 );
156 const bool bFocused
= ( ( i_nItemFlags
& ITEM_STATE_FOCUSED
) != 0 );
157 if ( bActive
|| bHovered
|| bFocused
)
159 Rectangle
aSelectionRect( i_rItemRect
);
160 aSelectionRect
.Left() += ITEM_OUTER_SPACE
/ 2;
161 aSelectionRect
.Top() += ITEM_OUTER_SPACE
/ 2;
162 aSelectionRect
.Right() -= ITEM_OUTER_SPACE
/ 2;
163 aSelectionRect
.Bottom() -= ITEM_OUTER_SPACE
/ 2;
164 i_rActualWindow
.DrawSelectionBackground(
166 ( bHovered
|| bFocused
) ? ( bActive
? 1 : 2 ) : 0 /* highlight */,
169 false /* ext border only */,
170 0 /* corner radius */,
178 //= NWFToolboxItemRenderer - declaration
180 class NWFToolboxItemRenderer
: public ITabBarRenderer
183 NWFToolboxItemRenderer( OutputDevice
& i_rTargetDevice
)
184 :m_rTargetDevice( i_rTargetDevice
)
187 virtual ~NWFToolboxItemRenderer() {}
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
;
196 OutputDevice
& getTargetDevice() const { return m_rTargetDevice
; }
199 OutputDevice
& m_rTargetDevice
;
203 //= NWFToolboxItemRenderer - implementation
206 void NWFToolboxItemRenderer::renderBackground() const
208 getTargetDevice().DrawRect( Rectangle( Point(), getTargetDevice().GetOutputSizePixel() ) );
212 Rectangle
NWFToolboxItemRenderer::calculateDecorations( const Rectangle
& i_rContentArea
, const ItemFlags i_nItemFlags
) const
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
226 Point( i_rContentArea
.Left() - 1, i_rContentArea
.Top() - 1 ),
227 Size( i_rContentArea
.GetWidth() + 2, i_rContentArea
.GetHeight() + 2 )
232 void NWFToolboxItemRenderer::preRenderItem( const Rectangle
& i_rContentRect
, const ItemFlags i_nItemFlags
) const
234 const ControlState nState
= lcl_ItemToControlState( i_nItemFlags
);
236 ImplControlValue aControlValue
;
237 aControlValue
.setTristateVal( ( i_nItemFlags
& ITEM_STATE_ACTIVE
) ? BUTTONVALUE_ON
: BUTTONVALUE_OFF
);
239 bool bNativeOK
= getTargetDevice().DrawNativeControl( CTRL_TOOLBAR
, PART_BUTTON
, i_rContentRect
, nState
, aControlValue
, OUString() );
241 OSL_ENSURE( bNativeOK
, "NWFToolboxItemRenderer::preRenderItem: inconsistent NWF implementation!" );
242 // IsNativeControlSupported returned true, previously, otherwise we would not be here ...
246 void NWFToolboxItemRenderer::postRenderItem( vcl::Window
& i_rActualWindow
, const Rectangle
& i_rItemRect
, const ItemFlags i_nItemFlags
) const
248 (void)i_rActualWindow
;
255 //= NWFTabItemRenderer - declaration
257 class NWFTabItemRenderer
: public ITabBarRenderer
260 NWFTabItemRenderer( OutputDevice
& i_rTargetDevice
)
261 :m_rTargetDevice( i_rTargetDevice
)
265 virtual ~NWFTabItemRenderer() {}
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
;
274 OutputDevice
& getTargetDevice() const { return m_rTargetDevice
; }
277 OutputDevice
& m_rTargetDevice
;
281 //= NWFTabItemRenderer - implementation
284 void NWFTabItemRenderer::renderBackground() const
286 Rectangle
aBackground( Point(), getTargetDevice().GetOutputSizePixel() );
287 getTargetDevice().DrawRect( aBackground
);
289 aBackground
.Top() = aBackground
.Bottom();
290 getTargetDevice().DrawNativeControl( CTRL_TAB_PANE
, PART_ENTIRE_CONTROL
, aBackground
,
291 ControlState::ENABLED
, ImplControlValue(), OUString() );
295 Rectangle
NWFTabItemRenderer::calculateDecorations( const Rectangle
& i_rContentArea
, const ItemFlags i_nItemFlags
) const
297 const ControlState
nState( lcl_ItemToControlState( i_nItemFlags
) );
299 TabitemValue
tiValue(Rectangle(i_rContentArea
.Left() + TAB_TABOFFSET_X
,
300 i_rContentArea
.Right() - TAB_TABOFFSET_X
,
301 i_rContentArea
.Top() + TAB_TABOFFSET_Y
,
302 i_rContentArea
.Bottom() - TAB_TABOFFSET_Y
));
304 Rectangle aBoundingRegion
, aContentRegion
;
305 bool bNativeOK
= getTargetDevice().GetNativeControlRegion(
306 CTRL_TAB_ITEM
, PART_ENTIRE_CONTROL
,
307 i_rContentArea
, nState
,
309 aBoundingRegion
, aContentRegion
312 OSL_ENSURE( bNativeOK
, "NWFTabItemRenderer::calculateDecorations: GetNativeControlRegion not implemented for CTRL_TAB_ITEM?!" );
314 return aBoundingRegion
;
318 void NWFTabItemRenderer::preRenderItem( const Rectangle
& i_rContentRect
, const ItemFlags i_nItemFlags
) const
320 const ControlState nState
= lcl_ItemToControlState( i_nItemFlags
);
322 TabitemValue
tiValue(Rectangle(i_rContentRect
.Left() + TAB_TABOFFSET_X
,
323 i_rContentRect
.Right() - TAB_TABOFFSET_X
,
324 i_rContentRect
.Top() + TAB_TABOFFSET_Y
,
325 i_rContentRect
.Bottom() - TAB_TABOFFSET_Y
));
327 if ( i_nItemFlags
& ITEM_POSITION_FIRST
)
328 tiValue
.mnAlignment
|= TABITEM_FIRST_IN_GROUP
;
329 if ( i_nItemFlags
& ITEM_POSITION_LAST
)
330 tiValue
.mnAlignment
|= TABITEM_LAST_IN_GROUP
;
333 bool bNativeOK
= getTargetDevice().DrawNativeControl( CTRL_TAB_ITEM
, PART_ENTIRE_CONTROL
, i_rContentRect
, nState
, tiValue
, OUString() );
335 OSL_ENSURE( bNativeOK
, "NWFTabItemRenderer::preRenderItem: inconsistent NWF implementation!" );
336 // IsNativeControlSupported returned true, previously, otherwise we would not be here ...
340 void NWFTabItemRenderer::postRenderItem( vcl::Window
& i_rActualWindow
, const Rectangle
& i_rItemRect
, const ItemFlags i_nItemFlags
) const
342 (void)i_rActualWindow
;
350 class PanelTabBar_Impl
: public IToolPanelDeckListener
353 PanelTabBar_Impl(PanelTabBar
& i_rTabBar
, IToolPanelDeck
& i_rPanelDeck
,
354 const TabAlignment i_eAlignment
, const TabItemContent i_eItemContent
);
356 virtual ~PanelTabBar_Impl()
358 m_rPanelDeck
.RemoveListener(*this);
361 // IToolPanelDeckListener
362 virtual void PanelInserted(const PToolPanel
& i_pPanel
, const size_t i_nPosition
) SAL_OVERRIDE
366 m_bItemsDirty
= true;
367 m_rTabBar
.Invalidate();
372 virtual void PanelRemoved( const size_t i_nPosition
) SAL_OVERRIDE
374 m_bItemsDirty
= true;
375 m_rTabBar
.Invalidate();
377 if ( i_nPosition
< m_nScrollPosition
)
383 virtual void ActivePanelChanged(const boost::optional
<size_t>& i_rOldActive
,
384 const boost::optional
<size_t>& i_rNewActive
) SAL_OVERRIDE
;
385 virtual void LayouterChanged(const PDeckLayouter
& i_rNewLayouter
) SAL_OVERRIDE
;
386 virtual void Dying() SAL_OVERRIDE
;
388 void UpdateScrollButtons()
390 m_aScrollBack
->Enable(m_nScrollPosition
> 0);
391 m_aScrollForward
->Enable(m_nScrollPosition
< m_aItems
.size() - 1);
395 void EnsureItemsCache();
396 boost::optional
<size_t> FindItemForPoint( const Point
& i_rPoint
) const;
397 void DrawItem(vcl::RenderContext
& rRenderContext
, const size_t i_nItemIndex
, const Rectangle
& i_rBoundaries
) const;
398 void InvalidateItem( const size_t i_nItemIndex
, const ItemFlags i_nAdditionalItemFlags
= 0 ) const;
399 void CopyFromRenderDevice(vcl::RenderContext
& rRenderContext
, const Rectangle
& i_rLogicalRect
) const;
400 Rectangle
GetActualLogicalItemRect( const Rectangle
& i_rLogicalItemRect
) const;
401 Rectangle
GetItemScreenRect( const size_t i_nItemPos
) const;
403 void FocusItem( const ::boost::optional
< size_t >& i_rItemPos
);
405 inline bool IsVertical() const
407 return ( ( m_eTabAlignment
== TABS_LEFT
)
408 || ( m_eTabAlignment
== TABS_RIGHT
)
413 DECL_LINK( OnScroll
, const PushButton
* );
415 void impl_calcItemRects();
416 Size
impl_calculateItemContentSize( const PToolPanel
& i_pPanel
, const TabItemContent i_eItemContent
) const;
417 void impl_renderItemContent(vcl::RenderContext
& rRenderContext
, const PToolPanel
& i_pPanel
,
418 const Rectangle
& i_rContentArea
, const TabItemContent i_eItemContent
) const;
419 ItemFlags
impl_getItemFlags( const size_t i_nItemIndex
) const;
422 PanelTabBar
& m_rTabBar
;
423 TabBarGeometry m_aGeometry
;
424 NormalizedArea m_aNormalizer
;
425 TabAlignment m_eTabAlignment
;
426 IToolPanelDeck
& m_rPanelDeck
;
428 ScopedVclPtr
<VirtualDevice
> m_aRenderDevice
;
429 PTabBarRenderer m_pRenderer
;
431 boost::optional
<size_t> m_aHoveredItem
;
432 boost::optional
<size_t> m_aFocusedItem
;
433 bool m_bMouseButtonDown
;
435 ItemDescriptors m_aItems
;
438 VclPtr
<PushButton
> m_aScrollBack
;
439 VclPtr
<PushButton
> m_aScrollForward
;
441 size_t m_nScrollPosition
;
450 #if OSL_DEBUG_LEVEL > 0
451 static void lcl_checkConsistency( const PanelTabBar_Impl
& i_rImpl
)
453 if ( !i_rImpl
.m_bItemsDirty
)
455 if ( i_rImpl
.m_rPanelDeck
.GetPanelCount() != i_rImpl
.m_aItems
.size() )
457 OSL_FAIL( "lcl_checkConsistency: inconsistent array sizes!" );
460 for ( size_t i
= 0; i
< i_rImpl
.m_rPanelDeck
.GetPanelCount(); ++i
)
462 if ( i_rImpl
.m_rPanelDeck
.GetPanel( i
).get() != i_rImpl
.m_aItems
[i
].pPanel
.get() )
464 OSL_FAIL( "lcl_checkConsistency: array elements are inconsistent!" );
471 #define DBG_CHECK( data ) \
472 lcl_checkConsistency( data );
474 #define DBG_CHECK( data ) \
482 ClipItemRegion( const PanelTabBar_Impl
& i_rImpl
)
483 :m_rDevice( i_rImpl
.m_rTabBar
)
485 m_rDevice
.Push( PushFlags::CLIPREGION
);
486 m_rDevice
.SetClipRegion(vcl::Region(
487 i_rImpl
.m_aNormalizer
.getTransformed(
488 i_rImpl
.m_aGeometry
.getItemsRect(),
489 i_rImpl
.m_eTabAlignment
)));
498 OutputDevice
& m_rDevice
;
503 //= PanelTabBar_Impl - implementation
506 PanelTabBar_Impl::PanelTabBar_Impl( PanelTabBar
& i_rTabBar
, IToolPanelDeck
& i_rPanelDeck
, const TabAlignment i_eAlignment
, const TabItemContent i_eItemContent
)
507 :m_rTabBar( i_rTabBar
)
508 ,m_aGeometry( i_eItemContent
)
510 ,m_eTabAlignment( i_eAlignment
)
511 ,m_rPanelDeck( i_rPanelDeck
)
512 ,m_aRenderDevice( VclPtr
<VirtualDevice
>::Create(i_rTabBar
) )
516 ,m_bMouseButtonDown( false )
518 ,m_bItemsDirty( true )
519 ,m_aScrollBack( VclPtr
<PushButton
>::Create(&i_rTabBar
, WB_BEVELBUTTON
) )
520 ,m_aScrollForward( VclPtr
<PushButton
>::Create(&i_rTabBar
, WB_BEVELBUTTON
) )
521 ,m_nScrollPosition( 0 )
524 if (m_aRenderDevice
->IsNativeControlSupported(CTRL_TAB_ITEM
, PART_ENTIRE_CONTROL
))
525 // this mode requires the NWF framework to be able to render those items onto a virtual
526 // device. For some frameworks (some GTK themes, in particular), this is known to fail.
527 // So, be on the safe side for the moment.
528 m_pRenderer
.reset(new NWFTabItemRenderer(*m_aRenderDevice
.get()));
531 if (m_aRenderDevice
->IsNativeControlSupported(CTRL_TOOLBAR
, PART_BUTTON
))
532 m_pRenderer
.reset(new NWFToolboxItemRenderer(*m_aRenderDevice
.get()));
534 m_pRenderer
.reset(new VCLItemRenderer(*m_aRenderDevice
.get()));
536 m_aRenderDevice
->SetLineColor();
538 m_rPanelDeck
.AddListener( *this );
540 m_aScrollBack
->SetSymbol( IsVertical() ? SymbolType::ARROW_UP
: SymbolType::ARROW_LEFT
);
541 m_aScrollBack
->Show();
542 m_aScrollBack
->SetClickHdl( LINK( this, PanelTabBar_Impl
, OnScroll
) );
543 m_aScrollBack
->SetAccessibleDescription( SvtResId( STR_SVT_TOOL_PANEL_BUTTON_FWD
).toString() );
544 m_aScrollBack
->SetAccessibleName( m_aScrollBack
->GetAccessibleDescription() );
546 m_aScrollForward
->SetSymbol( IsVertical() ? SymbolType::ARROW_DOWN
: SymbolType::ARROW_RIGHT
);
547 m_aScrollForward
->Show();
548 m_aScrollForward
->SetClickHdl( LINK( this, PanelTabBar_Impl
, OnScroll
) );
549 m_aScrollForward
->SetAccessibleDescription( SvtResId( STR_SVT_TOOL_PANEL_BUTTON_BACK
).toString() );
550 m_aScrollForward
->SetAccessibleName( m_aScrollForward
->GetAccessibleDescription() );
554 void PanelTabBar_Impl::impl_calcItemRects()
558 Point
aCompletePos( m_aGeometry
.getFirstItemPosition() );
559 Point
aIconOnlyPos( aCompletePos
);
560 Point
aTextOnlyPos( aCompletePos
);
563 i
< m_rPanelDeck
.GetPanelCount();
567 PToolPanel
pPanel( m_rPanelDeck
.GetPanel( i
) );
569 ItemDescriptor aItem
;
570 aItem
.pPanel
= pPanel
;
572 const Size
aCompleteSize( impl_calculateItemContentSize( pPanel
, TABITEM_IMAGE_AND_TEXT
) );
573 const Size
aIconOnlySize( impl_calculateItemContentSize( pPanel
, TABITEM_IMAGE_ONLY
) );
574 const Size
aTextOnlySize( impl_calculateItemContentSize( pPanel
, TABITEM_TEXT_ONLY
) );
576 // TODO: have one method calculating all sizes?
578 // remember the three areas
579 aItem
.aCompleteArea
= Rectangle( aCompletePos
, aCompleteSize
);
580 aItem
.aIconOnlyArea
= Rectangle( aIconOnlyPos
, aIconOnlySize
);
581 aItem
.aTextOnlyArea
= Rectangle( aTextOnlyPos
, aTextOnlySize
);
583 m_aItems
.push_back( aItem
);
585 aCompletePos
= aItem
.aCompleteArea
.TopRight();
586 aIconOnlyPos
= aItem
.aIconOnlyArea
.TopRight();
587 aTextOnlyPos
= aItem
.aTextOnlyArea
.TopRight();
590 m_bItemsDirty
= false;
594 Size
PanelTabBar_Impl::impl_calculateItemContentSize( const PToolPanel
& i_pPanel
, const TabItemContent i_eItemContent
) const
596 // calculate the size needed for the content
597 OSL_ENSURE( i_eItemContent
!= TABITEM_AUTO
, "PanelTabBar_Impl::impl_calculateItemContentSize: illegal TabItemContent value!" );
599 const Image
aImage( i_pPanel
->GetImage() );
600 const bool bUseImage
= !!aImage
&& ( i_eItemContent
!= TABITEM_TEXT_ONLY
);
602 const OUString
sItemText( i_pPanel
->GetDisplayName() );
603 const bool bUseText
= ( !sItemText
.isEmpty() ) && ( i_eItemContent
!= TABITEM_IMAGE_ONLY
);
605 Size aItemContentSize
;
608 aItemContentSize
= aImage
.GetSizePixel();
614 aItemContentSize
.Width() += ITEM_ICON_TEXT_DISTANCE
;
616 // add space for text
617 const Size
aTextSize( m_rTabBar
.GetCtrlTextWidth( sItemText
), m_rTabBar
.GetTextHeight() );
618 aItemContentSize
.Width() += aTextSize
.Width();
619 aItemContentSize
.Height() = ::std::max( aItemContentSize
.Height(), aTextSize
.Height() );
621 aItemContentSize
.Width() += 2 * ITEM_TEXT_FLOW_SPACE
;
624 if ( !bUseImage
&& !bUseText
)
626 // have a minimal size - this is pure heuristics, but if it doesn't suit your needs, then give your panels
627 // a name and or image! :)
628 aItemContentSize
= Size( 16, 16 );
631 aItemContentSize
.Width() += 2 * ITEM_OUTER_SPACE
;
632 aItemContentSize
.Height() += 2 * ITEM_OUTER_SPACE
;
634 return aItemContentSize
;
638 void PanelTabBar_Impl::impl_renderItemContent(vcl::RenderContext
& rRenderContext
, const PToolPanel
& i_pPanel
, const Rectangle
& i_rContentArea
, const TabItemContent i_eItemContent
) const
640 OSL_ENSURE(i_eItemContent
!= TABITEM_AUTO
, "PanelTabBar_Impl::impl_renderItemContent: illegal TabItemContent value!");
642 Rectangle
aRenderArea(i_rContentArea
);
645 aRenderArea
.Top() += ITEM_OUTER_SPACE
;
649 aRenderArea
.Left() += ITEM_OUTER_SPACE
;
653 const Image
aItemImage(i_pPanel
->GetImage());
654 const Size
aImageSize(aItemImage
.GetSizePixel());
655 const bool bUseImage
= !!aItemImage
&& (i_eItemContent
!= TABITEM_TEXT_ONLY
);
662 aImagePos
.X() = aRenderArea
.Left() + (aRenderArea
.GetWidth() - aImageSize
.Width()) / 2;
663 aImagePos
.Y() = aRenderArea
.Top();
667 aImagePos
.X() = aRenderArea
.Left();
668 aImagePos
.Y() = aRenderArea
.Top() + (aRenderArea
.GetHeight() - aImageSize
.Height()) / 2;
670 rRenderContext
.DrawImage(aImagePos
, aItemImage
);
673 const OUString
sItemText(i_pPanel
->GetDisplayName());
674 const bool bUseText
= (!sItemText
.isEmpty()) && (i_eItemContent
!= TABITEM_IMAGE_ONLY
);
681 aRenderArea
.Top() += aImageSize
.Height() + ITEM_ICON_TEXT_DISTANCE
;
682 aRenderArea
.Top() += ITEM_TEXT_FLOW_SPACE
;
687 aRenderArea
.Left() += aImageSize
.Width() + ITEM_ICON_TEXT_DISTANCE
;
688 aRenderArea
.Left() += ITEM_TEXT_FLOW_SPACE
;
692 const Size
aTextSize(m_rTabBar
.GetCtrlTextWidth(sItemText
), rRenderContext
.GetTextHeight());
693 Point
aTextPos(aRenderArea
.TopLeft());
696 rRenderContext
.Push(PushFlags::FONT
);
698 vcl::Font
aFont(rRenderContext
.GetFont());
699 aFont
.SetOrientation(2700);
700 aFont
.SetVertical(true);
701 rRenderContext
.SetFont(aFont
);
703 aTextPos
.X() += aTextSize
.Height();
704 aTextPos
.X() += (aRenderArea
.GetWidth() - aTextSize
.Height()) / 2;
708 aTextPos
.Y() += (aRenderArea
.GetHeight() - aTextSize
.Height()) / 2;
711 rRenderContext
.DrawText(aTextPos
, sItemText
);
715 rRenderContext
.Pop();
720 void PanelTabBar_Impl::CopyFromRenderDevice(vcl::RenderContext
& rRenderContext
, const Rectangle
& i_rLogicalRect
) const
722 BitmapEx
aBitmap(m_aRenderDevice
->GetBitmapEx(i_rLogicalRect
.TopLeft(),
723 Size(i_rLogicalRect
.GetSize().Width(),
724 i_rLogicalRect
.GetSize().Height())));
727 aBitmap
.Rotate(2700, COL_BLACK
);
728 if (m_eTabAlignment
== TABS_LEFT
)
729 aBitmap
.Mirror(BmpMirrorFlags::Horizontal
);
731 else if (m_eTabAlignment
== TABS_BOTTOM
)
733 aBitmap
.Mirror(BmpMirrorFlags::Vertical
);
736 const Rectangle
aActualRect(m_aNormalizer
.getTransformed(i_rLogicalRect
, m_eTabAlignment
));
737 rRenderContext
.DrawBitmapEx(aActualRect
.TopLeft(), aBitmap
);
741 void PanelTabBar_Impl::InvalidateItem( const size_t i_nItemIndex
, const ItemFlags i_nAdditionalItemFlags
) const
743 const ItemDescriptor
& rItem( m_aItems
[ i_nItemIndex
] );
744 const ItemFlags
nItemFlags( impl_getItemFlags( i_nItemIndex
) | i_nAdditionalItemFlags
);
746 const Rectangle
aNormalizedContent( GetActualLogicalItemRect( rItem
.GetCurrentRect() ) );
747 const Rectangle
aNormalizedBounds( m_pRenderer
->calculateDecorations( aNormalizedContent
, nItemFlags
) );
749 const Rectangle aActualBounds
= m_aNormalizer
.getTransformed( aNormalizedBounds
, m_eTabAlignment
);
750 m_rTabBar
.Invalidate( aActualBounds
);
754 ItemFlags
PanelTabBar_Impl::impl_getItemFlags( const size_t i_nItemIndex
) const
756 ItemFlags
nItemFlags( ITEM_STATE_NORMAL
);
757 if ( m_aHoveredItem
== i_nItemIndex
)
759 nItemFlags
|= ITEM_STATE_HOVERED
;
760 if ( m_bMouseButtonDown
)
761 nItemFlags
|= ITEM_STATE_ACTIVE
;
764 if ( m_rPanelDeck
.GetActivePanel() == i_nItemIndex
)
765 nItemFlags
|= ITEM_STATE_ACTIVE
;
767 if ( m_aFocusedItem
== i_nItemIndex
)
768 nItemFlags
|= ITEM_STATE_FOCUSED
;
770 if ( 0 == i_nItemIndex
)
771 nItemFlags
|= ITEM_POSITION_FIRST
;
773 if ( m_rPanelDeck
.GetPanelCount() - 1 == i_nItemIndex
)
774 nItemFlags
|= ITEM_POSITION_LAST
;
780 void PanelTabBar_Impl::DrawItem(vcl::RenderContext
& rRenderContext
, const size_t i_nItemIndex
, const Rectangle
& i_rBoundaries
) const
782 const ItemDescriptor
& rItem(m_aItems
[i_nItemIndex
]);
783 const ItemFlags
nItemFlags(impl_getItemFlags(i_nItemIndex
));
785 // the normalized bounding and content rect
786 const Rectangle
aNormalizedContent(GetActualLogicalItemRect(rItem
.GetCurrentRect()));
787 const Rectangle
aNormalizedBounds(m_pRenderer
->calculateDecorations(aNormalizedContent
, nItemFlags
));
789 // check whether the item actually overlaps with the painting area
790 if (!i_rBoundaries
.IsEmpty())
792 const Rectangle
aItemRect(GetActualLogicalItemRect(rItem
.GetCurrentRect()));
793 if (!aItemRect
.IsOver(i_rBoundaries
))
797 m_rTabBar
.SetUpdateMode(false);
799 // the aligned bounding and content rect
800 const Rectangle aActualBounds
= m_aNormalizer
.getTransformed( aNormalizedBounds
, m_eTabAlignment
);
801 const Rectangle aActualContent
= m_aNormalizer
.getTransformed( aNormalizedContent
, m_eTabAlignment
);
803 // render item "background" layer
804 m_pRenderer
->preRenderItem(aNormalizedContent
, nItemFlags
);
806 // copy from the virtual device to ourself
807 CopyFromRenderDevice(rRenderContext
, aNormalizedBounds
);
809 // render the actual item content
810 impl_renderItemContent(rRenderContext
, rItem
.pPanel
, aActualContent
, rItem
.eContent
);
812 // render item "foreground" layer
813 m_pRenderer
->postRenderItem(m_rTabBar
, aActualBounds
, nItemFlags
);
815 m_rTabBar
.SetUpdateMode(true);
819 void PanelTabBar_Impl::EnsureItemsCache()
821 if ( !m_bItemsDirty
)
826 impl_calcItemRects();
827 SAL_WARN_IF( m_bItemsDirty
, "svtools", "PanelTabBar_Impl::EnsureItemsCache: cache still dirty!" );
832 void PanelTabBar_Impl::Relayout()
836 const Size
aOutputSize( m_rTabBar
.GetOutputSizePixel() );
837 m_aNormalizer
= NormalizedArea( Rectangle( Point(), aOutputSize
), IsVertical() );
838 const Size
aLogicalOutputSize( m_aNormalizer
.getReferenceSize() );
840 // forward actual output size to our render device
841 m_aRenderDevice
->SetOutputSizePixel( aLogicalOutputSize
);
843 // re-calculate the size of the scroll buttons and of the items
844 m_aGeometry
.relayout( aLogicalOutputSize
, m_aItems
);
846 if ( m_aGeometry
.getButtonBackRect().IsEmpty() )
848 m_aScrollBack
->Hide();
852 const Rectangle
aButtonBack( m_aNormalizer
.getTransformed( m_aGeometry
.getButtonBackRect(), m_eTabAlignment
) );
853 m_aScrollBack
->SetPosSizePixel( aButtonBack
.TopLeft(), aButtonBack
.GetSize() );
854 m_aScrollBack
->Show();
857 if ( m_aGeometry
.getButtonForwardRect().IsEmpty() )
859 m_aScrollForward
->Hide();
863 const Rectangle
aButtonForward( m_aNormalizer
.getTransformed( m_aGeometry
.getButtonForwardRect(), m_eTabAlignment
) );
864 m_aScrollForward
->SetPosSizePixel( aButtonForward
.TopLeft(), aButtonForward
.GetSize() );
865 m_aScrollForward
->Show();
868 UpdateScrollButtons();
872 ::boost::optional
< size_t > PanelTabBar_Impl::FindItemForPoint( const Point
& i_rPoint
) const
874 Point
aPoint( IsVertical() ? i_rPoint
.Y() : i_rPoint
.X(), IsVertical() ? i_rPoint
.X() : i_rPoint
.Y() );
876 if ( !m_aGeometry
.getItemsRect().IsInside( aPoint
) )
877 return ::boost::optional
< size_t >();
880 for ( ItemDescriptors::const_iterator item
= m_aItems
.begin();
881 item
!= m_aItems
.end();
885 Rectangle
aItemRect( GetActualLogicalItemRect( item
->GetCurrentRect() ) );
886 if ( aItemRect
.IsInside( aPoint
) )
888 return ::boost::optional
< size_t >( i
);
891 return ::boost::optional
< size_t >();
895 Rectangle
PanelTabBar_Impl::GetItemScreenRect( const size_t i_nItemPos
) const
897 ENSURE_OR_RETURN( i_nItemPos
< m_aItems
.size(), "PanelTabBar_Impl::GetItemScreenRect: invalid item pos!", Rectangle() );
898 const ItemDescriptor
& rItem( m_aItems
[ i_nItemPos
] );
899 const Rectangle
aItemRect( m_aNormalizer
.getTransformed(
900 GetActualLogicalItemRect( rItem
.GetCurrentRect() ),
903 const Rectangle
aTabBarRect( m_rTabBar
.GetWindowExtentsRelative( NULL
) );
905 Point( aTabBarRect
.Left() + aItemRect
.Left(), aTabBarRect
.Top() + aItemRect
.Top() ),
911 void PanelTabBar_Impl::FocusItem( const ::boost::optional
< size_t >& i_rItemPos
)
913 // reset old focus item
914 if ( !!m_aFocusedItem
)
915 InvalidateItem( *m_aFocusedItem
);
916 m_aFocusedItem
.reset();
918 // mark the active icon as focused
921 m_aFocusedItem
= i_rItemPos
;
922 InvalidateItem( *m_aFocusedItem
);
927 IMPL_LINK( PanelTabBar_Impl
, OnScroll
, const PushButton
*, i_pButton
)
929 if ( i_pButton
== m_aScrollBack
.get() )
931 OSL_ENSURE( m_nScrollPosition
> 0, "PanelTabBar_Impl::OnScroll: inconsistency!" );
933 m_rTabBar
.Invalidate();
935 else if ( i_pButton
== m_aScrollForward
.get() )
937 OSL_ENSURE( m_nScrollPosition
< m_aItems
.size() - 1, "PanelTabBar_Impl::OnScroll: inconsistency!" );
939 m_rTabBar
.Invalidate();
942 UpdateScrollButtons();
948 Rectangle
PanelTabBar_Impl::GetActualLogicalItemRect( const Rectangle
& i_rLogicalItemRect
) const
950 // care for the offset imposed by our geometry, i.e. whether or not we have scroll buttons
951 Rectangle
aItemRect( i_rLogicalItemRect
);
952 aItemRect
.Move( m_aGeometry
.getItemsRect().Left() - m_aGeometry
.getButtonBackRect().Left(), 0 );
954 // care for the current scroll position
955 OSL_ENSURE( m_nScrollPosition
< m_aItems
.size(), "GetActualLogicalItemRect: invalid scroll position!" );
956 if ( ( m_nScrollPosition
> 0 ) && ( m_nScrollPosition
< m_aItems
.size() ) )
958 long nOffsetX
= m_aItems
[ m_nScrollPosition
].GetCurrentRect().Left() - m_aItems
[ 0 ].GetCurrentRect().Left();
959 long nOffsetY
= m_aItems
[ m_nScrollPosition
].GetCurrentRect().Top() - m_aItems
[ 0 ].GetCurrentRect().Top();
960 aItemRect
.Move( -nOffsetX
, -nOffsetY
);
970 void PanelTabBar_Impl::ActivePanelChanged( const ::boost::optional
< size_t >& i_rOldActive
, const ::boost::optional
< size_t >& i_rNewActive
)
974 if ( !!i_rOldActive
)
975 InvalidateItem( *i_rOldActive
, ITEM_STATE_ACTIVE
);
976 if ( !!i_rNewActive
)
977 InvalidateItem( *i_rNewActive
);
981 void PanelTabBar_Impl::LayouterChanged( const PDeckLayouter
& i_rNewLayouter
)
984 (void)i_rNewLayouter
;
988 void PanelTabBar_Impl::Dying()
990 // not interested in - the notifier is a member of this instance here, so we're dying ourself at the moment
997 PanelTabBar::PanelTabBar( vcl::Window
& i_rParentWindow
, IToolPanelDeck
& i_rPanelDeck
, const TabAlignment i_eAlignment
, const TabItemContent i_eItemContent
)
998 :Control( &i_rParentWindow
, 0 )
999 ,m_pImpl( new PanelTabBar_Impl( *this, i_rPanelDeck
, i_eAlignment
, i_eItemContent
) )
1001 DBG_CHECK( *m_pImpl
);
1004 PanelTabBar::~PanelTabBar()
1009 void PanelTabBar::dispose()
1014 TabItemContent
PanelTabBar::GetTabItemContent() const
1016 return m_pImpl
->m_aGeometry
.getItemContent();
1020 void PanelTabBar::SetTabItemContent( const TabItemContent
& i_eItemContent
)
1022 m_pImpl
->m_aGeometry
.setItemContent( i_eItemContent
);
1023 m_pImpl
->Relayout();
1028 IToolPanelDeck
& PanelTabBar::GetPanelDeck() const
1030 DBG_CHECK( *m_pImpl
);
1031 return m_pImpl
->m_rPanelDeck
;
1035 Size
PanelTabBar::GetOptimalSize() const
1037 m_pImpl
->EnsureItemsCache();
1038 Size
aOptimalSize(m_pImpl
->m_aGeometry
.getOptimalSize(m_pImpl
->m_aItems
));
1039 if ( m_pImpl
->IsVertical() )
1040 ::std::swap( aOptimalSize
.Width(), aOptimalSize
.Height() );
1041 return aOptimalSize
;
1045 void PanelTabBar::Resize()
1048 m_pImpl
->Relayout();
1052 void PanelTabBar::Paint(vcl::RenderContext
& rRenderContext
, const Rectangle
& i_rRect
)
1054 m_pImpl
->EnsureItemsCache();
1057 const Rectangle
aNormalizedPaintArea(m_pImpl
->m_aNormalizer
.getNormalized(i_rRect
, m_pImpl
->m_eTabAlignment
));
1058 m_pImpl
->m_aRenderDevice
->Push(PushFlags::CLIPREGION
);
1059 m_pImpl
->m_aRenderDevice
->SetClipRegion(vcl::Region(aNormalizedPaintArea
));
1060 m_pImpl
->m_pRenderer
->renderBackground();
1061 m_pImpl
->m_aRenderDevice
->Pop();
1062 m_pImpl
->CopyFromRenderDevice(rRenderContext
, aNormalizedPaintArea
);
1064 // ensure the items really paint into their own playground only
1065 ClipItemRegion
aClipItems(*m_pImpl
);
1067 const Rectangle
aLogicalPaintRect(m_pImpl
->m_aNormalizer
.getNormalized(i_rRect
, m_pImpl
->m_eTabAlignment
));
1069 const boost::optional
<size_t> aActivePanel(m_pImpl
->m_rPanelDeck
.GetActivePanel());
1070 const boost::optional
<size_t> aHoveredPanel(m_pImpl
->m_aHoveredItem
);
1073 // 1. paint all non-active, non-hovered items
1075 ItemDescriptors::const_iterator item
;
1076 for (item
= m_pImpl
->m_aItems
.begin(); item
!= m_pImpl
->m_aItems
.end(); ++item
, ++i
)
1078 if (i
== aActivePanel
)
1081 if (aHoveredPanel
== i
)
1084 m_pImpl
->DrawItem(rRenderContext
, i
, aLogicalPaintRect
);
1087 // 2. paint the item which is hovered, /without/ the mouse button pressed down
1088 if (!!aHoveredPanel
&& !m_pImpl
->m_bMouseButtonDown
)
1089 m_pImpl
->DrawItem(rRenderContext
, *aHoveredPanel
, aLogicalPaintRect
);
1091 // 3. paint the active item
1093 m_pImpl
->DrawItem(rRenderContext
, *aActivePanel
, aLogicalPaintRect
);
1095 // 4. paint the item which is hovered, /with/ the mouse button pressed down
1096 if (!!aHoveredPanel
&& m_pImpl
->m_bMouseButtonDown
)
1097 m_pImpl
->DrawItem(rRenderContext
, *aHoveredPanel
, aLogicalPaintRect
);
1101 void PanelTabBar::MouseMove( const MouseEvent
& i_rMouseEvent
)
1103 m_pImpl
->EnsureItemsCache();
1105 boost::optional
< size_t > aOldItem(m_pImpl
->m_aHoveredItem
);
1106 boost::optional
< size_t > aNewItem(m_pImpl
->FindItemForPoint(i_rMouseEvent
.GetPosPixel()));
1108 if (i_rMouseEvent
.IsLeaveWindow())
1109 aNewItem
= boost::optional
<size_t>();
1111 bool const bChanged(
1112 ( !aOldItem
&& aNewItem
)
1113 || ( aOldItem
&& !aNewItem
)
1114 || ( aOldItem
&& aNewItem
&& aOldItem
!= aNewItem
) );
1119 m_pImpl
->InvalidateItem( *aOldItem
);
1121 m_pImpl
->m_aHoveredItem
= aNewItem
;
1124 m_pImpl
->InvalidateItem( *aNewItem
);
1129 void PanelTabBar::MouseButtonDown( const MouseEvent
& i_rMouseEvent
)
1131 Control::MouseButtonDown( i_rMouseEvent
);
1133 if ( !i_rMouseEvent
.IsLeft() )
1136 m_pImpl
->EnsureItemsCache();
1138 ::boost::optional
< size_t > aHitItem( m_pImpl
->FindItemForPoint( i_rMouseEvent
.GetPosPixel() ) );
1143 m_pImpl
->m_bMouseButtonDown
= true;
1145 m_pImpl
->InvalidateItem( *aHitItem
);
1149 void PanelTabBar::MouseButtonUp( const MouseEvent
& i_rMouseEvent
)
1151 Control::MouseButtonUp( i_rMouseEvent
);
1153 if ( m_pImpl
->m_bMouseButtonDown
)
1155 ::boost::optional
< size_t > aHitItem( m_pImpl
->FindItemForPoint( i_rMouseEvent
.GetPosPixel() ) );
1158 // re-draw that item now that we're not in mouse-down mode anymore
1159 m_pImpl
->InvalidateItem( *aHitItem
);
1160 // activate the respective panel
1161 m_pImpl
->m_rPanelDeck
.ActivatePanel( *aHitItem
);
1164 OSL_ENSURE( IsMouseCaptured(), "PanelTabBar::MouseButtonUp: inconsistency!" );
1165 if ( IsMouseCaptured() )
1167 m_pImpl
->m_bMouseButtonDown
= false;
1172 void PanelTabBar::RequestHelp( const HelpEvent
& i_rHelpEvent
)
1174 m_pImpl
->EnsureItemsCache();
1176 ::boost::optional
< size_t > aHelpItem( m_pImpl
->FindItemForPoint( ScreenToOutputPixel( i_rHelpEvent
.GetMousePosPixel() ) ) );
1180 const ItemDescriptor
& rItem( m_pImpl
->m_aItems
[ *aHelpItem
] );
1181 if ( rItem
.eContent
!= TABITEM_IMAGE_ONLY
)
1182 // if the text is displayed for the item, we do not need to show it as tooltip
1185 const OUString
sItemText( rItem
.pPanel
->GetDisplayName() );
1186 if ( i_rHelpEvent
.GetMode() == HelpEventMode::BALLOON
)
1187 Help::ShowBalloon( this, OutputToScreenPixel( rItem
.GetCurrentRect().Center() ), rItem
.GetCurrentRect(), sItemText
);
1189 Help::ShowQuickHelp( this, rItem
.GetCurrentRect(), sItemText
);
1193 void PanelTabBar::GetFocus()
1195 Control::GetFocus();
1196 if ( !m_pImpl
->m_aFocusedItem
)
1197 m_pImpl
->FocusItem( m_pImpl
->m_rPanelDeck
.GetActivePanel() );
1201 void PanelTabBar::LoseFocus()
1203 Control::LoseFocus();
1207 if ( !!m_pImpl
->m_aFocusedItem
)
1208 m_pImpl
->InvalidateItem( *m_pImpl
->m_aFocusedItem
);
1210 m_pImpl
->m_aFocusedItem
.reset();
1215 class KeyInputHandler
1218 KeyInputHandler( Control
& i_rControl
, const KeyEvent
& i_rKeyEvent
)
1219 :m_rControl( i_rControl
)
1220 ,m_rKeyEvent( i_rKeyEvent
)
1221 ,m_bHandled( false )
1228 m_rControl
.Control::KeyInput( m_rKeyEvent
);
1237 Control
& m_rControl
;
1238 const KeyEvent
& m_rKeyEvent
;
1243 void PanelTabBar::KeyInput( const KeyEvent
& i_rKeyEvent
)
1245 KeyInputHandler
aKeyInputHandler( *this, i_rKeyEvent
);
1247 const vcl::KeyCode
& rKeyCode( i_rKeyEvent
.GetKeyCode() );
1248 if ( rKeyCode
.GetModifier() != 0 )
1249 // only interested in mere key presses
1252 // if there are less than 2 panels, we cannot travel them ...
1253 const size_t nPanelCount( m_pImpl
->m_rPanelDeck
.GetPanelCount() );
1254 if ( nPanelCount
< 2 )
1257 OSL_PRECOND( !!m_pImpl
->m_aFocusedItem
, "PanelTabBar::KeyInput: we should have a focused item here!" );
1258 // if we get KeyInput events, we should have the focus. In this case, m_aFocusedItem should not be empty,
1259 // except if there are no panels, but then we bail out of this method here earlier ...
1261 bool bFocusNext
= false;
1262 bool bFocusPrev
= false;
1264 switch ( rKeyCode
.GetCode() )
1266 case KEY_UP
: bFocusPrev
= true; break;
1267 case KEY_DOWN
: bFocusNext
= true; break;
1269 if ( IsRTLEnabled() )
1275 if ( IsRTLEnabled() )
1281 m_pImpl
->m_rPanelDeck
.ActivatePanel( *m_pImpl
->m_aFocusedItem
);
1285 if ( !bFocusNext
&& !bFocusPrev
)
1288 m_pImpl
->InvalidateItem( *m_pImpl
->m_aFocusedItem
);
1291 m_pImpl
->m_aFocusedItem
.reset( ( *m_pImpl
->m_aFocusedItem
+ 1 ) % nPanelCount
);
1295 m_pImpl
->m_aFocusedItem
.reset( ( *m_pImpl
->m_aFocusedItem
+ nPanelCount
- 1 ) % nPanelCount
);
1297 m_pImpl
->InvalidateItem( *m_pImpl
->m_aFocusedItem
);
1299 // don't delegate to base class
1300 aKeyInputHandler
.setHandled();
1304 void PanelTabBar::DataChanged( const DataChangedEvent
& i_rDataChanedEvent
)
1306 Control::DataChanged( i_rDataChanedEvent
);
1308 if ( ( i_rDataChanedEvent
.GetType() == DataChangedEventType::SETTINGS
)
1309 && ( i_rDataChanedEvent
.GetFlags() & AllSettingsFlags::STYLE
)
1317 bool PanelTabBar::IsVertical() const
1319 return m_pImpl
->IsVertical();
1323 PushButton
& PanelTabBar::GetScrollButton( const bool i_bForward
)
1325 return i_bForward
? *m_pImpl
->m_aScrollForward
.get() : *m_pImpl
->m_aScrollBack
.get();
1329 ::boost::optional
< size_t > PanelTabBar::GetFocusedPanelItem() const
1331 return m_pImpl
->m_aFocusedItem
;
1335 void PanelTabBar::FocusPanelItem( const size_t i_nItemPos
)
1337 ENSURE_OR_RETURN_VOID( i_nItemPos
< m_pImpl
->m_rPanelDeck
.GetPanelCount(), "PanelTabBar::FocusPanelItem: illegal item pos!" );
1339 if ( !HasChildPathFocus() )
1342 m_pImpl
->FocusItem( i_nItemPos
);
1343 SAL_WARN_IF( !m_pImpl
->m_aFocusedItem
, "svtools", "PanelTabBar::FocusPanelItem: have the focus, but no focused item?" );
1344 if ( !!m_pImpl
->m_aFocusedItem
)
1345 m_pImpl
->InvalidateItem( *m_pImpl
->m_aFocusedItem
);
1346 m_pImpl
->m_aFocusedItem
.reset( i_nItemPos
);
1350 Rectangle
PanelTabBar::GetItemScreenRect( const size_t i_nItemPos
) const
1352 return m_pImpl
->GetItemScreenRect( i_nItemPos
);
1356 Reference
< XWindowPeer
> PanelTabBar::GetComponentInterface( bool i_bCreate
)
1358 Reference
< XWindowPeer
> xWindowPeer( Control::GetComponentInterface( false ) );
1359 if ( !xWindowPeer
.is() && i_bCreate
)
1361 xWindowPeer
.set( new PanelTabBarPeer( *this ) );
1362 SetComponentInterface( xWindowPeer
);
1371 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */