1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
22 #include <svtools/svtdllapi.h>
23 #include <tools/link.hxx>
24 #include <vcl/window.hxx>
25 #include <o3tl/typed_flags_set.hxx>
35 WB_SCROLL - The tabs can be scrolled via an extra field
36 WB_MINSCROLL - The tabs can be scrolled via 2 additional buttons
37 WB_RANGESELECT - Connected ranges can be selected
38 WB_MULTISELECT - single tabs can be selected
39 WB_BORDER - a border is drawn in the top and in the bottom
40 WB_DRAG - A StartDrag handler is called by the TabBar, if drag
41 and drop should be started. In addition, drag and drop
42 is activated in the TabBar with EnableDrop().
43 WB_SIZEABLE - a Split handler is called by the TabBar, if the user
44 wants to change the width of the TabBar
45 WB_STDTABBAR - WB_BORDER
51 Setting page bits modify the display attributes of the tab name
54 - Display tab name in light blue, used in draw for
55 invisible layers and in calc for scenario pages
56 TabBarPageBits::Italic
57 - Display tab name italic, used in draw for
59 TabBarPageBits::Underline
60 - Display tab name underlined, used in draw for
67 Select - is called when a tab is selected or unselected
68 DoubleClick - Is called when a DoubleClick has been fired in the
69 TabBar. Inside of the handler, GetCurPageId() returns
70 the clicked tab or 0, if no tab has been clicked.
71 ActivatePage - Is called, if another page is activated.
72 GetCurPageId() returns the activated page.
73 DeactivatePage - Is called, when a page is deactivated. If another page
74 may be activated, true must be returned; if another
75 page shall be excluded from the activation, false must
76 be returned. GetCurPageId() returns the page to be
83 For Drag and Drop, the WinBit WB_DRAG must be set. In addition, the
84 Command handler, the QueryDrop handler and the Drop handler must be overlaid.
85 In doing so, the following must be implemented in the handlers:
87 Command - If dragging should be started in this handler,
88 StartDrag() must be called. This method
89 then selects the respective entry or returns
90 false, if dragging cannot be carried out.
92 QueryDrop - This handler is always called by StarView, when the
93 mouse is pulled over the window while dragging
94 (s.a. SV documentation). In this handler, it must be
95 determined whether a drop is possible. The drop
96 position can be shown in TabBar using ShowDropPos().
97 When calling, the position of the Event must be passed.
98 If the position is at the left or right border,
99 scrolling automatically takes place in the TabBar.
100 This method also returns the respective drop position,
101 which is also needed for a drop. If the window is left
102 while dragging, the drop position can be taken back
103 using HideDropPos(). Thus, it is also possible to handle
104 a drag which was triggered from outside the TabBar.
106 Drop - In the Drop handler, the pages have to be moved, or
107 the new pages have to be inserted. The respective
108 drop position can be determined using ShowDropPos().
110 The following methods are needed for Drag and Drop and must be called
113 StartDrag - Must be called from the Command handler. As parameters,
114 the CommandEvent and a reference to a Region must be
115 passed. This vcl::Region then must be passed in
116 ExecuteDrag(), if the return value indicates that
117 ExecuteDrag shall be carried out. If the entry is not
118 selected, it is set as the current entry beforehand.
119 Because of this, attention must be paid that the Select
120 handler can be called from this method.
122 ShowDropPos - This method must be called by the QueryDrop handler,
123 so that the TabBar shows where the Tabs are
124 inserted. This method can also be used in the Drop
125 handler, in order to determine the position at which
126 the Tabs shall be inserted. In the method, the
127 position of the Event must be passed. This method
128 returns the position, at which the Tabs shall be inserted.
130 HideDropPos - This method takes back the DropPosition previously
131 displayed using ShowDropPos(). This method should be
132 called, when the window is left in the QueryDrop()
133 handler or the drag process has been ended.
135 The following methods can be used if the pages should be switched
136 in the Drag and Drop:
138 SwitchPage - This method must be called by the QueryDrop handler
139 if the page, over which the mouse pointer resides,
140 should be switched. This method should be called
141 each time the QueryDrop-Handler is called.
142 Switching the page happens with a delay (500 ms) and
143 is automatically managed by this method.
144 The Position of the Event must be passed in the method.
145 This method returns true if the page has been switched.
147 EndSwitchPage - This method resets the data for the switching of the
148 page. This method should be called when the window
149 is left in QueryDrop() or the drag process has been
152 IsInSwitching - With this method, it can be queried in
153 ActivatePage()/DeactivatePage() whether this has been
154 caused by SwitchPage(). Thus, for example, switching
155 can be avoided in DeactivatePage() without an error
162 If the window width can be changed by the user, the WinBit WB_SIZEABLE
163 must be set. In this case, the following handler must be overlaid:
165 Split - When this handler is called, the window should be
166 adapted to the width that is returned by GetSplitSize().
167 In doing so, no minimal or maximum width is taken into
168 account. A minimal size can be queried using
169 GetMinSize() and the maximum width must be calculated
170 by the application itself. As only Online Resize is
171 supported, the window width must be changed inside
172 this handler and possibly the width of dependent windows
173 as well. For this handler, a link can also be set using
176 The following methods deliver more information while Splitting:
178 GetSplitSize() - Returns the width of the TabBar, to which the user
179 wants to resize the window. No minimum or maximum
180 width is taken into account. However, a width < 5
181 is never returned. This method only returns valid
182 values as long as splitting is active.
184 GetMinSize() - With this method, a minimum window width can be
185 queried, so that at least something of a Tab is
186 visible. Still, the TabBar can be set more narrow
187 then the width that this method returns.
188 This method can also be called, when no splitting
195 The TabBar also offers the user the possibility to change the names
198 EnableEditMode - With this, it can be configured that on Alt+LeftClick,
199 StartEditMode() is automatically called by the TabBar.
200 In the StartRenaming() handler, the renaming can still
202 StartEditMode - With this method, the EditMode is started on a Tab.
203 false is returned, if the EditMode is already
204 active, the mode is rejected with StartRenaming()
205 or no space is available for editing.
206 EndEditMode - With this method, the EditMode is ended.
207 SetEditText - With this method, the text in the AllowRenaming()
208 handler can still be replaced by another text.
209 GetEditText - With this method, the text, which the user has typed
210 in, can be queried in the AllowRenaming() handler.
211 IsInEditMode - This method is used to query whether the EditMode
213 IsEditModeCanceled - This method can be used in the EndRenaming()
214 handler to query whether the renaming has
216 GetEditPageId - With this method, the tab that is being/has been
217 renamed is queried in the Renaming handlers.
219 StartRenaming() - This handler is called when the EditMode hast been
220 started using StartEditMode(). GetEditPageId()
221 can be used to query which Tab should be renamed.
222 false should be returned if the EditMod should
224 AllowRenaming() - This handler is called when the EditMode is ended
225 (not in case of Cancel). Within this handler, it
226 can then be tested whether the text is OK.
227 The Tab which was renamed can be queried using
229 One of the following values should be returned:
233 The Tab is not renamed, but the EditMode remains
234 active, so that the user can adapt the name
237 The EditMode was cancelled and the old text
239 EndRenaming() - This handler is called when the EditMode has been
240 ended. The tab that has been renamed can be
241 queried using GetEditPageId(). Using
242 IsEditModeCanceled(), it can be queried whether
243 the mode has been cancelled and the name has
244 thus not been changed.
250 The Page width of the tabs can be limited in order to make an easier
251 navigation by them possible. If then, the text cannot be displayed
252 completely, it is abbreviated with "..." and the whole text is
253 displayed in the Tip or in the active help (if no help text is set).
254 Using EnableAutoMaxPageWidth(), it can be configured whether the
255 maximum page width should be based on the currently visible width
256 (which is the default). Otherwise, the maximum page width can
257 also be set using SetMaxPageWidth() (in pixels) (in this case, the
258 AutoMaxPageWidth is ignored).
263 If a context-sensitive PopupMenu should be displayed, the Command
264 handler must be overlaid. Using GetPageId() and when passing the
265 mouse position, it can be determined whether the mouse click has been
266 carried out over an item resp. over which item the mouse click has
274 #define WB_RANGESELECT (WinBits(0x00200000))
275 #define WB_MULTISELECT (WinBits(0x00400000))
276 #define WB_MINSCROLL (WinBits(0x20000000))
277 #define WB_INSERTTAB (WinBits(0x40000000))
278 #define WB_STDTABBAR WB_BORDER
282 enum class TabBarPageBits
{
289 template<> struct typed_flags
<TabBarPageBits
> : is_typed_flags
<TabBarPageBits
, 0x07> {};
292 // interface checks only, do not use in regular control flow
294 #define TPB_DISPLAY_NAME_ALLFLAGS (TabBarPageBits::Blue | TabBarPageBits::Italic | TabBarPageBits::Underline)
296 // - TabBar-Types - used in TabBar::AllowRenaming
298 enum TabBarAllowRenamingReturnCode
{
301 TABBAR_RENAMING_CANCEL
305 class DataChangedEvent
;
307 struct ImplTabBarItem
;
311 class SVT_DLLPUBLIC TabBar
: public vcl::Window
313 friend class ImplTabSizer
;
316 std::unique_ptr
<TabBar_Impl
> mpImpl
;
320 tools::Long mnMaxPageWidth
;
321 tools::Long mnCurMaxWidth
;
324 tools::Long mnLastOffX
;
325 tools::Long mnSplitSize
;
326 sal_uInt64 mnSwitchTime
;
328 sal_uInt16 mnCurPageId
;
329 sal_uInt16 mnFirstPos
;
330 sal_uInt16 mnDropPos
;
331 sal_uInt16 mnSwitchId
;
335 bool mbFirstFormat
: 1;
336 bool mbSizeFormat
: 1;
337 bool mbAutoEditMode
: 1;
338 bool mbEditCanceled
: 1;
342 bool mbScrollAlwaysEnabled
: 1;
345 Link
<TabBar
*,void> maSelectHdl
;
346 Link
<TabBar
*,void> maSplitHdl
;
347 Link
<const CommandEvent
&, void> maScrollAreaContextHdl
;
348 size_t maCurrentItemList
;
350 using Window::ImplInit
;
351 SVT_DLLPRIVATE
void ImplInit( WinBits nWinStyle
, bool bSheets
);
352 SVT_DLLPRIVATE
void ImplInitSettings( bool bFont
, bool bBackground
);
353 SVT_DLLPRIVATE
void ImplGetColors(const StyleSettings
& rStyleSettings
,
354 Color
& rFaceColor
, Color
& rFaceTextColor
,
355 Color
& rSelectColor
, Color
& rSelectTextColor
);
356 SVT_DLLPRIVATE
void ImplShowPage( sal_uInt16 nPos
);
357 SVT_DLLPRIVATE
bool ImplCalcWidth();
358 SVT_DLLPRIVATE
void ImplFormat();
359 SVT_DLLPRIVATE sal_uInt16
ImplGetLastFirstPos();
360 SVT_DLLPRIVATE
void ImplInitControls();
361 SVT_DLLPRIVATE
void ImplEnableControls();
362 SVT_DLLPRIVATE
void ImplSelect();
363 SVT_DLLPRIVATE
void ImplActivatePage();
364 SVT_DLLPRIVATE
bool ImplDeactivatePage();
365 SVT_DLLPRIVATE
void ImplPrePaint();
366 SVT_DLLPRIVATE ImplTabBarItem
* ImplGetLastTabBarItem( sal_uInt16 nItemCount
);
368 DECL_DLLPRIVATE_LINK(ImplClickHdl
, weld::Button
&, void);
369 DECL_DLLPRIVATE_LINK(ImplAddClickHandler
, weld::Button
&, void);
370 DECL_DLLPRIVATE_LINK(MousePressHdl
, const MouseEvent
&, bool);
371 DECL_DLLPRIVATE_LINK(ContextMenuHdl
, const CommandEvent
&, void);
373 ImplTabBarItem
* seek( size_t i
);
374 ImplTabBarItem
* prev();
375 ImplTabBarItem
* next();
378 virtual void AddTabClick();
379 const OUString
& GetAuxiliaryText(sal_uInt16 nPageId
) const; // needed in derived class LayerTabBar
380 void SetAuxiliaryText(sal_uInt16 nPageId
, const OUString
& rText
);
383 static const sal_uInt16 APPEND
;
384 static const sal_uInt16 PAGE_NOT_FOUND
;
386 TabBar(vcl::Window
* pParent
, WinBits nWinStyle
, bool bSheets
= false);
387 virtual ~TabBar() override
;
388 virtual void dispose() override
;
390 virtual void MouseMove( const MouseEvent
& rMEvt
) override
;
391 virtual void MouseButtonDown( const MouseEvent
& rMEvt
) override
;
392 virtual void MouseButtonUp( const MouseEvent
& rMEvt
) override
;
393 virtual void Paint( vcl::RenderContext
& rRenderContext
, const tools::Rectangle
& rRect
) override
;
394 virtual void Resize() override
;
395 virtual void RequestHelp( const HelpEvent
& rHEvt
) override
;
396 virtual void StateChanged( StateChangedType nStateChange
) override
;
397 virtual void DataChanged( const DataChangedEvent
& rDCEvt
) override
;
398 virtual bool PreNotify( NotifyEvent
& rNEvt
) override
;
400 virtual void Select();
401 virtual void DoubleClick();
403 virtual void ActivatePage();
404 virtual bool DeactivatePage();
405 virtual bool StartRenaming();
406 virtual TabBarAllowRenamingReturnCode
AllowRenaming();
407 virtual void EndRenaming();
408 virtual void Mirror();
410 virtual void InsertPage( sal_uInt16 nPageId
, const OUString
& rText
,
411 TabBarPageBits nBits
= TabBarPageBits::NONE
,
412 sal_uInt16 nPos
= TabBar::APPEND
);
413 void RemovePage( sal_uInt16 nPageId
);
414 void MovePage( sal_uInt16 nPageId
, sal_uInt16 nNewPos
);
416 Color
GetTabBgColor( sal_uInt16 nPageId
) const;
417 void SetTabBgColor( sal_uInt16 nPageId
, const Color
& aTabBgColor
);
421 bool IsPageEnabled( sal_uInt16 nPageId
) const;
423 void SetPageBits( sal_uInt16 nPageId
, TabBarPageBits nBits
);
424 TabBarPageBits
GetPageBits( sal_uInt16 nPageId
) const;
426 sal_uInt16
GetPageCount() const;
427 sal_uInt16
GetPageId( sal_uInt16 nPos
) const;
428 sal_uInt16
GetPagePos( sal_uInt16 nPageId
) const;
429 sal_uInt16
GetCurPagePos() const { return GetPagePos(GetCurPageId()); }
430 sal_uInt16
GetPageId( const Point
& rPos
) const;
431 tools::Rectangle
GetPageRect( sal_uInt16 nPageId
) const;
432 // returns the rectangle in which page tabs are drawn
433 tools::Rectangle
GetPageArea() const;
435 void SetCurPageId( sal_uInt16 nPageId
);
436 sal_uInt16
GetCurPageId() const { return mnCurPageId
; }
438 void SetFirstPageId( sal_uInt16 nPageId
);
439 void MakeVisible( sal_uInt16 nPageId
);
441 void SelectPage( sal_uInt16 nPageId
, bool bSelect
);
442 sal_uInt16
GetSelectPageCount() const;
443 bool IsPageSelected( sal_uInt16 nPageId
) const;
444 void SetProtectionSymbol( sal_uInt16 nPageId
, bool bProtection
);
446 void SetMaxPageWidth( tools::Long nMaxWidth
);
448 void EnableEditMode() { mbAutoEditMode
= true; }
449 bool StartEditMode( sal_uInt16 nPageId
);
450 void EndEditMode( bool bCancel
= false );
451 void SetEditText( const OUString
& rText
) { maEditText
= rText
; }
452 const OUString
& GetEditText() const { return maEditText
; }
453 bool IsInEditMode() const;
454 bool IsEditModeCanceled() const { return mbEditCanceled
; }
455 sal_uInt16
GetEditPageId() const { return mnEditId
; }
457 /** Mirrors the entire control including position of buttons and splitter.
458 Mirroring is done relative to the current direction of the GUI.
459 @param bMirrored sal_True = the control will draw itself RTL in LTR GUI,
460 and vice versa; sal_False = the control behaves according to the
461 current direction of the GUI. */
462 void SetMirrored(bool bMirrored
);
463 /** Returns true, if the control is set to mirrored mode (see SetMirrored()). */
464 bool IsMirrored() const { return mbMirrored
; }
466 /** Sets the control to LTR or RTL mode regardless of the GUI direction.
467 @param bRTL sal_False = the control will draw from left to right;
468 sal_True = the control will draw from right to left. */
469 void SetEffectiveRTL( bool bRTL
);
470 /** Returns true, if the control draws from right to left (see SetEffectiveRTL()). */
471 bool IsEffectiveRTL() const;
473 bool StartDrag( const CommandEvent
& rCEvt
, vcl::Region
& rRegion
);
474 sal_uInt16
ShowDropPos( const Point
& rPos
);
476 void SwitchPage( const Point
& rPos
);
477 void EndSwitchPage();
479 virtual void SetPageText( sal_uInt16 nPageId
, const OUString
& rText
);
480 const OUString
& GetPageText( sal_uInt16 nPageId
) const;
481 OUString
GetHelpText( sal_uInt16 nPageId
) const;
483 tools::Long
GetSplitSize() const { return mnSplitSize
; }
485 using Window::SetHelpText
;
486 using Window::GetHelpText
;
487 using Window::SetHelpId
;
488 using Window::GetHelpId
;
490 void SetStyle( WinBits nStyle
);
491 WinBits
GetStyle() const { return mnWinStyle
; }
493 void SetScrollAlwaysEnabled(bool bScrollAlwaysEnabled
);
495 Size
CalcWindowSizePixel() const;
497 void SetSelectHdl( const Link
<TabBar
*,void>& rLink
) { maSelectHdl
= rLink
; }
498 void SetSplitHdl( const Link
<TabBar
*,void>& rLink
) { maSplitHdl
= rLink
; }
499 void SetScrollAreaContextHdl( const Link
<const CommandEvent
&,void>& rLink
) { maScrollAreaContextHdl
= rLink
; }
500 void SetAddButtonEnabled(bool bAddButtonEnabled
);
503 virtual css::uno::Reference
<css::accessibility::XAccessible
> CreateAccessible() override
;
506 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */