aseprite/src/ui/button.cpp

386 lines
9.0 KiB
C++
Raw Normal View History

// ASEPRITE gui library
2012-01-06 11:52:11 +08:00
// Copyright (C) 2001-2012 David Capello
//
// This source file is ditributed under a BSD-like license, please
// read LICENSE.txt for more information.
2007-09-19 07:57:02 +08:00
2009-07-13 04:29:16 +08:00
#include "config.h"
2007-09-19 07:57:02 +08:00
#include <allegro/gfx.h>
#include <allegro/keyboard.h>
#include <allegro/timer.h>
#include <queue>
2012-06-18 09:49:58 +08:00
#include <string.h>
2007-09-19 07:57:02 +08:00
2012-06-18 09:49:58 +08:00
#include "ui/button.h"
#include "ui/frame.h"
#include "ui/list.h"
#include "ui/manager.h"
#include "ui/message.h"
#include "ui/preferred_size_event.h"
#include "ui/rect.h"
#include "ui/theme.h"
#include "ui/widget.h"
2007-09-19 07:57:02 +08:00
namespace ui {
ButtonBase::ButtonBase(const char* text, int type, int behaviorType, int drawType)
: Widget(type)
, m_pressedStatus(false)
, m_handleSelect(true)
, m_behaviorType(behaviorType)
, m_drawType(drawType)
, m_iconInterface(NULL)
2007-09-19 07:57:02 +08:00
{
setAlign(JI_CENTER | JI_MIDDLE);
setText(text);
setFocusStop(true);
// Initialize theme
this->type = m_drawType; // TODO Fix this nasty trick
initTheme();
this->type = type;
2007-09-19 07:57:02 +08:00
}
ButtonBase::~ButtonBase()
2007-09-19 07:57:02 +08:00
{
if (m_iconInterface)
m_iconInterface->destroy();
2007-09-19 07:57:02 +08:00
}
int ButtonBase::getBehaviorType() const
2007-09-19 07:57:02 +08:00
{
return m_behaviorType;
2007-09-19 07:57:02 +08:00
}
int ButtonBase::getDrawType() const
2007-09-19 07:57:02 +08:00
{
return m_drawType;
2007-09-19 07:57:02 +08:00
}
void ButtonBase::setIconInterface(IButtonIcon* iconInterface)
2007-09-19 07:57:02 +08:00
{
if (m_iconInterface)
m_iconInterface->destroy();
2007-09-19 07:57:02 +08:00
m_iconInterface = iconInterface;
2007-09-19 07:57:02 +08:00
invalidate();
2007-09-19 07:57:02 +08:00
}
void ButtonBase::onClick(Event& ev)
2007-09-19 07:57:02 +08:00
{
// Fire Click() signal
Click(ev);
2007-09-19 07:57:02 +08:00
}
bool ButtonBase::onProcessMessage(Message* msg)
2007-09-19 07:57:02 +08:00
{
switch (msg->type) {
case JM_FOCUSENTER:
case JM_FOCUSLEAVE:
if (isEnabled()) {
if (m_behaviorType == JI_BUTTON) {
// Deselect the widget (maybe the user press the key, but
// before release it, changes the focus).
if (isSelected())
setSelected(false);
}
// TODO theme specific stuff
invalidate();
2007-09-19 07:57:02 +08:00
}
break;
case JM_KEYPRESSED:
// If the button is enabled.
if (isEnabled()) {
// For JI_BUTTON
if (m_behaviorType == JI_BUTTON) {
// Has focus and press enter/space
if (hasFocus()) {
if ((msg->key.scancode == KEY_ENTER) ||
(msg->key.scancode == KEY_ENTER_PAD) ||
(msg->key.scancode == KEY_SPACE)) {
setSelected(true);
return true;
}
}
// Check if the user pressed mnemonic.
if ((msg->any.shifts & KB_ALT_FLAG) &&
(isScancodeMnemonic(msg->key.scancode))) {
setSelected(true);
return true;
}
// Magnetic widget catches ENTERs
else if (isFocusMagnet() &&
((msg->key.scancode == KEY_ENTER) ||
(msg->key.scancode == KEY_ENTER_PAD))) {
getManager()->setFocus(this);
// Dispatch focus movement messages (because the buttons
// process them)
getManager()->dispatchMessages();
setSelected(true);
return true;
}
}
// For JI_CHECK or JI_RADIO
else {
/* if the widget has the focus and the user press space or
if the user press Alt+the underscored letter of the button */
if ((hasFocus() &&
(msg->key.scancode == KEY_SPACE)) ||
((msg->any.shifts & KB_ALT_FLAG) &&
(isScancodeMnemonic(msg->key.scancode)))) {
if (m_behaviorType == JI_CHECK) {
// Swap the select status
setSelected(!isSelected());
invalidate();
}
else if (m_behaviorType == JI_RADIO) {
if (!isSelected()) {
setSelected(true);
}
}
return true;
}
}
2007-09-19 07:57:02 +08:00
}
break;
case JM_KEYRELEASED:
if (isEnabled()) {
if (m_behaviorType == JI_BUTTON) {
if (isSelected()) {
generateButtonSelectSignal();
return true;
}
}
2007-09-19 07:57:02 +08:00
}
break;
case JM_BUTTONPRESSED:
switch (m_behaviorType) {
2007-09-19 07:57:02 +08:00
case JI_BUTTON:
if (isEnabled()) {
setSelected(true);
m_pressedStatus = isSelected();
captureMouse();
}
return true;
case JI_CHECK:
if (isEnabled()) {
setSelected(!isSelected());
m_pressedStatus = isSelected();
captureMouse();
}
return true;
case JI_RADIO:
if (isEnabled()) {
if (!isSelected()) {
m_handleSelect = false;
setSelected(true);
m_handleSelect = true;
m_pressedStatus = isSelected();
captureMouse();
}
}
return true;
2007-09-19 07:57:02 +08:00
}
break;
case JM_BUTTONRELEASED:
if (hasCapture()) {
releaseMouse();
if (hasMouseOver()) {
switch (m_behaviorType) {
case JI_BUTTON:
generateButtonSelectSignal();
break;
case JI_CHECK:
{
// Fire onClick() event
Event ev(this);
onClick(ev);
invalidate();
}
break;
case JI_RADIO:
{
setSelected(false);
setSelected(true);
// Fire onClick() event
Event ev(this);
onClick(ev);
}
break;
}
}
return true;
2007-09-19 07:57:02 +08:00
}
break;
case JM_MOTION:
if (isEnabled() && hasCapture()) {
bool hasMouse = hasMouseOver();
m_handleSelect = false;
// Switch state when the mouse go out
if ((hasMouse && isSelected() != m_pressedStatus) ||
(!hasMouse && isSelected() == m_pressedStatus)) {
if (hasMouse)
setSelected(m_pressedStatus);
else
setSelected(!m_pressedStatus);
}
m_handleSelect = true;
2007-09-19 07:57:02 +08:00
}
break;
2007-09-19 07:57:02 +08:00
case JM_MOUSEENTER:
case JM_MOUSELEAVE:
// TODO theme stuff
if (isEnabled())
invalidate();
2007-09-19 07:57:02 +08:00
break;
}
return Widget::onProcessMessage(msg);
2007-09-19 07:57:02 +08:00
}
void ButtonBase::onPreferredSize(PreferredSizeEvent& ev)
2007-09-19 07:57:02 +08:00
{
struct jrect box, text, icon;
jwidget_get_texticon_info(this, &box, &text, &icon,
m_iconInterface ? m_iconInterface->getIconAlign(): 0,
m_iconInterface ? m_iconInterface->getWidth(): 0,
m_iconInterface ? m_iconInterface->getHeight(): 0);
2007-09-19 07:57:02 +08:00
ev.setPreferredSize(this->border_width.l + jrect_w(&box) + this->border_width.r,
this->border_width.t + jrect_h(&box) + this->border_width.b);
}
2007-09-19 07:57:02 +08:00
void ButtonBase::onPaint(PaintEvent& ev)
{
switch (m_drawType) {
case JI_BUTTON: getTheme()->paintButton(ev); break;
case JI_CHECK: getTheme()->paintCheckBox(ev); break;
case JI_RADIO: getTheme()->paintRadioButton(ev); break;
}
}
void ButtonBase::generateButtonSelectSignal()
{
// Deselect
setSelected(false);
2007-09-19 07:57:02 +08:00
// Fire onClick() event
Event ev(this);
onClick(ev);
2007-09-19 07:57:02 +08:00
}
// ======================================================================
// Button class
// ======================================================================
Button::Button(const char *text)
: ButtonBase(text, JI_BUTTON, JI_BUTTON, JI_BUTTON)
2007-09-19 07:57:02 +08:00
{
setAlign(JI_CENTER | JI_MIDDLE);
}
2007-09-19 07:57:02 +08:00
// ======================================================================
// CheckBox class
// ======================================================================
2007-09-19 07:57:02 +08:00
CheckBox::CheckBox(const char *text, int drawType)
: ButtonBase(text, JI_CHECK, JI_CHECK, drawType)
{
setAlign(JI_LEFT | JI_MIDDLE);
}
2007-09-19 07:57:02 +08:00
// ======================================================================
// RadioButton class
// ======================================================================
2007-09-19 07:57:02 +08:00
RadioButton::RadioButton(const char *text, int radioGroup, int drawType)
: ButtonBase(text, JI_RADIO, JI_RADIO, drawType)
{
setAlign(JI_LEFT | JI_MIDDLE);
setRadioGroup(radioGroup);
}
2007-09-19 07:57:02 +08:00
void RadioButton::setRadioGroup(int radioGroup)
{
m_radioGroup = radioGroup;
// TODO: Update old and new groups
}
int RadioButton::getRadioGroup() const
{
return m_radioGroup;
}
void RadioButton::deselectRadioGroup()
{
Widget* widget = getRoot();
if (!widget)
return;
std::queue<Widget*> allChildrens;
allChildrens.push(widget);
while (!allChildrens.empty()) {
widget = allChildrens.front();
allChildrens.pop();
if (RadioButton* radioButton = dynamic_cast<RadioButton*>(widget)) {
if (radioButton->getRadioGroup() == m_radioGroup)
radioButton->setSelected(false);
}
JLink link;
JI_LIST_FOR_EACH(widget->children, link) {
allChildrens.push((Widget*)link->data);
2007-09-19 07:57:02 +08:00
}
}
}
void RadioButton::onSelect()
2007-09-19 07:57:02 +08:00
{
ButtonBase::onSelect();
2007-09-19 07:57:02 +08:00
if (!m_handleSelect)
return;
2007-09-19 07:57:02 +08:00
if (getBehaviorType() == JI_RADIO) {
deselectRadioGroup();
m_handleSelect = false;
setSelected(true);
m_handleSelect = true;
}
2007-09-19 07:57:02 +08:00
}
} // namespace ui