2008-02-11 02:49:12 +08:00
|
|
|
/* ASE - Allegro Sprite Editor
|
2009-01-24 08:41:01 +08:00
|
|
|
* Copyright (C) 2008-2009 David Capello
|
2008-02-11 02:49:12 +08:00
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
*/
|
|
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
#include <assert.h>
|
2008-02-11 02:49:12 +08:00
|
|
|
#include <allegro.h>
|
|
|
|
|
|
|
|
|
|
#include "jinete/jinete.h"
|
2008-10-11 23:52:47 +08:00
|
|
|
#include "jinete/jintern.h"
|
2008-02-11 02:49:12 +08:00
|
|
|
|
|
|
|
|
typedef struct TipData
|
|
|
|
|
{
|
|
|
|
|
JWidget widget; /* widget that shows the tooltip */
|
|
|
|
|
JWidget window; /* window where is the tooltip */
|
|
|
|
|
char *text;
|
|
|
|
|
int timer_id;
|
|
|
|
|
} TipData;
|
|
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
typedef struct TipWindow
|
|
|
|
|
{
|
|
|
|
|
bool close_on_buttonpressed;
|
|
|
|
|
JRegion hot_region;
|
|
|
|
|
bool filtering;
|
|
|
|
|
} TipWindow;
|
|
|
|
|
|
2008-10-01 09:27:51 +08:00
|
|
|
static int tip_type();
|
2008-02-11 02:49:12 +08:00
|
|
|
static bool tip_hook(JWidget widget, JMessage msg);
|
|
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
static JWidget tipwindow_new(const char *text, bool close_on_buttonpressed);
|
2008-10-01 09:27:51 +08:00
|
|
|
static int tipwindow_type();
|
2008-03-01 03:29:49 +08:00
|
|
|
static TipWindow *tipwindow_data(JWidget widget);
|
|
|
|
|
static bool tipwindow_msg_proc(JWidget widget, JMessage msg);
|
2008-02-11 02:49:12 +08:00
|
|
|
|
|
|
|
|
void jwidget_add_tooltip_text(JWidget widget, const char *text)
|
|
|
|
|
{
|
2008-10-01 05:01:54 +08:00
|
|
|
TipData* tip = reinterpret_cast<TipData*>(jwidget_get_data(widget, tip_type()));
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2008-03-15 09:54:45 +08:00
|
|
|
assert(text != NULL);
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2008-03-15 09:54:45 +08:00
|
|
|
if (tip == NULL) {
|
|
|
|
|
tip = jnew(TipData, 1);
|
|
|
|
|
|
|
|
|
|
tip->widget = widget;
|
|
|
|
|
tip->window = NULL;
|
|
|
|
|
tip->text = jstrdup(text);
|
|
|
|
|
tip->timer_id = -1;
|
|
|
|
|
|
|
|
|
|
jwidget_add_hook(widget, tip_type(), tip_hook, tip);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (tip->text != NULL)
|
|
|
|
|
jfree(tip->text);
|
|
|
|
|
|
|
|
|
|
tip->text = jstrdup(text);
|
|
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
}
|
|
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
/**
|
|
|
|
|
* Creates a window to show a tool-tip.
|
|
|
|
|
*/
|
|
|
|
|
JWidget jtooltip_window_new(const char *text)
|
|
|
|
|
{
|
|
|
|
|
JWidget window = tipwindow_new(text, FALSE);
|
|
|
|
|
|
|
|
|
|
return window;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-23 02:43:56 +08:00
|
|
|
/**
|
|
|
|
|
* @param widget The tooltip window.
|
|
|
|
|
* @param region The new hot-region. This pointer is holded by the @a widget.
|
|
|
|
|
* So you can't destroy it after calling this routine.
|
|
|
|
|
*/
|
2008-03-01 03:29:49 +08:00
|
|
|
void jtooltip_window_set_hotregion(JWidget widget, JRegion region)
|
|
|
|
|
{
|
|
|
|
|
TipWindow *tipwindow = tipwindow_data(widget);
|
|
|
|
|
|
|
|
|
|
assert(region != NULL);
|
|
|
|
|
|
|
|
|
|
if (tipwindow->hot_region != NULL)
|
2008-03-23 02:43:56 +08:00
|
|
|
jregion_free(tipwindow->hot_region);
|
2008-03-01 03:29:49 +08:00
|
|
|
|
|
|
|
|
if (!tipwindow->filtering) {
|
|
|
|
|
tipwindow->filtering = TRUE;
|
|
|
|
|
jmanager_add_msg_filter(JM_MOTION, widget);
|
2008-03-23 02:43:56 +08:00
|
|
|
jmanager_add_msg_filter(JM_BUTTONPRESSED, widget);
|
|
|
|
|
jmanager_add_msg_filter(JM_KEYPRESSED, widget);
|
2008-03-01 03:29:49 +08:00
|
|
|
}
|
|
|
|
|
tipwindow->hot_region = region;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/********************************************************************/
|
|
|
|
|
/* hook for widgets that want a tool-tip */
|
|
|
|
|
|
2008-10-01 09:27:51 +08:00
|
|
|
static int tip_type()
|
2008-02-11 02:49:12 +08:00
|
|
|
{
|
|
|
|
|
static int type = 0;
|
|
|
|
|
if (!type)
|
|
|
|
|
type = ji_register_widget_type();
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-19 07:33:48 +08:00
|
|
|
/* hook for the widget in which we added a tooltip */
|
2008-02-11 02:49:12 +08:00
|
|
|
static bool tip_hook(JWidget widget, JMessage msg)
|
|
|
|
|
{
|
2008-10-01 05:01:54 +08:00
|
|
|
TipData* tip = reinterpret_cast<TipData*>(jwidget_get_data(widget, tip_type()));
|
2008-02-11 02:49:12 +08:00
|
|
|
|
|
|
|
|
switch (msg->type) {
|
|
|
|
|
|
|
|
|
|
case JM_DESTROY:
|
|
|
|
|
if (tip->timer_id >= 0)
|
|
|
|
|
jmanager_remove_timer(tip->timer_id);
|
|
|
|
|
|
|
|
|
|
jfree(tip->text);
|
|
|
|
|
jfree(tip);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case JM_MOUSEENTER:
|
|
|
|
|
if (tip->timer_id < 0)
|
|
|
|
|
tip->timer_id = jmanager_add_timer(widget, 300);
|
|
|
|
|
|
|
|
|
|
jmanager_start_timer(tip->timer_id);
|
|
|
|
|
break;
|
|
|
|
|
|
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:
|
2008-02-19 07:33:48 +08:00
|
|
|
if (tip->window) {
|
2008-02-11 02:49:12 +08:00
|
|
|
jwindow_close(tip->window, NULL);
|
2008-02-19 07:33:48 +08:00
|
|
|
jwidget_free(tip->window);
|
|
|
|
|
tip->window = NULL;
|
|
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2008-02-19 07:33:48 +08:00
|
|
|
if (tip->timer_id >= 0)
|
|
|
|
|
jmanager_stop_timer(tip->timer_id);
|
2008-02-11 02:49:12 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case JM_TIMER:
|
|
|
|
|
if (msg->timer.timer_id == tip->timer_id) {
|
2008-02-19 07:33:48 +08:00
|
|
|
if (!tip->window) {
|
2008-03-01 03:29:49 +08:00
|
|
|
JWidget window = tipwindow_new(tip->text, TRUE);
|
2008-03-27 22:29:33 +08:00
|
|
|
/* int x = tip->widget->rc->x1; */
|
|
|
|
|
/* int y = tip->widget->rc->y2; */
|
|
|
|
|
int x = jmouse_x(0)+12;
|
|
|
|
|
int y = jmouse_y(0)+12;
|
|
|
|
|
int w, h;
|
2008-02-19 07:33:48 +08:00
|
|
|
|
|
|
|
|
tip->window = window;
|
|
|
|
|
|
|
|
|
|
jwindow_remap(window);
|
2008-03-27 22:29:33 +08:00
|
|
|
|
|
|
|
|
w = jrect_w(window->rc);
|
|
|
|
|
h = jrect_h(window->rc);
|
|
|
|
|
|
|
|
|
|
if (x+w > JI_SCREEN_W) {
|
|
|
|
|
x = jmouse_x(0) - w - 4;
|
|
|
|
|
y = jmouse_y(0);
|
|
|
|
|
}
|
|
|
|
|
|
2008-02-19 07:33:48 +08:00
|
|
|
jwindow_position(window,
|
|
|
|
|
MID(0, x, JI_SCREEN_W-w),
|
|
|
|
|
MID(0, y, JI_SCREEN_H-h));
|
|
|
|
|
jwindow_open(window);
|
|
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
jmanager_stop_timer(tip->timer_id);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
/********************************************************************/
|
|
|
|
|
/* TipWindow */
|
|
|
|
|
|
|
|
|
|
static JWidget tipwindow_new(const char *text, bool close_on_buttonpressed)
|
2008-02-11 02:49:12 +08:00
|
|
|
{
|
|
|
|
|
JWidget window = jwindow_new(text);
|
|
|
|
|
JLink link, next;
|
2008-03-01 03:29:49 +08:00
|
|
|
TipWindow *tipwindow = jnew(TipWindow, 1);
|
|
|
|
|
|
|
|
|
|
tipwindow->close_on_buttonpressed = close_on_buttonpressed;
|
|
|
|
|
tipwindow->hot_region = NULL;
|
|
|
|
|
tipwindow->filtering = FALSE;
|
2008-02-11 02:49:12 +08:00
|
|
|
|
|
|
|
|
jwindow_sizeable(window, FALSE);
|
|
|
|
|
jwindow_moveable(window, FALSE);
|
|
|
|
|
jwindow_wantfocus(window, FALSE);
|
|
|
|
|
|
|
|
|
|
jwidget_set_align(window, JI_LEFT | JI_TOP);
|
|
|
|
|
|
|
|
|
|
/* remove decorative widgets */
|
2008-03-01 03:29:49 +08:00
|
|
|
JI_LIST_FOR_EACH_SAFE(window->children, link, next)
|
2008-10-01 05:01:54 +08:00
|
|
|
jwidget_free(reinterpret_cast<JWidget>(link->data));
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
jwidget_add_hook(window, tipwindow_type(),
|
|
|
|
|
tipwindow_msg_proc, tipwindow);
|
2008-02-11 02:49:12 +08:00
|
|
|
jwidget_init_theme(window);
|
|
|
|
|
|
|
|
|
|
return window;
|
|
|
|
|
}
|
|
|
|
|
|
2008-10-01 09:27:51 +08:00
|
|
|
static int tipwindow_type()
|
2008-03-01 03:29:49 +08:00
|
|
|
{
|
|
|
|
|
static int type = 0;
|
|
|
|
|
if (!type)
|
|
|
|
|
type = ji_register_widget_type();
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static TipWindow *tipwindow_data(JWidget widget)
|
2008-02-11 02:49:12 +08:00
|
|
|
{
|
2008-03-01 03:29:49 +08:00
|
|
|
return (TipWindow *)jwidget_get_data(widget,
|
|
|
|
|
tipwindow_type());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool tipwindow_msg_proc(JWidget widget, JMessage msg)
|
|
|
|
|
{
|
|
|
|
|
TipWindow *tipwindow = tipwindow_data(widget);
|
|
|
|
|
|
2008-02-11 02:49:12 +08:00
|
|
|
switch (msg->type) {
|
|
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
case JM_CLOSE:
|
|
|
|
|
if (tipwindow->filtering) {
|
|
|
|
|
tipwindow->filtering = FALSE;
|
|
|
|
|
jmanager_remove_msg_filter(JM_MOTION, widget);
|
2008-03-23 02:43:56 +08:00
|
|
|
jmanager_remove_msg_filter(JM_BUTTONPRESSED, widget);
|
|
|
|
|
jmanager_remove_msg_filter(JM_KEYPRESSED, widget);
|
2008-03-01 03:29:49 +08:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case JM_DESTROY:
|
2008-03-23 02:43:56 +08:00
|
|
|
if (tipwindow->filtering) {
|
|
|
|
|
tipwindow->filtering = FALSE;
|
|
|
|
|
jmanager_remove_msg_filter(JM_MOTION, widget);
|
|
|
|
|
jmanager_remove_msg_filter(JM_BUTTONPRESSED, widget);
|
|
|
|
|
jmanager_remove_msg_filter(JM_KEYPRESSED, widget);
|
|
|
|
|
}
|
2008-03-01 03:29:49 +08:00
|
|
|
if (tipwindow->hot_region != NULL) {
|
|
|
|
|
jregion_free(tipwindow->hot_region);
|
|
|
|
|
}
|
|
|
|
|
jfree(tipwindow);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case JM_REQSIZE: {
|
|
|
|
|
int w = 0, h = 0;
|
|
|
|
|
|
|
|
|
|
_ji_theme_textbox_draw(NULL, widget, &w, &h, 0, 0);
|
|
|
|
|
|
|
|
|
|
msg->reqsize.w = w;
|
|
|
|
|
msg->reqsize.h = widget->border_width.t + widget->border_width.b;
|
|
|
|
|
|
|
|
|
|
if (!jlist_empty(widget->children)) {
|
|
|
|
|
int max_w, max_h;
|
|
|
|
|
int req_w, req_h;
|
|
|
|
|
JWidget child;
|
|
|
|
|
JLink link;
|
|
|
|
|
|
|
|
|
|
max_w = max_h = 0;
|
|
|
|
|
JI_LIST_FOR_EACH(widget->children, link) {
|
|
|
|
|
child = (JWidget)link->data;
|
|
|
|
|
|
|
|
|
|
jwidget_request_size(child, &req_w, &req_h);
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
max_w = MAX(max_w, req_w);
|
|
|
|
|
max_h = MAX(max_h, req_h);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
msg->reqsize.w = MAX(msg->reqsize.w,
|
|
|
|
|
widget->border_width.l + max_w + widget->border_width.r);
|
|
|
|
|
msg->reqsize.h += max_h;
|
|
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
return TRUE;
|
2008-03-01 03:29:49 +08:00
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
|
|
|
|
|
case JM_SIGNAL:
|
|
|
|
|
if (msg->signal.num == JI_SIGNAL_INIT_THEME) {
|
2008-03-01 03:29:49 +08:00
|
|
|
int w = 0, h = 0;
|
|
|
|
|
|
2008-02-11 02:49:12 +08:00
|
|
|
widget->border_width.l = 3;
|
|
|
|
|
widget->border_width.t = 3;
|
|
|
|
|
widget->border_width.r = 3;
|
|
|
|
|
widget->border_width.b = 3;
|
2008-03-01 03:29:49 +08:00
|
|
|
|
|
|
|
|
_ji_theme_textbox_draw(NULL, widget, &w, &h, 0, 0);
|
|
|
|
|
|
|
|
|
|
widget->border_width.t = h-3;
|
2008-03-23 02:43:56 +08:00
|
|
|
|
|
|
|
|
/* setup the background color */
|
|
|
|
|
jwidget_set_bg_color(widget, makecol(255, 255, 200));
|
2008-02-11 02:49:12 +08:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case JM_MOUSELEAVE:
|
2008-03-01 03:29:49 +08:00
|
|
|
if (tipwindow->hot_region == NULL)
|
|
|
|
|
jwindow_close(widget, NULL);
|
|
|
|
|
break;
|
|
|
|
|
|
2008-03-23 02:43:56 +08:00
|
|
|
case JM_KEYPRESSED:
|
|
|
|
|
if (tipwindow->filtering && msg->key.scancode < KEY_MODIFIERS)
|
|
|
|
|
jwindow_close(widget, NULL);
|
|
|
|
|
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
|
|
|
|
|
tooltip window */
|
|
|
|
|
if (tipwindow->filtering) {
|
|
|
|
|
JWidget picked = jwidget_pick(widget, msg->mouse.x, msg->mouse.y);
|
|
|
|
|
if (!picked || jwidget_get_window(picked) != widget) {
|
|
|
|
|
jwindow_close(widget, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* this is used when the user click inside a small text
|
|
|
|
|
tooltip */
|
2008-03-01 03:29:49 +08:00
|
|
|
if (tipwindow->close_on_buttonpressed)
|
|
|
|
|
jwindow_close(widget, NULL);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case JM_MOTION:
|
|
|
|
|
if (tipwindow->hot_region != NULL &&
|
|
|
|
|
jmanager_get_capture() == NULL) {
|
|
|
|
|
struct jrect box;
|
|
|
|
|
|
|
|
|
|
/* if the mouse is outside the hot-region we have to close the window */
|
|
|
|
|
if (!jregion_point_in(tipwindow->hot_region,
|
|
|
|
|
msg->mouse.x, msg->mouse.y, &box)) {
|
|
|
|
|
jwindow_close(widget, NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-02-11 02:49:12 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case JM_DRAW: {
|
|
|
|
|
JRect pos = jwidget_get_rect(widget);
|
2008-03-01 03:29:49 +08:00
|
|
|
int oldt;
|
2008-02-11 02:49:12 +08:00
|
|
|
|
|
|
|
|
jdraw_rect(pos, makecol(0, 0, 0));
|
|
|
|
|
|
|
|
|
|
jrect_shrink(pos, 1);
|
2008-03-01 03:29:49 +08:00
|
|
|
jdraw_rectfill(pos, widget->bg_color);
|
2008-02-11 02:49:12 +08:00
|
|
|
|
2008-03-01 03:29:49 +08:00
|
|
|
oldt = widget->border_width.t;
|
|
|
|
|
widget->border_width.t = 3;
|
2008-02-11 02:49:12 +08:00
|
|
|
_ji_theme_textbox_draw(ji_screen, widget, NULL, NULL,
|
2008-03-01 03:29:49 +08:00
|
|
|
widget->bg_color,
|
|
|
|
|
ji_color_foreground());
|
|
|
|
|
widget->border_width.t = oldt;
|
2008-03-23 02:43:56 +08:00
|
|
|
|
|
|
|
|
jrect_free(pos);
|
2008-02-11 02:49:12 +08:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|