2015-02-12 23:16:25 +08:00
|
|
|
// Aseprite
|
|
|
|
// Copyright (C) 2001-2015 David Capello
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License version 2 as
|
|
|
|
// published by the Free Software Foundation.
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2012-04-20 07:33:57 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/button_set.h"
|
2014-09-08 13:27:41 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/modules/gui.h"
|
2014-09-08 13:27:41 +08:00
|
|
|
#include "app/ui/skin/skin_theme.h"
|
|
|
|
#include "base/bind.h"
|
|
|
|
#include "gfx/color.h"
|
|
|
|
#include "she/surface.h"
|
2012-06-18 09:49:58 +08:00
|
|
|
#include "ui/box.h"
|
|
|
|
#include "ui/button.h"
|
2014-09-08 13:27:41 +08:00
|
|
|
#include "ui/graphics.h"
|
|
|
|
#include "ui/message.h"
|
|
|
|
#include "ui/paint_event.h"
|
|
|
|
#include "ui/preferred_size_event.h"
|
2012-06-18 09:49:58 +08:00
|
|
|
#include "ui/system.h"
|
|
|
|
#include "ui/theme.h"
|
|
|
|
#include "ui/widget.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
#include <cstdarg>
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
namespace app {
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
using namespace ui;
|
2014-09-08 13:27:41 +08:00
|
|
|
using namespace app::skin;
|
2012-06-18 09:02:54 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
WidgetType buttonset_item_type()
|
2012-04-20 07:33:57 +08:00
|
|
|
{
|
2014-09-08 13:27:41 +08:00
|
|
|
static WidgetType type = kGenericWidget;
|
|
|
|
if (type == kGenericWidget)
|
|
|
|
type = register_widget_type();
|
|
|
|
return type;
|
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
ButtonSet::Item::Item()
|
|
|
|
: Widget(buttonset_item_type())
|
|
|
|
, m_icon(NULL)
|
|
|
|
{
|
2015-05-21 23:28:21 +08:00
|
|
|
setup_mini_font(this);
|
2015-08-12 23:38:07 +08:00
|
|
|
setAlign(CENTER | MIDDLE);
|
|
|
|
setFocusStop(true);
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2015-08-05 06:38:52 +08:00
|
|
|
void ButtonSet::Item::setIcon(const SkinPartPtr& icon)
|
2012-04-20 07:33:57 +08:00
|
|
|
{
|
2014-09-08 13:27:41 +08:00
|
|
|
m_icon = icon;
|
|
|
|
invalidate();
|
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
ButtonSet* ButtonSet::Item::buttonSet()
|
|
|
|
{
|
|
|
|
return static_cast<ButtonSet*>(getParent());
|
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
void ButtonSet::Item::onPaint(ui::PaintEvent& ev)
|
|
|
|
{
|
|
|
|
SkinTheme* theme = static_cast<SkinTheme*>(getTheme());
|
|
|
|
Graphics* g = ev.getGraphics();
|
|
|
|
gfx::Rect rc = getClientBounds();
|
2015-05-21 23:28:21 +08:00
|
|
|
gfx::Color fg, bg;
|
2015-08-05 06:38:52 +08:00
|
|
|
SkinPartPtr nw;
|
2015-08-12 23:38:07 +08:00
|
|
|
gfx::Rect boxRc, textRc, iconRc;
|
|
|
|
gfx::Size iconSize;
|
|
|
|
if (m_icon)
|
|
|
|
iconSize = m_icon->getSize();
|
|
|
|
|
|
|
|
getTextIconInfo(
|
|
|
|
&boxRc, &textRc, &iconRc,
|
|
|
|
CENTER | (hasText() ? BOTTOM: MIDDLE),
|
|
|
|
iconSize.w, iconSize.h);
|
|
|
|
|
|
|
|
textRc.y -= 1*guiscale();
|
|
|
|
iconRc.y -= 1*guiscale();
|
2014-09-08 13:27:41 +08:00
|
|
|
|
|
|
|
if (!gfx::is_transparent(getBgColor()))
|
|
|
|
g->fillRect(getBgColor(), g->getClipBounds());
|
|
|
|
|
|
|
|
if (isSelected() || hasMouseOver()) {
|
2015-04-07 22:29:36 +08:00
|
|
|
if (hasCapture()) {
|
2015-08-05 06:38:52 +08:00
|
|
|
nw = theme->parts.toolbuttonPushed();
|
2015-05-21 23:28:21 +08:00
|
|
|
fg = theme->colors.buttonSelectedText();
|
|
|
|
bg = theme->colors.buttonSelectedFace();
|
2015-04-07 22:29:36 +08:00
|
|
|
}
|
|
|
|
else {
|
2015-08-12 23:38:07 +08:00
|
|
|
nw = (hasFocus() ? theme->parts.toolbuttonHotFocused():
|
|
|
|
theme->parts.toolbuttonHot());
|
2015-05-21 23:28:21 +08:00
|
|
|
fg = theme->colors.buttonHotText();
|
|
|
|
bg = theme->colors.buttonHotFace();
|
2015-04-07 22:29:36 +08:00
|
|
|
}
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
|
|
|
else {
|
2015-08-12 23:38:07 +08:00
|
|
|
nw = (hasFocus() ? theme->parts.toolbuttonFocused():
|
|
|
|
theme->parts.toolbuttonLast());
|
2015-05-21 23:28:21 +08:00
|
|
|
fg = theme->colors.buttonNormalText();
|
|
|
|
bg = theme->colors.buttonNormalFace();
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
Grid::Info info = buttonSet()->getChildInfo(this);
|
2015-08-12 23:38:07 +08:00
|
|
|
if (info.col < info.grid_cols-1) rc.w += 1*guiscale();
|
|
|
|
if (info.row < info.grid_rows-1) rc.h += 3*guiscale();
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2015-08-05 06:38:52 +08:00
|
|
|
theme->drawRect(g, rc, nw.get(), bg);
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
if (m_icon) {
|
2015-04-07 22:29:36 +08:00
|
|
|
if (isSelected() && hasCapture())
|
2015-08-12 23:38:07 +08:00
|
|
|
g->drawColoredRgbaSurface(m_icon->getBitmap(0), theme->colors.buttonSelectedText(),
|
|
|
|
iconRc.x, iconRc.y);
|
2015-04-07 22:29:36 +08:00
|
|
|
else
|
2015-08-12 23:38:07 +08:00
|
|
|
g->drawRgbaSurface(m_icon->getBitmap(0), iconRc.x, iconRc.y);
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
2015-05-21 23:28:21 +08:00
|
|
|
|
2015-08-12 23:38:07 +08:00
|
|
|
if (hasText()) {
|
2015-05-21 23:28:21 +08:00
|
|
|
g->setFont(getFont());
|
2015-08-12 23:38:07 +08:00
|
|
|
g->drawUIString(getText(), fg, gfx::ColorNone, textRc.getOrigin(),
|
|
|
|
false);
|
2015-05-21 23:28:21 +08:00
|
|
|
}
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
bool ButtonSet::Item::onProcessMessage(ui::Message* msg)
|
|
|
|
{
|
|
|
|
switch (msg->type()) {
|
|
|
|
|
2015-08-12 23:38:07 +08:00
|
|
|
case kFocusEnterMessage:
|
|
|
|
case kFocusLeaveMessage:
|
|
|
|
if (isEnabled()) {
|
|
|
|
// TODO theme specific stuff
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ui::kKeyDownMessage:
|
|
|
|
if (isEnabled() && hasText()) {
|
|
|
|
KeyMessage* keymsg = static_cast<KeyMessage*>(msg);
|
|
|
|
bool mnemonicPressed =
|
|
|
|
(msg->altPressed() &&
|
|
|
|
getMnemonicChar() &&
|
|
|
|
getMnemonicChar() == tolower(keymsg->unicodeChar()));
|
|
|
|
|
|
|
|
if (mnemonicPressed ||
|
|
|
|
(hasFocus() && keymsg->scancode() == kKeySpace)) {
|
|
|
|
buttonSet()->setSelectedItem(this);
|
|
|
|
buttonSet()->onItemChange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
case ui::kMouseDownMessage:
|
|
|
|
captureMouse();
|
|
|
|
buttonSet()->setSelectedItem(this);
|
2015-04-07 22:29:36 +08:00
|
|
|
invalidate();
|
|
|
|
|
2015-05-08 06:08:24 +08:00
|
|
|
if (static_cast<MouseMessage*>(msg)->left() &&
|
|
|
|
!buttonSet()->m_triggerOnMouseUp) {
|
2015-04-07 13:29:33 +08:00
|
|
|
buttonSet()->onItemChange();
|
2015-05-08 06:08:24 +08:00
|
|
|
}
|
2014-09-08 13:27:41 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ui::kMouseUpMessage:
|
2015-04-07 13:29:33 +08:00
|
|
|
if (hasCapture()) {
|
2014-09-08 13:27:41 +08:00
|
|
|
releaseMouse();
|
2015-04-07 22:29:36 +08:00
|
|
|
invalidate();
|
|
|
|
|
2015-05-08 06:08:24 +08:00
|
|
|
if (static_cast<MouseMessage*>(msg)->left()) {
|
|
|
|
if (buttonSet()->m_triggerOnMouseUp)
|
|
|
|
buttonSet()->onItemChange();
|
|
|
|
}
|
|
|
|
else if (static_cast<MouseMessage*>(msg)->right()) {
|
|
|
|
buttonSet()->onRightClick(this);
|
|
|
|
}
|
2015-04-07 13:29:33 +08:00
|
|
|
}
|
2014-09-08 13:27:41 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ui::kMouseMoveMessage:
|
|
|
|
if (hasCapture()) {
|
|
|
|
if (buttonSet()->m_offerCapture)
|
|
|
|
offerCapture(static_cast<ui::MouseMessage*>(msg), buttonset_item_type());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ui::kMouseLeaveMessage:
|
|
|
|
case ui::kMouseEnterMessage:
|
|
|
|
invalidate();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return Widget::onProcessMessage(msg);
|
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
void ButtonSet::Item::onPreferredSize(ui::PreferredSizeEvent& ev)
|
|
|
|
{
|
2015-08-12 23:38:07 +08:00
|
|
|
gfx::Size iconSize;
|
2015-05-21 23:28:21 +08:00
|
|
|
if (m_icon) {
|
2015-08-12 23:38:07 +08:00
|
|
|
iconSize = m_icon->getSize();
|
|
|
|
iconSize.w = MAX(iconSize.w, 16*guiscale());
|
|
|
|
iconSize.h = MAX(iconSize.h, 16*guiscale());
|
2015-05-21 23:28:21 +08:00
|
|
|
}
|
2015-08-12 23:38:07 +08:00
|
|
|
|
|
|
|
gfx::Rect boxRc;
|
|
|
|
getTextIconInfo(
|
|
|
|
&boxRc, NULL, NULL,
|
|
|
|
CENTER | (hasText() ? BOTTOM: MIDDLE),
|
|
|
|
iconSize.w, iconSize.h);
|
|
|
|
|
|
|
|
gfx::Size sz = boxRc.getSize();
|
|
|
|
if (hasText())
|
|
|
|
sz += 8*guiscale();
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
Grid::Info info = buttonSet()->getChildInfo(this);
|
|
|
|
if (info.row == info.grid_rows-1)
|
2015-04-30 04:16:48 +08:00
|
|
|
sz.h += 3*guiscale();
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2015-07-07 03:43:28 +08:00
|
|
|
ev.setPreferredSize(sz);
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
ButtonSet::ButtonSet(int columns)
|
|
|
|
: Grid(columns, false)
|
|
|
|
, m_offerCapture(true)
|
2015-04-07 13:29:33 +08:00
|
|
|
, m_triggerOnMouseUp(false)
|
2014-09-08 13:27:41 +08:00
|
|
|
{
|
|
|
|
noBorderNoChildSpacing();
|
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2015-05-21 23:28:21 +08:00
|
|
|
void ButtonSet::addItem(const std::string& text, int hspan, int vspan)
|
|
|
|
{
|
|
|
|
Item* item = new Item();
|
|
|
|
item->setText(text);
|
|
|
|
addItem(item, hspan, vspan);
|
|
|
|
}
|
|
|
|
|
2015-08-05 06:38:52 +08:00
|
|
|
void ButtonSet::addItem(const skin::SkinPartPtr& icon, int hspan, int vspan)
|
2014-09-08 13:27:41 +08:00
|
|
|
{
|
|
|
|
Item* item = new Item();
|
|
|
|
item->setIcon(icon);
|
2015-04-29 23:32:44 +08:00
|
|
|
addItem(item, hspan, vspan);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ButtonSet::addItem(Item* item, int hspan, int vspan)
|
|
|
|
{
|
2015-08-12 23:38:07 +08:00
|
|
|
addChildInCell(item, hspan, vspan, HORIZONTAL | VERTICAL);
|
2014-09-08 13:27:41 +08:00
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
ButtonSet::Item* ButtonSet::getItem(int index)
|
|
|
|
{
|
|
|
|
return dynamic_cast<Item*>(at(index));
|
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
int ButtonSet::selectedItem() const
|
|
|
|
{
|
|
|
|
int index = 0;
|
|
|
|
for (Widget* child : getChildren()) {
|
|
|
|
if (child->isSelected())
|
|
|
|
return index;
|
|
|
|
++index;
|
2012-04-20 07:33:57 +08:00
|
|
|
}
|
2014-09-08 13:27:41 +08:00
|
|
|
return -1;
|
2012-04-20 07:33:57 +08:00
|
|
|
}
|
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
void ButtonSet::setSelectedItem(int index)
|
2012-04-20 07:33:57 +08:00
|
|
|
{
|
2014-09-08 13:27:41 +08:00
|
|
|
if (index >= 0 && index < (int)getChildren().size())
|
|
|
|
setSelectedItem(static_cast<Item*>(at(index)));
|
2012-04-20 07:33:57 +08:00
|
|
|
else
|
2014-09-08 13:27:41 +08:00
|
|
|
setSelectedItem(static_cast<Item*>(NULL));
|
2012-04-20 07:33:57 +08:00
|
|
|
}
|
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
void ButtonSet::setSelectedItem(Item* item)
|
2012-04-20 07:33:57 +08:00
|
|
|
{
|
2014-09-08 13:27:41 +08:00
|
|
|
if (item && item->isSelected())
|
2014-05-26 10:57:31 +08:00
|
|
|
return;
|
2012-04-20 07:33:57 +08:00
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
Item* sel = findSelectedItem();
|
|
|
|
if (sel)
|
|
|
|
sel->setSelected(false);
|
|
|
|
|
2015-08-12 23:38:07 +08:00
|
|
|
if (item) {
|
2014-09-08 13:27:41 +08:00
|
|
|
item->setSelected(true);
|
2015-08-12 23:38:07 +08:00
|
|
|
item->requestFocus();
|
|
|
|
}
|
2012-04-20 07:33:57 +08:00
|
|
|
}
|
|
|
|
|
2014-05-26 10:57:51 +08:00
|
|
|
void ButtonSet::deselectItems()
|
|
|
|
{
|
|
|
|
Item* sel = findSelectedItem();
|
|
|
|
if (sel)
|
|
|
|
sel->setSelected(false);
|
|
|
|
}
|
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
void ButtonSet::setOfferCapture(bool state)
|
2014-01-26 04:58:29 +08:00
|
|
|
{
|
2014-09-08 13:27:41 +08:00
|
|
|
m_offerCapture = state;
|
2014-01-26 04:58:29 +08:00
|
|
|
}
|
|
|
|
|
2015-04-07 13:29:33 +08:00
|
|
|
void ButtonSet::setTriggerOnMouseUp(bool state)
|
|
|
|
{
|
|
|
|
m_triggerOnMouseUp = state;
|
|
|
|
}
|
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
void ButtonSet::onItemChange()
|
2012-04-20 07:33:57 +08:00
|
|
|
{
|
2014-09-08 13:27:41 +08:00
|
|
|
ItemChange();
|
2012-04-20 07:33:57 +08:00
|
|
|
}
|
|
|
|
|
2015-05-08 06:08:24 +08:00
|
|
|
void ButtonSet::onRightClick(Item* item)
|
|
|
|
{
|
|
|
|
RightClick(item);
|
|
|
|
}
|
|
|
|
|
2014-09-08 13:27:41 +08:00
|
|
|
ButtonSet::Item* ButtonSet::findSelectedItem() const
|
2012-04-20 07:33:57 +08:00
|
|
|
{
|
2014-09-08 13:27:41 +08:00
|
|
|
for (Widget* child : getChildren()) {
|
|
|
|
if (child->isSelected())
|
|
|
|
return static_cast<Item*>(child);
|
|
|
|
}
|
|
|
|
return NULL;
|
2012-04-20 07:33:57 +08:00
|
|
|
}
|
2015-02-12 23:16:25 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
} // namespace app
|