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