2012-01-06 12:12:57 +08:00
|
|
|
// ASEPRITE gui library
|
2013-01-27 23:13:13 +08:00
|
|
|
// Copyright (C) 2001-2013 David Capello
|
2011-01-21 05:32:31 +08:00
|
|
|
//
|
2012-09-24 10:24:07 +08:00
|
|
|
// This source file is distributed under a BSD-like license, please
|
2011-01-21 05:32:31 +08:00
|
|
|
// read LICENSE.txt for more information.
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2009-07-13 04:29:16 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
2008-02-11 02:49:12 +08:00
|
|
|
#include <allegro.h>
|
2012-06-18 09:49:58 +08:00
|
|
|
#include <string>
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2012-04-08 00:12:01 +08:00
|
|
|
#include "base/unique_ptr.h"
|
2010-09-30 04:14:11 +08:00
|
|
|
#include "gfx/size.h"
|
2012-06-18 09:49:58 +08:00
|
|
|
#include "ui/graphics.h"
|
|
|
|
#include "ui/gui.h"
|
|
|
|
#include "ui/intern.h"
|
|
|
|
#include "ui/paint_event.h"
|
|
|
|
#include "ui/preferred_size_event.h"
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2012-07-06 12:06:00 +08:00
|
|
|
static const int kTooltipDelayMsecs = 300;
|
2010-09-26 03:22:32 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
using namespace gfx;
|
2008-03-01 03:29:49 +08:00
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
namespace ui {
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
TooltipManager::TooltipManager()
|
|
|
|
: Widget(JI_WIDGET)
|
2008-02-11 02:49:12 +08:00
|
|
|
{
|
2012-06-16 10:37:59 +08:00
|
|
|
Manager* manager = Manager::getDefault();
|
|
|
|
manager->addMessageFilter(JM_MOUSEENTER, this);
|
|
|
|
manager->addMessageFilter(JM_KEYPRESSED, this);
|
|
|
|
manager->addMessageFilter(JM_BUTTONPRESSED, this);
|
|
|
|
manager->addMessageFilter(JM_MOUSELEAVE, this);
|
2008-03-15 09:54:45 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
setVisible(false);
|
2008-02-11 02:49:12 +08:00
|
|
|
}
|
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
TooltipManager::~TooltipManager()
|
2008-02-11 02:49:12 +08:00
|
|
|
{
|
2012-06-16 10:37:59 +08:00
|
|
|
Manager* manager = Manager::getDefault();
|
|
|
|
manager->removeMessageFilterFor(this);
|
2008-02-11 02:49:12 +08:00
|
|
|
}
|
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
void TooltipManager::addTooltipFor(Widget* widget, const char* text, int arrowAlign)
|
2008-02-11 02:49:12 +08:00
|
|
|
{
|
2012-06-16 10:37:59 +08:00
|
|
|
m_tips[widget] = TipInfo(text, arrowAlign);
|
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
bool TooltipManager::onProcessMessage(Message* msg)
|
|
|
|
{
|
2008-02-11 02:49:12 +08:00
|
|
|
switch (msg->type) {
|
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
case JM_MOUSEENTER: {
|
2012-07-18 08:42:02 +08:00
|
|
|
UI_FOREACH_WIDGET(*msg->any.widgets, itWidget) {
|
|
|
|
Tips::iterator it = m_tips.find(*itWidget);
|
2012-06-16 10:37:59 +08:00
|
|
|
if (it != m_tips.end()) {
|
|
|
|
m_target.widget = it->first;
|
|
|
|
m_target.tipInfo = it->second;
|
|
|
|
|
|
|
|
if (m_timer == NULL) {
|
2012-07-06 12:06:00 +08:00
|
|
|
m_timer.reset(new Timer(kTooltipDelayMsecs, this));
|
2012-06-16 10:37:59 +08:00
|
|
|
m_timer->Tick.connect(&TooltipManager::onTick, this);
|
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
m_timer->start();
|
|
|
|
}
|
|
|
|
}
|
2012-06-16 11:48:29 +08:00
|
|
|
return false;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2008-02-19 07:33:48 +08:00
|
|
|
case JM_KEYPRESSED:
|
|
|
|
case JM_BUTTONPRESSED:
|
2008-02-11 02:49:12 +08:00
|
|
|
case JM_MOUSELEAVE:
|
2012-06-16 10:37:59 +08:00
|
|
|
if (m_tipWindow) {
|
|
|
|
m_tipWindow->closeWindow(NULL);
|
|
|
|
m_tipWindow.reset();
|
2008-02-19 07:33:48 +08:00
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
if (m_timer)
|
|
|
|
m_timer->stop();
|
2012-06-16 11:48:29 +08:00
|
|
|
|
|
|
|
return false;
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
2012-06-16 11:48:29 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
return Widget::onProcessMessage(msg);
|
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
void TooltipManager::onTick()
|
|
|
|
{
|
|
|
|
if (!m_tipWindow) {
|
|
|
|
m_tipWindow.reset(new TipWindow(m_target.tipInfo.text.c_str(), true));
|
|
|
|
gfx::Rect bounds = m_target.widget->getBounds();
|
|
|
|
int x = jmouse_x(0)+12*jguiscale();
|
|
|
|
int y = jmouse_y(0)+12*jguiscale();
|
|
|
|
int w, h;
|
|
|
|
|
|
|
|
m_tipWindow->setArrowAlign(m_target.tipInfo.arrowAlign);
|
2013-01-11 23:43:25 +08:00
|
|
|
m_tipWindow->remapWindow();
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
w = jrect_w(m_tipWindow->rc);
|
|
|
|
h = jrect_h(m_tipWindow->rc);
|
|
|
|
|
|
|
|
switch (m_target.tipInfo.arrowAlign) {
|
|
|
|
case JI_TOP | JI_LEFT:
|
|
|
|
x = bounds.x + bounds.w;
|
|
|
|
y = bounds.y + bounds.h;
|
|
|
|
break;
|
|
|
|
case JI_TOP | JI_RIGHT:
|
|
|
|
x = bounds.x - w;
|
|
|
|
y = bounds.y + bounds.h;
|
|
|
|
break;
|
|
|
|
case JI_BOTTOM | JI_LEFT:
|
|
|
|
x = bounds.x + bounds.w;
|
|
|
|
y = bounds.y - h;
|
|
|
|
break;
|
|
|
|
case JI_BOTTOM | JI_RIGHT:
|
|
|
|
x = bounds.x - w;
|
|
|
|
y = bounds.y - h;
|
|
|
|
break;
|
|
|
|
case JI_TOP:
|
|
|
|
x = bounds.x + bounds.w/2 - w/2;
|
|
|
|
y = bounds.y + bounds.h;
|
|
|
|
break;
|
|
|
|
case JI_BOTTOM:
|
|
|
|
x = bounds.x + bounds.w/2 - w/2;
|
|
|
|
y = bounds.y - h;
|
|
|
|
break;
|
|
|
|
case JI_LEFT:
|
|
|
|
x = bounds.x + bounds.w;
|
|
|
|
y = bounds.y + bounds.h/2 - h/2;
|
|
|
|
break;
|
|
|
|
case JI_RIGHT:
|
|
|
|
x = bounds.x - w;
|
|
|
|
y = bounds.y + bounds.h/2 - h/2;
|
|
|
|
break;
|
|
|
|
}
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
// if (x+w > JI_SCREEN_W) {
|
|
|
|
// x = jmouse_x(0) - w - 4*jguiscale();
|
|
|
|
// y = jmouse_y(0);
|
|
|
|
// }
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2013-01-11 23:43:25 +08:00
|
|
|
m_tipWindow->positionWindow(MID(0, x, JI_SCREEN_W-w),
|
|
|
|
MID(0, y, JI_SCREEN_H-h));
|
2012-07-09 10:24:42 +08:00
|
|
|
m_tipWindow->openWindow();
|
2008-02-11 02:49:12 +08:00
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
m_timer->stop();
|
2008-02-11 02:49:12 +08:00
|
|
|
}
|
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
// TipWindow
|
2008-03-01 03:29:49 +08:00
|
|
|
|
2010-01-26 08:38:05 +08:00
|
|
|
TipWindow::TipWindow(const char *text, bool close_on_buttonpressed)
|
2012-07-09 10:24:42 +08:00
|
|
|
: Window(false, text)
|
2008-02-11 02:49:12 +08:00
|
|
|
{
|
2010-01-26 08:38:05 +08:00
|
|
|
m_close_on_buttonpressed = close_on_buttonpressed;
|
|
|
|
m_filtering = false;
|
2011-02-15 20:02:51 +08:00
|
|
|
m_arrowAlign = 0;
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2013-01-11 23:43:25 +08:00
|
|
|
setSizeable(false);
|
|
|
|
setMoveable(false);
|
|
|
|
setWantFocus(false);
|
2010-01-26 08:38:05 +08:00
|
|
|
setAlign(JI_LEFT | JI_TOP);
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2012-07-18 08:42:02 +08:00
|
|
|
removeDecorativeWidgets();
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2011-02-15 20:00:29 +08:00
|
|
|
initTheme();
|
2008-02-11 02:49:12 +08:00
|
|
|
}
|
|
|
|
|
2010-03-28 05:53:47 +08:00
|
|
|
TipWindow::~TipWindow()
|
|
|
|
{
|
|
|
|
if (m_filtering) {
|
|
|
|
m_filtering = false;
|
2012-04-16 02:21:24 +08:00
|
|
|
getManager()->removeMessageFilter(JM_MOTION, this);
|
|
|
|
getManager()->removeMessageFilter(JM_BUTTONPRESSED, this);
|
|
|
|
getManager()->removeMessageFilter(JM_KEYPRESSED, this);
|
2010-03-28 05:53:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-14 09:39:44 +08:00
|
|
|
void TipWindow::setHotRegion(const Region& region)
|
2008-03-01 03:29:49 +08:00
|
|
|
{
|
2010-01-26 08:38:05 +08:00
|
|
|
if (!m_filtering) {
|
|
|
|
m_filtering = true;
|
2012-04-16 02:21:24 +08:00
|
|
|
getManager()->addMessageFilter(JM_MOTION, this);
|
|
|
|
getManager()->addMessageFilter(JM_BUTTONPRESSED, this);
|
|
|
|
getManager()->addMessageFilter(JM_KEYPRESSED, this);
|
2010-01-26 08:38:05 +08:00
|
|
|
}
|
2013-01-14 09:39:44 +08:00
|
|
|
|
|
|
|
m_hotRegion = region;
|
2008-03-01 03:29:49 +08:00
|
|
|
}
|
|
|
|
|
2011-02-15 20:02:51 +08:00
|
|
|
int TipWindow::getArrowAlign() const
|
|
|
|
{
|
|
|
|
return m_arrowAlign;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TipWindow::setArrowAlign(int arrowAlign)
|
|
|
|
{
|
|
|
|
m_arrowAlign = arrowAlign;
|
|
|
|
}
|
|
|
|
|
2011-04-03 00:14:07 +08:00
|
|
|
bool TipWindow::onProcessMessage(Message* msg)
|
2008-03-01 03:29:49 +08:00
|
|
|
{
|
2008-02-11 02:49:12 +08:00
|
|
|
switch (msg->type) {
|
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
case JM_CLOSE:
|
2010-01-26 08:38:05 +08:00
|
|
|
if (m_filtering) {
|
2012-01-06 06:45:03 +08:00
|
|
|
m_filtering = false;
|
2012-04-16 02:21:24 +08:00
|
|
|
getManager()->removeMessageFilter(JM_MOTION, this);
|
|
|
|
getManager()->removeMessageFilter(JM_BUTTONPRESSED, this);
|
|
|
|
getManager()->removeMessageFilter(JM_KEYPRESSED, this);
|
2008-03-01 03:29:49 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2008-02-11 02:49:12 +08:00
|
|
|
case JM_MOUSELEAVE:
|
2013-01-14 09:39:44 +08:00
|
|
|
if (m_hotRegion.isEmpty())
|
|
|
|
closeWindow(NULL);
|
2008-03-01 03:29:49 +08:00
|
|
|
break;
|
|
|
|
|
2008-03-23 02:43:56 +08:00
|
|
|
case JM_KEYPRESSED:
|
2010-01-26 08:38:05 +08:00
|
|
|
if (m_filtering && msg->key.scancode < KEY_MODIFIERS)
|
2012-01-06 06:45:03 +08:00
|
|
|
this->closeWindow(NULL);
|
2008-03-23 02:43:56 +08:00
|
|
|
break;
|
|
|
|
|
2008-02-11 02:49:12 +08:00
|
|
|
case JM_BUTTONPRESSED:
|
2008-03-23 02:43:56 +08:00
|
|
|
/* if the user click outside the window, we have to close the
|
2012-01-06 06:45:03 +08:00
|
|
|
tooltip window */
|
2010-01-26 08:38:05 +08:00
|
|
|
if (m_filtering) {
|
2012-01-06 06:45:03 +08:00
|
|
|
Widget* picked = this->pick(msg->mouse.x, msg->mouse.y);
|
|
|
|
if (!picked || picked->getRoot() != this) {
|
|
|
|
this->closeWindow(NULL);
|
|
|
|
}
|
2008-03-23 02:43:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* this is used when the user click inside a small text
|
2012-01-06 06:45:03 +08:00
|
|
|
tooltip */
|
2010-01-26 08:38:05 +08:00
|
|
|
if (m_close_on_buttonpressed)
|
2012-01-06 06:45:03 +08:00
|
|
|
this->closeWindow(NULL);
|
2008-03-01 03:29:49 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case JM_MOTION:
|
2013-01-14 09:39:44 +08:00
|
|
|
if (!m_hotRegion.isEmpty() &&
|
2012-04-16 02:21:24 +08:00
|
|
|
getManager()->getCapture() == NULL) {
|
2013-01-14 09:39:44 +08:00
|
|
|
// If the mouse is outside the hot-region we have to close the window
|
|
|
|
if (!m_hotRegion.contains(Point(msg->mouse.x, msg->mouse.y))) {
|
|
|
|
closeWindow(NULL);
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
2008-03-01 03:29:49 +08:00
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
2010-01-26 08:38:05 +08:00
|
|
|
|
2012-07-09 10:24:42 +08:00
|
|
|
return Window::onProcessMessage(msg);
|
2008-02-11 02:49:12 +08:00
|
|
|
}
|
2010-08-03 09:57:41 +08:00
|
|
|
|
|
|
|
void TipWindow::onPreferredSize(PreferredSizeEvent& ev)
|
|
|
|
{
|
2011-02-14 10:16:10 +08:00
|
|
|
ScreenGraphics g;
|
|
|
|
g.setFont(getFont());
|
|
|
|
Size resultSize = g.fitString(getText(),
|
2012-01-06 06:45:03 +08:00
|
|
|
(getClientBounds() - getBorder()).w,
|
|
|
|
getAlign());
|
2010-08-03 09:57:41 +08:00
|
|
|
|
2011-02-14 10:16:10 +08:00
|
|
|
resultSize.w += this->border_width.l + this->border_width.r;
|
|
|
|
resultSize.h += this->border_width.t + this->border_width.b;
|
2010-08-03 09:57:41 +08:00
|
|
|
|
2012-07-18 08:42:02 +08:00
|
|
|
if (!getChildren().empty()) {
|
2010-08-03 09:57:41 +08:00
|
|
|
Size maxSize(0, 0);
|
|
|
|
Size reqSize;
|
|
|
|
|
2012-07-18 08:42:02 +08:00
|
|
|
UI_FOREACH_WIDGET(getChildren(), it) {
|
|
|
|
Widget* child = *it;
|
2010-08-03 09:57:41 +08:00
|
|
|
|
|
|
|
reqSize = child->getPreferredSize();
|
|
|
|
|
|
|
|
maxSize.w = MAX(maxSize.w, reqSize.w);
|
|
|
|
maxSize.h = MAX(maxSize.h, reqSize.h);
|
|
|
|
}
|
|
|
|
|
2011-02-14 10:16:10 +08:00
|
|
|
resultSize.w = MAX(resultSize.w, border_width.l + maxSize.w + border_width.r);
|
2010-08-03 09:57:41 +08:00
|
|
|
resultSize.h += maxSize.h;
|
|
|
|
}
|
|
|
|
|
|
|
|
ev.setPreferredSize(resultSize);
|
|
|
|
}
|
2011-02-12 20:32:57 +08:00
|
|
|
|
2012-06-16 10:37:59 +08:00
|
|
|
void TipWindow::onInitTheme(InitThemeEvent& ev)
|
|
|
|
{
|
2012-07-09 10:24:42 +08:00
|
|
|
Window::onInitTheme(ev);
|
2012-06-16 10:37:59 +08:00
|
|
|
|
|
|
|
this->border_width.l = 6 * jguiscale();
|
|
|
|
this->border_width.t = 6 * jguiscale();
|
|
|
|
this->border_width.r = 6 * jguiscale();
|
|
|
|
this->border_width.b = 7 * jguiscale();
|
|
|
|
|
|
|
|
// Setup the background color.
|
2013-01-07 01:45:43 +08:00
|
|
|
setBgColor(ui::rgba(255, 255, 200));
|
2012-06-16 10:37:59 +08:00
|
|
|
}
|
|
|
|
|
2011-02-12 20:32:57 +08:00
|
|
|
void TipWindow::onPaint(PaintEvent& ev)
|
|
|
|
{
|
2011-02-15 09:50:39 +08:00
|
|
|
getTheme()->paintTooltip(ev);
|
2011-02-12 20:32:57 +08:00
|
|
|
}
|
2012-06-16 10:37:59 +08:00
|
|
|
|
2012-06-18 09:02:54 +08:00
|
|
|
} // namespace ui
|