aseprite/src/app/ui/palette_view.cpp

395 lines
9.5 KiB
C++
Raw Normal View History

/* Aseprite
2013-01-27 23:13:13 +08:00
* Copyright (C) 2001-2013 David Capello
2007-09-19 07:57:02 +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
*/
#ifdef HAVE_CONFIG_H
2007-09-19 07:57:02 +08:00
#include "config.h"
#endif
2007-09-19 07:57:02 +08:00
#include <allegro.h>
#include <stdlib.h>
#include <string.h>
#include "app/app.h"
#include "app/color.h"
#include "app/modules/gui.h"
#include "app/modules/palettes.h"
#include "app/ui/palette_view.h"
#include "app/ui/status_bar.h"
#include "gfx/point.h"
2007-09-19 07:57:02 +08:00
#include "raster/blend.h"
#include "raster/image.h"
#include "raster/palette.h"
#include "ui/graphics.h"
2012-06-18 09:49:58 +08:00
#include "ui/manager.h"
#include "ui/message.h"
#include "ui/paint_event.h"
2012-09-27 05:34:52 +08:00
#include "ui/preferred_size_event.h"
2012-06-18 09:49:58 +08:00
#include "ui/system.h"
#include "ui/theme.h"
#include "ui/view.h"
#include "ui/widget.h"
namespace app {
2007-09-19 07:57:02 +08:00
using namespace ui;
WidgetType palette_view_type()
2007-09-19 07:57:02 +08:00
{
static WidgetType type = kGenericWidget;
if (type == kGenericWidget)
type = register_widget_type();
2007-09-19 07:57:02 +08:00
return type;
}
PaletteView::PaletteView(bool editable)
: Widget(palette_view_type())
, m_currentEntry(-1)
, m_rangeAnchor(-1)
2012-05-03 10:09:34 +08:00
, m_selectedEntries(Palette::MaxColors, false)
, m_isUpdatingColumns(false)
{
setFocusStop(true);
setDoubleBuffered(true);
m_editable = editable;
m_columns = 16;
m_boxsize = 6;
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();
}
void PaletteView::setColumns(int columns)
{
int old_columns = m_columns;
2007-09-19 07:57:02 +08:00
2012-05-03 10:09:34 +08:00
ASSERT(columns >= 1 && columns <= Palette::MaxColors);
m_columns = columns;
if (m_columns != old_columns) {
View* view = View::getView(this);
2007-09-19 07:57:02 +08:00
if (view)
view->updateView();
2007-09-19 07:57:02 +08:00
invalidate();
2007-09-19 07:57:02 +08:00
}
}
void PaletteView::setBoxSize(int boxsize)
2007-09-19 07:57:02 +08:00
{
m_boxsize = boxsize;
}
void PaletteView::clearSelection()
{
std::fill(m_selectedEntries.begin(),
m_selectedEntries.end(), false);
}
void PaletteView::selectColor(int index)
{
2012-05-03 10:09:34 +08:00
ASSERT(index >= 0 && index < Palette::MaxColors);
if (m_currentEntry != index || !m_selectedEntries[index]) {
m_currentEntry = index;
m_rangeAnchor = index;
m_selectedEntries[index] = true;
2007-09-19 07:57:02 +08:00
update_scroll(m_currentEntry);
invalidate();
2007-09-19 07:57:02 +08:00
}
}
void PaletteView::selectRange(int index1, int index2)
2007-09-19 07:57:02 +08:00
{
m_rangeAnchor = index1;
m_currentEntry = index2;
2007-09-19 07:57:02 +08:00
std::fill(m_selectedEntries.begin()+std::min(index1, index2),
m_selectedEntries.begin()+std::max(index1, index2)+1, true);
2007-09-19 07:57:02 +08:00
update_scroll(index2);
invalidate();
2007-09-19 07:57:02 +08:00
}
int PaletteView::getSelectedEntry() const
2007-09-19 07:57:02 +08:00
{
return m_currentEntry;
2007-09-19 07:57:02 +08:00
}
bool PaletteView::getSelectedRange(int& index1, int& index2) const
2007-09-19 07:57:02 +08:00
{
int i, i2, j;
2007-09-19 07:57:02 +08:00
// Find the first selected entry
for (i=0; i<(int)m_selectedEntries.size(); ++i)
if (m_selectedEntries[i])
2007-09-19 07:57:02 +08:00
break;
// Find the first unselected entry after i
for (i2=i+1; i2<(int)m_selectedEntries.size(); ++i2)
if (!m_selectedEntries[i2])
2007-09-19 07:57:02 +08:00
break;
// Find the last selected entry
for (j=m_selectedEntries.size()-1; j>=0; --j)
if (m_selectedEntries[j])
break;
if (j-i+1 == i2-i) {
index1 = i;
index2 = j;
return true;
}
else
return false;
}
void PaletteView::getSelectedEntries(SelectedEntries& entries) const
{
entries = m_selectedEntries;
2007-09-19 07:57:02 +08:00
}
app::Color PaletteView::getColorByPosition(int target_x, int target_y)
{
Palette* palette = get_current_palette();
gfx::Rect cpos = getChildrenBounds();
2012-05-03 10:09:34 +08:00
div_t d = div(Palette::MaxColors, m_columns);
int cols = m_columns;
int rows = d.quot + ((d.rem)? 1: 0);
int req_w, req_h;
int x, y, u, v;
int c;
request_size(&req_w, &req_h);
y = cpos.y;
c = 0;
for (v=0; v<rows; v++) {
x = cpos.x;
for (u=0; u<cols; u++) {
if (c >= palette->size())
break;
if ((target_x >= x) && (target_x <= x+m_boxsize) &&
(target_y >= y) && (target_y <= y+m_boxsize))
return app::Color::fromIndex(c);
x += m_boxsize+this->child_spacing;
c++;
}
y += m_boxsize+this->child_spacing;
}
return app::Color::fromMask();
}
bool PaletteView::onProcessMessage(Message* msg)
2007-09-19 07:57:02 +08:00
{
switch (msg->type()) {
2007-09-19 07:57:02 +08:00
case kMouseDownMessage:
captureMouse();
2007-09-19 07:57:02 +08:00
/* continue... */
case kMouseMoveMessage: {
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
gfx::Rect cpos = getChildrenBounds();
2007-09-19 07:57:02 +08:00
int req_w, req_h;
request_size(&req_w, &req_h);
int mouse_x = MID(cpos.x, mouseMsg->position().x, cpos.x+req_w-this->border_width.r-1);
int mouse_y = MID(cpos.y, mouseMsg->position().y, cpos.y+req_h-this->border_width.b-1);
app::Color color = getColorByPosition(mouse_x, mouse_y);
if (color.getType() == app::Color::IndexType) {
int idx = color.getIndex();
StatusBar::instance()->showColor(0, "", color, 255);
if (hasCapture() && idx != m_currentEntry) {
if (!msg->ctrlPressed())
clearSelection();
if (msg->shiftPressed())
selectRange(m_rangeAnchor, idx);
else
selectColor(idx);
2007-09-19 07:57:02 +08:00
// Emit signal
IndexChange(idx);
}
}
2007-09-19 07:57:02 +08:00
if (hasCapture())
return true;
2007-09-19 07:57:02 +08:00
break;
}
2007-09-19 07:57:02 +08:00
case kMouseUpMessage:
releaseMouse();
return true;
case kMouseWheelMessage: {
View* view = View::getView(this);
if (view) {
gfx::Point scroll = view->getViewScroll();
scroll.y += (jmouse_z(1)-jmouse_z(0)) * 3 * m_boxsize;
view->setViewScroll(scroll);
}
break;
}
case kMouseLeaveMessage:
StatusBar::instance()->clearText();
break;
2007-09-19 07:57:02 +08:00
}
return Widget::onProcessMessage(msg);
2007-09-19 07:57:02 +08:00
}
void PaletteView::onPaint(ui::PaintEvent& ev)
{
ui::Graphics* g = ev.getGraphics();
gfx::Rect bounds = getClientBounds();
div_t d = div(Palette::MaxColors, m_columns);
int cols = m_columns;
int rows = d.quot + ((d.rem)? 1: 0);
int x, y, u, v;
int c, color;
Palette* palette = get_current_palette();
int bordercolor = makecol(255, 255, 255);
g->fillRect(ui::rgba(0 , 0, 0), bounds);
y = bounds.y + this->border_width.t;
c = 0;
for (v=0; v<rows; v++) {
x = bounds.x + this->border_width.l;
for (u=0; u<cols; u++) {
if (c >= palette->size())
break;
color = ui::rgba(
rgba_getr(palette->getEntry(c)),
rgba_getg(palette->getEntry(c)),
rgba_getb(palette->getEntry(c)));
g->fillRect(color, gfx::Rect(x, y, m_boxsize, m_boxsize));
if (m_selectedEntries[c]) {
const int max = Palette::MaxColors;
bool top = (c >= m_columns && c-m_columns >= 0 ? m_selectedEntries[c-m_columns]: false);
bool bottom = (c < max-m_columns && c+m_columns < max ? m_selectedEntries[c+m_columns]: false);
bool left = ((c%m_columns)>0 && c-1 >= 0 ? m_selectedEntries[c-1]: false);
bool right = ((c%m_columns)<m_columns-1 && c+1 < max ? m_selectedEntries[c+1]: false);
if (!top ) g->drawHLine(bordercolor, x-1, y-1, m_boxsize+2);
if (!bottom) g->drawHLine(bordercolor, x-1, y+m_boxsize, m_boxsize+2);
if (!left ) g->drawVLine(bordercolor, x-1, y-1, m_boxsize+2);
if (!right ) g->drawVLine(bordercolor, x+m_boxsize, y-1, m_boxsize+2);
}
x += m_boxsize+this->child_spacing;
c++;
}
y += m_boxsize+this->child_spacing;
}
}
void PaletteView::onResize(ui::ResizeEvent& ev)
{
if (!m_isUpdatingColumns) {
m_isUpdatingColumns = true;
View* view = View::getView(this);
if (view) {
int columns =
(view->getViewportBounds().w-this->child_spacing*2)
/ (m_boxsize+this->child_spacing);
setColumns(MID(1, columns, Palette::MaxColors));
}
m_isUpdatingColumns = false;
}
Widget::onResize(ev);
}
2012-09-27 05:34:52 +08:00
void PaletteView::onPreferredSize(ui::PreferredSizeEvent& ev)
{
gfx::Size sz;
request_size(&sz.w, &sz.h);
ev.setPreferredSize(sz);
}
void PaletteView::request_size(int* w, int* h)
2007-09-19 07:57:02 +08:00
{
2012-05-03 10:09:34 +08:00
div_t d = div(Palette::MaxColors, m_columns);
int cols = m_columns;
2007-09-19 07:57:02 +08:00
int rows = d.quot + ((d.rem)? 1: 0);
*w = this->border_width.l + this->border_width.r +
+ cols*m_boxsize + (cols-1)*this->child_spacing;
2007-09-19 07:57:02 +08:00
*h = this->border_width.t + this->border_width.b +
+ rows*m_boxsize + (rows-1)*this->child_spacing;
2007-09-19 07:57:02 +08:00
}
void PaletteView::update_scroll(int color)
2007-09-19 07:57:02 +08:00
{
View* view = View::getView(this);
if (!view)
return;
2007-09-19 07:57:02 +08:00
gfx::Rect vp = view->getViewportBounds();
gfx::Point scroll;
int x, y, cols;
div_t d;
2007-09-19 07:57:02 +08:00
scroll = view->getViewScroll();
2007-09-19 07:57:02 +08:00
2012-05-03 10:09:34 +08:00
d = div(Palette::MaxColors, m_columns);
cols = m_columns;
2007-09-19 07:57:02 +08:00
y = (m_boxsize+this->child_spacing) * (color / cols);
x = (m_boxsize+this->child_spacing) * (color % cols);
2007-09-19 07:57:02 +08:00
if (scroll.x > x)
scroll.x = x;
else if (scroll.x+vp.w-m_boxsize-2 < x)
scroll.x = x-vp.w+m_boxsize+2;
2007-09-19 07:57:02 +08:00
if (scroll.y > y)
scroll.y = y;
else if (scroll.y+vp.h-m_boxsize-2 < y)
scroll.y = y-vp.h+m_boxsize+2;
2007-09-19 07:57:02 +08:00
view->setViewScroll(scroll);
2007-09-19 07:57:02 +08:00
}
} // namespace app