mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-05 14:29:45 +00:00
608 lines
13 KiB
C++
608 lines
13 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 <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "jinete/jmanager.h"
|
|
#include "jinete/jmessage.h"
|
|
#include "jinete/jrect.h"
|
|
#include "jinete/jsystem.h"
|
|
#include "jinete/jview.h"
|
|
#include "jinete/jwidget.h"
|
|
#include "jinete/jtheme.h"
|
|
|
|
#include "core/color.h"
|
|
#include "modules/gui.h"
|
|
#include "modules/palettes.h"
|
|
#include "raster/blend.h"
|
|
#include "raster/image.h"
|
|
#include "raster/palette.h"
|
|
#include "widgets/paledit.h"
|
|
|
|
#define COLOR_SIZE (m_boxsize)
|
|
|
|
static int paledit_type()
|
|
{
|
|
static int type = 0;
|
|
if (!type)
|
|
type = ji_register_widget_type();
|
|
return type;
|
|
}
|
|
|
|
PalEdit::PalEdit(bool editable)
|
|
: Widget(paledit_type())
|
|
{
|
|
m_editable = editable;
|
|
m_range_type = PALETTE_EDITOR_RANGE_NONE;
|
|
m_columns = 16;
|
|
m_boxsize = 6;
|
|
m_color[0] = -1;
|
|
m_color[1] = -1;
|
|
|
|
jwidget_focusrest(this, true);
|
|
|
|
this->border_width.l = this->border_width.r = 1 * jguiscale();
|
|
this->border_width.t = this->border_width.b = 1 * jguiscale();
|
|
this->child_spacing = 1 * jguiscale();
|
|
}
|
|
|
|
int PalEdit::getRangeType()
|
|
{
|
|
return m_range_type;
|
|
}
|
|
|
|
int PalEdit::getColumns()
|
|
{
|
|
return m_columns;
|
|
}
|
|
|
|
void PalEdit::setColumns(int columns)
|
|
{
|
|
int old_columns = m_columns;
|
|
|
|
assert(columns >= 1 && columns <= 256);
|
|
m_columns = columns;
|
|
|
|
if (m_columns != old_columns) {
|
|
Widget* view = jwidget_get_view(this);
|
|
if (view)
|
|
jview_update(view);
|
|
|
|
jwidget_dirty(this);
|
|
}
|
|
}
|
|
|
|
void PalEdit::setBoxSize(int boxsize)
|
|
{
|
|
m_boxsize = boxsize;
|
|
}
|
|
|
|
void PalEdit::selectColor(int index)
|
|
{
|
|
assert(index >= 0 && index <= 255);
|
|
|
|
if ((m_color[0] != index) ||
|
|
(m_color[1] != index) ||
|
|
(m_range_type != PALETTE_EDITOR_RANGE_NONE)) {
|
|
m_color[0] = index;
|
|
m_color[1] = index;
|
|
m_range_type = PALETTE_EDITOR_RANGE_NONE;
|
|
|
|
if ((index >= 0) && (index <= 255))
|
|
update_scroll(index);
|
|
|
|
jwidget_dirty(this);
|
|
}
|
|
}
|
|
|
|
void PalEdit::selectRange(int begin, int end, int range_type)
|
|
{
|
|
/* assert(begin >= 0 && begin <= 255); */
|
|
/* assert(end >= 0 && end <= 255); */
|
|
|
|
m_color[0] = begin;
|
|
m_color[1] = end;
|
|
m_range_type = range_type;
|
|
|
|
update_scroll(end);
|
|
jwidget_dirty(this);
|
|
}
|
|
|
|
static void swap_color(Palette* palette, int i1, int i2)
|
|
{
|
|
ase_uint32 c1 = palette->getEntry(i1);
|
|
ase_uint32 c2 = palette->getEntry(i2);
|
|
|
|
palette->setEntry(i2, c1);
|
|
palette->setEntry(i1, c2);
|
|
}
|
|
|
|
void PalEdit::moveSelection(int x, int y)
|
|
{
|
|
if (!m_editable)
|
|
return;
|
|
|
|
switch (m_range_type) {
|
|
|
|
case PALETTE_EDITOR_RANGE_LINEAL: {
|
|
int c1 = MIN(m_color[0], m_color[1]);
|
|
int c2 = MAX(m_color[0], m_color[1]);
|
|
int c;
|
|
|
|
/* left */
|
|
if (x < 0) {
|
|
if (c1 > 0) {
|
|
for (c=c1; c<=c2; c++)
|
|
swap_color(get_current_palette(), c, c-1);
|
|
|
|
m_color[0]--;
|
|
m_color[1]--;
|
|
}
|
|
}
|
|
/* right */
|
|
else if (x > 0) {
|
|
if (c2 < 255) {
|
|
for (c=c2; c>=c1; c--)
|
|
swap_color(get_current_palette(), c, c+1);
|
|
|
|
m_color[0]++;
|
|
m_color[1]++;
|
|
}
|
|
}
|
|
/* up */
|
|
else if (y < 0) {
|
|
/* TODO this should be implemented? */
|
|
}
|
|
/* down */
|
|
else if (y > 0) {
|
|
/* TODO this should be implemented? */
|
|
}
|
|
break;
|
|
}
|
|
|
|
case PALETTE_EDITOR_RANGE_NONE:
|
|
case PALETTE_EDITOR_RANGE_RECTANGULAR: {
|
|
int cols = m_columns;
|
|
int index1 = m_color[0];
|
|
int index2 = m_color[1];
|
|
int c, u, v, x1, y1, x2, y2;
|
|
|
|
/* swap */
|
|
if (index1 > index2) {
|
|
c = index1;
|
|
index1 = index2;
|
|
index2 = c;
|
|
}
|
|
|
|
x1 = index1 % cols;
|
|
y1 = index1 / cols;
|
|
x2 = index2 % cols;
|
|
y2 = index2 / cols;
|
|
|
|
if (x2 < x1) { c = x2; x2 = x1; x1 = c; }
|
|
if (y2 < y1) { c = y2; y2 = y1; y1 = c; }
|
|
|
|
/* left */
|
|
if (x < 0) {
|
|
if ((x1 > 0) && ((y1*cols+x1-1) >= 0)) {
|
|
for (v=y1; v<=y2; v++)
|
|
for (u=x1; u<=x2; u++)
|
|
swap_color(get_current_palette(),
|
|
(v*cols + u),
|
|
(v*cols + (u-1)));
|
|
|
|
m_color[0]--;
|
|
m_color[1]--;
|
|
}
|
|
}
|
|
/* right */
|
|
else if (x > 0) {
|
|
if ((x2 < cols-1) && ((y2*cols+x2+1) <= 255)) {
|
|
for (v=y1; v<=y2; v++)
|
|
for (u=x2; u>=x1; u--)
|
|
swap_color(get_current_palette(),
|
|
(v*cols + u),
|
|
(v*cols + (u+1)));
|
|
|
|
m_color[0]++;
|
|
m_color[1]++;
|
|
}
|
|
}
|
|
/* up */
|
|
else if (y < 0) {
|
|
if (((y1-1)*cols+x1) >= 0) {
|
|
for (v=y1; v<=y2; v++)
|
|
for (u=x1; u<=x2; u++)
|
|
swap_color(get_current_palette(),
|
|
(v*cols + u),
|
|
((v-1)*cols + u));
|
|
|
|
m_color[0] -= cols;
|
|
m_color[1] -= cols;
|
|
}
|
|
}
|
|
/* down */
|
|
else if (y > 0) {
|
|
if (((y2+1)*cols+x2) <= 255) {
|
|
for (v=y2; v>=y1; v--)
|
|
for (u=x1; u<=x2; u++)
|
|
swap_color(get_current_palette(),
|
|
(v*cols + u),
|
|
((v+1)*cols + u));
|
|
|
|
m_color[0] += cols;
|
|
m_color[1] += cols;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* fixup the scroll */
|
|
update_scroll(m_color[1]);
|
|
|
|
/* set the palette */
|
|
//set_current_palette(m_palette, false);
|
|
|
|
/* refresh the screen */
|
|
jmanager_refresh_screen();
|
|
}
|
|
|
|
int PalEdit::get1stColor()
|
|
{
|
|
return m_color[0];
|
|
}
|
|
|
|
int PalEdit::get2ndColor()
|
|
{
|
|
return m_color[1];
|
|
}
|
|
|
|
void PalEdit::getSelectedEntries(bool array[256])
|
|
{
|
|
memset(array, false, sizeof(bool)*256);
|
|
|
|
switch (m_range_type) {
|
|
|
|
case PALETTE_EDITOR_RANGE_NONE:
|
|
if (m_color[1] >= 0)
|
|
array[m_color[1]] = true;
|
|
break;
|
|
|
|
case PALETTE_EDITOR_RANGE_LINEAL: {
|
|
int c1 = MIN(m_color[0], m_color[1]);
|
|
int c2 = MAX(m_color[0], m_color[1]);
|
|
int c;
|
|
|
|
for (c=c1; c<=c2; c++)
|
|
array[c] = true;
|
|
break;
|
|
}
|
|
|
|
case PALETTE_EDITOR_RANGE_RECTANGULAR: {
|
|
int cols = m_columns;
|
|
int index1 = m_color[0];
|
|
int index2 = m_color[1];
|
|
int c, x, y, x1, y1, x2, y2;
|
|
|
|
/* swap */
|
|
if (index1 > index2) {
|
|
c = index1;
|
|
index1 = index2;
|
|
index2 = c;
|
|
}
|
|
|
|
x1 = index1 % cols;
|
|
y1 = index1 / cols;
|
|
x2 = index2 % cols;
|
|
y2 = index2 / cols;
|
|
|
|
if (x2 < x1) { c = x2; x2 = x1; x1 = c; }
|
|
if (y2 < y1) { c = y2; y2 = y1; y1 = c; }
|
|
|
|
for (y=y1; y<=y2; y++)
|
|
for (x=x1; x<=x2; x++)
|
|
array[y*cols + x] = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool PalEdit::msg_proc(JMessage msg)
|
|
{
|
|
switch (msg->type) {
|
|
|
|
case JM_REQSIZE:
|
|
request_size(&msg->reqsize.w, &msg->reqsize.h);
|
|
return true;
|
|
|
|
// case JM_KEYPRESSED:
|
|
// if (jwidget_has_focus(this)) {
|
|
// /* other keys */
|
|
// if ((m_color[1] >= 0) && (m_color[1] <= 255)) {
|
|
// switch (msg->key.scancode) {
|
|
// case KEY_LEFT: moveSelection(-1, 0); return true;
|
|
// case KEY_RIGHT: moveSelection(+1, 0); return true;
|
|
// case KEY_UP: moveSelection(0, -1); return true;
|
|
// case KEY_DOWN: moveSelection(0, +1); return true;
|
|
// }
|
|
// }
|
|
// }
|
|
// break;
|
|
|
|
case JM_DRAW: {
|
|
div_t d = div(256, m_columns);
|
|
int cols = m_columns;
|
|
int rows = d.quot + ((d.rem)? 1: 0);
|
|
int x1, y1, x2, y2;
|
|
int x, y, u, v;
|
|
int c, color;
|
|
BITMAP *bmp;
|
|
Palette* palette = get_current_palette();
|
|
|
|
bmp = create_bitmap(jrect_w(this->rc), jrect_h(this->rc));
|
|
clear_to_color(bmp, makecol(0 , 0, 0));
|
|
|
|
y = this->border_width.t;
|
|
c = 0;
|
|
|
|
for (v=0; v<rows; v++) {
|
|
x = this->border_width.l;
|
|
|
|
for (u=0; u<cols; u++) {
|
|
if (c >= palette->size())
|
|
break;
|
|
|
|
if (bitmap_color_depth(ji_screen) == 8)
|
|
color = c;
|
|
else
|
|
color = makecol_depth
|
|
(bitmap_color_depth(ji_screen),
|
|
_rgba_getr(palette->getEntry(c)),
|
|
_rgba_getg(palette->getEntry(c)),
|
|
_rgba_getb(palette->getEntry(c)));
|
|
|
|
rectfill(bmp, x, y, x+COLOR_SIZE-1, y+COLOR_SIZE-1, color);
|
|
|
|
x += COLOR_SIZE+this->child_spacing;
|
|
c++;
|
|
}
|
|
|
|
y += COLOR_SIZE+this->child_spacing;
|
|
}
|
|
|
|
/* draw the edges in the selected color */
|
|
if (m_color[0] >= 0) {
|
|
int index1 = m_color[0];
|
|
int index2 = m_color[1];
|
|
int bl = this->border_width.l;
|
|
int bt = this->border_width.t;
|
|
int cs = this->child_spacing;
|
|
int color = makecol (255, 255, 255);
|
|
|
|
/* swap */
|
|
if (index1 > index2) {
|
|
c = index1;
|
|
index1 = index2;
|
|
index2 = c;
|
|
}
|
|
|
|
/* selection position */
|
|
x1 = index1 % cols;
|
|
y1 = index1 / cols;
|
|
x2 = index2 % cols;
|
|
y2 = index2 / cols;
|
|
|
|
if (y2 < y1) { c = y2; y2 = y1; y1 = c; }
|
|
|
|
/* draw the rectangular gamma or just the cursor */
|
|
if (m_range_type != PALETTE_EDITOR_RANGE_LINEAL) {
|
|
if (x2 < x1) { c = x2; x2 = x1; x1 = c; }
|
|
|
|
rect(bmp,
|
|
bl + x1*(cs+COLOR_SIZE)-1,
|
|
bt + y1*(cs+COLOR_SIZE)-1,
|
|
bl + x2*(cs+COLOR_SIZE)+COLOR_SIZE,
|
|
bt + y2*(cs+COLOR_SIZE)+COLOR_SIZE, color);
|
|
}
|
|
/* draw the linear gamma */
|
|
else {
|
|
c = 0;
|
|
for (y=0; y<rows; y++) {
|
|
for (x=0; x<cols; x++) {
|
|
if ((c == index1) || ((x == 0) && (y > y1) && (y <= y2))) {
|
|
vline(bmp,
|
|
bl + x*(cs+COLOR_SIZE)-1,
|
|
bt + y*(cs+COLOR_SIZE)-1,
|
|
bt + y*(cs+COLOR_SIZE)+COLOR_SIZE, color);
|
|
}
|
|
|
|
if ((c == index2) || ((x == cols-1) && (y >= y1) && (y < y2))) {
|
|
vline(bmp,
|
|
bl + x*(cs+COLOR_SIZE)+COLOR_SIZE,
|
|
bt + y*(cs+COLOR_SIZE)-1,
|
|
bt + y*(cs+COLOR_SIZE)+COLOR_SIZE, color);
|
|
}
|
|
|
|
if (y == y1) {
|
|
if (x >= x1) {
|
|
if ((y < y2) || (x <= x2))
|
|
hline(bmp,
|
|
bl + x*(cs+COLOR_SIZE)-1,
|
|
bt + y*(cs+COLOR_SIZE)-1,
|
|
bl + x*(cs+COLOR_SIZE)+COLOR_SIZE, color);
|
|
}
|
|
else if (y < y2) {
|
|
if ((y+1 < y2) || (x <= x2))
|
|
hline(bmp,
|
|
bl + x*(cs+COLOR_SIZE)-1,
|
|
bt + y*(cs+COLOR_SIZE)+COLOR_SIZE,
|
|
bl + x*(cs+COLOR_SIZE)+COLOR_SIZE, color);
|
|
}
|
|
}
|
|
|
|
if (y == y2) {
|
|
if (x <= x2) {
|
|
if ((y > y1) || (x >= x1))
|
|
hline(bmp,
|
|
bl + x*(cs+COLOR_SIZE)-1,
|
|
bt + y*(cs+COLOR_SIZE)+COLOR_SIZE,
|
|
bl + x*(cs+COLOR_SIZE)+COLOR_SIZE, color);
|
|
}
|
|
else if (y > y1) {
|
|
if ((y-1 > y1) || (x >= x1))
|
|
hline(bmp,
|
|
bl + x*(cs+COLOR_SIZE)-1,
|
|
bt + y*(cs+COLOR_SIZE)-1,
|
|
bl + x*(cs+COLOR_SIZE)+COLOR_SIZE, color);
|
|
}
|
|
}
|
|
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
blit(bmp, ji_screen,
|
|
0, 0, this->rc->x1, this->rc->y1, bmp->w, bmp->h);
|
|
destroy_bitmap(bmp);
|
|
break;
|
|
}
|
|
|
|
case JM_BUTTONPRESSED:
|
|
captureMouse();
|
|
/* continue... */
|
|
|
|
case JM_MOTION:
|
|
if (hasCapture()) {
|
|
JRect cpos = jwidget_get_child_rect(this);
|
|
div_t d = div(256, m_columns);
|
|
int cols = m_columns;
|
|
int rows = d.quot + ((d.rem)? 1: 0);
|
|
int mouse_x, mouse_y;
|
|
int req_w, req_h;
|
|
int x, y, u, v;
|
|
int c;
|
|
Palette* palette = get_current_palette();
|
|
|
|
request_size(&req_w, &req_h);
|
|
|
|
mouse_x = MID(cpos->x1, msg->mouse.x,
|
|
cpos->x1+req_w-this->border_width.r-1);
|
|
mouse_y = MID(cpos->y1, msg->mouse.y,
|
|
cpos->y1+req_h-this->border_width.b-1);
|
|
|
|
y = cpos->y1;
|
|
c = 0;
|
|
|
|
for (v=0; v<rows; v++) {
|
|
x = cpos->x1;
|
|
|
|
for (u=0; u<cols; u++) {
|
|
if (c >= palette->size())
|
|
break;
|
|
|
|
if ((mouse_x >= x) && (mouse_x <= x+COLOR_SIZE) &&
|
|
(mouse_y >= y) && (mouse_y <= y+COLOR_SIZE) &&
|
|
(c != m_color[1])) {
|
|
if (msg->any.shifts & KB_SHIFT_FLAG)
|
|
selectRange(m_color[0], c, PALETTE_EDITOR_RANGE_LINEAL);
|
|
else if (msg->any.shifts & KB_CTRL_FLAG)
|
|
selectRange(m_color[0], c, PALETTE_EDITOR_RANGE_RECTANGULAR);
|
|
else
|
|
selectColor(c);
|
|
|
|
update_scroll(c);
|
|
|
|
jwidget_emit_signal(this, SIGNAL_PALETTE_EDITOR_CHANGE);
|
|
c = 256;
|
|
break;
|
|
}
|
|
|
|
x += COLOR_SIZE+this->child_spacing;
|
|
c++;
|
|
}
|
|
|
|
y += COLOR_SIZE+this->child_spacing;
|
|
}
|
|
|
|
jrect_free(cpos);
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case JM_BUTTONRELEASED:
|
|
releaseMouse();
|
|
return true;
|
|
}
|
|
|
|
return Widget::msg_proc(msg);
|
|
}
|
|
|
|
void PalEdit::request_size(int* w, int* h)
|
|
{
|
|
div_t d = div(256, m_columns);
|
|
int cols = m_columns;
|
|
int rows = d.quot + ((d.rem)? 1: 0);
|
|
|
|
*w = this->border_width.l + this->border_width.r +
|
|
+ cols*COLOR_SIZE + (cols-1)*this->child_spacing;
|
|
|
|
*h = this->border_width.t + this->border_width.b +
|
|
+ rows*COLOR_SIZE + (rows-1)*this->child_spacing;
|
|
}
|
|
|
|
void PalEdit::update_scroll(int color)
|
|
{
|
|
Widget* view = jwidget_get_view(this);
|
|
if (view != NULL) {
|
|
JRect vp = jview_get_viewport_position(view);
|
|
int scroll_x, scroll_y;
|
|
int x, y, cols;
|
|
div_t d;
|
|
|
|
jview_get_scroll(view, &scroll_x, &scroll_y);
|
|
|
|
d = div(256, m_columns);
|
|
cols = m_columns;
|
|
|
|
y = (COLOR_SIZE+this->child_spacing) * (color / cols);
|
|
x = (COLOR_SIZE+this->child_spacing) * (color % cols);
|
|
|
|
if (scroll_x > x)
|
|
scroll_x = x;
|
|
else if (scroll_x+jrect_w(vp)-COLOR_SIZE-2 < x)
|
|
scroll_x = x-jrect_w(vp)+COLOR_SIZE+2;
|
|
|
|
if (scroll_y > y)
|
|
scroll_y = y;
|
|
else if (scroll_y+jrect_h(vp)-COLOR_SIZE-2 < y)
|
|
scroll_y = y-jrect_h(vp)+COLOR_SIZE+2;
|
|
|
|
jview_set_scroll(view, scroll_x, scroll_y);
|
|
|
|
jrect_free(vp);
|
|
}
|
|
}
|