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 #pragma once
21 
22 #include <svtools/svtdllapi.h>
23 #include <tools/wintypes.hxx>
24 #include <vcl/customweld.hxx>
25 #include <vcl/image.hxx>
26 #include <memory>
27 #include <vector>
28 
29 class MouseEvent;
30 class TrackingEvent;
31 class HelpEvent;
32 class KeyEvent;
33 class DataChangedEvent;
34 class ScrollBar;
35 class UserDrawEvent;
36 class VirtualDevice;
37 
38 struct ValueSetItem;
39 
40 enum class DrawFrameStyle;
41 
42 /*************************************************************************
43 
44 Description
45 ============
46 
47 class ValueSet
48 
49 This class allows the selection of an item. In the process items are
50 drawn side by side. The selection of items can be more clear than in a
51 ListBox shape for example in case of colors or samples.
52 The amount of columns drawn by the control and whether the items
53 should be encircled can be specified. Optional a NoSelection or name
54 field could be shown. By default image and color items are supported.
55 Items could be drawn by oneself if InsertItem() is only called with
56 an ID. To achieve this the UserDraw handler needs to be overridden. The
57 description text could be specified afterwards in case of UserDraw
58 and any other items.
59 
60 Cross references
61 
62 class ListBox
63 
64 --------------------------------------------------------------------------
65 
66 WinBits
67 
68 WB_RADIOSEL         If set the selection will be drawn like an
69                     RadioButton. This does only make sense if the image
70                     is at least 8 pixel smaller on each side than the item
71                     and also WB_DOUBLEBORDER is set and as color
72                     COL_WINDOWWORKSPACE is specified.
73 WB_FLATVALUESET     Flat Look (if you set WB_ITEMBORDER or WB_DOUBLEBORDER,
74                     then you get extra border space, but the Borders
75                     aren't painted),
76 WB_ITEMBORDER       Items will be bordered
77 WB_DOUBLEBORDER     Items will be bordered twice. Additionally WB_ITEMBORDER
78                     has to be set, as otherwise this WinBit wouldn't have any
79                     effect. It is needed if there are items with a white
80                     background, since otherwise the 3D effect wouldn't be
81                     recognizable.
82 WB_NAMEFIELD        There is a namefield, where the name of an item will be
83                     shown.
84 WB_NONEFIELD        There is a NoSelection field which can be selected if
85                     0 is passed along with SelectItem. Respectively
86                     GetSelectedItemId() returns 0 if this field or nothing
87                     is selected. This field shows the text which is specified
88                     by SetText() respectively no one, if no text was set. With
89                     SetNoSelection() the selection can be disabled.
90 WB_VSCROLL          A scrollbar will be always shown. The visible number of
91                     lines have to be specified with SetLineCount() if this
92                     flag is set.
93 WB_BORDER           A border will be drawn around the window.
94 WB_NOPOINTERFOCUS   The focus won't be gathered, if the control was pressed by
95                     the mouse.
96 WB_TABSTOP          It is possible to jump into the ValueSet with the tab key.
97 WB_NOTABSTOP        It is not possible to jump into the ValueSet with the
98                     tab key.
99 WB_NO_DIRECTSELECT  Cursor travelling doesn't call select immediately. To
100                     execute the selection <RETURN> has to be pressed.
101 --------------------------------------------------------------------------
102 
103 The number of columns must be either set with SetColCount() or
104 SetItemWidth(). If the number of columns is specified by SetColCount()
105 the width of the items will be calculated by the visible range.
106 If the items should have a static width, it has to be specified
107 with SetItemWidth(). In this case the number of columns will be calculated
108 by the visible range.
109 
110 The number of rows is given by the number of items / number of columns. The
111 number of visible rows must either specified by SetLineCount() or
112 SetItemWidth(). If the number of visible rows is specified by SetLineCount(),
113 the height of the items will be calculated from the visible height. If the
114 items should have a fixed height it has to be specified with SetItemHeight().
115 In this case the number of visible rows is then calculated from the visible
116 height. If the number of visible rows is neither specified by SetLineCount()
117 nor by SetItemHeight() all rows will be shown. The height of the items will
118 be calculated by the visible height. If the number of visible rows is
119 specified by SetLineCount() or SetItemHeight() ValueSet does scroll
120 automatically when more lines are available, as are visible. If scrolling
121 should be also possible with a ScrollBar  WB_VSCROLL needs to be set.
122 
123 The distance between the items can be increased by SetExtraSpacing(). The
124 distance, which will be shown between two items (both in x and in y), is
125 measured in pixels.
126 
127 The exact window size for a specific item size can be calculated by
128 CalcWindowSizePixel(). To do this all relevant data (number of columns/...)
129 have to be specified and if no number of rows was set, all items need to
130 be inserted. If the window was created with WB_BORDER/Border=sal_True the
131 size has to be specified with SetOutputSizePixel(). In other cases different
132 size-methods can be used. With CalcItemSize() the inner and outer size of
133 an item could be calculated (for this the free space defined by
134 SetExtraSpacing() will not be included).
135 
136 The background color could be specified by SetColor(), with which the image
137 or UserDraw items will be underlaid. If no color is specified the color
138 of other windows (WindowColor) will be used for the background.
139 
140 --------------------------------------------------------------------------
141 
142 At first all items should be inserted and only then Show() should be called
143 since the output area will be precomputed. If this is not done the first
144 Paint will appear a little bit slower. Therefore the Control, if it is loaded
145 from the resource and only supplied with items during runtime, should be
146 loaded with Hide = sal_True and then displayed with Show().
147 
148 In case of a visible Control the creation of the new output area could be
149 activated before Paint by calling Format().
150 
151 --------------------------------------------------------------------------
152 
153 If Drag and Drop will be called from the ValueSet the Command-Handler has to
154 be overridden. From this StartDrag needs to be called. If this method returns
155 sal_True the drag-process could be initiated by  ExecuteDrag(), otherwise no
156 processing will take place. This method makes sure that ValueSet stops its
157 processing and as appropriate selects the entry. Therefore the calling of
158 Select-Handler within this function must be expected.
159 
160 For dropping QueryDrop() and Drop() need to be overridden and ShowDropPos()
161 and HideDropPos() should be called within these methods.
162 To show the insertion point ShowDropPos() has to be called within the
163 QueryDrop-Handler. ShowDropPos() also scrolls the ValueSet if the passed
164 position is located at the window border. Furthermore ShowDropPos() returns
165 the position, at which the item should be inserted respectively which
166 insertion point was shown. If no insertion point was determined
167 VALUESET_ITEM_NOTFOUND will be returned. If the window was left during dragging
168 or the drag process is terminated HideDropPos() should be called in any case.
169 
170 --------------------------------------------------------------------------
171 
172 This class is currently still in the SV-Tools. That's why the ValueSet needs
173 to be loaded as a Control out of the resource and the desired WinBits have
174 to be set (before Show) with SetStyle().
175 
176 *************************************************************************/
177 
178 typedef std::vector<std::unique_ptr<ValueSetItem>> ValueItemList;
179 
180 #define WB_ITEMBORDER           (WinBits(0x00010000))
181 #define WB_DOUBLEBORDER         (WinBits(0x00020000))
182 #define WB_NAMEFIELD            (WinBits(0x00040000))
183 #define WB_NONEFIELD            (WinBits(0x00080000))
184 #define WB_FLATVALUESET         (WinBits(0x02000000))
185 #define WB_NO_DIRECTSELECT      (WinBits(0x04000000))
186 #define WB_MENUSTYLEVALUESET    (WinBits(0x08000000))
187 
188 #define VALUESET_APPEND         (size_t(-1))
189 #define VALUESET_ITEM_NOTFOUND  (size_t(-1))
190 
191 class SVT_DLLPUBLIC ValueSet : public weld::CustomWidgetController
192 {
193 private:
194     ScopedVclPtr<VirtualDevice> maVirDev;
195     css::uno::Reference<css::accessibility::XAccessible> mxAccessible;
196     ValueItemList   mItemList;
197     std::unique_ptr<ValueSetItem> mpNoneItem;
198     std::unique_ptr<weld::ScrolledWindow> mxScrolledWindow;
199     tools::Rectangle  maNoneItemRect;
200     tools::Rectangle  maItemListRect;
201     tools::Long            mnItemWidth;
202     tools::Long            mnItemHeight;
203     tools::Long            mnTextOffset;
204     tools::Long            mnVisLines;
205     tools::Long            mnLines;
206     tools::Long            mnUserItemWidth;
207     tools::Long            mnUserItemHeight;
208     sal_uInt16      mnSelItemId;
209     int             mnSavedItemId;
210     sal_uInt16      mnHighItemId;
211     sal_uInt16      mnCols;
212     sal_uInt16      mnCurCol;
213     sal_uInt16      mnUserCols;
214     sal_uInt16      mnUserVisLines;
215     sal_uInt16      mnFirstLine;
216     sal_uInt16      mnSpacing;
217     DrawFrameStyle  mnFrameStyle;
218     Color           maColor;
219     OUString        maText;
220     WinBits         mnStyle;
221     Link<ValueSet*,void>  maDoubleClickHdl;
222     Link<ValueSet*,void>  maSelectHdl;
223 
224     bool            mbFormat : 1;
225     bool            mbHighlight : 1;
226     bool            mbNoSelection : 1;
227     bool            mbDrawSelection : 1;
228     bool            mbBlackSel : 1;
229     bool            mbDoubleSel : 1;
230     bool            mbScroll : 1;
231     bool            mbFullMode : 1;
232     bool            mbEdgeBlending : 1;
233     bool            mbHasVisibleItems : 1;
234 
235     friend class ValueItemAcc;
236     friend class ValueSetAcc;
237 
238     SVT_DLLPRIVATE void         ImplDeleteItems();
239     SVT_DLLPRIVATE void         ImplFormatItem(vcl::RenderContext const & rRenderContext, ValueSetItem* pItem, tools::Rectangle aRect);
240     SVT_DLLPRIVATE void         ImplDrawItemText(vcl::RenderContext& rRenderContext, const OUString& rStr);
241     SVT_DLLPRIVATE void         ImplDrawSelect(vcl::RenderContext& rRenderContext, sal_uInt16 nItemId, const bool bFocus, const bool bDrawSel);
242     SVT_DLLPRIVATE void         ImplDrawSelect(vcl::RenderContext& rRenderContext);
243     SVT_DLLPRIVATE void         ImplHighlightItem(sal_uInt16 nItemId, bool bIsSelection = true);
244     SVT_DLLPRIVATE void         ImplDraw(vcl::RenderContext& rRenderContext);
245     SVT_DLLPRIVATE size_t       ImplGetItem( const Point& rPoint ) const;
246     SVT_DLLPRIVATE ValueSetItem*    ImplGetItem( size_t nPos );
247     SVT_DLLPRIVATE ValueSetItem*    ImplGetFirstItem();
248     SVT_DLLPRIVATE sal_uInt16          ImplGetVisibleItemCount() const;
249     SVT_DLLPRIVATE void         ImplInsertItem( std::unique_ptr<ValueSetItem> pItem, const size_t nPos );
250     SVT_DLLPRIVATE tools::Rectangle    ImplGetItemRect( size_t nPos ) const;
251     SVT_DLLPRIVATE void         ImplFireAccessibleEvent( short nEventId, const css::uno::Any& rOldValue, const css::uno::Any& rNewValue );
252     SVT_DLLPRIVATE bool         ImplHasAccessibleListeners();
253     SVT_DLLPRIVATE void         ImplTracking(const Point& rPos);
254     SVT_DLLPRIVATE void         QueueReformat();
255     SVT_DLLPRIVATE void         SetFirstLine(sal_uInt16 nNewFirstLine); // set mnFirstLine and update scrollbar to match
256     SVT_DLLPRIVATE void         RecalcScrollBar();
257     SVT_DLLPRIVATE bool         TurnOffScrollBar();
258     SVT_DLLPRIVATE void         TurnOnScrollBar();
259     DECL_DLLPRIVATE_LINK(ImplScrollHdl, weld::ScrolledWindow&, void);
260 
261     Size           GetLargestItemSize();
262 
263     ValueSet (const ValueSet &) = delete;
264     ValueSet & operator= (const ValueSet &) = delete;
265 
266 protected:
267     virtual css::uno::Reference<css::accessibility::XAccessible> CreateAccessible() override;
GetScrollBar() const268     weld::ScrolledWindow* GetScrollBar() const { return mxScrolledWindow.get(); }
269 
270 public:
271     ValueSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow);
272     virtual         ~ValueSet() override;
273 
274     virtual void    SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
275 
276     virtual bool    MouseButtonDown( const MouseEvent& rMEvt ) override;
277     virtual bool    MouseButtonUp( const MouseEvent& rMEvt ) override;
278     virtual bool    MouseMove( const MouseEvent& rMEvt ) override;
279     virtual bool    KeyInput( const KeyEvent& rKEvt ) override;
280     virtual void    Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
281     virtual void    GetFocus() override;
282     virtual void    LoseFocus() override;
283     virtual void    Resize() override;
284     virtual void    StyleUpdated() override;
285     virtual void    Show() override;
286     virtual void    Hide() override;
287     virtual OUString RequestHelp(tools::Rectangle& rHelpRect) override;
288 
289     virtual void    Select();
290     virtual void    UserDraw( const UserDrawEvent& rUDEvt );
291 
GetText() const292     OUString const & GetText() const { return maText; }
SetText(const OUString & rText)293     void            SetText(const OUString& rText) { maText = rText; }
294     void            SetStyle(WinBits nStyle);
GetStyle() const295     WinBits         GetStyle() const { return mnStyle; }
296 
297     void SetOptimalSize();
298 
299     /// Insert @rImage item.
300     void            InsertItem(sal_uInt16 nItemId, const Image& rImage);
301     /// Insert @rImage item with @rStr as either a legend or tooltip depending on @bShowLegend.
302     void            InsertItem(sal_uInt16 nItemId, const Image& rImage,
303                                const OUString& rStr, size_t nPos = VALUESET_APPEND, bool bShowLegend = false);
304     /// Insert an @rColor item with @rStr tooltip.
305     void            InsertItem(sal_uInt16 nItemId, const Color& rColor,
306                                const OUString& rStr);
307     /// Insert an User Drawn item.
308     void            InsertItem(sal_uInt16 nItemId, size_t nPos = VALUESET_APPEND);
309     /// Insert an User Drawn item with @rStr tooltip.
310     void            InsertItem(sal_uInt16 nItemId, const OUString& rStr, size_t nPos);
311     void            RemoveItem(sal_uInt16 nItemId);
312 
313     void            Clear();
314 
315     size_t          GetItemCount() const;
316     size_t          GetItemPos( sal_uInt16 nItemId ) const;
317     sal_uInt16      GetItemId( size_t nPos ) const;
318     sal_uInt16      GetItemId( const Point& rPos ) const;
319     tools::Rectangle       GetItemRect( sal_uInt16 nItemId ) const;
320     void            EnableFullItemMode( bool bFullMode );
321 
322     void            SetColCount( sal_uInt16 nNewCols = 1 );
GetColCount() const323     sal_uInt16      GetColCount() const
324     {
325         return mnUserCols;
326     }
327     void            SetLineCount( sal_uInt16 nNewLines = 0 );
GetLineCount() const328     sal_uInt16      GetLineCount() const
329     {
330         return mnUserVisLines;
331     }
332     void           SetItemWidth( tools::Long nItemWidth );
333     void           SetItemHeight( tools::Long nLineHeight );
334 
335     void           SelectItem( sal_uInt16 nItemId );
GetSelectedItemId() const336     sal_uInt16     GetSelectedItemId() const
337     {
338         return mnSelItemId;
339     }
GetSelectItemPos() const340     size_t         GetSelectItemPos() const
341     {
342         return GetItemPos( mnSelItemId );
343     }
IsItemSelected(sal_uInt16 nItemId) const344     bool IsItemSelected( sal_uInt16 nItemId ) const
345     {
346         return !mbNoSelection && (nItemId == mnSelItemId);
347     }
348     void SetNoSelection();
IsNoSelection() const349     bool IsNoSelection() const
350     {
351         return mbNoSelection;
352     }
353 
354     void            RecalculateItemSizes();
355 
356     void            SetItemImage( sal_uInt16 nItemId, const Image& rImage );
357     Image           GetItemImage( sal_uInt16 nItemId ) const;
358     void            SetItemColor( sal_uInt16 nItemId, const Color& rColor );
359     Color           GetItemColor( sal_uInt16 nItemId ) const;
360     void            SetItemData( sal_uInt16 nItemId, void* pData );
361     void*           GetItemData( sal_uInt16 nItemId ) const;
362     void            SetItemText( sal_uInt16 nItemId, const OUString& rStr );
363     OUString        GetItemText( sal_uInt16 nItemId ) const;
364     void            SetColor( const Color& rColor );
SetColor()365     void            SetColor()
366     {
367         SetColor(COL_TRANSPARENT);
368     }
IsColor() const369     bool            IsColor() const
370     {
371         return !maColor.IsTransparent();
372     }
373 
374     void            SetExtraSpacing( sal_uInt16 nNewSpacing );
375 
376     void            Format(vcl::RenderContext const & rRenderContext);
377     void            SetFormat();
378 
379     Size            CalcWindowSizePixel(const Size& rItemSize,
380                                         sal_uInt16 nCalcCols = 0,
381                                         sal_uInt16 nCalcLines = 0) const;
382     Size            CalcItemSizePixel(const Size& rSize) const;
383     int             GetScrollWidth() const;
384 
SetSelectHdl(const Link<ValueSet *,void> & rLink)385     void            SetSelectHdl(const Link<ValueSet*,void>& rLink)
386     {
387         maSelectHdl = rLink;
388     }
389 
SetDoubleClickHdl(const Link<ValueSet *,void> & rLink)390     void            SetDoubleClickHdl(const Link<ValueSet*,void>& rLink)
391     {
392         maDoubleClickHdl = rLink;
393     }
394 
GetEdgeBlending() const395     bool GetEdgeBlending() const
396     {
397         return mbEdgeBlending;
398     }
399     void SetEdgeBlending(bool bNew);
400 
SaveValue()401     void SaveValue()
402     {
403         mnSavedItemId = IsNoSelection() ? -1 : GetSelectedItemId();
404     }
405 
IsValueChangedFromSaved() const406     bool IsValueChangedFromSaved() const
407     {
408         int nItemId = IsNoSelection() ? -1 : GetSelectedItemId();
409         return mnSavedItemId != nItemId;
410     }
411 
412     virtual FactoryFunction GetUITestFactory() const override;
413 };
414 
415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
416