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 #ifndef INCLUDED_VCL_HEADBAR_HXX
21 #define INCLUDED_VCL_HEADBAR_HXX
22 
23 #include <vcl/dllapi.h>
24 #include <tools/link.hxx>
25 #include <vcl/window.hxx>
26 #include <o3tl/typed_flags_set.hxx>
27 #include <memory>
28 
29 /*************************************************************************
30 
31 Description
32 ============
33 
34 class HeaderBar
35 
36 This class serves for displaying a header bar. A header bar can display
37 texts, images or both of them. The items can be changed in size, dragged or
38 clicked at. In many cases, it makes, for example, sense to use this control
39 in combination with a SvTabListBox.
40 
41 --------------------------------------------------------------------------
42 
43 WinBits
44 
45 WB_BORDER           a border is drawn in the top and in the bottom
46 WB_BOTTOMBORDER     a border is drawn in the bottom
47 WB_BUTTONSTYLE      The items look like buttons, otherwise they are flat.
48 WB_3DLOOK           3D look
49 WB_DRAG             items can be dragged
50 WB_STDHEADERBAR     WB_BUTTONSTYLE | WB_BOTTOMBORDER
51 
52 --------------------------------------------------------------------------
53 
54 ItemBits
55 
56 HeaderBarItemBits::LEFT            content is displayed in the item left-justified
57 HeaderBarItemBits::CENTER          content is displayed in the item centred
58 HeaderBarItemBits::RIGHT           content is displayed in the item right-justified
59 HeaderBarItemBits::TOP             content is displayed in the item at the upper border
60 HeaderBarItemBits::VCENTER         content is displayed in the item vertically centred
61 HeaderBarItemBits::BOTTOM          content is displayed in the item at the bottom border
62 HeaderBarItemBits::LEFTIMAGE       in case of text and image, the image is displayed left of the text
63 HeaderBarItemBits::RIGHTIMAGE      in case of text and image, the image is displayed right of the text
64 HeaderBarItemBits::FIXED           item cannot be changed in size
65 HeaderBarItemBits::FIXEDPOS        item cannot be moved
66 HeaderBarItemBits::CLICKABLE       item is clickable
67                     (select handler is only called on MouseButtonUp)
68 HeaderBarItemBits::FLAT            item is displayed in a flat way, even if WB_BUTTONSTYLE is set
69 HeaderBarItemBits::DOWNARROW       An arrow pointing downwards is displayed behind the text,
70                     which should, for example, be shown, when after this item,
71                     a corresponding list is sorted in descending order.
72                     The status of the arrow can be set/reset with SetItemBits().
73 HeaderBarItemBits::UPARROW         An arrow pointing upwards is displayed behind the text,
74                     which should, for example, be shown, when after this item,
75                     a corresponding list is sorted in ascending order.
76                     The status of the arrow can be set/reset with SetItemBits().
77 HeaderBarItemBits::USERDRAW        For this item, the UserDraw handler is called as well.
78 HeaderBarItemBits::STDSTYLE        (HeaderBarItemBits::LEFT | HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::CLICKABLE)
79 
80 --------------------------------------------------------------------------
81 
82 Handler
83 
84 Select()            Is called, when the item is clicked. If HeaderBarItemBits::CLICKABLE
85                     is set in the item and not HeaderBarItemBits::FLAT, the handler is only
86                     called in the MouseButtonUp handler, when the mouse has been
87                     released over the item. In this case, the Select handler
88                     behaves like it does with a ToolBox button.
89 DoubleClick()       This handler is called, when an item is double-clicked.
90                     Whether the item or the separator has been clicked, can
91                     be determined by IsItemMode(). Normally, when a separator
92                     is double-clicked, the optimal column width should be
93                     calculated and should be set.
94 StartDrag()         This handler is called, when dragging is started resp.
95                     an item has been clicked. At the latest in this handler,
96                     the size of the size-line should be set with
97                     SetDragSize(), if IsItemMode() returns false.
98 Drag()              This handler is called, when dragging is taking place.
99                     If no size is set with SetDragSize(), this handler can
100                     be used to draw the line in the neighbouring window by
101                     oneself. The current dragging position can be requested
102                     with GetDragPos(). In every case, IsItemMode()
103                     should be checked to find out whether a separator is
104                     dragged as well.
105 EndDrag()           This handler is called, when a dragging process has been
106                     stopped. If GetCurItemId() returns 0 in the EndDrag handler,
107                     the drag process was aborted. If this is not the case and
108                     IsItemMode() returns false, the new size of the dragged
109                     item should be requested using GetItemSize() and it
110                     should be taken over in the corresponding control.
111                     If IsItemMode() returns true, GetCurItemId()
112                     returns an Id and IsItemDrag() returns true, this
113                     item has been dragged. In this case, the new position
114                     should be requested using  GetItemPos() and the data
115                     in the corresponding control should be adapted.
116                     Otherwise, the position to which the item has been dragged
117                     could also be requested with GetItemDragPos().
118 
119 Further methods that are important for the handler.
120 
121 GetCurItemId()      Returns the id of the item, for which the handler has
122                     currently been called. Only returns a valid id in the
123                     handlers Select(), DoubleClick(), StartDrag(),
124                     Drag() and EndDrag(). In the EndDrag handler,
125                     this method returns the id of the dragged item or 0,
126                     if the drag process has been aborted.
127 GetItemDragPos()    Returns the position, at which an item has been moved.
128                     HEADERBAR_ITEM_NOTFOUND is returned, if the process
129                     has been aborted or no ItemDrag is active.
130 IsItemMode()        This method can be used to determine whether the
131                     handler has been called for an item or a separator.
132                     true    - handler was called for the item
133                     false   - handler was called for the separator
134 IsItemDrag()        This method can be used to determine whether an item
135                     has been dragged or selected.
136                     true    - item is dragged
137                     false   - item is selected
138 SetDragSize()       This method is used to set the size of the separating
139                     line that is drawn by the control. It should be
140                     equivalent to the height of the neighbouring window.
141                     The height of the HeaderBar is added automatically.
142 
143 --------------------------------------------------------------------------
144 
145 Further methods
146 
147 SetOffset()             This method sets the offset, from which on the
148                         items are shown. This is needed when the
149                         corresponding window is scrolled.
150 CalcWindowSizePixel()   This method can be used to calculate the height
151                         of the window, so that the content of the item
152                         can be displayed.
153 
154 --------------------------------------------------------------------------
155 
156 Tips and tricks:
157 
158 1) ContextMenu
159 If a context sensitive PopupMenu should be shown, the command
160 handler must be overlaid. Using GetItemId() and when passing the
161 mouse position, it can be determined whether the mouse click has been
162 carried out over an item resp. over which item the mouse click has been
163 carried out.
164 
165 2) last item
166 If ButtonStyle has been set, it looks better, if an empty item is
167 set at the end which takes up the remaining space.
168 In order to do that, you can insert an item with an empty string and
169 pass HEADERBAR_FULLSIZE as size. For such an item, you should not set
170 HeaderBarItemBits::CLICKABLE, but HeaderBarItemBits::FIXEDPOS.
171 
172 *************************************************************************/
173 
174 class ImplHeadItem;
175 
176 #define WB_BOTTOMBORDER         (WinBits(0x0400))
177 #define WB_BUTTONSTYLE          (WinBits(0x0800))
178 #define WB_STDHEADERBAR         (WB_BUTTONSTYLE | WB_BOTTOMBORDER)
179 
180 enum class HeaderBarItemBits
181 {
182     NONE                = 0x0000,
183     LEFT                = 0x0001,
184     CENTER              = 0x0002,
185     RIGHT               = 0x0004,
186     LEFTIMAGE           = 0x0010,
187     RIGHTIMAGE          = 0x0020,
188     CLICKABLE           = 0x0400,
189     FLAT                = 0x0800,
190     DOWNARROW           = 0x1000,
191     UPARROW             = 0x2000,
192     STDSTYLE            = LEFT | LEFTIMAGE | CLICKABLE,
193 };
194 
195 namespace o3tl
196 {
197     template<> struct typed_flags<HeaderBarItemBits> : is_typed_flags<HeaderBarItemBits, 0x3c37> {};
198 }
199 
200 #define HEADERBAR_APPEND            (sal_uInt16(0xFFFF))
201 #define HEADERBAR_ITEM_NOTFOUND     (sal_uInt16(0xFFFF))
202 #define HEADERBAR_FULLSIZE          (tools::Long(1000000000))
203 
204 class VCL_DLLPUBLIC HeaderBar : public vcl::Window
205 {
206 private:
207     std::vector<std::unique_ptr<ImplHeadItem>> mvItemList;
208     tools::Long                mnBorderOff1;
209     tools::Long                mnBorderOff2;
210     tools::Long                mnOffset;
211     tools::Long                mnDX;
212     tools::Long                mnDY;
213     tools::Long                mnDragSize;
214     tools::Long                mnStartPos;
215     tools::Long                mnDragPos;
216     tools::Long                mnMouseOff;
217     sal_uInt16          mnCurItemId;
218     sal_uInt16          mnItemDragPos;
219     bool                mbDragable;
220     bool                mbDrag;
221     bool                mbItemDrag;
222     bool                mbOutDrag;
223     bool                mbButtonStyle;
224     bool                mbItemMode;
225     Link<HeaderBar*,void> maStartDragHdl;
226     Link<HeaderBar*,void> maEndDragHdl;
227     Link<HeaderBar*,void> maSelectHdl;
228     Link<HeaderBar*,void> maCreateAccessibleHdl;
229 
230     css::uno::Reference< css::accessibility::XAccessible >
231                           mxAccessible;
232 
233     using Window::ImplInit;
234     VCL_DLLPRIVATE void             ImplInit( WinBits nWinStyle );
235     VCL_DLLPRIVATE void             ImplInitSettings( bool bFont, bool bForeground, bool bBackground );
236     VCL_DLLPRIVATE tools::Long             ImplGetItemPos( sal_uInt16 nPos ) const;
237     VCL_DLLPRIVATE tools::Rectangle ImplGetItemRect( sal_uInt16 nPos ) const;
238     VCL_DLLPRIVATE sal_uInt16       ImplDoHitTest( const Point& rPos, tools::Long& nMouseOff, sal_uInt16& nPos ) const;
239     VCL_DLLPRIVATE void             ImplInvertDrag( sal_uInt16 nStartPos, sal_uInt16 nEndPos );
240     VCL_DLLPRIVATE void             ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, bool bHigh,
241                                                  const tools::Rectangle& rItemRect, const tools::Rectangle* pRect);
242     VCL_DLLPRIVATE void             ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, bool bHigh,
243                                                  const tools::Rectangle* pRect);
244     VCL_DLLPRIVATE void             ImplUpdate( sal_uInt16 nPos,
245                                        bool bEnd = false );
246     VCL_DLLPRIVATE void             ImplStartDrag( const Point& rPos, bool bCommand );
247     VCL_DLLPRIVATE void             ImplDrag( const Point& rPos );
248     VCL_DLLPRIVATE void             ImplEndDrag( bool bCancel );
249 
250     virtual void ApplySettings(vcl::RenderContext& rRenderContext) override;
251 
252 public:
253     HeaderBar( vcl::Window* pParent, WinBits nWinBits );
254     virtual ~HeaderBar() override;
255 
256     virtual void        MouseButtonDown( const MouseEvent& rMEvt ) override;
257     virtual void        MouseMove( const MouseEvent& rMEvt ) override;
258     virtual void        Tracking( const TrackingEvent& rTEvt ) override;
259     virtual void        Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
260     virtual void        Draw( OutputDevice* pDev, const Point& rPos, DrawFlags nFlags ) override;
261     virtual void        Resize() override;
262     virtual void        Command( const CommandEvent& rCEvt ) override;
263     virtual void        RequestHelp( const HelpEvent& rHEvt ) override;
264     virtual void        StateChanged( StateChangedType nStateChange ) override;
265     virtual void        DataChanged( const DataChangedEvent& rDCEvt ) override;
266 
267     virtual Size        GetOptimalSize() const override;
268 
269     virtual void        EndDrag();
270     virtual void        Select();
271     virtual void        DoubleClick();
272 
273     void                InsertItem( sal_uInt16 nItemId, const OUString& rText,
274                                     tools::Long nSize, HeaderBarItemBits nBits = HeaderBarItemBits::STDSTYLE,
275                                     sal_uInt16 nPos = HEADERBAR_APPEND );
276     void                RemoveItem( sal_uInt16 nItemId );
277     void                MoveItem( sal_uInt16 nItemId, sal_uInt16 nNewPos );
278     void                Clear();
279 
280     void                SetOffset( tools::Long nNewOffset );
SetDragSize(tools::Long nNewSize)281     void         SetDragSize( tools::Long nNewSize ) { mnDragSize = nNewSize; }
282 
283     sal_uInt16          GetItemCount() const;
284     sal_uInt16          GetItemPos( sal_uInt16 nItemId ) const;
285     sal_uInt16          GetItemId( sal_uInt16 nPos ) const;
286     sal_uInt16          GetItemId( const Point& rPos ) const;
287     tools::Rectangle           GetItemRect( sal_uInt16 nItemId ) const;
GetCurItemId() const288     sal_uInt16          GetCurItemId() const { return mnCurItemId; }
IsItemMode() const289     bool                IsItemMode() const { return mbItemMode; }
290 
291     void                SetItemSize( sal_uInt16 nItemId, tools::Long nNewSize );
292     tools::Long                GetItemSize( sal_uInt16 nItemId ) const;
293     void                SetItemBits( sal_uInt16 nItemId, HeaderBarItemBits nNewBits );
294     HeaderBarItemBits   GetItemBits( sal_uInt16 nItemId ) const;
295 
296     void                SetItemText( sal_uInt16 nItemId, const OUString& rText );
297     OUString            GetItemText( sal_uInt16 nItemId ) const;
298 
299     OUString            GetHelpText( sal_uInt16 nItemId ) const;
300 
301     Size                CalcWindowSizePixel() const;
302 
303     using Window::SetHelpId;
304 
SetStartDragHdl(const Link<HeaderBar *,void> & rLink)305     void         SetStartDragHdl( const Link<HeaderBar*,void>& rLink )      { maStartDragHdl = rLink; }
SetEndDragHdl(const Link<HeaderBar *,void> & rLink)306     void         SetEndDragHdl( const Link<HeaderBar*,void>& rLink )        { maEndDragHdl = rLink; }
SetSelectHdl(const Link<HeaderBar *,void> & rLink)307     void         SetSelectHdl( const Link<HeaderBar*,void>& rLink )         { maSelectHdl = rLink; }
SetCreateAccessibleHdl(const Link<HeaderBar *,void> & rLink)308     void         SetCreateAccessibleHdl( const Link<HeaderBar*,void>& rLink ) { maCreateAccessibleHdl = rLink; }
309 
IsDragable() const310     bool         IsDragable() const                          { return mbDragable; }
311 
312     /** Creates and returns the accessible object of the header bar. */
313     virtual css::uno::Reference< css::accessibility::XAccessible >  CreateAccessible() override;
314     void SetAccessible( const css::uno::Reference< css::accessibility::XAccessible >& );
315 };
316 
317 #endif // INCLUDED_VCL_HEADBAR_HXX
318 
319 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
320