mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-28 00:35:30 +00:00
- Added Job class.
- Added SpriteSizeJob class. - Added ScopedLock class. - Fixed some bugs.
This commit is contained in:
parent
dd003a8f33
commit
8f92f78702
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
||||
2009-05-31 David A. Capello <davidcapello@gmail.com>
|
||||
|
||||
* src/file/file.cpp (fop_free): Fixed a mutex-handle leak.
|
||||
|
||||
* src/raster/undo.cpp (update_undo): Fixed a bug where
|
||||
the current open-undo-chunk were discarded if the undo-limit
|
||||
were reached.
|
||||
|
||||
* src/core/job.cpp: Added Job class to do background jobs more easily.
|
||||
|
||||
2009-05-30 David A. Capello <davidcapello@gmail.com>
|
||||
|
||||
* src/raster/image_impl.h (ImageImpl): Changed the implementation of
|
||||
|
17
TODO.txt
17
TODO.txt
@ -2,6 +2,7 @@ High priority work
|
||||
------------------
|
||||
|
||||
- search for TODO;
|
||||
- fix bilinear: when getpixel have alpha = 0 get a neighbor color.
|
||||
- Ctrl+X / Ctrl+C / Ctrl+V should Cut/Copy/Paste in jentries.
|
||||
- fix problems with tiled mode XY in drawing corners (I cannot
|
||||
reproduce the exact scenario).
|
||||
@ -22,13 +23,7 @@ High priority work
|
||||
- add two DrawClick2:
|
||||
- DrawClick2FreeHand
|
||||
- DrawClick2Shape
|
||||
- remove the jfilesel.c & jquickmenu.c
|
||||
- see the new Allegro's load_font
|
||||
- fix Jinete examples:
|
||||
+ 05fsel
|
||||
+ 09lists
|
||||
+ 20combo
|
||||
+ 21manage
|
||||
+ finished the support for ICO files.
|
||||
- add "size" to GUI font (for TTF fonts);
|
||||
- layer movement between sets in animation-editor;
|
||||
@ -45,10 +40,6 @@ High priority work
|
||||
Wish-list
|
||||
---------
|
||||
|
||||
- ideas from freelunchdesign.com forum:
|
||||
Geti: angle locking, like, so the line tool can be
|
||||
snapped to 90, 45, 30 & 12.5 degree increments.
|
||||
would just be handy for isos.
|
||||
- dacap wish-list:
|
||||
+ added starred file-items in the file-selector.
|
||||
+ add AseContext structure to handle the current state of the
|
||||
@ -90,3 +81,9 @@ Low priority stuff
|
||||
various sizes have errors).
|
||||
- optimize the *_to_allegro image methods (I profiled ASE, and these
|
||||
are the more slow routines in all the program);
|
||||
- remove the jfilesel.c & jquickmenu.c
|
||||
- fix Jinete examples:
|
||||
+ 05fsel
|
||||
+ 09lists
|
||||
+ 20combo
|
||||
+ 21manage
|
||||
|
@ -86,6 +86,7 @@ COMMON_SOURCES = \
|
||||
src/core/dirs.cpp \
|
||||
src/core/drop_files.cpp \
|
||||
src/core/file_system.cpp \
|
||||
src/core/job.cpp \
|
||||
src/core/modules.cpp \
|
||||
src/dialogs/aniedit.cpp \
|
||||
src/dialogs/canvasze.cpp \
|
||||
|
@ -18,15 +18,11 @@ endif
|
||||
CFLAGS =
|
||||
LFLAGS = -mwindows -lshlwapi
|
||||
ifdef DEBUGMODE
|
||||
LFLAGS_LAST = -lalld
|
||||
LFLAGS_LAST = -lalld -lpsapi
|
||||
else
|
||||
LFLAGS_LAST = -lalleg
|
||||
endif
|
||||
|
||||
ifdef MEMLEAK
|
||||
LFLAGS += -lpsapi
|
||||
endif
|
||||
|
||||
WITHICON = 1
|
||||
|
||||
######################################################################
|
||||
|
@ -39,7 +39,7 @@ LIBS = User32.lib Shell32.lib ComCtl32.lib ComDlg32.lib Gdi32.lib \
|
||||
ifdef DEBUGMODE
|
||||
CFLAGS += -Zi -MDd -DDEBUGMODE
|
||||
LFLAGS += -DEBUG
|
||||
LIBS += Alld.lib
|
||||
LIBS += Alld.lib psapi.lib
|
||||
else
|
||||
CFLAGS += -O2 -MD -DNDEBUG
|
||||
LFLAGS += -RELEASE
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <allegro.h>
|
||||
#if defined ALLEGRO_WINDOWS && defined MEMLEAK
|
||||
#if defined ALLEGRO_WINDOWS && defined DEBUGMODE
|
||||
#include <winalleg.h>
|
||||
#include <psapi.h>
|
||||
#endif
|
||||
@ -29,6 +29,7 @@
|
||||
|
||||
#include "commands/commands.h"
|
||||
#include "core/app.h"
|
||||
#include "widgets/statebar.h"
|
||||
|
||||
static void cmd_refresh_execute(const char *argument)
|
||||
{
|
||||
@ -39,14 +40,15 @@ static void cmd_refresh_execute(const char *argument)
|
||||
app_refresh_screen();
|
||||
|
||||
/* print memory information */
|
||||
#if defined ALLEGRO_WINDOWS && defined MEMLEAK
|
||||
#if defined ALLEGRO_WINDOWS && defined DEBUGMODE
|
||||
{
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
|
||||
printf("----\n");
|
||||
printf("current memory: %.16g KB (%lu)\n", pmc.WorkingSetSize / 1024.0, pmc.WorkingSetSize);
|
||||
printf("peak of memory: %.16g KB (%lu)\n", pmc.PeakWorkingSetSize / 1024.0, pmc.PeakWorkingSetSize);
|
||||
fflush(stdout);
|
||||
statusbar_show_tip(app_get_statusbar(), 1000,
|
||||
"Current memory: %.16g KB (%lu)\n"
|
||||
"Peak of memory: %.16g KB (%lu)",
|
||||
pmc.WorkingSetSize / 1024.0, pmc.WorkingSetSize,
|
||||
pmc.PeakWorkingSetSize / 1024.0, pmc.PeakWorkingSetSize);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "jinete/jinete.h"
|
||||
|
||||
#include "core/cfg.h"
|
||||
#include "core/job.h"
|
||||
#include "commands/commands.h"
|
||||
#include "modules/gui.h"
|
||||
#include "modules/palettes.h"
|
||||
@ -35,6 +36,84 @@
|
||||
|
||||
#define PERC_FORMAT "%.1f%%"
|
||||
|
||||
class SpriteSizeJob : public Job
|
||||
{
|
||||
Sprite* m_sprite;
|
||||
int m_new_width;
|
||||
int m_new_height;
|
||||
ResizeMethod m_resize_method;
|
||||
|
||||
public:
|
||||
|
||||
SpriteSizeJob(Sprite* sprite, int new_width, int new_height, ResizeMethod resize_method)
|
||||
{
|
||||
m_sprite = sprite;
|
||||
m_new_width = new_width;
|
||||
m_new_height = new_height;
|
||||
m_resize_method = resize_method;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* [working thread]
|
||||
*/
|
||||
virtual void on_job()
|
||||
{
|
||||
Undoable undoable(m_sprite, "Sprite Size");
|
||||
|
||||
// get all sprite cels
|
||||
JList cels = jlist_new();
|
||||
sprite_get_cels(m_sprite, cels);
|
||||
|
||||
// for each cel...
|
||||
JLink link;
|
||||
JI_LIST_FOR_EACH(cels, link) {
|
||||
Cel* cel = (Cel*)link->data;
|
||||
|
||||
// change it location
|
||||
undoable.set_cel_position(cel,
|
||||
cel->x * m_new_width / m_sprite->w,
|
||||
cel->y * m_new_height / m_sprite->h);
|
||||
}
|
||||
jlist_free(cels);
|
||||
|
||||
// for each stock's image
|
||||
for (int i=0; i<m_sprite->stock->nimage; ++i) {
|
||||
Image* image = stock_get_image(m_sprite->stock, i);
|
||||
if (!image)
|
||||
continue;
|
||||
|
||||
// resize the image
|
||||
int w = image->w * m_new_width / m_sprite->w;
|
||||
int h = image->h * m_new_height / m_sprite->h;
|
||||
Image* new_image = image_new(image->imgtype, MAX(1, w), MAX(1, h));
|
||||
|
||||
image_resize(image, new_image,
|
||||
m_resize_method,
|
||||
get_current_palette(),
|
||||
orig_rgb_map);
|
||||
|
||||
undoable.replace_stock_image(i, new_image);
|
||||
|
||||
job_progress((float)i / m_sprite->stock->nimage);
|
||||
|
||||
// cancel all the operation?
|
||||
if (is_canceled())
|
||||
return; // Undoable destructor will undo all operations
|
||||
}
|
||||
|
||||
// resize sprite
|
||||
undoable.set_sprite_size(m_new_width, m_new_height);
|
||||
|
||||
// TODO resize mask
|
||||
|
||||
// commit changes
|
||||
undoable.commit();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static bool lock_ratio_change_hook(JWidget widget, void *data);
|
||||
static bool width_px_change_hook(JWidget widget, void *data);
|
||||
static bool height_px_change_hook(JWidget widget, void *data);
|
||||
@ -92,55 +171,16 @@ static void cmd_sprite_size_execute(const char *argument)
|
||||
if (jwindow_get_killer(window) == ok) {
|
||||
int new_width = width_px->text_int();
|
||||
int new_height = height_px->text_int();
|
||||
ResizeMethod resize_method =
|
||||
(ResizeMethod)jcombobox_get_selected_index(method);
|
||||
|
||||
set_config_int("SpriteSize", "Method", resize_method);
|
||||
|
||||
{
|
||||
Undoable undoable(sprite, "Sprite Size");
|
||||
ResizeMethod resize_method =
|
||||
(ResizeMethod)jcombobox_get_selected_index(method);
|
||||
|
||||
set_config_int("SpriteSize", "Method", resize_method);
|
||||
|
||||
// get all sprite cels
|
||||
JList cels = jlist_new();
|
||||
sprite_get_cels(sprite, cels);
|
||||
|
||||
// for each cel...
|
||||
JLink link;
|
||||
JI_LIST_FOR_EACH(cels, link) {
|
||||
Cel* cel = (Cel*)link->data;
|
||||
|
||||
// change it location
|
||||
undoable.set_cel_position(cel,
|
||||
cel->x * new_width / sprite->w,
|
||||
cel->y * new_height / sprite->h);
|
||||
}
|
||||
jlist_free(cels);
|
||||
|
||||
// for each stock's image
|
||||
for (int i=0; i<sprite->stock->nimage; ++i) {
|
||||
Image* image = stock_get_image(sprite->stock, i);
|
||||
if (!image)
|
||||
continue;
|
||||
|
||||
// resize the image
|
||||
int w = image->w * new_width / sprite->w;
|
||||
int h = image->h * new_height / sprite->h;
|
||||
Image* new_image = image_new(image->imgtype, MAX(1, w), MAX(1, h));
|
||||
|
||||
image_resize(image, new_image,
|
||||
resize_method,
|
||||
get_current_palette(),
|
||||
orig_rgb_map);
|
||||
|
||||
undoable.replace_stock_image(i, new_image);
|
||||
}
|
||||
|
||||
// resize sprite
|
||||
undoable.set_sprite_size(new_width, new_height);
|
||||
|
||||
// TODO resize mask
|
||||
undoable.commit();
|
||||
SpriteSizeJob job(sprite, new_width, new_height, resize_method);
|
||||
job.do_job();
|
||||
}
|
||||
|
||||
sprite_generate_mask_boundaries(sprite);
|
||||
update_screen_for_sprite(sprite);
|
||||
}
|
||||
|
183
src/core/job.cpp
Normal file
183
src/core/job.cpp
Normal file
@ -0,0 +1,183 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2009 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 "jinete/jalert.h"
|
||||
#include "jinete/jmutex.h"
|
||||
#include "jinete/jthread.h"
|
||||
#include "jinete/jwidget.h"
|
||||
#include "jinete/jwindow.h"
|
||||
|
||||
#include "core/app.h"
|
||||
#include "core/job.h"
|
||||
#include "modules/gui.h"
|
||||
#include "widgets/statebar.h"
|
||||
|
||||
Job::Job()
|
||||
{
|
||||
m_mutex = NULL;
|
||||
m_thread = NULL;
|
||||
m_progress = NULL;
|
||||
m_monitor = NULL;
|
||||
m_alert_window = NULL;
|
||||
m_last_progress = 0.0f;
|
||||
m_done_flag = false;
|
||||
m_canceled_flag = false;
|
||||
|
||||
m_mutex = jmutex_new();
|
||||
m_progress = progress_new(app_get_statusbar());
|
||||
m_monitor = add_gui_monitor(&Job::monitor_proc,
|
||||
&Job::monitor_free,
|
||||
(void*)this);
|
||||
m_alert_window = jalert_new(PACKAGE "<<Working...||&Cancel");
|
||||
}
|
||||
|
||||
Job::~Job()
|
||||
{
|
||||
// The job was canceled by the user?
|
||||
{
|
||||
ScopedLock hold(m_mutex);
|
||||
if (!m_done_flag)
|
||||
m_canceled_flag = true;
|
||||
}
|
||||
|
||||
if (m_monitor) {
|
||||
remove_gui_monitor(m_monitor);
|
||||
m_monitor = NULL;
|
||||
}
|
||||
|
||||
if (m_thread)
|
||||
jthread_join(m_thread);
|
||||
|
||||
if (m_progress)
|
||||
progress_free(m_progress);
|
||||
|
||||
if (m_mutex)
|
||||
jmutex_free(m_mutex);
|
||||
|
||||
if (m_alert_window)
|
||||
jwidget_free(m_alert_window);
|
||||
}
|
||||
|
||||
void Job::do_job()
|
||||
{
|
||||
m_thread = jthread_new(&Job::thread_proc, (void*)this);
|
||||
jwindow_open_fg(m_alert_window);
|
||||
}
|
||||
|
||||
void Job::job_progress(float f)
|
||||
{
|
||||
ScopedLock hold(m_mutex);
|
||||
m_last_progress = f;
|
||||
}
|
||||
|
||||
bool Job::is_canceled()
|
||||
{
|
||||
ScopedLock hold(m_mutex);
|
||||
return m_canceled_flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from another thread to do the hard work (image processing).
|
||||
*
|
||||
* [working thread]
|
||||
*/
|
||||
void Job::on_job()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Called each 1000 msecs by the GUI queue processing.
|
||||
*
|
||||
* [main thread]
|
||||
*/
|
||||
void Job::on_monitor_tick()
|
||||
{
|
||||
ScopedLock hold(m_mutex);
|
||||
|
||||
// update progress
|
||||
progress_update(m_progress, m_last_progress);
|
||||
|
||||
// is job done? we can close the monitor
|
||||
if (m_done_flag)
|
||||
remove_gui_monitor(m_monitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the monitor is destroyed.
|
||||
*
|
||||
* [main thread]
|
||||
*/
|
||||
void Job::on_monitor_destroyed()
|
||||
{
|
||||
if (m_alert_window != NULL) {
|
||||
m_monitor = NULL;
|
||||
jwindow_close(m_alert_window, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void Job::done()
|
||||
{
|
||||
ScopedLock hold(m_mutex);
|
||||
m_done_flag = true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Static methods
|
||||
|
||||
/**
|
||||
* Called to start the worker thread.
|
||||
*
|
||||
* [worker thread]
|
||||
*/
|
||||
void Job::thread_proc(void* data)
|
||||
{
|
||||
Job* self = (Job*)data;
|
||||
try {
|
||||
self->on_job();
|
||||
}
|
||||
catch (...) {
|
||||
// TODO handle this exception
|
||||
}
|
||||
|
||||
self->done();
|
||||
}
|
||||
|
||||
/**
|
||||
* Procedure called from the GUI loop to monitoring each 100 milliseconds.
|
||||
*
|
||||
* [main thread]
|
||||
*/
|
||||
void Job::monitor_proc(void* data)
|
||||
{
|
||||
Job* self = (Job*)data;
|
||||
self->on_monitor_tick();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called when the GUI monitor is deleted.
|
||||
*
|
||||
* [main thread]
|
||||
*/
|
||||
void Job::monitor_free(void* data)
|
||||
{
|
||||
Job* self = (Job*)data;
|
||||
self->on_monitor_destroyed();
|
||||
}
|
63
src/core/job.h
Normal file
63
src/core/job.h
Normal file
@ -0,0 +1,63 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2009 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
|
||||
*/
|
||||
|
||||
#ifndef CORE_JOB_H
|
||||
#define CORE_JOB_H
|
||||
|
||||
#include "jinete/jbase.h"
|
||||
|
||||
struct Monitor;
|
||||
struct Progress;
|
||||
|
||||
class Job
|
||||
{
|
||||
JThread m_thread;
|
||||
Monitor* m_monitor;
|
||||
Progress* m_progress;
|
||||
JMutex m_mutex;
|
||||
JWidget m_alert_window;
|
||||
float m_last_progress;
|
||||
bool m_done_flag;
|
||||
bool m_canceled_flag;
|
||||
|
||||
public:
|
||||
|
||||
Job();
|
||||
virtual ~Job();
|
||||
|
||||
void do_job();
|
||||
void job_progress(float f);
|
||||
bool is_canceled();
|
||||
|
||||
protected:
|
||||
|
||||
virtual void on_job();
|
||||
virtual void on_monitor_tick();
|
||||
virtual void on_monitor_destroyed();
|
||||
|
||||
private:
|
||||
|
||||
void done();
|
||||
|
||||
static void thread_proc(void* data);
|
||||
static void monitor_proc(void* data);
|
||||
static void monitor_free(void* data);
|
||||
|
||||
};
|
||||
|
||||
#endif // CORE_JOB_H
|
@ -704,6 +704,9 @@ void fop_free(FileOp *fop)
|
||||
if (fop->seq.palette != NULL)
|
||||
palette_free(fop->seq.palette);
|
||||
|
||||
if (fop->mutex)
|
||||
jmutex_free(fop->mutex);
|
||||
|
||||
jfree(fop);
|
||||
}
|
||||
|
||||
|
@ -34,34 +34,43 @@
|
||||
|
||||
#include "jinete/jmutex.h"
|
||||
|
||||
struct {
|
||||
void (*destroy)(JMutex mutex);
|
||||
void (*lock)(JMutex mutex);
|
||||
void (*unlock)(JMutex mutex);
|
||||
} mutex_vtable = { NULL, NULL, NULL };
|
||||
|
||||
JMutex jmutex_new()
|
||||
{
|
||||
assert(system_driver != NULL);
|
||||
assert(system_driver->create_mutex != NULL);
|
||||
|
||||
if (!mutex_vtable.destroy) {
|
||||
mutex_vtable.destroy = system_driver->destroy_mutex;
|
||||
mutex_vtable.lock = system_driver->lock_mutex;
|
||||
mutex_vtable.unlock = system_driver->unlock_mutex;
|
||||
}
|
||||
|
||||
return (JMutex)system_driver->create_mutex();
|
||||
}
|
||||
|
||||
void jmutex_free(JMutex mutex)
|
||||
{
|
||||
assert(system_driver != NULL);
|
||||
assert(system_driver->destroy_mutex != NULL);
|
||||
assert(mutex_vtable.destroy != NULL);
|
||||
|
||||
system_driver->destroy_mutex(mutex);
|
||||
(*mutex_vtable.destroy)(mutex);
|
||||
}
|
||||
|
||||
void jmutex_lock(JMutex mutex)
|
||||
{
|
||||
assert(system_driver != NULL);
|
||||
assert(system_driver->lock_mutex != NULL);
|
||||
assert(mutex_vtable.lock != NULL);
|
||||
|
||||
system_driver->lock_mutex(mutex);
|
||||
(*mutex_vtable.lock)(mutex);
|
||||
}
|
||||
|
||||
void jmutex_unlock(JMutex mutex)
|
||||
{
|
||||
assert(system_driver != NULL);
|
||||
assert(system_driver->unlock_mutex != NULL);
|
||||
assert(mutex_vtable.unlock != NULL);
|
||||
|
||||
system_driver->unlock_mutex(mutex);
|
||||
(*mutex_vtable.unlock)(mutex);
|
||||
}
|
||||
|
@ -40,4 +40,15 @@ void jmutex_free(JMutex mutex);
|
||||
void jmutex_lock(JMutex mutex);
|
||||
void jmutex_unlock(JMutex mutex);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// ScopedLock
|
||||
|
||||
class ScopedLock
|
||||
{
|
||||
JMutex m_mutex;
|
||||
public:
|
||||
ScopedLock(JMutex mutex) : m_mutex(mutex) { jmutex_lock(m_mutex); }
|
||||
~ScopedLock() { jmutex_unlock(m_mutex); }
|
||||
};
|
||||
|
||||
#endif /* JINETE_MUTEX_H */
|
||||
|
@ -113,8 +113,10 @@ typedef struct UndoAction
|
||||
void (*invert)(UndoStream* stream, UndoChunk* chunk, int state);
|
||||
} UndoAction;
|
||||
|
||||
static void run_undo(Undo* undo, int state, bool discard);
|
||||
static void run_undo(Undo* undo, int state);
|
||||
static void discard_undo_tail(Undo* undo);
|
||||
static int count_undo_groups(UndoStream* undo_stream);
|
||||
static bool out_of_group(UndoStream* undo_stream);
|
||||
static void update_undo(Undo* undo);
|
||||
|
||||
/* Undo actions */
|
||||
@ -230,7 +232,7 @@ static int get_raw_mask_size(Mask* mask);
|
||||
static UndoStream* undo_stream_new(Undo* undo);
|
||||
static void undo_stream_free(UndoStream* stream);
|
||||
|
||||
static UndoChunk* undo_stream_pop_chunk(UndoStream* stream, int tail);
|
||||
static UndoChunk* undo_stream_pop_chunk(UndoStream* stream, bool tail);
|
||||
static void undo_stream_push_chunk(UndoStream* stream, UndoChunk* chunk);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -314,13 +316,13 @@ bool undo_can_redo(Undo* undo)
|
||||
void undo_do_undo(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
run_undo(undo, DO_UNDO, FALSE);
|
||||
run_undo(undo, DO_UNDO);
|
||||
}
|
||||
|
||||
void undo_do_redo(Undo* undo)
|
||||
{
|
||||
assert(undo);
|
||||
run_undo(undo, DO_REDO, FALSE);
|
||||
run_undo(undo, DO_REDO);
|
||||
}
|
||||
|
||||
void undo_clear_redo(Undo* undo)
|
||||
@ -357,7 +359,7 @@ const char *undo_get_next_redo_label(Undo* undo)
|
||||
return chunk->label;
|
||||
}
|
||||
|
||||
static void run_undo(Undo* undo, int state, bool discard_tail)
|
||||
static void run_undo(Undo* undo, int state)
|
||||
{
|
||||
UndoStream* undo_stream = ((state == DO_UNDO)? undo->undo_stream:
|
||||
undo->redo_stream);
|
||||
@ -366,50 +368,55 @@ static void run_undo(Undo* undo, int state, bool discard_tail)
|
||||
UndoChunk* chunk;
|
||||
int level = 0;
|
||||
|
||||
if (!discard_tail) {
|
||||
do {
|
||||
chunk = undo_stream_pop_chunk(undo_stream, FALSE); /* read from head */
|
||||
if (!chunk)
|
||||
break;
|
||||
do {
|
||||
chunk = undo_stream_pop_chunk(undo_stream, false); // read from head
|
||||
if (!chunk)
|
||||
break;
|
||||
|
||||
{ int c;
|
||||
for (c=0; c<ABS(level); c++)
|
||||
PRINTF(" ");
|
||||
PRINTF("%s: %s (Label: %s)\n",
|
||||
(state == DO_UNDO) ? "Undo": "Redo",
|
||||
undo_actions[chunk->type].name,
|
||||
chunk->label); }
|
||||
{ int c;
|
||||
for (c=0; c<ABS(level); c++)
|
||||
PRINTF(" ");
|
||||
PRINTF("%s: %s (Label: %s)\n",
|
||||
(state == DO_UNDO) ? "Undo": "Redo",
|
||||
undo_actions[chunk->type].name,
|
||||
chunk->label); }
|
||||
|
||||
undo_set_label(undo, chunk->label);
|
||||
(undo_actions[chunk->type].invert)(redo_stream, chunk, state);
|
||||
undo_set_label(undo, chunk->label);
|
||||
(undo_actions[chunk->type].invert)(redo_stream, chunk, state);
|
||||
|
||||
if (chunk->type == UNDO_TYPE_OPEN)
|
||||
level++;
|
||||
else if (chunk->type == UNDO_TYPE_CLOSE)
|
||||
level--;
|
||||
if (chunk->type == UNDO_TYPE_OPEN)
|
||||
level++;
|
||||
else if (chunk->type == UNDO_TYPE_CLOSE)
|
||||
level--;
|
||||
|
||||
undo_chunk_free(chunk);
|
||||
undo_chunk_free(chunk);
|
||||
|
||||
if (state == DO_UNDO)
|
||||
undo->diff_count--;
|
||||
else if (state == DO_REDO)
|
||||
undo->diff_count++;
|
||||
} while (level);
|
||||
}
|
||||
else {
|
||||
do {
|
||||
chunk = undo_stream_pop_chunk(undo_stream, TRUE); /* read from tail */
|
||||
if (!chunk)
|
||||
break;
|
||||
if (state == DO_UNDO)
|
||||
undo->diff_count--;
|
||||
else if (state == DO_REDO)
|
||||
undo->diff_count++;
|
||||
} while (level);
|
||||
}
|
||||
|
||||
if (chunk->type == UNDO_TYPE_OPEN)
|
||||
level++;
|
||||
else if (chunk->type == UNDO_TYPE_CLOSE)
|
||||
level--;
|
||||
static void discard_undo_tail(Undo* undo)
|
||||
{
|
||||
UndoStream* undo_stream = undo->undo_stream;
|
||||
UndoStream* redo_stream = undo->redo_stream;
|
||||
UndoChunk* chunk;
|
||||
int level = 0;
|
||||
|
||||
undo_chunk_free(chunk);
|
||||
} while (level);
|
||||
}
|
||||
do {
|
||||
chunk = undo_stream_pop_chunk(undo_stream, true); // read from tail
|
||||
if (!chunk)
|
||||
break;
|
||||
|
||||
if (chunk->type == UNDO_TYPE_OPEN)
|
||||
level++;
|
||||
else if (chunk->type == UNDO_TYPE_CLOSE)
|
||||
level--;
|
||||
|
||||
undo_chunk_free(chunk);
|
||||
} while (level);
|
||||
}
|
||||
|
||||
static int count_undo_groups(UndoStream* undo_stream)
|
||||
@ -440,10 +447,33 @@ static int count_undo_groups(UndoStream* undo_stream)
|
||||
return groups;
|
||||
}
|
||||
|
||||
static bool out_of_group(UndoStream* undo_stream)
|
||||
{
|
||||
UndoChunk* chunk;
|
||||
int level;
|
||||
JLink link;
|
||||
|
||||
link = jlist_first(undo_stream->chunks);
|
||||
while (link != undo_stream->chunks->end) {
|
||||
level = 0;
|
||||
|
||||
do {
|
||||
chunk = reinterpret_cast<UndoChunk*>(link->data);
|
||||
link = link->next;
|
||||
|
||||
if (chunk->type == UNDO_TYPE_OPEN)
|
||||
level++;
|
||||
else if (chunk->type == UNDO_TYPE_CLOSE)
|
||||
level--;
|
||||
} while (level && (link != undo_stream->chunks->end));
|
||||
}
|
||||
|
||||
return level == 0;
|
||||
}
|
||||
|
||||
/* called every time a new undo is added */
|
||||
static void update_undo(Undo* undo)
|
||||
{
|
||||
int groups = count_undo_groups(undo->undo_stream);
|
||||
int undo_size_limit = get_config_int("Options", "UndoSizeLimit", 8)*1024*1024;
|
||||
|
||||
/* more diff */
|
||||
@ -452,10 +482,14 @@ static void update_undo(Undo* undo)
|
||||
/* reset the "redo" stream */
|
||||
undo_clear_redo(undo);
|
||||
|
||||
/* "undo" is too big? */
|
||||
while (groups > 1 && undo->undo_stream->size > undo_size_limit) {
|
||||
run_undo(undo, DO_UNDO, TRUE);
|
||||
groups--;
|
||||
if (out_of_group(undo->undo_stream)) {
|
||||
int groups = count_undo_groups(undo->undo_stream);
|
||||
|
||||
/* "undo" is too big? */
|
||||
while (groups > 1 && undo->undo_stream->size > undo_size_limit) {
|
||||
discard_undo_tail(undo);
|
||||
groups--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1990,7 +2024,7 @@ static void undo_stream_free(UndoStream* stream)
|
||||
jfree(stream);
|
||||
}
|
||||
|
||||
static UndoChunk* undo_stream_pop_chunk(UndoStream* stream, int tail)
|
||||
static UndoChunk* undo_stream_pop_chunk(UndoStream* stream, bool tail)
|
||||
{
|
||||
UndoChunk* chunk;
|
||||
JLink link;
|
||||
|
Loading…
x
Reference in New Issue
Block a user