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          (long(1000000000))
203 
204 #define HEADERBAR_TEXTOFF           2
205 
206 
207 class VCL_DLLPUBLIC HeaderBar : public vcl::Window
208 {
209 private:
210     std::vector<std::unique_ptr<ImplHeadItem>> mvItemList;
211     long                mnBorderOff1;
212     long                mnBorderOff2;
213     long                mnOffset;
214     long                mnDX;
215     long                mnDY;
216     long                mnDragSize;
217     long                mnStartPos;
218     long                mnDragPos;
219     long                mnMouseOff;
220     sal_uInt16          mnCurItemId;
221     sal_uInt16          mnItemDragPos;
222     bool                mbDragable;
223     bool                mbDrag;
224     bool                mbItemDrag;
225     bool                mbOutDrag;
226     bool                mbButtonStyle;
227     bool                mbItemMode;
228     Link<HeaderBar*,void> maStartDragHdl;
229     Link<HeaderBar*,void> maDragHdl;
230     Link<HeaderBar*,void> maEndDragHdl;
231     Link<HeaderBar*,void> maSelectHdl;
232     Link<HeaderBar*,void> maCreateAccessibleHdl;
233 
234     css::uno::Reference< css::accessibility::XAccessible >
235                           mxAccessible;
236 
237     using Window::ImplInit;
238     VCL_DLLPRIVATE void             ImplInit( WinBits nWinStyle );
239     VCL_DLLPRIVATE void             ImplInitSettings( bool bFont, bool bForeground, bool bBackground );
240     VCL_DLLPRIVATE long             ImplGetItemPos( sal_uInt16 nPos ) const;
241     VCL_DLLPRIVATE tools::Rectangle ImplGetItemRect( sal_uInt16 nPos ) const;
242     using Window::ImplHitTest;
243     VCL_DLLPRIVATE sal_uInt16       ImplHitTest( const Point& rPos, long& nMouseOff, sal_uInt16& nPos ) const;
244     VCL_DLLPRIVATE void             ImplInvertDrag( sal_uInt16 nStartPos, sal_uInt16 nEndPos );
245     VCL_DLLPRIVATE void             ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, bool bHigh,
246                                                  const tools::Rectangle& rItemRect, const tools::Rectangle* pRect);
247     VCL_DLLPRIVATE void             ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, bool bHigh,
248                                                  const tools::Rectangle* pRect);
249     VCL_DLLPRIVATE void             ImplUpdate( sal_uInt16 nPos,
250                                        bool bEnd = false );
251     VCL_DLLPRIVATE void             ImplStartDrag( const Point& rPos, bool bCommand );
252     VCL_DLLPRIVATE void             ImplDrag( const Point& rPos );
253     VCL_DLLPRIVATE void             ImplEndDrag( bool bCancel );
254 
255     virtual void ApplySettings(vcl::RenderContext& rRenderContext) override;
256 
257 public:
258     HeaderBar( vcl::Window* pParent, WinBits nWinBits );
259     virtual ~HeaderBar() override;
260 
261     virtual void        MouseButtonDown( const MouseEvent& rMEvt ) override;
262     virtual void        MouseMove( const MouseEvent& rMEvt ) override;
263     virtual void        Tracking( const TrackingEvent& rTEvt ) override;
264     virtual void        Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
265     virtual void        Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, DrawFlags nFlags ) override;
266     virtual void        Resize() override;
267     virtual void        Command( const CommandEvent& rCEvt ) override;
268     virtual void        RequestHelp( const HelpEvent& rHEvt ) override;
269     virtual void        StateChanged( StateChangedType nStateChange ) override;
270     virtual void        DataChanged( const DataChangedEvent& rDCEvt ) override;
271 
272     virtual Size        GetOptimalSize() const override;
273 
274     virtual void        EndDrag();
275     virtual void        Select();
276     virtual void        DoubleClick();
277 
278     void                InsertItem( sal_uInt16 nItemId, const OUString& rText,
279                                     long nSize, HeaderBarItemBits nBits = HeaderBarItemBits::STDSTYLE,
280                                     sal_uInt16 nPos = HEADERBAR_APPEND );
281     void                RemoveItem( sal_uInt16 nItemId );
282     void                MoveItem( sal_uInt16 nItemId, sal_uInt16 nNewPos );
283     void                Clear();
284 
285     void                SetOffset( long nNewOffset );
SetDragSize(long nNewSize)286     void         SetDragSize( long nNewSize ) { mnDragSize = nNewSize; }
287 
288     sal_uInt16          GetItemCount() const;
289     sal_uInt16          GetItemPos( sal_uInt16 nItemId ) const;
290     sal_uInt16          GetItemId( sal_uInt16 nPos ) const;
291     sal_uInt16          GetItemId( const Point& rPos ) const;
292     tools::Rectangle           GetItemRect( sal_uInt16 nItemId ) const;
GetCurItemId() const293     sal_uInt16          GetCurItemId() const { return mnCurItemId; }
IsItemMode() const294     bool                IsItemMode() const { return mbItemMode; }
295 
296     void                SetItemSize( sal_uInt16 nItemId, long nNewSize );
297     long                GetItemSize( sal_uInt16 nItemId ) const;
298     void                SetItemBits( sal_uInt16 nItemId, HeaderBarItemBits nNewBits );
299     HeaderBarItemBits   GetItemBits( sal_uInt16 nItemId ) const;
300 
301     void                SetItemText( sal_uInt16 nItemId, const OUString& rText );
302     OUString            GetItemText( sal_uInt16 nItemId ) const;
303 
304     OUString            GetHelpText( sal_uInt16 nItemId ) const;
305 
306     Size                CalcWindowSizePixel() const;
307 
308     using Window::SetHelpId;
309 
SetStartDragHdl(const Link<HeaderBar *,void> & rLink)310     void         SetStartDragHdl( const Link<HeaderBar*,void>& rLink )      { maStartDragHdl = rLink; }
SetEndDragHdl(const Link<HeaderBar *,void> & rLink)311     void         SetEndDragHdl( const Link<HeaderBar*,void>& rLink )        { maEndDragHdl = rLink; }
SetSelectHdl(const Link<HeaderBar *,void> & rLink)312     void         SetSelectHdl( const Link<HeaderBar*,void>& rLink )         { maSelectHdl = rLink; }
SetCreateAccessibleHdl(const Link<HeaderBar *,void> & rLink)313     void         SetCreateAccessibleHdl( const Link<HeaderBar*,void>& rLink ) { maCreateAccessibleHdl = rLink; }
314 
IsDragable() const315     bool         IsDragable() const                          { return mbDragable; }
316 
317     /** Creates and returns the accessible object of the header bar. */
318     virtual css::uno::Reference< css::accessibility::XAccessible >  CreateAccessible() override;
319     void SetAccessible( const css::uno::Reference< css::accessibility::XAccessible >& );
320 };
321 
322 #endif // INCLUDED_VCL_HEADBAR_HXX
323 
324 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
325