aseprite/src/modules/editors.cpp

446 lines
11 KiB
C++

/* ASE - Allegro Sprite Editor
* Copyright (C) 2001-2011 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 <vector>
#include <algorithm>
#include "gui/jinete.h"
#include "sprite_wrappers.h"
#include "ui_context.h"
#include "app.h"
#include "modules/editors.h"
#include "modules/gui.h"
#include "modules/palettes.h"
#include "raster/image.h"
#include "raster/sprite.h"
#include "util/misc.h"
#include "widgets/editor.h"
#define FIXUP_TOP_WINDOW() \
app_get_top_window()->remap_window(); \
app_get_top_window()->dirty();
typedef std::vector<Editor*> EditorList;
Editor* current_editor = NULL;
Widget* box_editors = NULL;
static EditorList editors;
static int is_sprite_in_some_editor(Sprite *sprite);
static Sprite *get_more_reliable_sprite();
static JWidget find_next_editor(JWidget widget);
static int count_parents(JWidget widget);
int init_module_editors()
{
return 0;
}
void exit_module_editors()
{
editors.clear();
}
Editor* create_new_editor()
{
Editor* editor = new Editor();
editors.push_back(editor);
return editor;
}
/**
* Removes the specified editor from the "editors" list.
*
* It does not delete the editor.
*/
void remove_editor(Editor* editor)
{
EditorList::iterator it = std::find(editors.begin(), editors.end(), editor);
ASSERT(it != editors.end());
editors.erase(it);
}
void refresh_all_editors()
{
for (EditorList::iterator it = editors.begin(); it != editors.end(); ++it) {
jwidget_dirty(*it);
}
}
void update_editors_with_sprite(const Sprite* sprite)
{
for (EditorList::iterator it = editors.begin(); it != editors.end(); ++it) {
Editor* editor = *it;
if (sprite == editor->getSprite())
editor->editor_update();
}
}
void editors_draw_sprite(const Sprite* sprite, int x1, int y1, int x2, int y2)
{
for (EditorList::iterator it = editors.begin(); it != editors.end(); ++it) {
Editor* editor = *it;
if (sprite == editor->getSprite())
editor->editor_draw_sprite_safe(x1, y1, x2, y2);
}
}
/* TODO improve this (with JRegion or something, and without
recursivity) */
void editors_draw_sprite_tiled(const Sprite* sprite, int x1, int y1, int x2, int y2)
{
int cx1, cy1, cx2, cy2; /* cel rectangle */
int lx1, ly1, lx2, ly2; /* limited rectangle to the cel rectangle */
#ifdef TILED_IN_LAYER
Image *image = GetImage2(sprite, &cx1, &cy1, NULL);
cx2 = cx1+image->w-1;
cy2 = cy1+image->h-1;
#else
cx1 = 0;
cy1 = 0;
cx2 = cx1+sprite->getWidth()-1;
cy2 = cy1+sprite->getHeight()-1;
#endif
lx1 = MAX(x1, cx1);
ly1 = MAX(y1, cy1);
lx2 = MIN(x2, cx2);
ly2 = MIN(y2, cy2);
/* draw the rectangles inside the editor */
editors_draw_sprite(sprite, lx1, ly1, lx2, ly2);
/* left */
if (x1 < cx1 && lx2 < cx2) {
editors_draw_sprite_tiled(sprite,
MAX(lx2+1, cx2+1+(x1-cx1)), y1,
cx2, y2);
}
/* top */
if (y1 < cy1 && ly2 < cy2) {
editors_draw_sprite_tiled(sprite,
x1, MAX(ly2+1, cy2+1+(y1-cx1)),
x2, cy2);
}
/* right */
if (x2 >= cx2+1 && lx1 > cx1) {
#ifdef TILED_IN_LAYER
editors_draw_sprite_tiled(sprite,
cx1, y1,
MIN(lx1-1, x2-image->w), y2);
#else
editors_draw_sprite_tiled(sprite,
cx1, y1,
MIN(lx1-1, x2-sprite->getWidth()), y2);
#endif
}
/* bottom */
if (y2 >= cy2+1 && ly1 > cy1) {
#if TILED_IN_LAYER
editors_draw_sprite_tiled(sprite,
x1, cy1,
x2, MIN(ly1-1, y2-image->h));
#else
editors_draw_sprite_tiled(sprite,
x1, cy1,
x2, MIN(ly1-1, y2-sprite->getHeight()));
#endif
}
}
void editors_hide_sprite(const Sprite* sprite)
{
UIContext* context = UIContext::instance();
bool refresh = (context->getCurrentSprite() == sprite) ? true: false;
for (EditorList::iterator it = editors.begin(); it != editors.end(); ++it) {
Editor* editor = *it;
if (sprite == editor->getSprite())
editor->editor_set_sprite(get_more_reliable_sprite());
}
if (refresh) {
Sprite* sprite = current_editor->getSprite();
context->setCurrentSprite(sprite);
app_refresh_screen(sprite);
}
}
void set_current_editor(Editor* editor)
{
if (current_editor != editor) {
if (current_editor)
jwidget_dirty(jwidget_get_view(current_editor));
current_editor = editor;
jwidget_dirty(jwidget_get_view(current_editor));
UIContext* context = UIContext::instance();
Sprite* sprite = current_editor->getSprite();
context->setCurrentSprite(sprite);
app_refresh_screen(sprite);
app_realloc_sprite_list();
}
}
void set_sprite_in_current_editor(Sprite *sprite)
{
if (current_editor) {
UIContext* context = UIContext::instance();
context->setCurrentSprite(sprite);
if (sprite != NULL)
context->sendSpriteToTop(sprite);
current_editor->editor_set_sprite(sprite);
jwidget_dirty(jwidget_get_view(current_editor));
app_refresh_screen(sprite);
app_realloc_sprite_list();
}
}
void set_sprite_in_more_reliable_editor(Sprite* sprite)
{
/* the current editor */
Editor* best = current_editor;
/* search for any empty editor */
if (best->getSprite()) {
for (EditorList::iterator it = editors.begin(); it != editors.end(); ++it) {
Editor* editor = *it;
if (!editor->getSprite()) {
best = editor;
break;
}
}
}
set_current_editor(best);
set_sprite_in_current_editor(sprite);
}
void split_editor(Editor* editor, int align)
{
if (count_parents(editor) > 10) {
jalert("Error<<You cannot split this editor more||&Close");
return;
}
JWidget view = jwidget_get_view(editor);
JWidget parent_box = jwidget_get_parent(view); /* box or panel */
/* create a new box to contain both editors, and a new view to put
the new editor */
JWidget new_panel = jpanel_new(align);
JWidget new_view = editor_view_new();
Editor* new_editor = create_new_editor();
/* insert the "new_box" in the same location that the view */
jwidget_replace_child(parent_box, view, new_panel);
/* append the new editor */
jview_attach(new_view, new_editor);
/* set the sprite for the new editor */
new_editor->editor_set_sprite(editor->getSprite());
new_editor->editor_set_zoom(editor->editor_get_zoom());
/* expansive widgets */
jwidget_expansive(new_panel, true);
jwidget_expansive(new_view, true);
/* append both views to the "new_panel" */
jwidget_add_child(new_panel, view);
jwidget_add_child(new_panel, new_view);
/* same position */
{
int scroll_x, scroll_y;
jview_get_scroll(view, &scroll_x, &scroll_y);
jview_set_scroll(new_view, scroll_x, scroll_y);
jrect_copy(new_view->rc, view->rc);
jrect_copy(jview_get_viewport(new_view)->rc,
jview_get_viewport(view)->rc);
jrect_copy(new_editor->rc, editor->rc);
new_editor->editor_set_offset_x(editor->editor_get_offset_x());
new_editor->editor_set_offset_y(editor->editor_get_offset_y());
}
/* fixup window */
FIXUP_TOP_WINDOW();
/* update both editors */
editor->editor_update();
new_editor->editor_update();
}
void close_editor(Editor* editor)
{
JWidget view = jwidget_get_view(editor);
JWidget parent_box = jwidget_get_parent(view); /* box or panel */
JWidget other_widget;
/* you can't remove all editors */
if (editors.size() == 1)
return;
/* deselect the editor */
if (editor == current_editor)
current_editor = 0;
/* remove this editor */
jwidget_remove_child(parent_box, view);
jwidget_free(view);
/* fixup the parent */
other_widget = reinterpret_cast<JWidget>(jlist_first_data(parent_box->children));
jwidget_remove_child(parent_box, other_widget);
jwidget_replace_child(jwidget_get_parent(parent_box),
parent_box, other_widget);
jwidget_free(parent_box);
/* find next editor to select */
if (!current_editor) {
JWidget next_editor = find_next_editor(other_widget);
if (next_editor) {
ASSERT(next_editor->type == editor_type());
set_current_editor(static_cast<Editor*>(next_editor));
}
}
/* fixup window */
FIXUP_TOP_WINDOW();
/* update all editors */
for (EditorList::iterator it = editors.begin(); it != editors.end(); ++it) {
Editor* editor = *it;
editor->editor_update();
}
}
void make_unique_editor(Editor* editor)
{
JWidget view = jwidget_get_view(editor);
JLink link, next;
JWidget child;
/* it's the unique editor */
if (editors.size() == 1)
return;
/* remove the editor-view of its parent */
jwidget_remove_child(jwidget_get_parent(view), view);
/* remove all children of main_editor_box */
JI_LIST_FOR_EACH_SAFE(box_editors->children, link, next) {
child = (JWidget)link->data;
jwidget_remove_child(box_editors, child);
delete child; // widget
}
/* append the editor to main box */
jwidget_add_child(box_editors, view);
/* new current editor */
set_current_editor(editor);
/* fixup window */
FIXUP_TOP_WINDOW();
/* update new editor */
editor->editor_update();
}
static int is_sprite_in_some_editor(Sprite* sprite)
{
for (EditorList::iterator it = editors.begin(); it != editors.end(); ++it) {
Editor* editor = *it;
if (sprite == editor->getSprite())
return true;
}
return false;
}
/**
* Returns the next sprite that should be show if we close the current
* one.
*/
static Sprite* get_more_reliable_sprite()
{
UIContext* context = UIContext::instance();
const SpriteList& list = context->getSpriteList();
for (SpriteList::const_iterator
it = list.begin(); it != list.end(); ++it) {
Sprite* sprite = *it;
if (!(is_sprite_in_some_editor(sprite)))
return sprite;
}
return NULL;
}
static JWidget find_next_editor(JWidget widget)
{
JWidget editor = NULL;
JLink link;
if (widget->type == JI_VIEW)
editor = reinterpret_cast<JWidget>(jlist_first_data(jview_get_viewport(widget)->children));
else {
JI_LIST_FOR_EACH(widget->children, link)
if ((editor = find_next_editor(reinterpret_cast<JWidget>(link->data))))
break;
}
return editor;
}
static int count_parents(JWidget widget)
{
int count = 0;
while ((widget = jwidget_get_parent(widget)))
count++;
return count;
}