aseprite/src/modules/skinneable_theme.cpp
2010-03-07 14:21:24 -02:00

1699 lines
46 KiB
C++

/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2010 David Capello
*
* 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
*/
#include "config.h"
#include <allegro.h>
#include <allegro/internal/aintern.h>
#include "jinete/jinete.h"
#include "jinete/jintern.h"
#include "core/dirs.h"
#include "loadpng.h"
#include "ase_exception.h"
#include "modules/skinneable_theme.h"
#include "modules/gui.h"
#define CHARACTER_LENGTH(f, c) ((f)->vtable->char_length((f), (c)))
#define BGCOLOR (get_bg_color(widget))
#define COLOR_FOREGROUND makecol(0, 0, 0)
#define COLOR_DISABLED makecol(150, 130, 117)
#define COLOR_FACE makecol(211, 203, 190)
#define COLOR_HOTFACE makecol(250, 240, 230)
#define COLOR_SELECTED makecol(44, 76, 145)
#define COLOR_BACKGROUND makecol(255, 255, 255)
static struct
{
int x, y, w, h;
} sheet_info[PARTS] = {
{ 80, 0, 16, 16 }, // PART_CURSOR_NORMAL,
{ 80, 16, 16, 16 }, // PART_CURSOR_NORMAL_ADD,
{ 80, 32, 16, 16 }, // PART_CURSOR_FORBIDDEN,
{ 80, 48, 16, 16 }, // PART_CURSOR_HAND,
{ 80, 64, 16, 16 }, // PART_CURSOR_SCROLL,
{ 80, 80, 16, 16 }, // PART_CURSOR_MOVE,
{ 80, 96, 16, 16 }, // PART_CURSOR_SIZE_TL,
{ 80,112, 16, 16 }, // PART_CURSOR_SIZE_T,
{ 80,128, 16, 16 }, // PART_CURSOR_SIZE_TR,
{ 80,144, 16, 16 }, // PART_CURSOR_SIZE_L,
{ 80,160, 16, 16 }, // PART_CURSOR_SIZE_R,
{ 80,176, 16, 16 }, // PART_CURSOR_SIZE_BL,
{ 80,192, 16, 16 }, // PART_CURSOR_SIZE_B,
{ 80,208, 16, 16 }, // PART_CURSOR_SIZE_BR,
{ 80,224, 16, 16 }, // PART_CURSOR_EYEDROPPER,
{ 32, 32, 8, 8 }, // PART_RADIO_NORMAL
{ 32, 48, 8, 8 }, // PART_RADIO_SELECTED
{ 32, 32, 8, 8 }, // PART_RADIO_DISABLED
{ 48, 32, 8, 8 }, // PART_CHECK_NORMAL
{ 48, 48, 8, 8 }, // PART_CHECK_SELECTED
{ 48, 32, 8, 8 }, // PART_CHECK_DISABLED
{ 32, 64, 2, 2 }, // PART_CHECK_FOCUS_NW
{ 34, 64, 6, 2 }, // PART_CHECK_FOCUS_N
{ 40, 64, 2, 2 }, // PART_CHECK_FOCUS_NE
{ 40, 66, 2, 6 }, // PART_CHECK_FOCUS_E
{ 40, 72, 2, 2 }, // PART_CHECK_FOCUS_SE
{ 34, 72, 6, 2 }, // PART_CHECK_FOCUS_S
{ 32, 72, 2, 2 }, // PART_CHECK_FOCUS_SW
{ 32, 66, 2, 6 }, // PART_CHECK_FOCUS_W
{ 32, 64, 2, 2 }, // PART_RADIO_FOCUS_NW
{ 34, 64, 6, 2 }, // PART_RADIO_FOCUS_N
{ 40, 64, 2, 2 }, // PART_RADIO_FOCUS_NE
{ 40, 66, 2, 6 }, // PART_RADIO_FOCUS_E
{ 40, 72, 2, 2 }, // PART_RADIO_FOCUS_SE
{ 34, 72, 6, 2 }, // PART_RADIO_FOCUS_S
{ 32, 72, 2, 2 }, // PART_RADIO_FOCUS_SW
{ 32, 66, 2, 6 }, // PART_RADIO_FOCUS_W
{ 48, 0, 4, 4 }, // PART_BUTTON_NORMAL_NW
{ 52, 0, 6, 4 }, // PART_BUTTON_NORMAL_N
{ 58, 0, 4, 4 }, // PART_BUTTON_NORMAL_NE
{ 58, 4, 4, 6 }, // PART_BUTTON_NORMAL_E
{ 58, 10, 4, 6 }, // PART_BUTTON_NORMAL_SE
{ 52, 10, 6, 6 }, // PART_BUTTON_NORMAL_S
{ 48, 10, 4, 6 }, // PART_BUTTON_NORMAL_SW
{ 48, 4, 4, 6 }, // PART_BUTTON_NORMAL_W
{ 64, 0, 4, 4 }, // PART_BUTTON_HOT_NW
{ 68, 0, 6, 4 }, // PART_BUTTON_HOT_N
{ 74, 0, 4, 4 }, // PART_BUTTON_HOT_NE
{ 74, 4, 4, 6 }, // PART_BUTTON_HOT_E
{ 74, 10, 4, 6 }, // PART_BUTTON_HOT_SE
{ 68, 10, 6, 6 }, // PART_BUTTON_HOT_S
{ 64, 10, 4, 6 }, // PART_BUTTON_HOT_SW
{ 64, 4, 4, 6 }, // PART_BUTTON_HOT_W
{ 48, 16, 4, 4 }, // PART_BUTTON_FOCUSED_NW
{ 52, 16, 6, 4 }, // PART_BUTTON_FOCUSED_N
{ 58, 16, 4, 4 }, // PART_BUTTON_FOCUSED_NE
{ 58, 20, 4, 6 }, // PART_BUTTON_FOCUSED_E
{ 58, 26, 4, 6 }, // PART_BUTTON_FOCUSED_SE
{ 52, 26, 6, 6 }, // PART_BUTTON_FOCUSED_S
{ 48, 26, 4, 6 }, // PART_BUTTON_FOCUSED_SW
{ 48, 20, 4, 6 }, // PART_BUTTON_FOCUSED_W
{ 64, 16, 4, 4 }, // PART_BUTTON_SELECTED_NW
{ 68, 16, 6, 4 }, // PART_BUTTON_SELECTED_N
{ 74, 16, 4, 4 }, // PART_BUTTON_SELECTED_NE
{ 74, 20, 4, 6 }, // PART_BUTTON_SELECTED_E
{ 74, 26, 4, 6 }, // PART_BUTTON_SELECTED_SE
{ 68, 26, 6, 6 }, // PART_BUTTON_SELECTED_S
{ 64, 26, 4, 6 }, // PART_BUTTON_SELECTED_SW
{ 64, 20, 4, 6 }, // PART_BUTTON_SELECTED_W
{ 0, 32, 4, 4 }, // PART_SUNKEN_NORMAL_NW
{ 4, 32, 4, 4 }, // PART_SUNKEN_NORMAL_N
{ 8, 32, 4, 4 }, // PART_SUNKEN_NORMAL_NE
{ 8, 36, 4, 4 }, // PART_SUNKEN_NORMAL_E
{ 8, 40, 4, 4 }, // PART_SUNKEN_NORMAL_SE
{ 4, 40, 4, 4 }, // PART_SUNKEN_NORMAL_S
{ 0, 40, 4, 4 }, // PART_SUNKEN_NORMAL_SW
{ 0, 36, 4, 4 }, // PART_SUNKEN_NORMAL_W
{ 0, 48, 4, 4 }, // PART_SUNKEN_FOCUSED_NW
{ 4, 48, 4, 4 }, // PART_SUNKEN_FOCUSED_N
{ 8, 48, 4, 4 }, // PART_SUNKEN_FOCUSED_NE
{ 8, 52, 4, 4 }, // PART_SUNKEN_FOCUSED_E
{ 8, 56, 4, 4 }, // PART_SUNKEN_FOCUSED_SE
{ 4, 56, 4, 4 }, // PART_SUNKEN_FOCUSED_S
{ 0, 56, 4, 4 }, // PART_SUNKEN_FOCUSED_SW
{ 0, 52, 4, 4 }, // PART_SUNKEN_FOCUSED_W
{ 0, 64, 5, 5 }, // PART_SUNKEN2_NORMAL_NW
{ 5, 64, 6, 5 }, // PART_SUNKEN2_NORMAL_N
{ 11, 64, 5, 5 }, // PART_SUNKEN2_NORMAL_NE
{ 11, 69, 5, 6 }, // PART_SUNKEN2_NORMAL_E
{ 11, 75, 5, 5 }, // PART_SUNKEN2_NORMAL_SE
{ 5, 75, 6, 5 }, // PART_SUNKEN2_NORMAL_S
{ 0, 75, 5, 5 }, // PART_SUNKEN2_NORMAL_SW
{ 0, 69, 5, 6 }, // PART_SUNKEN2_NORMAL_W
{ 0, 80, 5, 5 }, // PART_SUNKEN2_FOCUSED_NW
{ 5, 80, 6, 5 }, // PART_SUNKEN2_FOCUSED_N
{ 11, 80, 5, 5 }, // PART_SUNKEN2_FOCUSED_NE
{ 11, 85, 5, 6 }, // PART_SUNKEN2_FOCUSED_E
{ 11, 91, 5, 5 }, // PART_SUNKEN2_FOCUSED_SE
{ 5, 91, 6, 5 }, // PART_SUNKEN2_FOCUSED_S
{ 0, 91, 5, 5 }, // PART_SUNKEN2_FOCUSED_SW
{ 0, 85, 5, 6 }, // PART_SUNKEN2_FOCUSED_W
{ 0, 0, 3, 15 }, // PART_WINDOW_NW
{ 3, 0, 7, 15 }, // PART_WINDOW_N
{ 10, 0, 3, 15 }, // PART_WINDOW_NE
{ 10, 15, 3, 4 }, // PART_WINDOW_E
{ 10, 19, 3, 5 }, // PART_WINDOW_SE
{ 3, 19, 7, 5 }, // PART_WINDOW_S
{ 0, 19, 3, 5 }, // PART_WINDOW_SW
{ 0, 15, 3, 4 }, // PART_WINDOW_W
{ 0, 96, 3, 3 }, // PART_MENU_NW
{ 3, 96, 10, 3 }, // PART_MENU_N
{ 13, 96, 3, 3 }, // PART_MENU_NE
{ 13, 99, 3, 9 }, // PART_MENU_E
{ 13,108, 3, 4 }, // PART_MENU_SE
{ 3,108, 10, 4 }, // PART_MENU_S
{ 0,108, 3, 4 }, // PART_MENU_SW
{ 0, 99, 3, 9 }, // PART_MENU_W
{ 16, 0, 9, 11 }, // PART_WINDOW_CLOSE_BUTTON_NORMAL
{ 16, 16, 9, 11 }, // PART_WINDOW_CLOSE_BUTTON_HOT
{ 16, 32, 9, 11 }, // PART_WINDOW_CLOSE_BUTTON_SELECTED
{ 0,144, 5, 5 }, // PART_SLIDER_FULL_NW
{ 5,144, 6, 5 }, // PART_SLIDER_FULL_N
{ 11,144, 5, 5 }, // PART_SLIDER_FULL_NE
{ 11,149, 5, 5 }, // PART_SLIDER_FULL_E
{ 11,154, 5, 6 }, // PART_SLIDER_FULL_SE
{ 5,154, 6, 6 }, // PART_SLIDER_FULL_S
{ 0,154, 5, 6 }, // PART_SLIDER_FULL_SW
{ 0,149, 5, 5 }, // PART_SLIDER_FULL_W
{ 16,144, 5, 5 }, // PART_SLIDER_EMPTY_NW
{ 21,144, 6, 5 }, // PART_SLIDER_EMPTY_N
{ 27,144, 5, 5 }, // PART_SLIDER_EMPTY_NE
{ 27,149, 5, 5 }, // PART_SLIDER_EMPTY_E
{ 27,154, 5, 6 }, // PART_SLIDER_EMPTY_SE
{ 21,154, 6, 6 }, // PART_SLIDER_EMPTY_S
{ 16,154, 5, 6 }, // PART_SLIDER_EMPTY_SW
{ 16,149, 5, 5 }, // PART_SLIDER_EMPTY_W
{ 0,160, 5, 5 }, // PART_SLIDER_FULL_FOCUSED_NW
{ 5,160, 6, 5 }, // PART_SLIDER_FULL_FOCUSED_N
{ 11,160, 5, 5 }, // PART_SLIDER_FULL_FOCUSED_NE
{ 11,165, 5, 5 }, // PART_SLIDER_FULL_FOCUSED_E
{ 11,170, 5, 6 }, // PART_SLIDER_FULL_FOCUSED_SE
{ 5,170, 6, 6 }, // PART_SLIDER_FULL_FOCUSED_S
{ 0,170, 5, 6 }, // PART_SLIDER_FULL_FOCUSED_SW
{ 0,165, 5, 5 }, // PART_SLIDER_FULL_FOCUSED_W
{ 16,160, 5, 5 }, // PART_SLIDER_EMPTY_FOCUSED_NW
{ 21,160, 6, 5 }, // PART_SLIDER_EMPTY_FOCUSED_N
{ 27,160, 5, 5 }, // PART_SLIDER_EMPTY_FOCUSED_NE
{ 27,165, 5, 5 }, // PART_SLIDER_EMPTY_FOCUSED_E
{ 27,170, 5, 6 }, // PART_SLIDER_EMPTY_FOCUSED_SE
{ 21,170, 6, 6 }, // PART_SLIDER_EMPTY_FOCUSED_S
{ 16,170, 5, 6 }, // PART_SLIDER_EMPTY_FOCUSED_SW
{ 16,165, 5, 5 }, // PART_SLIDER_EMPTY_FOCUSED_W
{ 32, 80, 9, 5 }, // PART_SEPARATOR
{ 96, 32, 16, 16 }, // PART_COMBOBOX_ARROW
{ 96, 0, 3, 3 }, // PART_TOOLBUTTON_NORMAL_NW
{ 99, 0, 10, 3 }, // PART_TOOLBUTTON_NORMAL_N
{109, 0, 3, 3 }, // PART_TOOLBUTTON_NORMAL_NE
{109, 3, 3, 9 }, // PART_TOOLBUTTON_NORMAL_E
{109, 12, 3, 4 }, // PART_TOOLBUTTON_NORMAL_SE
{ 99, 12, 10, 4 }, // PART_TOOLBUTTON_NORMAL_S
{ 96, 12, 3, 4 }, // PART_TOOLBUTTON_NORMAL_SW
{ 96, 3, 3, 9 }, // PART_TOOLBUTTON_NORMAL_W
{112, 0, 3, 3 }, // PART_TOOLBUTTON_HOT_NW
{115, 0, 10, 3 }, // PART_TOOLBUTTON_HOT_N
{125, 0, 3, 3 }, // PART_TOOLBUTTON_HOT_NE
{125, 3, 3, 9 }, // PART_TOOLBUTTON_HOT_E
{125, 12, 3, 4 }, // PART_TOOLBUTTON_HOT_SE
{115, 12, 10, 4 }, // PART_TOOLBUTTON_HOT_S
{112, 12, 3, 4 }, // PART_TOOLBUTTON_HOT_SW
{112, 3, 3, 9 }, // PART_TOOLBUTTON_HOT_W
{ 96, 16, 3, 3 }, // PART_TOOLBUTTON_LAST_NORMAL_NW
{ 99, 16, 10, 3 }, // PART_TOOLBUTTON_LAST_NORMAL_N
{109, 16, 3, 3 }, // PART_TOOLBUTTON_LAST_NORMAL_NE
{109, 19, 3, 9 }, // PART_TOOLBUTTON_LAST_NORMAL_E
{109, 28, 3, 4 }, // PART_TOOLBUTTON_LAST_NORMAL_SE
{ 99, 28, 10, 4 }, // PART_TOOLBUTTON_LAST_NORMAL_S
{ 96, 28, 3, 4 }, // PART_TOOLBUTTON_LAST_NORMAL_SW
{ 96, 19, 3, 9 }, // PART_TOOLBUTTON_LAST_NORMAL_W
// Tabs
{ 2,112, 4, 4 }, // PART_TAB_NORMAL_NW
{ 6,112, 5, 4 }, // PART_TAB_NORMAL_N
{ 11,112, 5, 4 }, // PART_TAB_NORMAL_NE
{ 11,116, 5, 6 }, // PART_TAB_NORMAL_E
{ 11,122, 5, 2 }, // PART_TAB_NORMAL_SE
{ 6,122, 4, 2 }, // PART_TAB_NORMAL_S
{ 2,122, 4, 2 }, // PART_TAB_NORMAL_SW
{ 2,116, 4, 6 }, // PART_TAB_NORMAL_W
{ 16,112, 4, 4 }, // PART_TAB_SELECTED_NW
{ 20,112, 7, 4 }, // PART_TAB_SELECTED_N
{ 27,112, 5, 4 }, // PART_TAB_SELECTED_NE
{ 27,116, 5, 6 }, // PART_TAB_SELECTED_E
{ 27,122, 5, 2 }, // PART_TAB_SELECTED_SE
{ 20,122, 7, 2 }, // PART_TAB_SELECTED_S
{ 16,122, 4, 2 }, // PART_TAB_SELECTED_SW
{ 16,116, 4, 6 }, // PART_TAB_SELECTED_W
{ 16,124, 4, 4 }, // PART_TAB_BOTTOM_SELECTED_NW
{ 20,124, 7, 4 }, // PART_TAB_BOTTOM_SELECTED_N
{ 27,124, 5, 4 }, // PART_TAB_BOTTOM_SELECTED_NE
{ 27,128, 5, 1 }, // PART_TAB_BOTTOM_SELECTED_E
{ 27,129, 5, 4 }, // PART_TAB_BOTTOM_SELECTED_SE
{ 20,129, 7, 4 }, // PART_TAB_BOTTOM_SELECTED_S
{ 16,129, 4, 4 }, // PART_TAB_BOTTOM_SELECTED_SW
{ 16,128, 4, 1 }, // PART_TAB_BOTTOM_SELECTED_W
{ 2,124, 12, 9 }, // PART_TAB_BOTTOM_NORMAL
{ 0,112, 2, 12 }, // PART_TAB_FILLER
{ 32,112, 3, 3 }, // PART_EDITOR_NORMAL_NW
{ 35,112, 10, 3 }, // PART_EDITOR_NORMAL_N
{ 45,112, 3, 3 }, // PART_EDITOR_NORMAL_NE
{ 45,115, 3, 10 }, // PART_EDITOR_NORMAL_E
{ 45,125, 3, 3 }, // PART_EDITOR_NORMAL_SE
{ 35,125, 10, 3 }, // PART_EDITOR_NORMAL_S
{ 32,125, 3, 3 }, // PART_EDITOR_NORMAL_SW
{ 32,115, 3, 10 }, // PART_EDITOR_NORMAL_W
{ 48,112, 3, 3 }, // PART_EDITOR_SELECTED_NW
{ 51,112, 10, 3 }, // PART_EDITOR_SELECTED_N
{ 61,112, 3, 3 }, // PART_EDITOR_SELECTED_NE
{ 61,115, 3, 10 }, // PART_EDITOR_SELECTED_E
{ 61,125, 3, 3 }, // PART_EDITOR_SELECTED_SE
{ 51,125, 10, 3 }, // PART_EDITOR_SELECTED_S
{ 48,125, 3, 3 }, // PART_EDITOR_SELECTED_SW
{ 48,115, 3, 10 }, // PART_EDITOR_SELECTED_W
};
static struct
{
int x, y;
} focus_info[] = {
{ 0, 0 }, // PART_CURSOR_NORMAL,
{ 0, 0 }, // PART_CURSOR_NORMAL_ADD,
{ 0, 0 }, // PART_CURSOR_FORBIDDEN,
{ 5, 3 }, // PART_CURSOR_HAND,
{ 8, 8 }, // PART_CURSOR_SCROLL,
{ 0, 0 }, // PART_CURSOR_MOVE,
{ 8, 8 }, // PART_CURSOR_SIZE_TL,
{ 8, 8 }, // PART_CURSOR_SIZE_T,
{ 8, 8 }, // PART_CURSOR_SIZE_TR,
{ 8, 8 }, // PART_CURSOR_SIZE_L,
{ 8, 8 }, // PART_CURSOR_SIZE_R,
{ 8, 8 }, // PART_CURSOR_SIZE_BL,
{ 8, 8 }, // PART_CURSOR_SIZE_B,
{ 8, 8 }, // PART_CURSOR_SIZE_BR,
{ 0, 15 }, // PART_CURSOR_EYEDROPPER,
};
SkinneableTheme::SkinneableTheme()
{
int scale = guiscale();
this->name = "Skinneable Theme";
this->check_icon_size = 8 * scale;
this->radio_icon_size = 8 * scale;
this->scrollbar_size = 12 * scale;
m_sheet_bmp = NULL;
for (int c=0; c<PARTS; ++c)
m_part[c] = NULL;
// Load the skin sheet
{
DIRS* dirs = filename_in_datadir("skins/default_skin_sheet.png");
for (DIRS* dir=dirs; dir; dir=dir->next) {
if ((dir->path) && exists(dir->path)) {
int old_color_conv = _color_conv;
set_color_conversion(COLORCONV_NONE);
PALETTE pal;
m_sheet_bmp = load_png(dir->path, pal);
set_color_conversion(old_color_conv);
break;
}
}
dirs_free(dirs);
}
if (!m_sheet_bmp)
throw ase_exception("Error loading data/skins/default_skin_sheet.png file");
}
SkinneableTheme::~SkinneableTheme()
{
for (int c=0; c<PARTS; ++c)
destroy_bitmap(m_part[c]);
destroy_bitmap(m_sheet_bmp);
}
void SkinneableTheme::regen()
{
desktop_color = COLOR_DISABLED;
textbox_fg_color = COLOR_FOREGROUND;
textbox_bg_color = COLOR_BACKGROUND;
for (int c=0; c<PARTS; ++c) {
if (m_part[c]) destroy_bitmap(m_part[c]);
m_part[c] = create_bitmap(sheet_info[c].w, sheet_info[c].h);
clear_to_color(m_part[c], bitmap_mask_color(m_part[c]));
set_alpha_blender();
draw_trans_sprite(m_part[c], m_sheet_bmp, -sheet_info[c].x, -sheet_info[c].y);
set_trans_blender(0, 0, 0, 0);
m_part[c] = apply_gui_scale(m_part[c]);
}
}
}
BITMAP* SkinneableTheme::set_cursor(int type, int* focus_x, int* focus_y)
{
if (type == JI_CURSOR_NULL) {
*focus_x = 0;
*focus_y = 0;
return NULL;
}
else {
*focus_x = focus_info[type-JI_CURSOR_NORMAL].x;
*focus_y = focus_info[type-JI_CURSOR_NORMAL].y;
return m_part[PART_CURSOR_NORMAL+type-JI_CURSOR_NORMAL];
}
}
void SkinneableTheme::init_widget(JWidget widget)
{
#define BORDER(n) \
widget->border_width.l = (n); \
widget->border_width.t = (n); \
widget->border_width.r = (n); \
widget->border_width.b = (n);
#define BORDER4(L,T,R,B) \
widget->border_width.l = (L); \
widget->border_width.t = (T); \
widget->border_width.r = (R); \
widget->border_width.b = (B);
int scale = guiscale();
switch (widget->type) {
case JI_BOX:
BORDER(0);
widget->child_spacing = 4 * scale;
break;
case JI_BUTTON:
BORDER4(m_part[PART_BUTTON_NORMAL_W]->w,
m_part[PART_BUTTON_NORMAL_N]->h,
m_part[PART_BUTTON_NORMAL_E]->w,
m_part[PART_BUTTON_NORMAL_S]->h);
widget->child_spacing = 0;
break;
case JI_CHECK:
BORDER(2 * scale);
widget->child_spacing = 4 * scale;
break;
case JI_ENTRY:
BORDER4(m_part[PART_SUNKEN_NORMAL_W]->w,
m_part[PART_SUNKEN_NORMAL_N]->h,
m_part[PART_SUNKEN_NORMAL_E]->w,
m_part[PART_SUNKEN_NORMAL_S]->h);
break;
case JI_GRID:
BORDER(0);
widget->child_spacing = 4 * scale;
break;
case JI_LABEL:
BORDER(1 * scale);
break;
case JI_LISTBOX:
BORDER(0);
widget->child_spacing = 0;
break;
case JI_LISTITEM:
BORDER(1 * scale);
break;
case JI_COMBOBOX:
if (!(widget->flags & JI_INITIALIZED)) {
JWidget button = jcombobox_get_button_widget(widget);
button->border_width.l = 0;
button->border_width.t = 0;
button->border_width.r = 0;
button->border_width.b = 0;
button->child_spacing = 0;
jwidget_add_hook(button, JI_WIDGET,
&SkinneableTheme::theme_combobox_button_msg_proc, NULL);
}
break;
case JI_MENU:
case JI_MENUBAR:
case JI_MENUBOX:
BORDER(0);
widget->child_spacing = 0;
break;
case JI_MENUITEM:
BORDER(2);
widget->child_spacing = 18 * scale;
break;
case JI_PANEL:
BORDER(0);
widget->child_spacing = 3 * scale;
break;
case JI_RADIO:
BORDER(2 * scale);
widget->child_spacing = 4 * scale;
break;
case JI_SEPARATOR:
/* frame */
if ((widget->getAlign() & JI_HORIZONTAL) &&
(widget->getAlign() & JI_VERTICAL)) {
BORDER(4 * scale);
}
/* horizontal bar */
else if (widget->getAlign() & JI_HORIZONTAL) {
BORDER4(2 * scale, 4 * scale, 2 * scale, 0);
}
/* vertical bar */
else {
BORDER4(4 * scale, 2 * scale, 0, 2 * scale);
}
if (widget->hasText()) {
if (widget->getAlign() & JI_TOP)
widget->border_width.t = jwidget_get_text_height(widget);
else if (widget->getAlign() & JI_BOTTOM)
widget->border_width.b = jwidget_get_text_height(widget);
}
break;
case JI_SLIDER:
BORDER4(m_part[PART_SLIDER_EMPTY_W]->w-1,
m_part[PART_SLIDER_EMPTY_N]->h,
m_part[PART_SLIDER_EMPTY_E]->w-1,
m_part[PART_SLIDER_EMPTY_S]->h-1);
widget->child_spacing = jwidget_get_text_height(widget);
widget->setAlign(JI_CENTER | JI_MIDDLE);
break;
case JI_TEXTBOX:
BORDER(0);
widget->child_spacing = 0;
break;
case JI_VIEW:
BORDER4(m_part[PART_SUNKEN_NORMAL_W]->w-1,
m_part[PART_SUNKEN_NORMAL_N]->h,
m_part[PART_SUNKEN_NORMAL_E]->w-1,
m_part[PART_SUNKEN_NORMAL_S]->h-1);
widget->child_spacing = 0;
break;
case JI_VIEW_SCROLLBAR:
BORDER(1 * scale);
widget->child_spacing = 0;
break;
case JI_VIEW_VIEWPORT:
BORDER(0);
widget->child_spacing = 0;
break;
case JI_FRAME:
if (!static_cast<Frame*>(widget)->is_desktop()) {
if (widget->hasText()) {
BORDER4(6 * scale, (4+6) * scale, 6 * scale, 6 * scale);
widget->border_width.t += jwidget_get_text_height(widget);
#if 1 /* add close button */
if (!(widget->flags & JI_INITIALIZED)) {
JWidget button = jbutton_new("");
jbutton_set_bevel(button, 0, 0, 0, 0);
jwidget_add_hook(button, JI_WIDGET,
&SkinneableTheme::theme_frame_button_msg_proc, NULL);
jwidget_decorative(button, true);
jwidget_add_child(widget, button);
button->setName("theme_close_button");
}
#endif
}
else if (!(widget->flags & JI_INITIALIZED)) {
BORDER(3 * scale);
}
}
else {
BORDER(0);
}
widget->child_spacing = 4 * scale;
widget->setBgColor(get_window_face_color());
break;
default:
break;
}
}
JRegion SkinneableTheme::get_window_mask(JWidget widget)
{
return jregion_new(widget->rc, 1);
}
void SkinneableTheme::map_decorative_widget(JWidget widget)
{
if (widget->name != NULL &&
strcmp(widget->name, "theme_close_button") == 0) {
JWidget window = widget->parent;
JRect rect = jrect_new(0, 0, 0, 0);
rect->x2 = m_part[PART_WINDOW_CLOSE_BUTTON_NORMAL]->w;
rect->y2 = m_part[PART_WINDOW_CLOSE_BUTTON_NORMAL]->h;
jrect_displace(rect,
window->rc->x2 - 3 - jrect_w(rect),
window->rc->y1 + 3);
jwidget_set_rect(widget, rect);
jrect_free(rect);
}
}
int SkinneableTheme::color_foreground()
{
return COLOR_FOREGROUND;
}
int SkinneableTheme::color_disabled()
{
return COLOR_DISABLED;
}
int SkinneableTheme::color_face()
{
return COLOR_FACE;
}
int SkinneableTheme::color_hotface()
{
return COLOR_HOTFACE;
}
int SkinneableTheme::color_selected()
{
return COLOR_SELECTED;
}
int SkinneableTheme::color_background()
{
return COLOR_BACKGROUND;
}
void SkinneableTheme::draw_box(JWidget widget, JRect clip)
{
jdraw_rectfill(clip, BGCOLOR);
}
void SkinneableTheme::draw_button(JWidget widget, JRect clip)
{
BITMAP *icon_bmp = ji_generic_button_get_icon(widget);
int icon_align = ji_generic_button_get_icon_align(widget);
struct jrect box, text, icon;
int x1, y1, x2, y2;
int fg, bg, part_nw;
JRect crect;
jwidget_get_texticon_info(widget, &box, &text, &icon,
icon_align,
icon_bmp ? icon_bmp->w : 0,
icon_bmp ? icon_bmp->h : 0);
/* selected */
if (jwidget_is_selected(widget)) {
fg = get_button_selected_text_color();
bg = get_button_selected_face_color();
part_nw = PART_BUTTON_SELECTED_NW;
}
/* with mouse */
else if (jwidget_is_enabled(widget) && jwidget_has_mouse(widget)) {
fg = get_button_hot_text_color();
bg = get_button_hot_face_color();
part_nw = PART_BUTTON_HOT_NW;
}
/* without mouse */
else {
fg = get_button_normal_text_color();
bg = get_button_normal_face_color();
if (jwidget_has_focus(widget))
part_nw = PART_BUTTON_FOCUSED_NW;
else
part_nw = PART_BUTTON_NORMAL_NW;
}
/* widget position */
x1 = widget->rc->x1;
y1 = widget->rc->y1;
x2 = widget->rc->x2-1;
y2 = widget->rc->y2-1;
// external background
rectfill(ji_screen, x1, y1, x2, y2, BGCOLOR);
// draw borders
draw_bounds(x1, y1, x2, y2, part_nw, bg);
// text
crect = jwidget_get_child_rect(widget);
draw_textstring(NULL, fg, bg, false, widget, crect, get_button_selected_offset());
jrect_free(crect);
// icon
if (icon_bmp) {
if (jwidget_is_selected(widget))
jrect_displace(&icon,
get_button_selected_offset(),
get_button_selected_offset());
/* enabled */
if (jwidget_is_enabled(widget)) {
/* selected */
if (jwidget_is_selected(widget)) {
jdraw_inverted_sprite(ji_screen, icon_bmp, icon.x1, icon.y1);
}
/* non-selected */
else {
draw_sprite(ji_screen, icon_bmp, icon.x1, icon.y1);
}
}
/* disabled */
else {
_ji_theme_draw_sprite_color(ji_screen, icon_bmp, icon.x1+guiscale(), icon.y1+guiscale(),
COLOR_BACKGROUND);
_ji_theme_draw_sprite_color(ji_screen, icon_bmp, icon.x1, icon.y1,
COLOR_DISABLED);
}
}
}
void SkinneableTheme::draw_check(JWidget widget, JRect clip)
{
struct jrect box, text, icon;
int bg;
jwidget_get_texticon_info(widget, &box, &text, &icon,
ji_generic_button_get_icon_align(widget),
widget->theme->check_icon_size,
widget->theme->check_icon_size);
// background
jdraw_rectfill(widget->rc, bg = BGCOLOR);
// mouse
if (jwidget_is_enabled(widget)) {
if (jwidget_has_mouse(widget))
jdraw_rectfill(widget->rc, bg = get_check_hot_face_color());
else if (jwidget_has_focus(widget))
jdraw_rectfill(widget->rc, bg = get_check_focus_face_color());
}
/* text */
draw_textstring(NULL, -1, bg, false, widget, &text, 0);
/* icon */
draw_sprite(ji_screen,
jwidget_is_selected(widget) ? m_part[PART_CHECK_SELECTED]:
m_part[PART_CHECK_NORMAL],
icon.x1, icon.y1);
// draw focus
if (jwidget_has_focus(widget)) {
draw_bounds(widget->rc->x1,
widget->rc->y1,
widget->rc->x2-1,
widget->rc->y2-1, PART_CHECK_FOCUS_NW, -1);
}
}
void SkinneableTheme::draw_grid(JWidget widget, JRect clip)
{
jdraw_rectfill(clip, BGCOLOR);
}
void SkinneableTheme::draw_entry(JWidget widget, JRect clip)
{
bool password = jentry_is_password(widget);
int scroll, cursor, state, selbeg, selend;
const char *text = widget->getText();
int c, ch, x, y, w, fg, bg;
int x1, y1, x2, y2;
int cursor_x;
jtheme_entry_info(widget, &scroll, &cursor, &state, &selbeg, &selend);
/* main pos */
x1 = widget->rc->x1;
y1 = widget->rc->y1;
x2 = widget->rc->x2-1;
y2 = widget->rc->y2-1;
bg = COLOR_BACKGROUND;
draw_bounds(x1, y1, x2, y2,
jwidget_has_focus(widget) ? PART_SUNKEN_FOCUSED_NW:
PART_SUNKEN_NORMAL_NW, bg);
/* draw the text */
x = widget->rc->x1 + widget->border_width.l;
y = (widget->rc->y1+widget->rc->y2)/2 - jwidget_get_text_height(widget)/2;
for (c=scroll; ugetat(text, c); c++) {
ch = password ? '*': ugetat(text, c);
/* normal text */
bg = -1;
fg = COLOR_FOREGROUND;
/* selected */
if ((c >= selbeg) && (c <= selend)) {
if (jwidget_has_focus(widget))
bg = COLOR_SELECTED;
else
bg = COLOR_DISABLED;
fg = COLOR_BACKGROUND;
}
/* disabled */
if (jwidget_is_disabled (widget)) {
bg = -1;
fg = COLOR_DISABLED;
}
w = CHARACTER_LENGTH(widget->getFont(), ch);
if (x+w > widget->rc->x2-3)
return;
cursor_x = x;
ji_font_set_aa_mode(widget->getFont(), bg >= 0 ? bg: COLOR_BACKGROUND);
widget->getFont()->vtable->render_char(widget->getFont(),
ch, fg, bg, ji_screen, x, y);
x += w;
/* cursor */
if ((c == cursor) && (state) && (jwidget_has_focus (widget)))
draw_entry_cursor(widget, cursor_x, y);
}
/* draw the cursor if it is next of the last character */
if ((c == cursor) && (state) &&
(jwidget_has_focus(widget)) &&
(jwidget_is_enabled(widget)))
draw_entry_cursor(widget, x, y);
}
void SkinneableTheme::draw_label(JWidget widget, JRect clip)
{
int bg = BGCOLOR;
jdraw_rectfill(widget->rc, bg);
draw_textstring(NULL, -1, bg, false, widget, widget->rc, 0);
}
void SkinneableTheme::draw_listbox(JWidget widget, JRect clip)
{
jdraw_rectfill(widget->rc, COLOR_BACKGROUND);
}
void SkinneableTheme::draw_listitem(JWidget widget, JRect clip)
{
int fg, bg;
int x, y;
if (jwidget_is_disabled(widget)) {
bg = COLOR_FACE;
fg = COLOR_DISABLED;
}
else if (jwidget_is_selected(widget)) {
fg = get_listitem_selected_text_color();
bg = get_listitem_selected_face_color();
}
else {
fg = get_listitem_normal_text_color();
bg = get_listitem_normal_face_color();
}
x = widget->rc->x1+widget->border_width.l;
y = widget->rc->y1+widget->border_width.t;
if (widget->hasText()) {
/* text */
jdraw_text(widget->getFont(), widget->getText(), x, y, fg, bg, true);
/* background */
jrectexclude
(ji_screen,
widget->rc->x1, widget->rc->y1,
widget->rc->x2-1, widget->rc->y2-1,
x, y,
x+jwidget_get_text_length(widget)-1,
y+jwidget_get_text_height(widget)-1, bg);
}
/* background */
else {
jdraw_rectfill(widget->rc, bg);
}
}
void SkinneableTheme::draw_menu(JWidget widget, JRect clip)
{
jdraw_rectfill(widget->rc, BGCOLOR);
}
void SkinneableTheme::draw_menuitem(JWidget widget, JRect clip)
{
int c, bg, fg, bar;
int x1, y1, x2, y2;
JRect pos;
/* TODO assert? */
if (!widget->parent->parent)
return;
bar = (widget->parent->parent->type == JI_MENUBAR);
/* colors */
if (jwidget_is_disabled(widget)) {
fg = -1;
bg = get_menuitem_normal_face_color();
}
else {
if (jmenuitem_is_highlight(widget)) {
fg = get_menuitem_highlight_text_color();
bg = get_menuitem_highlight_face_color();
}
else if (jwidget_has_mouse(widget)) {
fg = get_menuitem_hot_text_color();
bg = get_menuitem_hot_face_color();
}
else {
fg = get_menuitem_normal_text_color();
bg = get_menuitem_normal_face_color();
}
}
/* widget position */
x1 = widget->rc->x1;
y1 = widget->rc->y1;
x2 = widget->rc->x2-1;
y2 = widget->rc->y2-1;
/* background */
rectfill(ji_screen, x1, y1, x2, y2, bg);
/* draw an indicator for selected items */
if (jwidget_is_selected(widget)) {
BITMAP* icon = m_part[jwidget_is_enabled(widget) ? PART_CHECK_SELECTED:
PART_CHECK_DISABLED];
int x = widget->rc->x1+4-icon->w/2;
int y = (widget->rc->y1+widget->rc->y2)/2-icon->h/2;
draw_sprite(ji_screen, icon, x, y);
}
/* text */
if (bar)
widget->setAlign(JI_CENTER | JI_MIDDLE);
else
widget->setAlign(JI_LEFT | JI_MIDDLE);
pos = jwidget_get_rect(widget);
if (!bar)
jrect_displace(pos, widget->child_spacing/2, 0);
draw_textstring(NULL, fg, bg, false, widget, pos, 0);
jrect_free(pos);
/* for menu-box */
if (!bar) {
/* draw the arrown (to indicate which this menu has a sub-menu) */
if (jmenuitem_get_submenu(widget)) {
/* enabled */
if (jwidget_is_enabled(widget)) {
for (c=0; c<3; c++)
vline(ji_screen,
widget->rc->x2-3-c,
(widget->rc->y1+widget->rc->y2)/2-c,
(widget->rc->y1+widget->rc->y2)/2+c, fg);
}
/* disabled */
else {
for (c=0; c<3; c++)
vline(ji_screen,
widget->rc->x2-3-c+1,
(widget->rc->y1+widget->rc->y2)/2-c+1,
(widget->rc->y1+widget->rc->y2)/2+c+1, COLOR_BACKGROUND);
for (c=0; c<3; c++)
vline(ji_screen,
widget->rc->x2-3-c,
(widget->rc->y1+widget->rc->y2)/2-c,
(widget->rc->y1+widget->rc->y2)/2+c, COLOR_DISABLED);
}
}
/* draw the keyboard shortcut */
else if (jmenuitem_get_accel(widget)) {
int old_align = widget->getAlign();
char buf[256];
pos = jwidget_get_rect(widget);
pos->x2 -= widget->child_spacing/4;
jaccel_to_string(jmenuitem_get_accel(widget), buf);
widget->setAlign(JI_RIGHT | JI_MIDDLE);
draw_textstring(buf, fg, bg, false, widget, pos, 0);
widget->setAlign(old_align);
jrect_free(pos);
}
}
}
void SkinneableTheme::draw_panel(JWidget widget, JRect clip)
{
jdraw_rectfill(widget->rc, get_panel_face_color());
}
void SkinneableTheme::draw_radio(JWidget widget, JRect clip)
{
struct jrect box, text, icon;
int bg = BGCOLOR;
jwidget_get_texticon_info(widget, &box, &text, &icon,
ji_generic_button_get_icon_align(widget),
widget->theme->radio_icon_size,
widget->theme->radio_icon_size);
/* background */
jdraw_rectfill(widget->rc, bg);
/* mouse */
if (jwidget_is_enabled(widget)) {
if (jwidget_has_mouse(widget))
jdraw_rectfill(widget->rc, bg = get_radio_hot_face_color());
else if (jwidget_has_focus(widget))
jdraw_rectfill(widget->rc, bg = get_radio_focus_face_color());
}
/* text */
draw_textstring(NULL, -1, bg, false, widget, &text, 0);
/* icon */
draw_sprite(ji_screen,
jwidget_is_selected(widget) ? m_part[PART_RADIO_SELECTED]:
m_part[PART_RADIO_NORMAL],
icon.x1, icon.y1);
// draw focus
if (jwidget_has_focus(widget)) {
draw_bounds(widget->rc->x1,
widget->rc->y1,
widget->rc->x2-1,
widget->rc->y2-1, PART_RADIO_FOCUS_NW, -1);
}
}
void SkinneableTheme::draw_separator(JWidget widget, JRect clip)
{
int x1, y1, x2, y2;
// frame position
x1 = widget->rc->x1 + widget->border_width.l/2;
y1 = widget->rc->y1 + widget->border_width.t/2;
x2 = widget->rc->x2 - 1 - widget->border_width.r/2;
y2 = widget->rc->y2 - 1 - widget->border_width.b/2;
// background
jdraw_rectfill(widget->rc, BGCOLOR);
if (widget->getAlign() & JI_HORIZONTAL) {
draw_hline(widget->rc->x1,
widget->rc->y1,
widget->rc->x2-1,
widget->rc->y2-1, PART_SEPARATOR);
}
// text
if (widget->hasText()) {
int h = jwidget_get_text_height(widget);
struct jrect r = { x1+h/2, y1-h/2, x2+1-h, y2+1+h };
draw_textstring(NULL, -1, BGCOLOR, false, widget, &r, 0);
}
}
#if 1
/* TODO when Allegro 4.1 will be officially released, replace this
with the get_clip_rect, add_clip_rect, set_clip_rect functions */
static int my_add_clip_rect(BITMAP *bitmap, int x1, int y1, int x2, int y2)
{
int u1 = MAX(x1, bitmap->cl);
int v1 = MAX(y1, bitmap->ct);
int u2 = MIN(x2, bitmap->cr-1);
int v2 = MIN(y2, bitmap->cb-1);
if (u1 > u2 || v1 > v2)
return false;
else
set_clip(bitmap, u1, v1, u2, v2);
return true;
}
#endif
void SkinneableTheme::draw_slider(JWidget widget, JRect clip)
{
int x, x1, y1, x2, y2;
int min, max, value;
char buf[256];
jtheme_slider_info(widget, &min, &max, &value);
x1 = widget->rc->x1 + widget->border_width.l;
y1 = widget->rc->y1 + widget->border_width.t;
x2 = widget->rc->x2 - widget->border_width.r - 1;
y2 = widget->rc->y2 - widget->border_width.b - 1;
if (min != max)
x = x1 + (x2-x1) * (value-min) / (max-min);
else
x = x1;
x1 = widget->rc->x1;
y1 = widget->rc->y1;
x2 = widget->rc->x2 - 1;
y2 = widget->rc->y2 - 1;
int full_part_nw = jwidget_has_focus(widget) ? PART_SLIDER_FULL_FOCUSED_NW: PART_SLIDER_FULL_NW;
int empty_part_nw = jwidget_has_focus(widget) ? PART_SLIDER_EMPTY_FOCUSED_NW: PART_SLIDER_EMPTY_NW;
if (value == min)
draw_bounds(x1, y1, x2, y2, empty_part_nw, get_slider_empty_face_color());
else if (value == max)
draw_bounds(x1, y1, x2, y2, full_part_nw, get_slider_full_face_color());
else
draw_bounds2(x1, y1, x2, y2, x,
full_part_nw, empty_part_nw,
get_slider_full_face_color(),
get_slider_empty_face_color());
/* text */
{
std::string old_text = widget->getText();
int cx1, cy1, cx2, cy2;
JRect r;
usprintf(buf, "%d", value);
widget->setTextQuiet(buf);
r = jrect_new(x1, y1, x2+1, y2+1);
/* TODO when Allegro 4.1 will be officially released, replace this
with the get_clip_rect, add_clip_rect, set_clip_rect
functions */
cx1 = ji_screen->cl;
cy1 = ji_screen->ct;
cx2 = ji_screen->cr-1;
cy2 = ji_screen->cb-1;
if (my_add_clip_rect(ji_screen, x1, y1, x, y2))
draw_textstring(NULL,
get_slider_full_text_color(),
get_slider_full_face_color(), false, widget, r, 0);
set_clip(ji_screen, cx1, cy1, cx2, cy2);
if (my_add_clip_rect(ji_screen, x+1, y1, x2, y2))
draw_textstring(NULL,
get_slider_empty_text_color(),
get_slider_empty_face_color(), false, widget, r, 0);
set_clip(ji_screen, cx1, cy1, cx2, cy2);
widget->setTextQuiet(old_text.c_str());
jrect_free(r);
}
}
void SkinneableTheme::draw_combobox_entry(JWidget widget, JRect clip)
{
bool password = jentry_is_password(widget);
int scroll, cursor, state, selbeg, selend;
const char *text = widget->getText();
int c, ch, x, y, w, fg, bg;
int x1, y1, x2, y2;
int cursor_x;
jtheme_entry_info(widget, &scroll, &cursor, &state, &selbeg, &selend);
/* main pos */
x1 = widget->rc->x1;
y1 = widget->rc->y1;
x2 = widget->rc->x2-1;
y2 = widget->rc->y2-1;
bg = COLOR_BACKGROUND;
draw_bounds(x1, y1, x2, y2,
jwidget_has_focus(widget) ? PART_SUNKEN2_FOCUSED_NW:
PART_SUNKEN2_NORMAL_NW, bg);
/* draw the text */
x = widget->rc->x1 + widget->border_width.l;
y = (widget->rc->y1+widget->rc->y2)/2 - jwidget_get_text_height(widget)/2;
for (c=scroll; ugetat(text, c); c++) {
ch = password ? '*': ugetat(text, c);
/* normal text */
bg = -1;
fg = COLOR_FOREGROUND;
/* selected */
if ((c >= selbeg) && (c <= selend)) {
if (jwidget_has_focus(widget))
bg = COLOR_SELECTED;
else
bg = COLOR_DISABLED;
fg = COLOR_BACKGROUND;
}
/* disabled */
if (jwidget_is_disabled (widget)) {
bg = -1;
fg = COLOR_DISABLED;
}
w = CHARACTER_LENGTH(widget->getFont(), ch);
if (x+w > widget->rc->x2-3)
return;
cursor_x = x;
ji_font_set_aa_mode(widget->getFont(), bg >= 0 ? bg: COLOR_BACKGROUND);
widget->getFont()->vtable->render_char(widget->getFont(),
ch, fg, bg, ji_screen, x, y);
x += w;
/* cursor */
if ((c == cursor) && (state) && (jwidget_has_focus (widget)))
draw_entry_cursor(widget, cursor_x, y);
}
/* draw the cursor if it is next of the last character */
if ((c == cursor) && (state) &&
(jwidget_has_focus(widget)) &&
(jwidget_is_enabled(widget)))
draw_entry_cursor(widget, x, y);
}
void SkinneableTheme::draw_combobox_button(JWidget widget, JRect clip)
{
BITMAP* icon_bmp = m_part[PART_COMBOBOX_ARROW];
struct jrect icon;
int x1, y1, x2, y2;
int fg, bg, part_nw;
/* with mouse */
if (jwidget_is_selected(widget) ||
(jwidget_is_enabled(widget) && jwidget_has_mouse(widget))) {
fg = get_button_hot_text_color();
bg = get_button_hot_face_color();
part_nw = PART_TOOLBUTTON_HOT_NW;
}
/* without mouse */
else {
fg = get_button_normal_text_color();
bg = get_button_normal_face_color();
part_nw = PART_TOOLBUTTON_LAST_NW;
}
/* widget position */
x1 = widget->rc->x1;
y1 = widget->rc->y1;
x2 = widget->rc->x2-1;
y2 = widget->rc->y2-1;
// external background
rectfill(ji_screen, x1, y1, x2, y2, BGCOLOR);
// draw borders
draw_bounds(x1, y1, x2, y2, part_nw, bg);
// icon
icon.x1 = (x1+x2)/2 - icon_bmp->w/2;
icon.y1 = (y1+y2)/2 - icon_bmp->h/2;
icon.x2 = icon.x1 + icon_bmp->w;
icon.y2 = icon.y1 + icon_bmp->h;
if (jwidget_is_selected(widget))
jrect_displace(&icon,
get_button_selected_offset(),
get_button_selected_offset());
draw_sprite(ji_screen, icon_bmp, icon.x1, icon.y1);
}
void SkinneableTheme::draw_textbox(JWidget widget, JRect clip)
{
_ji_theme_textbox_draw(ji_screen, widget, NULL, NULL,
widget->theme->textbox_bg_color,
widget->theme->textbox_fg_color);
}
void SkinneableTheme::draw_view(JWidget widget, JRect clip)
{
draw_bounds(widget->rc->x1,
widget->rc->y1,
widget->rc->x2-1,
widget->rc->y2-1,
jwidget_has_focus(widget) ? PART_SUNKEN_FOCUSED_NW:
PART_SUNKEN_NORMAL_NW,
COLOR_BACKGROUND);
}
void SkinneableTheme::draw_view_scrollbar(JWidget widget, JRect clip)
{
int x1, y1, x2, y2;
int u1, v1, u2, v2;
int pos, len;
jtheme_scrollbar_info(widget, &pos, &len);
x1 = widget->rc->x1;
y1 = widget->rc->y1;
x2 = widget->rc->x2-1;
y2 = widget->rc->y2-1;
/* border */
rect(ji_screen, x1, y1, x2, y2, BGCOLOR);
/* draw the content */
x1++, y1++, x2--, y2--;
/* horizontal bar */
if (widget->getAlign() & JI_HORIZONTAL) {
u1 = x1+pos;
v1 = y1;
u2 = x1+pos+len-1;
v2 = y2;
}
/* vertical bar */
else {
u1 = x1;
v1 = y1+pos;
u2 = x2;
v2 = y1+pos+len-1;
}
/* background */
jrectexclude(ji_screen,
x1, y1, x2, y2,
u1, v1, u2, v2, BGCOLOR);
/* 1st border */
if (jwidget_is_selected(widget))
jrectedge(ji_screen, u1, v1, u2, v2,
COLOR_DISABLED, COLOR_BACKGROUND);
else
jrectedge(ji_screen, u1, v1, u2, v2,
COLOR_BACKGROUND, COLOR_DISABLED);
/* bar-block background */
u1++, v1++, u2--, v2--;
if (jwidget_is_enabled(widget) && jwidget_has_mouse(widget))
rectfill(ji_screen, u1, v1, u2, v2, COLOR_HOTFACE);
else
rectfill(ji_screen, u1, v1, u2, v2, BGCOLOR);
}
void SkinneableTheme::draw_view_viewport(JWidget widget, JRect clip)
{
jdraw_rectfill(widget->rc, BGCOLOR);
}
void SkinneableTheme::draw_frame(Frame* window, JRect clip)
{
JRect pos = jwidget_get_rect(window);
JRect cpos = jwidget_get_child_rect(window);
if (!window->is_desktop()) {
// window frame
if (window->hasText()) {
draw_bounds(pos->x1,
pos->y1,
pos->x2-1,
pos->y2-1, PART_WINDOW_NW,
get_window_face_color());
pos->y2 = cpos->y1;
// titlebar
jdraw_text(window->getFont(), window->getText(),
cpos->x1,
pos->y1+jrect_h(pos)/2-text_height(window->getFont())/2,
COLOR_BACKGROUND, -1, false);
}
// menubox
else {
draw_bounds(pos->x1,
pos->y1,
pos->x2-1,
pos->y2-1, PART_MENU_NW,
get_window_face_color());
}
}
// desktop
else {
jdraw_rectfill(pos, window->theme->desktop_color);
}
jrect_free(pos);
jrect_free(cpos);
}
void SkinneableTheme::draw_frame_button(JWidget widget, JRect clip)
{
int part;
if (widget->isSelected())
part = PART_WINDOW_CLOSE_BUTTON_SELECTED;
else if (jwidget_has_mouse(widget))
part = PART_WINDOW_CLOSE_BUTTON_HOT;
else
part = PART_WINDOW_CLOSE_BUTTON_NORMAL;
draw_sprite(ji_screen, m_part[part], widget->rc->x1, widget->rc->y1);
}
int SkinneableTheme::get_bg_color(JWidget widget)
{
int c = jwidget_get_bg_color(widget);
int decorative = jwidget_is_decorative(widget);
return c >= 0 ? c: (decorative ? COLOR_SELECTED:
COLOR_FACE);
}
void SkinneableTheme::draw_textstring(const char *t, int fg_color, int bg_color,
bool fill_bg, JWidget widget, const JRect rect,
int selected_offset)
{
if (t || widget->hasText()) {
int x, y, w, h;
if (!t) {
t = widget->getText();
w = jwidget_get_text_length(widget);
h = jwidget_get_text_height(widget);
}
else {
w = ji_font_text_len(widget->getFont(), t);
h = text_height(widget->getFont());
}
/* horizontally text alignment */
if (widget->getAlign() & JI_RIGHT)
x = rect->x2 - w;
else if (widget->getAlign() & JI_CENTER)
x = (rect->x1+rect->x2)/2 - w/2;
else
x = rect->x1;
/* vertically text alignment */
if (widget->getAlign() & JI_BOTTOM)
y = rect->y2 - h;
else if (widget->getAlign() & JI_MIDDLE)
y = (rect->y1+rect->y2)/2 - h/2;
else
y = rect->y1;
if (jwidget_is_selected (widget)) {
x += selected_offset;
y += selected_offset;
}
/* background */
if (bg_color >= 0) {
if (jwidget_is_disabled (widget))
rectfill(ji_screen, x, y, x+w, y+h, bg_color);
else
rectfill(ji_screen, x, y, x+w-1, y+h-1, bg_color);
}
/* text */
if (jwidget_is_disabled (widget)) {
/* TODO avoid this */
if (fill_bg) /* only to draw the background */
jdraw_text(widget->getFont(), t, x, y, 0, bg_color, fill_bg);
/* draw white part */
jdraw_text(widget->getFont(), t, x+1, y+1,
COLOR_BACKGROUND, bg_color, fill_bg);
if (fill_bg)
fill_bg = false;
}
jdraw_text(widget->getFont(), t, x, y,
jwidget_is_disabled(widget) ?
COLOR_DISABLED: (fg_color >= 0 ? fg_color :
COLOR_FOREGROUND),
bg_color, fill_bg);
}
}
void SkinneableTheme::draw_entry_cursor(JWidget widget, int x, int y)
{
int h = jwidget_get_text_height(widget);
vline(ji_screen, x, y-1, y+h, COLOR_FOREGROUND);
vline(ji_screen, x+1, y-1, y+h, COLOR_FOREGROUND);
}
void SkinneableTheme::draw_bounds(int x1, int y1, int x2, int y2, int nw, int bg)
{
int x, y;
// top
draw_sprite(ji_screen, m_part[nw], x1, y1);
for (x = x1+m_part[nw]->w;
x < x2-m_part[nw+2]->w-m_part[nw+1]->w+1;
x += m_part[nw+1]->w) {
draw_sprite(ji_screen, m_part[nw+1], x, y1);
}
draw_sprite(ji_screen, m_part[nw+1], x2-m_part[nw+2]->w-m_part[nw+1]->w+1, y1);
draw_sprite(ji_screen, m_part[nw+2], x2-m_part[nw+2]->w+1, y1);
// bottom
draw_sprite(ji_screen, m_part[nw+6], x1, y2-m_part[nw+6]->h+1);
for (x = x1+m_part[nw+6]->w;
x < x2-m_part[nw+4]->w-m_part[nw+5]->w+1;
x += m_part[nw+5]->w) {
draw_sprite(ji_screen, m_part[nw+5], x, y2-m_part[nw+5]->h+1);
}
draw_sprite(ji_screen, m_part[nw+5], x2-m_part[nw+4]->w-m_part[nw+5]->w+1, y2-m_part[nw+5]->h+1);
draw_sprite(ji_screen, m_part[nw+4], x2-m_part[nw+4]->w+1, y2-m_part[nw+4]->h+1);
// left
for (y = y1+m_part[nw]->h;
y < y2-m_part[nw+6]->h-m_part[nw+7]->h+1;
y += m_part[nw+7]->h) {
draw_sprite(ji_screen, m_part[nw+7], x1, y);
}
draw_sprite(ji_screen, m_part[nw+7], x1, y2-m_part[nw+6]->h-m_part[nw+7]->h+1);
// right
for (y = y1+m_part[nw+2]->h;
y < y2-m_part[nw+4]->h-m_part[nw+3]->h+1;
y += m_part[nw+3]->h) {
draw_sprite(ji_screen, m_part[nw+3], x2-m_part[nw+3]->w+1, y);
}
draw_sprite(ji_screen, m_part[nw+3], x2-m_part[nw+3]->w+1, y2-m_part[nw+4]->h-m_part[nw+3]->h+1);
// background
if (bg >= 0) {
x1 += m_part[nw+7]->w;
y1 += m_part[nw+1]->h;
x2 -= m_part[nw+3]->w;
y2 -= m_part[nw+5]->h;
rectfill(ji_screen, x1, y1, x2, y2, bg);
}
}
void SkinneableTheme::draw_bounds2(int x1, int y1, int x2, int y2, int x_mid, int nw1, int nw2, int bg1, int bg2)
{
int cx1, cy1, cx2, cy2;
/* TODO when Allegro 4.1 will be officially released, replace this
with the get_clip_rect, add_clip_rect, set_clip_rect
functions */
cx1 = ji_screen->cl;
cy1 = ji_screen->ct;
cx2 = ji_screen->cr-1;
cy2 = ji_screen->cb-1;
if (my_add_clip_rect(ji_screen, x1, y1, x_mid, y2))
draw_bounds(x1, y1, x2, y2, nw1, bg1);
set_clip(ji_screen, cx1, cy1, cx2, cy2);
if (my_add_clip_rect(ji_screen, x_mid+1, y1, x2, y2))
draw_bounds(x1, y1, x2, y2, nw2, bg2);
set_clip(ji_screen, cx1, cy1, cx2, cy2);
}
void SkinneableTheme::draw_hline(int x1, int y1, int x2, int y2, int part)
{
int x;
for (x = x1;
x <= x2-m_part[part]->w;
x += m_part[part]->w) {
draw_sprite(ji_screen, m_part[part], x, y1);
}
if (x <= x2)
blit(m_part[part], ji_screen, 0, 0, x, y1, x2-x+1, m_part[part]->h);
}
void SkinneableTheme::draw_bevel_box(int x1, int y1, int x2, int y2, int c1, int c2, int *bevel)
{
hline(ji_screen, x1+bevel[0], y1, x2-bevel[1], c1); /* top */
hline(ji_screen, x1+bevel[2], y2, x2-bevel[3], c2); /* bottom */
vline(ji_screen, x1, y1+bevel[0], y2-bevel[2], c1); /* left */
vline(ji_screen, x2, y1+bevel[1], y2-bevel[3], c2); /* right */
line(ji_screen, x1, y1+bevel[0], x1+bevel[0], y1, c1); /* top-left */
line(ji_screen, x1, y2-bevel[2], x1+bevel[2], y2, c2); /* bottom-left */
line(ji_screen, x2-bevel[1], y1, x2, y1+bevel[1], c2); /* top-right */
line(ji_screen, x2-bevel[3], y2, x2, y2-bevel[3], c2); /* bottom-right */
}
void SkinneableTheme::less_bevel(int *bevel)
{
if (bevel[0] > 0) --bevel[0];
if (bevel[1] > 0) --bevel[1];
if (bevel[2] > 0) --bevel[2];
if (bevel[3] > 0) --bevel[3];
}
BITMAP* SkinneableTheme::apply_gui_scale(BITMAP* original)
{
int scale = guiscale();
if (scale > 1) {
BITMAP* scaled = create_bitmap(original->w*scale,
original->h*scale);
for (int y=0; y<scaled->h; ++y)
for (int x=0; x<scaled->w; ++x)
putpixel(scaled, x, y, getpixel(original, x/scale, y/scale));
destroy_bitmap(original);
return scaled;
}
else
return original;
}
/* controls the "X" button in a window to close it */
bool SkinneableTheme::theme_frame_button_msg_proc(JWidget widget, JMessage msg)
{
switch (msg->type) {
case JM_SETCURSOR:
jmouse_set_cursor(JI_CURSOR_NORMAL);
return true;
case JM_DRAW:
((SkinneableTheme*)widget->theme)->draw_frame_button(widget, &msg->draw.rect);
return true;
case JM_KEYPRESSED:
if (msg->key.scancode == KEY_ESC) {
jwidget_select(widget);
return true;
}
break;
case JM_KEYRELEASED:
if (msg->key.scancode == KEY_ESC) {
if (jwidget_is_selected(widget)) {
jwidget_deselect(widget);
jwidget_close_window(widget);
return true;
}
}
break;
}
return false;
}
bool SkinneableTheme::theme_combobox_button_msg_proc(JWidget widget, JMessage msg)
{
switch (msg->type) {
case JM_REQSIZE:
msg->reqsize.w = 15;
msg->reqsize.h = 16;
return true;
}
return false;
}