Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svtools/source/control/tabbar.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include "accessibletabbar.hxx"
21
22
#include <svtools/tabbar.hxx>
23
#include <tools/time.hxx>
24
#include <tools/poly.hxx>
25
#include <utility>
26
#include <vcl/InterimItemWindow.hxx>
27
#include <vcl/bitmap.hxx>
28
#include <vcl/salnativewidgets.hxx>
29
#include <vcl/svapp.hxx>
30
#include <vcl/help.hxx>
31
#include <vcl/decoview.hxx>
32
#include <vcl/event.hxx>
33
#include <vcl/settings.hxx>
34
#include <vcl/commandevent.hxx>
35
#include <vcl/ptrstyle.hxx>
36
#include <vcl/weld/Builder.hxx>
37
#include <vcl/weld/Entry.hxx>
38
#include <vcl/vclevent.hxx>
39
#include <vcl/weld/weldutils.hxx>
40
#include <svtools/svtresid.hxx>
41
#include <svtools/strings.hrc>
42
#include <limits>
43
#include <memory>
44
#include <vector>
45
#include <vcl/idle.hxx>
46
#include <bitmaps.hlst>
47
48
namespace
49
{
50
51
constexpr sal_uInt16 TABBAR_DRAG_SCROLLOFF = 5;
52
constexpr sal_uInt16 TABBAR_MINSIZE = 5;
53
54
constexpr sal_uInt16 ADDNEWPAGE_AREAWIDTH = 10;
55
56
class TabDrawer
57
{
58
private:
59
    vcl::RenderContext& mrRenderContext;
60
    const StyleSettings& mrStyleSettings;
61
62
    tools::Rectangle maRect;
63
    tools::Rectangle maLineRect;
64
65
    Color maSelectedColor;
66
    Color maCustomColor;
67
68
public:
69
    bool mbSelected:1;
70
    bool mbCustomColored:1;
71
    bool mbEnabled:1;
72
    bool mbProtect:1;
73
74
    explicit TabDrawer(vcl::RenderContext& rRenderContext)
75
0
        : mrRenderContext(rRenderContext)
76
0
        , mrStyleSettings(rRenderContext.GetSettings().GetStyleSettings())
77
0
        , mbSelected(false)
78
0
        , mbCustomColored(false)
79
0
        , mbEnabled(false)
80
0
        , mbProtect(false)
81
0
    {
82
83
0
    }
84
85
    void drawOuterFrame()
86
0
    {
87
        // set correct FillInBrush depending on status
88
0
        if (mbSelected)
89
0
        {
90
            // Currently selected Tab
91
0
            mrRenderContext.SetFillColor(maSelectedColor);
92
0
            mrRenderContext.SetLineColor(maSelectedColor);
93
0
            mrRenderContext.DrawRect(maRect);
94
0
            mrRenderContext.SetLineColor(mrStyleSettings.GetDarkShadowColor());
95
0
        }
96
0
        else if (mbCustomColored)
97
0
        {
98
0
            mrRenderContext.SetFillColor(maCustomColor);
99
0
            mrRenderContext.SetLineColor(maCustomColor);
100
0
            mrRenderContext.DrawRect(maRect);
101
0
            mrRenderContext.SetLineColor(mrStyleSettings.GetDarkShadowColor());
102
0
        }
103
0
    }
104
105
    void drawText(const OUString& aText)
106
0
    {
107
0
        tools::Rectangle aRect = maRect;
108
0
        tools::Long nTextWidth = mrRenderContext.GetTextWidth(aText);
109
0
        tools::Long nTextHeight = mrRenderContext.GetTextHeight();
110
0
        Point aPos = aRect.TopLeft();
111
0
        aPos.AdjustX((aRect.getOpenWidth()  - nTextWidth) / 2 );
112
0
        aPos.AdjustY((aRect.getOpenHeight() - nTextHeight) / 2 );
113
114
0
        if (mbEnabled)
115
0
            mrRenderContext.DrawText(aPos, aText);
116
0
        else
117
0
            mrRenderContext.DrawCtrlText(aPos, aText, 0, aText.getLength(), (DrawTextFlags::Disable | DrawTextFlags::Mnemonic));
118
0
    }
119
120
    void drawOverTopBorder()
121
0
    {
122
0
        Point aTopLeft  = maRect.TopLeft()  + Point(1, 0);
123
0
        Point aTopRight = maRect.TopRight() + Point(-1, 0);
124
125
0
        tools::Rectangle aDelRect(aTopLeft, aTopRight);
126
0
        mrRenderContext.DrawRect(aDelRect);
127
0
    }
128
129
    void drawColorLine()
130
0
    {
131
0
        if (!mbSelected)
132
0
            return;
133
134
        // tdf#141396: the color must be different from the rest of the selected tab
135
0
        Color aLineColor = (mbCustomColored && maCustomColor != maSelectedColor)
136
0
                               ? maCustomColor
137
0
                               : mrStyleSettings.GetDarkShadowColor();
138
0
        mrRenderContext.SetFillColor(aLineColor);
139
0
        mrRenderContext.SetLineColor(aLineColor);
140
0
        mrRenderContext.DrawRect(maLineRect);
141
0
    }
142
143
    void drawSeparator()
144
0
    {
145
0
        const tools::Long cMargin = 5;
146
0
        const tools::Long aRight( maRect.Right() - 1 );
147
0
        mrRenderContext.SetLineColor(mrStyleSettings.GetShadowColor());
148
0
        mrRenderContext.DrawLine(Point(aRight, maRect.Top() + cMargin),
149
0
                                 Point(aRight, maRect.Bottom() - cMargin));
150
0
    }
151
152
    void drawTab()
153
0
    {
154
0
        drawOuterFrame();
155
0
        drawColorLine();
156
0
        if (!mbSelected && !mbCustomColored)
157
0
            drawSeparator();
158
0
        if (mbProtect)
159
0
        {
160
0
            Bitmap aBitmap(BMP_TAB_LOCK);
161
0
            Point aPosition = maRect.TopLeft();
162
0
            aPosition.AdjustX(2);
163
0
            aPosition.AdjustY((maRect.getOpenHeight() - aBitmap.GetSizePixel().Height()) / 2);
164
0
            mrRenderContext.DrawBitmap(aPosition, aBitmap);
165
0
        }
166
0
    }
167
168
    void setRect(const tools::Rectangle& rRect)
169
0
    {
170
0
        maLineRect = tools::Rectangle(rRect.BottomLeft(), rRect.BottomRight());
171
0
        maLineRect.AdjustTop(-2);
172
0
        maRect = rRect;
173
0
    }
174
175
    void setSelected(bool bSelected)
176
0
    {
177
0
        mbSelected = bSelected;
178
0
    }
179
180
    void setCustomColored(bool bCustomColored)
181
0
    {
182
0
        mbCustomColored = bCustomColored;
183
0
    }
184
185
    void setEnabled(bool bEnabled)
186
0
    {
187
0
        mbEnabled = bEnabled;
188
0
    }
189
190
    void setSelectedFillColor(const Color& rColor)
191
0
    {
192
0
        maSelectedColor = rColor;
193
0
    }
194
195
    void setCustomColor(const Color& rColor)
196
0
    {
197
0
        maCustomColor = rColor;
198
0
    }
199
};
200
201
} // anonymous namespace
202
203
struct ImplTabBarItem
204
{
205
    sal_uInt16 mnId;
206
    TabBarPageBits mnBits;
207
    OUString maText;
208
    OUString maHelpText;
209
    OUString maAuxiliaryText; // used in LayerTabBar for real layer name
210
    tools::Rectangle maRect;
211
    tools::Long mnWidth;
212
    OString maHelpId;
213
    bool mbShort : 1;
214
    bool mbSelect : 1;
215
    bool mbProtect : 1;
216
    Color maTabBgColor;
217
    Color maTabTextColor;
218
219
    ImplTabBarItem(sal_uInt16 nItemId, OUString aText, TabBarPageBits nPageBits)
220
0
        : mnId(nItemId)
221
0
        , mnBits(nPageBits)
222
0
        , maText(std::move(aText))
223
0
        , mnWidth(0)
224
0
        , mbShort(false)
225
0
        , mbSelect(false)
226
0
        , mbProtect(false)
227
0
        , maTabBgColor(COL_AUTO)
228
0
        , maTabTextColor(COL_AUTO)
229
0
    {
230
0
    }
231
232
    bool IsDefaultTabBgColor() const
233
0
    {
234
0
        return maTabBgColor == COL_AUTO;
235
0
    }
236
237
    bool IsSelected(ImplTabBarItem const * pCurItem) const
238
0
    {
239
0
        return mbSelect || (pCurItem == this);
240
0
    }
241
242
    OUString const & GetRenderText() const
243
0
    {
244
0
        return maText;
245
0
    }
246
};
247
248
class ImplTabSizer : public vcl::Window
249
{
250
public:
251
                    ImplTabSizer( TabBar* pParent, WinBits nWinStyle );
252
253
0
    TabBar*         GetParent() const { return static_cast<TabBar*>(Window::GetParent()); }
254
255
private:
256
    void            ImplTrack( const Point& rScreenPos );
257
258
    virtual void    MouseButtonDown( const MouseEvent& rMEvt ) override;
259
    virtual void    Tracking( const TrackingEvent& rTEvt ) override;
260
    virtual void    Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect ) override;
261
262
    Point           maStartPos;
263
    tools::Long            mnStartWidth;
264
};
265
266
ImplTabSizer::ImplTabSizer( TabBar* pParent, WinBits nWinStyle )
267
0
    : Window( pParent, nWinStyle & WB_3DLOOK )
268
0
    , mnStartWidth(0)
269
0
{
270
0
    SetPointer(PointerStyle::HSizeBar);
271
0
    SetSizePixel(Size(7 * GetDPIScaleFactor(), 0));
272
0
}
Unexecuted instantiation: ImplTabSizer::ImplTabSizer(TabBar*, long)
Unexecuted instantiation: ImplTabSizer::ImplTabSizer(TabBar*, long)
273
274
void ImplTabSizer::ImplTrack( const Point& rScreenPos )
275
0
{
276
0
    TabBar* pParent = GetParent();
277
0
    tools::Long nDiff = rScreenPos.X() - maStartPos.X();
278
0
    pParent->mnSplitSize = mnStartWidth + (pParent->IsMirrored() ? -nDiff : nDiff);
279
0
    if ( pParent->mnSplitSize < TABBAR_MINSIZE )
280
0
        pParent->mnSplitSize = TABBAR_MINSIZE;
281
0
    pParent->Split();
282
0
    pParent->PaintImmediately();
283
0
}
284
285
void ImplTabSizer::MouseButtonDown( const MouseEvent& rMEvt )
286
0
{
287
0
    if ( GetParent()->IsInEditMode() )
288
0
    {
289
0
        GetParent()->EndEditMode();
290
0
        return;
291
0
    }
292
293
0
    if ( rMEvt.IsLeft() )
294
0
    {
295
0
        maStartPos = OutputToScreenPixel( rMEvt.GetPosPixel() );
296
0
        mnStartWidth = GetParent()->GetSizePixel().Width();
297
0
        StartTracking();
298
0
    }
299
0
}
300
301
void ImplTabSizer::Tracking( const TrackingEvent& rTEvt )
302
0
{
303
0
    if ( rTEvt.IsTrackingEnded() )
304
0
    {
305
0
        if ( rTEvt.IsTrackingCanceled() )
306
0
            ImplTrack( maStartPos );
307
0
        GetParent()->mnSplitSize = 0;
308
0
    }
309
0
    else
310
0
        ImplTrack( OutputToScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) );
311
0
}
312
313
void ImplTabSizer::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
314
0
{
315
0
    DecorationView aDecoView(&rRenderContext);
316
0
    tools::Rectangle aOutputRect(Point(0, 0), GetOutputSizePixel());
317
0
    aDecoView.DrawHandle(aOutputRect);
318
0
}
319
320
namespace {
321
322
// Is not named Impl. as it may be both instantiated and derived from
323
class TabBarEdit final : public InterimItemWindow
324
{
325
private:
326
    std::unique_ptr<weld::Entry> m_xEntry;
327
    Idle            maLoseFocusIdle;
328
    bool            mbPostEvt;
329
330
    DECL_LINK( ImplEndEditHdl, void*, void );
331
    DECL_LINK( ImplEndTimerHdl, Timer*, void );
332
    DECL_LINK( ActivatedHdl, weld::Entry&, bool );
333
    DECL_LINK( KeyInputHdl, const KeyEvent&, bool );
334
    DECL_LINK( FocusOutHdl, weld::Widget&, void );
335
336
public:
337
    TabBarEdit(TabBar* pParent);
338
    virtual void dispose() override;
339
340
0
    TabBar*         GetParent() const { return static_cast<TabBar*>(Window::GetParent()); }
341
342
0
    weld::Entry&    get_widget() { return *m_xEntry; }
343
344
0
    void            SetPostEvent() { mbPostEvt = true; }
345
0
    void            ResetPostEvent() { mbPostEvt = false; }
346
};
347
348
}
349
350
TabBarEdit::TabBarEdit(TabBar* pParent)
351
0
    : InterimItemWindow(pParent, u"svt/ui/tabbaredit.ui"_ustr, u"TabBarEdit"_ustr)
352
0
    , m_xEntry(m_xBuilder->weld_entry(u"entry"_ustr))
353
0
    , maLoseFocusIdle( "svtools::TabBarEdit maLoseFocusIdle" )
354
0
{
355
0
    InitControlBase(m_xEntry.get());
356
357
0
    mbPostEvt = false;
358
0
    maLoseFocusIdle.SetPriority( TaskPriority::REPAINT );
359
0
    maLoseFocusIdle.SetInvokeHandler( LINK( this, TabBarEdit, ImplEndTimerHdl ) );
360
361
0
    m_xEntry->connect_activate(LINK(this, TabBarEdit, ActivatedHdl));
362
0
    m_xEntry->connect_key_press(LINK(this, TabBarEdit, KeyInputHdl));
363
0
    m_xEntry->connect_focus_out(LINK(this, TabBarEdit, FocusOutHdl));
364
0
}
365
366
void TabBarEdit::dispose()
367
0
{
368
0
    m_xEntry.reset();
369
0
    InterimItemWindow::dispose();
370
0
}
371
372
IMPL_LINK_NOARG(TabBarEdit, ActivatedHdl, weld::Entry&, bool)
373
0
{
374
0
    if ( !mbPostEvt )
375
0
    {
376
0
        if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(false), true ) )
377
0
            mbPostEvt = true;
378
0
    }
379
0
    return true;
380
0
}
381
382
IMPL_LINK(TabBarEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool)
383
0
{
384
0
    if (!rKEvt.GetKeyCode().GetModifier() && rKEvt.GetKeyCode().GetCode() == KEY_ESCAPE)
385
0
    {
386
0
        if ( !mbPostEvt )
387
0
        {
388
0
            if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(true), true ) )
389
0
                mbPostEvt = true;
390
0
        }
391
0
        return true;
392
0
    }
393
0
    return false;
394
0
}
395
396
IMPL_LINK_NOARG(TabBarEdit, FocusOutHdl, weld::Widget&, void)
397
0
{
398
0
    if ( !mbPostEvt )
399
0
    {
400
0
        if ( PostUserEvent( LINK( this, TabBarEdit, ImplEndEditHdl ), reinterpret_cast<void*>(false), true ) )
401
0
            mbPostEvt = true;
402
0
    }
403
0
}
404
405
IMPL_LINK( TabBarEdit, ImplEndEditHdl, void*, pCancel, void )
406
0
{
407
0
    ResetPostEvent();
408
0
    maLoseFocusIdle.Stop();
409
410
    // tdf#156958: when renaming and clicking on canvas, LO goes into GetParent()->EndEditMode first time
411
    // then it calls TabBarEdit::dispose method which resets m_xEntry BUT, on the same thread, LO comes here again
412
    // so return if already disposed to avoid a crash
413
0
    if (isDisposed())
414
0
        return;
415
416
    // We need this query, because the edit gets a losefocus event,
417
    // when it shows the context menu or the insert symbol dialog
418
0
    if (!m_xEntry->has_focus() && m_xEntry->has_child_focus())
419
0
        maLoseFocusIdle.Start();
420
0
    else
421
0
        GetParent()->EndEditMode( pCancel != nullptr );
422
0
}
423
424
IMPL_LINK_NOARG(TabBarEdit, ImplEndTimerHdl, Timer *, void)
425
0
{
426
0
    if (m_xEntry->has_focus())
427
0
        return;
428
429
    // We need this query, because the edit gets a losefocus event,
430
    // when it shows the context menu or the insert symbol dialog
431
0
    if (m_xEntry->has_child_focus())
432
0
        maLoseFocusIdle.Start();
433
0
    else
434
0
        GetParent()->EndEditMode( true );
435
0
}
436
437
namespace {
438
439
class TabButtons final : public InterimItemWindow
440
{
441
public:
442
    std::unique_ptr<weld::Button> m_xFirstButton;
443
    std::unique_ptr<weld::Button> m_xPrevButton;
444
    std::unique_ptr<weld::Button> m_xNextButton;
445
    std::unique_ptr<weld::Button> m_xLastButton;
446
    std::unique_ptr<weld::Button> m_xAddButton;
447
    std::shared_ptr<weld::ButtonPressRepeater> m_xAddRepeater;
448
    std::shared_ptr<weld::ButtonPressRepeater> m_xPrevRepeater;
449
    std::shared_ptr<weld::ButtonPressRepeater> m_xNextRepeater;
450
451
    TabButtons(TabBar* pParent, bool bSheets)
452
0
        : InterimItemWindow(pParent,
453
0
                            pParent->IsMirrored() ? u"svt/ui/tabbuttonsmirrored.ui"_ustr
454
0
                                                  : u"svt/ui/tabbuttons.ui"_ustr,
455
0
                            u"TabButtons"_ustr)
456
0
        , m_xFirstButton(m_xBuilder->weld_button(u"first"_ustr))
457
0
        , m_xPrevButton(m_xBuilder->weld_button(u"prev"_ustr))
458
0
        , m_xNextButton(m_xBuilder->weld_button(u"next"_ustr))
459
0
        , m_xLastButton(m_xBuilder->weld_button(u"last"_ustr))
460
0
        , m_xAddButton(m_xBuilder->weld_button(u"add"_ustr))
461
0
    {
462
0
        const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
463
0
        SetPaintTransparent(false);
464
0
        SetBackground(rStyleSettings.GetFaceColor());
465
466
0
        m_xFirstButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_MOVET0HOME));
467
0
        m_xPrevButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_MOVELEFT));
468
0
        m_xNextButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_MOVERIGHT));
469
0
        m_xLastButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_MOVETOEND));
470
0
        m_xAddButton->set_accessible_name(SvtResId(STR_TABBAR_PUSHBUTTON_ADDTAB));
471
472
0
        if (bSheets)
473
0
        {
474
0
            m_xFirstButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_MOVETOHOME_SHEETS));
475
0
            m_xPrevButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_MOVELEFT_SHEETS));
476
0
            m_xNextButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_MOVERIGHT_SHEETS));
477
0
            m_xLastButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_MOVETOEND_SHEETS));
478
0
            m_xAddButton->set_tooltip_text(SvtResId(STR_TABBAR_HINT_ADDTAB_SHEETS));
479
0
        }
480
0
    }
481
482
    void AdaptToHeight(int nHeight)
483
0
    {
484
0
        if (m_xFirstButton->get_preferred_size() == Size(nHeight, nHeight))
485
0
            return;
486
0
        m_xFirstButton->set_size_request(nHeight, nHeight);
487
0
        m_xPrevButton->set_size_request(nHeight, nHeight);
488
0
        m_xNextButton->set_size_request(nHeight, nHeight);
489
0
        m_xLastButton->set_size_request(nHeight, nHeight);
490
0
        m_xAddButton->set_size_request(nHeight, nHeight);
491
0
        InvalidateChildSizeCache();
492
0
    }
493
494
    virtual void dispose() override
495
0
    {
496
0
        m_xNextRepeater.reset();
497
0
        m_xPrevRepeater.reset();
498
0
        m_xAddRepeater.reset();
499
0
        m_xAddButton.reset();
500
0
        m_xLastButton.reset();
501
0
        m_xNextButton.reset();
502
0
        m_xPrevButton.reset();
503
0
        m_xFirstButton.reset();
504
0
        InterimItemWindow::dispose();
505
0
    }
506
};
507
508
}
509
510
struct TabBar_Impl
511
{
512
    ScopedVclPtr<ImplTabSizer>  mpSizer;
513
    ScopedVclPtr<TabButtons>    mxButtonBox;
514
    ScopedVclPtr<TabBarEdit>    mxEdit;
515
    std::vector<ImplTabBarItem> maItemList;
516
517
    sal_uInt16 getItemSize() const
518
0
    {
519
0
        return static_cast<sal_uInt16>(maItemList.size());
520
0
    }
521
};
522
523
TabBar::TabBar( vcl::Window* pParent, WinBits nWinStyle, bool bSheets ) :
524
0
    Window( pParent, (nWinStyle & WB_3DLOOK) | WB_CLIPCHILDREN )
525
0
{
526
0
    ImplInit( nWinStyle, bSheets );
527
0
    maCurrentItemList = 0;
528
0
}
Unexecuted instantiation: TabBar::TabBar(vcl::Window*, long, bool)
Unexecuted instantiation: TabBar::TabBar(vcl::Window*, long, bool)
529
530
TabBar::~TabBar()
531
0
{
532
0
    disposeOnce();
533
0
}
534
535
void TabBar::dispose()
536
0
{
537
0
    EndEditMode( true );
538
0
    mpImpl.reset();
539
0
    Window::dispose();
540
0
}
541
542
const sal_uInt16 TabBar::APPEND         = ::std::numeric_limits<sal_uInt16>::max();
543
const sal_uInt16 TabBar::PAGE_NOT_FOUND = ::std::numeric_limits<sal_uInt16>::max();
544
545
void TabBar::ImplInit( WinBits nWinStyle, bool bSheets )
546
0
{
547
0
    mpImpl.reset(new TabBar_Impl);
548
549
0
    mnMaxPageWidth  = 0;
550
0
    mnCurMaxWidth   = 0;
551
0
    mnOffX          = 0;
552
0
    mnOffY          = 0;
553
0
    mnLastOffX      = 0;
554
0
    mnSplitSize     = 0;
555
0
    mnSwitchTime    = 0;
556
0
    mnWinStyle      = nWinStyle;
557
0
    mnCurPageId     = 0;
558
0
    mnFirstPos      = 0;
559
0
    mnDropPos       = 0;
560
0
    mnSwitchId      = 0;
561
0
    mnEditId        = 0;
562
0
    mbFormat        = true;
563
0
    mbFirstFormat   = true;
564
0
    mbSizeFormat    = true;
565
0
    mbAutoEditMode  = false;
566
0
    mbEditCanceled  = false;
567
0
    mbDropPos       = false;
568
0
    mbInSelect      = false;
569
0
    mbMirrored      = false;
570
0
    mbScrollAlwaysEnabled = false;
571
0
    mbSheets = bSheets;
572
573
0
    ImplInitControls();
574
575
0
    SetSizePixel( Size( 100, CalcWindowSizePixel().Height() ) );
576
0
    ImplInitSettings( true, true );
577
0
}
578
579
ImplTabBarItem* TabBar::seek( size_t i )
580
0
{
581
0
    if ( i < mpImpl->maItemList.size() )
582
0
    {
583
0
        maCurrentItemList = i;
584
0
        return &mpImpl->maItemList[maCurrentItemList];
585
0
    }
586
0
    return nullptr;
587
0
}
588
589
ImplTabBarItem* TabBar::prev()
590
0
{
591
0
    if ( maCurrentItemList > 0 )
592
0
    {
593
0
        return &mpImpl->maItemList[--maCurrentItemList];
594
0
    }
595
0
    return nullptr;
596
0
}
597
598
ImplTabBarItem* TabBar::next()
599
0
{
600
0
    if ( maCurrentItemList + 1 < mpImpl->maItemList.size() )
601
0
    {
602
0
        return &mpImpl->maItemList[++maCurrentItemList];
603
0
    }
604
0
    return nullptr;
605
0
}
606
607
void TabBar::ImplInitSettings( bool bFont, bool bBackground )
608
0
{
609
    // FIXME RenderContext
610
611
0
    const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
612
613
0
    if (bFont)
614
0
    {
615
0
        vcl::Font aToolFont = rStyleSettings.GetToolFont();
616
0
        aToolFont.SetWeight( WEIGHT_BOLD );
617
0
        ApplyControlFont(*GetOutDev(), aToolFont);
618
619
        // Adapt font size if window too small?
620
0
        while (GetTextHeight() > (GetOutputSizePixel().Height() - 1))
621
0
        {
622
0
            vcl::Font aFont = GetFont();
623
0
            if (aFont.GetFontHeight() <= 6)
624
0
                break;
625
0
            aFont.SetFontHeight(aFont.GetFontHeight() - 1);
626
0
            SetFont(aFont);
627
0
        }
628
0
    }
629
630
0
    if (bBackground)
631
0
    {
632
0
        ApplyControlBackground(*GetOutDev(), rStyleSettings.GetFaceColor());
633
0
    }
634
0
}
635
636
void TabBar::ImplGetColors(const StyleSettings& rStyleSettings,
637
                           Color& rFaceColor, Color& rFaceTextColor,
638
                           Color& rSelectColor, Color& rSelectTextColor)
639
0
{
640
0
    if (IsControlBackground())
641
0
        rFaceColor = GetControlBackground();
642
0
    else
643
0
        rFaceColor = rStyleSettings.GetInactiveTabColor();
644
0
    if (IsControlForeground())
645
0
        rFaceTextColor = GetControlForeground();
646
0
    else
647
0
        rFaceTextColor = rStyleSettings.GetButtonTextColor();
648
0
    rSelectColor = rStyleSettings.GetActiveTabColor();
649
0
    rSelectTextColor = rStyleSettings.GetWindowTextColor();
650
0
}
651
652
bool TabBar::ImplCalcWidth()
653
0
{
654
    // Sizes should only be retrieved if the text or the font was changed
655
0
    if (!mbSizeFormat)
656
0
        return false;
657
658
    // retrieve width of tabs with bold font
659
0
    vcl::Font aFont = GetFont();
660
0
    if (aFont.GetWeightMaybeAskConfig() != WEIGHT_BOLD)
661
0
    {
662
0
        aFont.SetWeight(WEIGHT_BOLD);
663
0
        SetFont(aFont);
664
0
    }
665
666
0
    if (mnMaxPageWidth)
667
0
        mnCurMaxWidth = mnMaxPageWidth;
668
0
    else
669
0
    {
670
0
        mnCurMaxWidth = mnLastOffX - mnOffX;
671
0
        if (mnCurMaxWidth < 1)
672
0
            mnCurMaxWidth = 1;
673
0
    }
674
675
0
    bool bChanged = false;
676
0
    for (auto& rItem : mpImpl->maItemList)
677
0
    {
678
0
        tools::Long nNewWidth = GetTextWidth(rItem.GetRenderText());
679
0
        if (mnCurMaxWidth && (nNewWidth > mnCurMaxWidth))
680
0
        {
681
0
            rItem.mbShort = true;
682
0
            nNewWidth = mnCurMaxWidth;
683
0
        }
684
0
        else
685
0
        {
686
0
            rItem.mbShort = false;
687
0
        }
688
689
        // Padding is dependent on font height - bigger font = bigger padding
690
0
        tools::Long nFontWidth = aFont.GetFontHeight();
691
0
        if (rItem.mbProtect)
692
0
            nNewWidth += 24;
693
0
        nNewWidth += nFontWidth * 2;
694
695
0
        if (rItem.mnWidth != nNewWidth)
696
0
        {
697
0
            rItem.mnWidth = nNewWidth;
698
0
            if (!rItem.maRect.IsEmpty())
699
0
                bChanged = true;
700
0
        }
701
0
    }
702
0
    mbSizeFormat = false;
703
0
    mbFormat = true;
704
0
    return bChanged;
705
0
}
706
707
void TabBar::ImplFormat()
708
0
{
709
0
    ImplCalcWidth();
710
711
0
    if (!mbFormat)
712
0
        return;
713
714
0
    sal_uInt16 nItemIndex = 0;
715
0
    tools::Long x = mnOffX;
716
0
    for (auto & rItem : mpImpl->maItemList)
717
0
    {
718
        // At all non-visible tabs an empty rectangle is set
719
0
        if ((nItemIndex + 1 < mnFirstPos) || (x > mnLastOffX))
720
0
            rItem.maRect.SetEmpty();
721
0
        else
722
0
        {
723
            // Slightly before the tab before the first visible page
724
            // should also be visible
725
0
            if (nItemIndex + 1 == mnFirstPos)
726
0
            {
727
0
                rItem.maRect.SetLeft(x - rItem.mnWidth);
728
0
            }
729
0
            else
730
0
            {
731
0
                rItem.maRect.SetLeft(x);
732
0
                x += rItem.mnWidth;
733
0
            }
734
0
            rItem.maRect.SetRight(x);
735
0
            rItem.maRect.SetBottom(maWinSize.Height() - 1);
736
737
0
            if (mbMirrored)
738
0
            {
739
0
                tools::Long nNewLeft  = mnOffX + mnLastOffX - rItem.maRect.Right();
740
0
                tools::Long nNewRight = mnOffX + mnLastOffX - rItem.maRect.Left();
741
0
                rItem.maRect.SetRight(nNewRight);
742
0
                rItem.maRect.SetLeft(nNewLeft);
743
0
            }
744
0
        }
745
746
0
        nItemIndex++;
747
0
    }
748
749
0
    mbFormat = false;
750
751
    //  enable/disable button
752
0
    ImplEnableControls();
753
0
}
754
755
sal_uInt16 TabBar::ImplGetLastFirstPos()
756
0
{
757
0
    sal_uInt16 nCount = mpImpl->getItemSize();
758
0
    if (!nCount || mbSizeFormat || mbFormat)
759
0
        return 0;
760
761
0
    sal_uInt16  nLastFirstPos = nCount - 1;
762
0
    tools::Long nWinWidth = mnLastOffX - mnOffX - ADDNEWPAGE_AREAWIDTH;
763
0
    tools::Long nWidth = mpImpl->maItemList[nLastFirstPos].mnWidth;
764
765
0
    while (nLastFirstPos && (nWidth < nWinWidth))
766
0
    {
767
0
        nLastFirstPos--;
768
0
        nWidth += mpImpl->maItemList[nLastFirstPos].mnWidth;
769
0
    }
770
0
    if ((nLastFirstPos != static_cast<sal_uInt16>(mpImpl->maItemList.size() - 1)) && (nWidth > nWinWidth))
771
0
        nLastFirstPos++;
772
0
    return nLastFirstPos;
773
0
}
774
775
IMPL_LINK(TabBar, ContextMenuHdl, const CommandEvent&, rCommandEvent, void)
776
0
{
777
0
    maScrollAreaContextHdl.Call(rCommandEvent);
778
0
}
779
780
IMPL_LINK(TabBar, MousePressHdl, const MouseEvent&, rMouseEvent, bool)
781
0
{
782
0
    if (rMouseEvent.IsRight())
783
0
        ContextMenuHdl(CommandEvent(rMouseEvent.GetPosPixel(), CommandEventId::ContextMenu, true));
784
0
    return false;
785
0
}
786
787
void TabBar::ImplInitControls()
788
0
{
789
0
    if (mnWinStyle & WB_SIZEABLE)
790
0
    {
791
0
        if (!mpImpl->mpSizer)
792
0
        {
793
0
            mpImpl->mpSizer.disposeAndReset(VclPtr<ImplTabSizer>::Create( this, mnWinStyle & (WB_DRAG | WB_3DLOOK)));
794
0
        }
795
0
        mpImpl->mpSizer->Show();
796
0
    }
797
0
    else
798
0
    {
799
0
        mpImpl->mpSizer.disposeAndClear();
800
0
    }
801
802
0
    mpImpl->mxButtonBox.disposeAndReset(VclPtr<TabButtons>::Create(this, mbSheets));
803
804
0
    Link<const CommandEvent&, void> aContextLink = LINK( this, TabBar, ContextMenuHdl );
805
806
0
    if (mnWinStyle & WB_INSERTTAB)
807
0
    {
808
0
        Link<weld::Button&,void> aLink = LINK(this, TabBar, ImplAddClickHandler);
809
0
        mpImpl->mxButtonBox->m_xAddRepeater = std::make_shared<weld::ButtonPressRepeater>(
810
0
                    *mpImpl->mxButtonBox->m_xAddButton, aLink, aContextLink);
811
0
        mpImpl->mxButtonBox->m_xAddButton->show();
812
0
    }
813
814
0
    Link<weld::Button&,void> aLink = LINK( this, TabBar, ImplClickHdl );
815
816
0
    if (mnWinStyle & (WB_MINSCROLL | WB_SCROLL))
817
0
    {
818
0
        mpImpl->mxButtonBox->m_xPrevRepeater = std::make_shared<weld::ButtonPressRepeater>(
819
0
                    *mpImpl->mxButtonBox->m_xPrevButton, aLink, aContextLink);
820
0
        mpImpl->mxButtonBox->m_xPrevButton->show();
821
0
        mpImpl->mxButtonBox->m_xNextRepeater = std::make_shared<weld::ButtonPressRepeater>(
822
0
                    *mpImpl->mxButtonBox->m_xNextButton, aLink, aContextLink);
823
0
        mpImpl->mxButtonBox->m_xNextButton->show();
824
0
    }
825
826
0
    if (mnWinStyle & WB_SCROLL)
827
0
    {
828
0
        Link<const MouseEvent&, bool> aBtnContextLink = LINK(this, TabBar, MousePressHdl);
829
830
0
        mpImpl->mxButtonBox->m_xFirstButton->connect_clicked(aLink);
831
0
        mpImpl->mxButtonBox->m_xFirstButton->connect_mouse_press(aBtnContextLink);
832
0
        mpImpl->mxButtonBox->m_xFirstButton->show();
833
0
        mpImpl->mxButtonBox->m_xLastButton->connect_clicked(aLink);
834
0
        mpImpl->mxButtonBox->m_xLastButton->connect_mouse_press(aBtnContextLink);
835
0
        mpImpl->mxButtonBox->m_xLastButton->show();
836
0
    }
837
838
0
    mpImpl->mxButtonBox->Show();
839
0
}
840
841
void TabBar::ImplEnableControls()
842
0
{
843
0
    if (mbSizeFormat || mbFormat)
844
0
        return;
845
846
    // enable/disable buttons
847
0
    bool bEnableBtn = mbScrollAlwaysEnabled || mnFirstPos > 0;
848
0
    mpImpl->mxButtonBox->m_xFirstButton->set_sensitive(bEnableBtn);
849
0
    mpImpl->mxButtonBox->m_xPrevButton->set_sensitive(bEnableBtn);
850
0
    if (!bEnableBtn && mpImpl->mxButtonBox->m_xPrevRepeater)
851
0
        mpImpl->mxButtonBox->m_xPrevRepeater->Stop();
852
0
    bEnableBtn = mbScrollAlwaysEnabled || mnFirstPos < ImplGetLastFirstPos();
853
0
    mpImpl->mxButtonBox->m_xLastButton->set_sensitive(bEnableBtn);
854
0
    mpImpl->mxButtonBox->m_xNextButton->set_sensitive(bEnableBtn);
855
0
    if (!bEnableBtn && mpImpl->mxButtonBox->m_xNextRepeater)
856
0
        mpImpl->mxButtonBox->m_xNextRepeater->Stop();
857
0
}
858
859
void TabBar::SetScrollAlwaysEnabled(bool bScrollAlwaysEnabled)
860
0
{
861
0
    mbScrollAlwaysEnabled = bScrollAlwaysEnabled;
862
0
    ImplEnableControls();
863
0
}
864
865
void TabBar::ImplShowPage( sal_uInt16 nPos )
866
0
{
867
0
    if (nPos >= mpImpl->getItemSize())
868
0
        return;
869
870
    // calculate width
871
0
    tools::Long nWidth = GetOutputSizePixel().Width();
872
873
0
    auto& rItem = mpImpl->maItemList[nPos];
874
0
    if (nPos < mnFirstPos)
875
0
        SetFirstPageId( rItem.mnId );
876
0
    else if (rItem.maRect.Right() > nWidth)
877
0
    {
878
0
        while (rItem.maRect.Right() > nWidth)
879
0
        {
880
0
            sal_uInt16 nNewPos = mnFirstPos + 1;
881
0
            SetFirstPageId(GetPageId(nNewPos));
882
0
            ImplFormat();
883
0
            if (nNewPos != mnFirstPos)
884
0
                break;
885
0
        }
886
0
    }
887
0
}
888
889
IMPL_LINK( TabBar, ImplClickHdl, weld::Button&, rBtn, void )
890
0
{
891
0
    if (&rBtn != mpImpl->mxButtonBox->m_xFirstButton.get() && &rBtn != mpImpl->mxButtonBox->m_xLastButton.get())
892
0
    {
893
0
        if ((GetPointerState().mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0)
894
0
        {
895
            // like tdf#149482 if we didn't see a mouse up, but find that the mouse is no
896
            // longer pressed at this point, then bail
897
0
            mpImpl->mxButtonBox->m_xPrevRepeater->Stop();
898
0
            mpImpl->mxButtonBox->m_xNextRepeater->Stop();
899
0
            return;
900
0
        }
901
0
    }
902
903
0
    EndEditMode();
904
905
0
    sal_uInt16 nNewPos = mnFirstPos;
906
907
0
    if (&rBtn == mpImpl->mxButtonBox->m_xFirstButton.get() || (&rBtn == mpImpl->mxButtonBox->m_xPrevButton.get() &&
908
0
                                                               mpImpl->mxButtonBox->m_xPrevRepeater->IsModKeyPressed()))
909
0
    {
910
0
        nNewPos = 0;
911
0
    }
912
0
    else if (&rBtn == mpImpl->mxButtonBox->m_xLastButton.get() || (&rBtn == mpImpl->mxButtonBox->m_xNextButton.get() &&
913
0
                                                                   mpImpl->mxButtonBox->m_xNextRepeater->IsModKeyPressed()))
914
0
    {
915
0
        sal_uInt16 nCount = GetPageCount();
916
0
        if (nCount)
917
0
            nNewPos = nCount - 1;
918
0
    }
919
0
    else if (&rBtn == mpImpl->mxButtonBox->m_xPrevButton.get())
920
0
    {
921
0
        if (mnFirstPos)
922
0
            nNewPos = mnFirstPos - 1;
923
0
    }
924
0
    else if (&rBtn == mpImpl->mxButtonBox->m_xNextButton.get())
925
0
    {
926
0
        sal_uInt16 nCount = GetPageCount();
927
0
        if (mnFirstPos <  nCount)
928
0
            nNewPos = mnFirstPos+1;
929
0
    }
930
0
    else
931
0
    {
932
0
        return;
933
0
    }
934
935
0
    if (nNewPos != mnFirstPos)
936
0
        SetFirstPageId(GetPageId(nNewPos));
937
0
}
938
939
IMPL_LINK_NOARG(TabBar, ImplAddClickHandler, weld::Button&, void)
940
0
{
941
0
    if ((GetPointerState().mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0)
942
0
    {
943
        // tdf#149482 if we didn't see a mouse up, but find that the mouse is no
944
        // longer pressed at this point, then bail
945
0
        mpImpl->mxButtonBox->m_xAddRepeater->Stop();
946
0
        return;
947
0
    }
948
949
0
    EndEditMode();
950
0
    AddTabClick();
951
0
}
952
953
void TabBar::MouseMove(const MouseEvent& rMEvt)
954
0
{
955
0
    if (rMEvt.IsLeaveWindow())
956
0
        mbInSelect = false;
957
958
0
    Window::MouseMove(rMEvt);
959
0
}
960
961
void TabBar::MouseButtonDown(const MouseEvent& rMEvt)
962
0
{
963
    // Only terminate EditMode and do not execute click
964
    // if clicked inside our window,
965
0
    if (IsInEditMode())
966
0
    {
967
0
        EndEditMode();
968
0
        return;
969
0
    }
970
971
0
    sal_uInt16 nSelId = GetPageId(rMEvt.GetPosPixel());
972
973
0
    if (!rMEvt.IsLeft())
974
0
    {
975
0
        Window::MouseButtonDown(rMEvt);
976
0
        if (nSelId > 0 && nSelId != mnCurPageId)
977
0
        {
978
0
            if (ImplDeactivatePage())
979
0
            {
980
0
                SetCurPageId(nSelId);
981
0
                PaintImmediately();
982
0
                ImplActivatePage();
983
0
                ImplSelect();
984
0
            }
985
0
            mbInSelect = true;
986
0
        }
987
0
        return;
988
0
    }
989
990
0
    if (rMEvt.IsMod2() && mbAutoEditMode && nSelId)
991
0
    {
992
0
        if (StartEditMode(nSelId))
993
0
            return;
994
0
    }
995
996
0
    if ((rMEvt.GetMode() & (MouseEventModifiers::MULTISELECT | MouseEventModifiers::RANGESELECT)) && (rMEvt.GetClicks() == 1))
997
0
    {
998
0
        if (nSelId)
999
0
        {
1000
0
            sal_uInt16  nPos = GetPagePos(nSelId);
1001
1002
0
            bool bSelectTab = false;
1003
1004
0
            if ((rMEvt.GetMode() & MouseEventModifiers::MULTISELECT) && (mnWinStyle & WB_MULTISELECT))
1005
0
            {
1006
0
                if (nSelId != mnCurPageId)
1007
0
                {
1008
0
                    SelectPage(nSelId, !IsPageSelected(nSelId));
1009
0
                    bSelectTab = true;
1010
0
                }
1011
0
            }
1012
0
            else if (mnWinStyle & (WB_MULTISELECT | WB_RANGESELECT))
1013
0
            {
1014
0
                bSelectTab = true;
1015
0
                sal_uInt16 n;
1016
0
                bool bSelect;
1017
0
                sal_uInt16 nCurPos = GetPagePos(mnCurPageId);
1018
0
                if (nPos <= nCurPos)
1019
0
                {
1020
                    // Deselect all tabs till the clicked tab
1021
                    // and select all tabs from the clicked tab
1022
                    // 'till the actual position
1023
0
                    n = 0;
1024
0
                    while (n < nCurPos)
1025
0
                    {
1026
0
                        auto& rItem = mpImpl->maItemList[n];
1027
0
                        bSelect = n >= nPos;
1028
1029
0
                        if (rItem.mbSelect != bSelect)
1030
0
                        {
1031
0
                            rItem.mbSelect = bSelect;
1032
0
                            if (!rItem.maRect.IsEmpty())
1033
0
                                Invalidate(rItem.maRect);
1034
0
                        }
1035
1036
0
                        n++;
1037
0
                    }
1038
0
                }
1039
1040
0
                if (nPos >= nCurPos)
1041
0
                {
1042
                    // Select all tabs from the actual position till the clicked tab
1043
                    // and deselect all tabs from the actual position
1044
                    // till the last tab
1045
0
                    sal_uInt16 nCount = mpImpl->getItemSize();
1046
0
                    n = nCurPos;
1047
0
                    while (n < nCount)
1048
0
                    {
1049
0
                        auto& rItem = mpImpl->maItemList[n];
1050
1051
0
                        bSelect = n <= nPos;
1052
1053
0
                        if (rItem.mbSelect != bSelect)
1054
0
                        {
1055
0
                            rItem.mbSelect = bSelect;
1056
0
                            if (!rItem.maRect.IsEmpty())
1057
0
                                Invalidate(rItem.maRect);
1058
0
                        }
1059
1060
0
                        n++;
1061
0
                    }
1062
0
                }
1063
0
            }
1064
1065
            // scroll the selected tab if required
1066
0
            if (bSelectTab)
1067
0
            {
1068
0
                ImplShowPage(nPos);
1069
0
                PaintImmediately();
1070
0
                ImplSelect();
1071
0
            }
1072
1073
0
            mbInSelect = true;
1074
1075
0
            return;
1076
0
        }
1077
0
    }
1078
0
    else if (rMEvt.GetClicks() == 2)
1079
0
    {
1080
        // call double-click-handler if required
1081
0
        if (!rMEvt.GetModifier() && (!nSelId || (nSelId == mnCurPageId)))
1082
0
        {
1083
0
            sal_uInt16 nOldCurId = mnCurPageId;
1084
0
            mnCurPageId = nSelId;
1085
0
            DoubleClick();
1086
            // check, as actual page could be switched inside
1087
            // the doubleclick-handler
1088
0
            if (mnCurPageId == nSelId)
1089
0
                mnCurPageId = nOldCurId;
1090
0
        }
1091
1092
0
        return;
1093
0
    }
1094
0
    else
1095
0
    {
1096
0
        if (nSelId)
1097
0
        {
1098
            // execute Select if not actual page
1099
0
            if (nSelId != mnCurPageId)
1100
0
            {
1101
0
                sal_uInt16 nPos = GetPagePos(nSelId);
1102
0
                auto& rItem = mpImpl->maItemList[nPos];
1103
1104
0
                if (!rItem.mbSelect)
1105
0
                {
1106
                    // make not valid
1107
0
                    bool bUpdate = false;
1108
0
                    if (IsReallyVisible() && IsUpdateMode())
1109
0
                        bUpdate = true;
1110
1111
                    // deselect all selected items
1112
0
                    for (auto& xItem : mpImpl->maItemList)
1113
0
                    {
1114
0
                        if (xItem.mbSelect || (xItem.mnId == mnCurPageId))
1115
0
                        {
1116
0
                            xItem.mbSelect = false;
1117
0
                            if (bUpdate)
1118
0
                                Invalidate(xItem.maRect);
1119
0
                        }
1120
0
                    }
1121
0
                }
1122
1123
0
                if (ImplDeactivatePage())
1124
0
                {
1125
0
                    SetCurPageId(nSelId);
1126
0
                    PaintImmediately();
1127
0
                    ImplActivatePage();
1128
0
                    ImplSelect();
1129
0
                }
1130
1131
0
                mbInSelect = true;
1132
0
            }
1133
1134
0
            return;
1135
0
        }
1136
0
    }
1137
1138
0
    Window::MouseButtonDown(rMEvt);
1139
0
}
1140
1141
void TabBar::MouseButtonUp(const MouseEvent& rMEvt)
1142
0
{
1143
0
    mbInSelect = false;
1144
0
    Window::MouseButtonUp(rMEvt);
1145
0
}
1146
1147
void TabBar::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rect)
1148
0
{
1149
0
    if (rRenderContext.IsNativeControlSupported(ControlType::WindowBackground,ControlPart::Entire))
1150
0
    {
1151
0
        rRenderContext.DrawNativeControl(ControlType::WindowBackground,ControlPart::Entire,rect,
1152
0
                                         ControlState::ENABLED,ImplControlValue(0),OUString());
1153
0
    }
1154
    // calculate items and emit
1155
0
    sal_uInt16 nItemCount = mpImpl->getItemSize();
1156
0
    if (!nItemCount)
1157
0
        return;
1158
1159
0
    ImplPrePaint();
1160
1161
0
    Color aFaceColor, aSelectColor, aFaceTextColor, aSelectTextColor;
1162
0
    const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
1163
0
    ImplGetColors(rStyleSettings, aFaceColor, aFaceTextColor, aSelectColor, aSelectTextColor);
1164
1165
0
    auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::FONT | vcl::PushFlags::CLIPREGION);
1166
0
    rRenderContext.SetClipRegion(vcl::Region(GetPageArea()));
1167
1168
    // select font
1169
0
    vcl::Font aFont = rRenderContext.GetFont();
1170
0
    vcl::Font aLightFont = aFont;
1171
0
    aLightFont.SetWeight(WEIGHT_NORMAL);
1172
1173
0
    TabDrawer aDrawer(rRenderContext);
1174
1175
0
    aDrawer.setSelectedFillColor(aSelectColor);
1176
1177
    // Now, start drawing the tabs.
1178
1179
0
    ImplTabBarItem* pItem = ImplGetLastTabBarItem(nItemCount);
1180
0
    ImplTabBarItem* pCurItem = nullptr;
1181
0
    while (pItem)
1182
0
    {
1183
        // emit CurrentItem last, as it covers all others
1184
0
        if (!pCurItem && (pItem->mnId == mnCurPageId))
1185
0
        {
1186
0
            pCurItem = pItem;
1187
0
            pItem = prev();
1188
0
            if (!pItem)
1189
0
                pItem = pCurItem;
1190
0
            continue;
1191
0
        }
1192
1193
0
        bool bCurrent = pItem == pCurItem;
1194
1195
0
        if (!pItem->maRect.IsEmpty())
1196
0
        {
1197
0
            tools::Rectangle aRect = pItem->maRect;
1198
0
            bool bSelected = pItem->IsSelected(pCurItem);
1199
            // We disable custom background color in high contrast mode.
1200
0
            bool bCustomBgColor = !pItem->IsDefaultTabBgColor() && !rStyleSettings.GetHighContrastMode();
1201
0
            OUString aText = pItem->mbShort ?
1202
0
                rRenderContext.GetEllipsisString(pItem->GetRenderText(), mnCurMaxWidth) :
1203
0
                pItem->GetRenderText();
1204
1205
0
            aDrawer.setRect(aRect);
1206
0
            aDrawer.setSelected(bSelected);
1207
0
            aDrawer.setCustomColored(bCustomBgColor);
1208
0
            aDrawer.setEnabled(true);
1209
0
            aDrawer.setCustomColor(pItem->maTabBgColor);
1210
0
            aDrawer.mbProtect = pItem->mbProtect;
1211
0
            aDrawer.drawTab();
1212
1213
            // currently visible sheet is drawn using a bold font
1214
0
            if (bCurrent)
1215
0
                rRenderContext.SetFont(aFont);
1216
0
            else
1217
0
                rRenderContext.SetFont(aLightFont);
1218
1219
            // Set the correct FillInBrush depending on status
1220
1221
0
            if (bSelected)
1222
0
                rRenderContext.SetTextColor(aSelectTextColor);
1223
0
            else if (bCustomBgColor)
1224
0
                rRenderContext.SetTextColor(pItem->maTabTextColor);
1225
0
            else
1226
0
                rRenderContext.SetTextColor(aFaceTextColor);
1227
1228
            // Special display of tab name depending on page bits
1229
1230
0
            if (pItem->mnBits & TabBarPageBits::Blue)
1231
0
            {
1232
0
                rRenderContext.SetTextColor(COL_LIGHTBLUE);
1233
0
            }
1234
0
            if (pItem->mnBits & TabBarPageBits::Italic)
1235
0
            {
1236
0
                vcl::Font aSpecialFont = rRenderContext.GetFont();
1237
0
                aSpecialFont.SetItalic(FontItalic::ITALIC_NORMAL);
1238
0
                rRenderContext.SetFont(aSpecialFont);
1239
0
            }
1240
0
            if (pItem->mnBits & TabBarPageBits::Underline)
1241
0
            {
1242
0
                vcl::Font aSpecialFont = rRenderContext.GetFont();
1243
0
                aSpecialFont.SetUnderline(LINESTYLE_SINGLE);
1244
0
                rRenderContext.SetFont(aSpecialFont);
1245
0
            }
1246
1247
0
            aDrawer.drawText(aText);
1248
1249
0
            if (bCurrent)
1250
0
            {
1251
0
                rRenderContext.SetLineColor();
1252
0
                rRenderContext.SetFillColor(aSelectColor);
1253
0
                aDrawer.drawOverTopBorder();
1254
0
                break;
1255
0
            }
1256
1257
0
            pItem = prev();
1258
0
        }
1259
0
        else
1260
0
        {
1261
0
            if (bCurrent)
1262
0
                break;
1263
1264
0
            pItem = nullptr;
1265
0
        }
1266
1267
0
        if (!pItem)
1268
0
            pItem = pCurItem;
1269
0
    }
1270
0
}
1271
1272
void TabBar::Resize()
1273
0
{
1274
0
    Size aNewSize = GetOutputSizePixel();
1275
1276
0
    tools::Long nSizerWidth = 0;
1277
1278
    // order the Sizer
1279
0
    if ( mpImpl->mpSizer )
1280
0
    {
1281
0
        Size    aSizerSize = mpImpl->mpSizer->GetSizePixel();
1282
0
        Point   aNewSizerPos( mbMirrored ? 0 : (aNewSize.Width()-aSizerSize.Width()), 0 );
1283
0
        Size    aNewSizerSize( aSizerSize.Width(), aNewSize.Height() );
1284
0
        mpImpl->mpSizer->SetPosSizePixel( aNewSizerPos, aNewSizerSize );
1285
0
        nSizerWidth = aSizerSize.Width();
1286
0
    }
1287
1288
    // order the scroll buttons
1289
0
    tools::Long const nHeight = aNewSize.Height();
1290
    // adapt font height?
1291
0
    ImplInitSettings( true, false );
1292
1293
0
    mpImpl->mxButtonBox->AdaptToHeight(nHeight);
1294
0
    Size const aBtnsSize(mpImpl->mxButtonBox->get_preferred_size().Width(), nHeight);
1295
0
    Point aPos(mbMirrored ? (aNewSize.Width() - aBtnsSize.Width()) : 0, 0);
1296
0
    mpImpl->mxButtonBox->SetPosSizePixel(aPos, aBtnsSize);
1297
0
    auto nButtonWidth = aBtnsSize.Width();
1298
1299
    // store size
1300
0
    maWinSize = aNewSize;
1301
1302
0
    if( mbMirrored )
1303
0
    {
1304
0
        mnOffX = nSizerWidth;
1305
0
        mnLastOffX = maWinSize.Width() - nButtonWidth - 1;
1306
0
    }
1307
0
    else
1308
0
    {
1309
0
        mnOffX = nButtonWidth;
1310
0
        mnLastOffX = maWinSize.Width() - nSizerWidth - 1;
1311
0
    }
1312
1313
    // reformat
1314
0
    mbSizeFormat = true;
1315
0
    if ( IsReallyVisible() )
1316
0
    {
1317
0
        if ( ImplCalcWidth() )
1318
0
            Invalidate();
1319
1320
0
        ImplFormat();
1321
1322
        // Ensure as many tabs as possible are visible:
1323
0
        sal_uInt16 nLastFirstPos = ImplGetLastFirstPos();
1324
0
        if ( mnFirstPos > nLastFirstPos )
1325
0
        {
1326
0
            mnFirstPos = nLastFirstPos;
1327
0
            mbFormat = true;
1328
0
            Invalidate();
1329
0
        }
1330
        // Ensure the currently selected page is visible
1331
0
        ImplShowPage(GetPagePos(mnCurPageId));
1332
1333
0
        ImplFormat();
1334
0
    }
1335
1336
    // enable/disable button
1337
0
    ImplEnableControls();
1338
0
}
1339
1340
bool TabBar::PreNotify(NotifyEvent& rNEvt)
1341
0
{
1342
0
    if (rNEvt.GetType() == NotifyEventType::COMMAND)
1343
0
    {
1344
0
        if (rNEvt.GetCommandEvent()->GetCommand() == CommandEventId::Wheel)
1345
0
        {
1346
0
            const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData();
1347
0
            sal_uInt16 nNewPos = mnFirstPos;
1348
0
            if (pData->GetNotchDelta() > 0)
1349
0
            {
1350
0
                if (mnFirstPos)
1351
0
                    nNewPos = mnFirstPos - 1;
1352
0
            }
1353
0
            else if (pData->GetNotchDelta() < 0)
1354
0
            {
1355
0
                sal_uInt16 nCount = GetPageCount();
1356
0
                if (mnFirstPos <  nCount)
1357
0
                    nNewPos = mnFirstPos + 1;
1358
0
            }
1359
0
            if (nNewPos != mnFirstPos)
1360
0
                SetFirstPageId(GetPageId(nNewPos));
1361
0
        }
1362
0
    }
1363
0
    return Window::PreNotify(rNEvt);
1364
0
}
1365
1366
void TabBar::RequestHelp(const HelpEvent& rHEvt)
1367
0
{
1368
0
    sal_uInt16 nItemId = GetPageId(ScreenToOutputPixel(rHEvt.GetMousePosPixel()));
1369
0
    if (nItemId)
1370
0
    {
1371
0
        if (rHEvt.GetMode() & HelpEventMode::BALLOON)
1372
0
        {
1373
0
            OUString aStr = GetHelpText(nItemId);
1374
0
            if (!aStr.isEmpty())
1375
0
            {
1376
0
                tools::Rectangle aItemRect = GetPageRect(nItemId);
1377
0
                Point aPt = OutputToScreenPixel(aItemRect.TopLeft());
1378
0
                aItemRect.SetLeft( aPt.X() );
1379
0
                aItemRect.SetTop( aPt.Y() );
1380
0
                aPt = OutputToScreenPixel(aItemRect.BottomRight());
1381
0
                aItemRect.SetRight( aPt.X() );
1382
0
                aItemRect.SetBottom( aPt.Y() );
1383
0
                Help::ShowBalloon(this, aItemRect.Center(), aItemRect, aStr);
1384
0
                return;
1385
0
            }
1386
0
        }
1387
1388
        // show text for quick- or balloon-help
1389
        // if this is isolated or not fully visible
1390
0
        if (rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON))
1391
0
        {
1392
0
            sal_uInt16 nPos = GetPagePos(nItemId);
1393
0
            auto& rItem = mpImpl->maItemList[nPos];
1394
0
            if (rItem.mbShort || (rItem.maRect.Right() - 5 > mnLastOffX))
1395
0
            {
1396
0
                tools::Rectangle aItemRect = GetPageRect(nItemId);
1397
0
                Point aPt = OutputToScreenPixel(aItemRect.TopLeft());
1398
0
                aItemRect.SetLeft( aPt.X() );
1399
0
                aItemRect.SetTop( aPt.Y() );
1400
0
                aPt = OutputToScreenPixel(aItemRect.BottomRight());
1401
0
                aItemRect.SetRight( aPt.X() );
1402
0
                aItemRect.SetBottom( aPt.Y() );
1403
0
                OUString aStr = mpImpl->maItemList[nPos].maText;
1404
0
                if (!aStr.isEmpty())
1405
0
                {
1406
0
                    if (rHEvt.GetMode() & HelpEventMode::BALLOON)
1407
0
                        Help::ShowBalloon(this, aItemRect.Center(), aItemRect, aStr);
1408
0
                    else
1409
0
                        Help::ShowQuickHelp(this, aItemRect, aStr);
1410
0
                    return;
1411
0
                }
1412
0
            }
1413
0
        }
1414
0
    }
1415
1416
0
    Window::RequestHelp(rHEvt);
1417
0
}
1418
1419
void TabBar::StateChanged(StateChangedType nType)
1420
0
{
1421
0
    Window::StateChanged(nType);
1422
1423
0
    if (nType == StateChangedType::InitShow)
1424
0
    {
1425
0
        if ( (mbSizeFormat || mbFormat) && !mpImpl->maItemList.empty() )
1426
0
            ImplFormat();
1427
0
    }
1428
0
    else if (nType == StateChangedType::Zoom ||
1429
0
             nType == StateChangedType::ControlFont)
1430
0
    {
1431
0
        ImplInitSettings(true, false);
1432
0
        Invalidate();
1433
0
    }
1434
0
    else if (nType == StateChangedType::ControlForeground)
1435
0
        Invalidate();
1436
0
    else if (nType == StateChangedType::ControlBackground)
1437
0
    {
1438
0
        ImplInitSettings(false, true);
1439
0
        Invalidate();
1440
0
    }
1441
0
    else if (nType == StateChangedType::Mirroring)
1442
0
    {
1443
0
        bool bIsRTLEnabled = IsRTLEnabled();
1444
        // reacts on calls of EnableRTL, have to mirror all child controls
1445
0
        if (mpImpl->mpSizer)
1446
0
            mpImpl->mpSizer->EnableRTL(bIsRTLEnabled);
1447
0
        if (mpImpl->mxButtonBox)
1448
0
        {
1449
0
            mpImpl->mxButtonBox->m_xFirstButton->set_direction(bIsRTLEnabled);
1450
0
            mpImpl->mxButtonBox->m_xPrevButton->set_direction(bIsRTLEnabled);
1451
0
            mpImpl->mxButtonBox->m_xNextButton->set_direction(bIsRTLEnabled);
1452
0
            mpImpl->mxButtonBox->m_xLastButton->set_direction(bIsRTLEnabled);
1453
0
            mpImpl->mxButtonBox->m_xAddButton->set_direction(bIsRTLEnabled);
1454
0
        }
1455
0
        if (mpImpl->mxEdit)
1456
0
        {
1457
0
            weld::Entry& rEntry = mpImpl->mxEdit->get_widget();
1458
0
            rEntry.set_direction(bIsRTLEnabled);
1459
0
        }
1460
0
    }
1461
0
}
1462
1463
void TabBar::DataChanged(const DataChangedEvent& rDCEvt)
1464
0
{
1465
0
    Window::DataChanged(rDCEvt);
1466
1467
0
    if (rDCEvt.GetType() == DataChangedEventType::FONTS
1468
0
        || rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION
1469
0
        || (rDCEvt.GetType() == DataChangedEventType::SETTINGS
1470
0
            && rDCEvt.GetFlags() & AllSettingsFlags::STYLE))
1471
0
    {
1472
0
        ImplInitSettings(true, true);
1473
0
        Invalidate();
1474
0
    }
1475
0
}
1476
1477
void TabBar::ImplSelect()
1478
0
{
1479
0
    Select();
1480
0
    CallEventListeners(VclEventId::TabbarPageSelected, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(mnCurPageId)));
1481
0
}
1482
1483
void TabBar::Select()
1484
0
{
1485
0
    maSelectHdl.Call(this);
1486
0
}
1487
1488
void TabBar::DoubleClick()
1489
0
{
1490
0
}
1491
1492
void TabBar::Split()
1493
0
{
1494
0
    maSplitHdl.Call(this);
1495
0
}
1496
1497
void TabBar::ImplActivatePage()
1498
0
{
1499
0
    ActivatePage();
1500
1501
0
    CallEventListeners(VclEventId::TabbarPageActivated, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(mnCurPageId)));
1502
0
}
1503
1504
void TabBar::ActivatePage()
1505
0
{}
1506
1507
bool TabBar::ImplDeactivatePage()
1508
0
{
1509
0
    bool bRet = DeactivatePage();
1510
1511
0
    CallEventListeners(VclEventId::TabbarPageDeactivated, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(mnCurPageId)));
1512
1513
0
    return bRet;
1514
0
}
1515
1516
void TabBar::ImplPrePaint()
1517
0
{
1518
0
    sal_uInt16 nItemCount = mpImpl->getItemSize();
1519
0
    if (!nItemCount)
1520
0
        return;
1521
1522
    // tabbar should be formatted
1523
0
    ImplFormat();
1524
1525
    // assure the actual tabpage becomes visible at first format
1526
0
    if (!mbFirstFormat)
1527
0
        return;
1528
1529
0
    mbFirstFormat = false;
1530
1531
0
    if (!mnCurPageId || (mnFirstPos != 0) || mbDropPos)
1532
0
        return;
1533
1534
0
    auto& rItem = mpImpl->maItemList[GetPagePos(mnCurPageId)];
1535
0
    if (rItem.maRect.IsEmpty())
1536
0
    {
1537
        // set mbDropPos (or misuse) to prevent Invalidate()
1538
0
        mbDropPos = true;
1539
0
        SetFirstPageId(mnCurPageId);
1540
0
        mbDropPos = false;
1541
0
        if (mnFirstPos != 0)
1542
0
            ImplFormat();
1543
0
    }
1544
0
}
1545
1546
ImplTabBarItem* TabBar::ImplGetLastTabBarItem( sal_uInt16 nItemCount )
1547
0
{
1548
    // find last visible entry
1549
0
    sal_uInt16 n = mnFirstPos + 1;
1550
0
    if (n >= nItemCount)
1551
0
        n = nItemCount-1;
1552
0
    ImplTabBarItem* pItem = seek(n);
1553
0
    while (pItem)
1554
0
    {
1555
0
        if (!pItem->maRect.IsEmpty())
1556
0
        {
1557
0
            n++;
1558
0
            pItem = next();
1559
0
        }
1560
0
        else
1561
0
            break;
1562
0
    }
1563
1564
    // draw all tabs (from back to front and actual last)
1565
0
    if (pItem)
1566
0
        n--;
1567
0
    else if (n >= nItemCount)
1568
0
        n = nItemCount-1;
1569
0
    pItem = seek(n);
1570
0
    return pItem;
1571
0
}
1572
1573
bool TabBar::DeactivatePage()
1574
0
{
1575
0
    return true;
1576
0
}
1577
1578
bool TabBar::StartRenaming()
1579
0
{
1580
0
    return true;
1581
0
}
1582
1583
TabBarAllowRenamingReturnCode TabBar::AllowRenaming()
1584
0
{
1585
0
    return TABBAR_RENAMING_YES;
1586
0
}
1587
1588
void TabBar::EndRenaming()
1589
0
{
1590
0
}
1591
1592
void TabBar::Mirror()
1593
0
{
1594
1595
0
}
1596
1597
void TabBar::AddTabClick()
1598
0
{
1599
1600
0
}
1601
1602
void TabBar::InsertPage(sal_uInt16 nPageId, const OUString& rText,
1603
                        TabBarPageBits nBits, sal_uInt16 nPos)
1604
0
{
1605
0
    assert (nPageId && "TabBar::InsertPage(): PageId must not be 0");
1606
0
    assert ((GetPagePos(nPageId) == PAGE_NOT_FOUND) && "TabBar::InsertPage(): Page already exists");
1607
0
    assert ((nBits <= TPB_DISPLAY_NAME_ALLFLAGS) && "TabBar::InsertPage(): Invalid flag set in nBits");
1608
1609
    // create PageItem and insert in the item list
1610
0
    ImplTabBarItem aItem( nPageId, rText, nBits );
1611
0
    if (nPos < mpImpl->maItemList.size())
1612
0
    {
1613
0
        auto it = mpImpl->maItemList.begin();
1614
0
        it += nPos;
1615
0
        mpImpl->maItemList.insert(it, aItem);
1616
0
    }
1617
0
    else
1618
0
    {
1619
0
        mpImpl->maItemList.push_back(aItem);
1620
0
    }
1621
0
    mbSizeFormat = true;
1622
1623
    // set CurPageId if required
1624
0
    if (!mnCurPageId)
1625
0
        mnCurPageId = nPageId;
1626
1627
    // redraw bar
1628
0
    if (IsReallyVisible() && IsUpdateMode())
1629
0
        Invalidate();
1630
1631
0
    CallEventListeners(VclEventId::TabbarPageInserted, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)));
1632
0
}
1633
1634
Color TabBar::GetTabBgColor(sal_uInt16 nPageId) const
1635
0
{
1636
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1637
1638
0
    if (nPos != PAGE_NOT_FOUND)
1639
0
        return mpImpl->maItemList[nPos].maTabBgColor;
1640
0
    else
1641
0
        return COL_AUTO;
1642
0
}
1643
1644
void TabBar::SetTabBgColor(sal_uInt16 nPageId, const Color& aTabBgColor)
1645
0
{
1646
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1647
0
    if (nPos == PAGE_NOT_FOUND)
1648
0
        return;
1649
1650
0
    auto& rItem = mpImpl->maItemList[nPos];
1651
0
    if (aTabBgColor != COL_AUTO)
1652
0
    {
1653
0
        rItem.maTabBgColor = aTabBgColor;
1654
0
        if (aTabBgColor.GetLuminance() <= 128) //Do not use aTabBgColor.IsDark(), because that threshold is way too low...
1655
0
            rItem.maTabTextColor = COL_WHITE;
1656
0
        else
1657
0
            rItem.maTabTextColor = COL_BLACK;
1658
0
    }
1659
0
    else
1660
0
    {
1661
0
        rItem.maTabBgColor = COL_AUTO;
1662
0
        rItem.maTabTextColor = COL_AUTO;
1663
0
    }
1664
0
}
1665
1666
void TabBar::RemovePage(sal_uInt16 nPageId)
1667
0
{
1668
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1669
1670
    // does item exist
1671
0
    if (nPos == PAGE_NOT_FOUND)
1672
0
        return;
1673
1674
0
    if (mnCurPageId == nPageId)
1675
0
        mnCurPageId = 0;
1676
1677
    // check if first visible page should be moved
1678
0
    if (mnFirstPos > nPos)
1679
0
        mnFirstPos--;
1680
1681
    // delete item data
1682
0
    auto it = mpImpl->maItemList.begin();
1683
0
    it += nPos;
1684
0
    mpImpl->maItemList.erase(it);
1685
1686
    // redraw bar
1687
0
    if (IsReallyVisible() && IsUpdateMode())
1688
0
        Invalidate();
1689
1690
0
    CallEventListeners(VclEventId::TabbarPageRemoved, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)));
1691
0
}
1692
1693
void TabBar::MovePage(sal_uInt16 nPageId, sal_uInt16 nNewPos)
1694
0
{
1695
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1696
0
    Pair aPair(nPos, nNewPos);
1697
1698
0
    if (nPos < nNewPos)
1699
0
        nNewPos--;
1700
1701
0
    if (nPos == nNewPos)
1702
0
        return;
1703
1704
    // does item exit
1705
0
    if (nPos == PAGE_NOT_FOUND)
1706
0
        return;
1707
1708
    // move tabbar item in the list
1709
0
    auto it = mpImpl->maItemList.begin();
1710
0
    it += nPos;
1711
0
    ImplTabBarItem aItem = std::move(*it);
1712
0
    mpImpl->maItemList.erase(it);
1713
0
    if (nNewPos < mpImpl->maItemList.size())
1714
0
    {
1715
0
        it = mpImpl->maItemList.begin();
1716
0
        it += nNewPos;
1717
0
        mpImpl->maItemList.insert(it, aItem);
1718
0
    }
1719
0
    else
1720
0
    {
1721
0
        mpImpl->maItemList.push_back(aItem);
1722
0
    }
1723
1724
    // redraw bar
1725
0
    if (IsReallyVisible() && IsUpdateMode())
1726
0
        Invalidate();
1727
1728
0
    CallEventListeners( VclEventId::TabbarPageMoved, static_cast<void*>(&aPair) );
1729
0
}
1730
1731
void TabBar::Clear()
1732
0
{
1733
    // delete all items
1734
0
    mpImpl->maItemList.clear();
1735
1736
    // remove items from the list
1737
0
    mbSizeFormat = true;
1738
0
    mnCurPageId = 0;
1739
0
    mnFirstPos = 0;
1740
0
    maCurrentItemList = 0;
1741
1742
    // redraw bar
1743
0
    if (IsReallyVisible() && IsUpdateMode())
1744
0
        Invalidate();
1745
1746
0
    CallEventListeners(VclEventId::TabbarPageRemoved, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(PAGE_NOT_FOUND)));
1747
0
}
1748
1749
bool TabBar::IsPageEnabled(sal_uInt16 nPageId) const
1750
0
{
1751
0
    if (isDisposed())
1752
0
        return false;
1753
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1754
1755
0
    return nPos != PAGE_NOT_FOUND;
1756
0
}
1757
1758
void TabBar::SetPageBits(sal_uInt16 nPageId, TabBarPageBits nBits)
1759
0
{
1760
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1761
1762
0
    if (nPos == PAGE_NOT_FOUND)
1763
0
        return;
1764
1765
0
    auto& rItem = mpImpl->maItemList[nPos];
1766
1767
0
    if (rItem.mnBits != nBits)
1768
0
    {
1769
0
        rItem.mnBits = nBits;
1770
1771
        // redraw bar
1772
0
        if (IsReallyVisible() && IsUpdateMode())
1773
0
            Invalidate(rItem.maRect);
1774
0
    }
1775
0
}
1776
1777
TabBarPageBits TabBar::GetPageBits(sal_uInt16 nPageId) const
1778
0
{
1779
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1780
1781
0
    if (nPos != PAGE_NOT_FOUND)
1782
0
        return mpImpl->maItemList[nPos].mnBits;
1783
0
    else
1784
0
        return TabBarPageBits::NONE;
1785
0
}
1786
1787
sal_uInt16 TabBar::GetPageCount() const
1788
0
{
1789
0
    return mpImpl->getItemSize();
1790
0
}
1791
1792
sal_uInt16 TabBar::GetPageId(sal_uInt16 nPos) const
1793
0
{
1794
0
    return nPos < mpImpl->maItemList.size() ? mpImpl->maItemList[nPos].mnId : 0;
1795
0
}
1796
1797
sal_uInt16 TabBar::GetPagePos(sal_uInt16 nPageId) const
1798
0
{
1799
0
    for (size_t i = 0; i < mpImpl->maItemList.size(); ++i)
1800
0
    {
1801
0
        if (mpImpl->maItemList[i].mnId == nPageId)
1802
0
        {
1803
0
            return static_cast<sal_uInt16>(i);
1804
0
        }
1805
0
    }
1806
0
    return PAGE_NOT_FOUND;
1807
0
}
1808
1809
sal_uInt16 TabBar::GetPageId(const Point& rPos) const
1810
0
{
1811
0
    for (const auto& rItem : mpImpl->maItemList)
1812
0
    {
1813
0
        if (rItem.maRect.Contains(rPos))
1814
0
            return rItem.mnId;
1815
0
    }
1816
1817
0
    return 0;
1818
0
}
1819
1820
tools::Rectangle TabBar::GetPageRect(sal_uInt16 nPageId) const
1821
0
{
1822
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1823
1824
0
    if (nPos != PAGE_NOT_FOUND)
1825
0
        return mpImpl->maItemList[nPos].maRect;
1826
0
    else
1827
0
        return tools::Rectangle();
1828
0
}
1829
1830
void TabBar::SetCurPageId(sal_uInt16 nPageId)
1831
0
{
1832
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1833
1834
    // do nothing if item does not exit
1835
0
    if (nPos == PAGE_NOT_FOUND)
1836
0
        return;
1837
1838
    // do nothing if the actual page did not change
1839
0
    if (nPageId == mnCurPageId)
1840
0
        return;
1841
1842
    // make invalid
1843
0
    bool bUpdate = false;
1844
0
    if (IsReallyVisible() && IsUpdateMode())
1845
0
        bUpdate = true;
1846
1847
0
    auto& rItem = mpImpl->maItemList[nPos];
1848
0
    ImplTabBarItem* pOldItem;
1849
1850
0
    if (mnCurPageId)
1851
0
        pOldItem = &mpImpl->maItemList[GetPagePos(mnCurPageId)];
1852
0
    else
1853
0
        pOldItem = nullptr;
1854
1855
    // deselect previous page if page was not selected, if this is the
1856
    // only selected page
1857
0
    if (!rItem.mbSelect && pOldItem)
1858
0
    {
1859
0
        sal_uInt16 nSelPageCount = GetSelectPageCount();
1860
0
        if (nSelPageCount == 1)
1861
0
            pOldItem->mbSelect = false;
1862
0
        rItem.mbSelect = true;
1863
0
    }
1864
1865
0
    mnCurPageId = nPageId;
1866
0
    mbFormat = true;
1867
1868
    // assure the actual page becomes visible
1869
0
    if (IsReallyVisible())
1870
0
    {
1871
0
        if (nPos < mnFirstPos)
1872
0
            SetFirstPageId(nPageId);
1873
0
        else
1874
0
        {
1875
            // calculate visible width
1876
0
            tools::Long nWidth = mnLastOffX;
1877
0
            if (nWidth > ADDNEWPAGE_AREAWIDTH)
1878
0
                nWidth -= ADDNEWPAGE_AREAWIDTH;
1879
1880
0
            if (rItem.maRect.IsEmpty())
1881
0
                ImplFormat();
1882
1883
0
            while ((mbMirrored ? (rItem.maRect.Left() < mnOffX) : (rItem.maRect.Right() > nWidth)) ||
1884
0
                    rItem.maRect.IsEmpty())
1885
0
            {
1886
0
                sal_uInt16 nNewPos = mnFirstPos + 1;
1887
                // assure at least the actual tabpages are visible as first tabpage
1888
0
                if (nNewPos >= nPos)
1889
0
                {
1890
0
                    SetFirstPageId(nPageId);
1891
0
                    break;
1892
0
                }
1893
0
                else
1894
0
                    SetFirstPageId(GetPageId(nNewPos));
1895
0
                ImplFormat();
1896
                // abort if first page is not forwarded
1897
0
                if (nNewPos != mnFirstPos)
1898
0
                    break;
1899
0
            }
1900
0
        }
1901
0
    }
1902
1903
    // redraw bar
1904
0
    if (bUpdate)
1905
0
    {
1906
0
        Invalidate(rItem.maRect);
1907
0
        if (pOldItem)
1908
0
            Invalidate(pOldItem->maRect);
1909
0
    }
1910
0
}
1911
1912
void TabBar::MakeVisible(sal_uInt16 nPageId)
1913
0
{
1914
0
    if (!IsReallyVisible())
1915
0
        return;
1916
1917
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1918
1919
    // do nothing if item does not exist
1920
0
    if (nPos == PAGE_NOT_FOUND)
1921
0
        return;
1922
1923
0
    if (nPos < mnFirstPos)
1924
0
        SetFirstPageId(nPageId);
1925
0
    else
1926
0
    {
1927
0
        auto& rItem = mpImpl->maItemList[nPos];
1928
1929
        // calculate visible area
1930
0
        tools::Long nWidth = mnLastOffX;
1931
1932
0
        if (mbFormat || rItem.maRect.IsEmpty())
1933
0
        {
1934
0
            mbFormat = true;
1935
0
            ImplFormat();
1936
0
        }
1937
1938
0
        while ((rItem.maRect.Right() > nWidth) ||
1939
0
                rItem.maRect.IsEmpty())
1940
0
        {
1941
0
            sal_uInt16 nNewPos = mnFirstPos+1;
1942
            // assure at least the actual tabpages are visible as first tabpage
1943
0
            if (nNewPos >= nPos)
1944
0
            {
1945
0
                SetFirstPageId(nPageId);
1946
0
                break;
1947
0
            }
1948
0
            else
1949
0
                SetFirstPageId(GetPageId(nNewPos));
1950
0
            ImplFormat();
1951
            // abort if first page is not forwarded
1952
0
            if (nNewPos != mnFirstPos)
1953
0
                break;
1954
0
        }
1955
0
    }
1956
0
}
1957
1958
void TabBar::SetFirstPageId(sal_uInt16 nPageId)
1959
0
{
1960
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1961
1962
    // return false if item does not exist
1963
0
    if (nPos == PAGE_NOT_FOUND)
1964
0
        return;
1965
1966
0
    if (nPos == mnFirstPos)
1967
0
        return;
1968
1969
    // assure as much pages are visible as possible
1970
0
    ImplFormat();
1971
0
    sal_uInt16 nLastFirstPos = ImplGetLastFirstPos();
1972
0
    sal_uInt16 nNewPos;
1973
0
    if (nPos > nLastFirstPos)
1974
0
        nNewPos = nLastFirstPos;
1975
0
    else
1976
0
        nNewPos = nPos;
1977
1978
0
    if (nNewPos != mnFirstPos)
1979
0
    {
1980
0
        mnFirstPos = nNewPos;
1981
0
        mbFormat = true;
1982
1983
        // redraw bar (attention: check mbDropPos,
1984
        // as if this flag was set, we do not re-paint immediately
1985
0
        if (IsReallyVisible() && IsUpdateMode() && !mbDropPos)
1986
0
            Invalidate();
1987
0
    }
1988
0
}
1989
1990
void TabBar::SelectPage(sal_uInt16 nPageId, bool bSelect)
1991
0
{
1992
0
    sal_uInt16 nPos = GetPagePos(nPageId);
1993
1994
0
    if (nPos == PAGE_NOT_FOUND)
1995
0
        return;
1996
1997
0
    auto& rItem = mpImpl->maItemList[nPos];
1998
1999
0
    if (rItem.mbSelect != bSelect)
2000
0
    {
2001
0
        rItem.mbSelect = bSelect;
2002
2003
        // redraw bar
2004
0
        if (IsReallyVisible() && IsUpdateMode())
2005
0
            Invalidate(rItem.maRect);
2006
0
    }
2007
0
}
2008
2009
sal_uInt16 TabBar::GetSelectPageCount() const
2010
0
{
2011
0
    sal_uInt16 nSelected = 0;
2012
0
    for (const auto& rItem : mpImpl->maItemList)
2013
0
    {
2014
0
        if (rItem.mbSelect)
2015
0
            nSelected++;
2016
0
    }
2017
2018
0
    return nSelected;
2019
0
}
2020
2021
bool TabBar::IsPageSelected(sal_uInt16 nPageId) const
2022
0
{
2023
0
    sal_uInt16 nPos = GetPagePos(nPageId);
2024
0
    if (nPos != PAGE_NOT_FOUND)
2025
0
        return mpImpl->maItemList[nPos].mbSelect;
2026
0
    else
2027
0
        return false;
2028
0
}
2029
2030
void TabBar::SetProtectionSymbol(sal_uInt16 nPageId, bool bProtection)
2031
0
{
2032
0
    sal_uInt16 nPos = GetPagePos(nPageId);
2033
0
    if (nPos != PAGE_NOT_FOUND)
2034
0
    {
2035
0
        if (mpImpl->maItemList[nPos].mbProtect != bProtection)
2036
0
        {
2037
0
            mpImpl->maItemList[nPos].mbProtect = bProtection;
2038
0
            mbSizeFormat = true;    // render text width changes, thus bar width
2039
2040
            // redraw bar
2041
0
            if (IsReallyVisible() && IsUpdateMode())
2042
0
                Invalidate();
2043
0
        }
2044
0
    }
2045
0
}
2046
2047
bool TabBar::StartEditMode(sal_uInt16 nPageId)
2048
0
{
2049
0
    sal_uInt16 nPos = GetPagePos( nPageId );
2050
0
    if (mpImpl->mxEdit || (nPos == PAGE_NOT_FOUND) || (mnLastOffX < 8))
2051
0
        return false;
2052
2053
0
    mnEditId = nPageId;
2054
0
    if (StartRenaming())
2055
0
    {
2056
0
        ImplShowPage(nPos);
2057
0
        ImplFormat();
2058
0
        PaintImmediately();
2059
2060
0
        mpImpl->mxEdit.disposeAndReset(VclPtr<TabBarEdit>::Create(this));
2061
0
        tools::Rectangle aRect = GetPageRect( mnEditId );
2062
0
        tools::Long nX = aRect.Left();
2063
0
        tools::Long nWidth = aRect.GetWidth();
2064
0
        if (mnEditId != GetCurPageId())
2065
0
            nX += 1;
2066
0
        if (nX + nWidth > mnLastOffX)
2067
0
            nWidth = mnLastOffX-nX;
2068
0
        if (nWidth < 3)
2069
0
        {
2070
0
            nX = aRect.Left();
2071
0
            nWidth = aRect.GetWidth();
2072
0
        }
2073
0
        weld::Entry& rEntry = mpImpl->mxEdit->get_widget();
2074
0
        rEntry.set_text(GetPageText(mnEditId));
2075
0
        mpImpl->mxEdit->SetPosSizePixel(Point(nX, aRect.Top() + mnOffY + 1), Size(nWidth, aRect.GetHeight() - 3));
2076
0
        vcl::Font aFont = GetPointFont(*GetOutDev()); // FIXME RenderContext
2077
2078
0
        Color   aForegroundColor;
2079
0
        Color   aBackgroundColor;
2080
0
        Color   aFaceColor;
2081
0
        Color   aSelectColor;
2082
0
        Color   aFaceTextColor;
2083
0
        Color   aSelectTextColor;
2084
2085
0
        ImplGetColors(Application::GetSettings().GetStyleSettings(), aFaceColor, aFaceTextColor, aSelectColor, aSelectTextColor);
2086
2087
0
        if (mnEditId != GetCurPageId())
2088
0
        {
2089
0
            aFont.SetWeight(WEIGHT_LIGHT);
2090
0
        }
2091
0
        if (IsPageSelected(mnEditId) || mnEditId == GetCurPageId())
2092
0
        {
2093
0
            aForegroundColor = aSelectTextColor;
2094
0
            aBackgroundColor = aSelectColor;
2095
0
        }
2096
0
        else
2097
0
        {
2098
0
            aForegroundColor = aFaceTextColor;
2099
0
            aBackgroundColor = aFaceColor;
2100
0
        }
2101
0
        if (GetPageBits( mnEditId ) & TabBarPageBits::Blue)
2102
0
        {
2103
0
            aForegroundColor = COL_LIGHTBLUE;
2104
0
        }
2105
0
        rEntry.set_font(aFont);
2106
0
        rEntry.set_font_color(aForegroundColor);
2107
0
        mpImpl->mxEdit->SetControlBackground(aBackgroundColor);
2108
0
        rEntry.grab_focus();
2109
0
        rEntry.select_region(0, -1);
2110
0
        mpImpl->mxEdit->Show();
2111
0
        return true;
2112
0
    }
2113
0
    else
2114
0
    {
2115
0
        mnEditId = 0;
2116
0
        return false;
2117
0
    }
2118
0
}
2119
2120
bool TabBar::IsInEditMode() const
2121
0
{
2122
0
    return bool(mpImpl->mxEdit);
2123
0
}
2124
2125
void TabBar::EndEditMode(bool bCancel)
2126
0
{
2127
0
    if (!mpImpl->mxEdit)
2128
0
        return;
2129
2130
    // call hdl
2131
0
    bool bEnd = true;
2132
0
    mbEditCanceled = bCancel;
2133
0
    weld::Entry& rEntry = mpImpl->mxEdit->get_widget();
2134
0
    maEditText = rEntry.get_text();
2135
0
    mpImpl->mxEdit->SetPostEvent();
2136
0
    if (!bCancel)
2137
0
    {
2138
0
        TabBarAllowRenamingReturnCode nAllowRenaming = AllowRenaming();
2139
0
        if (nAllowRenaming == TABBAR_RENAMING_YES)
2140
0
            SetPageText(mnEditId, maEditText);
2141
0
        else if (nAllowRenaming == TABBAR_RENAMING_NO)
2142
0
            bEnd = false;
2143
0
        else // nAllowRenaming == TABBAR_RENAMING_CANCEL
2144
0
            mbEditCanceled = true;
2145
0
    }
2146
2147
    // renaming not allowed, then reset edit data
2148
0
    if (!bEnd)
2149
0
    {
2150
0
        mpImpl->mxEdit->ResetPostEvent();
2151
0
        rEntry.grab_focus();
2152
0
    }
2153
0
    else
2154
0
    {
2155
        // close edit and call end hdl
2156
0
        mpImpl->mxEdit.disposeAndClear();
2157
2158
0
        EndRenaming();
2159
0
        mnEditId = 0;
2160
0
    }
2161
2162
    // reset
2163
0
    maEditText.clear();
2164
0
    mbEditCanceled = false;
2165
0
}
2166
2167
void TabBar::SetMirrored(bool bMirrored)
2168
0
{
2169
0
    if (mbMirrored != bMirrored)
2170
0
    {
2171
0
        mbMirrored = bMirrored;
2172
0
        mbSizeFormat = true;
2173
0
        ImplInitControls();     // for button images
2174
0
        Resize();               // recalculates control positions
2175
0
        Mirror();
2176
0
    }
2177
0
}
2178
2179
void TabBar::SetEffectiveRTL(bool bRTL)
2180
0
{
2181
0
    SetMirrored( bRTL != AllSettings::GetLayoutRTL() );
2182
0
}
2183
2184
bool TabBar::IsEffectiveRTL() const
2185
0
{
2186
0
    return IsMirrored() != AllSettings::GetLayoutRTL();
2187
0
}
2188
2189
void TabBar::SetMaxPageWidth(tools::Long nMaxWidth)
2190
0
{
2191
0
    if (mnMaxPageWidth != nMaxWidth)
2192
0
    {
2193
0
        mnMaxPageWidth = nMaxWidth;
2194
0
        mbSizeFormat = true;
2195
2196
        // redraw bar
2197
0
        if (IsReallyVisible() && IsUpdateMode())
2198
0
            Invalidate();
2199
0
    }
2200
0
}
2201
2202
void TabBar::SetPageText(sal_uInt16 nPageId, const OUString& rText)
2203
0
{
2204
0
    sal_uInt16 nPos = GetPagePos(nPageId);
2205
0
    if (nPos != PAGE_NOT_FOUND)
2206
0
    {
2207
0
        mpImpl->maItemList[nPos].maText = rText;
2208
0
        mbSizeFormat = true;
2209
2210
        // redraw bar
2211
0
        if (IsReallyVisible() && IsUpdateMode())
2212
0
            Invalidate();
2213
2214
0
        CallEventListeners(VclEventId::TabbarPageTextChanged, reinterpret_cast<void*>(sal::static_int_cast<sal_IntPtr>(nPageId)));
2215
0
    }
2216
0
}
2217
2218
const OUString & TabBar::GetPageText(sal_uInt16 nPageId) const
2219
0
{
2220
0
    sal_uInt16 nPos = GetPagePos(nPageId);
2221
0
    if (nPos != PAGE_NOT_FOUND)
2222
0
        return mpImpl->maItemList[nPos].maText;
2223
0
    return EMPTY_OUSTRING;
2224
0
}
2225
2226
const OUString & TabBar::GetAuxiliaryText(sal_uInt16 nPageId) const
2227
0
{
2228
0
    sal_uInt16 nPos = GetPagePos(nPageId);
2229
0
    if (nPos != PAGE_NOT_FOUND)
2230
0
        return mpImpl->maItemList[nPos].maAuxiliaryText;
2231
0
    return EMPTY_OUSTRING;
2232
0
}
2233
2234
void TabBar::SetAuxiliaryText(sal_uInt16 nPageId, const OUString& rText )
2235
0
{
2236
0
    sal_uInt16 nPos = GetPagePos(nPageId);
2237
0
    if (nPos != PAGE_NOT_FOUND)
2238
0
    {
2239
0
        mpImpl->maItemList[nPos].maAuxiliaryText = rText;
2240
        // no redraw bar, no CallEventListener, internal use in LayerTabBar
2241
0
    }
2242
0
}
2243
2244
OUString TabBar::GetHelpText(sal_uInt16 nPageId) const
2245
0
{
2246
0
    sal_uInt16 nPos = GetPagePos(nPageId);
2247
0
    if (nPos != PAGE_NOT_FOUND)
2248
0
    {
2249
0
        auto& rItem = mpImpl->maItemList[nPos];
2250
0
        if (rItem.maHelpText.isEmpty() && !rItem.maHelpId.isEmpty())
2251
0
        {
2252
0
            Help* pHelp = Application::GetHelp();
2253
0
            if (pHelp)
2254
0
                rItem.maHelpText = pHelp->GetHelpText(OStringToOUString(rItem.maHelpId, RTL_TEXTENCODING_UTF8));
2255
0
        }
2256
2257
0
        return rItem.maHelpText;
2258
0
    }
2259
0
    return OUString();
2260
0
}
2261
2262
bool TabBar::StartDrag(const CommandEvent& rCEvt, vcl::Region& rRegion)
2263
0
{
2264
0
    if (!(mnWinStyle & WB_DRAG) || (rCEvt.GetCommand() != CommandEventId::StartDrag))
2265
0
        return false;
2266
2267
    // Check if the clicked page was selected. If this is not the case
2268
    // set it as actual entry. We check for this only at a mouse action
2269
    // if Drag and Drop can be triggered from the keyboard.
2270
    // We only do this, if Select() was not triggered, as the Select()
2271
    // could have scrolled the area
2272
0
    if (rCEvt.IsMouseEvent() && !mbInSelect)
2273
0
    {
2274
0
        sal_uInt16 nSelId = GetPageId(rCEvt.GetMousePosPixel());
2275
2276
        // do not start dragging if no entry was clicked
2277
0
        if (!nSelId)
2278
0
            return false;
2279
2280
        // check if page was selected. If not set it as actual
2281
        // page and call Select()
2282
0
        if (!IsPageSelected(nSelId))
2283
0
        {
2284
0
            if (ImplDeactivatePage())
2285
0
            {
2286
0
                SetCurPageId(nSelId);
2287
0
                PaintImmediately();
2288
0
                ImplActivatePage();
2289
0
                ImplSelect();
2290
0
            }
2291
0
            else
2292
0
                return false;
2293
0
        }
2294
0
    }
2295
0
    mbInSelect = false;
2296
2297
    // assign region
2298
0
    rRegion = vcl::Region();
2299
2300
0
    return true;
2301
0
}
2302
2303
sal_uInt16 TabBar::ShowDropPos(const Point& rPos)
2304
0
{
2305
0
    sal_uInt16 nNewDropPos;
2306
0
    sal_uInt16 nItemCount = mpImpl->getItemSize();
2307
0
    sal_Int16 nScroll = 0;
2308
2309
0
    if (rPos.X() > mnLastOffX-TABBAR_DRAG_SCROLLOFF)
2310
0
    {
2311
0
        auto& rItem = mpImpl->maItemList[mpImpl->maItemList.size() - 1];
2312
0
        if (!rItem.maRect.IsEmpty() && (rPos.X() > rItem.maRect.Right()))
2313
0
            nNewDropPos = mpImpl->getItemSize();
2314
0
        else
2315
0
        {
2316
0
            nNewDropPos = mnFirstPos + 1;
2317
0
            nScroll = 1;
2318
0
        }
2319
0
    }
2320
0
    else if ((rPos.X() <= mnOffX) ||
2321
0
             (!mnOffX && (rPos.X() <= TABBAR_DRAG_SCROLLOFF)))
2322
0
    {
2323
0
        if (mnFirstPos)
2324
0
        {
2325
0
            nNewDropPos = mnFirstPos;
2326
0
            nScroll = -1;
2327
0
        }
2328
0
        else
2329
0
            nNewDropPos = 0;
2330
0
    }
2331
0
    else
2332
0
    {
2333
0
        sal_uInt16 nDropId = GetPageId(rPos);
2334
0
        if (nDropId)
2335
0
        {
2336
0
            nNewDropPos = GetPagePos(nDropId);
2337
0
            if (mnFirstPos && (nNewDropPos == mnFirstPos - 1))
2338
0
                nScroll = -1;
2339
0
        }
2340
0
        else
2341
0
            nNewDropPos = nItemCount;
2342
0
    }
2343
2344
0
    if (mbDropPos && (nNewDropPos == mnDropPos) && !nScroll)
2345
0
        return mnDropPos;
2346
2347
0
    if (mbDropPos)
2348
0
        HideDropPos();
2349
0
    mbDropPos = true;
2350
0
    mnDropPos = nNewDropPos;
2351
2352
0
    if (nScroll)
2353
0
    {
2354
0
        sal_uInt16 nOldFirstPos = mnFirstPos;
2355
0
        SetFirstPageId(GetPageId(mnFirstPos + nScroll));
2356
2357
        // draw immediately, as Paint not possible during Drag and Drop
2358
0
        if (nOldFirstPos != mnFirstPos)
2359
0
        {
2360
0
            tools::Rectangle aRect(mnOffX, 0, mnLastOffX, maWinSize.Height());
2361
0
            GetOutDev()->SetFillColor(GetBackground().GetColor());
2362
0
            GetOutDev()->DrawRect(aRect);
2363
0
            Invalidate(aRect);
2364
0
        }
2365
0
    }
2366
2367
    // draw drop position arrows
2368
0
    const StyleSettings& rStyles = Application::GetSettings().GetStyleSettings();
2369
0
    const Color aTextColor = rStyles.GetLabelTextColor();
2370
0
    tools::Long nX;
2371
0
    tools::Long nY = (maWinSize.Height() / 2) - 1;
2372
0
    sal_uInt16 nCurPos = GetPagePos(mnCurPageId);
2373
2374
0
    sal_Int32 nTriangleWidth = 3 * GetDPIScaleFactor();
2375
2376
0
    if (mnDropPos < nItemCount)
2377
0
    {
2378
0
        GetOutDev()->SetLineColor(aTextColor);
2379
0
        GetOutDev()->SetFillColor(aTextColor);
2380
2381
0
        auto& rItem = mpImpl->maItemList[mnDropPos];
2382
0
        nX = rItem.maRect.Left();
2383
0
        if ( mnDropPos == nCurPos )
2384
0
            nX--;
2385
0
        else
2386
0
            nX++;
2387
2388
0
        if (!rItem.IsDefaultTabBgColor() && !rItem.mbSelect)
2389
0
        {
2390
0
            GetOutDev()->SetLineColor(rItem.maTabTextColor);
2391
0
            GetOutDev()->SetFillColor(rItem.maTabTextColor);
2392
0
        }
2393
2394
0
        tools::Polygon aPoly(3);
2395
0
        aPoly.SetPoint(Point(nX, nY), 0);
2396
0
        aPoly.SetPoint(Point(nX + nTriangleWidth, nY - nTriangleWidth), 1);
2397
0
        aPoly.SetPoint(Point(nX + nTriangleWidth, nY + nTriangleWidth), 2);
2398
0
        GetOutDev()->DrawPolygon(aPoly);
2399
0
    }
2400
0
    if (mnDropPos > 0 && mnDropPos < nItemCount + 1)
2401
0
    {
2402
0
        GetOutDev()->SetLineColor(aTextColor);
2403
0
        GetOutDev()->SetFillColor(aTextColor);
2404
2405
0
        auto& rItem = mpImpl->maItemList[mnDropPos - 1];
2406
0
        nX = rItem.maRect.Right();
2407
0
        if (mnDropPos == nCurPos)
2408
0
            nX++;
2409
0
        if (!rItem.IsDefaultTabBgColor() && !rItem.mbSelect)
2410
0
        {
2411
0
            GetOutDev()->SetLineColor(rItem.maTabTextColor);
2412
0
            GetOutDev()->SetFillColor(rItem.maTabTextColor);
2413
0
        }
2414
0
        tools::Polygon aPoly(3);
2415
0
        aPoly.SetPoint(Point(nX, nY), 0);
2416
0
        aPoly.SetPoint(Point(nX - nTriangleWidth, nY - nTriangleWidth), 1);
2417
0
        aPoly.SetPoint(Point(nX - nTriangleWidth, nY + nTriangleWidth), 2);
2418
0
        GetOutDev()->DrawPolygon(aPoly);
2419
0
    }
2420
2421
0
    return mnDropPos;
2422
0
}
2423
2424
void TabBar::HideDropPos()
2425
0
{
2426
0
    if (!mbDropPos)
2427
0
        return;
2428
2429
0
    tools::Long nX;
2430
0
    tools::Long nY1 = (maWinSize.Height() / 2) - 3;
2431
0
    tools::Long nY2 = nY1 + 5;
2432
0
    sal_uInt16 nItemCount = mpImpl->getItemSize();
2433
2434
0
    if (mnDropPos < nItemCount)
2435
0
    {
2436
0
        auto& rItem = mpImpl->maItemList[mnDropPos];
2437
0
        nX = rItem.maRect.Left();
2438
        // immediately call Paint, as it is not possible during drag and drop
2439
0
        tools::Rectangle aRect( nX-1, nY1, nX+3, nY2 );
2440
0
        vcl::Region aRegion( aRect );
2441
0
        GetOutDev()->SetClipRegion( aRegion );
2442
0
        Invalidate(aRect);
2443
0
        GetOutDev()->SetClipRegion();
2444
0
    }
2445
0
    if (mnDropPos > 0 && mnDropPos < nItemCount + 1)
2446
0
    {
2447
0
        auto& rItem = mpImpl->maItemList[mnDropPos - 1];
2448
0
        nX = rItem.maRect.Right();
2449
        // immediately call Paint, as it is not possible during drag and drop
2450
0
        tools::Rectangle aRect(nX - 2, nY1, nX + 1, nY2);
2451
0
        vcl::Region aRegion(aRect);
2452
0
        GetOutDev()->SetClipRegion(aRegion);
2453
0
        Invalidate(aRect);
2454
0
        GetOutDev()->SetClipRegion();
2455
0
    }
2456
2457
0
    mbDropPos = false;
2458
0
    mnDropPos = 0;
2459
0
}
2460
2461
void TabBar::SwitchPage(const Point& rPos)
2462
0
{
2463
0
    sal_uInt16 nSwitchId = GetPageId(rPos);
2464
0
    if (!nSwitchId)
2465
0
        EndSwitchPage();
2466
0
    else
2467
0
    {
2468
0
        if (nSwitchId != mnSwitchId)
2469
0
        {
2470
0
            mnSwitchId = nSwitchId;
2471
0
            mnSwitchTime = tools::Time::GetSystemTicks();
2472
0
        }
2473
0
        else
2474
0
        {
2475
            // change only after 500 ms
2476
0
            if (mnSwitchId != GetCurPageId())
2477
0
            {
2478
0
                if (tools::Time::GetSystemTicks() > mnSwitchTime + 500)
2479
0
                {
2480
0
                    if (ImplDeactivatePage())
2481
0
                    {
2482
0
                        SetCurPageId( mnSwitchId );
2483
0
                        PaintImmediately();
2484
0
                        ImplActivatePage();
2485
0
                        ImplSelect();
2486
0
                    }
2487
0
                }
2488
0
            }
2489
0
        }
2490
0
    }
2491
0
}
2492
2493
void TabBar::EndSwitchPage()
2494
0
{
2495
0
    mnSwitchTime = 0;
2496
0
    mnSwitchId = 0;
2497
0
}
2498
2499
void TabBar::SetStyle(WinBits nStyle)
2500
0
{
2501
0
    if (mnWinStyle == nStyle)
2502
0
        return;
2503
0
    mnWinStyle = nStyle;
2504
0
    ImplInitControls();
2505
    // order possible controls
2506
0
    if (IsReallyVisible() && IsUpdateMode())
2507
0
        Resize();
2508
0
}
2509
2510
Size TabBar::CalcWindowSizePixel() const
2511
0
{
2512
0
    tools::Long nWidth = 0;
2513
2514
0
    if (!mpImpl->maItemList.empty())
2515
0
    {
2516
0
        const_cast<TabBar*>(this)->ImplCalcWidth();
2517
0
        for (const auto& rItem : mpImpl->maItemList)
2518
0
        {
2519
0
            nWidth += rItem.mnWidth;
2520
0
        }
2521
0
    }
2522
2523
0
    return Size(nWidth, GetSettings().GetStyleSettings().GetScrollBarSize());
2524
0
}
2525
2526
tools::Rectangle TabBar::GetPageArea() const
2527
0
{
2528
0
    return tools::Rectangle(Point(mnOffX, mnOffY),
2529
0
                     Size(mnLastOffX - mnOffX + 1, GetSizePixel().Height() - mnOffY));
2530
0
}
2531
2532
void TabBar::SetAddButtonEnabled(bool bAddButtonEnabled)
2533
0
{
2534
0
    mpImpl->mxButtonBox->m_xAddButton->set_sensitive(bAddButtonEnabled);
2535
0
}
2536
2537
rtl::Reference<comphelper::OAccessible> TabBar::CreateAccessible()
2538
0
{
2539
0
    return new accessibility::AccessibleTabBar(this);
2540
0
}
2541
2542
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */