2013-08-09 08:01:20 +08:00
|
|
|
// Aseprite UI Library
|
2013-01-27 23:13:13 +08:00
|
|
|
// Copyright (C) 2001-2013 David Capello
|
2010-09-28 06:18:17 +08:00
|
|
|
//
|
2014-03-30 07:08:05 +08:00
|
|
|
// This file is released under the terms of the MIT license.
|
|
|
|
// Read LICENSE.txt for more information.
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2009-07-13 04:29:16 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
2009-07-13 04:29:16 +08:00
|
|
|
|
2012-06-18 09:49:58 +08:00
|
|
|
#include "ui/button.h"
|
|
|
|
#include "ui/manager.h"
|
|
|
|
#include "ui/message.h"
|
|
|
|
#include "ui/preferred_size_event.h"
|
|
|
|
#include "ui/theme.h"
|
|
|
|
#include "ui/widget.h"
|
2012-07-09 10:24:42 +08:00
|
|
|
#include "ui/window.h"
|
|
|
|
|
|
|
|
#include <allegro/gfx.h>
|
|
|
|
#include <allegro/keyboard.h>
|
|
|
|
#include <allegro/timer.h>
|
|
|
|
#include <queue>
|
|
|
|
#include <string.h>
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
namespace ui {
|
|
|
|
|
2013-10-15 06:58:11 +08:00
|
|
|
ButtonBase::ButtonBase(const base::string& text,
|
2013-04-04 09:07:24 +08:00
|
|
|
WidgetType type,
|
|
|
|
WidgetType behaviorType,
|
|
|
|
WidgetType drawType)
|
2010-08-24 04:41:19 +08:00
|
|
|
: Widget(type)
|
2012-06-16 10:37:59 +08:00
|
|
|
, m_pressedStatus(false)
|
|
|
|
, m_handleSelect(true)
|
2011-03-07 03:15:05 +08:00
|
|
|
, m_behaviorType(behaviorType)
|
|
|
|
, m_drawType(drawType)
|
|
|
|
, m_iconInterface(NULL)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2012-06-16 10:37:59 +08:00
|
|
|
setAlign(JI_CENTER | JI_MIDDLE);
|
|
|
|
setText(text);
|
|
|
|
setFocusStop(true);
|
2010-08-24 04:41:19 +08:00
|
|
|
|
|
|
|
// Initialize theme
|
2012-01-06 06:45:03 +08:00
|
|
|
this->type = m_drawType; // TODO Fix this nasty trick
|
2011-02-15 20:00:29 +08:00
|
|
|
initTheme();
|
2010-08-24 04:41:19 +08:00
|
|
|
this->type = type;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 04:41:19 +08:00
|
|
|
ButtonBase::~ButtonBase()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2011-03-07 03:15:05 +08:00
|
|
|
if (m_iconInterface)
|
|
|
|
m_iconInterface->destroy();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2013-04-04 09:07:24 +08:00
|
|
|
WidgetType ButtonBase::getBehaviorType() const
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2011-03-07 03:15:05 +08:00
|
|
|
return m_behaviorType;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2013-04-04 09:07:24 +08:00
|
|
|
WidgetType ButtonBase::getDrawType() const
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2011-03-07 03:15:05 +08:00
|
|
|
return m_drawType;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2011-03-07 03:15:05 +08:00
|
|
|
void ButtonBase::setIconInterface(IButtonIcon* iconInterface)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2011-03-07 03:15:05 +08:00
|
|
|
if (m_iconInterface)
|
|
|
|
m_iconInterface->destroy();
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2011-03-07 03:15:05 +08:00
|
|
|
m_iconInterface = iconInterface;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2011-03-07 03:15:05 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 04:41:19 +08:00
|
|
|
void ButtonBase::onClick(Event& ev)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-08-24 04:41:19 +08:00
|
|
|
// Fire Click() signal
|
|
|
|
Click(ev);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2011-04-03 00:14:07 +08:00
|
|
|
bool ButtonBase::onProcessMessage(Message* msg)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2013-07-29 08:17:07 +08:00
|
|
|
switch (msg->type()) {
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kFocusEnterMessage:
|
|
|
|
case kFocusLeaveMessage:
|
2012-06-16 10:37:59 +08:00
|
|
|
if (isEnabled()) {
|
2013-04-04 09:07:24 +08:00
|
|
|
if (m_behaviorType == kButtonWidget) {
|
2012-06-16 10:37:59 +08:00
|
|
|
// Deselect the widget (maybe the user press the key, but
|
|
|
|
// before release it, changes the focus).
|
|
|
|
if (isSelected())
|
|
|
|
setSelected(false);
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
// TODO theme specific stuff
|
2012-01-06 06:45:03 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-07-29 08:17:07 +08:00
|
|
|
case kKeyDownMessage: {
|
|
|
|
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
|
|
|
|
KeyScancode scancode = keymsg->scancode();
|
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
// If the button is enabled.
|
|
|
|
if (isEnabled()) {
|
2013-04-04 09:07:24 +08:00
|
|
|
// For kButtonWidget
|
|
|
|
if (m_behaviorType == kButtonWidget) {
|
2012-06-16 10:37:59 +08:00
|
|
|
// Has focus and press enter/space
|
|
|
|
if (hasFocus()) {
|
2013-07-29 08:17:07 +08:00
|
|
|
if ((scancode == kKeyEnter) ||
|
|
|
|
(scancode == kKeyEnterPad) ||
|
|
|
|
(scancode == kKeySpace)) {
|
2012-06-16 10:37:59 +08:00
|
|
|
setSelected(true);
|
2012-01-06 06:45:03 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2012-04-16 02:43:07 +08:00
|
|
|
// Check if the user pressed mnemonic.
|
2013-07-29 08:17:07 +08:00
|
|
|
if ((msg->altPressed()) && (isScancodeMnemonic(scancode))) {
|
2012-06-16 10:37:59 +08:00
|
|
|
setSelected(true);
|
2012-01-06 06:45:03 +08:00
|
|
|
return true;
|
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
// Magnetic widget catches ENTERs
|
|
|
|
else if (isFocusMagnet() &&
|
2013-07-29 08:17:07 +08:00
|
|
|
((scancode == kKeyEnter) ||
|
|
|
|
(scancode == kKeyEnterPad))) {
|
2012-04-16 02:21:24 +08:00
|
|
|
getManager()->setFocus(this);
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2012-04-16 02:21:24 +08:00
|
|
|
// Dispatch focus movement messages (because the buttons
|
|
|
|
// process them)
|
|
|
|
getManager()->dispatchMessages();
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
setSelected(true);
|
2012-01-06 06:45:03 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2013-04-04 09:07:24 +08:00
|
|
|
// For kCheckWidget or kRadioWidget
|
2012-01-06 06:45:03 +08:00
|
|
|
else {
|
|
|
|
/* if the widget has the focus and the user press space or
|
|
|
|
if the user press Alt+the underscored letter of the button */
|
2012-06-16 10:37:59 +08:00
|
|
|
if ((hasFocus() &&
|
2013-07-29 08:17:07 +08:00
|
|
|
(scancode == kKeySpace)) ||
|
|
|
|
((msg->altPressed()) &&
|
|
|
|
(isScancodeMnemonic(scancode)))) {
|
2013-04-04 09:07:24 +08:00
|
|
|
if (m_behaviorType == kCheckWidget) {
|
2012-01-06 06:45:03 +08:00
|
|
|
// Swap the select status
|
2012-06-16 10:37:59 +08:00
|
|
|
setSelected(!isSelected());
|
2012-01-06 06:45:03 +08:00
|
|
|
|
|
|
|
invalidate();
|
|
|
|
}
|
2013-04-04 09:07:24 +08:00
|
|
|
else if (m_behaviorType == kRadioWidget) {
|
2012-06-16 10:37:59 +08:00
|
|
|
if (!isSelected()) {
|
|
|
|
setSelected(true);
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
break;
|
2013-07-29 08:17:07 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kKeyUpMessage:
|
2012-06-16 10:37:59 +08:00
|
|
|
if (isEnabled()) {
|
2013-04-04 09:07:24 +08:00
|
|
|
if (m_behaviorType == kButtonWidget) {
|
2012-06-16 10:37:59 +08:00
|
|
|
if (isSelected()) {
|
2012-01-06 06:45:03 +08:00
|
|
|
generateButtonSelectSignal();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseDownMessage:
|
2010-08-24 04:41:19 +08:00
|
|
|
switch (m_behaviorType) {
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-04-04 09:07:24 +08:00
|
|
|
case kButtonWidget:
|
2012-06-16 10:37:59 +08:00
|
|
|
if (isEnabled()) {
|
|
|
|
setSelected(true);
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
m_pressedStatus = isSelected();
|
|
|
|
captureMouse();
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
2013-04-04 09:07:24 +08:00
|
|
|
case kCheckWidget:
|
2012-06-16 10:37:59 +08:00
|
|
|
if (isEnabled()) {
|
|
|
|
setSelected(!isSelected());
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
m_pressedStatus = isSelected();
|
|
|
|
captureMouse();
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
|
2013-04-04 09:07:24 +08:00
|
|
|
case kRadioWidget:
|
2012-06-16 10:37:59 +08:00
|
|
|
if (isEnabled()) {
|
|
|
|
if (!isSelected()) {
|
|
|
|
m_handleSelect = false;
|
|
|
|
setSelected(true);
|
|
|
|
m_handleSelect = true;
|
|
|
|
|
|
|
|
m_pressedStatus = isSelected();
|
|
|
|
captureMouse();
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseUpMessage:
|
2012-06-16 10:37:59 +08:00
|
|
|
if (hasCapture()) {
|
|
|
|
releaseMouse();
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
if (hasMouseOver()) {
|
2012-01-06 06:45:03 +08:00
|
|
|
switch (m_behaviorType) {
|
|
|
|
|
2013-04-04 09:07:24 +08:00
|
|
|
case kButtonWidget:
|
2012-01-06 06:45:03 +08:00
|
|
|
generateButtonSelectSignal();
|
|
|
|
break;
|
|
|
|
|
2013-04-04 09:07:24 +08:00
|
|
|
case kCheckWidget:
|
2012-01-06 06:45:03 +08:00
|
|
|
{
|
|
|
|
// Fire onClick() event
|
|
|
|
Event ev(this);
|
|
|
|
onClick(ev);
|
|
|
|
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-04-04 09:07:24 +08:00
|
|
|
case kRadioWidget:
|
2012-01-06 06:45:03 +08:00
|
|
|
{
|
2012-06-16 10:37:59 +08:00
|
|
|
setSelected(false);
|
|
|
|
setSelected(true);
|
2012-01-06 06:45:03 +08:00
|
|
|
|
|
|
|
// Fire onClick() event
|
|
|
|
Event ev(this);
|
|
|
|
onClick(ev);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseMoveMessage:
|
2012-06-16 10:37:59 +08:00
|
|
|
if (isEnabled() && hasCapture()) {
|
|
|
|
bool hasMouse = hasMouseOver();
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
m_handleSelect = false;
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
// 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);
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
m_handleSelect = true;
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2010-04-25 23:03:25 +08:00
|
|
|
break;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-04-05 08:53:29 +08:00
|
|
|
case kMouseEnterMessage:
|
|
|
|
case kMouseLeaveMessage:
|
2010-04-25 23:03:25 +08:00
|
|
|
// TODO theme stuff
|
2012-06-16 10:37:59 +08:00
|
|
|
if (isEnabled())
|
2012-01-06 06:45:03 +08:00
|
|
|
invalidate();
|
2007-09-19 07:57:02 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-08-24 04:41:19 +08:00
|
|
|
return Widget::onProcessMessage(msg);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 04:41:19 +08:00
|
|
|
void ButtonBase::onPreferredSize(PreferredSizeEvent& ev)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2013-10-26 23:50:55 +08:00
|
|
|
gfx::Rect box;
|
2014-04-20 02:18:16 +08:00
|
|
|
getTextIconInfo(&box, NULL, NULL,
|
|
|
|
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
|
|
|
|
2013-10-26 23:50:55 +08:00
|
|
|
ev.setPreferredSize(border_width.l + box.w + border_width.r,
|
|
|
|
border_width.t + box.h + border_width.b);
|
2010-08-24 04:41:19 +08:00
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2011-02-12 20:32:57 +08:00
|
|
|
void ButtonBase::onPaint(PaintEvent& ev)
|
|
|
|
{
|
|
|
|
switch (m_drawType) {
|
2013-04-04 09:07:24 +08:00
|
|
|
case kButtonWidget: getTheme()->paintButton(ev); break;
|
|
|
|
case kCheckWidget: getTheme()->paintCheckBox(ev); break;
|
|
|
|
case kRadioWidget: getTheme()->paintRadioButton(ev); break;
|
2011-02-12 20:32:57 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-24 04:41:19 +08:00
|
|
|
void ButtonBase::generateButtonSelectSignal()
|
|
|
|
{
|
|
|
|
// Deselect
|
2012-06-16 10:37:59 +08:00
|
|
|
setSelected(false);
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-08-24 04:41:19 +08:00
|
|
|
// Fire onClick() event
|
2010-09-30 04:14:11 +08:00
|
|
|
Event ev(this);
|
2010-08-24 04:41:19 +08:00
|
|
|
onClick(ev);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
|
2010-08-24 04:41:19 +08:00
|
|
|
// ======================================================================
|
|
|
|
// Button class
|
|
|
|
// ======================================================================
|
|
|
|
|
2013-10-15 06:58:11 +08:00
|
|
|
Button::Button(const base::string& text)
|
2013-04-04 09:07:24 +08:00
|
|
|
: ButtonBase(text, kButtonWidget, kButtonWidget, kButtonWidget)
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2010-08-24 04:41:19 +08:00
|
|
|
setAlign(JI_CENTER | JI_MIDDLE);
|
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-08-24 04:41:19 +08:00
|
|
|
// ======================================================================
|
|
|
|
// CheckBox class
|
|
|
|
// ======================================================================
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-10-15 06:58:11 +08:00
|
|
|
CheckBox::CheckBox(const base::string& text, WidgetType drawType)
|
2013-04-04 09:07:24 +08:00
|
|
|
: ButtonBase(text, kCheckWidget, kCheckWidget, drawType)
|
2010-08-24 04:41:19 +08:00
|
|
|
{
|
|
|
|
setAlign(JI_LEFT | JI_MIDDLE);
|
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-08-24 04:41:19 +08:00
|
|
|
// ======================================================================
|
|
|
|
// RadioButton class
|
|
|
|
// ======================================================================
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-10-15 06:58:11 +08:00
|
|
|
RadioButton::RadioButton(const base::string& text, int radioGroup, WidgetType drawType)
|
2013-04-04 09:07:24 +08:00
|
|
|
: ButtonBase(text, kRadioWidget, kRadioWidget, drawType)
|
2010-08-24 04:41:19 +08:00
|
|
|
{
|
|
|
|
setAlign(JI_LEFT | JI_MIDDLE);
|
|
|
|
setRadioGroup(radioGroup);
|
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2010-08-24 04:41:19 +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)
|
2012-01-06 06:45:03 +08:00
|
|
|
radioButton->setSelected(false);
|
2010-08-24 04:41:19 +08:00
|
|
|
}
|
|
|
|
|
2012-07-18 08:42:02 +08:00
|
|
|
UI_FOREACH_WIDGET(widget->getChildren(), it) {
|
|
|
|
allChildrens.push(*it);
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
void RadioButton::onSelect()
|
2007-09-19 07:57:02 +08:00
|
|
|
{
|
2012-06-16 10:37:59 +08:00
|
|
|
ButtonBase::onSelect();
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
if (!m_handleSelect)
|
|
|
|
return;
|
2007-09-19 07:57:02 +08:00
|
|
|
|
2013-04-04 09:07:24 +08:00
|
|
|
if (getBehaviorType() == kRadioWidget) {
|
2012-06-16 10:37:59 +08:00
|
|
|
deselectRadioGroup();
|
2010-08-24 04:41:19 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
m_handleSelect = false;
|
|
|
|
setSelected(true);
|
|
|
|
m_handleSelect = true;
|
|
|
|
}
|
2007-09-19 07:57:02 +08:00
|
|
|
}
|
2012-06-18 09:02:54 +08:00
|
|
|
|
|
|
|
} // namespace ui
|