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