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