2542 lines
71 KiB
C++
2542 lines
71 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
|
|
#include <svtools/tabbar.hxx>
|
|
#include <tools/time.hxx>
|
|
#include <tools/poly.hxx>
|
|
#include <utility>
|
|
#include <vcl/InterimItemWindow.hxx>
|
|
#include <vcl/bitmapex.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/help.hxx>
|
|
#include <vcl/decoview.hxx>
|
|
#include <vcl/event.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/commandevent.hxx>
|
|
#include <vcl/svtaccessiblefactory.hxx>
|
|
#include <vcl/accessiblefactory.hxx>
|
|
#include <vcl/ptrstyle.hxx>
|
|
#include <vcl/weldutils.hxx>
|
|
#include <svtools/svtresid.hxx>
|
|
#include <svtools/strings.hrc>
|
|
#include <limits>
|
|
#include <memory>
|
|
#include <vector>
|
|
#include <vcl/idle.hxx>
|
|
#include <bitmaps.hlst>
|
|
|
|
namespace
|
|
{
|
|
|
|
constexpr sal_uInt16 TABBAR_DRAG_SCROLLOFF = 5;
|
|
constexpr sal_uInt16 TABBAR_MINSIZE = 5;
|
|
|
|
constexpr sal_uInt16 ADDNEWPAGE_AREAWIDTH = 10;
|
|
|
|
class TabDrawer
|
|
{
|
|
private:
|
|
vcl::RenderContext& mrRenderContext;
|
|
const StyleSettings& mrStyleSettings;
|
|
|
|
tools::Rectangle maRect;
|
|
tools::Rectangle maLineRect;
|
|
|
|
Color maSelectedColor;
|
|
Color maCustomColor;
|
|
|
|
public:
|
|
bool mbSelected:1;
|
|
bool mbCustomColored:1;
|
|
bool mbEnabled:1;
|
|
bool mbProtect:1;
|
|
|
|
explicit TabDrawer(vcl::RenderContext& rRenderContext)
|
|
: mrRenderContext(rRenderContext)
|
|
, mrStyleSettings(rRenderContext.GetSettings().GetStyleSettings())
|
|
, mbSelected(false)
|
|
, mbCustomColored(false)
|
|
, mbEnabled(false)
|
|
, mbProtect(false)
|
|
{
|
|
|
|
}
|
|
|
|
void drawOuterFrame()
|
|
{
|
|
// set correct FillInBrush depending on status
|
|
if (mbSelected)
|
|
{
|
|
// Currently selected Tab
|
|
mrRenderContext.SetFillColor(maSelectedColor);
|
|
mrRenderContext.SetLineColor(maSelectedColor);
|
|
mrRenderContext.DrawRect(maRect);
|
|
mrRenderContext.SetLineColor(mrStyleSettings.GetDarkShadowColor());
|
|
}
|
|
else if (mbCustomColored)
|
|
{
|
|
mrRenderContext.SetFillColor(maCustomColor);
|
|
mrRenderContext.SetLineColor(maCustomColor);
|
|
mrRenderContext.DrawRect(maRect);
|
|
mrRenderContext.SetLineColor(mrStyleSettings.GetDarkShadowColor());
|
|
}
|
|
}
|
|
|
|
void drawText(const OUString& aText)
|
|
{
|
|
tools::Rectangle aRect = maRect;
|
|
tools::Long nTextWidth = mrRenderContext.GetTextWidth(aText);
|
|
tools::Long nTextHeight = mrRenderContext.GetTextHeight();
|
|
Point aPos = aRect.TopLeft();
|
|
aPos.AdjustX((aRect.getOpenWidth() - nTextWidth) / 2 );
|
|
aPos.AdjustY((aRect.getOpenHeight() - nTextHeight) / 2 );
|
|
|
|
if (mbEnabled)
|
|
mrRenderContext.DrawText(aPos, aText);
|
|
else
|
|
mrRenderContext.DrawCtrlText(aPos, aText, 0, aText.getLength(), (DrawTextFlags::Disable | DrawTextFlags::Mnemonic));
|
|
}
|
|
|
|
void drawOverTopBorder()
|
|
{
|
|
Point aTopLeft = maRect.TopLeft() + Point(1, 0);
|
|
Point aTopRight = maRect.TopRight() + Point(-1, 0);
|
|
|
|
tools::Rectangle aDelRect(aTopLeft, aTopRight);
|
|
mrRenderContext.DrawRect(aDelRect);
|
|
}
|
|
|
|
void drawColorLine()
|
|
{
|
|
if (!mbSelected)
|
|
return;
|
|
|
|
// tdf#141396: the color must be different from the rest of the selected tab
|
|
Color aLineColor = (mbCustomColored && maCustomColor != maSelectedColor)
|
|
? maCustomColor
|
|
: mrStyleSettings.GetDarkShadowColor();
|
|
mrRenderContext.SetFillColor(aLineColor);
|
|
mrRenderContext.SetLineColor(aLineColor);
|
|
mrRenderContext.DrawRect(maLineRect);
|
|
}
|
|
|
|
void drawSeparator()
|
|
{
|
|
const tools::Long cMargin = 5;
|
|
const tools::Long aRight( maRect.Right() - 1 );
|
|
mrRenderContext.SetLineColor(mrStyleSettings.GetShadowColor());
|
|
mrRenderContext.DrawLine(Point(aRight, maRect.Top() + cMargin),
|
|
Point(aRight, maRect.Bottom() - cMargin));
|
|
}
|
|
|
|
void drawTab()
|
|
{
|
|
drawOuterFrame();
|
|
drawColorLine();
|
|
if (!mbSelected && !mbCustomColored)
|
|
drawSeparator();
|
|
if (mbProtect)
|
|
{
|
|
BitmapEx aBitmap(BMP_TAB_LOCK);
|
|
Point aPosition = maRect.TopLeft();
|
|
aPosition.AdjustX(2);
|
|
aPosition.AdjustY((maRect.getOpenHeight() - aBitmap.GetSizePixel().Height()) / 2);
|
|
mrRenderContext.DrawBitmapEx(aPosition, aBitmap);
|
|
}
|
|
}
|
|
|
|
void setRect(const tools::Rectangle& rRect)
|
|
{
|
|
maLineRect = tools::Rectangle(rRect.BottomLeft(), rRect.BottomRight());
|
|
maLineRect.AdjustTop(-2);
|
|
maRect = rRect;
|
|
}
|
|
|
|
void setSelected(bool bSelected)
|
|
{
|
|
mbSelected = bSelected;
|
|
}
|
|
|
|
void setCustomColored(bool bCustomColored)
|
|
{
|
|
mbCustomColored = bCustomColored;
|
|
}
|
|
|
|
void setEnabled(bool bEnabled)
|
|
{
|
|
mbEnabled = bEnabled;
|
|
}
|
|
|
|
void setSelectedFillColor(const Color& rColor)
|
|
{
|
|
maSelectedColor = rColor;
|
|
}
|
|
|
|
void setCustomColor(const Color& rColor)
|
|
{
|
|
maCustomColor = rColor;
|
|
}
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
struct ImplTabBarItem
|
|
{
|
|
sal_uInt16 mnId;
|
|
TabBarPageBits mnBits;
|
|
OUString maText;
|
|
OUString maHelpText;
|
|
OUString maAuxiliaryText; // used in LayerTabBar for real layer name
|
|
tools::Rectangle maRect;
|
|
tools::Long mnWidth;
|
|
OString maHelpId;
|
|
bool mbShort : 1;
|
|
bool mbSelect : 1;
|
|
bool mbProtect : 1;
|
|
Color maTabBgColor;
|
|
Color maTabTextColor;
|
|
|
|
ImplTabBarItem(sal_uInt16 nItemId, OUString aText, TabBarPageBits nPageBits)
|
|
: mnId(nItemId)
|
|
, mnBits(nPageBits)
|
|
, maText(std::move(aText))
|
|
, mnWidth(0)
|
|
, mbShort(false)
|
|
, mbSelect(false)
|
|
, mbProtect(false)
|
|
, maTabBgColor(COL_AUTO)
|
|
, maTabTextColor(COL_AUTO)
|
|
{
|
|
}
|
|
|
|
bool IsDefaultTabBgColor() const
|
|
{
|
|
return maTabBgColor == COL_AUTO;
|
|
}
|
|
|
|
bool IsSelected(ImplTabBarItem const * pCurItem) const
|
|
{
|
|
return mbSelect || (pCurItem == this);
|
|
}
|
|
|
|
OUString const & GetRenderText() const
|
|
{
|
|
return maText;
|
|
}
|
|
};
|
|
|
|
class ImplTabSizer : public vcl::Window
|
|
{
|
|
public:
|
|
ImplTabSizer( TabBar* pParent, WinBits nWinStyle );
|
|
|
|
TabBar* GetParent() const { return static_cast<TabBar*>(Window::GetParent()); }
|
|
|
|
private:
|
|
void ImplTrack( const Point& rScreenPos );
|
|
|
|
virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
|
|
virtual void Tracking( const TrackingEvent& rTEvt ) override;
|
|
virtual void Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect ) override;
|
|
|
|
Point maStartPos;
|
|
tools::Long mnStartWidth;
|
|
};
|
|
|
|
ImplTabSizer::ImplTabSizer( TabBar* pParent, WinBits nWinStyle )
|
|
: Window( pParent, nWinStyle & WB_3DLOOK )
|
|
, mnStartWidth(0)
|
|
{
|
|
SetPointer(PointerStyle::HSizeBar);
|
|
SetSizePixel(Size(7 * GetDPIScaleFactor(), 0));
|
|
}
|
|
|
|
void ImplTabSizer::ImplTrack( const Point& rScreenPos )
|
|
{
|
|
TabBar* pParent = GetParent();
|
|
tools::Long nDiff = rScreenPos.X() - maStartPos.X();
|
|
pParent->mnSplitSize = mnStartWidth + (pParent->IsMirrored() ? -nDiff : nDiff);
|
|
if ( pParent->mnSplitSize < TABBAR_MINSIZE )
|
|
pParent->mnSplitSize = TABBAR_MINSIZE;
|
|
pParent->Split();
|
|
pParent->PaintImmediately();
|
|
}
|
|
|
|
void ImplTabSizer::MouseButtonDown( const MouseEvent& rMEvt )
|
|
{
|
|
if ( GetParent()->IsInEditMode() )
|
|
{
|
|
GetParent()->EndEditMode();
|
|
return;
|
|
}
|
|
|
|
if ( rMEvt.IsLeft() )
|
|
{
|
|
maStartPos = OutputToScreenPixel( rMEvt.GetPosPixel() );
|
|
mnStartWidth = GetParent()->GetSizePixel().Width();
|
|
StartTracking();
|
|
}
|
|
}
|
|
|
|
void ImplTabSizer::Tracking( const TrackingEvent& rTEvt )
|
|
{
|
|
if ( rTEvt.IsTrackingEnded() )
|
|
{
|
|
if ( rTEvt.IsTrackingCanceled() )
|
|
ImplTrack( maStartPos );
|
|
GetParent()->mnSplitSize = 0;
|
|
}
|
|
else
|
|
ImplTrack( OutputToScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) );
|
|
}
|
|
|
|
void ImplTabSizer::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
|
|
{
|
|
DecorationView aDecoView(&rRenderContext);
|
|
tools::Rectangle aOutputRect(Point(0, 0), GetOutputSizePixel());
|
|
aDecoView.DrawHandle(aOutputRect);
|
|
}
|
|
|
|
namespace {
|
|
|
|
// Is not named Impl. as it may be both instantiated and derived from
|
|
class TabBarEdit final : public InterimItemWindow
|
|
{
|
|
private:
|
|
std::unique_ptr<weld::Entry> m_xEntry;
|
|
Idle maLoseFocusIdle;
|
|
bool mbPostEvt;
|
|
|
|
DECL_LINK( ImplEndEditHdl, void*, void );
|
|
DECL_LINK( ImplEndTimerHdl, Timer*, void );
|
|
DECL_LINK( ActivatedHdl, weld::Entry&, bool );
|
|
DECL_LINK( KeyInputHdl, const KeyEvent&, bool );
|
|
DECL_LINK( FocusOutHdl, weld::Widget&, void );
|
|
|
|
public:
|
|
TabBarEdit(TabBar* pParent);
|
|
virtual void dispose() override;
|
|
|
|
TabBar* GetParent() const { return static_cast<TabBar*>(Window::GetParent()); }
|
|
|
|
weld::Entry& get_widget() { return *m_xEntry; }
|
|
|
|
void SetPostEvent() { mbPostEvt = true; }
|
|
void ResetPostEvent() { mbPostEvt = false; }
|
|
};
|
|
|
|
}
|
|
|
|
TabBarEdit::TabBarEdit(TabBar* pParent)
|
|
: InterimItemWindow(pParent, u"svt/ui/tabbaredit.ui"_ustr, u"TabBarEdit"_ustr)
|
|
, m_xEntry(m_xBuilder->weld_entry(u"entry"_ustr))
|
|
, maLoseFocusIdle( "svtools::TabBarEdit maLoseFocusIdle" )
|
|
{
|
|
InitControlBase(m_xEntry.get());
|
|
|
|
mbPostEvt = false;
|
|
maLoseFocusIdle.SetPriority( TaskPriority::REPAINT );
|
|
maLoseFocusIdle.SetInvokeHandler( LINK( this, TabBarEdit, ImplEndTimerHdl ) );
|
|
|
|
m_xEntry->connect_activate(LINK(this, TabBarEdit, ActivatedHdl));
|
|
m_xEntry->connect_key_press(LINK(this, TabBarEdit, KeyInputHdl));
|
|
m_xEntry->connect_focus_out(LINK(this, TabBarEdit, FocusOutHdl));
|
|
}
|
|
|
|
void TabBarEdit::dispose()
|
|
{
|
|
m_xEntry.reset();
|
|
InterimItemWindow::dispose();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(TabBarEdit, ActivatedHdl, weld::Entry&, bool)
|
|
{
|
|
if ( !mbPostEvt )
|
|
{
|
|
if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(false), true ) )
|
|
mbPostEvt = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
IMPL_LINK(TabBarEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool)
|
|
{
|
|
if (!rKEvt.GetKeyCode().GetModifier() && rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
|
|
{
|
|
if ( !mbPostEvt )
|
|
{
|
|
if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(true), true ) )
|
|
mbPostEvt = true;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
IMPL_LINK_NOARG(TabBarEdit, FocusOutHdl, weld::Widget&, void)
|
|
{
|
|
if ( !mbPostEvt )
|
|
{
|
|
if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(false), true ) )
|
|
mbPostEvt = true;
|
|
}
|
|
}
|
|
|
|
IMPL_LINK( TabBarEdit, ImplEndEditHdl, void*, pCancel, void )
|
|
{
|
|
ResetPostEvent();
|
|
maLoseFocusIdle.Stop();
|
|
|
|
// tdf#156958: when renaming and clicking on canvas, LO goes into GetParent()->EndEditMode first time
|
|
// then it calls TabBarEdit::dispose method which resets m_xEntry BUT, on the same thread, LO comes here again
|
|
// so return if already disposed to avoid a crash
|
|
if (isDisposed())
|
|
return;
|
|
|
|
// We need this query, because the edit gets a losefocus event,
|
|
// when it shows the context menu or the insert symbol dialog
|
|
if (!m_xEntry->has_focus() && m_xEntry->has_child_focus())
|
|
maLoseFocusIdle.Start();
|
|
else
|
|
GetParent()->EndEditMode( pCancel != nullptr );
|
|
}
|
|
|
|
IMPL_LINK_NOARG(TabBarEdit, ImplEndTimerHdl, Timer *, void)
|
|
{
|
|
if (m_xEntry->has_focus())
|
|
return;
|
|
|
|
// We need this query, because the edit gets a losefocus event,
|
|
// when it shows the context menu or the insert symbol dialog
|
|
if (m_xEntry->has_child_focus())
|
|
maLoseFocusIdle.Start();
|
|
else
|
|
GetParent()->EndEditMode( true );
|
|
}
|
|
|
|
namespace {
|
|
|
|
class TabButtons final : public InterimItemWindow
|
|
{
|
|
public:
|
|
std::unique_ptr<weld::Button> m_xFirstButton;
|
|
std::unique_ptr<weld::Button> m_xPrevButton;
|
|
std::unique_ptr<weld::Button> m_xNextButton;
|
|
std::unique_ptr<weld::Button> m_xLastButton;
|
|
std::unique_ptr<weld::Button> m_xAddButton;
|
|
std::shared_ptr<weld::ButtonPressRepeater> m_xAddRepeater;
|
|
std::shared_ptr<weld::ButtonPressRepeater> m_xPrevRepeater;
|
|
std::shared_ptr<weld::ButtonPressRepeater> m_xNextRepeater;
|
|
|
|
TabButtons(TabBar* pParent, bool bSheets)
|
|
: InterimItemWindow(pParent,
|
|
pParent->IsMirrored() ? u"svt/ui/tabbuttonsmirrored.ui"_ustr
|
|
: u"svt/ui/tabbuttons.ui"_ustr,
|
|
u"TabButtons"_ustr)
|
|
, m_xFirstButton(m_xBuilder->weld_button(u"first"_ustr))
|
|
, m_xPrevButton(m_xBuilder->weld_button(u"prev"_ustr))
|
|
, m_xNextButton(m_xBuilder->weld_button(u"next"_ustr))
|
|
, m_xLastButton(m_xBuilder->weld_button(u"last"_ustr))
|
|
, m_xAddButton(m_xBuilder->weld_button(u"add"_ustr))
|
|
{
|
|
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
|
|
SetPaintTransparent(false);
|
|
SetBackground(rStyleSettings.GetFaceColor());
|
|
|
|
m_xFirstButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_MOVET0HOME));
|
|
m_xPrevButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_MOVELEFT));
|
|
m_xNextButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_MOVERIGHT));
|
|
m_xLastButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_MOVETOEND));
|
|
m_xAddButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_ADDTAB));
|
|
|
|
if (bSheets)
|
|
{
|
|
m_xFirstButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_MOVETOHOME_SHEETS));
|
|
m_xPrevButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_MOVELEFT_SHEETS));
|
|
m_xNextButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_MOVERIGHT_SHEETS));
|
|
m_xLastButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_MOVETOEND_SHEETS));
|
|
m_xAddButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_ADDTAB_SHEETS));
|
|
}
|
|
}
|
|
|
|
void AdaptToHeight(int nHeight)
|
|
{
|
|
if (m_xFirstButton->get_preferred_size() == Size(nHeight, nHeight))
|
|
return;
|
|
m_xFirstButton->set_size_request(nHeight, nHeight);
|
|
m_xPrevButton->set_size_request(nHeight, nHeight);
|
|
m_xNextButton->set_size_request(nHeight, nHeight);
|
|
m_xLastButton->set_size_request(nHeight, nHeight);
|
|
m_xAddButton->set_size_request(nHeight, nHeight);
|
|
InvalidateChildSizeCache();
|
|
}
|
|
|
|
virtual void dispose() override
|
|
{
|
|
m_xNextRepeater.reset();
|
|
m_xPrevRepeater.reset();
|
|
m_xAddRepeater.reset();
|
|
m_xAddButton.reset();
|
|
m_xLastButton.reset();
|
|
m_xNextButton.reset();
|
|
m_xPrevButton.reset();
|
|
m_xFirstButton.reset();
|
|
InterimItemWindow::dispose();
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
struct TabBar_Impl
|
|
{
|
|
ScopedVclPtr<ImplTabSizer> mpSizer;
|
|
ScopedVclPtr<TabButtons> mxButtonBox;
|
|
ScopedVclPtr<TabBarEdit> mxEdit;
|
|
std::vector<ImplTabBarItem> maItemList;
|
|
|
|
vcl::AccessibleFactoryAccess maAccessibleFactory;
|
|
|
|
sal_uInt16 getItemSize() const
|
|
{
|
|
return static_cast<sal_uInt16>(maItemList.size());
|
|
}
|
|
};
|
|
|
|
TabBar::TabBar( vcl::Window* pParent, WinBits nWinStyle, bool bSheets ) :
|
|
Window( pParent, (nWinStyle & WB_3DLOOK) | WB_CLIPCHILDREN )
|
|
{
|
|
ImplInit( nWinStyle, bSheets );
|
|
maCurrentItemList = 0;
|
|
}
|
|
|
|
TabBar::~TabBar()
|
|
{
|
|
disposeOnce();
|
|
}
|
|
|
|
void TabBar::dispose()
|
|
{
|
|
EndEditMode( true );
|
|
mpImpl.reset();
|
|
Window::dispose();
|
|
}
|
|
|
|
const sal_uInt16 TabBar::APPEND = ::std::numeric_limits<sal_uInt16>::max();
|
|
const sal_uInt16 TabBar::PAGE_NOT_FOUND = ::std::numeric_limits<sal_uInt16>::max();
|
|
|
|
void TabBar::ImplInit( WinBits nWinStyle, bool bSheets )
|
|
{
|
|
mpImpl.reset(new TabBar_Impl);
|
|
|
|
mnMaxPageWidth = 0;
|
|
mnCurMaxWidth = 0;
|
|
mnOffX = 0;
|
|
mnOffY = 0;
|
|
mnLastOffX = 0;
|
|
mnSplitSize = 0;
|
|
mnSwitchTime = 0;
|
|
mnWinStyle = nWinStyle;
|
|
mnCurPageId = 0;
|
|
mnFirstPos = 0;
|
|
mnDropPos = 0;
|
|
mnSwitchId = 0;
|
|
mnEditId = 0;
|
|
mbFormat = true;
|
|
mbFirstFormat = true;
|
|
mbSizeFormat = true;
|
|
mbAutoEditMode = false;
|
|
mbEditCanceled = false;
|
|
mbDropPos = false;
|
|
mbInSelect = false;
|
|
mbMirrored = false;
|
|
mbScrollAlwaysEnabled = false;
|
|
mbSheets = bSheets;
|
|
|
|
ImplInitControls();
|
|
|
|
SetSizePixel( Size( 100, CalcWindowSizePixel().Height() ) );
|
|
ImplInitSettings( true, true );
|
|
}
|
|
|
|
ImplTabBarItem* TabBar::seek( size_t i )
|
|
{
|
|
if ( i < mpImpl->maItemList.size() )
|
|
{
|
|
maCurrentItemList = i;
|
|
return &mpImpl->maItemList[maCurrentItemList];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ImplTabBarItem* TabBar::prev()
|
|
{
|
|
if ( maCurrentItemList > 0 )
|
|
{
|
|
return &mpImpl->maItemList[--maCurrentItemList];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
ImplTabBarItem* TabBar::next()
|
|
{
|
|
if ( maCurrentItemList + 1 < mpImpl->maItemList.size() )
|
|
{
|
|
return &mpImpl->maItemList[++maCurrentItemList];
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void TabBar::ImplInitSettings( bool bFont, bool bBackground )
|
|
{
|
|
// FIXME RenderContext
|
|
|
|
const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
|
|
|
|
if (bFont)
|
|
{
|
|
vcl::Font aToolFont = rStyleSettings.GetToolFont();
|
|
aToolFont.SetWeight( WEIGHT_BOLD );
|
|
ApplyControlFont(*GetOutDev(), aToolFont);
|
|
|
|
// Adapt font size if window too small?
|
|
while (GetTextHeight() > (GetOutputSizePixel().Height() - 1))
|
|
{
|
|
vcl::Font aFont = GetFont();
|
|
if (aFont.GetFontHeight() <= 6)
|
|
break;
|
|
aFont.SetFontHeight(aFont.GetFontHeight() - 1);
|
|
SetFont(aFont);
|
|
}
|
|
}
|
|
|
|
if (bBackground)
|
|
{
|
|
ApplyControlBackground(*GetOutDev(), rStyleSettings.GetFaceColor());
|
|
}
|
|
}
|
|
|
|
void TabBar::ImplGetColors(const StyleSettings& rStyleSettings,
|
|
Color& rFaceColor, Color& rFaceTextColor,
|
|
Color& rSelectColor, Color& rSelectTextColor)
|
|
{
|
|
if (IsControlBackground())
|
|
rFaceColor = GetControlBackground();
|
|
else
|
|
rFaceColor = rStyleSettings.GetInactiveTabColor();
|
|
if (IsControlForeground())
|
|
rFaceTextColor = GetControlForeground();
|
|
else
|
|
rFaceTextColor = rStyleSettings.GetButtonTextColor();
|
|
rSelectColor = rStyleSettings.GetActiveTabColor();
|
|
rSelectTextColor = rStyleSettings.GetWindowTextColor();
|
|
}
|
|
|
|
bool TabBar::ImplCalcWidth()
|
|
{
|
|
// Sizes should only be retrieved if the text or the font was changed
|
|
if (!mbSizeFormat)
|
|
return false;
|
|
|
|
// retrieve width of tabs with bold font
|
|
vcl::Font aFont = GetFont();
|
|
if (aFont.GetWeight() != WEIGHT_BOLD)
|
|
{
|
|
aFont.SetWeight(WEIGHT_BOLD);
|
|
SetFont(aFont);
|
|
}
|
|
|
|
if (mnMaxPageWidth)
|
|
mnCurMaxWidth = mnMaxPageWidth;
|
|
else
|
|
{
|
|
mnCurMaxWidth = mnLastOffX - mnOffX;
|
|
if (mnCurMaxWidth < 1)
|
|
mnCurMaxWidth = 1;
|
|
}
|
|
|
|
bool bChanged = false;
|
|
for (auto& rItem : mpImpl->maItemList)
|
|
{
|
|
tools::Long nNewWidth = GetTextWidth(rItem.GetRenderText());
|
|
if (mnCurMaxWidth && (nNewWidth > mnCurMaxWidth))
|
|
{
|
|
rItem.mbShort = true;
|
|
nNewWidth = mnCurMaxWidth;
|
|
}
|
|
else
|
|
{
|
|
rItem.mbShort = false;
|
|
}
|
|
|
|
// Padding is dependent on font height - bigger font = bigger padding
|
|
tools::Long nFontWidth = aFont.GetFontHeight();
|
|
if (rItem.mbProtect)
|
|
nNewWidth += 24;
|
|
nNewWidth += nFontWidth * 2;
|
|
|
|
if (rItem.mnWidth != nNewWidth)
|
|
{
|
|
rItem.mnWidth = nNewWidth;
|
|
if (!rItem.maRect.IsEmpty())
|
|
bChanged = true;
|
|
}
|
|
}
|
|
mbSizeFormat = false;
|
|
mbFormat = true;
|
|
return bChanged;
|
|
}
|
|
|
|
void TabBar::ImplFormat()
|
|
{
|
|
ImplCalcWidth();
|
|
|
|
if (!mbFormat)
|
|
return;
|
|
|
|
sal_uInt16 nItemIndex = 0;
|
|
tools::Long x = mnOffX;
|
|
for (auto & rItem : mpImpl->maItemList)
|
|
{
|
|
// At all non-visible tabs an empty rectangle is set
|
|
if ((nItemIndex + 1 < mnFirstPos) || (x > mnLastOffX))
|
|
rItem.maRect.SetEmpty();
|
|
else
|
|
{
|
|
// Slightly before the tab before the first visible page
|
|
// should also be visible
|
|
if (nItemIndex + 1 == mnFirstPos)
|
|
{
|
|
rItem.maRect.SetLeft(x - rItem.mnWidth);
|
|
}
|
|
else
|
|
{
|
|
rItem.maRect.SetLeft(x);
|
|
x += rItem.mnWidth;
|
|
}
|
|
rItem.maRect.SetRight(x);
|
|
rItem.maRect.SetBottom(maWinSize.Height() - 1);
|
|
|
|
if (mbMirrored)
|
|
{
|
|
tools::Long nNewLeft = mnOffX + mnLastOffX - rItem.maRect.Right();
|
|
tools::Long nNewRight = mnOffX + mnLastOffX - rItem.maRect.Left();
|
|
rItem.maRect.SetRight(nNewRight);
|
|
rItem.maRect.SetLeft(nNewLeft);
|
|
}
|
|
}
|
|
|
|
nItemIndex++;
|
|
}
|
|
|
|
mbFormat = false;
|
|
|
|
// enable/disable button
|
|
ImplEnableControls();
|
|
}
|
|
|
|
sal_uInt16 TabBar::ImplGetLastFirstPos()
|
|
{
|
|
sal_uInt16 nCount = mpImpl->getItemSize();
|
|
if (!nCount || mbSizeFormat || mbFormat)
|
|
return 0;
|
|
|
|
sal_uInt16 nLastFirstPos = nCount - 1;
|
|
tools::Long nWinWidth = mnLastOffX - mnOffX - ADDNEWPAGE_AREAWIDTH;
|
|
tools::Long nWidth = mpImpl->maItemList[nLastFirstPos].mnWidth;
|
|
|
|
while (nLastFirstPos && (nWidth < nWinWidth))
|
|
{
|
|
nLastFirstPos--;
|
|
nWidth += mpImpl->maItemList[nLastFirstPos].mnWidth;
|
|
}
|
|
if ((nLastFirstPos != static_cast<sal_uInt16>(mpImpl->maItemList.size() - 1)) && (nWidth > nWinWidth))
|
|
nLastFirstPos++;
|
|
return nLastFirstPos;
|
|
}
|
|
|
|
IMPL_LINK(TabBar, ContextMenuHdl, const CommandEvent&, rCommandEvent, void)
|
|
{
|
|
maScrollAreaContextHdl.Call(rCommandEvent);
|
|
}
|
|
|
|
IMPL_LINK(TabBar, MousePressHdl, const MouseEvent&, rMouseEvent, bool)
|
|
{
|
|
if (rMouseEvent.IsRight())
|
|
ContextMenuHdl(CommandEvent(rMouseEvent.GetPosPixel(), CommandEventId::ContextMenu, true));
|
|
return false;
|
|
}
|
|
|
|
void TabBar::ImplInitControls()
|
|
{
|
|
if (mnWinStyle & WB_SIZEABLE)
|
|
{
|
|
if (!mpImpl->mpSizer)
|
|
{
|
|
mpImpl->mpSizer.disposeAndReset(VclPtr<ImplTabSizer>::Create( this, mnWinStyle & (WB_DRAG | WB_3DLOOK)));
|
|
}
|
|
mpImpl->mpSizer->Show();
|
|
}
|
|
else
|
|
{
|
|
mpImpl->mpSizer.disposeAndClear();
|
|
}
|
|
|
|
mpImpl->mxButtonBox.disposeAndReset(VclPtr<TabButtons>::Create(this, mbSheets));
|
|
|
|
Link<const CommandEvent&, void> aContextLink = LINK( this, TabBar, ContextMenuHdl );
|
|
|
|
if (mnWinStyle & WB_INSERTTAB)
|
|
{
|
|
Link<weld::Button&,void> aLink = LINK(this, TabBar, ImplAddClickHandler);
|
|
mpImpl->mxButtonBox->m_xAddRepeater = std::make_shared<weld::ButtonPressRepeater>(
|
|
*mpImpl->mxButtonBox->m_xAddButton, aLink, aContextLink);
|
|
mpImpl->mxButtonBox->m_xAddButton->show();
|
|
}
|
|
|
|
Link<weld::Button&,void> aLink = LINK( this, TabBar, ImplClickHdl );
|
|
|
|
if (mnWinStyle & (WB_MINSCROLL | WB_SCROLL))
|
|
{
|
|
mpImpl->mxButtonBox->m_xPrevRepeater = std::make_shared<weld::ButtonPressRepeater>(
|
|
*mpImpl->mxButtonBox->m_xPrevButton, aLink, aContextLink);
|
|
mpImpl->mxButtonBox->m_xPrevButton->show();
|
|
mpImpl->mxButtonBox->m_xNextRepeater = std::make_shared<weld::ButtonPressRepeater>(
|
|
*mpImpl->mxButtonBox->m_xNextButton, aLink, aContextLink);
|
|
mpImpl->mxButtonBox->m_xNextButton->show();
|
|
}
|
|
|
|
if (mnWinStyle & WB_SCROLL)
|
|
{
|
|
Link<const MouseEvent&, bool> aBtnContextLink = LINK(this, TabBar, MousePressHdl);
|
|
|
|
mpImpl->mxButtonBox->m_xFirstButton->connect_clicked(aLink);
|
|
mpImpl->mxButtonBox->m_xFirstButton->connect_mouse_press(aBtnContextLink);
|
|
mpImpl->mxButtonBox->m_xFirstButton->show();
|
|
mpImpl->mxButtonBox->m_xLastButton->connect_clicked(aLink);
|
|
mpImpl->mxButtonBox->m_xLastButton->connect_mouse_press(aBtnContextLink);
|
|
mpImpl->mxButtonBox->m_xLastButton->show();
|
|
}
|
|
|
|
mpImpl->mxButtonBox->Show();
|
|
}
|
|
|
|
void TabBar::ImplEnableControls()
|
|
{
|
|
if (mbSizeFormat || mbFormat)
|
|
return;
|
|
|
|
// enable/disable buttons
|
|
bool bEnableBtn = mbScrollAlwaysEnabled || mnFirstPos > 0;
|
|
mpImpl->mxButtonBox->m_xFirstButton->set_sensitive(bEnableBtn);
|
|
mpImpl->mxButtonBox->m_xPrevButton->set_sensitive(bEnableBtn);
|
|
if (!bEnableBtn && mpImpl->mxButtonBox->m_xPrevRepeater)
|
|
mpImpl->mxButtonBox->m_xPrevRepeater->Stop();
|
|
bEnableBtn = mbScrollAlwaysEnabled || mnFirstPos < ImplGetLastFirstPos();
|
|
mpImpl->mxButtonBox->m_xLastButton->set_sensitive(bEnableBtn);
|
|
mpImpl->mxButtonBox->m_xNextButton->set_sensitive(bEnableBtn);
|
|
if (!bEnableBtn && mpImpl->mxButtonBox->m_xNextRepeater)
|
|
mpImpl->mxButtonBox->m_xNextRepeater->Stop();
|
|
}
|
|
|
|
void TabBar::SetScrollAlwaysEnabled(bool bScrollAlwaysEnabled)
|
|
{
|
|
mbScrollAlwaysEnabled = bScrollAlwaysEnabled;
|
|
ImplEnableControls();
|
|
}
|
|
|
|
void TabBar::ImplShowPage( sal_uInt16 nPos )
|
|
{
|
|
if (nPos >= mpImpl->getItemSize())
|
|
return;
|
|
|
|
// calculate width
|
|
tools::Long nWidth = GetOutputSizePixel().Width();
|
|
|
|
auto& rItem = mpImpl->maItemList[nPos];
|
|
if (nPos < mnFirstPos)
|
|
SetFirstPageId( rItem.mnId );
|
|
else if (rItem.maRect.Right() > nWidth)
|
|
{
|
|
while (rItem.maRect.Right() > nWidth)
|
|
{
|
|
sal_uInt16 nNewPos = mnFirstPos + 1;
|
|
SetFirstPageId(GetPageId(nNewPos));
|
|
ImplFormat();
|
|
if (nNewPos != mnFirstPos)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
IMPL_LINK( TabBar, ImplClickHdl, weld::Button&, rBtn, void )
|
|
{
|
|
if (&rBtn != mpImpl->mxButtonBox->m_xFirstButton.get() && &rBtn != mpImpl->mxButtonBox->m_xLastButton.get())
|
|
{
|
|
if ((GetPointerState().mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0)
|
|
{
|
|
// like tdf#149482 if we didn't see a mouse up, but find that the mouse is no
|
|
// longer pressed at this point, then bail
|
|
mpImpl->mxButtonBox->m_xPrevRepeater->Stop();
|
|
mpImpl->mxButtonBox->m_xNextRepeater->Stop();
|
|
return;
|
|
}
|
|
}
|
|
|
|
EndEditMode();
|
|
|
|
sal_uInt16 nNewPos = mnFirstPos;
|
|
|
|
if (&rBtn == mpImpl->mxButtonBox->m_xFirstButton.get() || (&rBtn == mpImpl->mxButtonBox->m_xPrevButton.get() &&
|
|
mpImpl->mxButtonBox->m_xPrevRepeater->IsModKeyPressed()))
|
|
{
|
|
nNewPos = 0;
|
|
}
|
|
else if (&rBtn == mpImpl->mxButtonBox->m_xLastButton.get() || (&rBtn == mpImpl->mxButtonBox->m_xNextButton.get() &&
|
|
mpImpl->mxButtonBox->m_xNextRepeater->IsModKeyPressed()))
|
|
{
|
|
sal_uInt16 nCount = GetPageCount();
|
|
if (nCount)
|
|
nNewPos = nCount - 1;
|
|
}
|
|
else if (&rBtn == mpImpl->mxButtonBox->m_xPrevButton.get())
|
|
{
|
|
if (mnFirstPos)
|
|
nNewPos = mnFirstPos - 1;
|
|
}
|
|
else if (&rBtn == mpImpl->mxButtonBox->m_xNextButton.get())
|
|
{
|
|
sal_uInt16 nCount = GetPageCount();
|
|
if (mnFirstPos < nCount)
|
|
nNewPos = mnFirstPos+1;
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (nNewPos != mnFirstPos)
|
|
SetFirstPageId(GetPageId(nNewPos));
|
|
}
|
|
|
|
IMPL_LINK_NOARG(TabBar, ImplAddClickHandler, weld::Button&, void)
|
|
{
|
|
if ((GetPointerState().mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0)
|
|
{
|
|
// tdf#149482 if we didn't see a mouse up, but find that the mouse is no
|
|
// longer pressed at this point, then bail
|
|
mpImpl->mxButtonBox->m_xAddRepeater->Stop();
|
|
return;
|
|
}
|
|
|
|
EndEditMode();
|
|
AddTabClick();
|
|
}
|
|
|
|
void TabBar::MouseMove(const MouseEvent& rMEvt)
|
|
{
|
|
if (rMEvt.IsLeaveWindow())
|
|
mbInSelect = false;
|
|
|
|
Window::MouseMove(rMEvt);
|
|
}
|
|
|
|
void TabBar::MouseButtonDown(const MouseEvent& rMEvt)
|
|
{
|
|
// Only terminate EditMode and do not execute click
|
|
// if clicked inside our window,
|
|
if (IsInEditMode())
|
|
{
|
|
EndEditMode();
|
|
return;
|
|
}
|
|
|
|
sal_uInt16 nSelId = GetPageId(rMEvt.GetPosPixel());
|
|
|
|
if (!rMEvt.IsLeft())
|
|
{
|
|
Window::MouseButtonDown(rMEvt);
|
|
if (nSelId > 0 && nSelId != mnCurPageId)
|
|
{
|
|
if (ImplDeactivatePage())
|
|
{
|
|
SetCurPageId(nSelId);
|
|
PaintImmediately();
|
|
ImplActivatePage();
|
|
ImplSelect();
|
|
}
|
|
mbInSelect = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (rMEvt.IsMod2() && mbAutoEditMode && nSelId)
|
|
{
|
|
if (StartEditMode(nSelId))
|
|
return;
|
|
}
|
|
|
|
if ((rMEvt.GetMode() & (MouseEventModifiers::MULTISELECT | MouseEventModifiers::RANGESELECT)) && (rMEvt.GetClicks() == 1))
|
|
{
|
|
if (nSelId)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nSelId);
|
|
|
|
bool bSelectTab = false;
|
|
|
|
if ((rMEvt.GetMode() & MouseEventModifiers::MULTISELECT) && (mnWinStyle & WB_MULTISELECT))
|
|
{
|
|
if (nSelId != mnCurPageId)
|
|
{
|
|
SelectPage(nSelId, !IsPageSelected(nSelId));
|
|
bSelectTab = true;
|
|
}
|
|
}
|
|
else if (mnWinStyle & (WB_MULTISELECT | WB_RANGESELECT))
|
|
{
|
|
bSelectTab = true;
|
|
sal_uInt16 n;
|
|
bool bSelect;
|
|
sal_uInt16 nCurPos = GetPagePos(mnCurPageId);
|
|
if (nPos <= nCurPos)
|
|
{
|
|
// Deselect all tabs till the clicked tab
|
|
// and select all tabs from the clicked tab
|
|
// 'till the actual position
|
|
n = 0;
|
|
while (n < nCurPos)
|
|
{
|
|
auto& rItem = mpImpl->maItemList[n];
|
|
bSelect = n >= nPos;
|
|
|
|
if (rItem.mbSelect != bSelect)
|
|
{
|
|
rItem.mbSelect = bSelect;
|
|
if (!rItem.maRect.IsEmpty())
|
|
Invalidate(rItem.maRect);
|
|
}
|
|
|
|
n++;
|
|
}
|
|
}
|
|
|
|
if (nPos >= nCurPos)
|
|
{
|
|
// Select all tabs from the actual position till the clicked tab
|
|
// and deselect all tabs from the actual position
|
|
// till the last tab
|
|
sal_uInt16 nCount = mpImpl->getItemSize();
|
|
n = nCurPos;
|
|
while (n < nCount)
|
|
{
|
|
auto& rItem = mpImpl->maItemList[n];
|
|
|
|
bSelect = n <= nPos;
|
|
|
|
if (rItem.mbSelect != bSelect)
|
|
{
|
|
rItem.mbSelect = bSelect;
|
|
if (!rItem.maRect.IsEmpty())
|
|
Invalidate(rItem.maRect);
|
|
}
|
|
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// scroll the selected tab if required
|
|
if (bSelectTab)
|
|
{
|
|
ImplShowPage(nPos);
|
|
PaintImmediately();
|
|
ImplSelect();
|
|
}
|
|
|
|
mbInSelect = true;
|
|
|
|
return;
|
|
}
|
|
}
|
|
else if (rMEvt.GetClicks() == 2)
|
|
{
|
|
// call double-click-handler if required
|
|
if (!rMEvt.GetModifier() && (!nSelId || (nSelId == mnCurPageId)))
|
|
{
|
|
sal_uInt16 nOldCurId = mnCurPageId;
|
|
mnCurPageId = nSelId;
|
|
DoubleClick();
|
|
// check, as actual page could be switched inside
|
|
// the doubleclick-handler
|
|
if (mnCurPageId == nSelId)
|
|
mnCurPageId = nOldCurId;
|
|
}
|
|
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (nSelId)
|
|
{
|
|
// execute Select if not actual page
|
|
if (nSelId != mnCurPageId)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nSelId);
|
|
auto& rItem = mpImpl->maItemList[nPos];
|
|
|
|
if (!rItem.mbSelect)
|
|
{
|
|
// make not valid
|
|
bool bUpdate = false;
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
bUpdate = true;
|
|
|
|
// deselect all selected items
|
|
for (auto& xItem : mpImpl->maItemList)
|
|
{
|
|
if (xItem.mbSelect || (xItem.mnId == mnCurPageId))
|
|
{
|
|
xItem.mbSelect = false;
|
|
if (bUpdate)
|
|
Invalidate(xItem.maRect);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ImplDeactivatePage())
|
|
{
|
|
SetCurPageId(nSelId);
|
|
PaintImmediately();
|
|
ImplActivatePage();
|
|
ImplSelect();
|
|
}
|
|
|
|
mbInSelect = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
Window::MouseButtonDown(rMEvt);
|
|
}
|
|
|
|
void TabBar::MouseButtonUp(const MouseEvent& rMEvt)
|
|
{
|
|
mbInSelect = false;
|
|
Window::MouseButtonUp(rMEvt);
|
|
}
|
|
|
|
void TabBar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rect)
|
|
{
|
|
if (rRenderContext.IsNativeControlSupported(ControlType::WindowBackground,ControlPart::Entire))
|
|
{
|
|
rRenderContext.DrawNativeControl(ControlType::WindowBackground,ControlPart::Entire,rect,
|
|
ControlState::ENABLED,ImplControlValue(0),OUString());
|
|
}
|
|
// calculate items and emit
|
|
sal_uInt16 nItemCount = mpImpl->getItemSize();
|
|
if (!nItemCount)
|
|
return;
|
|
|
|
ImplPrePaint();
|
|
|
|
Color aFaceColor, aSelectColor, aFaceTextColor, aSelectTextColor;
|
|
const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
|
|
ImplGetColors(rStyleSettings, aFaceColor, aFaceTextColor, aSelectColor, aSelectTextColor);
|
|
|
|
rRenderContext.Push(vcl::PushFlags::FONT | vcl::PushFlags::CLIPREGION);
|
|
rRenderContext.SetClipRegion(vcl::Region(GetPageArea()));
|
|
|
|
// select font
|
|
vcl::Font aFont = rRenderContext.GetFont();
|
|
vcl::Font aLightFont = aFont;
|
|
aLightFont.SetWeight(WEIGHT_NORMAL);
|
|
|
|
TabDrawer aDrawer(rRenderContext);
|
|
|
|
aDrawer.setSelectedFillColor(aSelectColor);
|
|
|
|
// Now, start drawing the tabs.
|
|
|
|
ImplTabBarItem* pItem = ImplGetLastTabBarItem(nItemCount);
|
|
ImplTabBarItem* pCurItem = nullptr;
|
|
while (pItem)
|
|
{
|
|
// emit CurrentItem last, as it covers all others
|
|
if (!pCurItem && (pItem->mnId == mnCurPageId))
|
|
{
|
|
pCurItem = pItem;
|
|
pItem = prev();
|
|
if (!pItem)
|
|
pItem = pCurItem;
|
|
continue;
|
|
}
|
|
|
|
bool bCurrent = pItem == pCurItem;
|
|
|
|
if (!pItem->maRect.IsEmpty())
|
|
{
|
|
tools::Rectangle aRect = pItem->maRect;
|
|
bool bSelected = pItem->IsSelected(pCurItem);
|
|
// We disable custom background color in high contrast mode.
|
|
bool bCustomBgColor = !pItem->IsDefaultTabBgColor() && !rStyleSettings.GetHighContrastMode();
|
|
OUString aText = pItem->mbShort ?
|
|
rRenderContext.GetEllipsisString(pItem->GetRenderText(), mnCurMaxWidth) :
|
|
pItem->GetRenderText();
|
|
|
|
aDrawer.setRect(aRect);
|
|
aDrawer.setSelected(bSelected);
|
|
aDrawer.setCustomColored(bCustomBgColor);
|
|
aDrawer.setEnabled(true);
|
|
aDrawer.setCustomColor(pItem->maTabBgColor);
|
|
aDrawer.mbProtect = pItem->mbProtect;
|
|
aDrawer.drawTab();
|
|
|
|
// currently visible sheet is drawn using a bold font
|
|
if (bCurrent)
|
|
rRenderContext.SetFont(aFont);
|
|
else
|
|
rRenderContext.SetFont(aLightFont);
|
|
|
|
// Set the correct FillInBrush depending on status
|
|
|
|
if (bSelected)
|
|
rRenderContext.SetTextColor(aSelectTextColor);
|
|
else if (bCustomBgColor)
|
|
rRenderContext.SetTextColor(pItem->maTabTextColor);
|
|
else
|
|
rRenderContext.SetTextColor(aFaceTextColor);
|
|
|
|
// Special display of tab name depending on page bits
|
|
|
|
if (pItem->mnBits & TabBarPageBits::Blue)
|
|
{
|
|
rRenderContext.SetTextColor(COL_LIGHTBLUE);
|
|
}
|
|
if (pItem->mnBits & TabBarPageBits::Italic)
|
|
{
|
|
vcl::Font aSpecialFont = rRenderContext.GetFont();
|
|
aSpecialFont.SetItalic(FontItalic::ITALIC_NORMAL);
|
|
rRenderContext.SetFont(aSpecialFont);
|
|
}
|
|
if (pItem->mnBits & TabBarPageBits::Underline)
|
|
{
|
|
vcl::Font aSpecialFont = rRenderContext.GetFont();
|
|
aSpecialFont.SetUnderline(LINESTYLE_SINGLE);
|
|
rRenderContext.SetFont(aSpecialFont);
|
|
}
|
|
|
|
aDrawer.drawText(aText);
|
|
|
|
if (bCurrent)
|
|
{
|
|
rRenderContext.SetLineColor();
|
|
rRenderContext.SetFillColor(aSelectColor);
|
|
aDrawer.drawOverTopBorder();
|
|
break;
|
|
}
|
|
|
|
pItem = prev();
|
|
}
|
|
else
|
|
{
|
|
if (bCurrent)
|
|
break;
|
|
|
|
pItem = nullptr;
|
|
}
|
|
|
|
if (!pItem)
|
|
pItem = pCurItem;
|
|
}
|
|
rRenderContext.Pop();
|
|
}
|
|
|
|
void TabBar::Resize()
|
|
{
|
|
Size aNewSize = GetOutputSizePixel();
|
|
|
|
tools::Long nSizerWidth = 0;
|
|
|
|
// order the Sizer
|
|
if ( mpImpl->mpSizer )
|
|
{
|
|
Size aSizerSize = mpImpl->mpSizer->GetSizePixel();
|
|
Point aNewSizerPos( mbMirrored ? 0 : (aNewSize.Width()-aSizerSize.Width()), 0 );
|
|
Size aNewSizerSize( aSizerSize.Width(), aNewSize.Height() );
|
|
mpImpl->mpSizer->SetPosSizePixel( aNewSizerPos, aNewSizerSize );
|
|
nSizerWidth = aSizerSize.Width();
|
|
}
|
|
|
|
// order the scroll buttons
|
|
tools::Long const nHeight = aNewSize.Height();
|
|
// adapt font height?
|
|
ImplInitSettings( true, false );
|
|
|
|
mpImpl->mxButtonBox->AdaptToHeight(nHeight);
|
|
Size const aBtnsSize(mpImpl->mxButtonBox->get_preferred_size().Width(), nHeight);
|
|
Point aPos(mbMirrored ? (aNewSize.Width() - aBtnsSize.Width()) : 0, 0);
|
|
mpImpl->mxButtonBox->SetPosSizePixel(aPos, aBtnsSize);
|
|
auto nButtonWidth = aBtnsSize.Width();
|
|
|
|
// store size
|
|
maWinSize = aNewSize;
|
|
|
|
if( mbMirrored )
|
|
{
|
|
mnOffX = nSizerWidth;
|
|
mnLastOffX = maWinSize.Width() - nButtonWidth - 1;
|
|
}
|
|
else
|
|
{
|
|
mnOffX = nButtonWidth;
|
|
mnLastOffX = maWinSize.Width() - nSizerWidth - 1;
|
|
}
|
|
|
|
// reformat
|
|
mbSizeFormat = true;
|
|
if ( IsReallyVisible() )
|
|
{
|
|
if ( ImplCalcWidth() )
|
|
Invalidate();
|
|
|
|
ImplFormat();
|
|
|
|
// Ensure as many tabs as possible are visible:
|
|
sal_uInt16 nLastFirstPos = ImplGetLastFirstPos();
|
|
if ( mnFirstPos > nLastFirstPos )
|
|
{
|
|
mnFirstPos = nLastFirstPos;
|
|
mbFormat = true;
|
|
Invalidate();
|
|
}
|
|
// Ensure the currently selected page is visible
|
|
ImplShowPage(GetPagePos(mnCurPageId));
|
|
|
|
ImplFormat();
|
|
}
|
|
|
|
// enable/disable button
|
|
ImplEnableControls();
|
|
}
|
|
|
|
bool TabBar::PreNotify(NotifyEvent& rNEvt)
|
|
{
|
|
if (rNEvt.GetType() == NotifyEventType::COMMAND)
|
|
{
|
|
if (rNEvt.GetCommandEvent()->GetCommand() == CommandEventId::Wheel)
|
|
{
|
|
const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
|
|
sal_uInt16 nNewPos = mnFirstPos;
|
|
if (pData->GetNotchDelta() > 0)
|
|
{
|
|
if (mnFirstPos)
|
|
nNewPos = mnFirstPos - 1;
|
|
}
|
|
else if (pData->GetNotchDelta() < 0)
|
|
{
|
|
sal_uInt16 nCount = GetPageCount();
|
|
if (mnFirstPos < nCount)
|
|
nNewPos = mnFirstPos + 1;
|
|
}
|
|
if (nNewPos != mnFirstPos)
|
|
SetFirstPageId(GetPageId(nNewPos));
|
|
}
|
|
}
|
|
return Window::PreNotify(rNEvt);
|
|
}
|
|
|
|
void TabBar::RequestHelp(const HelpEvent& rHEvt)
|
|
{
|
|
sal_uInt16 nItemId = GetPageId(ScreenToOutputPixel(rHEvt.GetMousePosPixel()));
|
|
if (nItemId)
|
|
{
|
|
if (rHEvt.GetMode() & HelpEventMode::BALLOON)
|
|
{
|
|
OUString aStr = GetHelpText(nItemId);
|
|
if (!aStr.isEmpty())
|
|
{
|
|
tools::Rectangle aItemRect = GetPageRect(nItemId);
|
|
Point aPt = OutputToScreenPixel(aItemRect.TopLeft());
|
|
aItemRect.SetLeft( aPt.X() );
|
|
aItemRect.SetTop( aPt.Y() );
|
|
aPt = OutputToScreenPixel(aItemRect.BottomRight());
|
|
aItemRect.SetRight( aPt.X() );
|
|
aItemRect.SetBottom( aPt.Y() );
|
|
Help::ShowBalloon(this, aItemRect.Center(), aItemRect, aStr);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// show text for quick- or balloon-help
|
|
// if this is isolated or not fully visible
|
|
if (rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON))
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nItemId);
|
|
auto& rItem = mpImpl->maItemList[nPos];
|
|
if (rItem.mbShort || (rItem.maRect.Right() - 5 > mnLastOffX))
|
|
{
|
|
tools::Rectangle aItemRect = GetPageRect(nItemId);
|
|
Point aPt = OutputToScreenPixel(aItemRect.TopLeft());
|
|
aItemRect.SetLeft( aPt.X() );
|
|
aItemRect.SetTop( aPt.Y() );
|
|
aPt = OutputToScreenPixel(aItemRect.BottomRight());
|
|
aItemRect.SetRight( aPt.X() );
|
|
aItemRect.SetBottom( aPt.Y() );
|
|
OUString aStr = mpImpl->maItemList[nPos].maText;
|
|
if (!aStr.isEmpty())
|
|
{
|
|
if (rHEvt.GetMode() & HelpEventMode::BALLOON)
|
|
Help::ShowBalloon(this, aItemRect.Center(), aItemRect, aStr);
|
|
else
|
|
Help::ShowQuickHelp(this, aItemRect, aStr);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Window::RequestHelp(rHEvt);
|
|
}
|
|
|
|
void TabBar::StateChanged(StateChangedType nType)
|
|
{
|
|
Window::StateChanged(nType);
|
|
|
|
if (nType == StateChangedType::InitShow)
|
|
{
|
|
if ( (mbSizeFormat || mbFormat) && !mpImpl->maItemList.empty() )
|
|
ImplFormat();
|
|
}
|
|
else if (nType == StateChangedType::Zoom ||
|
|
nType == StateChangedType::ControlFont)
|
|
{
|
|
ImplInitSettings(true, false);
|
|
Invalidate();
|
|
}
|
|
else if (nType == StateChangedType::ControlForeground)
|
|
Invalidate();
|
|
else if (nType == StateChangedType::ControlBackground)
|
|
{
|
|
ImplInitSettings(false, true);
|
|
Invalidate();
|
|
}
|
|
else if (nType == StateChangedType::Mirroring)
|
|
{
|
|
bool bIsRTLEnabled = IsRTLEnabled();
|
|
// reacts on calls of EnableRTL, have to mirror all child controls
|
|
if (mpImpl->mpSizer)
|
|
mpImpl->mpSizer->EnableRTL(bIsRTLEnabled);
|
|
if (mpImpl->mxButtonBox)
|
|
{
|
|
mpImpl->mxButtonBox->m_xFirstButton->set_direction(bIsRTLEnabled);
|
|
mpImpl->mxButtonBox->m_xPrevButton->set_direction(bIsRTLEnabled);
|
|
mpImpl->mxButtonBox->m_xNextButton->set_direction(bIsRTLEnabled);
|
|
mpImpl->mxButtonBox->m_xLastButton->set_direction(bIsRTLEnabled);
|
|
mpImpl->mxButtonBox->m_xAddButton->set_direction(bIsRTLEnabled);
|
|
}
|
|
if (mpImpl->mxEdit)
|
|
{
|
|
weld::Entry& rEntry = mpImpl->mxEdit->get_widget();
|
|
rEntry.set_direction(bIsRTLEnabled);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TabBar::DataChanged(const DataChangedEvent& rDCEvt)
|
|
{
|
|
Window::DataChanged(rDCEvt);
|
|
|
|
if (rDCEvt.GetType() == DataChangedEventType::FONTS
|
|
|| rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION
|
|
|| (rDCEvt.GetType() == DataChangedEventType::SETTINGS
|
|
&& rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
|
|
{
|
|
ImplInitSettings(true, true);
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
void TabBar::ImplSelect()
|
|
{
|
|
Select();
|
|
CallEventListeners(VclEventId::TabbarPageSelected, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(mnCurPageId)));
|
|
}
|
|
|
|
void TabBar::Select()
|
|
{
|
|
maSelectHdl.Call(this);
|
|
}
|
|
|
|
void TabBar::DoubleClick()
|
|
{
|
|
}
|
|
|
|
void TabBar::Split()
|
|
{
|
|
maSplitHdl.Call(this);
|
|
}
|
|
|
|
void TabBar::ImplActivatePage()
|
|
{
|
|
ActivatePage();
|
|
|
|
CallEventListeners(VclEventId::TabbarPageActivated, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(mnCurPageId)));
|
|
}
|
|
|
|
void TabBar::ActivatePage()
|
|
{}
|
|
|
|
bool TabBar::ImplDeactivatePage()
|
|
{
|
|
bool bRet = DeactivatePage();
|
|
|
|
CallEventListeners(VclEventId::TabbarPageDeactivated, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(mnCurPageId)));
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void TabBar::ImplPrePaint()
|
|
{
|
|
sal_uInt16 nItemCount = mpImpl->getItemSize();
|
|
if (!nItemCount)
|
|
return;
|
|
|
|
// tabbar should be formatted
|
|
ImplFormat();
|
|
|
|
// assure the actual tabpage becomes visible at first format
|
|
if (!mbFirstFormat)
|
|
return;
|
|
|
|
mbFirstFormat = false;
|
|
|
|
if (!mnCurPageId || (mnFirstPos != 0) || mbDropPos)
|
|
return;
|
|
|
|
auto& rItem = mpImpl->maItemList[GetPagePos(mnCurPageId)];
|
|
if (rItem.maRect.IsEmpty())
|
|
{
|
|
// set mbDropPos (or misuse) to prevent Invalidate()
|
|
mbDropPos = true;
|
|
SetFirstPageId(mnCurPageId);
|
|
mbDropPos = false;
|
|
if (mnFirstPos != 0)
|
|
ImplFormat();
|
|
}
|
|
}
|
|
|
|
ImplTabBarItem* TabBar::ImplGetLastTabBarItem( sal_uInt16 nItemCount )
|
|
{
|
|
// find last visible entry
|
|
sal_uInt16 n = mnFirstPos + 1;
|
|
if (n >= nItemCount)
|
|
n = nItemCount-1;
|
|
ImplTabBarItem* pItem = seek(n);
|
|
while (pItem)
|
|
{
|
|
if (!pItem->maRect.IsEmpty())
|
|
{
|
|
n++;
|
|
pItem = next();
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
// draw all tabs (from back to front and actual last)
|
|
if (pItem)
|
|
n--;
|
|
else if (n >= nItemCount)
|
|
n = nItemCount-1;
|
|
pItem = seek(n);
|
|
return pItem;
|
|
}
|
|
|
|
bool TabBar::DeactivatePage()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool TabBar::StartRenaming()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
TabBarAllowRenamingReturnCode TabBar::AllowRenaming()
|
|
{
|
|
return TABBAR_RENAMING_YES;
|
|
}
|
|
|
|
void TabBar::EndRenaming()
|
|
{
|
|
}
|
|
|
|
void TabBar::Mirror()
|
|
{
|
|
|
|
}
|
|
|
|
void TabBar::AddTabClick()
|
|
{
|
|
|
|
}
|
|
|
|
void TabBar::InsertPage(sal_uInt16 nPageId, const OUString& rText,
|
|
TabBarPageBits nBits, sal_uInt16 nPos)
|
|
{
|
|
assert (nPageId && "TabBar::InsertPage(): PageId must not be 0");
|
|
assert ((GetPagePos(nPageId) == PAGE_NOT_FOUND) && "TabBar::InsertPage(): Page already exists");
|
|
assert ((nBits <= TPB_DISPLAY_NAME_ALLFLAGS) && "TabBar::InsertPage(): Invalid flag set in nBits");
|
|
|
|
// create PageItem and insert in the item list
|
|
ImplTabBarItem aItem( nPageId, rText, nBits );
|
|
if (nPos < mpImpl->maItemList.size())
|
|
{
|
|
auto it = mpImpl->maItemList.begin();
|
|
it += nPos;
|
|
mpImpl->maItemList.insert(it, aItem);
|
|
}
|
|
else
|
|
{
|
|
mpImpl->maItemList.push_back(aItem);
|
|
}
|
|
mbSizeFormat = true;
|
|
|
|
// set CurPageId if required
|
|
if (!mnCurPageId)
|
|
mnCurPageId = nPageId;
|
|
|
|
// redraw bar
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Invalidate();
|
|
|
|
CallEventListeners(VclEventId::TabbarPageInserted, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)));
|
|
}
|
|
|
|
Color TabBar::GetTabBgColor(sal_uInt16 nPageId) const
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
return mpImpl->maItemList[nPos].maTabBgColor;
|
|
else
|
|
return COL_AUTO;
|
|
}
|
|
|
|
void TabBar::SetTabBgColor(sal_uInt16 nPageId, const Color& aTabBgColor)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
if (nPos == PAGE_NOT_FOUND)
|
|
return;
|
|
|
|
auto& rItem = mpImpl->maItemList[nPos];
|
|
if (aTabBgColor != COL_AUTO)
|
|
{
|
|
rItem.maTabBgColor = aTabBgColor;
|
|
if (aTabBgColor.GetLuminance() <= 128) //Do not use aTabBgColor.IsDark(), because that threshold is way too low...
|
|
rItem.maTabTextColor = COL_WHITE;
|
|
else
|
|
rItem.maTabTextColor = COL_BLACK;
|
|
}
|
|
else
|
|
{
|
|
rItem.maTabBgColor = COL_AUTO;
|
|
rItem.maTabTextColor = COL_AUTO;
|
|
}
|
|
}
|
|
|
|
void TabBar::RemovePage(sal_uInt16 nPageId)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
// does item exist
|
|
if (nPos == PAGE_NOT_FOUND)
|
|
return;
|
|
|
|
if (mnCurPageId == nPageId)
|
|
mnCurPageId = 0;
|
|
|
|
// check if first visible page should be moved
|
|
if (mnFirstPos > nPos)
|
|
mnFirstPos--;
|
|
|
|
// delete item data
|
|
auto it = mpImpl->maItemList.begin();
|
|
it += nPos;
|
|
mpImpl->maItemList.erase(it);
|
|
|
|
// redraw bar
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Invalidate();
|
|
|
|
CallEventListeners(VclEventId::TabbarPageRemoved, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)));
|
|
}
|
|
|
|
void TabBar::MovePage(sal_uInt16 nPageId, sal_uInt16 nNewPos)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
Pair aPair(nPos, nNewPos);
|
|
|
|
if (nPos < nNewPos)
|
|
nNewPos--;
|
|
|
|
if (nPos == nNewPos)
|
|
return;
|
|
|
|
// does item exit
|
|
if (nPos == PAGE_NOT_FOUND)
|
|
return;
|
|
|
|
// move tabbar item in the list
|
|
auto it = mpImpl->maItemList.begin();
|
|
it += nPos;
|
|
ImplTabBarItem aItem = std::move(*it);
|
|
mpImpl->maItemList.erase(it);
|
|
if (nNewPos < mpImpl->maItemList.size())
|
|
{
|
|
it = mpImpl->maItemList.begin();
|
|
it += nNewPos;
|
|
mpImpl->maItemList.insert(it, aItem);
|
|
}
|
|
else
|
|
{
|
|
mpImpl->maItemList.push_back(aItem);
|
|
}
|
|
|
|
// redraw bar
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Invalidate();
|
|
|
|
CallEventListeners( VclEventId::TabbarPageMoved, static_cast<void*>(&aPair) );
|
|
}
|
|
|
|
void TabBar::Clear()
|
|
{
|
|
// delete all items
|
|
mpImpl->maItemList.clear();
|
|
|
|
// remove items from the list
|
|
mbSizeFormat = true;
|
|
mnCurPageId = 0;
|
|
mnFirstPos = 0;
|
|
maCurrentItemList = 0;
|
|
|
|
// redraw bar
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Invalidate();
|
|
|
|
CallEventListeners(VclEventId::TabbarPageRemoved, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(PAGE_NOT_FOUND)));
|
|
}
|
|
|
|
bool TabBar::IsPageEnabled(sal_uInt16 nPageId) const
|
|
{
|
|
if (isDisposed())
|
|
return false;
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
return nPos != PAGE_NOT_FOUND;
|
|
}
|
|
|
|
void TabBar::SetPageBits(sal_uInt16 nPageId, TabBarPageBits nBits)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
if (nPos == PAGE_NOT_FOUND)
|
|
return;
|
|
|
|
auto& rItem = mpImpl->maItemList[nPos];
|
|
|
|
if (rItem.mnBits != nBits)
|
|
{
|
|
rItem.mnBits = nBits;
|
|
|
|
// redraw bar
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Invalidate(rItem.maRect);
|
|
}
|
|
}
|
|
|
|
TabBarPageBits TabBar::GetPageBits(sal_uInt16 nPageId) const
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
return mpImpl->maItemList[nPos].mnBits;
|
|
else
|
|
return TabBarPageBits::NONE;
|
|
}
|
|
|
|
sal_uInt16 TabBar::GetPageCount() const
|
|
{
|
|
return mpImpl->getItemSize();
|
|
}
|
|
|
|
sal_uInt16 TabBar::GetPageId(sal_uInt16 nPos) const
|
|
{
|
|
return nPos < mpImpl->maItemList.size() ? mpImpl->maItemList[nPos].mnId : 0;
|
|
}
|
|
|
|
sal_uInt16 TabBar::GetPagePos(sal_uInt16 nPageId) const
|
|
{
|
|
for (size_t i = 0; i < mpImpl->maItemList.size(); ++i)
|
|
{
|
|
if (mpImpl->maItemList[i].mnId == nPageId)
|
|
{
|
|
return static_cast<sal_uInt16>(i);
|
|
}
|
|
}
|
|
return PAGE_NOT_FOUND;
|
|
}
|
|
|
|
sal_uInt16 TabBar::GetPageId(const Point& rPos) const
|
|
{
|
|
for (const auto& rItem : mpImpl->maItemList)
|
|
{
|
|
if (rItem.maRect.Contains(rPos))
|
|
return rItem.mnId;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
tools::Rectangle TabBar::GetPageRect(sal_uInt16 nPageId) const
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
return mpImpl->maItemList[nPos].maRect;
|
|
else
|
|
return tools::Rectangle();
|
|
}
|
|
|
|
void TabBar::SetCurPageId(sal_uInt16 nPageId)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
// do nothing if item does not exit
|
|
if (nPos == PAGE_NOT_FOUND)
|
|
return;
|
|
|
|
// do nothing if the actual page did not change
|
|
if (nPageId == mnCurPageId)
|
|
return;
|
|
|
|
// make invalid
|
|
bool bUpdate = false;
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
bUpdate = true;
|
|
|
|
auto& rItem = mpImpl->maItemList[nPos];
|
|
ImplTabBarItem* pOldItem;
|
|
|
|
if (mnCurPageId)
|
|
pOldItem = &mpImpl->maItemList[GetPagePos(mnCurPageId)];
|
|
else
|
|
pOldItem = nullptr;
|
|
|
|
// deselect previous page if page was not selected, if this is the
|
|
// only selected page
|
|
if (!rItem.mbSelect && pOldItem)
|
|
{
|
|
sal_uInt16 nSelPageCount = GetSelectPageCount();
|
|
if (nSelPageCount == 1)
|
|
pOldItem->mbSelect = false;
|
|
rItem.mbSelect = true;
|
|
}
|
|
|
|
mnCurPageId = nPageId;
|
|
mbFormat = true;
|
|
|
|
// assure the actual page becomes visible
|
|
if (IsReallyVisible())
|
|
{
|
|
if (nPos < mnFirstPos)
|
|
SetFirstPageId(nPageId);
|
|
else
|
|
{
|
|
// calculate visible width
|
|
tools::Long nWidth = mnLastOffX;
|
|
if (nWidth > ADDNEWPAGE_AREAWIDTH)
|
|
nWidth -= ADDNEWPAGE_AREAWIDTH;
|
|
|
|
if (rItem.maRect.IsEmpty())
|
|
ImplFormat();
|
|
|
|
while ((mbMirrored ? (rItem.maRect.Left() < mnOffX) : (rItem.maRect.Right() > nWidth)) ||
|
|
rItem.maRect.IsEmpty())
|
|
{
|
|
sal_uInt16 nNewPos = mnFirstPos + 1;
|
|
// assure at least the actual tabpages are visible as first tabpage
|
|
if (nNewPos >= nPos)
|
|
{
|
|
SetFirstPageId(nPageId);
|
|
break;
|
|
}
|
|
else
|
|
SetFirstPageId(GetPageId(nNewPos));
|
|
ImplFormat();
|
|
// abort if first page is not forwarded
|
|
if (nNewPos != mnFirstPos)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// redraw bar
|
|
if (bUpdate)
|
|
{
|
|
Invalidate(rItem.maRect);
|
|
if (pOldItem)
|
|
Invalidate(pOldItem->maRect);
|
|
}
|
|
}
|
|
|
|
void TabBar::MakeVisible(sal_uInt16 nPageId)
|
|
{
|
|
if (!IsReallyVisible())
|
|
return;
|
|
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
// do nothing if item does not exist
|
|
if (nPos == PAGE_NOT_FOUND)
|
|
return;
|
|
|
|
if (nPos < mnFirstPos)
|
|
SetFirstPageId(nPageId);
|
|
else
|
|
{
|
|
auto& rItem = mpImpl->maItemList[nPos];
|
|
|
|
// calculate visible area
|
|
tools::Long nWidth = mnLastOffX;
|
|
|
|
if (mbFormat || rItem.maRect.IsEmpty())
|
|
{
|
|
mbFormat = true;
|
|
ImplFormat();
|
|
}
|
|
|
|
while ((rItem.maRect.Right() > nWidth) ||
|
|
rItem.maRect.IsEmpty())
|
|
{
|
|
sal_uInt16 nNewPos = mnFirstPos+1;
|
|
// assure at least the actual tabpages are visible as first tabpage
|
|
if (nNewPos >= nPos)
|
|
{
|
|
SetFirstPageId(nPageId);
|
|
break;
|
|
}
|
|
else
|
|
SetFirstPageId(GetPageId(nNewPos));
|
|
ImplFormat();
|
|
// abort if first page is not forwarded
|
|
if (nNewPos != mnFirstPos)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TabBar::SetFirstPageId(sal_uInt16 nPageId)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
// return false if item does not exist
|
|
if (nPos == PAGE_NOT_FOUND)
|
|
return;
|
|
|
|
if (nPos == mnFirstPos)
|
|
return;
|
|
|
|
// assure as much pages are visible as possible
|
|
ImplFormat();
|
|
sal_uInt16 nLastFirstPos = ImplGetLastFirstPos();
|
|
sal_uInt16 nNewPos;
|
|
if (nPos > nLastFirstPos)
|
|
nNewPos = nLastFirstPos;
|
|
else
|
|
nNewPos = nPos;
|
|
|
|
if (nNewPos != mnFirstPos)
|
|
{
|
|
mnFirstPos = nNewPos;
|
|
mbFormat = true;
|
|
|
|
// redraw bar (attention: check mbDropPos,
|
|
// as if this flag was set, we do not re-paint immediately
|
|
if (IsReallyVisible() && IsUpdateMode() && !mbDropPos)
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
void TabBar::SelectPage(sal_uInt16 nPageId, bool bSelect)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
|
|
if (nPos == PAGE_NOT_FOUND)
|
|
return;
|
|
|
|
auto& rItem = mpImpl->maItemList[nPos];
|
|
|
|
if (rItem.mbSelect != bSelect)
|
|
{
|
|
rItem.mbSelect = bSelect;
|
|
|
|
// redraw bar
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Invalidate(rItem.maRect);
|
|
}
|
|
}
|
|
|
|
sal_uInt16 TabBar::GetSelectPageCount() const
|
|
{
|
|
sal_uInt16 nSelected = 0;
|
|
for (const auto& rItem : mpImpl->maItemList)
|
|
{
|
|
if (rItem.mbSelect)
|
|
nSelected++;
|
|
}
|
|
|
|
return nSelected;
|
|
}
|
|
|
|
bool TabBar::IsPageSelected(sal_uInt16 nPageId) const
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
return mpImpl->maItemList[nPos].mbSelect;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void TabBar::SetProtectionSymbol(sal_uInt16 nPageId, bool bProtection)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
{
|
|
if (mpImpl->maItemList[nPos].mbProtect != bProtection)
|
|
{
|
|
mpImpl->maItemList[nPos].mbProtect = bProtection;
|
|
mbSizeFormat = true; // render text width changes, thus bar width
|
|
|
|
// redraw bar
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Invalidate();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool TabBar::StartEditMode(sal_uInt16 nPageId)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos( nPageId );
|
|
if (mpImpl->mxEdit || (nPos == PAGE_NOT_FOUND) || (mnLastOffX < 8))
|
|
return false;
|
|
|
|
mnEditId = nPageId;
|
|
if (StartRenaming())
|
|
{
|
|
ImplShowPage(nPos);
|
|
ImplFormat();
|
|
PaintImmediately();
|
|
|
|
mpImpl->mxEdit.disposeAndReset(VclPtr<TabBarEdit>::Create(this));
|
|
tools::Rectangle aRect = GetPageRect( mnEditId );
|
|
tools::Long nX = aRect.Left();
|
|
tools::Long nWidth = aRect.GetWidth();
|
|
if (mnEditId != GetCurPageId())
|
|
nX += 1;
|
|
if (nX + nWidth > mnLastOffX)
|
|
nWidth = mnLastOffX-nX;
|
|
if (nWidth < 3)
|
|
{
|
|
nX = aRect.Left();
|
|
nWidth = aRect.GetWidth();
|
|
}
|
|
weld::Entry& rEntry = mpImpl->mxEdit->get_widget();
|
|
rEntry.set_text(GetPageText(mnEditId));
|
|
mpImpl->mxEdit->SetPosSizePixel(Point(nX, aRect.Top() + mnOffY + 1), Size(nWidth, aRect.GetHeight() - 3));
|
|
vcl::Font aFont = GetPointFont(*GetOutDev()); // FIXME RenderContext
|
|
|
|
Color aForegroundColor;
|
|
Color aBackgroundColor;
|
|
Color aFaceColor;
|
|
Color aSelectColor;
|
|
Color aFaceTextColor;
|
|
Color aSelectTextColor;
|
|
|
|
ImplGetColors(Application::GetSettings().GetStyleSettings(), aFaceColor, aFaceTextColor, aSelectColor, aSelectTextColor);
|
|
|
|
if (mnEditId != GetCurPageId())
|
|
{
|
|
aFont.SetWeight(WEIGHT_LIGHT);
|
|
}
|
|
if (IsPageSelected(mnEditId) || mnEditId == GetCurPageId())
|
|
{
|
|
aForegroundColor = aSelectTextColor;
|
|
aBackgroundColor = aSelectColor;
|
|
}
|
|
else
|
|
{
|
|
aForegroundColor = aFaceTextColor;
|
|
aBackgroundColor = aFaceColor;
|
|
}
|
|
if (GetPageBits( mnEditId ) & TabBarPageBits::Blue)
|
|
{
|
|
aForegroundColor = COL_LIGHTBLUE;
|
|
}
|
|
rEntry.set_font(aFont);
|
|
rEntry.set_font_color(aForegroundColor);
|
|
mpImpl->mxEdit->SetControlBackground(aBackgroundColor);
|
|
rEntry.grab_focus();
|
|
rEntry.select_region(0, -1);
|
|
mpImpl->mxEdit->Show();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
mnEditId = 0;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool TabBar::IsInEditMode() const
|
|
{
|
|
return bool(mpImpl->mxEdit);
|
|
}
|
|
|
|
void TabBar::EndEditMode(bool bCancel)
|
|
{
|
|
if (!mpImpl->mxEdit)
|
|
return;
|
|
|
|
// call hdl
|
|
bool bEnd = true;
|
|
mbEditCanceled = bCancel;
|
|
weld::Entry& rEntry = mpImpl->mxEdit->get_widget();
|
|
maEditText = rEntry.get_text();
|
|
mpImpl->mxEdit->SetPostEvent();
|
|
if (!bCancel)
|
|
{
|
|
TabBarAllowRenamingReturnCode nAllowRenaming = AllowRenaming();
|
|
if (nAllowRenaming == TABBAR_RENAMING_YES)
|
|
SetPageText(mnEditId, maEditText);
|
|
else if (nAllowRenaming == TABBAR_RENAMING_NO)
|
|
bEnd = false;
|
|
else // nAllowRenaming == TABBAR_RENAMING_CANCEL
|
|
mbEditCanceled = true;
|
|
}
|
|
|
|
// renaming not allowed, then reset edit data
|
|
if (!bEnd)
|
|
{
|
|
mpImpl->mxEdit->ResetPostEvent();
|
|
rEntry.grab_focus();
|
|
}
|
|
else
|
|
{
|
|
// close edit and call end hdl
|
|
mpImpl->mxEdit.disposeAndClear();
|
|
|
|
EndRenaming();
|
|
mnEditId = 0;
|
|
}
|
|
|
|
// reset
|
|
maEditText.clear();
|
|
mbEditCanceled = false;
|
|
}
|
|
|
|
void TabBar::SetMirrored(bool bMirrored)
|
|
{
|
|
if (mbMirrored != bMirrored)
|
|
{
|
|
mbMirrored = bMirrored;
|
|
mbSizeFormat = true;
|
|
ImplInitControls(); // for button images
|
|
Resize(); // recalculates control positions
|
|
Mirror();
|
|
}
|
|
}
|
|
|
|
void TabBar::SetEffectiveRTL(bool bRTL)
|
|
{
|
|
SetMirrored( bRTL != AllSettings::GetLayoutRTL() );
|
|
}
|
|
|
|
bool TabBar::IsEffectiveRTL() const
|
|
{
|
|
return IsMirrored() != AllSettings::GetLayoutRTL();
|
|
}
|
|
|
|
void TabBar::SetMaxPageWidth(tools::Long nMaxWidth)
|
|
{
|
|
if (mnMaxPageWidth != nMaxWidth)
|
|
{
|
|
mnMaxPageWidth = nMaxWidth;
|
|
mbSizeFormat = true;
|
|
|
|
// redraw bar
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Invalidate();
|
|
}
|
|
}
|
|
|
|
void TabBar::SetPageText(sal_uInt16 nPageId, const OUString& rText)
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
{
|
|
mpImpl->maItemList[nPos].maText = rText;
|
|
mbSizeFormat = true;
|
|
|
|
// redraw bar
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Invalidate();
|
|
|
|
CallEventListeners(VclEventId::TabbarPageTextChanged, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)));
|
|
}
|
|
}
|
|
|
|
const OUString & TabBar::GetPageText(sal_uInt16 nPageId) const
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
return mpImpl->maItemList[nPos].maText;
|
|
return EMPTY_OUSTRING;
|
|
}
|
|
|
|
const OUString & TabBar::GetAuxiliaryText(sal_uInt16 nPageId) const
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
return mpImpl->maItemList[nPos].maAuxiliaryText;
|
|
return EMPTY_OUSTRING;
|
|
}
|
|
|
|
void TabBar::SetAuxiliaryText(sal_uInt16 nPageId, const OUString& rText )
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
{
|
|
mpImpl->maItemList[nPos].maAuxiliaryText = rText;
|
|
// no redraw bar, no CallEventListener, internal use in LayerTabBar
|
|
}
|
|
}
|
|
|
|
OUString TabBar::GetHelpText(sal_uInt16 nPageId) const
|
|
{
|
|
sal_uInt16 nPos = GetPagePos(nPageId);
|
|
if (nPos != PAGE_NOT_FOUND)
|
|
{
|
|
auto& rItem = mpImpl->maItemList[nPos];
|
|
if (rItem.maHelpText.isEmpty() && !rItem.maHelpId.isEmpty())
|
|
{
|
|
Help* pHelp = Application::GetHelp();
|
|
if (pHelp)
|
|
rItem.maHelpText = pHelp->GetHelpText(OStringToOUString(rItem.maHelpId, RTL_TEXTENCODING_UTF8));
|
|
}
|
|
|
|
return rItem.maHelpText;
|
|
}
|
|
return OUString();
|
|
}
|
|
|
|
bool TabBar::StartDrag(const CommandEvent& rCEvt, vcl::Region& rRegion)
|
|
{
|
|
if (!(mnWinStyle & WB_DRAG) || (rCEvt.GetCommand() != CommandEventId::StartDrag))
|
|
return false;
|
|
|
|
// Check if the clicked page was selected. If this is not the case
|
|
// set it as actual entry. We check for this only at a mouse action
|
|
// if Drag and Drop can be triggered from the keyboard.
|
|
// We only do this, if Select() was not triggered, as the Select()
|
|
// could have scrolled the area
|
|
if (rCEvt.IsMouseEvent() && !mbInSelect)
|
|
{
|
|
sal_uInt16 nSelId = GetPageId(rCEvt.GetMousePosPixel());
|
|
|
|
// do not start dragging if no entry was clicked
|
|
if (!nSelId)
|
|
return false;
|
|
|
|
// check if page was selected. If not set it as actual
|
|
// page and call Select()
|
|
if (!IsPageSelected(nSelId))
|
|
{
|
|
if (ImplDeactivatePage())
|
|
{
|
|
SetCurPageId(nSelId);
|
|
PaintImmediately();
|
|
ImplActivatePage();
|
|
ImplSelect();
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
mbInSelect = false;
|
|
|
|
// assign region
|
|
rRegion = vcl::Region();
|
|
|
|
return true;
|
|
}
|
|
|
|
sal_uInt16 TabBar::ShowDropPos(const Point& rPos)
|
|
{
|
|
sal_uInt16 nNewDropPos;
|
|
sal_uInt16 nItemCount = mpImpl->getItemSize();
|
|
sal_Int16 nScroll = 0;
|
|
|
|
if (rPos.X() > mnLastOffX-TABBAR_DRAG_SCROLLOFF)
|
|
{
|
|
auto& rItem = mpImpl->maItemList[mpImpl->maItemList.size() - 1];
|
|
if (!rItem.maRect.IsEmpty() && (rPos.X() > rItem.maRect.Right()))
|
|
nNewDropPos = mpImpl->getItemSize();
|
|
else
|
|
{
|
|
nNewDropPos = mnFirstPos + 1;
|
|
nScroll = 1;
|
|
}
|
|
}
|
|
else if ((rPos.X() <= mnOffX) ||
|
|
(!mnOffX && (rPos.X() <= TABBAR_DRAG_SCROLLOFF)))
|
|
{
|
|
if (mnFirstPos)
|
|
{
|
|
nNewDropPos = mnFirstPos;
|
|
nScroll = -1;
|
|
}
|
|
else
|
|
nNewDropPos = 0;
|
|
}
|
|
else
|
|
{
|
|
sal_uInt16 nDropId = GetPageId(rPos);
|
|
if (nDropId)
|
|
{
|
|
nNewDropPos = GetPagePos(nDropId);
|
|
if (mnFirstPos && (nNewDropPos == mnFirstPos - 1))
|
|
nScroll = -1;
|
|
}
|
|
else
|
|
nNewDropPos = nItemCount;
|
|
}
|
|
|
|
if (mbDropPos && (nNewDropPos == mnDropPos) && !nScroll)
|
|
return mnDropPos;
|
|
|
|
if (mbDropPos)
|
|
HideDropPos();
|
|
mbDropPos = true;
|
|
mnDropPos = nNewDropPos;
|
|
|
|
if (nScroll)
|
|
{
|
|
sal_uInt16 nOldFirstPos = mnFirstPos;
|
|
SetFirstPageId(GetPageId(mnFirstPos + nScroll));
|
|
|
|
// draw immediately, as Paint not possible during Drag and Drop
|
|
if (nOldFirstPos != mnFirstPos)
|
|
{
|
|
tools::Rectangle aRect(mnOffX, 0, mnLastOffX, maWinSize.Height());
|
|
GetOutDev()->SetFillColor(GetBackground().GetColor());
|
|
GetOutDev()->DrawRect(aRect);
|
|
Invalidate(aRect);
|
|
}
|
|
}
|
|
|
|
// draw drop position arrows
|
|
const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
|
|
const Color aTextColor = rStyles.GetLabelTextColor();
|
|
tools::Long nX;
|
|
tools::Long nY = (maWinSize.Height() / 2) - 1;
|
|
sal_uInt16 nCurPos = GetPagePos(mnCurPageId);
|
|
|
|
sal_Int32 nTriangleWidth = 3 * GetDPIScaleFactor();
|
|
|
|
if (mnDropPos < nItemCount)
|
|
{
|
|
GetOutDev()->SetLineColor(aTextColor);
|
|
GetOutDev()->SetFillColor(aTextColor);
|
|
|
|
auto& rItem = mpImpl->maItemList[mnDropPos];
|
|
nX = rItem.maRect.Left();
|
|
if ( mnDropPos == nCurPos )
|
|
nX--;
|
|
else
|
|
nX++;
|
|
|
|
if (!rItem.IsDefaultTabBgColor() && !rItem.mbSelect)
|
|
{
|
|
GetOutDev()->SetLineColor(rItem.maTabTextColor);
|
|
GetOutDev()->SetFillColor(rItem.maTabTextColor);
|
|
}
|
|
|
|
tools::Polygon aPoly(3);
|
|
aPoly.SetPoint(Point(nX, nY), 0);
|
|
aPoly.SetPoint(Point(nX + nTriangleWidth, nY - nTriangleWidth), 1);
|
|
aPoly.SetPoint(Point(nX + nTriangleWidth, nY + nTriangleWidth), 2);
|
|
GetOutDev()->DrawPolygon(aPoly);
|
|
}
|
|
if (mnDropPos > 0 && mnDropPos < nItemCount + 1)
|
|
{
|
|
GetOutDev()->SetLineColor(aTextColor);
|
|
GetOutDev()->SetFillColor(aTextColor);
|
|
|
|
auto& rItem = mpImpl->maItemList[mnDropPos - 1];
|
|
nX = rItem.maRect.Right();
|
|
if (mnDropPos == nCurPos)
|
|
nX++;
|
|
if (!rItem.IsDefaultTabBgColor() && !rItem.mbSelect)
|
|
{
|
|
GetOutDev()->SetLineColor(rItem.maTabTextColor);
|
|
GetOutDev()->SetFillColor(rItem.maTabTextColor);
|
|
}
|
|
tools::Polygon aPoly(3);
|
|
aPoly.SetPoint(Point(nX, nY), 0);
|
|
aPoly.SetPoint(Point(nX - nTriangleWidth, nY - nTriangleWidth), 1);
|
|
aPoly.SetPoint(Point(nX - nTriangleWidth, nY + nTriangleWidth), 2);
|
|
GetOutDev()->DrawPolygon(aPoly);
|
|
}
|
|
|
|
return mnDropPos;
|
|
}
|
|
|
|
void TabBar::HideDropPos()
|
|
{
|
|
if (!mbDropPos)
|
|
return;
|
|
|
|
tools::Long nX;
|
|
tools::Long nY1 = (maWinSize.Height() / 2) - 3;
|
|
tools::Long nY2 = nY1 + 5;
|
|
sal_uInt16 nItemCount = mpImpl->getItemSize();
|
|
|
|
if (mnDropPos < nItemCount)
|
|
{
|
|
auto& rItem = mpImpl->maItemList[mnDropPos];
|
|
nX = rItem.maRect.Left();
|
|
// immediately call Paint, as it is not possible during drag and drop
|
|
tools::Rectangle aRect( nX-1, nY1, nX+3, nY2 );
|
|
vcl::Region aRegion( aRect );
|
|
GetOutDev()->SetClipRegion( aRegion );
|
|
Invalidate(aRect);
|
|
GetOutDev()->SetClipRegion();
|
|
}
|
|
if (mnDropPos > 0 && mnDropPos < nItemCount + 1)
|
|
{
|
|
auto& rItem = mpImpl->maItemList[mnDropPos - 1];
|
|
nX = rItem.maRect.Right();
|
|
// immediately call Paint, as it is not possible during drag and drop
|
|
tools::Rectangle aRect(nX - 2, nY1, nX + 1, nY2);
|
|
vcl::Region aRegion(aRect);
|
|
GetOutDev()->SetClipRegion(aRegion);
|
|
Invalidate(aRect);
|
|
GetOutDev()->SetClipRegion();
|
|
}
|
|
|
|
mbDropPos = false;
|
|
mnDropPos = 0;
|
|
}
|
|
|
|
void TabBar::SwitchPage(const Point& rPos)
|
|
{
|
|
sal_uInt16 nSwitchId = GetPageId(rPos);
|
|
if (!nSwitchId)
|
|
EndSwitchPage();
|
|
else
|
|
{
|
|
if (nSwitchId != mnSwitchId)
|
|
{
|
|
mnSwitchId = nSwitchId;
|
|
mnSwitchTime = tools::Time::GetSystemTicks();
|
|
}
|
|
else
|
|
{
|
|
// change only after 500 ms
|
|
if (mnSwitchId != GetCurPageId())
|
|
{
|
|
if (tools::Time::GetSystemTicks() > mnSwitchTime + 500)
|
|
{
|
|
if (ImplDeactivatePage())
|
|
{
|
|
SetCurPageId( mnSwitchId );
|
|
PaintImmediately();
|
|
ImplActivatePage();
|
|
ImplSelect();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void TabBar::EndSwitchPage()
|
|
{
|
|
mnSwitchTime = 0;
|
|
mnSwitchId = 0;
|
|
}
|
|
|
|
void TabBar::SetStyle(WinBits nStyle)
|
|
{
|
|
if (mnWinStyle == nStyle)
|
|
return;
|
|
mnWinStyle = nStyle;
|
|
ImplInitControls();
|
|
// order possible controls
|
|
if (IsReallyVisible() && IsUpdateMode())
|
|
Resize();
|
|
}
|
|
|
|
Size TabBar::CalcWindowSizePixel() const
|
|
{
|
|
tools::Long nWidth = 0;
|
|
|
|
if (!mpImpl->maItemList.empty())
|
|
{
|
|
const_cast<TabBar*>(this)->ImplCalcWidth();
|
|
for (const auto& rItem : mpImpl->maItemList)
|
|
{
|
|
nWidth += rItem.mnWidth;
|
|
}
|
|
}
|
|
|
|
return Size(nWidth, GetSettings().GetStyleSettings().GetScrollBarSize());
|
|
}
|
|
|
|
tools::Rectangle TabBar::GetPageArea() const
|
|
{
|
|
return tools::Rectangle(Point(mnOffX, mnOffY),
|
|
Size(mnLastOffX - mnOffX + 1, GetSizePixel().Height() - mnOffY));
|
|
}
|
|
|
|
void TabBar::SetAddButtonEnabled(bool bAddButtonEnabled)
|
|
{
|
|
mpImpl->mxButtonBox->m_xAddButton->set_sensitive(bAddButtonEnabled);
|
|
}
|
|
|
|
css::uno::Reference<css::accessibility::XAccessible> TabBar::CreateAccessible()
|
|
{
|
|
return mpImpl->maAccessibleFactory.getFactory().createAccessibleTabBar(*this);
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|