573 lines
16 KiB
Text
573 lines
16 KiB
Text
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: wxCustomButton based on wxCustomToggleCtrl.cpp
|
|
// Purpose: a toggle button
|
|
// Author: Bruce Phillips
|
|
// Modified by: John Labenski
|
|
// Created: 11/05/2002
|
|
// RCS-ID:
|
|
// Copyright: (c) Bruce Phillips, John Labenki
|
|
// Licence: wxWidgets licence
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
|
|
#pragma implementation "toggle.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/settings.h"
|
|
#include "wx/bitmap.h"
|
|
#include "wx/timer.h"
|
|
#include "wx/dc.h"
|
|
#include "wx/dcclient.h"
|
|
#endif // WX_PRECOMP
|
|
|
|
#include "wx/tglbtn.h"
|
|
#include "wx/image.h"
|
|
#include "wx/things/toggle.h"
|
|
|
|
// ==========================================================================
|
|
// wxCustomButton
|
|
// ==========================================================================
|
|
IMPLEMENT_DYNAMIC_CLASS( wxCustomButton, wxControl )
|
|
|
|
BEGIN_EVENT_TABLE(wxCustomButton,wxControl)
|
|
EVT_MOUSE_EVENTS ( wxCustomButton::OnMouseEvents )
|
|
EVT_PAINT ( wxCustomButton::OnPaint )
|
|
EVT_TIMER ( wxID_ANY, wxCustomButton::OnTimer)
|
|
EVT_SIZE ( wxCustomButton::OnSize )
|
|
END_EVENT_TABLE()
|
|
|
|
wxCustomButton::~wxCustomButton()
|
|
{
|
|
if (HasCapture()) ReleaseMouse();
|
|
if (m_timer) delete m_timer;
|
|
}
|
|
|
|
void wxCustomButton::Init()
|
|
{
|
|
m_focused = false;
|
|
m_labelMargin = wxSize(4,4);
|
|
m_bitmapMargin = wxSize(2,2);
|
|
m_down = 0;
|
|
m_timer = NULL;
|
|
m_eventType = 0;
|
|
m_button_style = wxCUSTBUT_TOGGLE|wxCUSTBUT_BOTTOM;
|
|
}
|
|
|
|
bool wxCustomButton::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)
|
|
{
|
|
if (!wxControl::Create(parent,id,pos,size,wxNO_BORDER|wxCLIP_CHILDREN,val,name))
|
|
return false;
|
|
|
|
wxControl::SetLabel(label);
|
|
wxControl::SetBackgroundColour(parent->GetBackgroundColour());
|
|
wxControl::SetForegroundColour(parent->GetForegroundColour());
|
|
wxControl::SetFont(parent->GetFont());
|
|
|
|
if (bitmap.Ok()) m_bmpLabel = bitmap;
|
|
|
|
if (!SetButtonStyle(style)) return false;
|
|
|
|
wxSize bestSize = DoGetBestSize();
|
|
SetSize(wxSize(size.x<0 ? bestSize.x:size.x, size.y<0 ? bestSize.y:size.y));
|
|
SetBestSize(GetSize());
|
|
|
|
CalcLayout(true);
|
|
return true;
|
|
}
|
|
|
|
void wxCustomButton::SetValue(bool depressed)
|
|
{
|
|
wxCHECK_RET(!(m_button_style & wxCUSTBUT_NOTOGGLE), wxT("can't set button state"));
|
|
m_down = depressed ? 1 : 0;
|
|
Refresh(false);
|
|
}
|
|
|
|
bool wxCustomButton::SetButtonStyle(long style)
|
|
{
|
|
int n_styles = 0;
|
|
if ((style & wxCUSTBUT_LEFT) != 0) n_styles++;
|
|
if ((style & wxCUSTBUT_RIGHT) != 0) n_styles++;
|
|
if ((style & wxCUSTBUT_TOP) != 0) n_styles++;
|
|
if ((style & wxCUSTBUT_BOTTOM) != 0) n_styles++;
|
|
wxCHECK_MSG(n_styles < 2, false, wxT("Only one wxCustomButton label position allowed"));
|
|
|
|
n_styles = 0;
|
|
if ((style & wxCUSTBUT_NOTOGGLE) != 0) n_styles++;
|
|
if ((style & wxCUSTBUT_BUTTON) != 0) n_styles++;
|
|
if ((style & wxCUSTBUT_TOGGLE) != 0) n_styles++;
|
|
if ((style & wxCUSTBUT_BUT_DCLICK_TOG) != 0) n_styles++;
|
|
if ((style & wxCUSTBUT_TOG_DCLICK_BUT) != 0) n_styles++;
|
|
wxCHECK_MSG(n_styles < 2, false, wxT("Only one wxCustomButton style allowed"));
|
|
|
|
m_button_style = style;
|
|
|
|
if ((m_button_style & wxCUSTBUT_BUTTON) != 0)
|
|
m_down = 0;
|
|
|
|
CalcLayout(true);
|
|
return true;
|
|
}
|
|
|
|
void wxCustomButton::SetLabel( const wxString &label )
|
|
{
|
|
wxControl::SetLabel(label);
|
|
CalcLayout(true);
|
|
}
|
|
|
|
// sequence of events in GTK is up, dclick, up.
|
|
|
|
void wxCustomButton::OnMouseEvents(wxMouseEvent& event)
|
|
{
|
|
if (m_button_style & wxCUSTBUT_NOTOGGLE) return;
|
|
|
|
if (event.LeftDown() || event.RightDown())
|
|
{
|
|
if (!HasCapture())
|
|
CaptureMouse(); // keep depressed until up
|
|
|
|
m_down++;
|
|
Redraw();
|
|
}
|
|
else if (event.LeftDClick() || event.RightDClick())
|
|
{
|
|
m_down++; // GTK eats second down event
|
|
Redraw();
|
|
}
|
|
else if (event.LeftUp())
|
|
{
|
|
if (HasCapture())
|
|
ReleaseMouse();
|
|
|
|
m_eventType = wxEVT_LEFT_UP;
|
|
|
|
if (wxRect(wxPoint(0,0), GetSize()).Inside(event.GetPosition()))
|
|
{
|
|
if ((m_button_style & wxCUSTBUT_BUTTON) && (m_down > 0))
|
|
{
|
|
m_down = 0;
|
|
Redraw();
|
|
SendEvent();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if (!m_timer)
|
|
{
|
|
m_timer = new wxTimer(this, m_down+1);
|
|
m_timer->Start(200, true);
|
|
}
|
|
else
|
|
{
|
|
m_eventType = wxEVT_LEFT_DCLICK;
|
|
}
|
|
|
|
if ((m_button_style & wxCUSTBUT_TOGGLE) &&
|
|
(m_button_style & wxCUSTBUT_TOG_DCLICK_BUT)) m_down++;
|
|
}
|
|
}
|
|
|
|
Redraw();
|
|
}
|
|
else if (event.RightUp())
|
|
{
|
|
if (HasCapture())
|
|
ReleaseMouse();
|
|
|
|
m_eventType = wxEVT_RIGHT_UP;
|
|
|
|
if (wxRect(wxPoint(0,0), GetSize()).Inside(event.GetPosition()))
|
|
{
|
|
if ((m_button_style & wxCUSTBUT_BUTTON) && (m_down > 0))
|
|
{
|
|
m_down = 0;
|
|
Redraw();
|
|
SendEvent();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
m_down++;
|
|
|
|
if (!m_timer)
|
|
{
|
|
m_timer = new wxTimer(this, m_down);
|
|
m_timer->Start(250, true);
|
|
}
|
|
else
|
|
{
|
|
m_eventType = wxEVT_RIGHT_DCLICK;
|
|
}
|
|
}
|
|
}
|
|
|
|
Redraw();
|
|
}
|
|
else if (event.Entering())
|
|
{
|
|
m_focused = true;
|
|
if ((event.LeftIsDown() || event.RightIsDown()) && HasCapture())
|
|
m_down++;
|
|
|
|
Redraw();
|
|
}
|
|
else if (event.Leaving())
|
|
{
|
|
m_focused = false;
|
|
if ((event.LeftIsDown() || event.RightIsDown()) && HasCapture())
|
|
m_down--;
|
|
|
|
Redraw();
|
|
}
|
|
}
|
|
|
|
void wxCustomButton::OnTimer( wxTimerEvent &event )
|
|
{
|
|
m_timer->Stop();
|
|
delete m_timer;
|
|
m_timer = NULL;
|
|
|
|
// Clean up the button presses
|
|
// FIXME - GTK eats second left down for a DClick, who know about the others?
|
|
if (m_button_style & wxCUSTBUT_BUTTON)
|
|
{
|
|
m_down = 0;
|
|
}
|
|
else if (m_button_style & wxCUSTBUT_TOGGLE)
|
|
{
|
|
if (m_eventType == wxEVT_LEFT_UP)
|
|
m_down = event.GetId()%2 ? 0 : 1;
|
|
else
|
|
m_down = event.GetId()%2 ? 1 : 0;
|
|
}
|
|
else if (m_button_style & wxCUSTBUT_BUT_DCLICK_TOG)
|
|
{
|
|
if (m_eventType == wxEVT_LEFT_DCLICK)
|
|
m_down = event.GetId()%2 ? 0 : 1;
|
|
else
|
|
m_down = event.GetId()%2 ? 1 : 0;
|
|
}
|
|
else if (m_button_style & wxCUSTBUT_TOG_DCLICK_BUT)
|
|
{
|
|
if (m_eventType == wxEVT_LEFT_UP)
|
|
m_down = event.GetId()%2 ? 0 : 1;
|
|
else
|
|
m_down = event.GetId()%2 ? 1 : 0;
|
|
}
|
|
|
|
Refresh(false);
|
|
SendEvent();
|
|
}
|
|
|
|
void wxCustomButton::SendEvent()
|
|
{
|
|
if (((m_button_style & wxCUSTBUT_TOGGLE) && (m_eventType == wxEVT_LEFT_UP)) ||
|
|
((m_button_style & wxCUSTBUT_BUT_DCLICK_TOG) && (m_eventType == wxEVT_LEFT_DCLICK)) ||
|
|
((m_button_style & wxCUSTBUT_TOG_DCLICK_BUT) && (m_eventType == wxEVT_LEFT_UP)))
|
|
{
|
|
wxCommandEvent eventOut(wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, GetId());
|
|
eventOut.SetInt(m_down%2 ? 1 : 0);
|
|
eventOut.SetExtraLong(m_eventType);
|
|
eventOut.SetEventObject(this);
|
|
GetEventHandler()->ProcessEvent(eventOut);
|
|
}
|
|
else
|
|
{
|
|
wxCommandEvent eventOut(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
|
|
eventOut.SetInt(0);
|
|
eventOut.SetExtraLong(m_eventType);
|
|
eventOut.SetEventObject(this);
|
|
GetEventHandler()->ProcessEvent(eventOut);
|
|
}
|
|
}
|
|
|
|
wxBitmap wxCustomButton::CreateBitmapDisabled(const wxBitmap &bitmap) const
|
|
{
|
|
wxCHECK_MSG(bitmap.Ok(), wxNullBitmap, wxT("invalid bitmap"));
|
|
|
|
unsigned char br = GetBackgroundColour().Red();
|
|
unsigned char bg = GetBackgroundColour().Green();
|
|
unsigned char bb = GetBackgroundColour().Blue();
|
|
|
|
wxImage image = bitmap.ConvertToImage();
|
|
int pos, width = image.GetWidth(), height = image.GetHeight();
|
|
unsigned char *img_data = image.GetData();
|
|
|
|
for (int j=0; j<height; j++)
|
|
{
|
|
for (int i=j%2; i<width; i+=2)
|
|
{
|
|
pos = (j*width+i)*3;
|
|
img_data[pos ] = br;
|
|
img_data[pos+1] = bg;
|
|
img_data[pos+2] = bb;
|
|
}
|
|
}
|
|
|
|
return wxBitmap(image);
|
|
|
|
/* // FIXME why bother creating focused wxCustomButton's bitmap
|
|
wxImage imgFoc = bitmap.ConvertToImage();
|
|
|
|
bool mask = false;
|
|
unsigned char mr=0, mg=0, mb=0;
|
|
if (img.HasMask())
|
|
{
|
|
mask = true;
|
|
mr = imgDis.GetMaskRed();
|
|
mg = imgDis.GetMaskGreen();
|
|
mb = imgDis.GetMaskBlue();
|
|
}
|
|
unsigned char *r, *g, *b;
|
|
unsigned char *focData = imgFoc.GetData();
|
|
r = imgFoc.GetData();
|
|
g = imgFoc.GetData() + 1;
|
|
b = imgFoc.GetData() + 2;
|
|
for (int j=0; j<h; j++)
|
|
{
|
|
for (int i=0; i<w; i++)
|
|
{
|
|
if ((!mask || ((*r!=mr)&&(*b!=mb)&&(*g!=mg))) &&
|
|
((*r<236)&&(*b<236)&&(*g<236)))
|
|
{
|
|
*r += 20; *g += 20; *b += 20;
|
|
}
|
|
r += 3; g += 3; b += 3;
|
|
}
|
|
}
|
|
m_bmpFocus = wxBitmap(imgFoc);
|
|
*/
|
|
|
|
}
|
|
|
|
void wxCustomButton::SetBitmapLabel(const wxBitmap& bitmap)
|
|
{
|
|
m_bmpLabel = bitmap;
|
|
CalcLayout(true);
|
|
}
|
|
|
|
void wxCustomButton::OnPaint(wxPaintEvent& WXUNUSED(event))
|
|
{
|
|
wxPaintDC dc(this);
|
|
Paint(dc);
|
|
}
|
|
|
|
void wxCustomButton::Redraw()
|
|
{
|
|
wxClientDC dc(this);
|
|
Paint(dc);
|
|
}
|
|
|
|
void wxCustomButton::Paint( wxDC &dc )
|
|
{
|
|
dc.BeginDrawing();
|
|
|
|
int w, h;
|
|
GetSize(&w,&h);
|
|
|
|
wxColour foreColour = GetForegroundColour();
|
|
wxColour backColour = GetBackgroundColour();
|
|
|
|
if (m_focused)
|
|
{
|
|
backColour.Set( wxMin(backColour.Red() + 20, 255),
|
|
wxMin(backColour.Green() + 20, 255),
|
|
wxMin(backColour.Blue() + 20, 255) );
|
|
}
|
|
|
|
wxBitmap bitmap;
|
|
|
|
if (IsEnabled())
|
|
{
|
|
if (GetValue() && m_bmpSelected.Ok())
|
|
bitmap = m_bmpSelected;
|
|
else if (m_focused && m_bmpFocus.Ok())
|
|
bitmap = m_bmpFocus;
|
|
else if (m_bmpLabel.Ok())
|
|
bitmap = m_bmpLabel;
|
|
}
|
|
else
|
|
{
|
|
// try to create disabled if it doesn't exist
|
|
if (!m_bmpDisabled.Ok() && m_bmpLabel.Ok())
|
|
m_bmpDisabled = CreateBitmapDisabled(m_bmpLabel);
|
|
|
|
if (m_bmpDisabled.Ok())
|
|
bitmap = m_bmpDisabled;
|
|
else if (m_bmpLabel.Ok())
|
|
bitmap = m_bmpLabel;
|
|
|
|
foreColour = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
|
|
}
|
|
|
|
wxBrush brush(backColour, wxSOLID);
|
|
dc.SetBackground(brush);
|
|
dc.SetBrush(brush);
|
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
|
|
|
dc.DrawRectangle(0, 0, w, h);
|
|
|
|
if (bitmap.Ok())
|
|
dc.DrawBitmap(bitmap, m_bitmapPos.x, m_bitmapPos.y, true );
|
|
|
|
if (!GetLabel().IsEmpty())
|
|
{
|
|
dc.SetFont(GetFont());
|
|
dc.SetTextBackground(backColour);
|
|
dc.SetTextForeground(foreColour);
|
|
dc.DrawText(GetLabel(), m_labelPos.x, m_labelPos.y);
|
|
}
|
|
|
|
if (GetValue()) // draw sunken border
|
|
{
|
|
dc.SetPen(*wxGREY_PEN);
|
|
dc.DrawLine(0,h-1,0,0); dc.DrawLine(0,0,w,0);
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.DrawLine(w-1,1,w-1,h-1); dc.DrawLine(w-1,h-1,0,h-1);
|
|
dc.SetPen(*wxBLACK_PEN);
|
|
dc.DrawLine(1,h-2,1,1); dc.DrawLine(1,1,w-1,1);
|
|
}
|
|
else if (((m_button_style & wxCUSTBUT_FLAT) == 0) || m_focused) // draw raised border
|
|
{
|
|
dc.SetPen(*wxWHITE_PEN);
|
|
dc.DrawLine(0,h-2,0,0); dc.DrawLine(0,0,w-1,0);
|
|
dc.SetPen(*wxBLACK_PEN);
|
|
dc.DrawLine(w-1,0,w-1,h-1); dc.DrawLine(w-1,h-1,-1,h-1);
|
|
dc.SetPen(*wxGREY_PEN);
|
|
dc.DrawLine(2,h-2,w-2,h-2); dc.DrawLine(w-2,h-2,w-2,1);
|
|
}
|
|
|
|
dc.SetBackground(wxNullBrush);
|
|
dc.SetBrush(wxNullBrush);
|
|
dc.SetPen(wxNullPen);
|
|
dc.EndDrawing();
|
|
}
|
|
|
|
void wxCustomButton::OnSize( wxSizeEvent &event )
|
|
{
|
|
CalcLayout(true);
|
|
event.Skip();
|
|
}
|
|
|
|
void wxCustomButton::SetMargins(const wxSize &margin, bool fit)
|
|
{
|
|
m_labelMargin = margin;
|
|
m_bitmapMargin = margin;
|
|
CalcLayout(true);
|
|
if (fit) SetSize(DoGetBestSize());
|
|
}
|
|
void wxCustomButton::SetLabelMargin(const wxSize &margin, bool fit)
|
|
{
|
|
m_labelMargin = margin;
|
|
CalcLayout(true);
|
|
if (fit) SetSize(DoGetBestSize());
|
|
}
|
|
void wxCustomButton::SetBitmapMargin(const wxSize &margin, bool fit)
|
|
{
|
|
m_bitmapMargin = margin;
|
|
CalcLayout(true);
|
|
if (fit) SetSize(DoGetBestSize());
|
|
}
|
|
|
|
wxSize wxCustomButton::DoGetBestSize() const
|
|
{
|
|
int lw=0, lh=0;
|
|
int bw=0, bh=0;
|
|
bool has_bitmap = false;
|
|
bool has_label = false;
|
|
|
|
if (!GetLabel().IsEmpty())
|
|
{
|
|
GetTextExtent(GetLabel(), &lw, &lh);
|
|
lw += 2*m_labelMargin.x;
|
|
lh += 2*m_labelMargin.y;
|
|
has_label = true;
|
|
}
|
|
if (m_bmpLabel.Ok())
|
|
{
|
|
bw = m_bmpLabel.GetWidth() + 2*m_bitmapMargin.x;
|
|
bh = m_bmpLabel.GetHeight() + 2*m_bitmapMargin.y;
|
|
has_bitmap = true;
|
|
}
|
|
|
|
if ((m_button_style & wxCUSTBUT_LEFT) || (m_button_style & wxCUSTBUT_RIGHT))
|
|
{
|
|
int h = bh > lh ? bh : lh;
|
|
if (has_bitmap && has_label) lw -= wxMin(m_labelMargin.x, m_bitmapMargin.x);
|
|
return wxSize(lw+bw, h);
|
|
}
|
|
|
|
int w = bw > lw ? bw : lw;
|
|
if (has_bitmap && has_label) lh -= wxMin(m_labelMargin.y, m_bitmapMargin.y);
|
|
return wxSize(w, lh+bh);
|
|
}
|
|
|
|
void wxCustomButton::CalcLayout(bool refresh)
|
|
{
|
|
int w, h;
|
|
GetSize(&w,&h);
|
|
|
|
int bw = 0, bh = 0;
|
|
int lw = 0, lh = 0;
|
|
|
|
if (m_bmpLabel.Ok()) // assume they're all the same size
|
|
{
|
|
bw = m_bmpLabel.GetWidth();
|
|
bh = m_bmpLabel.GetHeight();
|
|
}
|
|
wxString label = GetLabel();
|
|
if (!label.IsEmpty())
|
|
{
|
|
GetTextExtent(label, &lw, &lh);
|
|
}
|
|
|
|
// Center the label or bitmap if only one or the other
|
|
if (!m_bmpLabel.Ok())
|
|
{
|
|
m_bitmapPos = wxPoint(0,0);
|
|
m_labelPos = wxPoint((w-lw)/2, (h-lh)/2);
|
|
}
|
|
else if (label.IsEmpty())
|
|
{
|
|
m_bitmapPos = wxPoint((w-bw)/2, (h-bh)/2);
|
|
m_labelPos = wxPoint(0,0);
|
|
}
|
|
else if (m_button_style & wxCUSTBUT_LEFT)
|
|
{
|
|
int mid_margin = wxMax(m_labelMargin.x, m_bitmapMargin.x);
|
|
m_labelPos = wxPoint((w - (bw+lw+m_labelMargin.x+m_bitmapMargin.x+mid_margin))/2 + m_labelMargin.x, (h - lh)/2);
|
|
m_bitmapPos = wxPoint(m_labelPos.x + lw + mid_margin, (h - bh)/2);
|
|
}
|
|
else if (m_button_style & wxCUSTBUT_RIGHT)
|
|
{
|
|
int mid_margin = wxMax(m_labelMargin.x, m_bitmapMargin.x);
|
|
m_bitmapPos = wxPoint((w - (bw+lw+m_labelMargin.x+m_bitmapMargin.x+mid_margin))/2 + m_bitmapMargin.x, (h - bh)/2);
|
|
m_labelPos = wxPoint(m_bitmapPos.x + bw + mid_margin, (h - lh)/2);
|
|
}
|
|
else if (m_button_style & wxCUSTBUT_TOP)
|
|
{
|
|
int mid_margin = wxMax(m_labelMargin.y, m_bitmapMargin.y);
|
|
m_labelPos = wxPoint((w - lw)/2, (h - (bh+lh+m_labelMargin.y+m_bitmapMargin.y+mid_margin))/2 + m_labelMargin.y);
|
|
m_bitmapPos = wxPoint((w - bw)/2, m_labelPos.y + lh + mid_margin);
|
|
}
|
|
else // if (m_button_style & wxCUSTBUT_BOTTOM) DEFAULT
|
|
{
|
|
int mid_margin = wxMax(m_labelMargin.y, m_bitmapMargin.y);
|
|
m_bitmapPos = wxPoint((w - bw)/2, (h - (bh+lh+m_labelMargin.y+m_bitmapMargin.y+mid_margin))/2 + m_bitmapMargin.y);
|
|
m_labelPos = wxPoint((w - lw)/2, m_bitmapPos.y + bh + mid_margin);
|
|
}
|
|
|
|
if (refresh) Refresh(false);
|
|
}
|