357 lines
9.8 KiB
Text
357 lines
9.8 KiB
Text
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// Name: wxMenuButton
|
||
|
// Purpose: A button with a dropdown wxMenu
|
||
|
// Author: John Labenski
|
||
|
// Modified by:
|
||
|
// Created: 11/05/2002
|
||
|
// RCS-ID:
|
||
|
// Copyright: (c) John Labenki
|
||
|
// Licence: wxWidgets licence
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
|
||
|
#pragma implementation "menubtn.h"
|
||
|
#endif
|
||
|
|
||
|
// For compilers that support precompilation, includes "wx/wx.h".
|
||
|
#include "wx/wxprec.h"
|
||
|
|
||
|
#ifdef __BORLANDC__
|
||
|
#pragma hdrstop
|
||
|
#endif
|
||
|
|
||
|
#ifndef WX_PRECOMP
|
||
|
#include "wx/control.h"
|
||
|
#include "wx/menu.h"
|
||
|
#include "wx/settings.h"
|
||
|
#include "wx/bitmap.h"
|
||
|
#include "wx/pen.h"
|
||
|
#include "wx/dc.h"
|
||
|
#endif // WX_PRECOMP
|
||
|
|
||
|
#include "wx/things/toggle.h"
|
||
|
#include "wx/things/menubtn.h"
|
||
|
|
||
|
/* XPM */
|
||
|
static const char *down_arrow_xpm_data[] = {
|
||
|
/* columns rows colors chars-per-pixel */
|
||
|
"5 3 2 1",
|
||
|
" c None",
|
||
|
"a c Black",
|
||
|
/* pixels */
|
||
|
"aaaaa",
|
||
|
" aaa ",
|
||
|
" a "};
|
||
|
|
||
|
static wxBitmap s_dropdownBitmap; // all buttons share the same bitmap
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
IDD_DROPDOWN_BUTTON = 100
|
||
|
};
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// wxMenuButtonEvents
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
DEFINE_LOCAL_EVENT_TYPE(wxEVT_MENUBUTTON_OPEN)
|
||
|
|
||
|
// ==========================================================================
|
||
|
// MenuDropButton
|
||
|
// ==========================================================================
|
||
|
|
||
|
class MenuDropButton : public wxCustomButton
|
||
|
{
|
||
|
public:
|
||
|
MenuDropButton( wxWindow *parent, wxWindowID id, long style) : wxCustomButton()
|
||
|
{
|
||
|
if (!s_dropdownBitmap.Ok())
|
||
|
s_dropdownBitmap = wxBitmap(down_arrow_xpm_data);
|
||
|
|
||
|
Create( parent, id, wxEmptyString, s_dropdownBitmap, wxDefaultPosition,
|
||
|
wxSize(wxMENUBUTTON_DROP_WIDTH, wxMENUBUTTON_DROP_HEIGHT), style);
|
||
|
}
|
||
|
|
||
|
virtual void Paint( wxDC &dc )
|
||
|
{
|
||
|
wxCustomButton *labelBut = ((wxMenuButton*)GetParent())->GetLabelButton();
|
||
|
|
||
|
// pretend that both buttons have focus (for flat style)
|
||
|
if (labelBut)
|
||
|
{
|
||
|
wxPoint p = GetParent()->ScreenToClient(wxGetMousePosition());
|
||
|
|
||
|
if (GetRect().Inside(p) || labelBut->GetRect().Inside(p))
|
||
|
{
|
||
|
m_focused = true;
|
||
|
|
||
|
if (!labelBut->GetFocused())
|
||
|
labelBut->SetFocused(true);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_focused = false;
|
||
|
|
||
|
if (labelBut->GetFocused())
|
||
|
labelBut->SetFocused(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
wxCustomButton::Paint(dc);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// ==========================================================================
|
||
|
// MenuLabelButton
|
||
|
// ==========================================================================
|
||
|
|
||
|
class MenuLabelButton : public wxCustomButton
|
||
|
{
|
||
|
public:
|
||
|
MenuLabelButton( wxWindow* parent, wxWindowID id,
|
||
|
const wxString &label,
|
||
|
const wxBitmap &bitmap,
|
||
|
long style ) : wxCustomButton()
|
||
|
{
|
||
|
Create(parent, id, label, bitmap, wxDefaultPosition, wxDefaultSize, style);
|
||
|
}
|
||
|
|
||
|
virtual void Paint( wxDC &dc )
|
||
|
{
|
||
|
wxCustomButton *dropBut = ((wxMenuButton*)GetParent())->GetDropDownButton();
|
||
|
|
||
|
// pretend that both buttons have focus (for flat style)
|
||
|
if (dropBut)
|
||
|
{
|
||
|
wxPoint p = GetParent()->ScreenToClient(wxGetMousePosition());
|
||
|
|
||
|
if (GetRect().Inside(p) || dropBut->GetRect().Inside(p))
|
||
|
{
|
||
|
m_focused = true;
|
||
|
|
||
|
if (!dropBut->GetFocused())
|
||
|
dropBut->SetFocused(true);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_focused = false;
|
||
|
|
||
|
if (dropBut->GetFocused())
|
||
|
dropBut->SetFocused(false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
wxCustomButton::Paint(dc);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// ==========================================================================
|
||
|
// wxMenuButton
|
||
|
// ==========================================================================
|
||
|
|
||
|
IMPLEMENT_DYNAMIC_CLASS( wxMenuButton, wxControl )
|
||
|
|
||
|
BEGIN_EVENT_TABLE(wxMenuButton,wxControl)
|
||
|
EVT_BUTTON(wxID_ANY, wxMenuButton::OnButton)
|
||
|
|
||
|
#ifdef __WXMSW__
|
||
|
EVT_MENU(wxID_ANY, wxMenuButton::OnMenu)
|
||
|
#endif
|
||
|
END_EVENT_TABLE()
|
||
|
|
||
|
wxMenuButton::~wxMenuButton()
|
||
|
{
|
||
|
AssignMenu(NULL, true);
|
||
|
}
|
||
|
|
||
|
void wxMenuButton::Init()
|
||
|
{
|
||
|
m_labelButton = NULL;
|
||
|
m_dropdownButton = NULL;
|
||
|
m_menu = NULL;
|
||
|
m_menu_static = false;
|
||
|
m_style = 0;
|
||
|
}
|
||
|
|
||
|
bool wxMenuButton::Create( wxWindow* parent, wxWindowID id,
|
||
|
const wxString &label,
|
||
|
const wxBitmap &bitmap,
|
||
|
const wxPoint& pos,
|
||
|
const wxSize& size,
|
||
|
long style,
|
||
|
const wxValidator& val,
|
||
|
const wxString& name)
|
||
|
{
|
||
|
m_style = style;
|
||
|
|
||
|
long flat = style & wxMENUBUT_FLAT;
|
||
|
|
||
|
wxControl::Create(parent,id,pos,size,wxNO_BORDER|wxCLIP_CHILDREN,val,name);
|
||
|
wxControl::SetLabel(label);
|
||
|
SetBackgroundColour(parent->GetBackgroundColour());
|
||
|
SetForegroundColour(parent->GetForegroundColour());
|
||
|
SetFont(parent->GetFont());
|
||
|
|
||
|
m_labelButton = new MenuLabelButton(this, id, label, bitmap, wxCUSTBUT_BUTTON|flat);
|
||
|
m_dropdownButton = new MenuDropButton(this, IDD_DROPDOWN_BUTTON, wxCUSTBUT_BUTTON|flat);
|
||
|
|
||
|
wxSize bestSize = DoGetBestSize();
|
||
|
SetSize( wxSize(size.x < 0 ? bestSize.x : size.x,
|
||
|
size.y < 0 ? bestSize.y : size.y) );
|
||
|
|
||
|
//SetBestSize(GetSize());
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
#ifdef __WXMSW__
|
||
|
// FIXME - I think there was a patch to fix this
|
||
|
void wxMenuButton::OnMenu( wxCommandEvent &event )
|
||
|
{
|
||
|
event.Skip();
|
||
|
wxMenuItem *mi = m_menu->FindItem(event.GetId());
|
||
|
if (mi && (mi->GetKind() == wxITEM_RADIO))
|
||
|
m_menu->Check(event.GetId(), true);
|
||
|
}
|
||
|
#endif // __WXMSW__
|
||
|
|
||
|
void wxMenuButton::OnButton( wxCommandEvent &event)
|
||
|
{
|
||
|
int win_id = event.GetId();
|
||
|
|
||
|
if (win_id == IDD_DROPDOWN_BUTTON)
|
||
|
{
|
||
|
if (m_menu)
|
||
|
{
|
||
|
wxNotifyEvent mevent(wxEVT_MENUBUTTON_OPEN, GetId());
|
||
|
mevent.SetEventObject(this);
|
||
|
if (GetEventHandler()->ProcessEvent(mevent) && !mevent.IsAllowed())
|
||
|
return;
|
||
|
|
||
|
if (!m_menu)
|
||
|
return;
|
||
|
|
||
|
PopupMenu(m_menu, wxPoint(0, GetSize().y));
|
||
|
|
||
|
m_labelButton->Refresh(false);
|
||
|
m_dropdownButton->Refresh(false);
|
||
|
}
|
||
|
}
|
||
|
else if (win_id == m_labelButton->GetId())
|
||
|
{
|
||
|
if (!m_menu) return;
|
||
|
|
||
|
const wxMenuItemList &items = m_menu->GetMenuItems();
|
||
|
int first_radio_id = -1;
|
||
|
int checked_id = -1;
|
||
|
bool check_next = false;
|
||
|
|
||
|
// find the next available radio item to check
|
||
|
for (wxMenuItemList::Node *node = items.GetFirst(); node; node = node->GetNext())
|
||
|
{
|
||
|
wxMenuItem *mi = (wxMenuItem*)node->GetData();
|
||
|
if (mi && (mi->GetKind() == wxITEM_RADIO))
|
||
|
{
|
||
|
if (first_radio_id == -1)
|
||
|
first_radio_id = mi->GetId();
|
||
|
|
||
|
if (check_next)
|
||
|
{
|
||
|
check_next = false;
|
||
|
checked_id = mi->GetId();
|
||
|
break;
|
||
|
}
|
||
|
else if (mi->IsChecked())
|
||
|
check_next = true;
|
||
|
}
|
||
|
}
|
||
|
// the last item was checked, go back to the first
|
||
|
if (check_next && (first_radio_id != -1))
|
||
|
checked_id = first_radio_id;
|
||
|
|
||
|
if (checked_id != -1)
|
||
|
{
|
||
|
m_menu->Check(checked_id, true);
|
||
|
|
||
|
wxCommandEvent mevent( wxEVT_COMMAND_MENU_SELECTED, checked_id);
|
||
|
mevent.SetEventObject( m_menu );
|
||
|
mevent.SetInt(1);
|
||
|
GetEventHandler()->ProcessEvent(mevent);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int wxMenuButton::GetSelection() const
|
||
|
{
|
||
|
wxCHECK_MSG(m_menu != NULL, wxNOT_FOUND, wxT("No attached menu in wxMenuButton::GetSelection"));
|
||
|
|
||
|
const wxMenuItemList &items = m_menu->GetMenuItems();
|
||
|
|
||
|
for (wxMenuItemList::Node *node = items.GetFirst(); node; node = node->GetNext())
|
||
|
{
|
||
|
wxMenuItem *mi = (wxMenuItem*)node->GetData();
|
||
|
if (mi && (mi->GetKind() == wxITEM_RADIO))
|
||
|
{
|
||
|
if (mi->IsChecked())
|
||
|
return mi->GetId();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return wxNOT_FOUND;
|
||
|
}
|
||
|
|
||
|
void wxMenuButton::AssignMenu(wxMenu *menu, bool static_menu)
|
||
|
{
|
||
|
if (!m_menu_static && m_menu)
|
||
|
delete m_menu;
|
||
|
|
||
|
m_menu = menu;
|
||
|
m_menu_static = static_menu;
|
||
|
}
|
||
|
|
||
|
void wxMenuButton::SetToolTip(const wxString &tip)
|
||
|
{
|
||
|
wxWindow::SetToolTip(tip);
|
||
|
((wxWindow*)m_labelButton)->SetToolTip(tip);
|
||
|
((wxWindow*)m_dropdownButton)->SetToolTip(tip);
|
||
|
}
|
||
|
void wxMenuButton::SetToolTip(wxToolTip *tip)
|
||
|
{
|
||
|
wxWindow::SetToolTip(tip);
|
||
|
((wxWindow*)m_labelButton)->SetToolTip(tip);
|
||
|
((wxWindow*)m_dropdownButton)->SetToolTip(tip);
|
||
|
}
|
||
|
|
||
|
void wxMenuButton::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
||
|
{
|
||
|
wxSize curSize( GetSize() );
|
||
|
wxSize bestSize( DoGetBestSize() );
|
||
|
|
||
|
if (width == -1)
|
||
|
width = curSize.GetWidth();
|
||
|
if (width < 10)
|
||
|
width = bestSize.GetWidth();
|
||
|
|
||
|
if (height == -1)
|
||
|
height = curSize.GetHeight();
|
||
|
if (height < 5)
|
||
|
height = bestSize.GetHeight();
|
||
|
|
||
|
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
|
||
|
|
||
|
if (m_labelButton)
|
||
|
m_labelButton->SetSize(0, 0, width - wxMENUBUTTON_DROP_WIDTH, height);
|
||
|
if (m_dropdownButton)
|
||
|
m_dropdownButton->SetSize(width-wxMENUBUTTON_DROP_WIDTH, 0, wxMENUBUTTON_DROP_WIDTH, height);
|
||
|
}
|
||
|
|
||
|
wxSize wxMenuButton::DoGetBestSize()
|
||
|
{
|
||
|
if (!m_labelButton || !m_dropdownButton)
|
||
|
return wxSize(wxMENUBUTTON_DROP_WIDTH+wxMENUBUTTON_DROP_HEIGHT, wxMENUBUTTON_DROP_HEIGHT);
|
||
|
|
||
|
wxSize size = m_labelButton->GetBestSize();
|
||
|
size.x += wxMENUBUTTON_DROP_WIDTH;
|
||
|
return size;
|
||
|
}
|