/* -*- 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 .
*/
// 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);
}
// 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;
// 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;
bool TabBar::ImplCalcWidth()
{ // Sizes should only be retrieved if the text or the font was changed if (!mbSizeFormat) returnfalse;
// retrieve width of tabs with bold font
vcl::Font aFont = GetFont(); if (aFont.GetWeightMaybeAskConfig() != WEIGHT_BOLD)
{
aFont.SetWeight(WEIGHT_BOLD);
SetFont(aFont);
}
if (mnMaxPageWidth)
mnCurMaxWidth = mnMaxPageWidth; else
{
mnCurMaxWidth = mnLastOffX - mnOffX; if (mnCurMaxWidth < 1)
mnCurMaxWidth = 1;
}
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);
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;
}
}
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;
}
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;
}
} elseif (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;
}
} elseif (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();
}
// 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));
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();
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;
}
}
// 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();
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;
// 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;
}
}
}
// 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;
// redraw bar (attention: check mbDropPos, // as if this flag was set, we do not re-paint immediately if (IsReallyVisible() && IsUpdateMode() && !mbDropPos)
Invalidate();
}
}
// 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();
// 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) returnfalse;
// check if page was selected. If not set it as actual // page and call Select() if (!IsPageSelected(nSelId))
{ if (ImplDeactivatePage())
{
SetCurPageId(nSelId);
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.