Merged GSOC Ribbon work from SOC2009_RIBBON branch into trunk.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@61944 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
998
src/ribbon/buttonbar.cpp
Normal file
998
src/ribbon/buttonbar.cpp
Normal file
@@ -0,0 +1,998 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Name: src/ribbon/buttonbar.cpp
|
||||
// Purpose: Ribbon control similar to a tool bar
|
||||
// Author: Peter Cawley
|
||||
// Modified by:
|
||||
// Created: 2009-07-01
|
||||
// RCS-ID: $Id$
|
||||
// Copyright: (C) Peter Cawley
|
||||
// Licence: wxWindows licence
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "wx/wxprec.h"
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
#pragma hdrstop
|
||||
#endif
|
||||
|
||||
#include "wx/ribbon/buttonbar.h"
|
||||
|
||||
#if wxUSE_RIBBON
|
||||
|
||||
#include "wx/ribbon/art.h"
|
||||
#include "wx/dcbuffer.h"
|
||||
|
||||
#ifndef WX_PRECOMP
|
||||
#endif
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#include "wx/msw/private.h"
|
||||
#endif
|
||||
|
||||
wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBUTTON_CLICKED, wxRibbonButtonBarEvent);
|
||||
wxDEFINE_EVENT(wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED, wxRibbonButtonBarEvent);
|
||||
|
||||
IMPLEMENT_DYNAMIC_CLASS(wxRibbonButtonBarEvent, wxCommandEvent)
|
||||
IMPLEMENT_CLASS(wxRibbonButtonBar, wxRibbonControl)
|
||||
|
||||
BEGIN_EVENT_TABLE(wxRibbonButtonBar, wxRibbonControl)
|
||||
EVT_ERASE_BACKGROUND(wxRibbonButtonBar::OnEraseBackground)
|
||||
EVT_ENTER_WINDOW(wxRibbonButtonBar::OnMouseEnter)
|
||||
EVT_LEAVE_WINDOW(wxRibbonButtonBar::OnMouseLeave)
|
||||
EVT_MOTION(wxRibbonButtonBar::OnMouseMove)
|
||||
EVT_PAINT(wxRibbonButtonBar::OnPaint)
|
||||
EVT_SIZE(wxRibbonButtonBar::OnSize)
|
||||
EVT_LEFT_DOWN(wxRibbonButtonBar::OnMouseDown)
|
||||
EVT_LEFT_UP(wxRibbonButtonBar::OnMouseUp)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
class wxRibbonButtonBarButtonSizeInfo
|
||||
{
|
||||
public:
|
||||
bool is_supported;
|
||||
wxSize size;
|
||||
wxRect normal_region;
|
||||
wxRect dropdown_region;
|
||||
};
|
||||
|
||||
class wxRibbonButtonBarButtonInstance
|
||||
{
|
||||
public:
|
||||
wxPoint position;
|
||||
wxRibbonButtonBarButtonBase* base;
|
||||
wxRibbonButtonBarButtonState size;
|
||||
};
|
||||
|
||||
class wxRibbonButtonBarButtonBase
|
||||
{
|
||||
public:
|
||||
wxRibbonButtonBarButtonInstance NewInstance()
|
||||
{
|
||||
wxRibbonButtonBarButtonInstance i;
|
||||
i.base = this;
|
||||
return i;
|
||||
}
|
||||
|
||||
wxRibbonButtonBarButtonState GetLargestSize()
|
||||
{
|
||||
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_LARGE].is_supported)
|
||||
return wxRIBBON_BUTTONBAR_BUTTON_LARGE;
|
||||
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM].is_supported)
|
||||
return wxRIBBON_BUTTONBAR_BUTTON_MEDIUM;
|
||||
wxASSERT(sizes[wxRIBBON_BUTTONBAR_BUTTON_SMALL].is_supported);
|
||||
return wxRIBBON_BUTTONBAR_BUTTON_SMALL;
|
||||
}
|
||||
|
||||
bool GetSmallerSize(
|
||||
wxRibbonButtonBarButtonState* size, int n = 1)
|
||||
{
|
||||
for(; n > 0; --n)
|
||||
{
|
||||
switch(*size)
|
||||
{
|
||||
case wxRIBBON_BUTTONBAR_BUTTON_LARGE:
|
||||
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_MEDIUM].is_supported)
|
||||
{
|
||||
*size = wxRIBBON_BUTTONBAR_BUTTON_MEDIUM;
|
||||
break;
|
||||
}
|
||||
case wxRIBBON_BUTTONBAR_BUTTON_MEDIUM:
|
||||
if(sizes[wxRIBBON_BUTTONBAR_BUTTON_SMALL].is_supported)
|
||||
{
|
||||
*size = wxRIBBON_BUTTONBAR_BUTTON_SMALL;
|
||||
break;
|
||||
}
|
||||
case wxRIBBON_BUTTONBAR_BUTTON_SMALL:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
wxString label;
|
||||
wxString help_string;
|
||||
wxBitmap bitmap_large;
|
||||
wxBitmap bitmap_large_disabled;
|
||||
wxBitmap bitmap_small;
|
||||
wxBitmap bitmap_small_disabled;
|
||||
wxRibbonButtonBarButtonSizeInfo sizes[3];
|
||||
wxObject* client_data;
|
||||
int id;
|
||||
wxRibbonButtonKind kind;
|
||||
long state;
|
||||
};
|
||||
|
||||
WX_DECLARE_OBJARRAY(wxRibbonButtonBarButtonInstance, wxArrayRibbonButtonBarButtonInstance);
|
||||
#include <wx/arrimpl.cpp>
|
||||
WX_DEFINE_OBJARRAY(wxArrayRibbonButtonBarButtonInstance);
|
||||
|
||||
class wxRibbonButtonBarLayout
|
||||
{
|
||||
public:
|
||||
wxSize overall_size;
|
||||
wxArrayRibbonButtonBarButtonInstance buttons;
|
||||
|
||||
void CalculateOverallSize()
|
||||
{
|
||||
overall_size = wxSize(0, 0);
|
||||
size_t btn_count = buttons.Count();
|
||||
size_t btn_i;
|
||||
for(btn_i = 0; btn_i < btn_count; ++btn_i)
|
||||
{
|
||||
wxRibbonButtonBarButtonInstance& instance = buttons.Item(btn_i);
|
||||
wxSize size = instance.base->sizes[instance.size].size;
|
||||
int right = instance.position.x + size.GetWidth();
|
||||
int bottom = instance.position.y + size.GetHeight();
|
||||
if(right > overall_size.GetWidth())
|
||||
{
|
||||
overall_size.SetWidth(right);
|
||||
}
|
||||
if(bottom > overall_size.GetHeight())
|
||||
{
|
||||
overall_size.SetHeight(bottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxRibbonButtonBarButtonInstance* FindSimilarInstance(
|
||||
wxRibbonButtonBarButtonInstance* inst)
|
||||
{
|
||||
if(inst == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
size_t btn_count = buttons.Count();
|
||||
size_t btn_i;
|
||||
for(btn_i = 0; btn_i < btn_count; ++btn_i)
|
||||
{
|
||||
wxRibbonButtonBarButtonInstance& instance = buttons.Item(btn_i);
|
||||
if(instance.base == inst->base)
|
||||
{
|
||||
return &instance;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
wxRibbonButtonBar::wxRibbonButtonBar()
|
||||
{
|
||||
m_layouts_valid = false;
|
||||
}
|
||||
|
||||
wxRibbonButtonBar::wxRibbonButtonBar(wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style)
|
||||
: wxRibbonControl(parent, id, pos, size, wxBORDER_NONE)
|
||||
{
|
||||
m_layouts_valid = false;
|
||||
|
||||
CommonInit(style);
|
||||
}
|
||||
|
||||
wxRibbonButtonBar::~wxRibbonButtonBar()
|
||||
{
|
||||
size_t count = m_buttons.GetCount();
|
||||
size_t i;
|
||||
for(i = 0; i < count; ++i)
|
||||
{
|
||||
wxRibbonButtonBarButtonBase* button = m_buttons.Item(i);
|
||||
delete button;
|
||||
}
|
||||
m_buttons.Clear();
|
||||
|
||||
count = m_layouts.GetCount();
|
||||
for(i = 0; i < count; ++i)
|
||||
{
|
||||
wxRibbonButtonBarLayout* layout = m_layouts.Item(i);
|
||||
delete layout;
|
||||
}
|
||||
m_layouts.Clear();
|
||||
}
|
||||
|
||||
bool wxRibbonButtonBar::Create(wxWindow* parent,
|
||||
wxWindowID id,
|
||||
const wxPoint& pos,
|
||||
const wxSize& size,
|
||||
long style)
|
||||
{
|
||||
if(!wxRibbonControl::Create(parent, id, pos, size, wxBORDER_NONE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CommonInit(style);
|
||||
return true;
|
||||
}
|
||||
|
||||
wxRibbonButtonBarButtonBase* wxRibbonButtonBar::AddButton(
|
||||
int button_id,
|
||||
const wxString& label,
|
||||
const wxBitmap& bitmap,
|
||||
const wxString& help_string,
|
||||
wxRibbonButtonKind kind)
|
||||
{
|
||||
return AddButton(button_id, label, bitmap, wxNullBitmap, wxNullBitmap,
|
||||
wxNullBitmap, kind, help_string);
|
||||
}
|
||||
|
||||
wxRibbonButtonBarButtonBase* wxRibbonButtonBar::AddDropdownButton(
|
||||
int button_id,
|
||||
const wxString& label,
|
||||
const wxBitmap& bitmap,
|
||||
const wxString& help_string)
|
||||
{
|
||||
return AddButton(button_id, label, bitmap, help_string,
|
||||
wxRIBBON_BUTTON_DROPDOWN);
|
||||
}
|
||||
|
||||
wxRibbonButtonBarButtonBase* wxRibbonButtonBar::AddHybridButton(
|
||||
int button_id,
|
||||
const wxString& label,
|
||||
const wxBitmap& bitmap,
|
||||
const wxString& help_string)
|
||||
{
|
||||
return AddButton(button_id, label, bitmap, help_string,
|
||||
wxRIBBON_BUTTON_HYBRID);
|
||||
}
|
||||
|
||||
wxRibbonButtonBarButtonBase* wxRibbonButtonBar::AddButton(
|
||||
int button_id,
|
||||
const wxString& label,
|
||||
const wxBitmap& bitmap,
|
||||
const wxBitmap& bitmap_small,
|
||||
const wxBitmap& bitmap_disabled,
|
||||
const wxBitmap& bitmap_small_disabled,
|
||||
wxRibbonButtonKind kind,
|
||||
const wxString& help_string,
|
||||
wxObject* client_data)
|
||||
{
|
||||
wxASSERT(bitmap.IsOk() || bitmap_small.IsOk());
|
||||
if(m_buttons.IsEmpty())
|
||||
{
|
||||
if(bitmap.IsOk())
|
||||
{
|
||||
m_bitmap_size_large = bitmap.GetSize();
|
||||
if(!bitmap_small.IsOk())
|
||||
{
|
||||
m_bitmap_size_small = m_bitmap_size_large;
|
||||
m_bitmap_size_small *= 0.5;
|
||||
}
|
||||
}
|
||||
if(bitmap_small.IsOk())
|
||||
{
|
||||
m_bitmap_size_small = bitmap_small.GetSize();
|
||||
if(!bitmap.IsOk())
|
||||
{
|
||||
m_bitmap_size_large = m_bitmap_size_small;
|
||||
m_bitmap_size_large *= 2.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxRibbonButtonBarButtonBase* base = new wxRibbonButtonBarButtonBase;
|
||||
base->id = button_id;
|
||||
base->label = label;
|
||||
base->bitmap_large = bitmap;
|
||||
if(!base->bitmap_large.IsOk())
|
||||
{
|
||||
base->bitmap_large = MakeResizedBitmap(base->bitmap_small,
|
||||
m_bitmap_size_large);
|
||||
}
|
||||
else if(base->bitmap_large.GetSize() != m_bitmap_size_large)
|
||||
{
|
||||
base->bitmap_large = MakeResizedBitmap(base->bitmap_large,
|
||||
m_bitmap_size_large);
|
||||
}
|
||||
base->bitmap_small = bitmap_small;
|
||||
if(!base->bitmap_small.IsOk())
|
||||
{
|
||||
base->bitmap_small = MakeResizedBitmap(base->bitmap_large,
|
||||
m_bitmap_size_small);
|
||||
}
|
||||
else if(base->bitmap_small.GetSize() != m_bitmap_size_small)
|
||||
{
|
||||
base->bitmap_small = MakeResizedBitmap(base->bitmap_small,
|
||||
m_bitmap_size_small);
|
||||
}
|
||||
base->bitmap_large_disabled = bitmap_disabled;
|
||||
if(!base->bitmap_large_disabled.IsOk())
|
||||
{
|
||||
base->bitmap_large_disabled = MakeDisabledBitmap(base->bitmap_large);
|
||||
}
|
||||
base->bitmap_small_disabled = bitmap_small_disabled;
|
||||
if(!base->bitmap_small_disabled.IsOk())
|
||||
{
|
||||
base->bitmap_small_disabled = MakeDisabledBitmap(base->bitmap_small);
|
||||
}
|
||||
base->kind = kind;
|
||||
base->help_string = help_string;
|
||||
base->client_data = client_data;
|
||||
base->state = 0;
|
||||
|
||||
wxMemoryDC temp_dc;
|
||||
FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_SMALL, temp_dc);
|
||||
FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM, temp_dc);
|
||||
FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_LARGE, temp_dc);
|
||||
|
||||
// TODO
|
||||
m_buttons.Add(base);
|
||||
m_layouts_valid = false;
|
||||
return base;
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::FetchButtonSizeInfo(wxRibbonButtonBarButtonBase* button,
|
||||
wxRibbonButtonBarButtonState size, wxDC& dc)
|
||||
{
|
||||
wxRibbonButtonBarButtonSizeInfo& info = button->sizes[size];
|
||||
if(m_art)
|
||||
{
|
||||
info.is_supported = m_art->GetButtonBarButtonSize(dc, this,
|
||||
button->kind, size, button->label, m_bitmap_size_large,
|
||||
m_bitmap_size_small, &info.size, &info.normal_region,
|
||||
&info.dropdown_region);
|
||||
}
|
||||
else
|
||||
info.is_supported = false;
|
||||
}
|
||||
|
||||
wxBitmap wxRibbonButtonBar::MakeResizedBitmap(const wxBitmap& original, wxSize size)
|
||||
{
|
||||
wxImage img(original.ConvertToImage());
|
||||
img.Rescale(size.GetWidth(), size.GetHeight(), wxIMAGE_QUALITY_HIGH);
|
||||
return wxBitmap(img);
|
||||
}
|
||||
|
||||
wxBitmap wxRibbonButtonBar::MakeDisabledBitmap(const wxBitmap& original)
|
||||
{
|
||||
wxImage img(original.ConvertToImage());
|
||||
return wxBitmap(img.ConvertToGreyscale());
|
||||
}
|
||||
|
||||
bool wxRibbonButtonBar::Realize()
|
||||
{
|
||||
if(!m_layouts_valid)
|
||||
{
|
||||
MakeLayouts();
|
||||
m_layouts_valid = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::ClearButtons()
|
||||
{
|
||||
m_layouts_valid = false;
|
||||
size_t count = m_buttons.GetCount();
|
||||
size_t i;
|
||||
for(i = 0; i < count; ++i)
|
||||
{
|
||||
wxRibbonButtonBarButtonBase* button = m_buttons.Item(i);
|
||||
delete button;
|
||||
}
|
||||
m_buttons.Clear();
|
||||
Realize();
|
||||
}
|
||||
|
||||
bool wxRibbonButtonBar::DeleteButton(int button_id)
|
||||
{
|
||||
size_t count = m_buttons.GetCount();
|
||||
size_t i;
|
||||
for(i = 0; i < count; ++i)
|
||||
{
|
||||
wxRibbonButtonBarButtonBase* button = m_buttons.Item(i);
|
||||
if(button->id == button_id)
|
||||
{
|
||||
m_layouts_valid = false;
|
||||
m_buttons.RemoveAt(i);
|
||||
Realize();
|
||||
Refresh();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::EnableButton(int button_id, bool enable)
|
||||
{
|
||||
size_t count = m_buttons.GetCount();
|
||||
size_t i;
|
||||
for(i = 0; i < count; ++i)
|
||||
{
|
||||
wxRibbonButtonBarButtonBase* button = m_buttons.Item(i);
|
||||
if(button->id == button_id)
|
||||
{
|
||||
if(enable)
|
||||
{
|
||||
if(button->state & wxRIBBON_BUTTONBAR_BUTTON_DISABLED)
|
||||
{
|
||||
button->state &= ~wxRIBBON_BUTTONBAR_BUTTON_DISABLED;
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((button->state & wxRIBBON_BUTTONBAR_BUTTON_DISABLED) == 0)
|
||||
{
|
||||
button->state |= wxRIBBON_BUTTONBAR_BUTTON_DISABLED;
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider* art)
|
||||
{
|
||||
if(art == m_art)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
wxRibbonControl::SetArtProvider(art);
|
||||
|
||||
wxMemoryDC temp_dc;
|
||||
size_t btn_count = m_buttons.Count();
|
||||
size_t btn_i;
|
||||
for(btn_i = 0; btn_i < btn_count; ++btn_i)
|
||||
{
|
||||
wxRibbonButtonBarButtonBase* base = m_buttons.Item(btn_i);
|
||||
|
||||
FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_SMALL, temp_dc);
|
||||
FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_MEDIUM, temp_dc);
|
||||
FetchButtonSizeInfo(base, wxRIBBON_BUTTONBAR_BUTTON_LARGE, temp_dc);
|
||||
}
|
||||
|
||||
m_layouts_valid = false;
|
||||
Realize();
|
||||
}
|
||||
|
||||
bool wxRibbonButtonBar::IsSizingContinuous() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
wxSize wxRibbonButtonBar::DoGetNextSmallerSize(wxOrientation direction,
|
||||
wxSize result) const
|
||||
{
|
||||
size_t nlayouts = m_layouts.GetCount();
|
||||
size_t i;
|
||||
for(i = 0; i < nlayouts; ++i)
|
||||
{
|
||||
wxRibbonButtonBarLayout* layout = m_layouts.Item(i);
|
||||
wxSize size = layout->overall_size;
|
||||
switch(direction)
|
||||
{
|
||||
case wxHORIZONTAL:
|
||||
if(size.x < result.x && size.y <= result.y)
|
||||
{
|
||||
result.x = size.x;
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
case wxVERTICAL:
|
||||
if(size.x <= result.x && size.y < result.y)
|
||||
{
|
||||
result.y = size.y;
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
case wxBOTH:
|
||||
if(size.x < result.x && size.y < result.y)
|
||||
{
|
||||
result = size;
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
wxSize wxRibbonButtonBar::DoGetNextLargerSize(wxOrientation direction,
|
||||
wxSize result) const
|
||||
{
|
||||
size_t nlayouts = m_layouts.GetCount();
|
||||
size_t i = nlayouts;
|
||||
while(i > 0)
|
||||
{
|
||||
--i;
|
||||
wxRibbonButtonBarLayout* layout = m_layouts.Item(i);
|
||||
wxSize size = layout->overall_size;
|
||||
switch(direction)
|
||||
{
|
||||
case wxHORIZONTAL:
|
||||
if(size.x > result.x && size.y <= result.y)
|
||||
{
|
||||
result.x = size.x;
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
case wxVERTICAL:
|
||||
if(size.x <= result.x && size.y > result.y)
|
||||
{
|
||||
result.y = size.y;
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
case wxBOTH:
|
||||
if(size.x > result.x && size.y > result.y)
|
||||
{
|
||||
result = size;
|
||||
break;
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
|
||||
{
|
||||
// All painting done in main paint handler to minimise flicker
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::OnPaint(wxPaintEvent& WXUNUSED(evt))
|
||||
{
|
||||
wxAutoBufferedPaintDC dc(this);
|
||||
m_art->DrawButtonBarBackground(dc, this, GetSize());
|
||||
|
||||
wxRibbonButtonBarLayout* layout = m_layouts.Item(m_current_layout);
|
||||
|
||||
size_t btn_count = layout->buttons.Count();
|
||||
size_t btn_i;
|
||||
for(btn_i = 0; btn_i < btn_count; ++btn_i)
|
||||
{
|
||||
wxRibbonButtonBarButtonInstance& button = layout->buttons.Item(btn_i);
|
||||
wxRibbonButtonBarButtonBase* base = button.base;
|
||||
|
||||
wxBitmap* bitmap = &base->bitmap_large;
|
||||
wxBitmap* bitmap_small = &base->bitmap_small;
|
||||
if(base->state & wxRIBBON_BUTTONBAR_BUTTON_DISABLED)
|
||||
{
|
||||
bitmap = &base->bitmap_large_disabled;
|
||||
bitmap_small = &base->bitmap_small_disabled;
|
||||
}
|
||||
wxRect rect(button.position + m_layout_offset, base->sizes[button.size].size);
|
||||
|
||||
m_art->DrawButtonBarButton(dc, this, rect, base->kind,
|
||||
base->state | button.size, base->label, *bitmap, *bitmap_small);
|
||||
}
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::OnSize(wxSizeEvent& evt)
|
||||
{
|
||||
wxSize new_size = evt.GetSize();
|
||||
size_t layout_count = m_layouts.GetCount();
|
||||
size_t layout_i;
|
||||
m_current_layout = layout_count - 1;
|
||||
for(layout_i = 0; layout_i < layout_count; ++layout_i)
|
||||
{
|
||||
wxSize layout_size = m_layouts.Item(layout_i)->overall_size;
|
||||
if(layout_size.x <= new_size.x && layout_size.y <= new_size.y)
|
||||
{
|
||||
m_layout_offset.x = (new_size.x - layout_size.x) / 2;
|
||||
m_layout_offset.y = (new_size.y - layout_size.y) / 2;
|
||||
m_current_layout = layout_i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_hovered_button = m_layouts.Item(m_current_layout)->FindSimilarInstance(m_hovered_button);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::CommonInit(long WXUNUSED(style))
|
||||
{
|
||||
m_bitmap_size_large = wxSize(32, 32);
|
||||
m_bitmap_size_small = wxSize(16, 16);
|
||||
|
||||
wxRibbonButtonBarLayout* placeholder_layout = new wxRibbonButtonBarLayout;
|
||||
placeholder_layout->overall_size = wxSize(20, 20);
|
||||
m_layouts.Add(placeholder_layout);
|
||||
m_current_layout = 0;
|
||||
m_layout_offset = wxPoint(0, 0);
|
||||
m_hovered_button = NULL;
|
||||
m_active_button = NULL;
|
||||
m_lock_active_state = false;
|
||||
|
||||
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
|
||||
};
|
||||
|
||||
wxSize wxRibbonButtonBar::GetMinSize() const
|
||||
{
|
||||
return m_layouts.Last()->overall_size;
|
||||
}
|
||||
|
||||
wxSize wxRibbonButtonBar::DoGetBestSize() const
|
||||
{
|
||||
return m_layouts.Item(0)->overall_size;
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::MakeLayouts()
|
||||
{
|
||||
if(m_layouts_valid || m_art == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
{
|
||||
// Clear existing layouts
|
||||
if(m_hovered_button)
|
||||
{
|
||||
m_hovered_button->base->state &= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK;
|
||||
m_hovered_button = NULL;
|
||||
}
|
||||
if(m_active_button)
|
||||
{
|
||||
m_active_button->base->state &= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK;
|
||||
m_active_button = NULL;
|
||||
}
|
||||
size_t count = m_layouts.GetCount();
|
||||
size_t i;
|
||||
for(i = 0; i < count; ++i)
|
||||
{
|
||||
wxRibbonButtonBarLayout* layout = m_layouts.Item(i);
|
||||
delete layout;
|
||||
}
|
||||
m_layouts.Clear();
|
||||
}
|
||||
size_t btn_count = m_buttons.Count();
|
||||
size_t btn_i;
|
||||
{
|
||||
// Best layout : all buttons large, stacking horizontally
|
||||
wxRibbonButtonBarLayout* layout = new wxRibbonButtonBarLayout;
|
||||
wxPoint cursor(0, 0);
|
||||
layout->overall_size.SetHeight(0);
|
||||
for(btn_i = 0; btn_i < btn_count; ++btn_i)
|
||||
{
|
||||
wxRibbonButtonBarButtonBase* button = m_buttons.Item(btn_i);
|
||||
wxRibbonButtonBarButtonInstance instance = button->NewInstance();
|
||||
instance.position = cursor;
|
||||
instance.size = button->GetLargestSize();
|
||||
wxSize& size = button->sizes[instance.size].size;
|
||||
cursor.x += size.GetWidth();
|
||||
layout->overall_size.SetHeight(wxMax(layout->overall_size.GetHeight(),
|
||||
size.GetHeight()));
|
||||
layout->buttons.Add(instance);
|
||||
}
|
||||
layout->overall_size.SetWidth(cursor.x);
|
||||
m_layouts.Add(layout);
|
||||
}
|
||||
if(btn_count >= 2)
|
||||
{
|
||||
// Collapse the rightmost buttons and stack them vertically
|
||||
size_t iLast = btn_count - 1;
|
||||
while(TryCollapseLayout(m_layouts.Last(), iLast, &iLast) && iLast > 0)
|
||||
{
|
||||
--iLast;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool wxRibbonButtonBar::TryCollapseLayout(wxRibbonButtonBarLayout* original,
|
||||
size_t first_btn, size_t* last_button)
|
||||
{
|
||||
size_t btn_count = m_buttons.Count();
|
||||
size_t btn_i;
|
||||
int used_height = 0;
|
||||
int used_width = 0;
|
||||
int available_width = 0;
|
||||
int available_height = 0;
|
||||
|
||||
for(btn_i = first_btn + 1; btn_i > 0; /* decrement is inside loop */)
|
||||
{
|
||||
--btn_i;
|
||||
wxRibbonButtonBarButtonBase* button = m_buttons.Item(btn_i);
|
||||
wxRibbonButtonBarButtonState large_size_class = button->GetLargestSize();
|
||||
wxSize large_size = button->sizes[large_size_class].size;
|
||||
int t_available_height = wxMax(available_height,
|
||||
large_size.GetHeight());
|
||||
int t_available_width = available_width + large_size.GetWidth();
|
||||
wxRibbonButtonBarButtonState small_size_class = large_size_class;
|
||||
if(!button->GetSmallerSize(&small_size_class))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
wxSize small_size = button->sizes[small_size_class].size;
|
||||
int t_used_height = used_height + small_size.GetHeight();
|
||||
int t_used_width = wxMax(used_width, small_size.GetWidth());
|
||||
|
||||
if(t_used_height > t_available_height)
|
||||
{
|
||||
++btn_i;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
used_height = t_used_height;
|
||||
used_width = t_used_width;
|
||||
available_width = t_available_width;
|
||||
available_height = t_available_height;
|
||||
}
|
||||
}
|
||||
|
||||
if(btn_i >= first_btn || used_width >= available_width)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(last_button != NULL)
|
||||
{
|
||||
*last_button = btn_i;
|
||||
}
|
||||
|
||||
wxRibbonButtonBarLayout* layout = new wxRibbonButtonBarLayout;
|
||||
WX_APPEND_ARRAY(layout->buttons, original->buttons);
|
||||
wxPoint cursor(layout->buttons.Item(btn_i).position);
|
||||
bool preserve_height = false;
|
||||
if(btn_i == 0)
|
||||
{
|
||||
// If height isn't preserved (i.e. it is reduced), then the minimum
|
||||
// size for the button bar will decrease, preventing the original
|
||||
// layout from being used (in some cases).
|
||||
// It may be a good idea to always preverse the height, but for now
|
||||
// it is only done when the first button is involved in a collapse.
|
||||
preserve_height = true;
|
||||
}
|
||||
|
||||
for(; btn_i <= first_btn; ++btn_i)
|
||||
{
|
||||
wxRibbonButtonBarButtonInstance& instance = layout->buttons.Item(btn_i);
|
||||
instance.base->GetSmallerSize(&instance.size);
|
||||
instance.position = cursor;
|
||||
cursor.y += instance.base->sizes[instance.size].size.GetHeight();
|
||||
}
|
||||
|
||||
int x_adjust = available_width - used_width;
|
||||
|
||||
for(; btn_i < btn_count; ++btn_i)
|
||||
{
|
||||
wxRibbonButtonBarButtonInstance& instance = layout->buttons.Item(btn_i);
|
||||
instance.position.x -= x_adjust;
|
||||
}
|
||||
|
||||
layout->CalculateOverallSize();
|
||||
|
||||
// Sanity check
|
||||
if(layout->overall_size.GetWidth() >= original->overall_size.GetWidth() ||
|
||||
layout->overall_size.GetHeight() > original->overall_size.GetHeight())
|
||||
{
|
||||
delete layout;
|
||||
wxASSERT_MSG(false, wxT("Layout collapse resulted in increased size"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if(preserve_height)
|
||||
{
|
||||
layout->overall_size.SetHeight(original->overall_size.GetHeight());
|
||||
}
|
||||
|
||||
m_layouts.Add(layout);
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::OnMouseMove(wxMouseEvent& evt)
|
||||
{
|
||||
wxPoint cursor(evt.GetPosition());
|
||||
wxRibbonButtonBarButtonInstance* new_hovered = NULL;
|
||||
long new_hovered_state = 0;
|
||||
|
||||
wxRibbonButtonBarLayout* layout = m_layouts.Item(m_current_layout);
|
||||
size_t btn_count = layout->buttons.Count();
|
||||
size_t btn_i;
|
||||
for(btn_i = 0; btn_i < btn_count; ++btn_i)
|
||||
{
|
||||
wxRibbonButtonBarButtonInstance& instance = layout->buttons.Item(btn_i);
|
||||
wxRibbonButtonBarButtonSizeInfo& size = instance.base->sizes[instance.size];
|
||||
wxRect btn_rect;
|
||||
btn_rect.SetTopLeft(m_layout_offset + instance.position);
|
||||
btn_rect.SetSize(size.size);
|
||||
if(btn_rect.Contains(cursor))
|
||||
{
|
||||
new_hovered = &instance;
|
||||
new_hovered_state = instance.base->state;
|
||||
new_hovered_state &= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK;
|
||||
wxPoint offset(cursor);
|
||||
offset -= btn_rect.GetTopLeft();
|
||||
if(size.normal_region.Contains(offset))
|
||||
{
|
||||
new_hovered_state |= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED;
|
||||
}
|
||||
if(size.dropdown_region.Contains(offset))
|
||||
{
|
||||
new_hovered_state |= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_HOVERED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(new_hovered != m_hovered_button || (m_hovered_button != NULL &&
|
||||
new_hovered_state != m_hovered_button->base->state))
|
||||
{
|
||||
if(m_hovered_button != NULL)
|
||||
{
|
||||
m_hovered_button->base->state &= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK;
|
||||
}
|
||||
m_hovered_button = new_hovered;
|
||||
if(m_hovered_button != NULL)
|
||||
{
|
||||
m_hovered_button->base->state = new_hovered_state;
|
||||
}
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
if(m_active_button && !m_lock_active_state)
|
||||
{
|
||||
long new_active_state = m_active_button->base->state;
|
||||
new_active_state &= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK;
|
||||
wxRibbonButtonBarButtonSizeInfo& size =
|
||||
m_active_button->base->sizes[m_active_button->size];
|
||||
wxRect btn_rect;
|
||||
btn_rect.SetTopLeft(m_layout_offset + m_active_button->position);
|
||||
btn_rect.SetSize(size.size);
|
||||
if(btn_rect.Contains(cursor))
|
||||
{
|
||||
wxPoint offset(cursor);
|
||||
offset -= btn_rect.GetTopLeft();
|
||||
if(size.normal_region.Contains(offset))
|
||||
{
|
||||
new_active_state |= wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE;
|
||||
}
|
||||
if(size.dropdown_region.Contains(offset))
|
||||
{
|
||||
new_active_state |= wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE;
|
||||
}
|
||||
}
|
||||
if(new_active_state != m_active_button->base->state)
|
||||
{
|
||||
m_active_button->base->state = new_active_state;
|
||||
Refresh(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::OnMouseDown(wxMouseEvent& evt)
|
||||
{
|
||||
wxPoint cursor(evt.GetPosition());
|
||||
m_active_button = NULL;
|
||||
|
||||
wxRibbonButtonBarLayout* layout = m_layouts.Item(m_current_layout);
|
||||
size_t btn_count = layout->buttons.Count();
|
||||
size_t btn_i;
|
||||
for(btn_i = 0; btn_i < btn_count; ++btn_i)
|
||||
{
|
||||
wxRibbonButtonBarButtonInstance& instance = layout->buttons.Item(btn_i);
|
||||
wxRibbonButtonBarButtonSizeInfo& size = instance.base->sizes[instance.size];
|
||||
wxRect btn_rect;
|
||||
btn_rect.SetTopLeft(m_layout_offset + instance.position);
|
||||
btn_rect.SetSize(size.size);
|
||||
if(btn_rect.Contains(cursor))
|
||||
{
|
||||
m_active_button = &instance;
|
||||
cursor -= btn_rect.GetTopLeft();
|
||||
long state = 0;
|
||||
if(size.normal_region.Contains(cursor))
|
||||
state = wxRIBBON_BUTTONBAR_BUTTON_NORMAL_ACTIVE;
|
||||
else if(size.dropdown_region.Contains(cursor))
|
||||
state = wxRIBBON_BUTTONBAR_BUTTON_DROPDOWN_ACTIVE;
|
||||
instance.base->state |= state;
|
||||
Refresh(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::OnMouseUp(wxMouseEvent& evt)
|
||||
{
|
||||
wxPoint cursor(evt.GetPosition());
|
||||
|
||||
if(m_active_button)
|
||||
{
|
||||
wxRibbonButtonBarButtonSizeInfo& size =
|
||||
m_active_button->base->sizes[m_active_button->size];
|
||||
wxRect btn_rect;
|
||||
btn_rect.SetTopLeft(m_layout_offset + m_active_button->position);
|
||||
btn_rect.SetSize(size.size);
|
||||
if(btn_rect.Contains(cursor))
|
||||
{
|
||||
int id = m_active_button->base->id;
|
||||
cursor -= btn_rect.GetTopLeft();
|
||||
wxEventType event_type;
|
||||
do
|
||||
{
|
||||
if(size.normal_region.Contains(cursor))
|
||||
event_type = wxEVT_COMMAND_RIBBONBUTTON_CLICKED;
|
||||
else if(size.dropdown_region.Contains(cursor))
|
||||
event_type = wxEVT_COMMAND_RIBBONBUTTON_DROPDOWN_CLICKED;
|
||||
else
|
||||
break;
|
||||
wxRibbonButtonBarEvent notification(event_type, id);
|
||||
notification.SetEventObject(this);
|
||||
notification.SetBar(this);
|
||||
m_lock_active_state = true;
|
||||
ProcessWindowEvent(notification);
|
||||
m_lock_active_state = false;
|
||||
} while(false);
|
||||
if(m_active_button) // may have been NULLed by event handler
|
||||
{
|
||||
m_active_button->base->state &= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK;
|
||||
m_active_button = NULL;
|
||||
}
|
||||
Refresh(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::OnMouseEnter(wxMouseEvent& evt)
|
||||
{
|
||||
if(m_active_button && !evt.LeftIsDown())
|
||||
{
|
||||
m_active_button = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void wxRibbonButtonBar::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
|
||||
{
|
||||
bool repaint = false;
|
||||
if(m_hovered_button != NULL)
|
||||
{
|
||||
m_hovered_button->base->state &= ~wxRIBBON_BUTTONBAR_BUTTON_HOVER_MASK;
|
||||
m_hovered_button = NULL;
|
||||
repaint = true;
|
||||
}
|
||||
if(m_active_button != NULL && !m_lock_active_state)
|
||||
{
|
||||
m_active_button->base->state &= ~wxRIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK;
|
||||
repaint = true;
|
||||
}
|
||||
if(repaint)
|
||||
Refresh(false);
|
||||
}
|
||||
|
||||
bool wxRibbonButtonBarEvent::PopupMenu(wxMenu* menu)
|
||||
{
|
||||
wxPoint pos = wxDefaultPosition;
|
||||
if(m_bar->m_active_button)
|
||||
{
|
||||
wxRibbonButtonBarButtonSizeInfo& size =
|
||||
m_bar->m_active_button->base->sizes[m_bar->m_active_button->size];
|
||||
wxRect btn_rect;
|
||||
btn_rect.SetTopLeft(m_bar->m_layout_offset +
|
||||
m_bar->m_active_button->position);
|
||||
btn_rect.SetSize(size.size);
|
||||
pos = btn_rect.GetBottomLeft();
|
||||
pos.y++;
|
||||
}
|
||||
return m_bar->PopupMenu(menu, pos);
|
||||
}
|
||||
|
||||
#endif // wxUSE_RIBBON
|
||||
Reference in New Issue
Block a user