mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-16 22:18:30 +00:00
522 lines
12 KiB
C
522 lines
12 KiB
C
/* jinete - a GUI library
|
|
* Copyright (C) 2003-2005, 2007 by David A. Capello
|
|
*
|
|
* Jinete is gift-ware.
|
|
*/
|
|
|
|
#include <allegro/gfx.h>
|
|
#include <allegro/keyboard.h>
|
|
#include <allegro/timer.h>
|
|
#include <string.h>
|
|
|
|
#include "jinete/button.h"
|
|
#include "jinete/list.h"
|
|
#include "jinete/manager.h"
|
|
#include "jinete/message.h"
|
|
#include "jinete/rect.h"
|
|
#include "jinete/theme.h"
|
|
#include "jinete/widget.h"
|
|
|
|
typedef void (*command_t)(JWidget widget);
|
|
typedef void (*command_data_t)(JWidget widget, void *data);
|
|
|
|
typedef struct ButtonCommand
|
|
{
|
|
bool use_data;
|
|
void *proc;
|
|
void *data;
|
|
} ButtonCommand;
|
|
|
|
typedef struct Button
|
|
{
|
|
/* generic */
|
|
BITMAP *icon;
|
|
int icon_align;
|
|
/* button */
|
|
JList commands;
|
|
int bevel[4];
|
|
/* check */
|
|
/* ...nothing... */
|
|
/* radio */
|
|
int group;
|
|
} Button;
|
|
|
|
static bool button_msg_proc(JWidget widget, JMessage msg);
|
|
static void button_request_size(JWidget widget, int *w, int *h);
|
|
static void button_selected_signal(JWidget widget);
|
|
static void button_deselect_group(JWidget widget, int radio_group);
|
|
|
|
JWidget ji_generic_button_new(const char *text,
|
|
int behavior_type,
|
|
int draw_type)
|
|
{
|
|
JWidget widget = jwidget_new(behavior_type);
|
|
Button *button = jnew(Button, 1);
|
|
|
|
widget->draw_type = draw_type;
|
|
|
|
button->icon = NULL;
|
|
button->icon_align = JI_LEFT | JI_MIDDLE;
|
|
button->commands = jlist_new();
|
|
button->bevel[0] = 2;
|
|
button->bevel[1] = 2;
|
|
button->bevel[2] = 2;
|
|
button->bevel[3] = 2;
|
|
button->group = 0;
|
|
|
|
jwidget_add_hook(widget, behavior_type, button_msg_proc, button);
|
|
jwidget_set_align(widget, JI_CENTER | JI_MIDDLE);
|
|
jwidget_set_text(widget, text);
|
|
jwidget_focusrest(widget, TRUE);
|
|
jwidget_init_theme(widget);
|
|
|
|
return widget;
|
|
}
|
|
|
|
void ji_generic_button_set_icon(JWidget widget, struct BITMAP *icon)
|
|
{
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
|
|
button->icon = icon;
|
|
|
|
jwidget_dirty(widget);
|
|
}
|
|
|
|
void ji_generic_button_set_icon_align(JWidget widget, int icon_align)
|
|
{
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
|
|
button->icon_align = icon_align;
|
|
|
|
jwidget_dirty(widget);
|
|
}
|
|
|
|
BITMAP *ji_generic_button_get_icon(JWidget widget)
|
|
{
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
|
|
return button->icon;
|
|
}
|
|
|
|
int ji_generic_button_get_icon_align(JWidget widget)
|
|
{
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
|
|
return button->icon_align;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* button */
|
|
|
|
JWidget jbutton_new(const char *text)
|
|
{
|
|
JWidget widget = ji_generic_button_new(text, JI_BUTTON, JI_BUTTON);
|
|
if (widget)
|
|
jwidget_set_align(widget, JI_CENTER | JI_MIDDLE);
|
|
return widget;
|
|
}
|
|
|
|
void jbutton_set_bevel(JWidget widget, int b0, int b1, int b2, int b3)
|
|
{
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
|
|
button->bevel[0] = b0;
|
|
button->bevel[1] = b1;
|
|
button->bevel[2] = b2;
|
|
button->bevel[3] = b3;
|
|
|
|
jwidget_dirty(widget);
|
|
}
|
|
|
|
void jbutton_get_bevel(JWidget widget, int *b4)
|
|
{
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
|
|
b4[0] = button->bevel[0];
|
|
b4[1] = button->bevel[1];
|
|
b4[2] = button->bevel[2];
|
|
b4[3] = button->bevel[3];
|
|
}
|
|
|
|
void jbutton_add_command(JWidget widget,
|
|
void (*command_proc)(JWidget widget))
|
|
{
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
ButtonCommand *command = jnew(ButtonCommand, 1);
|
|
|
|
command->use_data = FALSE;
|
|
command->proc = (void *)command_proc;
|
|
command->data = NULL;
|
|
|
|
jlist_prepend(button->commands, command);
|
|
}
|
|
|
|
void jbutton_add_command_data(JWidget widget,
|
|
void (*command_proc)(JWidget widget,
|
|
void *data),
|
|
void *data)
|
|
{
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
ButtonCommand *command = jnew(ButtonCommand, 1);
|
|
|
|
command->use_data = TRUE;
|
|
command->proc = (void *)command_proc;
|
|
command->data = data;
|
|
|
|
jlist_prepend(button->commands, command);
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* check */
|
|
|
|
JWidget jcheck_new(const char *text)
|
|
{
|
|
JWidget widget = ji_generic_button_new(text, JI_CHECK, JI_CHECK);
|
|
if (widget) {
|
|
jwidget_set_align(widget, JI_LEFT | JI_MIDDLE);
|
|
}
|
|
return widget;
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* radio */
|
|
|
|
JWidget jradio_new(const char *text, int radio_group)
|
|
{
|
|
JWidget widget = ji_generic_button_new(text, JI_RADIO, JI_RADIO);
|
|
if (widget) {
|
|
jwidget_set_align(widget, JI_LEFT | JI_MIDDLE);
|
|
jradio_set_group(widget, radio_group);
|
|
}
|
|
return widget;
|
|
}
|
|
|
|
void jradio_set_group(JWidget widget, int radio_group)
|
|
{
|
|
Button *radio = jwidget_get_data(widget, widget->type);
|
|
|
|
radio->group = radio_group;
|
|
|
|
/* XXX: update old and new groups */
|
|
}
|
|
|
|
int jradio_get_group(JWidget widget)
|
|
{
|
|
Button *radio = jwidget_get_data(widget, widget->type);
|
|
|
|
return radio->group;
|
|
}
|
|
|
|
void jradio_deselect_group(JWidget widget)
|
|
{
|
|
JWidget window = jwidget_get_window(widget);
|
|
if (window)
|
|
button_deselect_group(window, jradio_get_group(widget));
|
|
}
|
|
|
|
/**********************************************************************/
|
|
/* procedures */
|
|
|
|
static bool button_msg_proc(JWidget widget, JMessage msg)
|
|
{
|
|
switch (msg->type) {
|
|
|
|
case JM_DESTROY: {
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
JLink link;
|
|
|
|
JI_LIST_FOR_EACH(button->commands, link)
|
|
jfree(link->data);
|
|
|
|
jlist_free(button->commands);
|
|
jfree(button);
|
|
break;
|
|
}
|
|
|
|
case JM_REQSIZE:
|
|
button_request_size(widget, &msg->reqsize.w, &msg->reqsize.h);
|
|
return TRUE;
|
|
|
|
case JM_SIGNAL:
|
|
if (widget->type == JI_RADIO) {
|
|
if (msg->signal.num == JI_SIGNAL_SELECT) {
|
|
jradio_deselect_group(widget);
|
|
|
|
jwidget_signal_off(widget);
|
|
jwidget_select(widget);
|
|
jwidget_signal_on(widget);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JM_FOCUSENTER:
|
|
case JM_FOCUSLEAVE:
|
|
if (jwidget_is_enabled(widget)) {
|
|
if (widget->type == JI_BUTTON) {
|
|
/* deselect the widget (maybe the user press the key, but
|
|
before release it, changes the focus) */
|
|
if (jwidget_is_selected(widget))
|
|
jwidget_deselect(widget);
|
|
}
|
|
|
|
/* XXX theme specific stuff */
|
|
jwidget_dirty(widget);
|
|
}
|
|
break;
|
|
|
|
case JM_CHAR:
|
|
if (widget->type != JI_BUTTON) {
|
|
if (jwidget_is_enabled (widget)) {
|
|
/* if the widget has the focus and the user press space or
|
|
if the user press Alt+the underscored letter of the button */
|
|
if ((jwidget_has_focus (widget) &&
|
|
(msg->key.scancode == KEY_SPACE)) ||
|
|
((msg->any.shifts & KB_ALT_FLAG) &&
|
|
(jwidget_check_underscored(widget, msg->key.scancode)))) {
|
|
if (widget->type == JI_CHECK) {
|
|
/* swap the select status */
|
|
if (jwidget_is_selected(widget))
|
|
jwidget_deselect(widget);
|
|
else
|
|
jwidget_select(widget);
|
|
|
|
/* signal */
|
|
jwidget_emit_signal(widget, JI_SIGNAL_CHECK_CHANGE);
|
|
jwidget_dirty(widget);
|
|
}
|
|
else if (widget->type == JI_RADIO) {
|
|
if (jwidget_is_deselected(widget)) {
|
|
jwidget_select(widget);
|
|
jwidget_emit_signal(widget, JI_SIGNAL_RADIO_CHANGE);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JM_KEYPRESSED:
|
|
if (widget->type == JI_BUTTON) {
|
|
/* if the button is enabled */
|
|
if (jwidget_is_enabled (widget)) {
|
|
/* has focus and press enter/space */
|
|
if (jwidget_has_focus (widget)) {
|
|
if ((msg->key.scancode == KEY_ENTER) ||
|
|
(msg->key.scancode == KEY_ENTER_PAD) ||
|
|
(msg->key.scancode == KEY_SPACE)) {
|
|
jwidget_select (widget);
|
|
return TRUE;
|
|
}
|
|
}
|
|
/* else { */
|
|
/* the underscored letter with Alt */
|
|
if ((msg->any.shifts & KB_ALT_FLAG) &&
|
|
(jwidget_check_underscored(widget, msg->key.scancode))) {
|
|
jwidget_select(widget);
|
|
return TRUE;
|
|
}
|
|
/* magnetic */
|
|
else if (jwidget_is_magnetic(widget) &&
|
|
((msg->key.scancode == KEY_ENTER) ||
|
|
(msg->key.scancode == KEY_ENTER_PAD))) {
|
|
jmanager_set_focus(widget);
|
|
|
|
/* dispatch focus movement messages (because the buttons
|
|
process them) */
|
|
jmanager_dispatch_messages();
|
|
|
|
jwidget_select(widget);
|
|
return TRUE;
|
|
}
|
|
/* } */
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JM_KEYRELEASED:
|
|
if (widget->type == JI_BUTTON) {
|
|
/* if the button is enabled */
|
|
if (jwidget_is_enabled(widget)) {
|
|
/* has focus and press enter/space, or if the user just
|
|
pressed the underscored letter */
|
|
if ((jwidget_has_focus(widget) &&
|
|
((msg->key.scancode == KEY_ENTER) ||
|
|
(msg->key.scancode == KEY_ENTER_PAD) ||
|
|
(msg->key.scancode == KEY_SPACE))) ||
|
|
(jwidget_check_underscored(widget, msg->key.scancode))) {
|
|
/* if it's selected we must emit the signal */
|
|
if (jwidget_is_selected(widget)) {
|
|
button_selected_signal(widget);
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JM_BUTTONPRESSED:
|
|
switch (widget->type) {
|
|
|
|
case JI_BUTTON:
|
|
if (jwidget_is_enabled(widget)) {
|
|
jwidget_select(widget);
|
|
jwidget_capture_mouse(widget);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case JI_CHECK:
|
|
if (jwidget_is_selected(widget))
|
|
jwidget_deselect(widget);
|
|
else
|
|
jwidget_select(widget);
|
|
|
|
jwidget_capture_mouse(widget);
|
|
return TRUE;
|
|
break;
|
|
|
|
case JI_RADIO:
|
|
if (jwidget_is_deselected(widget)) {
|
|
jwidget_signal_off(widget);
|
|
jwidget_select(widget);
|
|
jwidget_signal_on(widget);
|
|
|
|
jwidget_capture_mouse(widget);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case JM_BUTTONRELEASED:
|
|
if (jwidget_has_capture(widget)) {
|
|
if (jwidget_has_mouse(widget)) {
|
|
switch (widget->type) {
|
|
|
|
case JI_BUTTON:
|
|
button_selected_signal(widget);
|
|
break;
|
|
|
|
case JI_CHECK:
|
|
jwidget_emit_signal(widget, JI_SIGNAL_CHECK_CHANGE);
|
|
jwidget_dirty(widget);
|
|
break;
|
|
|
|
case JI_RADIO:
|
|
jwidget_deselect(widget);
|
|
jwidget_select(widget);
|
|
jwidget_emit_signal(widget, JI_SIGNAL_RADIO_CHANGE);
|
|
break;
|
|
}
|
|
}
|
|
jwidget_release_mouse(widget);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case JM_MOUSEENTER:
|
|
case JM_MOUSELEAVE:
|
|
if (jwidget_is_enabled(widget) && jwidget_has_capture(widget)) {
|
|
jwidget_signal_off(widget);
|
|
|
|
if (jwidget_is_selected(widget))
|
|
jwidget_deselect(widget);
|
|
else
|
|
jwidget_select(widget);
|
|
|
|
jwidget_signal_on(widget);
|
|
}
|
|
|
|
/* XXX theme stuff */
|
|
if (jwidget_is_enabled(widget))
|
|
jwidget_dirty(widget);
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void button_request_size(JWidget widget, int *w, int *h)
|
|
{
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
struct jrect box, text, icon;
|
|
int icon_w = 0;
|
|
int icon_h = 0;
|
|
|
|
switch (widget->draw_type) {
|
|
|
|
case JI_BUTTON:
|
|
if (button->icon) {
|
|
icon_w = button->icon->w;
|
|
icon_h = button->icon->h;
|
|
}
|
|
break;
|
|
|
|
case JI_CHECK:
|
|
icon_w = widget->theme->check_icon_size;
|
|
icon_h = widget->theme->check_icon_size;
|
|
break;
|
|
|
|
case JI_RADIO:
|
|
icon_w = widget->theme->radio_icon_size;
|
|
icon_h = widget->theme->radio_icon_size;
|
|
break;
|
|
}
|
|
|
|
jwidget_get_texticon_info(widget, &box, &text, &icon,
|
|
button->icon_align, icon_w, icon_h);
|
|
|
|
*w = widget->border_width.l + jrect_w(&box) + widget->border_width.r;
|
|
*h = widget->border_width.t + jrect_h(&box) + widget->border_width.b;
|
|
}
|
|
|
|
static void button_selected_signal(JWidget widget)
|
|
{
|
|
bool used;
|
|
|
|
/* deselect */
|
|
jwidget_deselect(widget);
|
|
|
|
/* emit the signal */
|
|
used = jwidget_emit_signal(widget, JI_SIGNAL_BUTTON_SELECT);
|
|
|
|
/* not used? */
|
|
if (!used) {
|
|
Button *button = jwidget_get_data(widget, widget->type);
|
|
|
|
/* call commands */
|
|
if (!jlist_empty(button->commands)) {
|
|
ButtonCommand *command;
|
|
JLink link;
|
|
|
|
JI_LIST_FOR_EACH(button->commands, link) {
|
|
command = link->data;
|
|
|
|
if (command->proc) {
|
|
if (command->use_data)
|
|
(*(command_data_t)command->proc)(widget, command->data);
|
|
else
|
|
(*(command_t)command->proc)(widget);
|
|
}
|
|
}
|
|
}
|
|
/* default action: close the window */
|
|
else
|
|
jwidget_close_window(widget);
|
|
}
|
|
}
|
|
|
|
static void button_deselect_group(JWidget widget, int radio_group)
|
|
{
|
|
JLink link;
|
|
|
|
JI_LIST_FOR_EACH(widget->children, link)
|
|
button_deselect_group(link->data, radio_group);
|
|
|
|
if (widget->type == JI_RADIO) {
|
|
if (jradio_get_group(widget) == radio_group)
|
|
jwidget_deselect(widget);
|
|
}
|
|
}
|