diff options
author | Mathias Bauer <mba@openoffice.org> | 2010-07-13 14:38:37 +0200 |
---|---|---|
committer | Mathias Bauer <mba@openoffice.org> | 2010-07-13 14:38:37 +0200 |
commit | ca851f72310bf83c0e6e7cb98fd58e6271fa0f01 (patch) | |
tree | 7f1d1b1461d41b823a7a91464b1874c21b25d2a3 /svtools/source/toolpanel | |
parent | 22e9afcab567030e0b1d029400dd85851b2d86e3 (diff) | |
parent | be588658ea127a6a05390435126f1d739a477b58 (diff) |
CWS changehid: resync to m84
Diffstat (limited to 'svtools/source/toolpanel')
25 files changed, 4943 insertions, 0 deletions
diff --git a/svtools/source/toolpanel/drawerlayouter.cxx b/svtools/source/toolpanel/drawerlayouter.cxx new file mode 100644 index 000000000000..7fc7d05ea0c9 --- /dev/null +++ b/svtools/source/toolpanel/drawerlayouter.cxx @@ -0,0 +1,305 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "svtools/toolpanel/drawerlayouter.hxx" +#include "toolpaneldrawer.hxx" + +#include <com/sun/star/accessibility/XAccessible.hpp> + +#include <comphelper/accimplaccess.hxx> +#include <tools/diagnose_ex.h> + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::accessibility::XAccessible; + /** === end UNO using === **/ + + //================================================================================================================== + //= DrawerDeckLayouter + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + DrawerDeckLayouter::DrawerDeckLayouter( ::Window& i_rParentWindow, IToolPanelDeck& i_rPanels ) + :m_rParentWindow( i_rParentWindow ) + ,m_rPanelDeck( i_rPanels ) + ,m_aDrawers() + ,m_aLastKnownActivePanel() + { + m_rPanelDeck.AddListener( *this ); + + // simulate PanelInserted events for the panels which are already there + for ( size_t i=0; i<m_rPanelDeck.GetPanelCount(); ++i ) + PanelInserted( m_rPanelDeck.GetPanel( i ), i ); + } + + //------------------------------------------------------------------------------------------------------------------ + DrawerDeckLayouter::~DrawerDeckLayouter() + { + } + + //------------------------------------------------------------------------------------------------------------------ + IMPLEMENT_IREFERENCE( DrawerDeckLayouter ) + + //------------------------------------------------------------------------------------------------------------------ + Rectangle DrawerDeckLayouter::Layout( const Rectangle& i_rDeckPlayground ) + { + const size_t nPanelCount( m_rPanelDeck.GetPanelCount() ); + if ( nPanelCount == 0 ) + return i_rDeckPlayground; + + const int nWidth( i_rDeckPlayground.GetWidth() ); + ::boost::optional< size_t > aActivePanel( m_rPanelDeck.GetActivePanel() ); + if ( !aActivePanel ) + aActivePanel = m_aLastKnownActivePanel; + + // arrange the title bars which are *above* the active panel (or *all* if there is no active panel), plus + // the title bar of the active panel itself + Point aUpperDrawerPos( i_rDeckPlayground.TopLeft() ); + const size_t nUpperBound = !!aActivePanel ? *aActivePanel : nPanelCount - 1; + for ( size_t i=0; i<=nUpperBound; ++i ) + { + sal_uInt32 nDrawerHeight = m_aDrawers[i]->GetPreferredHeightPixel(); + m_aDrawers[i]->SetPosSizePixel( + aUpperDrawerPos, Size( nWidth, nDrawerHeight ) ); + aUpperDrawerPos.Move( 0, nDrawerHeight ); + } + + // arrange title bars which are below the active panel (or *none* if there is no active panel) + Point aLowerDrawerPos( i_rDeckPlayground.BottomLeft() ); + for ( size_t j = nPanelCount - 1; j > nUpperBound; --j ) + { + sal_uInt32 nDrawerHeight = m_aDrawers[j]->GetPreferredHeightPixel(); + m_aDrawers[j]->SetPosSizePixel( + Point( aLowerDrawerPos.X(), aLowerDrawerPos.Y() - nDrawerHeight + 1 ), + Size( nWidth, nDrawerHeight ) + ); + aLowerDrawerPos.Move( 0, -nDrawerHeight ); + } + + // fincally calculate the rectangle for the active panel + return Rectangle( + aUpperDrawerPos, + Size( nWidth, aLowerDrawerPos.Y() - aUpperDrawerPos.Y() + 1 ) + ); + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerDeckLayouter::Destroy() + { + while ( !m_aDrawers.empty() ) + impl_removeDrawer( 0 ); + m_rPanelDeck.RemoveListener( *this ); + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerDeckLayouter::SetFocusToPanelSelector() + { + const size_t nPanelCount( m_rPanelDeck.GetPanelCount() ); + if ( !nPanelCount ) + // nothing to focus + return; + ::boost::optional< size_t > aActivePanel( m_rPanelDeck.GetActivePanel() ); + if ( !aActivePanel ) + aActivePanel = 0; + ENSURE_OR_RETURN_VOID( *aActivePanel < m_aDrawers.size(), "DrawerDeckLayouter::SetFocusToPanelSelector: invalid active panel, or inconsistent drawers!" ); + m_aDrawers[ *aActivePanel ]->GrabFocus(); + } + + //------------------------------------------------------------------------------------------------------------------ + size_t DrawerDeckLayouter::GetAccessibleChildCount() const + { + return m_aDrawers.size(); + } + + //------------------------------------------------------------------------------------------------------------------ + Reference< XAccessible > DrawerDeckLayouter::GetAccessibleChild( const size_t i_nChildIndex, const Reference< XAccessible >& i_rParentAccessible ) + { + ENSURE_OR_RETURN( i_nChildIndex < m_aDrawers.size(), "illegal index", NULL ); + + const PToolPanelDrawer pDrawer( m_aDrawers[ i_nChildIndex ] ); + + Reference< XAccessible > xItemAccessible = pDrawer->GetAccessible( FALSE ); + if ( !xItemAccessible.is() ) + { + xItemAccessible = pDrawer->GetAccessible( TRUE ); + ENSURE_OR_RETURN( xItemAccessible.is(), "illegal accessible provided by the drawer implementation!", NULL ); + OSL_VERIFY( ::comphelper::OAccessibleImplementationAccess::setAccessibleParent( xItemAccessible->getAccessibleContext(), + i_rParentAccessible ) ); + } + + return xItemAccessible; + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerDeckLayouter::PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ) + { + OSL_PRECOND( i_nPosition <= m_aDrawers.size(), "DrawerDeckLayouter::PanelInserted: inconsistency!" ); + + PToolPanelDrawer pDrawer( new ToolPanelDrawer( m_rParentWindow, i_pPanel->GetDisplayName() ) ); + pDrawer->SetHelpId( i_pPanel->GetHelpID() ); + // proper Z-Order + if ( i_nPosition == 0 ) + { + pDrawer->SetZOrder( NULL, WINDOW_ZORDER_FIRST ); + } + else + { + const PToolPanelDrawer pFirstDrawer( m_aDrawers[ i_nPosition - 1 ] ); + pDrawer->SetZOrder( pFirstDrawer.get(), WINDOW_ZORDER_BEHIND ); + } + + pDrawer->Show(); + pDrawer->AddEventListener( LINK( this, DrawerDeckLayouter, OnWindowEvent ) ); + m_aDrawers.insert( m_aDrawers.begin() + i_nPosition, pDrawer ); + impl_triggerRearrange(); + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerDeckLayouter::PanelRemoved( const size_t i_nPosition ) + { + impl_removeDrawer( i_nPosition ); + impl_triggerRearrange(); + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerDeckLayouter::impl_triggerRearrange() const + { + // this is somewhat hacky, it assumes that the parent of our panels is a tool panel deck, which, in its + // Resize implementation, rearrances all elements. + m_rParentWindow.Resize(); + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerDeckLayouter::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) + { + if ( !!i_rOldActive ) + { + OSL_ENSURE( *i_rOldActive < m_aDrawers.size(), "DrawerDeckLayouter::ActivePanelChanged: illegal old index!" ); + m_aDrawers[ *i_rOldActive ]->SetExpanded( false ); + } + + if ( !!i_rNewActive ) + { + OSL_ENSURE( *i_rNewActive < m_aDrawers.size(), "DrawerDeckLayouter::ActivePanelChanged: illegal new index!" ); + m_aDrawers[ *i_rNewActive ]->SetExpanded( true ); + } + + impl_triggerRearrange(); + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerDeckLayouter::LayouterChanged( const PDeckLayouter& i_rNewLayouter ) + { + // not interested in + (void)i_rNewLayouter; + } + + //------------------------------------------------------------------------------------------------------------------ + size_t DrawerDeckLayouter::impl_getPanelPositionFromWindow( const Window* i_pDrawerWindow ) const + { + for ( ::std::vector< PToolPanelDrawer >::const_iterator drawerPos = m_aDrawers.begin(); + drawerPos != m_aDrawers.end(); + ++drawerPos + ) + { + if ( drawerPos->get() == i_pDrawerWindow ) + return drawerPos - m_aDrawers.begin(); + } + return m_aDrawers.size(); + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerDeckLayouter::impl_removeDrawer( const size_t i_nPosition ) + { + OSL_PRECOND( i_nPosition < m_aDrawers.size(), "DrawerDeckLayouter::impl_removeDrawer: invalid panel position!" ); + m_aDrawers[ i_nPosition ]->RemoveEventListener( LINK( this, DrawerDeckLayouter, OnWindowEvent ) ); + OSL_ENSURE( m_aDrawers[ i_nPosition ].unique(), "DrawerDeckLayouter::impl_removeDrawer: somebody else is still holding a reference!" ); + m_aDrawers.erase( m_aDrawers.begin() + i_nPosition ); + } + + //------------------------------------------------------------------------------------------------------------------ + IMPL_LINK( DrawerDeckLayouter, OnWindowEvent, VclSimpleEvent*, i_pEvent ) + { + const VclWindowEvent* pWindowEvent = PTR_CAST( VclWindowEvent, i_pEvent ); + ENSURE_OR_RETURN( pWindowEvent, "no WindowEvent", 0L ); + + bool bActivatePanel = false; + switch ( pWindowEvent->GetId() ) + { + case VCLEVENT_WINDOW_MOUSEBUTTONUP: + { + const MouseEvent* pMouseEvent = static_cast< const MouseEvent* >( pWindowEvent->GetData() ); + ENSURE_OR_RETURN( pMouseEvent, "no mouse event with MouseButtonUp", 0L ); + if ( pMouseEvent->GetButtons() == MOUSE_LEFT ) + { + bActivatePanel = true; + } + } + break; + case VCLEVENT_WINDOW_KEYINPUT: + { + const KeyEvent* pKeyEvent = static_cast< const KeyEvent* >( pWindowEvent->GetData() ); + ENSURE_OR_RETURN( pKeyEvent, "no key event with KeyInput", 0L ); + const KeyCode& rKeyCode( pKeyEvent->GetKeyCode() ); + if ( ( rKeyCode.GetModifier() == 0 ) && ( rKeyCode.GetCode() == KEY_RETURN ) ) + { + bActivatePanel = true; + } + } + break; + } + if ( bActivatePanel ) + { + const size_t nPanelPos = impl_getPanelPositionFromWindow( pWindowEvent->GetWindow() ); + if ( nPanelPos != m_rPanelDeck.GetActivePanel() ) + { + m_rPanelDeck.ActivatePanel( nPanelPos ); + } + else + { + PToolPanel pPanel( m_rPanelDeck.GetPanel( nPanelPos ) ); + pPanel->GrabFocus(); + } + return 1L; + } + return 0L; + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerDeckLayouter::Dying() + { + Destroy(); + } + +//...................................................................................................................... +} // namespace svt +//...................................................................................................................... diff --git a/svtools/source/toolpanel/dummypanel.cxx b/svtools/source/toolpanel/dummypanel.cxx new file mode 100644 index 000000000000..4de38b7f4bb3 --- /dev/null +++ b/svtools/source/toolpanel/dummypanel.cxx @@ -0,0 +1,107 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "dummypanel.hxx" + +//........................................................................ +namespace svt +{ +//........................................................................ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::accessibility::XAccessible; + + //==================================================================== + //= DummyPanel + //==================================================================== + //-------------------------------------------------------------------- + DummyPanel::DummyPanel() + { + } + + //-------------------------------------------------------------------- + DummyPanel::~DummyPanel() + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_IREFERENCE( DummyPanel ) + + //-------------------------------------------------------------------- + void DummyPanel::Activate( Window& ) + { + } + + //-------------------------------------------------------------------- + void DummyPanel::Deactivate() + { + } + + //-------------------------------------------------------------------- + void DummyPanel::SetSizePixel( const Size& ) + { + } + + //-------------------------------------------------------------------- + ::rtl::OUString DummyPanel::GetDisplayName() const + { + return ::rtl::OUString(); + } + + //-------------------------------------------------------------------- + Image DummyPanel::GetImage() const + { + return Image(); + } + + //-------------------------------------------------------------------- + rtl::OString DummyPanel::GetHelpID() const + { + return rtl::OString(); + } + + //-------------------------------------------------------------------- + void DummyPanel::GrabFocus() + { + } + + //-------------------------------------------------------------------- + void DummyPanel::Dispose() + { + } + + //-------------------------------------------------------------------- + Reference< XAccessible > DummyPanel::CreatePanelAccessible( const Reference< XAccessible >& i_rParentAccessible ) + { + (void)i_rParentAccessible; + return NULL; + } + +//........................................................................ +} // namespace svt +//........................................................................ diff --git a/svtools/source/toolpanel/dummypanel.hxx b/svtools/source/toolpanel/dummypanel.hxx new file mode 100644 index 000000000000..d2ca4480fce5 --- /dev/null +++ b/svtools/source/toolpanel/dummypanel.hxx @@ -0,0 +1,70 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#ifndef DUMMYPANEL_HXX +#define DUMMYPANEL_HXX + +#include "svtools/toolpanel/toolpanel.hxx" +#include "svtools/toolpanel/refbase.hxx" + +//........................................................................ +namespace svt +{ +//........................................................................ + + //==================================================================== + //= DummyPanel + //==================================================================== + /// is a dummy implementation of the IToolPanel interface + class DummyPanel :public RefBase + ,public IToolPanel + { + public: + DummyPanel(); + ~DummyPanel(); + + // IToolPanel + virtual ::rtl::OUString GetDisplayName() const; + virtual Image GetImage() const; + virtual rtl::OString GetHelpID() const; + virtual void Activate( Window& i_rParentWindow ); + virtual void Deactivate(); + virtual void SetSizePixel( const Size& i_rPanelWindowSize ); + virtual void GrabFocus(); + virtual void Dispose(); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > + CreatePanelAccessible( + const ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible >& i_rParentAccessible + ); + + DECLARE_IREFERENCE() + }; + +//........................................................................ +} // namespace svt +//........................................................................ + +#endif // DUMMYPANEL_HXX diff --git a/svtools/source/toolpanel/makefile.mk b/svtools/source/toolpanel/makefile.mk new file mode 100755 index 000000000000..58282056f529 --- /dev/null +++ b/svtools/source/toolpanel/makefile.mk @@ -0,0 +1,68 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2008 by Sun Microsystems, Inc. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# $RCSfile: makefile.mk,v $ +# +# $Revision: 1.16 $ +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. + +PRJNAME=svtools +TARGET=toolpanel + +# --- Settings ----------------------------------------------------- + +ENABLE_EXCEPTIONS=TRUE + +.INCLUDE : settings.mk +.INCLUDE : $(PRJ)$/util$/svt.pmk + +# --- Files -------------------------------------------------------- + +SRS1NAME=$(TARGET) +SRC1FILES=\ + toolpanel.src + +SLOFILES=\ + $(SLO)$/drawerlayouter.obj \ + $(SLO)$/dummypanel.obj \ + $(SLO)$/paneldecklisteners.obj \ + $(SLO)$/paneltabbar.obj \ + $(SLO)$/paneltabbarpeer.obj \ + $(SLO)$/refbase.obj \ + $(SLO)$/tabbargeometry.obj \ + $(SLO)$/tablayouter.obj \ + $(SLO)$/toolpanel.obj \ + $(SLO)$/toolpanelcollection.obj \ + $(SLO)$/toolpaneldrawer.obj \ + $(SLO)$/toolpaneldrawerpeer.obj \ + $(SLO)$/toolpaneldeck.obj \ + $(SLO)$/toolpaneldeckpeer.obj \ + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/svtools/source/toolpanel/paneldecklisteners.cxx b/svtools/source/toolpanel/paneldecklisteners.cxx new file mode 100755 index 000000000000..32ba9b5c6a24 --- /dev/null +++ b/svtools/source/toolpanel/paneldecklisteners.cxx @@ -0,0 +1,137 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "paneldecklisteners.hxx" +#include "svtools/toolpanel/toolpaneldeck.hxx" + +//........................................................................ +namespace svt +{ +//........................................................................ + + //==================================================================== + //= PanelDeckListeners + //==================================================================== + //-------------------------------------------------------------------- + PanelDeckListeners::PanelDeckListeners() + { + } + + //-------------------------------------------------------------------- + PanelDeckListeners::~PanelDeckListeners() + { + } + + //-------------------------------------------------------------------- + void PanelDeckListeners::PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ) + { + ::std::vector< IToolPanelDeckListener* > aListeners( m_aListeners ); + for ( ::std::vector< IToolPanelDeckListener* >::const_iterator loop = aListeners.begin(); + loop != aListeners.end(); + ++loop + ) + { + (*loop)->PanelInserted( i_pPanel, i_nPosition ); + } + } + + //-------------------------------------------------------------------- + void PanelDeckListeners::PanelRemoved( const size_t i_nPosition ) + { + ::std::vector< IToolPanelDeckListener* > aListeners( m_aListeners ); + for ( ::std::vector< IToolPanelDeckListener* >::const_iterator loop = aListeners.begin(); + loop != aListeners.end(); + ++loop + ) + { + (*loop)->PanelRemoved( i_nPosition ); + } + } + + //-------------------------------------------------------------------- + void PanelDeckListeners::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) + { + ::std::vector< IToolPanelDeckListener* > aListeners( m_aListeners ); + for ( ::std::vector< IToolPanelDeckListener* >::const_iterator loop = aListeners.begin(); + loop != aListeners.end(); + ++loop + ) + { + (*loop)->ActivePanelChanged( i_rOldActive, i_rNewActive ); + } + } + + //-------------------------------------------------------------------- + void PanelDeckListeners::LayouterChanged( const PDeckLayouter& i_rNewLayouter ) + { + ::std::vector< IToolPanelDeckListener* > aListeners( m_aListeners ); + for ( ::std::vector< IToolPanelDeckListener* >::const_iterator loop = aListeners.begin(); + loop != aListeners.end(); + ++loop + ) + { + (*loop)->LayouterChanged( i_rNewLayouter ); + } + } + + //-------------------------------------------------------------------- + void PanelDeckListeners::Dying() + { + while ( !m_aListeners.empty() ) + { + IToolPanelDeckListener* pListener( *m_aListeners.begin() ); + m_aListeners.erase( m_aListeners.begin() ); + pListener->Dying(); + } + } + + //-------------------------------------------------------------------- + void PanelDeckListeners::AddListener( IToolPanelDeckListener& i_rListener ) + { + m_aListeners.push_back( &i_rListener ); + } + + //-------------------------------------------------------------------- + void PanelDeckListeners::RemoveListener( IToolPanelDeckListener& i_rListener ) + { + for ( ::std::vector< IToolPanelDeckListener* >::iterator lookup = m_aListeners.begin(); + lookup != m_aListeners.end(); + ++lookup + ) + { + if ( *lookup == &i_rListener ) + { + m_aListeners.erase( lookup ); + return; + } + } + } + +//........................................................................ +} // namespace svt +//........................................................................ diff --git a/svtools/source/toolpanel/paneldecklisteners.hxx b/svtools/source/toolpanel/paneldecklisteners.hxx new file mode 100755 index 000000000000..bc7e2ae7db88 --- /dev/null +++ b/svtools/source/toolpanel/paneldecklisteners.hxx @@ -0,0 +1,72 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#ifndef PANELDECKLISTENERS_HXX +#define PANELDECKLISTENERS_HXX + +#include "svtools/toolpanel/toolpaneldeck.hxx" + +#include <boost/optional.hpp> +#include <vector> + +//........................................................................ +namespace svt +{ +//........................................................................ + + class IToolPanelDeckListener; + + //==================================================================== + //= PanelDeckListeners + //==================================================================== + /** implements a container for IToolPanelDeckListeners + */ + class PanelDeckListeners + { + public: + PanelDeckListeners(); + ~PanelDeckListeners(); + + // IToolPanelDeckListener equivalents, forward the events to all registered listeners + void PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ); + void PanelRemoved( const size_t i_nPosition ); + void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ); + void LayouterChanged( const PDeckLayouter& i_rNewLayouter ); + void Dying(); + + // listener maintainance + void AddListener( IToolPanelDeckListener& i_rListener ); + void RemoveListener( IToolPanelDeckListener& i_rListener ); + + private: + ::std::vector< IToolPanelDeckListener* > m_aListeners; + }; + +//........................................................................ +} // namespace svt +//........................................................................ + +#endif // PANELDECKLISTENERS_HXX diff --git a/svtools/source/toolpanel/paneltabbar.cxx b/svtools/source/toolpanel/paneltabbar.cxx new file mode 100755 index 000000000000..38aee00c8f55 --- /dev/null +++ b/svtools/source/toolpanel/paneltabbar.cxx @@ -0,0 +1,1356 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "svtools/toolpanel/paneltabbar.hxx" +#include "svtools/toolpanel/toolpaneldeck.hxx" +#include "svtools/svtdata.hxx" +#include "svtools/svtools.hrc" + +#include "tabitemdescriptor.hxx" +#include "paneltabbarpeer.hxx" +#include "tabbargeometry.hxx" + +#include <vcl/button.hxx> +#include <vcl/help.hxx> +#include <vcl/virdev.hxx> +#include <tools/diagnose_ex.h> + +#include <boost/optional.hpp> +#include <vector> + +// space around an item +#define ITEM_OUTER_SPACE 2 * 3 +// spacing before and after an item's text +#define ITEM_TEXT_FLOW_SPACE 5 +// space between item icon and icon text +#define ITEM_ICON_TEXT_DISTANCE 4 + +//........................................................................ +namespace svt +{ +//........................................................................ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::awt::XWindowPeer; + + typedef sal_uInt16 ItemFlags; + + #define ITEM_STATE_NORMAL 0x00 + #define ITEM_STATE_ACTIVE 0x01 + #define ITEM_STATE_HOVERED 0x02 + #define ITEM_STATE_FOCUSED 0x04 + #define ITEM_POSITION_FIRST 0x08 + #define ITEM_POSITION_LAST 0x10 + + //================================================================================================================== + //= helper + //================================================================================================================== + namespace + { + ControlState lcl_ItemToControlState( const ItemFlags i_nItemFlags ) + { + ControlState nState = CTRL_STATE_ENABLED; + if ( i_nItemFlags & ITEM_STATE_FOCUSED ) nState |= CTRL_STATE_FOCUSED | CTRL_STATE_PRESSED; + if ( i_nItemFlags & ITEM_STATE_HOVERED ) nState |= CTRL_STATE_ROLLOVER; + if ( i_nItemFlags & ITEM_STATE_ACTIVE ) nState |= CTRL_STATE_SELECTED; + return nState; + } + } + + //================================================================================================================== + //= ITabBarRenderer + //================================================================================================================== + class SAL_NO_VTABLE ITabBarRenderer + { + public: + /** fills the background of our target device + */ + virtual void renderBackground() const = 0; + virtual Rectangle calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const = 0; + virtual void preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const = 0; + virtual void postRenderItem( Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const = 0; + + // TODO: postRenderItem takes the "real" window, i.e. effectively the tab bar. This is because + // DrawSelectionBackground needs to be applied after everything else is painted, and is available at the Window + // class, but not at the OutputDevice. This makes the API somewhat weird, as we're now mixing operations on the + // target device, done in a normalized geometry, with operations on the window, done in a transformed geometry. + // So, we should get rid of postRenderItem completely. + }; + typedef ::boost::shared_ptr< ITabBarRenderer > PTabBarRenderer; + + //================================================================================================================== + //= VCLItemRenderer - declaration + //================================================================================================================== + class VCLItemRenderer : public ITabBarRenderer + { + public: + VCLItemRenderer( OutputDevice& i_rTargetDevice ) + :m_rTargetDevice( i_rTargetDevice ) + { + } + + // ITabBarRenderer + virtual void renderBackground() const; + virtual Rectangle calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const; + virtual void preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const; + virtual void postRenderItem( Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const; + + protected: + OutputDevice& getTargetDevice() const { return m_rTargetDevice; } + + private: + OutputDevice& m_rTargetDevice; + }; + + //================================================================================================================== + //= VCLItemRenderer - implementation + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + void VCLItemRenderer::renderBackground() const + { + getTargetDevice().DrawRect( Rectangle( Point(), getTargetDevice().GetOutputSizePixel() ) ); + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle VCLItemRenderer::calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const + { + (void)i_nItemFlags; + // no decorations at all + return i_rContentArea; + } + + //------------------------------------------------------------------------------------------------------------------ + void VCLItemRenderer::preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const + { + (void)i_rContentRect; + (void)i_nItemFlags; + } + + //------------------------------------------------------------------------------------------------------------------ + void VCLItemRenderer::postRenderItem( Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const + { + const bool bActive = ( ( i_nItemFlags & ITEM_STATE_ACTIVE ) != 0 ); + const bool bHovered = ( ( i_nItemFlags & ITEM_STATE_HOVERED ) != 0 ); + const bool bFocused = ( ( i_nItemFlags & ITEM_STATE_FOCUSED ) != 0 ); + if ( bActive || bHovered || bFocused ) + { + Rectangle aSelectionRect( i_rItemRect ); + aSelectionRect.Left() += ITEM_OUTER_SPACE / 2; + aSelectionRect.Top() += ITEM_OUTER_SPACE / 2; + aSelectionRect.Right() -= ITEM_OUTER_SPACE / 2; + aSelectionRect.Bottom() -= ITEM_OUTER_SPACE / 2; + i_rActualWindow.DrawSelectionBackground( + aSelectionRect, + ( bHovered || bFocused ) ? ( bActive ? 1 : 2 ) : 0 /* hilight */, + bActive /* check */, + TRUE /* border */, + FALSE /* ext border only */, + 0 /* corner radius */, + NULL, + NULL + ); + } + } + + //================================================================================================================== + //= NWFToolboxItemRenderer - declaration + //================================================================================================================== + class NWFToolboxItemRenderer : public ITabBarRenderer + { + public: + NWFToolboxItemRenderer( OutputDevice& i_rTargetDevice ) + :m_rTargetDevice( i_rTargetDevice ) + { + } + + // ITabBarRenderer + virtual void renderBackground() const; + virtual Rectangle calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const; + virtual void preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const; + virtual void postRenderItem( Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const; + + protected: + OutputDevice& getTargetDevice() const { return m_rTargetDevice; } + + private: + OutputDevice& m_rTargetDevice; + }; + + //================================================================================================================== + //= NWFToolboxItemRenderer - implementation + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + void NWFToolboxItemRenderer::renderBackground() const + { + getTargetDevice().DrawRect( Rectangle( Point(), getTargetDevice().GetOutputSizePixel() ) ); + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle NWFToolboxItemRenderer::calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const + { + // don't ask GetNativeControlRegion, this will not deliver proper results in all cases. + // Instead, simply assume that both the content and the bounding region are the same. +// const ControlState nState( lcl_ItemToControlState( i_nItemFlags ); +// const ImplControlValue aControlValue; +// bool bNativeOK = m_rTargetWindow.GetNativeControlRegion( +// CTRL_TOOLBAR, PART_BUTTON, +// i_rContentArea, nState, +// aControlValue, ::rtl::OUString(), +// aBoundingRegion, aContentRegion +// ); + (void)i_nItemFlags; + return Rectangle( + Point( i_rContentArea.Left() - 1, i_rContentArea.Top() - 1 ), + Size( i_rContentArea.GetWidth() + 2, i_rContentArea.GetHeight() + 2 ) + ); + } + + //------------------------------------------------------------------------------------------------------------------ + void NWFToolboxItemRenderer::preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const + { + const ControlState nState = lcl_ItemToControlState( i_nItemFlags ); + + ImplControlValue aControlValue; + aControlValue.setTristateVal( ( i_nItemFlags & ITEM_STATE_ACTIVE ) ? BUTTONVALUE_ON : BUTTONVALUE_OFF ); + + bool bNativeOK = getTargetDevice().DrawNativeControl( CTRL_TOOLBAR, PART_BUTTON, i_rContentRect, nState, aControlValue, rtl::OUString() ); + (void)bNativeOK; + OSL_ENSURE( bNativeOK, "NWFToolboxItemRenderer::preRenderItem: inconsistent NWF implementation!" ); + // IsNativeControlSupported returned true, previously, otherwise we would not be here ... + } + + //------------------------------------------------------------------------------------------------------------------ + void NWFToolboxItemRenderer::postRenderItem( Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const + { + (void)i_rActualWindow; + (void)i_rItemRect; + (void)i_nItemFlags; + } + + //================================================================================================================== + //= NWFTabItemRenderer - declaration + //================================================================================================================== + class NWFTabItemRenderer : public ITabBarRenderer + { + public: + NWFTabItemRenderer( OutputDevice& i_rTargetDevice ) + :m_rTargetDevice( i_rTargetDevice ) + { + } + + // ITabBarRenderer + virtual void renderBackground() const; + virtual Rectangle calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const; + virtual void preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const; + virtual void postRenderItem( Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const; + + protected: + OutputDevice& getTargetDevice() const { return m_rTargetDevice; } + + private: + OutputDevice& m_rTargetDevice; + }; + + //================================================================================================================== + //= NWFTabItemRenderer - implementation + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + void NWFTabItemRenderer::renderBackground() const + { + Rectangle aBackground( Point(), getTargetDevice().GetOutputSizePixel() ); + getTargetDevice().DrawRect( aBackground ); + + aBackground.Top() = aBackground.Bottom(); + getTargetDevice().DrawNativeControl( CTRL_TAB_PANE, PART_ENTIRE_CONTROL, aBackground, + CTRL_STATE_ENABLED, ImplControlValue(), ::rtl::OUString() ); + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle NWFTabItemRenderer::calculateDecorations( const Rectangle& i_rContentArea, const ItemFlags i_nItemFlags ) const + { + const ControlState nState( lcl_ItemToControlState( i_nItemFlags ) ); + + TabitemValue tiValue; + ImplControlValue aControlValue( (void*)(&tiValue) ); + + Region aBoundingRegion, aContentRegion; + bool bNativeOK = getTargetDevice().GetNativeControlRegion( + CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, + i_rContentArea, nState, + aControlValue, ::rtl::OUString(), + aBoundingRegion, aContentRegion + ); + (void)bNativeOK; + OSL_ENSURE( bNativeOK, "NWFTabItemRenderer::calculateDecorations: GetNativeControlRegion not implemented for CTRL_TAB_ITEM?!" ); + + return aBoundingRegion.GetBoundRect(); + } + + //------------------------------------------------------------------------------------------------------------------ + void NWFTabItemRenderer::preRenderItem( const Rectangle& i_rContentRect, const ItemFlags i_nItemFlags ) const + { + const ControlState nState = lcl_ItemToControlState( i_nItemFlags ); + + TabitemValue tiValue; + if ( i_nItemFlags & ITEM_POSITION_FIRST ) + tiValue.mnAlignment |= TABITEM_FIRST_IN_GROUP; + if ( i_nItemFlags & ITEM_POSITION_LAST ) + tiValue.mnAlignment |= TABITEM_LAST_IN_GROUP; + + ImplControlValue aControlValue( (void *)(&tiValue) ); + + bool bNativeOK = getTargetDevice().DrawNativeControl( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL, i_rContentRect, nState, aControlValue, rtl::OUString() ); + (void)bNativeOK; + OSL_ENSURE( bNativeOK, "NWFTabItemRenderer::preRenderItem: inconsistent NWF implementation!" ); + // IsNativeControlSupported returned true, previously, otherwise we would not be here ... + } + + //------------------------------------------------------------------------------------------------------------------ + void NWFTabItemRenderer::postRenderItem( Window& i_rActualWindow, const Rectangle& i_rItemRect, const ItemFlags i_nItemFlags ) const + { + (void)i_rActualWindow; + (void)i_rItemRect; + (void)i_nItemFlags; + } + + //================================================================================================================== + //= PanelTabBar_Impl + //================================================================================================================== + class PanelTabBar_Impl : public IToolPanelDeckListener + { + public: + PanelTabBar_Impl( PanelTabBar& i_rTabBar, IToolPanelDeck& i_rPanelDeck, const TabAlignment i_eAlignment, const TabItemContent i_eItemContent ); + + ~PanelTabBar_Impl() + { + m_rPanelDeck.RemoveListener( *this ); + } + + // IToolPanelDeckListener + virtual void PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ) + { + (void)i_pPanel; + (void)i_nPosition; + m_bItemsDirty = true; + m_rTabBar.Invalidate(); + + Relayout(); + } + + virtual void PanelRemoved( const size_t i_nPosition ) + { + m_bItemsDirty = true; + m_rTabBar.Invalidate(); + + if ( i_nPosition < m_nScrollPosition ) + --m_nScrollPosition; + + Relayout(); + } + + virtual void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ); + virtual void LayouterChanged( const PDeckLayouter& i_rNewLayouter ); + virtual void Dying(); + + void UpdateScrollButtons() + { + m_aScrollBack.Enable( m_nScrollPosition > 0 ); + m_aScrollForward.Enable( m_nScrollPosition < m_aItems.size() - 1 ); + } + + void Relayout(); + void EnsureItemsCache(); + ::boost::optional< size_t > FindItemForPoint( const Point& i_rPoint ) const; + void DrawItem( const size_t i_nItemIndex, const Rectangle& i_rBoundaries ) const; + void InvalidateItem( const size_t i_nItemIndex, const ItemFlags i_nAdditionalItemFlags = 0 ) const; + void CopyFromRenderDevice( const Rectangle& i_rLogicalRect ) const; + Rectangle GetActualLogicalItemRect( const Rectangle& i_rLogicalItemRect ) const; + Rectangle GetItemScreenRect( const size_t i_nItemPos ) const; + + void FocusItem( const ::boost::optional< size_t >& i_rItemPos ); + + inline bool IsVertical() const + { + return ( ( m_eTabAlignment == TABS_LEFT ) + || ( m_eTabAlignment == TABS_RIGHT ) + ); + } + + protected: + DECL_LINK( OnScroll, const PushButton* ); + + void impl_calcItemRects(); + Size impl_calculateItemContentSize( const PToolPanel& i_pPanel, const TabItemContent i_eItemContent ) const; + void impl_renderItemContent( const PToolPanel& i_pPanel, const Rectangle& i_rContentArea, const TabItemContent i_eItemContent ) const; + ItemFlags impl_getItemFlags( const size_t i_nItemIndex ) const; + + public: + PanelTabBar& m_rTabBar; + TabBarGeometry m_aGeometry; + NormalizedArea m_aNormalizer; + TabAlignment m_eTabAlignment; + IToolPanelDeck& m_rPanelDeck; + + VirtualDevice m_aRenderDevice; + PTabBarRenderer m_pRenderer; + + ::boost::optional< size_t > m_aHoveredItem; + ::boost::optional< size_t > m_aFocusedItem; + bool m_bMouseButtonDown; + + ItemDescriptors m_aItems; + bool m_bItemsDirty; + + PushButton m_aScrollBack; + PushButton m_aScrollForward; + + size_t m_nScrollPosition; + }; + + //================================================================================================================== + //= helper + //================================================================================================================== + namespace + { + //-------------------------------------------------------------------------------------------------------------- + #if OSL_DEBUG_LEVEL > 0 + static void lcl_checkConsistency( const PanelTabBar_Impl& i_rImpl ) + { + if ( !i_rImpl.m_bItemsDirty ) + { + if ( i_rImpl.m_rPanelDeck.GetPanelCount() != i_rImpl.m_aItems.size() ) + { + OSL_ENSURE( false, "lcl_checkConsistency: inconsistent array sizes!" ); + return; + } + for ( size_t i = 0; i < i_rImpl.m_rPanelDeck.GetPanelCount(); ++i ) + { + if ( i_rImpl.m_rPanelDeck.GetPanel( i ).get() != i_rImpl.m_aItems[i].pPanel.get() ) + { + OSL_ENSURE( false, "lcl_checkConsistency: array elements are inconsistent!" ); + return; + } + } + } + } + + #define DBG_CHECK( data ) \ + lcl_checkConsistency( data ); + #else + #define DBG_CHECK( data ) \ + (void)data; + #endif + + //-------------------------------------------------------------------------------------------------------------- + class ClipItemRegion + { + public: + ClipItemRegion( const PanelTabBar_Impl& i_rImpl ) + :m_rDevice( i_rImpl.m_rTabBar ) + { + m_rDevice.Push( PUSH_CLIPREGION ); + m_rDevice.SetClipRegion( i_rImpl.m_aNormalizer.getTransformed( i_rImpl.m_aGeometry.getItemsRect(), i_rImpl.m_eTabAlignment ) ); + } + + ~ClipItemRegion() + { + m_rDevice.Pop(); + } + + private: + OutputDevice& m_rDevice; + }; + } + + //================================================================================================================== + //= PanelTabBar_Impl - implementation + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + PanelTabBar_Impl::PanelTabBar_Impl( PanelTabBar& i_rTabBar, IToolPanelDeck& i_rPanelDeck, const TabAlignment i_eAlignment, const TabItemContent i_eItemContent ) + :m_rTabBar( i_rTabBar ) + ,m_aGeometry( i_eItemContent ) + ,m_aNormalizer() + ,m_eTabAlignment( i_eAlignment ) + ,m_rPanelDeck( i_rPanelDeck ) + ,m_aRenderDevice( i_rTabBar ) + ,m_pRenderer() + ,m_aHoveredItem() + ,m_aFocusedItem() + ,m_bMouseButtonDown( false ) + ,m_aItems() + ,m_bItemsDirty( true ) + ,m_aScrollBack( &i_rTabBar, WB_BEVELBUTTON ) + ,m_aScrollForward( &i_rTabBar, WB_BEVELBUTTON ) + ,m_nScrollPosition( 0 ) + { +#ifdef WNT + if ( m_aRenderDevice.IsNativeControlSupported( CTRL_TAB_ITEM, PART_ENTIRE_CONTROL ) ) + // this mode requires the NWF framework to be able to render those items onto a virtual + // device. For some frameworks (some GTK themes, in particular), this is known to fail. + // So, be on the safe side for the moment. + m_pRenderer.reset( new NWFTabItemRenderer( m_aRenderDevice ) ); + else +#endif + if ( m_aRenderDevice.IsNativeControlSupported( CTRL_TOOLBAR, PART_BUTTON ) ) + m_pRenderer.reset( new NWFToolboxItemRenderer( m_aRenderDevice ) ); + else + m_pRenderer.reset( new VCLItemRenderer( m_aRenderDevice ) ); + + m_aRenderDevice.SetLineColor(); + + m_rPanelDeck.AddListener( *this ); + + m_aScrollBack.SetSymbol( IsVertical() ? SYMBOL_ARROW_UP : SYMBOL_ARROW_LEFT ); + m_aScrollBack.Show(); + m_aScrollBack.SetClickHdl( LINK( this, PanelTabBar_Impl, OnScroll ) ); + m_aScrollBack.SetAccessibleDescription( String( SvtResId( STR_SVT_TOOL_PANEL_BUTTON_FWD ) ) ); + m_aScrollBack.SetAccessibleName( m_aScrollBack.GetAccessibleDescription() ); + + m_aScrollForward.SetSymbol( IsVertical() ? SYMBOL_ARROW_DOWN : SYMBOL_ARROW_RIGHT ); + m_aScrollForward.Show(); + m_aScrollForward.SetClickHdl( LINK( this, PanelTabBar_Impl, OnScroll ) ); + m_aScrollForward.SetAccessibleDescription( String( SvtResId( STR_SVT_TOOL_PANEL_BUTTON_BACK ) ) ); + m_aScrollForward.SetAccessibleName( m_aScrollForward.GetAccessibleDescription() ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::impl_calcItemRects() + { + m_aItems.resize(0); + + Point aCompletePos( m_aGeometry.getFirstItemPosition() ); + Point aIconOnlyPos( aCompletePos ); + Point aTextOnlyPos( aCompletePos ); + + for ( size_t i = 0; + i < m_rPanelDeck.GetPanelCount(); + ++i + ) + { + PToolPanel pPanel( m_rPanelDeck.GetPanel( i ) ); + + ItemDescriptor aItem; + aItem.pPanel = pPanel; + + Rectangle aContentArea; + + const Size aCompleteSize( impl_calculateItemContentSize( pPanel, TABITEM_IMAGE_AND_TEXT ) ); + const Size aIconOnlySize( impl_calculateItemContentSize( pPanel, TABITEM_IMAGE_ONLY ) ); + const Size aTextOnlySize( impl_calculateItemContentSize( pPanel, TABITEM_TEXT_ONLY ) ); + + // TODO: have one method calculating all sizes? + + // remember the three areas + aItem.aCompleteArea = Rectangle( aCompletePos, aCompleteSize ); + aItem.aIconOnlyArea = Rectangle( aIconOnlyPos, aIconOnlySize ); + aItem.aTextOnlyArea = Rectangle( aTextOnlyPos, aTextOnlySize ); + + m_aItems.push_back( aItem ); + + aCompletePos = aItem.aCompleteArea.TopRight(); + aIconOnlyPos = aItem.aIconOnlyArea.TopRight(); + aTextOnlyPos = aItem.aTextOnlyArea.TopRight(); + } + + m_bItemsDirty = false; + } + + //------------------------------------------------------------------------------------------------------------------ + Size PanelTabBar_Impl::impl_calculateItemContentSize( const PToolPanel& i_pPanel, const TabItemContent i_eItemContent ) const + { + // calculate the size needed for the content + OSL_ENSURE( i_eItemContent != TABITEM_AUTO, "PanelTabBar_Impl::impl_calculateItemContentSize: illegal TabItemContent value!" ); + + const Image aImage( i_pPanel->GetImage() ); + const bool bUseImage = !!aImage && ( i_eItemContent != TABITEM_TEXT_ONLY ); + + const ::rtl::OUString sItemText( i_pPanel->GetDisplayName() ); + const bool bUseText = ( sItemText.getLength() != 0 ) && ( i_eItemContent != TABITEM_IMAGE_ONLY ); + + Size aItemContentSize; + if ( bUseImage ) + { + aItemContentSize = aImage.GetSizePixel(); + } + + if ( bUseText ) + { + if ( bUseImage ) + aItemContentSize.Width() += ITEM_ICON_TEXT_DISTANCE; + + // add space for text + const Size aTextSize( m_rTabBar.GetCtrlTextWidth( sItemText ), m_rTabBar.GetTextHeight() ); + aItemContentSize.Width() += aTextSize.Width(); + aItemContentSize.Height() = ::std::max( aItemContentSize.Height(), aTextSize.Height() ); + + aItemContentSize.Width() += 2 * ITEM_TEXT_FLOW_SPACE; + } + + if ( !bUseImage && !bUseText ) + { + // have a minimal size - this is pure heuristics, but if it doesn't suit your needs, then give your panels + // a name and or image! :) + aItemContentSize = Size( 16, 16 ); + } + + aItemContentSize.Width() += 2 * ITEM_OUTER_SPACE; + aItemContentSize.Height() += 2 * ITEM_OUTER_SPACE; + + return aItemContentSize; + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::impl_renderItemContent( const PToolPanel& i_pPanel, const Rectangle& i_rContentArea, const TabItemContent i_eItemContent ) const + { + OSL_ENSURE( i_eItemContent != TABITEM_AUTO, "PanelTabBar_Impl::impl_renderItemContent: illegal TabItemContent value!" ); + + Rectangle aRenderArea( i_rContentArea ); + if ( IsVertical() ) + { + aRenderArea.Top() += ITEM_OUTER_SPACE; + } + else + { + aRenderArea.Left() += ITEM_OUTER_SPACE; + } + + // draw the image + const Image aItemImage( i_pPanel->GetImage() ); + const Size aImageSize( aItemImage.GetSizePixel() ); + const bool bUseImage = !!aItemImage && ( i_eItemContent != TABITEM_TEXT_ONLY ); + + if ( bUseImage ) + { + Point aImagePos; + if ( IsVertical() ) + { + aImagePos.X() = aRenderArea.Left() + ( aRenderArea.GetWidth() - aImageSize.Width() ) / 2; + aImagePos.Y() = aRenderArea.Top(); + } + else + { + aImagePos.X() = aRenderArea.Left(); + aImagePos.Y() = aRenderArea.Top() + ( aRenderArea.GetHeight() - aImageSize.Height() ) / 2; + } + m_rTabBar.DrawImage( aImagePos, aItemImage ); + } + + const ::rtl::OUString sItemText( i_pPanel->GetDisplayName() ); + const bool bUseText = ( sItemText.getLength() != 0 ) && ( i_eItemContent != TABITEM_IMAGE_ONLY ); + + if ( bUseText ) + { + if ( IsVertical() ) + { + if ( bUseImage ) + aRenderArea.Top() += aImageSize.Height() + ITEM_ICON_TEXT_DISTANCE; + aRenderArea.Top() += ITEM_TEXT_FLOW_SPACE; + } + else + { + if ( bUseImage ) + aRenderArea.Left() += aImageSize.Width() + ITEM_ICON_TEXT_DISTANCE; + aRenderArea.Left() += ITEM_TEXT_FLOW_SPACE; + } + + // draw the text + const Size aTextSize( m_rTabBar.GetCtrlTextWidth( sItemText ), m_rTabBar.GetTextHeight() ); + Point aTextPos( aRenderArea.TopLeft() ); + if ( IsVertical() ) + { + m_rTabBar.Push( PUSH_FONT ); + + Font aFont( m_rTabBar.GetFont() ); + aFont.SetOrientation( 2700 ); + aFont.SetVertical( TRUE ); + m_rTabBar.SetFont( aFont ); + + aTextPos.X() += aTextSize.Height(); + aTextPos.X() += ( aRenderArea.GetWidth() - aTextSize.Height() ) / 2; + } + else + { + aTextPos.Y() += ( aRenderArea.GetHeight() - aTextSize.Height() ) / 2; + } + + m_rTabBar.DrawText( aTextPos, sItemText ); + + if ( IsVertical() ) + { + m_rTabBar.Pop(); + } + } + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::CopyFromRenderDevice( const Rectangle& i_rLogicalRect ) const + { + BitmapEx aBitmap( m_aRenderDevice.GetBitmapEx( + i_rLogicalRect.TopLeft(), + Size( + i_rLogicalRect.GetSize().Width(), + i_rLogicalRect.GetSize().Height() + ) + ) ); + if ( IsVertical() ) + { + aBitmap.Rotate( 2700, COL_BLACK ); + if ( m_eTabAlignment == TABS_LEFT ) + aBitmap.Mirror( BMP_MIRROR_HORZ ); + } + else if ( m_eTabAlignment == TABS_BOTTOM ) + { + aBitmap.Mirror( BMP_MIRROR_VERT ); + } + + const Rectangle aActualRect( m_aNormalizer.getTransformed( i_rLogicalRect, m_eTabAlignment ) ); + m_rTabBar.DrawBitmapEx( aActualRect.TopLeft(), aBitmap ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::InvalidateItem( const size_t i_nItemIndex, const ItemFlags i_nAdditionalItemFlags ) const + { + const ItemDescriptor& rItem( m_aItems[ i_nItemIndex ] ); + const ItemFlags nItemFlags( impl_getItemFlags( i_nItemIndex ) | i_nAdditionalItemFlags ); + + const Rectangle aNormalizedContent( GetActualLogicalItemRect( rItem.GetCurrentRect() ) ); + const Rectangle aNormalizedBounds( m_pRenderer->calculateDecorations( aNormalizedContent, nItemFlags ) ); + + const Rectangle aActualBounds = m_aNormalizer.getTransformed( aNormalizedBounds, m_eTabAlignment ); + m_rTabBar.Invalidate( aActualBounds ); + } + + //------------------------------------------------------------------------------------------------------------------ + ItemFlags PanelTabBar_Impl::impl_getItemFlags( const size_t i_nItemIndex ) const + { + ItemFlags nItemFlags( ITEM_STATE_NORMAL ); + if ( m_aHoveredItem == i_nItemIndex ) + { + nItemFlags |= ITEM_STATE_HOVERED; + if ( m_bMouseButtonDown ) + nItemFlags |= ITEM_STATE_ACTIVE; + } + + if ( m_rPanelDeck.GetActivePanel() == i_nItemIndex ) + nItemFlags |= ITEM_STATE_ACTIVE; + + if ( m_aFocusedItem == i_nItemIndex ) + nItemFlags |= ITEM_STATE_FOCUSED; + + if ( 0 == i_nItemIndex ) + nItemFlags |= ITEM_POSITION_FIRST; + + if ( m_rPanelDeck.GetPanelCount() - 1 == i_nItemIndex ) + nItemFlags |= ITEM_POSITION_LAST; + + return nItemFlags; + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::DrawItem( const size_t i_nItemIndex, const Rectangle& i_rBoundaries ) const + { + const ItemDescriptor& rItem( m_aItems[ i_nItemIndex ] ); + const ItemFlags nItemFlags( impl_getItemFlags( i_nItemIndex ) ); + + // the normalized bounding and content rect + const Rectangle aNormalizedContent( GetActualLogicalItemRect( rItem.GetCurrentRect() ) ); + const Rectangle aNormalizedBounds( m_pRenderer->calculateDecorations( aNormalizedContent, nItemFlags ) ); + + // check whether the item actually overlaps with the painting area + if ( !i_rBoundaries.IsEmpty() ) + { + const Rectangle aItemRect( GetActualLogicalItemRect( rItem.GetCurrentRect() ) ); + if ( !aItemRect.IsOver( i_rBoundaries ) ) + return; + } + + m_rTabBar.SetUpdateMode( FALSE ); + + // the aligned bounding and content rect + const Rectangle aActualBounds = m_aNormalizer.getTransformed( aNormalizedBounds, m_eTabAlignment ); + const Rectangle aActualContent = m_aNormalizer.getTransformed( aNormalizedContent, m_eTabAlignment ); + + // render item "background" layer + m_pRenderer->preRenderItem( aNormalizedContent, nItemFlags ); + + // copy from the virtual device to ourself + CopyFromRenderDevice( aNormalizedBounds ); + + // render the actual item content + impl_renderItemContent( rItem.pPanel, aActualContent, rItem.eContent ); + + // render item "foreground" layer + m_pRenderer->postRenderItem( m_rTabBar, aActualBounds, nItemFlags ); + + m_rTabBar.SetUpdateMode( TRUE ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::EnsureItemsCache() + { + if ( m_bItemsDirty == false ) + { + DBG_CHECK( *this ); + return; + } + impl_calcItemRects(); + OSL_POSTCOND( m_bItemsDirty == false, "PanelTabBar_Impl::EnsureItemsCache: cache still dirty!" ); + DBG_CHECK( *this ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::Relayout() + { + EnsureItemsCache(); + + const Size aOutputSize( m_rTabBar.GetOutputSizePixel() ); + m_aNormalizer = NormalizedArea( Rectangle( Point(), aOutputSize ), IsVertical() ); + const Size aLogicalOutputSize( m_aNormalizer.getReferenceSize() ); + + // forward actual output size to our render device + m_aRenderDevice.SetOutputSizePixel( aLogicalOutputSize ); + + // re-calculate the size of the scroll buttons and of the items + m_aGeometry.relayout( aLogicalOutputSize, m_aItems ); + + if ( m_aGeometry.getButtonBackRect().IsEmpty() ) + { + m_aScrollBack.Hide(); + } + else + { + const Rectangle aButtonBack( m_aNormalizer.getTransformed( m_aGeometry.getButtonBackRect(), m_eTabAlignment ) ); + m_aScrollBack.SetPosSizePixel( aButtonBack.TopLeft(), aButtonBack.GetSize() ); + m_aScrollBack.Show(); + } + + if ( m_aGeometry.getButtonForwardRect().IsEmpty() ) + { + m_aScrollForward.Hide(); + } + else + { + const Rectangle aButtonForward( m_aNormalizer.getTransformed( m_aGeometry.getButtonForwardRect(), m_eTabAlignment ) ); + m_aScrollForward.SetPosSizePixel( aButtonForward.TopLeft(), aButtonForward.GetSize() ); + m_aScrollForward.Show(); + } + + UpdateScrollButtons(); + } + + //------------------------------------------------------------------------------------------------------------------ + ::boost::optional< size_t > PanelTabBar_Impl::FindItemForPoint( const Point& i_rPoint ) const + { + Point aPoint( IsVertical() ? i_rPoint.Y() : i_rPoint.X(), IsVertical() ? i_rPoint.X() : i_rPoint.Y() ); + + if ( !m_aGeometry.getItemsRect().IsInside( aPoint ) ) + return ::boost::optional< size_t >(); + + size_t i=0; + for ( ItemDescriptors::const_iterator item = m_aItems.begin(); + item != m_aItems.end(); + ++item, ++i + ) + { + Rectangle aItemRect( GetActualLogicalItemRect( item->GetCurrentRect() ) ); + if ( aItemRect.IsInside( aPoint ) ) + { + return ::boost::optional< size_t >( i ); + } + } + return ::boost::optional< size_t >(); + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle PanelTabBar_Impl::GetItemScreenRect( const size_t i_nItemPos ) const + { + ENSURE_OR_RETURN( i_nItemPos < m_aItems.size(), "PanelTabBar_Impl::GetItemScreenRect: invalid item pos!", Rectangle() ); + const ItemDescriptor& rItem( m_aItems[ i_nItemPos ] ); + const Rectangle aItemRect( m_aNormalizer.getTransformed( + GetActualLogicalItemRect( rItem.GetCurrentRect() ), + m_eTabAlignment ) ); + + const Rectangle aTabBarRect( m_rTabBar.GetWindowExtentsRelative( NULL ) ); + return Rectangle( + Point( aTabBarRect.Left() + aItemRect.Left(), aTabBarRect.Top() + aItemRect.Top() ), + aItemRect.GetSize() + ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::FocusItem( const ::boost::optional< size_t >& i_rItemPos ) + { + // reset old focus item + if ( !!m_aFocusedItem ) + InvalidateItem( *m_aFocusedItem ); + m_aFocusedItem.reset(); + + // mark the active icon as focused + if ( !!i_rItemPos ) + { + m_aFocusedItem = i_rItemPos; + InvalidateItem( *m_aFocusedItem ); + } + } + + //------------------------------------------------------------------------------------------------------------------ + IMPL_LINK( PanelTabBar_Impl, OnScroll, const PushButton*, i_pButton ) + { + if ( i_pButton == &m_aScrollBack ) + { + OSL_ENSURE( m_nScrollPosition > 0, "PanelTabBar_Impl::OnScroll: inconsistency!" ); + --m_nScrollPosition; + m_rTabBar.Invalidate(); + } + else if ( i_pButton == &m_aScrollForward ) + { + OSL_ENSURE( m_nScrollPosition < m_aItems.size() - 1, "PanelTabBar_Impl::OnScroll: inconsistency!" ); + ++m_nScrollPosition; + m_rTabBar.Invalidate(); + } + + UpdateScrollButtons(); + + return 0L; + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle PanelTabBar_Impl::GetActualLogicalItemRect( const Rectangle& i_rLogicalItemRect ) const + { + // care for the offset imposed by our geometry, i.e. whether or not we have scroll buttons + Rectangle aItemRect( i_rLogicalItemRect ); + aItemRect.Move( m_aGeometry.getItemsRect().Left() - m_aGeometry.getButtonBackRect().Left(), 0 ); + + // care for the current scroll position + OSL_ENSURE( m_nScrollPosition < m_aItems.size(), "GetActualLogicalItemRect: invalid scroll position!" ); + if ( ( m_nScrollPosition > 0 ) && ( m_nScrollPosition < m_aItems.size() ) ) + { + long nOffsetX = m_aItems[ m_nScrollPosition ].GetCurrentRect().Left() - m_aItems[ 0 ].GetCurrentRect().Left(); + long nOffsetY = m_aItems[ m_nScrollPosition ].GetCurrentRect().Top() - m_aItems[ 0 ].GetCurrentRect().Top(); + aItemRect.Move( -nOffsetX, -nOffsetY ); + } + + return aItemRect; + } + + //================================================================================================================== + //= PanelTabBar_Impl + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) + { + EnsureItemsCache(); + + if ( !!i_rOldActive ) + InvalidateItem( *i_rOldActive, ITEM_STATE_ACTIVE ); + if ( !!i_rNewActive ) + InvalidateItem( *i_rNewActive ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::LayouterChanged( const PDeckLayouter& i_rNewLayouter ) + { + // not interested in + (void)i_rNewLayouter; + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar_Impl::Dying() + { + // not interested in - the notifier is a member of this instance here, so we're dying ourself at the moment + } + + //================================================================================================================== + //= PanelTabBar + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + PanelTabBar::PanelTabBar( Window& i_rParentWindow, IToolPanelDeck& i_rPanelDeck, const TabAlignment i_eAlignment, const TabItemContent i_eItemContent ) + :Control( &i_rParentWindow, 0 ) + ,m_pImpl( new PanelTabBar_Impl( *this, i_rPanelDeck, i_eAlignment, i_eItemContent ) ) + { + DBG_CHECK( *m_pImpl ); + } + + //------------------------------------------------------------------------------------------------------------------ + PanelTabBar::~PanelTabBar() + { + } + + //------------------------------------------------------------------------------------------------------------------ + TabItemContent PanelTabBar::GetTabItemContent() const + { + return m_pImpl->m_aGeometry.getItemContent(); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::SetTabItemContent( const TabItemContent& i_eItemContent ) + { + m_pImpl->m_aGeometry.setItemContent( i_eItemContent ); + m_pImpl->Relayout(); + Invalidate(); + } + + //------------------------------------------------------------------------------------------------------------------ + IToolPanelDeck& PanelTabBar::GetPanelDeck() const + { + DBG_CHECK( *m_pImpl ); + return m_pImpl->m_rPanelDeck; + } + + //------------------------------------------------------------------------------------------------------------------ + Size PanelTabBar::GetOptimalSize( WindowSizeType i_eType ) const + { + m_pImpl->EnsureItemsCache(); + Size aOptimalSize( m_pImpl->m_aGeometry.getOptimalSize( m_pImpl->m_aItems, i_eType == WINDOWSIZE_MINIMUM ) ); + if ( m_pImpl->IsVertical() ) + ::std::swap( aOptimalSize.Width(), aOptimalSize.Height() ); + return aOptimalSize; + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::Resize() + { + Control::Resize(); + m_pImpl->Relayout(); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::Paint( const Rectangle& i_rRect ) + { + m_pImpl->EnsureItemsCache(); + + // background + const Rectangle aNormalizedPaintArea( m_pImpl->m_aNormalizer.getNormalized( i_rRect, m_pImpl->m_eTabAlignment ) ); + m_pImpl->m_aRenderDevice.Push( PUSH_CLIPREGION ); + m_pImpl->m_aRenderDevice.SetClipRegion( aNormalizedPaintArea ); + m_pImpl->m_pRenderer->renderBackground(); + m_pImpl->m_aRenderDevice.Pop(); + m_pImpl->CopyFromRenderDevice( aNormalizedPaintArea ); + + // ensure the items really paint into their own playground only + ClipItemRegion aClipItems( *m_pImpl ); + + const Rectangle aLogicalPaintRect( m_pImpl->m_aNormalizer.getNormalized( i_rRect, m_pImpl->m_eTabAlignment ) ); + + const ::boost::optional< size_t > aActivePanel( m_pImpl->m_rPanelDeck.GetActivePanel() ); + const ::boost::optional< size_t > aHoveredPanel( m_pImpl->m_aHoveredItem ); + + // items: + // 1. paint all non-active, non-hovered items + size_t i=0; + for ( ItemDescriptors::const_iterator item = m_pImpl->m_aItems.begin(); + item != m_pImpl->m_aItems.end(); + ++item, ++i + ) + { + if ( i == aActivePanel ) + continue; + + if ( aHoveredPanel == i ) + continue; + + m_pImpl->DrawItem( i, aLogicalPaintRect ); + } + + // 2. paint the item which is hovered, /without/ the mouse button pressed down + if ( !!aHoveredPanel && !m_pImpl->m_bMouseButtonDown ) + m_pImpl->DrawItem( *aHoveredPanel, aLogicalPaintRect ); + + // 3. paint the active item + if ( !!aActivePanel ) + m_pImpl->DrawItem( *aActivePanel, aLogicalPaintRect ); + + // 4. paint the item which is hovered, /with/ the mouse button pressed down + if ( !!aHoveredPanel && m_pImpl->m_bMouseButtonDown ) + m_pImpl->DrawItem( *aHoveredPanel, aLogicalPaintRect ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::MouseMove( const MouseEvent& i_rMouseEvent ) + { + m_pImpl->EnsureItemsCache(); + + ::boost::optional< size_t > aOldItem( m_pImpl->m_aHoveredItem ); + ::boost::optional< size_t > aNewItem( m_pImpl->FindItemForPoint( i_rMouseEvent.GetPosPixel() ) ); + + if ( i_rMouseEvent.IsLeaveWindow() ) + aNewItem.reset(); + + if ( aOldItem != aNewItem ) + { + if ( !!aOldItem ) + m_pImpl->InvalidateItem( *aOldItem ); + + m_pImpl->m_aHoveredItem = aNewItem; + + if ( !!aNewItem ) + m_pImpl->InvalidateItem( *aNewItem ); + } + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::MouseButtonDown( const MouseEvent& i_rMouseEvent ) + { + Control::MouseButtonDown( i_rMouseEvent ); + + if ( !i_rMouseEvent.IsLeft() ) + return; + + m_pImpl->EnsureItemsCache(); + + ::boost::optional< size_t > aHitItem( m_pImpl->FindItemForPoint( i_rMouseEvent.GetPosPixel() ) ); + if ( !aHitItem ) + return; + + CaptureMouse(); + m_pImpl->m_bMouseButtonDown = true; + + m_pImpl->InvalidateItem( *aHitItem ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::MouseButtonUp( const MouseEvent& i_rMouseEvent ) + { + Control::MouseButtonUp( i_rMouseEvent ); + + if ( m_pImpl->m_bMouseButtonDown ) + { + ::boost::optional< size_t > aHitItem( m_pImpl->FindItemForPoint( i_rMouseEvent.GetPosPixel() ) ); + if ( !!aHitItem ) + { + // re-draw that item now that we're not in mouse-down mode anymore + m_pImpl->InvalidateItem( *aHitItem ); + // activate the respective panel + m_pImpl->m_rPanelDeck.ActivatePanel( *aHitItem ); + } + + OSL_ENSURE( IsMouseCaptured(), "PanelTabBar::MouseButtonUp: inconsistency!" ); + if ( IsMouseCaptured() ) + ReleaseMouse(); + m_pImpl->m_bMouseButtonDown = false; + } + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::RequestHelp( const HelpEvent& i_rHelpEvent ) + { + m_pImpl->EnsureItemsCache(); + + ::boost::optional< size_t > aHelpItem( m_pImpl->FindItemForPoint( ScreenToOutputPixel( i_rHelpEvent.GetMousePosPixel() ) ) ); + if ( !aHelpItem ) + return; + + const ItemDescriptor& rItem( m_pImpl->m_aItems[ *aHelpItem ] ); + if ( rItem.eContent != TABITEM_IMAGE_ONLY ) + // if the text is displayed for the item, we do not need to show it as tooltip + return; + + const ::rtl::OUString sItemText( rItem.pPanel->GetDisplayName() ); + if ( i_rHelpEvent.GetMode() == HELPMODE_BALLOON ) + Help::ShowBalloon( this, OutputToScreenPixel( rItem.GetCurrentRect().Center() ), rItem.GetCurrentRect(), sItemText ); + else + Help::ShowQuickHelp( this, rItem.GetCurrentRect(), sItemText ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::GetFocus() + { + Control::GetFocus(); + if ( !m_pImpl->m_aFocusedItem ) + m_pImpl->FocusItem( m_pImpl->m_rPanelDeck.GetActivePanel() ); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::LoseFocus() + { + Control::LoseFocus(); + + if ( !!m_pImpl->m_aFocusedItem ) + { + m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem ); + } + + m_pImpl->m_aFocusedItem.reset(); + } + + //------------------------------------------------------------------------------------------------------------------ + class KeyInputHandler + { + public: + KeyInputHandler( Control& i_rControl, const KeyEvent& i_rKeyEvent ) + :m_rControl( i_rControl ) + ,m_rKeyEvent( i_rKeyEvent ) + ,m_bHandled( false ) + { + } + + ~KeyInputHandler() + { + if ( !m_bHandled ) + m_rControl.Control::KeyInput( m_rKeyEvent ); + } + + void setHandled() + { + m_bHandled = true; + } + + private: + Control& m_rControl; + const KeyEvent& m_rKeyEvent; + bool m_bHandled; + }; + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::KeyInput( const KeyEvent& i_rKeyEvent ) + { + KeyInputHandler aKeyInputHandler( *this, i_rKeyEvent ); + + const KeyCode& rKeyCode( i_rKeyEvent.GetKeyCode() ); + if ( rKeyCode.GetModifier() != 0 ) + // only interested in mere key presses + return; + + // if there are less than 2 panels, we cannot travel them ... + const size_t nPanelCount( m_pImpl->m_rPanelDeck.GetPanelCount() ); + if ( nPanelCount < 2 ) + return; + + OSL_PRECOND( !!m_pImpl->m_aFocusedItem, "PanelTabBar::KeyInput: we should have a focused item here!" ); + // if we get KeyInput events, we should have the focus. In this case, m_aFocusedItem should not be empty, + // except if there are no panels, but then we bail out of this method here earlier ... + + bool bFocusNext = false; + bool bFocusPrev = false; + + switch ( rKeyCode.GetCode() ) + { + case KEY_UP: bFocusPrev = true; break; + case KEY_DOWN: bFocusNext = true; break; + case KEY_LEFT: + if ( IsRTLEnabled() ) + bFocusNext = true; + else + bFocusPrev = true; + break; + case KEY_RIGHT: + if ( IsRTLEnabled() ) + bFocusPrev = true; + else + bFocusNext = true; + break; + case KEY_RETURN: + m_pImpl->m_rPanelDeck.ActivatePanel( *m_pImpl->m_aFocusedItem ); + break; + } + + if ( !bFocusNext && !bFocusPrev ) + return; + + m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem ); + if ( bFocusNext ) + { + m_pImpl->m_aFocusedItem.reset( ( *m_pImpl->m_aFocusedItem + 1 ) % nPanelCount ); + } + else + { + m_pImpl->m_aFocusedItem.reset( ( *m_pImpl->m_aFocusedItem + nPanelCount - 1 ) % nPanelCount ); + } + m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem ); + + // don't delegate to base class + aKeyInputHandler.setHandled(); + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::DataChanged( const DataChangedEvent& i_rDataChanedEvent ) + { + Control::DataChanged( i_rDataChanedEvent ); + + if ( ( i_rDataChanedEvent.GetType() == DATACHANGED_SETTINGS ) + && ( ( i_rDataChanedEvent.GetFlags() & SETTINGS_STYLE ) != 0 ) + ) + { + Invalidate(); + } + } + + //------------------------------------------------------------------------------------------------------------------ + bool PanelTabBar::IsVertical() const + { + return m_pImpl->IsVertical(); + } + + //------------------------------------------------------------------------------------------------------------------ + PushButton& PanelTabBar::GetScrollButton( const bool i_bForward ) + { + return i_bForward ? m_pImpl->m_aScrollForward : m_pImpl->m_aScrollBack; + } + + //------------------------------------------------------------------------------------------------------------------ + ::boost::optional< size_t > PanelTabBar::GetFocusedPanelItem() const + { + return m_pImpl->m_aFocusedItem; + } + + //------------------------------------------------------------------------------------------------------------------ + void PanelTabBar::FocusPanelItem( const size_t i_nItemPos ) + { + ENSURE_OR_RETURN_VOID( i_nItemPos < m_pImpl->m_rPanelDeck.GetPanelCount(), "PanelTabBar::FocusPanelItem: illegal item pos!" ); + + if ( !HasChildPathFocus() ) + GrabFocus(); + + m_pImpl->FocusItem( i_nItemPos ); + OSL_POSTCOND( !!m_pImpl->m_aFocusedItem, "PanelTabBar::FocusPanelItem: have the focus, but no focused item?" ); + if ( !!m_pImpl->m_aFocusedItem ) + m_pImpl->InvalidateItem( *m_pImpl->m_aFocusedItem ); + m_pImpl->m_aFocusedItem.reset( i_nItemPos ); + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle PanelTabBar::GetItemScreenRect( const size_t i_nItemPos ) const + { + return m_pImpl->GetItemScreenRect( i_nItemPos ); + } + + //------------------------------------------------------------------------------------------------------------------ + Reference< XWindowPeer > PanelTabBar::GetComponentInterface( BOOL i_bCreate ) + { + Reference< XWindowPeer > xWindowPeer( Control::GetComponentInterface( FALSE ) ); + if ( !xWindowPeer.is() && i_bCreate ) + { + xWindowPeer.set( new PanelTabBarPeer( *this ) ); + SetComponentInterface( xWindowPeer ); + } + return xWindowPeer; + } + +//........................................................................ +} // namespace svt +//........................................................................ diff --git a/svtools/source/toolpanel/paneltabbarpeer.cxx b/svtools/source/toolpanel/paneltabbarpeer.cxx new file mode 100644 index 000000000000..d8329109ffb4 --- /dev/null +++ b/svtools/source/toolpanel/paneltabbarpeer.cxx @@ -0,0 +1,101 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "paneltabbarpeer.hxx" +#include "svtools/toolpanel/paneltabbar.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/DisposedException.hpp> +/** === end UNO includes === **/ + +#include <tools/diagnose_ex.h> + +//........................................................................ +namespace svt +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::accessibility::XAccessibleContext; + using ::com::sun::star::lang::DisposedException; + /** === end UNO using === **/ + + //================================================================================================================== + //= PanelTabBarPeer + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + PanelTabBarPeer::PanelTabBarPeer( PanelTabBar& i_rTabBar ) + :VCLXWindow() + ,m_pTabBar( &i_rTabBar ) + { + } + + //------------------------------------------------------------------------------------------------------------------ + PanelTabBarPeer::~PanelTabBarPeer() + { + } + + //------------------------------------------------------------------------------------------------------------------ + Reference< XAccessibleContext > PanelTabBarPeer::CreateAccessibleContext() + { + ::vos::OGuard aSolarGuard( GetMutex() ); + if ( m_pTabBar == NULL ) + throw DisposedException( ::rtl::OUString(), *this ); + + + + Window* pAccessibleParent( m_pTabBar->GetAccessibleParentWindow() ); + ENSURE_OR_RETURN( pAccessibleParent != NULL, "no accessible parent => no accessible context", NULL ); + Reference< XAccessible > xAccessibleParent( pAccessibleParent->GetAccessible(), UNO_SET_THROW ); + return m_aAccessibleFactory.getFactory().createAccessibleToolPanelTabBar( xAccessibleParent, m_pTabBar->GetPanelDeck(), *m_pTabBar ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL PanelTabBarPeer::dispose() throw(RuntimeException) + { + { + ::vos::OGuard aSolarGuard( GetMutex() ); + m_pTabBar = NULL; + } + VCLXWindow::dispose(); + } + +//........................................................................ +} // namespace svt +//........................................................................ diff --git a/svtools/source/toolpanel/paneltabbarpeer.hxx b/svtools/source/toolpanel/paneltabbarpeer.hxx new file mode 100644 index 000000000000..7c2e5188d994 --- /dev/null +++ b/svtools/source/toolpanel/paneltabbarpeer.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SVT_PANELTABBARPEER_HXX +#define SVT_PANELTABBARPEER_HXX + +#include "svtaccessiblefactory.hxx" + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ + +#include <toolkit/awt/vclxwindow.hxx> + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + class PanelTabBar; + //==================================================================== + //= PanelTabBarPeer + //==================================================================== + class PanelTabBarPeer : public VCLXWindow + { + public: + PanelTabBarPeer( PanelTabBar& i_rTabBar ); + + protected: + ~PanelTabBarPeer(); + + // VCLXWindow overridables + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > CreateAccessibleContext(); + + // XComponent + void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException); + + private: + AccessibleFactoryAccess m_aAccessibleFactory; + PanelTabBar* m_pTabBar; + }; + +//........................................................................ +} // namespace svt +//........................................................................ + +#endif // SVT_PANELTABBARPEER_HXX diff --git a/svtools/source/toolpanel/refbase.cxx b/svtools/source/toolpanel/refbase.cxx new file mode 100644 index 000000000000..f41aa2d9bb9c --- /dev/null +++ b/svtools/source/toolpanel/refbase.cxx @@ -0,0 +1,56 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "svtools/toolpanel/refbase.hxx" + +//........................................................................ +namespace svt +{ +//........................................................................ + + //==================================================================== + //= RefBase + //==================================================================== + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL RefBase::acquire() + { + return osl_incrementInterlockedCount( &m_refCount ); + } + + //-------------------------------------------------------------------- + oslInterlockedCount SAL_CALL RefBase::release() + { + oslInterlockedCount newCount = osl_decrementInterlockedCount( &m_refCount ); + if ( 0 == newCount ) + delete this; + return newCount; + } + +//........................................................................ +} // namespace svt +//........................................................................ diff --git a/svtools/source/toolpanel/tabbargeometry.cxx b/svtools/source/toolpanel/tabbargeometry.cxx new file mode 100644 index 000000000000..45c40cee6ef2 --- /dev/null +++ b/svtools/source/toolpanel/tabbargeometry.cxx @@ -0,0 +1,328 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "tabbargeometry.hxx" + +#include <basegfx/range/b2drange.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <vcl/window.hxx> + +#include <algorithm> + +// the width (or height, depending on alignment) of the scroll buttons +#define BUTTON_FLOW_WIDTH 20 +// the space between the scroll buttons and the items +#define BUTTON_FLOW_SPACE 2 +// outer space to apply between the tab bar borders and any content. Note that those refer to a "normalized" geometry, +// i.e. if the tab bar were aligned at the top +#define OUTER_SPACE_LEFT 2 +#define OUTER_SPACE_TOP 4 +#define OUTER_SPACE_RIGHT 4 +#define OUTER_SPACE_BOTTOM 2 + +// outer space to apply between the area for the items, and the actual items. They refer to a normalized geometry. +#define ITEMS_INSET_LEFT 4 +#define ITEMS_INSET_TOP 3 +#define ITEMS_INSET_RIGHT 4 +#define ITEMS_INSET_BOTTOM 0 + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + //================================================================================================================== + //= helper + //================================================================================================================== + namespace + { + //-------------------------------------------------------------------------------------------------------------- + static void lcl_transform( Rectangle& io_rRect, const ::basegfx::B2DHomMatrix& i_rTransformation ) + { + ::basegfx::B2DRange aRect( io_rRect.Left(), io_rRect.Top(), io_rRect.Right(), io_rRect.Bottom() ); + aRect.transform( i_rTransformation ); + io_rRect.Left() = long( aRect.getMinX() ); + io_rRect.Top() = long( aRect.getMinY() ); + io_rRect.Right() = long( aRect.getMaxX() ); + io_rRect.Bottom() = long( aRect.getMaxY() ); + } + + //-------------------------------------------------------------------------------------------------------------- + /** transforms the given, possible rotated playground, + */ + void lcl_rotate( const Rectangle& i_rReference, Rectangle& io_rArea, const bool i_bRight ) + { + // step 1: move the to-be-upper-left corner (left/bottom) of the rectangle to (0,0) + ::basegfx::B2DHomMatrix aTransformation; + aTransformation.translate( + i_bRight ? -i_rReference.Left() : -i_rReference.Right(), + i_bRight ? -i_rReference.Bottom() : -i_rReference.Top() + ); + + // step 2: rotate by -90 degrees + aTransformation.rotate( i_bRight ? +F_PI2 : -F_PI2 ); + // note: + // on the screen, the ordinate goes top-down, while basegfx calculates in a system where the + // ordinate goes bottom-up; thus the "wrong" sign before F_PI2 here + + // step 3: move back to original coordinates + aTransformation.translate( i_rReference.Left(), i_rReference.Top() ); + + // apply transformation + lcl_transform( io_rArea, aTransformation ); + } + } + + //------------------------------------------------------------------------------------------------------------------ + void lcl_mirrorHorizontally( const Rectangle& i_rReferenceArea, Rectangle& io_rArea ) + { + io_rArea.Left() = i_rReferenceArea.Left() + i_rReferenceArea.Right() - io_rArea.Left(); + io_rArea.Right() = i_rReferenceArea.Left() + i_rReferenceArea.Right() - io_rArea.Right(); + ::std::swap( io_rArea.Left(), io_rArea.Right() ); + } + + //------------------------------------------------------------------------------------------------------------------ + void lcl_mirrorVertically( const Rectangle& i_rReferenceArea, Rectangle& io_rArea ) + { + io_rArea.Top() = i_rReferenceArea.Top() + i_rReferenceArea.Bottom() - io_rArea.Top(); + io_rArea.Bottom() = i_rReferenceArea.Top() + i_rReferenceArea.Bottom() - io_rArea.Bottom(); + ::std::swap( io_rArea.Top(), io_rArea.Bottom() ); + } + + //================================================================================================================== + //= NormalizedArea + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + NormalizedArea::NormalizedArea() + :m_aReference() + { + } + + //------------------------------------------------------------------------------------------------------------------ + NormalizedArea::NormalizedArea( const Rectangle& i_rReference, const bool i_bIsVertical ) + :m_aReference( i_bIsVertical ? Rectangle( i_rReference.TopLeft(), Size( i_rReference.GetHeight(), i_rReference.GetWidth() ) ) : i_rReference ) + { + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle NormalizedArea::getTransformed( const Rectangle& i_rArea, const TabAlignment i_eTargetAlignment ) const + { + Rectangle aResult( i_rArea ); + + if ( ( i_eTargetAlignment == TABS_RIGHT ) + || ( i_eTargetAlignment == TABS_LEFT ) + ) + { + lcl_rotate( m_aReference, aResult, true ); + + if ( i_eTargetAlignment == TABS_LEFT ) + { + Rectangle aReference( m_aReference ); + aReference.Transpose(); + lcl_mirrorHorizontally( aReference, aResult ); + } + } + else + if ( i_eTargetAlignment == TABS_BOTTOM ) + { + lcl_mirrorVertically( m_aReference, aResult ); + } + + return aResult; + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle NormalizedArea::getNormalized( const Rectangle& i_rArea, const TabAlignment i_eTargetAlignment ) const + { + Rectangle aResult( i_rArea ); + + if ( ( i_eTargetAlignment == TABS_RIGHT ) + || ( i_eTargetAlignment == TABS_LEFT ) + ) + { + Rectangle aReference( m_aReference ); + lcl_rotate( m_aReference, aReference, true ); + + if ( i_eTargetAlignment == TABS_LEFT ) + { + lcl_mirrorHorizontally( aReference, aResult ); + } + + lcl_rotate( aReference, aResult, false ); + } + else + if ( i_eTargetAlignment == TABS_BOTTOM ) + { + lcl_mirrorVertically( m_aReference, aResult ); + } + return aResult; + } + + //================================================================================================================== + //= TabBarGeometry + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + TabBarGeometry::TabBarGeometry( const TabItemContent i_eItemContent ) + :m_eTabItemContent( i_eItemContent ) + ,m_aItemsInset() + ,m_aButtonBackRect() + ,m_aItemsRect() + ,m_aButtonForwardRect() + { + m_aItemsInset.Left() = ITEMS_INSET_LEFT; + m_aItemsInset.Top() = ITEMS_INSET_TOP; + m_aItemsInset.Right() = ITEMS_INSET_RIGHT; + m_aItemsInset.Bottom() = ITEMS_INSET_BOTTOM; + } + + //------------------------------------------------------------------------------------------------------------------ + TabBarGeometry::~TabBarGeometry() + { + } + + //------------------------------------------------------------------------------------------------------------------ + bool TabBarGeometry::impl_fitItems( ItemDescriptors& io_rItems ) const + { + if ( io_rItems.empty() ) + // nothing to do, "no items" perfectly fit into any space we have ... + return true; + + // the available size + Size aOutputSize( getItemsRect().GetSize() ); + // shrunk by the outer space + aOutputSize.Width() -= m_aItemsInset.Right(); + aOutputSize.Height() -= m_aItemsInset.Bottom(); + const Rectangle aFitInto( Point( 0, 0 ), aOutputSize ); + + TabItemContent eItemContent( getItemContent() ); + if ( eItemContent == TABITEM_AUTO ) + { + // the "content modes" to try + TabItemContent eTryThis[] = + { + TABITEM_IMAGE_ONLY, // assumed to have the smallest rects + TABITEM_TEXT_ONLY, + TABITEM_IMAGE_AND_TEXT // assumed to have the largest rects + }; + + + // determine which of the different version fits + eItemContent = eTryThis[0]; + size_t nTryIndex = 2; + while ( nTryIndex > 0 ) + { + const Point aBottomRight( io_rItems.rbegin()->GetRect( eTryThis[ nTryIndex ] ).BottomRight() ); + if ( aFitInto.IsInside( aBottomRight ) ) + { + eItemContent = eTryThis[ nTryIndex ]; + break; + } + --nTryIndex; + } + } + + // propagate to the items + for ( ItemDescriptors::iterator item = io_rItems.begin(); + item != io_rItems.end(); + ++item + ) + { + item->eContent = eItemContent; + } + + const ItemDescriptor& rLastItem( *io_rItems.rbegin() ); + const Point aLastItemBottomRight( rLastItem.GetCurrentRect().BottomRight() ); + return aFitInto.Left() <= aLastItemBottomRight.X() + && aFitInto.Right() >= aLastItemBottomRight.X(); + } + + //------------------------------------------------------------------------------------------------------------------ + Size TabBarGeometry::getOptimalSize( ItemDescriptors& io_rItems, const bool i_bMinimalSize ) const + { + if ( io_rItems.empty() ) + return Size( + m_aItemsInset.Left() + m_aItemsInset.Right(), + m_aItemsInset.Top() + m_aItemsInset.Bottom() + ); + + // the rect of the last item + const Rectangle& rLastItemRect( i_bMinimalSize ? io_rItems.rbegin()->aIconOnlyArea : io_rItems.rbegin()->aCompleteArea ); + return Size( + rLastItemRect.Left() + 1 + m_aItemsInset.Right(), + rLastItemRect.Top() + 1 + rLastItemRect.Bottom() + m_aItemsInset.Bottom() + ); + } + + //------------------------------------------------------------------------------------------------------------------ + void TabBarGeometry::relayout( const Size& i_rActualOutputSize, ItemDescriptors& io_rItems ) + { + // assume all items fit + Point aButtonBackPos( OUTER_SPACE_LEFT, OUTER_SPACE_TOP ); + m_aButtonBackRect = Rectangle( aButtonBackPos, Size( 1, 1 ) ); + m_aButtonBackRect.SetEmpty(); + + Point aButtonForwardPos( i_rActualOutputSize.Width(), OUTER_SPACE_TOP ); + m_aButtonForwardRect = Rectangle( aButtonForwardPos, Size( 1, 1 ) ); + m_aButtonForwardRect.SetEmpty(); + + Point aItemsPos( OUTER_SPACE_LEFT, 0 ); + Size aItemsSize( i_rActualOutputSize.Width() - OUTER_SPACE_LEFT - OUTER_SPACE_RIGHT, i_rActualOutputSize.Height() ); + m_aItemsRect = Rectangle( aItemsPos, aItemsSize ); + + if ( !impl_fitItems( io_rItems ) ) + { + // assumption was wrong, the items do not fit => calculate rects for the scroll buttons + const Size aButtonSize( BUTTON_FLOW_WIDTH, i_rActualOutputSize.Height() - OUTER_SPACE_TOP - OUTER_SPACE_BOTTOM ); + + aButtonBackPos = Point( OUTER_SPACE_LEFT, OUTER_SPACE_TOP ); + m_aButtonBackRect = Rectangle( aButtonBackPos, aButtonSize ); + + aButtonForwardPos = Point( i_rActualOutputSize.Width() - BUTTON_FLOW_WIDTH - OUTER_SPACE_RIGHT, OUTER_SPACE_TOP ); + m_aButtonForwardRect = Rectangle( aButtonForwardPos, aButtonSize ); + + aItemsPos.X() = aButtonBackPos.X() + aButtonSize.Width() + BUTTON_FLOW_SPACE; + aItemsSize.Width() = aButtonForwardPos.X() - BUTTON_FLOW_SPACE - aItemsPos.X(); + m_aItemsRect = Rectangle( aItemsPos, aItemsSize ); + + // fit items, again. In the TABITEM_AUTO case, the smaller playground for the items might lead to another + // item content. + impl_fitItems( io_rItems ); + } + } + + //------------------------------------------------------------------------------------------------------------------ + Point TabBarGeometry::getFirstItemPosition() const + { + return Point( m_aItemsInset.Left(), m_aItemsInset.Top() ); + } + +//...................................................................................................................... +} // namespace svt +//...................................................................................................................... diff --git a/svtools/source/toolpanel/tabbargeometry.hxx b/svtools/source/toolpanel/tabbargeometry.hxx new file mode 100644 index 000000000000..059d69a3e233 --- /dev/null +++ b/svtools/source/toolpanel/tabbargeometry.hxx @@ -0,0 +1,137 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#ifndef TABBARGEOMETRY_HXX +#define TABBARGEOMETRY_HXX + +#include "svtools/toolpanel/tabalignment.hxx" + +#include "tabitemdescriptor.hxx" + +#include <tools/gen.hxx> +#include <tools/svborder.hxx> + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + //================================================================================================================== + //= NormalizedArea + //================================================================================================================== + /** a rectangle which automatically translates between unrotated and rotated geometry. + + It can be operated as if it were an unrotated area, but is able to provide corrdinates of rotated objects, + relative to its playground. + */ + class NormalizedArea + { + public: + NormalizedArea(); + NormalizedArea( const Rectangle& i_rReference, const bool i_bIsVertical ); + + /** transforms a rectangle, relative to our playground, into a coordinate system defined by the given alignment + @param i_rArea + the area which is to be transformed. + */ + Rectangle getTransformed( + const Rectangle& i_rArea, + const TabAlignment i_eTargetAlignment + ) const; + + /** normalizes an already transformed rectangle + @param i_rArea + the area which is to be normalized. + */ + Rectangle getNormalized( + const Rectangle& i_rArea, + const TabAlignment i_eTargetAlignment + ) const; + + + Size getReferenceSize() const { return m_aReference.GetSize(); } + const Rectangle& + getReference() const { return m_aReference; } + + private: + // the normalized reference area + Rectangle m_aReference; + }; + + //================================================================================================================== + //= TabBarGeometry + //================================================================================================================== + class TabBarGeometry_Impl; + class TabBarGeometry + { + public: + TabBarGeometry( const TabItemContent i_eItemContent ); + ~TabBarGeometry(); + + // retrieves the rectangle to be occupied by the button for scrolling backward through the items + const Rectangle& getButtonBackRect() const { return m_aButtonBackRect; } + // retrieves the rectangle to be occupied by the items + const Rectangle& getItemsRect() const { return m_aItemsRect; } + // retrieves the rectangle to be occupied by the button for scrolling forward through the items + const Rectangle& getButtonForwardRect() const { return m_aButtonForwardRect; } + + inline TabItemContent + getItemContent() const { return m_eTabItemContent; } + inline void setItemContent( const TabItemContent i_eItemContent ) { m_eTabItemContent = i_eItemContent; } + + /** adjusts the sizes of the buttons and the item's playground, plus the sizes of the items + */ + void relayout( const Size& i_rActualOutputSize, ItemDescriptors& io_rItems ); + + /** calculates the optimal size of the tab bar, depending on the item's sizes + */ + Size getOptimalSize( ItemDescriptors& io_rItems, const bool i_bMinimalSize ) const; + + /** retrieves the position where the first item should start, relative to the item rect + */ + Point getFirstItemPosition() const; + + private: + bool impl_fitItems( ItemDescriptors& io_rItems ) const; + + private: + /// specifies the content to be displayed in the tab items + TabItemContent m_eTabItemContent; + /// specifies the inset to be used in the items area, depends on the actual alignment + SvBorder m_aItemsInset; + // the (logical) rectangle to be used for the "back" button, empty if the button is not needed + Rectangle m_aButtonBackRect; + // the (logical) rectangle to be used for the items + Rectangle m_aItemsRect; + // the (logical) rectangle to be used for the "forward" button, empty if the button is not needed + Rectangle m_aButtonForwardRect; + }; + +//...................................................................................................................... +} // namespace svt +//...................................................................................................................... + +#endif // TABBARGEOMETRY_HXX diff --git a/svtools/source/toolpanel/tabitemdescriptor.hxx b/svtools/source/toolpanel/tabitemdescriptor.hxx new file mode 100644 index 000000000000..8005816b0fe2 --- /dev/null +++ b/svtools/source/toolpanel/tabitemdescriptor.hxx @@ -0,0 +1,90 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#ifndef TABITEMDESCRIPTOR_HXX +#define TABITEMDESCRIPTOR_HXX + +#include "svtools/toolpanel/toolpanel.hxx" +#include "svtools/toolpanel/tabitemcontent.hxx" + +#include <tools/gen.hxx> +#include <osl/diagnose.h> + +#include <vector> + +//........................................................................ +namespace svt +{ +//........................................................................ + + //================================================================================================================== + //= ItemDescriptor + //================================================================================================================== + struct ItemDescriptor + { + PToolPanel pPanel; + Rectangle aCompleteArea; // bounding area if the both text and icon are to be rendererd + Rectangle aIconOnlyArea; // bounding area if the icon is to be rendererd + Rectangle aTextOnlyArea; // bounding area if the text is to be rendererd + TabItemContent eContent; + // content to be used for this particular item. Might differ from item content which has been set + // up for the complete control, in case not the complete content fits into the available space. + + ItemDescriptor() + :pPanel() + ,aCompleteArea() + ,aIconOnlyArea() + ,aTextOnlyArea() + ,eContent( TABITEM_IMAGE_AND_TEXT ) + { + } + + const Rectangle& GetRect( const TabItemContent i_eItemContent ) const + { + OSL_ENSURE( i_eItemContent != TABITEM_AUTO, "ItemDescriptor::GetRect: illegal value!" ); + + return ( i_eItemContent == TABITEM_IMAGE_AND_TEXT ) + ? aCompleteArea + : ( ( i_eItemContent == TABITEM_TEXT_ONLY ) + ? aTextOnlyArea + : aIconOnlyArea + ); + } + + const Rectangle& GetCurrentRect() const + { + return GetRect( eContent ); + } + }; + + typedef ::std::vector< ItemDescriptor > ItemDescriptors; + + +//........................................................................ +} // namespace svt +//........................................................................ + +#endif // TABITEMDESCRIPTOR_HXX diff --git a/svtools/source/toolpanel/tablayouter.cxx b/svtools/source/toolpanel/tablayouter.cxx new file mode 100755 index 000000000000..f68bbc1bbd0f --- /dev/null +++ b/svtools/source/toolpanel/tablayouter.cxx @@ -0,0 +1,262 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "svtools/toolpanel/tablayouter.hxx" +#include "svtools/toolpanel/toolpaneldeck.hxx" +#include "svtools/toolpanel/paneltabbar.hxx" +#include "svtaccessiblefactory.hxx" + +#include <tools/gen.hxx> +#include <tools/diagnose_ex.h> + +//........................................................................ +namespace svt +{ +//........................................................................ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::accessibility::XAccessible; + + //==================================================================== + //= TabDeckLayouter_Data + //==================================================================== + struct TabDeckLayouter_Data + { + TabAlignment eAlignment; + IToolPanelDeck& rPanels; + ::std::auto_ptr< PanelTabBar > pTabBar; + AccessibleFactoryAccess aAccessibleFactory; + + TabDeckLayouter_Data( Window& i_rParent, IToolPanelDeck& i_rPanels, + const TabAlignment i_eAlignment, const TabItemContent i_eItemContent ) + :eAlignment( i_eAlignment ) + ,rPanels( i_rPanels ) + ,pTabBar( new PanelTabBar( i_rParent, i_rPanels, i_eAlignment, i_eItemContent ) ) + { + pTabBar->Show(); + } + }; + + //==================================================================== + //= helper + //==================================================================== + namespace + { + static bool lcl_isVerticalTabBar( const TabAlignment i_eAlignment ) + { + return ( i_eAlignment == TABS_RIGHT ) + || ( i_eAlignment == TABS_LEFT ); + } + + static bool lcl_checkDisposed( const TabDeckLayouter_Data& i_rData ) + { + if ( !i_rData.pTabBar.get() ) + { + OSL_ENSURE( false, "lcl_checkDisposed: already disposed!" ); + return true; + } + return false; + } + } + + //==================================================================== + //= TabDeckLayouter + //==================================================================== + //-------------------------------------------------------------------- + TabDeckLayouter::TabDeckLayouter( Window& i_rParent, IToolPanelDeck& i_rPanels, + const TabAlignment i_eAlignment, const TabItemContent i_eItemContent ) + :m_pData( new TabDeckLayouter_Data( i_rParent, i_rPanels, i_eAlignment, i_eItemContent ) ) + { + } + + //-------------------------------------------------------------------- + TabDeckLayouter::~TabDeckLayouter() + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_IREFERENCE( TabDeckLayouter ) + + //-------------------------------------------------------------------- + TabItemContent TabDeckLayouter::GetTabItemContent() const + { + if ( lcl_checkDisposed( *m_pData ) ) + return TABITEM_IMAGE_AND_TEXT; + return m_pData->pTabBar->GetTabItemContent(); + } + + //-------------------------------------------------------------------- + void TabDeckLayouter::SetTabItemContent( const TabItemContent& i_eItemContent ) + { + if ( lcl_checkDisposed( *m_pData ) ) + return; + m_pData->pTabBar->SetTabItemContent( i_eItemContent ); + } + + //-------------------------------------------------------------------- + TabAlignment TabDeckLayouter::GetTabAlignment() const + { + if ( lcl_checkDisposed( *m_pData ) ) + return TABS_RIGHT; + return m_pData->eAlignment; + } + + //-------------------------------------------------------------------- + ::boost::optional< size_t > TabDeckLayouter::GetFocusedPanelItem() const + { + if ( lcl_checkDisposed( *m_pData ) ) + return ::boost::optional< size_t >(); + return m_pData->pTabBar->GetFocusedPanelItem(); + } + + //-------------------------------------------------------------------- + void TabDeckLayouter::FocusPanelItem( const size_t i_nItemPos ) + { + if ( lcl_checkDisposed( *m_pData ) ) + return; + m_pData->pTabBar->FocusPanelItem( i_nItemPos ); + } + + //-------------------------------------------------------------------- + bool TabDeckLayouter::IsPanelSelectorEnabled() const + { + if ( lcl_checkDisposed( *m_pData ) ) + return false; + return m_pData->pTabBar->IsEnabled(); + } + + //-------------------------------------------------------------------- + bool TabDeckLayouter::IsPanelSelectorVisible() const + { + if ( lcl_checkDisposed( *m_pData ) ) + return false; + return m_pData->pTabBar->IsVisible(); + } + + //-------------------------------------------------------------------- + Rectangle TabDeckLayouter::GetItemScreenRect( const size_t i_nItemPos ) const + { + if ( lcl_checkDisposed( *m_pData ) ) + return Rectangle(); + return m_pData->pTabBar->GetItemScreenRect( i_nItemPos ); + } + + //-------------------------------------------------------------------- + Rectangle TabDeckLayouter::Layout( const Rectangle& i_rDeckPlayground ) + { + if ( lcl_checkDisposed( *m_pData ) ) + return i_rDeckPlayground; + + const Size aPreferredSize( m_pData->pTabBar->GetOptimalSize( WINDOWSIZE_PREFERRED ) ); + if ( lcl_isVerticalTabBar( m_pData->eAlignment ) ) + { + Size aTabBarSize = ( aPreferredSize.Width() < i_rDeckPlayground.GetWidth() ) + ? aPreferredSize + : m_pData->pTabBar->GetOptimalSize( WINDOWSIZE_MINIMUM ); + aTabBarSize.Height() = i_rDeckPlayground.GetHeight(); + + Rectangle aPanelRect( i_rDeckPlayground ); + if ( m_pData->eAlignment == TABS_RIGHT ) + { + aPanelRect.Right() -= aTabBarSize.Width(); + Point aTabBarTopLeft( aPanelRect.TopRight() ); + aTabBarTopLeft.X() += 1; + m_pData->pTabBar->SetPosSizePixel( aTabBarTopLeft, aTabBarSize ); + } + else + { + m_pData->pTabBar->SetPosSizePixel( aPanelRect.TopLeft(), aTabBarSize ); + aPanelRect.Left() += aTabBarSize.Width(); + } + if ( aPanelRect.Left() >= aPanelRect.Right() ) + aPanelRect = Rectangle(); + + return aPanelRect; + } + + Size aTabBarSize = ( aPreferredSize.Height() < i_rDeckPlayground.GetHeight() ) + ? aPreferredSize + : m_pData->pTabBar->GetOptimalSize( WINDOWSIZE_MINIMUM ); + aTabBarSize.Width() = i_rDeckPlayground.GetWidth(); + + Rectangle aPanelRect( i_rDeckPlayground ); + if ( m_pData->eAlignment == TABS_TOP ) + { + m_pData->pTabBar->SetPosSizePixel( aPanelRect.TopLeft(), aTabBarSize ); + aPanelRect.Top() += aTabBarSize.Height(); + } + else + { + aPanelRect.Bottom() -= aTabBarSize.Height(); + Point aTabBarTopLeft( aPanelRect.BottomLeft() ); + aTabBarTopLeft.Y() -= 1; + m_pData->pTabBar->SetPosSizePixel( aTabBarTopLeft, aTabBarSize ); + } + if ( aPanelRect.Top() >= aPanelRect.Bottom() ) + aPanelRect = Rectangle(); + + return aPanelRect; + } + + //-------------------------------------------------------------------- + void TabDeckLayouter::Destroy() + { + m_pData->pTabBar.reset(); + } + + //-------------------------------------------------------------------- + void TabDeckLayouter::SetFocusToPanelSelector() + { + if ( lcl_checkDisposed( *m_pData ) ) + return; + m_pData->pTabBar->GrabFocus(); + } + + //-------------------------------------------------------------------- + size_t TabDeckLayouter::GetAccessibleChildCount() const + { + if ( lcl_checkDisposed( *m_pData ) ) + return 0; + + return 1; + } + + //-------------------------------------------------------------------- + Reference< XAccessible > TabDeckLayouter::GetAccessibleChild( const size_t i_nChildIndex, const Reference< XAccessible >& i_rParentAccessible ) + { + (void)i_nChildIndex; + (void)i_rParentAccessible; + if ( lcl_checkDisposed( *m_pData ) ) + return NULL; + + return m_pData->pTabBar->GetAccessible( TRUE ); + } + +//........................................................................ +} // namespace svt +//........................................................................ diff --git a/svtools/source/toolpanel/toolpanel.cxx b/svtools/source/toolpanel/toolpanel.cxx new file mode 100644 index 000000000000..f7b999494563 --- /dev/null +++ b/svtools/source/toolpanel/toolpanel.cxx @@ -0,0 +1,54 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "svtools/toolpanel/toolpanel.hxx" + +//........................................................................ +namespace svt +{ +//........................................................................ + + //==================================================================== + //= ToolPanelBase + //==================================================================== + //-------------------------------------------------------------------- + ToolPanelBase::ToolPanelBase() + { + } + + //-------------------------------------------------------------------- + ToolPanelBase::~ToolPanelBase() + { + } + + //-------------------------------------------------------------------- + IMPLEMENT_IREFERENCE( ToolPanelBase ) + +//........................................................................ +} // namespace svt +//........................................................................ diff --git a/svtools/source/toolpanel/toolpanel.src b/svtools/source/toolpanel/toolpanel.src new file mode 100644 index 000000000000..5908a8fbcf98 --- /dev/null +++ b/svtools/source/toolpanel/toolpanel.src @@ -0,0 +1,57 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "svtools/svtools.hrc" + +String STR_SVT_TOOL_PANEL_BUTTON_FWD +{ + Text [ en-US ] = "Tab Panel Scroll Button, backward"; +}; + +String STR_SVT_TOOL_PANEL_BUTTON_BACK +{ + Text [ en-US ] = "Tab Panel Scroll Button, forward"; +}; + +Image IMG_TRIANGLE_RIGHT +{ + ImageBitmap = Bitmap { File = "triangle_right.png"; }; +}; + +Image IMG_TRIANGLE_RIGHT_HC +{ + ImageBitmap = Bitmap { File = "triangle_right_hc.png"; }; +}; + +Image IMG_TRIANGLE_DOWN +{ + ImageBitmap = Bitmap { File = "triangle_down.png"; }; +}; + +Image IMG_TRIANGLE_DOWN_HC +{ + ImageBitmap = Bitmap { File = "plus.png"; } ; +}; diff --git a/svtools/source/toolpanel/toolpanelcollection.cxx b/svtools/source/toolpanel/toolpanelcollection.cxx new file mode 100644 index 000000000000..baefbd92400f --- /dev/null +++ b/svtools/source/toolpanel/toolpanelcollection.cxx @@ -0,0 +1,193 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "toolpanelcollection.hxx" +#include "paneldecklisteners.hxx" + +#include <tools/diagnose_ex.h> + +#include <vector> + +//........................................................................ +namespace svt +{ +//........................................................................ + + //==================================================================== + //= ToolPanelCollection_Data + //==================================================================== + struct ToolPanelCollection_Data + { + ::std::vector< PToolPanel > aPanels; + ::boost::optional< size_t > aActivePanel; + PanelDeckListeners aListeners; + }; + + //==================================================================== + //= ToolPanelCollection + //==================================================================== + //-------------------------------------------------------------------- + ToolPanelCollection::ToolPanelCollection() + :m_pData( new ToolPanelCollection_Data ) + { + } + + //-------------------------------------------------------------------- + ToolPanelCollection::~ToolPanelCollection() + { + m_pData->aListeners.Dying(); + } + + //-------------------------------------------------------------------- + size_t ToolPanelCollection::GetPanelCount() const + { + return m_pData->aPanels.size(); + } + + //-------------------------------------------------------------------- + ::boost::optional< size_t > ToolPanelCollection::GetActivePanel() const + { + return m_pData->aActivePanel; + } + + //-------------------------------------------------------------------- + void ToolPanelCollection::ActivatePanel( const ::boost::optional< size_t >& i_rPanel ) + { + if ( !!i_rPanel ) + { + OSL_ENSURE( *i_rPanel < GetPanelCount(), "ToolPanelCollection::ActivatePanel: illegal panel no.!" ); + if ( *i_rPanel >= GetPanelCount() ) + return; + } + + if ( m_pData->aActivePanel == i_rPanel ) + return; + + const ::boost::optional< size_t > aOldPanel( m_pData->aActivePanel ); + m_pData->aActivePanel = i_rPanel; + + // notify listeners + m_pData->aListeners.ActivePanelChanged( aOldPanel, m_pData->aActivePanel ); + } + + //-------------------------------------------------------------------- + PToolPanel ToolPanelCollection::GetPanel( const size_t i_nPos ) const + { + OSL_ENSURE( i_nPos < m_pData->aPanels.size(), "ToolPanelCollection::GetPanel: illegal position!" ); + if ( i_nPos >= m_pData->aPanels.size() ) + return PToolPanel(); + return m_pData->aPanels[ i_nPos ]; + } + + //-------------------------------------------------------------------- + size_t ToolPanelCollection::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ) + { + OSL_ENSURE( i_pPanel.get(), "ToolPanelCollection::InsertPanel: illegal panel!" ); + if ( !i_pPanel.get() ) + return 0; + + // insert + const size_t position = i_nPosition < m_pData->aPanels.size() ? i_nPosition : m_pData->aPanels.size(); + m_pData->aPanels.insert( m_pData->aPanels.begin() + position, i_pPanel ); + + // update active panel + if ( !!m_pData->aActivePanel ) + { + if ( i_nPosition <= *m_pData->aActivePanel ) + ++*m_pData->aActivePanel; + } + + // notifications + m_pData->aListeners.PanelInserted( i_pPanel, i_nPosition ); + + return position; + } + + //-------------------------------------------------------------------- + PToolPanel ToolPanelCollection::RemovePanel( const size_t i_nPosition ) + { + OSL_ENSURE( i_nPosition < m_pData->aPanels.size(), "ToolPanelCollection::RemovePanel: illegal position!" ); + if ( i_nPosition >= m_pData->aPanels.size() ) + return NULL; + + // if the active panel is going to be removed, activate another one (before the actual removal) + if ( m_pData->aActivePanel == i_nPosition ) + { + const ::boost::optional< size_t > aOldActive( m_pData->aActivePanel ); + + if ( i_nPosition + 1 < GetPanelCount() ) + { + ++*m_pData->aActivePanel; + } + else if ( i_nPosition > 0 ) + { + --*m_pData->aActivePanel; + } + else + { + m_pData->aActivePanel.reset(); + } + + m_pData->aListeners.ActivePanelChanged( aOldActive, m_pData->aActivePanel ); + } + + // remember the removed panel for the aller + PToolPanel pRemovedPanel( m_pData->aPanels[ i_nPosition ] ); + + // actually remove + m_pData->aPanels.erase( m_pData->aPanels.begin() + i_nPosition ); + + if ( !!m_pData->aActivePanel ) + { + if ( i_nPosition < *m_pData->aActivePanel ) + { + --*m_pData->aActivePanel; + } + } + + // notify removed panel + m_pData->aListeners.PanelRemoved( i_nPosition ); + + return pRemovedPanel; + } + + //-------------------------------------------------------------------- + void ToolPanelCollection::AddListener( IToolPanelDeckListener& i_rListener ) + { + m_pData->aListeners.AddListener( i_rListener ); + } + + //-------------------------------------------------------------------- + void ToolPanelCollection::RemoveListener( IToolPanelDeckListener& i_rListener ) + { + m_pData->aListeners.RemoveListener( i_rListener ); + } + +//........................................................................ +} // namespace svt +//........................................................................ diff --git a/svtools/source/toolpanel/toolpanelcollection.hxx b/svtools/source/toolpanel/toolpanelcollection.hxx new file mode 100644 index 000000000000..2bdba38546c9 --- /dev/null +++ b/svtools/source/toolpanel/toolpanelcollection.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#ifndef TOOLPANELCOLLECTION_HXX +#define TOOLPANELCOLLECTION_HXX + +#include "svtools/toolpanel/toolpaneldeck.hxx" + +#include <memory> + +//........................................................................ +namespace svt +{ +//........................................................................ + + struct ToolPanelCollection_Data; + + //==================================================================== + //= ToolPanelCollection + //==================================================================== + class ToolPanelCollection : public IToolPanelDeck + { + public: + ToolPanelCollection(); + ~ToolPanelCollection(); + + // IToolPanelDeck + virtual size_t GetPanelCount() const; + virtual PToolPanel GetPanel( const size_t i_nPos ) const; + virtual ::boost::optional< size_t > + GetActivePanel() const; + virtual void ActivatePanel( const ::boost::optional< size_t >& i_rPanel ); + virtual size_t InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ); + virtual PToolPanel RemovePanel( const size_t i_nPosition ); + virtual void AddListener( IToolPanelDeckListener& i_rListener ); + virtual void RemoveListener( IToolPanelDeckListener& i_rListener ); + + private: + ::std::auto_ptr< ToolPanelCollection_Data > m_pData; + }; + +//........................................................................ +} // namespace svt +//........................................................................ + +#endif // TOOLPANELCOLLECTION_HXX diff --git a/svtools/source/toolpanel/toolpaneldeck.cxx b/svtools/source/toolpanel/toolpaneldeck.cxx new file mode 100755 index 000000000000..e157090bbf0e --- /dev/null +++ b/svtools/source/toolpanel/toolpaneldeck.cxx @@ -0,0 +1,560 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * +************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "dummypanel.hxx" +#include "toolpanelcollection.hxx" +#include "paneldecklisteners.hxx" +#include "toolpaneldeckpeer.hxx" +#include "svtools/toolpanel/toolpaneldeck.hxx" +#include "svtools/toolpanel/tablayouter.hxx" +#include "svtools/toolpanel/drawerlayouter.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +/** === end UNO includes === **/ + +#include <tools/diagnose_ex.h> + +#include <boost/optional.hpp> + +//........................................................................ +namespace svt +{ +//........................................................................ + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::accessibility::XAccessible; + using ::com::sun::star::awt::XWindowPeer; + using ::com::sun::star::uno::UNO_SET_THROW; + /** === end UNO using === **/ + namespace AccessibleRole = ::com::sun::star::accessibility::AccessibleRole; + + enum DeckAction + { + /// activates the first panel + ACTION_ACTIVATE_FIRST, + // activates the panel after the currently active panel + ACTION_ACTIVATE_NEXT, + // activates the panel before the currently active panel + ACTION_ACTIVATE_PREV, + // activates the last panel + ACTION_ACTIVATE_LAST, + + // toggles the focus between the active panel and the panel selector + ACTION_TOGGLE_FOCUS, + }; + + //==================================================================== + //= ToolPanelDeck_Impl + //==================================================================== + class ToolPanelDeck_Impl : public IToolPanelDeckListener + { + public: + ToolPanelDeck_Impl( ToolPanelDeck& i_rDeck ) + :m_rDeck( i_rDeck ) + ,m_aPanelAnchor( &i_rDeck, WB_DIALOGCONTROL | WB_CHILDDLGCTRL ) + ,m_aPanels() + ,m_pDummyPanel( new DummyPanel ) + ,m_pLayouter() + ,m_bInDtor( false ) + ,m_pAccessibleParent( NULL ) + { + m_aPanels.AddListener( *this ); + m_aPanelAnchor.Show(); + m_aPanelAnchor.SetAccessibleRole( AccessibleRole::PANEL ); + } + + ~ToolPanelDeck_Impl() + { + m_bInDtor = true; + } + + PDeckLayouter GetLayouter() const { return m_pLayouter; } + void SetLayouter( const PDeckLayouter& i_pNewLayouter ); + + Window& GetPanelWindowAnchor() { return m_aPanelAnchor; } + const Window& GetPanelWindowAnchor() const { return m_aPanelAnchor; } + + bool IsDead() const { return m_bInDtor; } + + /// notifies our listeners that we're going to die. Only to be called from with our anti-impl's destructor + void NotifyDying() + { + m_aPanels.RemoveListener( *this ); + m_aListeners.Dying(); + } + + // IToolPanelDeck equivalents + size_t GetPanelCount() const; + PToolPanel GetPanel( const size_t i_nPos ) const; + ::boost::optional< size_t > + GetActivePanel() const; + void ActivatePanel( const ::boost::optional< size_t >& i_rPanel ); + size_t InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ); + PToolPanel RemovePanel( const size_t i_nPosition ); + void AddListener( IToolPanelDeckListener& i_rListener ); + void RemoveListener( IToolPanelDeckListener& i_rListener ); + + /// re-layouts everything + void LayoutAll() { ImplDoLayout(); } + + void DoAction( const DeckAction i_eAction ); + + bool FocusActivePanel(); + + void SetAccessibleParentWindow( Window* i_pAccessibleParent ); + Window* GetAccessibleParentWindow() const { return m_pAccessibleParent; } + + protected: + // IToolPanelDeckListener + virtual void PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ); + virtual void PanelRemoved( const size_t i_nPosition ); + virtual void ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ); + virtual void LayouterChanged( const PDeckLayouter& i_rNewLayouter ); + virtual void Dying(); + + private: + void ImplDoLayout(); + PToolPanel GetActiveOrDummyPanel_Impl(); + + private: + ToolPanelDeck& m_rDeck; + Window m_aPanelAnchor; + ToolPanelCollection m_aPanels; + PToolPanel m_pDummyPanel; + PanelDeckListeners m_aListeners; + PDeckLayouter m_pLayouter; + bool m_bInDtor; + Window* m_pAccessibleParent; + }; + + //-------------------------------------------------------------------- + PToolPanel ToolPanelDeck_Impl::GetActiveOrDummyPanel_Impl() + { + ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() ); + if ( !aActivePanel ) + return m_pDummyPanel; + return m_aPanels.GetPanel( *aActivePanel ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::SetLayouter( const PDeckLayouter& i_pNewLayouter ) + { + ENSURE_OR_RETURN_VOID( i_pNewLayouter.get(), "invalid layouter" ); + + if ( m_pLayouter.get() ) + m_pLayouter->Destroy(); + + m_pLayouter = i_pNewLayouter; + + ImplDoLayout(); + + m_aListeners.LayouterChanged( m_pLayouter ); + } + + //-------------------------------------------------------------------- + size_t ToolPanelDeck_Impl::GetPanelCount() const + { + return m_aPanels.GetPanelCount(); + } + + //-------------------------------------------------------------------- + PToolPanel ToolPanelDeck_Impl::GetPanel( const size_t i_nPos ) const + { + return m_aPanels.GetPanel( i_nPos ); + } + + //-------------------------------------------------------------------- + ::boost::optional< size_t > ToolPanelDeck_Impl::GetActivePanel() const + { + return m_aPanels.GetActivePanel(); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::ActivatePanel( const ::boost::optional< size_t >& i_rPanel ) + { + m_aPanels.ActivatePanel( i_rPanel ); + } + + //-------------------------------------------------------------------- + size_t ToolPanelDeck_Impl::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ) + { + return m_aPanels.InsertPanel( i_pPanel, i_nPosition ); + } + + //-------------------------------------------------------------------- + PToolPanel ToolPanelDeck_Impl::RemovePanel( const size_t i_nPosition ) + { + return m_aPanels.RemovePanel( i_nPosition ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::ImplDoLayout() + { + const Rectangle aDeckPlayground( Point(), m_rDeck.GetOutputSizePixel() ); + + // ask the layouter what is left for our panel, and position the panel container window appropriately + Rectangle aPlaygroundArea( aDeckPlayground ); + OSL_ENSURE( m_pLayouter.get(), "ToolPanelDeck_Impl::ImplDoLayout: no layouter!" ); + if ( m_pLayouter.get() ) + { + aPlaygroundArea = m_pLayouter->Layout( aDeckPlayground ); + } + m_aPanelAnchor.SetPosSizePixel( aPlaygroundArea.TopLeft(), aPlaygroundArea.GetSize() ); + + // position the active panel + const PToolPanel pActive( GetActiveOrDummyPanel_Impl() ); + pActive->SetSizePixel( m_aPanelAnchor.GetOutputSizePixel() ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::AddListener( IToolPanelDeckListener& i_rListener ) + { + m_aListeners.AddListener( i_rListener ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::RemoveListener( IToolPanelDeckListener& i_rListener ) + { + m_aListeners.RemoveListener( i_rListener ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::DoAction( const DeckAction i_eAction ) + { + const size_t nPanelCount( m_aPanels.GetPanelCount() ); + ::boost::optional< size_t > aActivatePanel; + ::boost::optional< size_t > aCurrentPanel( GetActivePanel() ); + + switch ( i_eAction ) + { + case ACTION_ACTIVATE_FIRST: + if ( nPanelCount > 0 ) + aActivatePanel = 0; + break; + case ACTION_ACTIVATE_PREV: + if ( !aCurrentPanel && ( nPanelCount > 0 ) ) + aActivatePanel = nPanelCount - 1; + else + if ( !!aCurrentPanel && ( *aCurrentPanel > 0 ) ) + aActivatePanel = *aCurrentPanel - 1; + break; + case ACTION_ACTIVATE_NEXT: + if ( !aCurrentPanel && ( nPanelCount > 0 ) ) + aActivatePanel = 0; + else + if ( !!aCurrentPanel && ( *aCurrentPanel < nPanelCount - 1 ) ) + aActivatePanel = *aCurrentPanel + 1; + break; + case ACTION_ACTIVATE_LAST: + if ( nPanelCount > 0 ) + aActivatePanel = nPanelCount - 1; + break; + case ACTION_TOGGLE_FOCUS: + { + PToolPanel pActivePanel( GetActiveOrDummyPanel_Impl() ); + if ( !m_aPanelAnchor.HasChildPathFocus() ) + pActivePanel->GrabFocus(); + else + GetLayouter()->SetFocusToPanelSelector(); + } + break; + } + + if ( !!aActivatePanel ) + { + ActivatePanel( aActivatePanel ); + } + } + + //-------------------------------------------------------------------- + bool ToolPanelDeck_Impl::FocusActivePanel() + { + ::boost::optional< size_t > aActivePanel( m_aPanels.GetActivePanel() ); + if ( !aActivePanel ) + return false; + + PToolPanel pActivePanel( m_aPanels.GetPanel( *aActivePanel ) ); + pActivePanel->GrabFocus(); + return true; + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::PanelInserted( const PToolPanel& i_pPanel, const size_t i_nPosition ) + { + // multiplex to our own listeners + m_aListeners.PanelInserted( i_pPanel, i_nPosition ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::PanelRemoved( const size_t i_nPosition ) + { + // multiplex to our own listeners + m_aListeners.PanelRemoved( i_nPosition ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::ActivePanelChanged( const ::boost::optional< size_t >& i_rOldActive, const ::boost::optional< size_t >& i_rNewActive ) + { + // hide the old panel + if ( !!i_rOldActive ) + { + const PToolPanel pOldActive( m_aPanels.GetPanel( *i_rOldActive ) ); + pOldActive->Deactivate(); + } + + // position and show the new panel + const PToolPanel pNewActive( !i_rNewActive ? m_pDummyPanel : m_aPanels.GetPanel( *i_rNewActive ) ); + pNewActive->Activate( m_aPanelAnchor ); + pNewActive->GrabFocus(); + + // resize the panel (cannot guarantee it has ever been resized before + pNewActive->SetSizePixel( m_aPanelAnchor.GetOutputSizePixel() ); + + // multiplex to our own listeners + m_aListeners.ActivePanelChanged( i_rOldActive, i_rNewActive ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::LayouterChanged( const PDeckLayouter& i_rNewLayouter ) + { + // not interested in + (void)i_rNewLayouter; + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::Dying() + { + // not interested in. Since the ToolPanelCollection is our member, this just means we ourself + // are dying, and we already sent this notification in our dtor. + } + + //-------------------------------------------------------------------- + void ToolPanelDeck_Impl::SetAccessibleParentWindow( Window* i_pAccessibleParent ) + { + m_pAccessibleParent = i_pAccessibleParent; + } + + //==================================================================== + //= ToolPanelDeck + //==================================================================== + //-------------------------------------------------------------------- + ToolPanelDeck::ToolPanelDeck( Window& i_rParent, const WinBits i_nStyle ) + :Control( &i_rParent, i_nStyle ) + ,m_pImpl( new ToolPanelDeck_Impl( *this ) ) + { + // use a default layouter +// SetLayouter( PDeckLayouter( new TabDeckLayouter( *this, *this, TABS_RIGHT, TABITEM_IMAGE_AND_TEXT ) ) ); + SetLayouter( PDeckLayouter( new DrawerDeckLayouter( *this, *this ) ) ); + } + + //-------------------------------------------------------------------- + ToolPanelDeck::~ToolPanelDeck() + { + m_pImpl->NotifyDying(); + GetLayouter()->Destroy(); + + Hide(); + for ( size_t i=0; i<GetPanelCount(); ++i ) + { + PToolPanel pPanel( GetPanel( i ) ); + pPanel->Dispose(); + } + } + + //-------------------------------------------------------------------- + size_t ToolPanelDeck::GetPanelCount() const + { + return m_pImpl->GetPanelCount(); + } + + //-------------------------------------------------------------------- + PToolPanel ToolPanelDeck::GetPanel( const size_t i_nPos ) const + { + return m_pImpl->GetPanel( i_nPos ); + } + + //-------------------------------------------------------------------- + ::boost::optional< size_t > ToolPanelDeck::GetActivePanel() const + { + return m_pImpl->GetActivePanel(); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck::ActivatePanel( const ::boost::optional< size_t >& i_rPanel ) + { + m_pImpl->ActivatePanel( i_rPanel ); + } + + //-------------------------------------------------------------------- + size_t ToolPanelDeck::InsertPanel( const PToolPanel& i_pPanel, const size_t i_nPosition ) + { + return m_pImpl->InsertPanel( i_pPanel, i_nPosition ); + } + + //-------------------------------------------------------------------- + PToolPanel ToolPanelDeck::RemovePanel( const size_t i_nPosition ) + { + return m_pImpl->RemovePanel( i_nPosition ); + } + + //-------------------------------------------------------------------- + PDeckLayouter ToolPanelDeck::GetLayouter() const + { + return m_pImpl->GetLayouter(); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck::SetLayouter( const PDeckLayouter& i_pNewLayouter ) + { + return m_pImpl->SetLayouter( i_pNewLayouter ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck::AddListener( IToolPanelDeckListener& i_rListener ) + { + m_pImpl->AddListener( i_rListener ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck::RemoveListener( IToolPanelDeckListener& i_rListener ) + { + m_pImpl->RemoveListener( i_rListener ); + } + + //-------------------------------------------------------------------- + Window& ToolPanelDeck::GetPanelWindowAnchor() + { + return m_pImpl->GetPanelWindowAnchor(); + } + + //-------------------------------------------------------------------- + const Window& ToolPanelDeck::GetPanelWindowAnchor() const + { + return m_pImpl->GetPanelWindowAnchor(); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck::Resize() + { + Control::Resize(); + m_pImpl->LayoutAll(); + } + + //-------------------------------------------------------------------- + long ToolPanelDeck::Notify( NotifyEvent& i_rNotifyEvent ) + { + bool bHandled = false; + if ( i_rNotifyEvent.GetType() == EVENT_KEYINPUT ) + { + const KeyEvent* pEvent = i_rNotifyEvent.GetKeyEvent(); + const KeyCode& rKeyCode = pEvent->GetKeyCode(); + if ( rKeyCode.GetModifier() == KEY_MOD1 ) + { + bHandled = true; + switch ( rKeyCode.GetCode() ) + { + case KEY_HOME: + m_pImpl->DoAction( ACTION_ACTIVATE_FIRST ); + break; + case KEY_PAGEUP: + m_pImpl->DoAction( ACTION_ACTIVATE_PREV ); + break; + case KEY_PAGEDOWN: + m_pImpl->DoAction( ACTION_ACTIVATE_NEXT ); + break; + case KEY_END: + m_pImpl->DoAction( ACTION_ACTIVATE_LAST ); + break; + default: + bHandled = false; + break; + } + } + else if ( rKeyCode.GetModifier() == ( KEY_MOD1 | KEY_SHIFT ) ) + { + if ( rKeyCode.GetCode() == KEY_E ) + { + m_pImpl->DoAction( ACTION_TOGGLE_FOCUS ); + bHandled = true; + } + } + } + + if ( bHandled ) + return 1; + + return Control::Notify( i_rNotifyEvent ); + } + + //-------------------------------------------------------------------- + void ToolPanelDeck::GetFocus() + { + Control::GetFocus(); + if ( m_pImpl->IsDead() ) + return; + if ( !m_pImpl->FocusActivePanel() ) + { + PDeckLayouter pLayouter( GetLayouter() ); + ENSURE_OR_RETURN_VOID( pLayouter.get(), "ToolPanelDeck::GetFocus: no layouter?!" ); + pLayouter->SetFocusToPanelSelector(); + } + } + + //-------------------------------------------------------------------- + void ToolPanelDeck::SetAccessibleParentWindow( Window* i_pAccessibleParent ) + { + m_pImpl->SetAccessibleParentWindow( i_pAccessibleParent ); + } + + //-------------------------------------------------------------------- + Window* ToolPanelDeck::GetAccessibleParentWindow() const + { + Window* pAccessibleParent( m_pImpl->GetAccessibleParentWindow() ); + if ( !pAccessibleParent ) + pAccessibleParent = Window::GetAccessibleParentWindow(); + return pAccessibleParent; + } + + //-------------------------------------------------------------------- + Reference< XWindowPeer > ToolPanelDeck::GetComponentInterface( BOOL i_bCreate ) + { + Reference< XWindowPeer > xWindowPeer( Control::GetComponentInterface( FALSE ) ); + if ( !xWindowPeer.is() && i_bCreate ) + { + xWindowPeer.set( new ToolPanelDeckPeer( *this ) ); + SetComponentInterface( xWindowPeer ); + } + return xWindowPeer; + } + +//........................................................................ +} // namespace svt +//........................................................................ diff --git a/svtools/source/toolpanel/toolpaneldeckpeer.cxx b/svtools/source/toolpanel/toolpaneldeckpeer.cxx new file mode 100755 index 000000000000..0a84a90b4fb3 --- /dev/null +++ b/svtools/source/toolpanel/toolpaneldeckpeer.cxx @@ -0,0 +1,99 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "toolpaneldeckpeer.hxx" +#include "svtools/toolpanel/toolpaneldeck.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/lang/DisposedException.hpp> +/** === end UNO includes === **/ + +#include <tools/diagnose_ex.h> + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::accessibility::XAccessibleContext; + using ::com::sun::star::lang::DisposedException; + /** === end UNO using === **/ + + //================================================================================================================== + //= ToolPanelDeckPeer + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + ToolPanelDeckPeer::ToolPanelDeckPeer( ToolPanelDeck& i_rDeck ) + :VCLXWindow() + ,m_pDeck( &i_rDeck ) + { + } + + //------------------------------------------------------------------------------------------------------------------ + ToolPanelDeckPeer::~ToolPanelDeckPeer() + { + } + + //------------------------------------------------------------------------------------------------------------------ + Reference< XAccessibleContext > ToolPanelDeckPeer::CreateAccessibleContext() + { + ::vos::OGuard aSolarGuard( GetMutex() ); + if ( m_pDeck == NULL ) + throw DisposedException( ::rtl::OUString(), *this ); + + Window* pAccessibleParent( m_pDeck->GetAccessibleParentWindow() ); + ENSURE_OR_RETURN( pAccessibleParent != NULL, "no accessible parent => no accessible context", NULL ); + Reference< XAccessible > xAccessibleParent( pAccessibleParent->GetAccessible(), UNO_SET_THROW ); + return m_aAccessibleFactory.getFactory().createAccessibleToolPanelDeck( xAccessibleParent, *m_pDeck ); + } + + //------------------------------------------------------------------------------------------------------------------ + void SAL_CALL ToolPanelDeckPeer::dispose() throw(RuntimeException) + { + { + ::vos::OGuard aSolarGuard( GetMutex() ); + m_pDeck = NULL; + } + VCLXWindow::dispose(); + } + +//...................................................................................................................... +} // namespace svt +//...................................................................................................................... diff --git a/svtools/source/toolpanel/toolpaneldeckpeer.hxx b/svtools/source/toolpanel/toolpaneldeckpeer.hxx new file mode 100755 index 000000000000..4b6607ecbd05 --- /dev/null +++ b/svtools/source/toolpanel/toolpaneldeckpeer.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SVT_TOOLPANELDECKPEER_HXX +#define SVT_TOOLPANELDECKPEER_HXX + +#include "svtaccessiblefactory.hxx" + +/** === begin UNO includes === **/ +/** === end UNO includes === **/ + +#include <toolkit/awt/vclxwindow.hxx> + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + class ToolPanelDeck; + //================================================================================================================== + //= ToolPanelDeckPeer + //================================================================================================================== + class ToolPanelDeckPeer : public VCLXWindow + { + public: + ToolPanelDeckPeer( ToolPanelDeck& i_rDeck ); + + protected: + ~ToolPanelDeckPeer(); + + // VCLXWindow overridables + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > CreateAccessibleContext(); + + // XComponent + void SAL_CALL dispose() throw(::com::sun::star::uno::RuntimeException); + + private: + AccessibleFactoryAccess m_aAccessibleFactory; + ToolPanelDeck* m_pDeck; + }; + +//...................................................................................................................... +} // namespace svt +//...................................................................................................................... + +#endif // SVT_TOOLPANELDECKPEER_HXX diff --git a/svtools/source/toolpanel/toolpaneldrawer.cxx b/svtools/source/toolpanel/toolpaneldrawer.cxx new file mode 100644 index 000000000000..851556bc7874 --- /dev/null +++ b/svtools/source/toolpanel/toolpaneldrawer.cxx @@ -0,0 +1,373 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "toolpaneldrawer.hxx" +#include "toolpaneldrawerpeer.hxx" +#include "svtools/svtdata.hxx" +#include "svtools/svtools.hrc" + +#include <com/sun/star/accessibility/AccessibleRole.hpp> + +#include <vcl/lineinfo.hxx> +#include <vcl/image.hxx> +#include <vcl/svapp.hxx> +#include <vcl/vclevent.hxx> + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::awt::XWindowPeer; + namespace AccessibleRole = ::com::sun::star::accessibility::AccessibleRole; + + static const int s_nIndentationWidth = 16; + + //================================================================================================================== + //= DrawerVisualization + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + DrawerVisualization::DrawerVisualization( ToolPanelDrawer& i_rParent ) + :Window( &i_rParent ) + ,m_rDrawer( i_rParent ) + { + SetMouseTransparent( TRUE ); + Show(); + SetAccessibleRole( AccessibleRole::LABEL ); + } + + //------------------------------------------------------------------------------------------------------------------ + DrawerVisualization::~DrawerVisualization() + { + } + + //------------------------------------------------------------------------------------------------------------------ + void DrawerVisualization::Paint( const Rectangle& i_rBoundingBox ) + { + Window::Paint( i_rBoundingBox ); + m_rDrawer.Paint(); + } + + //================================================================================================================== + //= ToolPanelDrawer + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + ToolPanelDrawer::ToolPanelDrawer( Window& i_rParent, const ::rtl::OUString& i_rTitle ) + :Window( &i_rParent, WB_TABSTOP ) + ,m_pPaintDevice( new VirtualDevice( *this ) ) + ,m_aVisualization( *this ) + ,m_bFocused( false ) + ,m_bExpanded( false ) + { + EnableMapMode( FALSE ); + SetBackground( Wallpaper() ); + SetPointer( POINTER_REFHAND ); + + SetAccessibleRole( AccessibleRole::LIST_ITEM ); + + SetText( i_rTitle ); + SetAccessibleName( i_rTitle ); + SetAccessibleDescription( i_rTitle ); + + m_aVisualization.SetAccessibleName( i_rTitle ); + m_aVisualization.SetAccessibleDescription( i_rTitle ); + } + + //------------------------------------------------------------------------------------------------------------------ + ToolPanelDrawer::~ToolPanelDrawer() + { + } + + //------------------------------------------------------------------------------------------------------------------ + long ToolPanelDrawer::GetPreferredHeightPixel() const + { + Rectangle aTitleBarBox( impl_calcTitleBarBox( impl_calcTextBoundingBox() ) ); + return aTitleBarBox.GetHeight(); + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawer::Paint() + { + m_pPaintDevice->SetMapMode( GetMapMode() ); + m_pPaintDevice->SetOutputSize( GetOutputSizePixel() ); + m_pPaintDevice->SetSettings( GetSettings() ); + m_pPaintDevice->SetDrawMode( GetDrawMode() ); + + const Rectangle aTextBox( impl_calcTextBoundingBox() ); + impl_paintBackground( impl_calcTitleBarBox( aTextBox ) ); + + Rectangle aFocusBox( impl_paintExpansionIndicator( aTextBox ) ); + + m_pPaintDevice->DrawText( aTextBox, GetText(), impl_getTextStyle() ); + + aFocusBox.Union( aTextBox ); + aFocusBox.Left() += 2; + impl_paintFocusIndicator( aFocusBox ); + + m_aVisualization.DrawOutDev( + Point(), GetOutputSizePixel(), + Point(), GetOutputSizePixel(), + *m_pPaintDevice + ); + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle ToolPanelDrawer::impl_paintExpansionIndicator( const Rectangle& i_rTextBox ) + { + Rectangle aExpansionIndicatorArea; + + Image aImage( impl_getExpansionIndicator() ); + const int nHeight( aImage.GetSizePixel().Height() ); + if ( nHeight > 0 ) + { + Point aPosition( + 0, + i_rTextBox.Top() + ( GetTextHeight() - nHeight ) / 2 + ); + m_pPaintDevice->DrawImage( aPosition, aImage ); + + aExpansionIndicatorArea = Rectangle( aPosition, aImage.GetSizePixel() ); + } + + return aExpansionIndicatorArea; + } + + //------------------------------------------------------------------------------------------------------------------ + Image ToolPanelDrawer::impl_getExpansionIndicator() const + { + const bool bHighContrastMode( GetSettings().GetStyleSettings().GetHighContrastMode() != 0 ); + USHORT nResourceId = 0; + if ( m_bExpanded ) + if ( bHighContrastMode ) + nResourceId = IMG_TRIANGLE_DOWN_HC; + else + nResourceId = IMG_TRIANGLE_DOWN; + else + if ( bHighContrastMode ) + nResourceId = IMG_TRIANGLE_RIGHT_HC; + else + nResourceId = IMG_TRIANGLE_RIGHT; + return Image( SvtResId( nResourceId ) ); + } + + //------------------------------------------------------------------------------------------------------------------ + USHORT ToolPanelDrawer::impl_getTextStyle() const + { + const USHORT nBasicStyle = TEXT_DRAW_LEFT + | TEXT_DRAW_TOP + | TEXT_DRAW_WORDBREAK; + + if ( IsEnabled() ) + return nBasicStyle; + + return nBasicStyle | TEXT_DRAW_DISABLE; + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawer::impl_paintBackground( const Rectangle& i_rTitleBarBox ) + { + m_pPaintDevice->SetFillColor( GetSettings().GetStyleSettings().GetDialogColor() ); + m_pPaintDevice->DrawRect( i_rTitleBarBox ); + + m_pPaintDevice->SetFillColor(); + m_pPaintDevice->SetLineColor( GetSettings().GetStyleSettings().GetLightColor() ); + m_pPaintDevice->DrawLine( i_rTitleBarBox.TopLeft(), i_rTitleBarBox.TopRight() ); + m_pPaintDevice->DrawLine( i_rTitleBarBox.TopLeft(), i_rTitleBarBox.BottomLeft() ); + + m_pPaintDevice->SetLineColor( GetSettings().GetStyleSettings().GetShadowColor() ); + m_pPaintDevice->DrawLine( i_rTitleBarBox.BottomLeft(), i_rTitleBarBox.BottomRight() ); + m_pPaintDevice->DrawLine( i_rTitleBarBox.TopRight(), i_rTitleBarBox.BottomRight() ); + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawer::impl_paintFocusIndicator( const Rectangle& i_rTextBox ) + { + if ( m_bFocused ) + { + const Rectangle aTextPixelBox( m_pPaintDevice->LogicToPixel( i_rTextBox ) ); + + m_pPaintDevice->EnableMapMode( FALSE ); + m_pPaintDevice->SetFillColor(); + + Rectangle aBox( i_rTextBox ); + aBox.Top() -= 1; + aBox.Bottom() += 1; + + m_pPaintDevice->DrawRect( aTextPixelBox ); + + LineInfo aDottedStyle( LINE_DASH ); + aDottedStyle.SetDashCount( 0 ); + aDottedStyle.SetDotCount( 1 ); + aDottedStyle.SetDotLen( 1 ); + aDottedStyle.SetDistance( 1 ); + + m_pPaintDevice->SetLineColor( COL_BLACK ); + m_pPaintDevice->DrawPolyLine( Polygon( aTextPixelBox ), aDottedStyle ); + m_pPaintDevice->EnableMapMode( FALSE ); + } + else + HideFocus(); + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawer::GetFocus() + { + m_bFocused = true; + Invalidate(); + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawer::LoseFocus() + { + m_bFocused = false; + Invalidate(); + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawer::Resize() + { + Window::Resize(); + m_aVisualization.SetPosSizePixel( Point(), GetOutputSizePixel() ); + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawer::MouseButtonDown( const MouseEvent& i_rMouseEvent ) + { + // consume this event, and do not forward to the base class - it would sent a NotifyEvent, which in turn, when + // we live in a DockingWindow, would start undocking + (void)i_rMouseEvent; + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawer::DataChanged( const DataChangedEvent& i_rEvent ) + { + Window::DataChanged( i_rEvent ); + + switch ( i_rEvent.GetType() ) + { + case DATACHANGED_SETTINGS: + if ( ( i_rEvent.GetFlags() & SETTINGS_STYLE ) == 0 ) + break; + SetSettings( Application::GetSettings() ); + m_pPaintDevice.reset( new VirtualDevice( *this ) ); + + // fall through. + + case DATACHANGED_FONTS: + case DATACHANGED_FONTSUBSTITUTION: + { + const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() ); + + // Font. + Font aFont = rStyleSettings.GetAppFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont( aFont ); + + // Color. + Color aColor; + if ( IsControlForeground() ) + aColor = GetControlForeground(); + else + aColor = rStyleSettings.GetButtonTextColor(); + SetTextColor( aColor ); + SetTextFillColor(); + + Invalidate(); + } + break; + } + } + + //------------------------------------------------------------------------------------------------------------------ + Reference< XWindowPeer > ToolPanelDrawer::GetComponentInterface( BOOL i_bCreate ) + { + Reference< XWindowPeer > xWindowPeer( Window::GetComponentInterface( FALSE ) ); + if ( !xWindowPeer.is() && i_bCreate ) + { + xWindowPeer.set( new ToolPanelDrawerPeer() ); + SetComponentInterface( xWindowPeer ); + } + return xWindowPeer; + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle ToolPanelDrawer::impl_calcTextBoundingBox() const + { + Font aFont( GetFont() ); + if ( m_bExpanded ) + aFont.SetWeight( m_bExpanded ? WEIGHT_BOLD : WEIGHT_NORMAL ); + m_pPaintDevice->SetFont( aFont ); + + int nAvailableWidth = m_pPaintDevice->GetTextWidth( GetText() ); + + Rectangle aTextBox( + Point(), + Size( + nAvailableWidth, + GetSettings().GetStyleSettings().GetTitleHeight() + ) + ); + aTextBox.Top() += ( aTextBox.GetHeight() - GetTextHeight() ) / 2; + aTextBox.Left() += s_nIndentationWidth; + aTextBox.Right() -= 1; + + aTextBox = m_pPaintDevice->GetTextRect( aTextBox, GetText(), impl_getTextStyle() ); + return aTextBox; + } + + //------------------------------------------------------------------------------------------------------------------ + Rectangle ToolPanelDrawer::impl_calcTitleBarBox( const Rectangle& i_rTextBox ) const + { + Rectangle aTitleBarBox( i_rTextBox ); + aTitleBarBox.Bottom() += aTitleBarBox.Top(); + aTitleBarBox.Top() = 0; + aTitleBarBox.Left() = 0; + + const long nWidth = GetOutputSizePixel().Width(); + if ( aTitleBarBox.GetWidth() < nWidth ) + aTitleBarBox.Right() = nWidth - 1; + + return aTitleBarBox; + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawer::SetExpanded( const bool i_bExpanded ) + { + if ( m_bExpanded != i_bExpanded ) + { + m_bExpanded = i_bExpanded; + CallEventListeners( m_bExpanded ? VCLEVENT_ITEM_EXPANDED : VCLEVENT_ITEM_COLLAPSED ); + Invalidate(); + } + } + +//...................................................................................................................... +} // namespace svt +//...................................................................................................................... diff --git a/svtools/source/toolpanel/toolpaneldrawer.hxx b/svtools/source/toolpanel/toolpaneldrawer.hxx new file mode 100644 index 000000000000..a465a0a6c9e1 --- /dev/null +++ b/svtools/source/toolpanel/toolpaneldrawer.hxx @@ -0,0 +1,113 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include <vcl/window.hxx> +#include <vcl/virdev.hxx> + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + class ToolPanelDrawer; + //================================================================================================================== + //= DrawerVisualization + //================================================================================================================== + /** serves a single purpose - let ZoomText read the drawers ... + + Strange enough, ZoomText does not read the drawers when they get the focus (in none of the combinations + of AccessibleRoles I tried), except when it does have an AccessibleChild with the role LABEL. To "inject" + such a child into the A11Y hierarchy, we use this window here. + + (We could also inject the A11Y component on the A11Y level only, but this would mean additional code. With + this approach here, VCL/toolkit will take care of creating and maintaining the A11Y component for us.) + */ + class DrawerVisualization : public Window + { + public: + DrawerVisualization( ToolPanelDrawer& i_rParent ); + ~DrawerVisualization(); + + protected: + // Window overridables + virtual void Paint( const Rectangle& i_rBoundingBox ); + + private: + ToolPanelDrawer& m_rDrawer; + }; + + //================================================================================================================== + //= ToolPanelDrawer + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + class ToolPanelDrawer : public Window + { + public: + ToolPanelDrawer( Window& i_rParent, const ::rtl::OUString& i_rTitle ); + ~ToolPanelDrawer(); + + long GetPreferredHeightPixel() const; + void SetExpanded( const bool i_bExpanded ); + bool IsExpanded() const { return m_bExpanded; } + + void Paint(); + + protected: + // Window overridables + virtual void GetFocus(); + virtual void LoseFocus(); + virtual void Resize(); + virtual void DataChanged( const DataChangedEvent& i_rEvent ); + virtual void MouseButtonDown( const MouseEvent& i_rMouseEvent ); + + virtual ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > + GetComponentInterface( BOOL i_bCreate ); + + private: + Rectangle impl_calcTextBoundingBox() const; + Rectangle impl_calcTitleBarBox( const Rectangle& i_rTextBox ) const; + void impl_paintBackground( const Rectangle& i_rTitleBarBox ); + USHORT impl_getTextStyle() const; + void impl_paintFocusIndicator( const Rectangle& i_rTextBox ); + Rectangle impl_paintExpansionIndicator( const Rectangle& i_rTextBox ); + Image impl_getExpansionIndicator() const; + + // don't expose SetText. Our text is used as AccessibleName/Desc, and those are not expected to change. + using Window::SetText; + using Window::Paint; + + private: + ::std::auto_ptr< VirtualDevice > m_pPaintDevice; + DrawerVisualization m_aVisualization; + bool m_bFocused; + bool m_bExpanded; + }; + +//...................................................................................................................... +} // namespace svt +//...................................................................................................................... diff --git a/svtools/source/toolpanel/toolpaneldrawerpeer.cxx b/svtools/source/toolpanel/toolpaneldrawerpeer.cxx new file mode 100644 index 000000000000..959527330897 --- /dev/null +++ b/svtools/source/toolpanel/toolpaneldrawerpeer.cxx @@ -0,0 +1,142 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_svtools.hxx" + +#include "toolpaneldrawerpeer.hxx" +#include "toolpaneldrawer.hxx" + +/** === begin UNO includes === **/ +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +/** === end UNO includes === **/ + +#include <tools/diagnose_ex.h> +#include <toolkit/awt/vclxaccessiblecomponent.hxx> +#include <unotools/accessiblestatesethelper.hxx> +#include <vcl/vclevent.hxx> + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + /** === begin UNO using === **/ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + using ::com::sun::star::accessibility::XAccessibleContext; + /** === end UNO using === **/ + namespace AccessibleStateType = ::com::sun::star::accessibility::AccessibleStateType; + namespace AccessibleEventId = ::com::sun::star::accessibility::AccessibleEventId; + + //================================================================================================================== + //= ToolPanelDrawerContext + //================================================================================================================== + class ToolPanelDrawerContext : public VCLXAccessibleComponent + { + public: + ToolPanelDrawerContext( VCLXWindow& i_rWindow ) + :VCLXAccessibleComponent( &i_rWindow ) + { + } + + virtual void ProcessWindowEvent( const VclWindowEvent& i_rVclWindowEvent ); + virtual void FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& i_rStateSet ); + + protected: + ~ToolPanelDrawerContext() + { + } + }; + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawerContext::ProcessWindowEvent( const VclWindowEvent& i_rVclWindowEvent ) + { + VCLXAccessibleComponent::ProcessWindowEvent( i_rVclWindowEvent ); + + switch ( i_rVclWindowEvent.GetId() ) + { + case VCLEVENT_ITEM_EXPANDED: + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, Any(), makeAny( AccessibleStateType::EXPANDED ) ); + break; + case VCLEVENT_ITEM_COLLAPSED: + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, makeAny( AccessibleStateType::EXPANDED ), Any() ); + break; + } + } + + //------------------------------------------------------------------------------------------------------------------ + void ToolPanelDrawerContext::FillAccessibleStateSet( ::utl::AccessibleStateSetHelper& i_rStateSet ) + { + VCLXAccessibleComponent::FillAccessibleStateSet( i_rStateSet ); + if ( !GetWindow() ) + return; + + i_rStateSet.AddState( AccessibleStateType::EXPANDABLE ); + i_rStateSet.AddState( AccessibleStateType::FOCUSABLE ); + + const ToolPanelDrawer* pDrawer( dynamic_cast< const ToolPanelDrawer* > ( GetWindow() ) ); + ENSURE_OR_RETURN_VOID( pDrawer, "ToolPanelDrawerContext::FillAccessibleStateSet: illegal window!" ); + if ( pDrawer->IsExpanded() ) + i_rStateSet.AddState( AccessibleStateType::EXPANDED ); + + if ( pDrawer->HasChildPathFocus() ) + i_rStateSet.AddState( AccessibleStateType::FOCUSED ); + } + + //================================================================================================================== + //= ToolPanelDrawerPeer + //================================================================================================================== + //------------------------------------------------------------------------------------------------------------------ + ToolPanelDrawerPeer::ToolPanelDrawerPeer() + :VCLXWindow() + { + } + + //------------------------------------------------------------------------------------------------------------------ + ToolPanelDrawerPeer::~ToolPanelDrawerPeer() + { + } + + //------------------------------------------------------------------------------------------------------------------ + Reference< XAccessibleContext > ToolPanelDrawerPeer::CreateAccessibleContext() + { + ::vos::OGuard aSolarGuard( GetMutex() ); + return new ToolPanelDrawerContext( *this ); + } + +//...................................................................................................................... +} // namespace svt +//...................................................................................................................... diff --git a/svtools/source/toolpanel/toolpaneldrawerpeer.hxx b/svtools/source/toolpanel/toolpaneldrawerpeer.hxx new file mode 100644 index 000000000000..5fcf0ac0ae7c --- /dev/null +++ b/svtools/source/toolpanel/toolpaneldrawerpeer.hxx @@ -0,0 +1,56 @@ +/************************************************************************* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SVT_TOOLPANELDRAWERPEER_HXX +#define SVT_TOOLPANELDRAWERPEER_HXX + +#include <toolkit/awt/vclxwindow.hxx> + +//...................................................................................................................... +namespace svt +{ +//...................................................................................................................... + + //================================================================================================================== + //= ToolPanelDrawerPeer + //================================================================================================================== + class ToolPanelDrawerPeer : public VCLXWindow + { + public: + ToolPanelDrawerPeer(); + + protected: + ~ToolPanelDrawerPeer(); + + // VCLXWindow overridables + virtual ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessibleContext > CreateAccessibleContext(); + }; + +//...................................................................................................................... +} // namespace svt +//...................................................................................................................... + +#endif // SVT_TOOLPANELDRAWERPEER_HXX |