1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/ribbon/gallery.cpp
3 // Purpose:     Ribbon control which displays a gallery of items to choose from
4 // Author:      Peter Cawley
5 // Modified by:
6 // Created:     2009-07-22
7 // Copyright:   (C) Peter Cawley
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 #include "wx/wxprec.h"
12 
13 
14 #if wxUSE_RIBBON
15 
16 #include "wx/ribbon/gallery.h"
17 #include "wx/ribbon/art.h"
18 #include "wx/ribbon/bar.h"
19 #include "wx/dcbuffer.h"
20 #include "wx/clntdata.h"
21 
22 #ifndef WX_PRECOMP
23 #endif
24 
25 #ifdef __WXMSW__
26 #include "wx/msw/private.h"
27 #endif
28 
29 wxDEFINE_EVENT(wxEVT_RIBBONGALLERY_HOVER_CHANGED, wxRibbonGalleryEvent);
30 wxDEFINE_EVENT(wxEVT_RIBBONGALLERY_SELECTED, wxRibbonGalleryEvent);
31 wxDEFINE_EVENT(wxEVT_RIBBONGALLERY_CLICKED, wxRibbonGalleryEvent);
32 
33 wxIMPLEMENT_DYNAMIC_CLASS(wxRibbonGalleryEvent, wxCommandEvent);
34 wxIMPLEMENT_CLASS(wxRibbonGallery, wxRibbonControl);
35 
36 class wxRibbonGalleryItem
37 {
38 public:
wxRibbonGalleryItem()39     wxRibbonGalleryItem()
40     {
41         m_id = 0;
42         m_is_visible = false;
43     }
44 
SetId(int id)45     void SetId(int id) {m_id = id;}
SetBitmap(const wxBitmap & bitmap)46     void SetBitmap(const wxBitmap& bitmap) {m_bitmap = bitmap;}
GetBitmap() const47     const wxBitmap& GetBitmap() const {return m_bitmap;}
SetIsVisible(bool visible)48     void SetIsVisible(bool visible) {m_is_visible = visible;}
SetPosition(int x,int y,const wxSize & size)49     void SetPosition(int x, int y, const wxSize& size)
50     {
51         m_position = wxRect(wxPoint(x, y), size);
52     }
IsVisible() const53     bool IsVisible() const {return m_is_visible;}
GetPosition() const54     const wxRect& GetPosition() const {return m_position;}
55 
SetClientObject(wxClientData * data)56     void SetClientObject(wxClientData *data) {m_client_data.SetClientObject(data);}
GetClientObject() const57     wxClientData *GetClientObject() const {return m_client_data.GetClientObject();}
SetClientData(void * data)58     void SetClientData(void *data) {m_client_data.SetClientData(data);}
GetClientData() const59     void *GetClientData() const {return m_client_data.GetClientData();}
60 
61 protected:
62     wxBitmap m_bitmap;
63     wxClientDataContainer m_client_data;
64     wxRect m_position;
65     int m_id;
66     bool m_is_visible;
67 };
68 
wxBEGIN_EVENT_TABLE(wxRibbonGallery,wxRibbonControl)69 wxBEGIN_EVENT_TABLE(wxRibbonGallery, wxRibbonControl)
70     EVT_ENTER_WINDOW(wxRibbonGallery::OnMouseEnter)
71     EVT_ERASE_BACKGROUND(wxRibbonGallery::OnEraseBackground)
72     EVT_LEAVE_WINDOW(wxRibbonGallery::OnMouseLeave)
73     EVT_LEFT_DOWN(wxRibbonGallery::OnMouseDown)
74     EVT_LEFT_UP(wxRibbonGallery::OnMouseUp)
75     EVT_LEFT_DCLICK(wxRibbonGallery::OnMouseDClick)
76     EVT_MOTION(wxRibbonGallery::OnMouseMove)
77     EVT_PAINT(wxRibbonGallery::OnPaint)
78     EVT_SIZE(wxRibbonGallery::OnSize)
79 wxEND_EVENT_TABLE()
80 
81 wxRibbonGallery::wxRibbonGallery()
82 {
83 }
84 
wxRibbonGallery(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style)85 wxRibbonGallery::wxRibbonGallery(wxWindow* parent,
86                   wxWindowID id,
87                   const wxPoint& pos,
88                   const wxSize& size,
89                   long style)
90     : wxRibbonControl(parent, id, pos, size, wxBORDER_NONE)
91 {
92     CommonInit(style);
93 }
94 
~wxRibbonGallery()95 wxRibbonGallery::~wxRibbonGallery()
96 {
97     Clear();
98 }
99 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style)100 bool wxRibbonGallery::Create(wxWindow* parent,
101                 wxWindowID id,
102                 const wxPoint& pos,
103                 const wxSize& size,
104                 long style)
105 {
106     if(!wxRibbonControl::Create(parent, id, pos, size, wxBORDER_NONE))
107     {
108         return false;
109     }
110 
111     CommonInit(style);
112     return true;
113 }
114 
CommonInit(long WXUNUSED (style))115 void wxRibbonGallery::CommonInit(long WXUNUSED(style))
116 {
117     m_selected_item = NULL;
118     m_hovered_item = NULL;
119     m_active_item = NULL;
120     m_scroll_up_button_rect = wxRect(0, 0, 0, 0);
121     m_scroll_down_button_rect = wxRect(0, 0, 0, 0);
122     m_extension_button_rect = wxRect(0, 0, 0, 0);
123     m_mouse_active_rect = NULL;
124     m_bitmap_size = wxSize(64, 32);
125     m_bitmap_padded_size = m_bitmap_size;
126     m_item_separation_x = 0;
127     m_item_separation_y = 0;
128     m_scroll_amount = 0;
129     m_scroll_limit = 0;
130     m_up_button_state = wxRIBBON_GALLERY_BUTTON_DISABLED;
131     m_down_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
132     m_extension_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
133     m_hovered = false;
134 
135     SetBackgroundStyle(wxBG_STYLE_PAINT);
136 }
137 
OnMouseEnter(wxMouseEvent & evt)138 void wxRibbonGallery::OnMouseEnter(wxMouseEvent& evt)
139 {
140     m_hovered = true;
141     if(m_mouse_active_rect != NULL && !evt.LeftIsDown())
142     {
143         m_mouse_active_rect = NULL;
144         m_active_item = NULL;
145     }
146     Refresh(false);
147 }
148 
OnMouseMove(wxMouseEvent & evt)149 void wxRibbonGallery::OnMouseMove(wxMouseEvent& evt)
150 {
151     bool refresh = false;
152     wxPoint pos = evt.GetPosition();
153 
154     if(TestButtonHover(m_scroll_up_button_rect, pos, &m_up_button_state))
155         refresh = true;
156     if(TestButtonHover(m_scroll_down_button_rect, pos, &m_down_button_state))
157         refresh = true;
158     if(TestButtonHover(m_extension_button_rect, pos, &m_extension_button_state))
159         refresh = true;
160 
161     wxRibbonGalleryItem *hovered_item = NULL;
162     wxRibbonGalleryItem *active_item = NULL;
163     if(m_client_rect.Contains(pos))
164     {
165         if(m_art && m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL)
166             pos.x += m_scroll_amount;
167         else
168             pos.y += m_scroll_amount;
169 
170         size_t item_count = m_items.Count();
171         size_t item_i;
172         for(item_i = 0; item_i < item_count; ++item_i)
173         {
174             wxRibbonGalleryItem *item = m_items.Item(item_i);
175             if(!item->IsVisible())
176                 continue;
177 
178             if(item->GetPosition().Contains(pos))
179             {
180                 if(m_mouse_active_rect == &item->GetPosition())
181                     active_item = item;
182                 hovered_item = item;
183                 break;
184             }
185         }
186     }
187     if(active_item != m_active_item)
188     {
189         m_active_item = active_item;
190         refresh = true;
191     }
192     if(hovered_item != m_hovered_item)
193     {
194         m_hovered_item = hovered_item;
195         wxRibbonGalleryEvent notification(
196             wxEVT_RIBBONGALLERY_HOVER_CHANGED, GetId());
197         notification.SetEventObject(this);
198         notification.SetGallery(this);
199         notification.SetGalleryItem(hovered_item);
200         ProcessWindowEvent(notification);
201         refresh = true;
202     }
203 
204     if(refresh)
205         Refresh(false);
206 }
207 
TestButtonHover(const wxRect & rect,wxPoint pos,wxRibbonGalleryButtonState * state)208 bool wxRibbonGallery::TestButtonHover(const wxRect& rect, wxPoint pos,
209         wxRibbonGalleryButtonState* state)
210 {
211     if(*state == wxRIBBON_GALLERY_BUTTON_DISABLED)
212         return false;
213 
214     wxRibbonGalleryButtonState new_state;
215     if(rect.Contains(pos))
216     {
217         if(m_mouse_active_rect == &rect)
218             new_state = wxRIBBON_GALLERY_BUTTON_ACTIVE;
219         else
220             new_state = wxRIBBON_GALLERY_BUTTON_HOVERED;
221     }
222     else
223         new_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
224 
225     if(new_state != *state)
226     {
227         *state = new_state;
228         return true;
229     }
230     else
231     {
232         return false;
233     }
234 }
235 
OnMouseLeave(wxMouseEvent & WXUNUSED (evt))236 void wxRibbonGallery::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
237 {
238     m_hovered = false;
239     m_active_item = NULL;
240     if(m_up_button_state != wxRIBBON_GALLERY_BUTTON_DISABLED)
241         m_up_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
242     if(m_down_button_state != wxRIBBON_GALLERY_BUTTON_DISABLED)
243         m_down_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
244     if(m_extension_button_state != wxRIBBON_GALLERY_BUTTON_DISABLED)
245         m_extension_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
246     if(m_hovered_item != NULL)
247     {
248         m_hovered_item = NULL;
249         wxRibbonGalleryEvent notification(
250             wxEVT_RIBBONGALLERY_HOVER_CHANGED, GetId());
251         notification.SetEventObject(this);
252         notification.SetGallery(this);
253         ProcessWindowEvent(notification);
254     }
255     Refresh(false);
256 }
257 
OnMouseDown(wxMouseEvent & evt)258 void wxRibbonGallery::OnMouseDown(wxMouseEvent& evt)
259 {
260     wxPoint pos = evt.GetPosition();
261     m_mouse_active_rect = NULL;
262     if(m_client_rect.Contains(pos))
263     {
264         if(m_art && m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL)
265             pos.x += m_scroll_amount;
266         else
267             pos.y += m_scroll_amount;
268         size_t item_count = m_items.Count();
269         size_t item_i;
270         for(item_i = 0; item_i < item_count; ++item_i)
271         {
272             wxRibbonGalleryItem *item = m_items.Item(item_i);
273             if(!item->IsVisible())
274                 continue;
275 
276             const wxRect& rect = item->GetPosition();
277             if(rect.Contains(pos))
278             {
279                 m_active_item = item;
280                 m_mouse_active_rect = &rect;
281                 break;
282             }
283         }
284     }
285     else if(m_scroll_up_button_rect.Contains(pos))
286     {
287         if(m_up_button_state != wxRIBBON_GALLERY_BUTTON_DISABLED)
288         {
289             m_mouse_active_rect = &m_scroll_up_button_rect;
290             m_up_button_state = wxRIBBON_GALLERY_BUTTON_ACTIVE;
291         }
292     }
293     else if(m_scroll_down_button_rect.Contains(pos))
294     {
295         if(m_down_button_state != wxRIBBON_GALLERY_BUTTON_DISABLED)
296         {
297             m_mouse_active_rect = &m_scroll_down_button_rect;
298             m_down_button_state = wxRIBBON_GALLERY_BUTTON_ACTIVE;
299         }
300     }
301     else if(m_extension_button_rect.Contains(pos))
302     {
303         if(m_extension_button_state != wxRIBBON_GALLERY_BUTTON_DISABLED)
304         {
305             m_mouse_active_rect = &m_extension_button_rect;
306             m_extension_button_state = wxRIBBON_GALLERY_BUTTON_ACTIVE;
307         }
308     }
309     if(m_mouse_active_rect != NULL)
310         Refresh(false);
311 }
312 
OnMouseUp(wxMouseEvent & evt)313 void wxRibbonGallery::OnMouseUp(wxMouseEvent& evt)
314 {
315     if(m_mouse_active_rect != NULL)
316     {
317         wxPoint pos = evt.GetPosition();
318         if(m_active_item)
319         {
320             if(m_art && m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL)
321                 pos.x += m_scroll_amount;
322             else
323                 pos.y += m_scroll_amount;
324         }
325         if(m_mouse_active_rect->Contains(pos))
326         {
327             if(m_mouse_active_rect == &m_scroll_up_button_rect)
328             {
329                 m_up_button_state = wxRIBBON_GALLERY_BUTTON_HOVERED;
330                 ScrollLines(-1);
331             }
332             else if(m_mouse_active_rect == &m_scroll_down_button_rect)
333             {
334                 m_down_button_state = wxRIBBON_GALLERY_BUTTON_HOVERED;
335                 ScrollLines(1);
336             }
337             else if(m_mouse_active_rect == &m_extension_button_rect)
338             {
339                 m_extension_button_state = wxRIBBON_GALLERY_BUTTON_HOVERED;
340                 wxCommandEvent notification(wxEVT_BUTTON,
341                     GetId());
342                 notification.SetEventObject(this);
343                 ProcessWindowEvent(notification);
344             }
345             else if(m_active_item != NULL)
346             {
347                 if(m_selected_item != m_active_item)
348                 {
349                     m_selected_item = m_active_item;
350                     wxRibbonGalleryEvent notification(
351                         wxEVT_RIBBONGALLERY_SELECTED, GetId());
352                     notification.SetEventObject(this);
353                     notification.SetGallery(this);
354                     notification.SetGalleryItem(m_selected_item);
355                     ProcessWindowEvent(notification);
356                 }
357 
358                 wxRibbonGalleryEvent notification(
359                     wxEVT_RIBBONGALLERY_CLICKED, GetId());
360                 notification.SetEventObject(this);
361                 notification.SetGallery(this);
362                 notification.SetGalleryItem(m_selected_item);
363                 ProcessWindowEvent(notification);
364             }
365         }
366         m_mouse_active_rect = NULL;
367         m_active_item = NULL;
368         Refresh(false);
369     }
370 }
371 
OnMouseDClick(wxMouseEvent & evt)372 void wxRibbonGallery::OnMouseDClick(wxMouseEvent& evt)
373 {
374     // The 2nd click of a double-click should be handled as a click in the
375     // same way as the 1st click of the double-click. This is useful for
376     // scrolling through the gallery.
377     OnMouseDown(evt);
378     OnMouseUp(evt);
379 }
380 
SetItemClientObject(wxRibbonGalleryItem * itm,wxClientData * data)381 void wxRibbonGallery::SetItemClientObject(wxRibbonGalleryItem* itm,
382                                           wxClientData* data)
383 {
384     itm->SetClientObject(data);
385 }
386 
GetItemClientObject(const wxRibbonGalleryItem * itm) const387 wxClientData* wxRibbonGallery::GetItemClientObject(const wxRibbonGalleryItem* itm) const
388 {
389     return itm->GetClientObject();
390 }
391 
SetItemClientData(wxRibbonGalleryItem * itm,void * data)392 void wxRibbonGallery::SetItemClientData(wxRibbonGalleryItem* itm, void* data)
393 {
394     itm->SetClientData(data);
395 }
396 
GetItemClientData(const wxRibbonGalleryItem * itm) const397 void* wxRibbonGallery::GetItemClientData(const wxRibbonGalleryItem* itm) const
398 {
399     return itm->GetClientData();
400 }
401 
ScrollLines(int lines)402 bool wxRibbonGallery::ScrollLines(int lines)
403 {
404     if(m_scroll_limit == 0 || m_art == NULL)
405         return false;
406 
407     return ScrollPixels(lines * GetScrollLineSize());
408 }
409 
GetScrollLineSize() const410 int wxRibbonGallery::GetScrollLineSize() const
411 {
412     if(m_art == NULL)
413         return 32;
414 
415     int line_size = m_bitmap_padded_size.GetHeight();
416     if(m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL)
417         line_size = m_bitmap_padded_size.GetWidth();
418 
419     return line_size;
420 }
421 
ScrollPixels(int pixels)422 bool wxRibbonGallery::ScrollPixels(int pixels)
423 {
424     if(m_scroll_limit == 0 || m_art == NULL)
425         return false;
426 
427     if(pixels < 0)
428     {
429         if(m_scroll_amount > 0)
430         {
431             m_scroll_amount += pixels;
432             if(m_scroll_amount <= 0)
433             {
434                 m_scroll_amount = 0;
435                 m_up_button_state = wxRIBBON_GALLERY_BUTTON_DISABLED;
436             }
437             else if(m_up_button_state == wxRIBBON_GALLERY_BUTTON_DISABLED)
438                 m_up_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
439             if(m_down_button_state == wxRIBBON_GALLERY_BUTTON_DISABLED)
440                 m_down_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
441             return true;
442         }
443     }
444     else if(pixels > 0)
445     {
446         if(m_scroll_amount < m_scroll_limit)
447         {
448             m_scroll_amount += pixels;
449             if(m_scroll_amount >= m_scroll_limit)
450             {
451                 m_scroll_amount = m_scroll_limit;
452                 m_down_button_state = wxRIBBON_GALLERY_BUTTON_DISABLED;
453             }
454             else if(m_down_button_state == wxRIBBON_GALLERY_BUTTON_DISABLED)
455                 m_down_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
456             if(m_up_button_state == wxRIBBON_GALLERY_BUTTON_DISABLED)
457                 m_up_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
458             return true;
459         }
460     }
461     return false;
462 }
463 
EnsureVisible(const wxRibbonGalleryItem * item)464 void wxRibbonGallery::EnsureVisible(const wxRibbonGalleryItem* item)
465 {
466     if(item == NULL || !item->IsVisible() || IsEmpty())
467         return;
468 
469     if(m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL)
470     {
471         int x = item->GetPosition().GetLeft();
472         int base_x = m_items.Item(0)->GetPosition().GetLeft();
473         int delta = x - base_x - m_scroll_amount;
474         ScrollLines(delta / m_bitmap_padded_size.GetWidth());
475     }
476     else
477     {
478         int y = item->GetPosition().GetTop();
479         int base_y = m_items.Item(0)->GetPosition().GetTop();
480         int delta = y - base_y - m_scroll_amount;
481         ScrollLines(delta / m_bitmap_padded_size.GetHeight());
482     }
483 }
484 
IsHovered() const485 bool wxRibbonGallery::IsHovered() const
486 {
487     return m_hovered;
488 }
489 
OnEraseBackground(wxEraseEvent & WXUNUSED (evt))490 void wxRibbonGallery::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
491 {
492     // All painting done in main paint handler to minimise flicker
493 }
494 
OnPaint(wxPaintEvent & WXUNUSED (evt))495 void wxRibbonGallery::OnPaint(wxPaintEvent& WXUNUSED(evt))
496 {
497     wxAutoBufferedPaintDC dc(this);
498     if(m_art == NULL)
499         return;
500 
501     m_art->DrawGalleryBackground(dc, this, GetSize());
502 
503     int padding_top = m_art->GetMetric(wxRIBBON_ART_GALLERY_BITMAP_PADDING_TOP_SIZE);
504     int padding_left = m_art->GetMetric(wxRIBBON_ART_GALLERY_BITMAP_PADDING_LEFT_SIZE);
505 
506     dc.SetClippingRegion(m_client_rect);
507 
508     bool offset_vertical = true;
509     if(m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL)
510         offset_vertical = false;
511     size_t item_count = m_items.Count();
512     size_t item_i;
513     for(item_i = 0; item_i < item_count; ++item_i)
514     {
515         wxRibbonGalleryItem *item = m_items.Item(item_i);
516         if(!item->IsVisible())
517             continue;
518 
519         const wxRect& pos = item->GetPosition();
520         wxRect offset_pos(pos);
521         if(offset_vertical)
522             offset_pos.SetTop(offset_pos.GetTop() - m_scroll_amount);
523         else
524             offset_pos.SetLeft(offset_pos.GetLeft() - m_scroll_amount);
525         m_art->DrawGalleryItemBackground(dc, this, offset_pos, item);
526         dc.DrawBitmap(item->GetBitmap(), offset_pos.GetLeft() + padding_left,
527             offset_pos.GetTop() + padding_top);
528     }
529 }
530 
OnSize(wxSizeEvent & WXUNUSED (evt))531 void wxRibbonGallery::OnSize(wxSizeEvent& WXUNUSED(evt))
532 {
533     Layout();
534 }
535 
Append(const wxBitmap & bitmap,int id)536 wxRibbonGalleryItem* wxRibbonGallery::Append(const wxBitmap& bitmap, int id)
537 {
538     wxASSERT(bitmap.IsOk());
539     if(m_items.IsEmpty())
540     {
541         m_bitmap_size = bitmap.GetScaledSize();
542         CalculateMinSize();
543     }
544     else
545     {
546         wxASSERT(bitmap.GetScaledSize() == m_bitmap_size);
547     }
548 
549     wxRibbonGalleryItem *item = new wxRibbonGalleryItem;
550     item->SetId(id);
551     item->SetBitmap(bitmap);
552     m_items.Add(item);
553     return item;
554 }
555 
Append(const wxBitmap & bitmap,int id,void * clientData)556 wxRibbonGalleryItem* wxRibbonGallery::Append(const wxBitmap& bitmap, int id,
557                                              void* clientData)
558 {
559     wxRibbonGalleryItem *item = Append(bitmap, id);
560     item->SetClientData(clientData);
561     return item;
562 }
563 
Append(const wxBitmap & bitmap,int id,wxClientData * clientData)564 wxRibbonGalleryItem* wxRibbonGallery::Append(const wxBitmap& bitmap, int id,
565                                              wxClientData* clientData)
566 {
567     wxRibbonGalleryItem *item = Append(bitmap, id);
568     item->SetClientObject(clientData);
569     return item;
570 }
571 
Clear()572 void wxRibbonGallery::Clear()
573 {
574     size_t item_count = m_items.Count();
575     size_t item_i;
576     for(item_i = 0; item_i < item_count; ++item_i)
577     {
578         wxRibbonGalleryItem *item = m_items.Item(item_i);
579         delete item;
580     }
581     m_items.Clear();
582 }
583 
IsSizingContinuous() const584 bool wxRibbonGallery::IsSizingContinuous() const
585 {
586     return false;
587 }
588 
CalculateMinSize()589 void wxRibbonGallery::CalculateMinSize()
590 {
591     if(m_art == NULL || !m_bitmap_size.IsFullySpecified())
592     {
593         SetMinSize(wxSize(20, 20));
594     }
595     else
596     {
597         m_bitmap_padded_size = m_bitmap_size;
598         m_bitmap_padded_size.IncBy(
599             m_art->GetMetric(wxRIBBON_ART_GALLERY_BITMAP_PADDING_LEFT_SIZE) +
600             m_art->GetMetric(wxRIBBON_ART_GALLERY_BITMAP_PADDING_RIGHT_SIZE),
601             m_art->GetMetric(wxRIBBON_ART_GALLERY_BITMAP_PADDING_TOP_SIZE) +
602             m_art->GetMetric(wxRIBBON_ART_GALLERY_BITMAP_PADDING_BOTTOM_SIZE));
603 
604         wxMemoryDC dc;
605         SetMinSize(m_art->GetGallerySize(dc, this, m_bitmap_padded_size));
606 
607         // The best size is displaying several items
608         m_best_size = m_bitmap_padded_size;
609         m_best_size.x *= 3;
610         m_best_size = m_art->GetGallerySize(dc, this, m_best_size);
611     }
612 }
613 
Realize()614 bool wxRibbonGallery::Realize()
615 {
616     CalculateMinSize();
617     return Layout();
618 }
619 
Layout()620 bool wxRibbonGallery::Layout()
621 {
622     if(m_art == NULL)
623         return false;
624 
625     wxMemoryDC dc;
626     wxPoint origin;
627     wxSize client_size = m_art->GetGalleryClientSize(dc, this, GetSize(),
628         &origin, &m_scroll_up_button_rect, &m_scroll_down_button_rect,
629         &m_extension_button_rect);
630     m_client_rect = wxRect(origin, client_size);
631 
632     int x_cursor = 0;
633     int y_cursor = 0;
634 
635     size_t item_count = m_items.Count();
636     size_t item_i;
637     long art_flags = m_art->GetFlags();
638     for(item_i = 0; item_i < item_count; ++item_i)
639     {
640         wxRibbonGalleryItem *item = m_items.Item(item_i);
641         item->SetIsVisible(true);
642         if(art_flags & wxRIBBON_BAR_FLOW_VERTICAL)
643         {
644             if(y_cursor + m_bitmap_padded_size.y > client_size.GetHeight())
645             {
646                 if(y_cursor == 0)
647                     break;
648                 y_cursor = 0;
649                 x_cursor += m_bitmap_padded_size.x;
650             }
651             item->SetPosition(origin.x + x_cursor, origin.y + y_cursor,
652                 m_bitmap_padded_size);
653             y_cursor += m_bitmap_padded_size.y;
654         }
655         else
656         {
657             if(x_cursor + m_bitmap_padded_size.x > client_size.GetWidth())
658             {
659                 if(x_cursor == 0)
660                     break;
661                 x_cursor = 0;
662                 y_cursor += m_bitmap_padded_size.y;
663             }
664             item->SetPosition(origin.x + x_cursor, origin.y + y_cursor,
665                 m_bitmap_padded_size);
666             x_cursor += m_bitmap_padded_size.x;
667         }
668     }
669     for(; item_i < item_count; ++item_i)
670     {
671         wxRibbonGalleryItem *item = m_items.Item(item_i);
672         item->SetIsVisible(false);
673     }
674     if(art_flags & wxRIBBON_BAR_FLOW_VERTICAL)
675         m_scroll_limit = x_cursor;
676     else
677         m_scroll_limit = y_cursor;
678     if(m_scroll_amount >= m_scroll_limit)
679     {
680         m_scroll_amount = m_scroll_limit;
681         m_down_button_state = wxRIBBON_GALLERY_BUTTON_DISABLED;
682     }
683     else if(m_down_button_state == wxRIBBON_GALLERY_BUTTON_DISABLED)
684         m_down_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
685 
686     if(m_scroll_amount <= 0)
687     {
688         m_scroll_amount = 0;
689         m_up_button_state = wxRIBBON_GALLERY_BUTTON_DISABLED;
690     }
691     else if(m_up_button_state == wxRIBBON_GALLERY_BUTTON_DISABLED)
692         m_up_button_state = wxRIBBON_GALLERY_BUTTON_NORMAL;
693 
694     return true;
695 }
696 
DoGetBestSize() const697 wxSize wxRibbonGallery::DoGetBestSize() const
698 {
699     return m_best_size;
700 }
701 
DoGetNextSmallerSize(wxOrientation direction,wxSize relative_to) const702 wxSize wxRibbonGallery::DoGetNextSmallerSize(wxOrientation direction,
703                                         wxSize relative_to) const
704 {
705     if(m_art == NULL)
706         return relative_to;
707 
708     wxMemoryDC dc;
709 
710     wxSize client = m_art->GetGalleryClientSize(dc, this, relative_to, NULL,
711         NULL, NULL, NULL);
712     switch(direction)
713     {
714     case wxHORIZONTAL:
715         client.DecBy(1, 0);
716         break;
717     case wxVERTICAL:
718         client.DecBy(0, 1);
719         break;
720     case wxBOTH:
721         client.DecBy(1, 1);
722         break;
723     }
724     if(client.GetWidth() < 0 || client.GetHeight() < 0)
725         return relative_to;
726 
727     client.x = (client.x / m_bitmap_padded_size.x) * m_bitmap_padded_size.x;
728     client.y = (client.y / m_bitmap_padded_size.y) * m_bitmap_padded_size.y;
729 
730     wxSize size = m_art->GetGallerySize(dc, this, client);
731     wxSize minimum = GetMinSize();
732 
733     if(size.GetWidth() < minimum.GetWidth() ||
734         size.GetHeight() < minimum.GetHeight())
735     {
736         return relative_to;
737     }
738 
739     switch(direction)
740     {
741     case wxHORIZONTAL:
742         size.SetHeight(relative_to.GetHeight());
743         break;
744     case wxVERTICAL:
745         size.SetWidth(relative_to.GetWidth());
746         break;
747     default:
748         break;
749     }
750 
751     return size;
752 }
753 
DoGetNextLargerSize(wxOrientation direction,wxSize relative_to) const754 wxSize wxRibbonGallery::DoGetNextLargerSize(wxOrientation direction,
755                                        wxSize relative_to) const
756 {
757     if(m_art == NULL)
758         return relative_to;
759 
760     wxMemoryDC dc;
761 
762     wxSize client = m_art->GetGalleryClientSize(dc, this, relative_to, NULL,
763         NULL, NULL, NULL);
764 
765     // No need to grow if the given size can already display every item
766     int nitems = (client.GetWidth() / m_bitmap_padded_size.x) *
767         (client.GetHeight() / m_bitmap_padded_size.y);
768     if(nitems >= (int)m_items.GetCount())
769         return relative_to;
770 
771     switch(direction)
772     {
773     case wxHORIZONTAL:
774         client.IncBy(m_bitmap_padded_size.x, 0);
775         break;
776     case wxVERTICAL:
777         client.IncBy(0, m_bitmap_padded_size.y);
778         break;
779     case wxBOTH:
780         client.IncBy(m_bitmap_padded_size);
781         break;
782     }
783 
784     client.x = (client.x / m_bitmap_padded_size.x) * m_bitmap_padded_size.x;
785     client.y = (client.y / m_bitmap_padded_size.y) * m_bitmap_padded_size.y;
786 
787     wxSize size = m_art->GetGallerySize(dc, this, client);
788     wxSize minimum = GetMinSize();
789 
790     if(size.GetWidth() < minimum.GetWidth() ||
791         size.GetHeight() < minimum.GetHeight())
792     {
793         return relative_to;
794     }
795 
796     switch(direction)
797     {
798     case wxHORIZONTAL:
799         size.SetHeight(relative_to.GetHeight());
800         break;
801     case wxVERTICAL:
802         size.SetWidth(relative_to.GetWidth());
803         break;
804     default:
805         break;
806     }
807 
808     return size;
809 }
810 
IsEmpty() const811 bool wxRibbonGallery::IsEmpty() const
812 {
813     return m_items.IsEmpty();
814 }
815 
GetCount() const816 unsigned int wxRibbonGallery::GetCount() const
817 {
818     return (unsigned int)m_items.GetCount();
819 }
820 
GetItem(unsigned int n)821 wxRibbonGalleryItem* wxRibbonGallery::GetItem(unsigned int n)
822 {
823     if(n >= GetCount())
824         return NULL;
825     return m_items.Item(n);
826 }
827 
SetSelection(wxRibbonGalleryItem * item)828 void wxRibbonGallery::SetSelection(wxRibbonGalleryItem* item)
829 {
830     if(item != m_selected_item)
831     {
832         m_selected_item = item;
833         Refresh(false);
834     }
835 }
836 
GetSelection() const837 wxRibbonGalleryItem* wxRibbonGallery::GetSelection() const
838 {
839     return m_selected_item;
840 }
841 
GetHoveredItem() const842 wxRibbonGalleryItem* wxRibbonGallery::GetHoveredItem() const
843 {
844     return m_hovered_item;
845 }
846 
GetActiveItem() const847 wxRibbonGalleryItem* wxRibbonGallery::GetActiveItem() const
848 {
849     return m_active_item;
850 }
851 
GetUpButtonState() const852 wxRibbonGalleryButtonState wxRibbonGallery::GetUpButtonState() const
853 {
854     return m_up_button_state;
855 }
856 
GetDownButtonState() const857 wxRibbonGalleryButtonState wxRibbonGallery::GetDownButtonState() const
858 {
859     return m_down_button_state;
860 }
861 
GetExtensionButtonState() const862 wxRibbonGalleryButtonState wxRibbonGallery::GetExtensionButtonState() const
863 {
864     return m_extension_button_state;
865 }
866 
867 #endif // wxUSE_RIBBON
868