diff --git a/ChangeLog b/ChangeLog index 907aebcfc..66954e602 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2009-10-14 David Capello + + * src/core/app.h (IAppHook, AppEvent): Added IAppHook interface + for a cleaner event/hook interface. + + * src/core/app.cpp (Option): Converted to a class. + 2009-10-08 David Capello * src/modules/tools.cpp (tool_marker): Modified marquee tooltip. diff --git a/src/commands/cmd_about.cpp b/src/commands/cmd_about.cpp index 6a810a2da..8637e65e5 100644 --- a/src/commands/cmd_about.cpp +++ b/src/commands/cmd_about.cpp @@ -65,7 +65,7 @@ void AboutCommand::execute(Context* context) box1 = jbox_new(JI_VERTICAL); label1 = jlabel_new("Allegro Sprite Editor - " VERSION); - label2 = jlabel_new(_("Just Another Tool to Create Sprites")); + label2 = jlabel_new(_("Just another tool to create sprites")); separator1 = ji_separator_new(NULL, JI_HORIZONTAL); if (authors_txt) { diff --git a/src/commands/cmd_configure_tools.cpp b/src/commands/cmd_configure_tools.cpp index 313cf282c..61e8edd52 100644 --- a/src/commands/cmd_configure_tools.cpp +++ b/src/commands/cmd_configure_tools.cpp @@ -40,6 +40,17 @@ #include "widgets/statebar.h" #include "sprite_wrappers.h" +class FreeWidget : public IAppHook +{ + JWidget m_widget; +public: + FreeWidget(JWidget widget) : m_widget(widget) { } + void on_event() + { + jwidget_free(m_widget); + } +}; + static JWidget window = NULL; static bool brush_preview_msg_proc(JWidget widget, JMessage msg); @@ -201,9 +212,7 @@ void ConfigureTools::execute(Context* context) HOOK(cursor_color, SIGNAL_COLORBUTTON_CHANGE, cursor_button_change_hook, 0); HOOK(check_onionskin, JI_SIGNAL_CHECK_CHANGE, onionskin_check_change_hook, 0); - app_add_hook(APP_EXIT, - reinterpret_cast(jwidget_free), - window); + App::instance()->add_hook(AppEvent::Exit, new FreeWidget(window)); } /* default position */ diff --git a/src/commands/fx/cmd_color_curve.cpp b/src/commands/fx/cmd_color_curve.cpp index e1042224f..0ee11572e 100644 --- a/src/commands/fx/cmd_color_curve.cpp +++ b/src/commands/fx/cmd_color_curve.cpp @@ -72,6 +72,17 @@ bool ColorCurveCommand::enabled(Context* context) sprite != NULL; } +class DestroyCurve : public IAppHook +{ + Curve* m_curve; +public: + DestroyCurve(Curve* curve) : m_curve(curve) { } + void on_event() + { + curve_free(m_curve); + } +}; + void ColorCurveCommand::execute(Context* context) { const CurrentSpriteReader sprite(context); @@ -85,9 +96,7 @@ void ColorCurveCommand::execute(Context* context) curve_add_point(the_curve, curve_point_new(0, 0)); curve_add_point(the_curve, curve_point_new(255, 255)); - app_add_hook(APP_EXIT, - reinterpret_cast(curve_free), - the_curve); + App::instance()->add_hook(AppEvent::Exit, new DestroyCurve(the_curve)); } JWidgetPtr window(load_widget("colcurv.jid", "color_curve")); diff --git a/src/core/app.cpp b/src/core/app.cpp index b3e2acf3c..a0b289c00 100644 --- a/src/core/app.cpp +++ b/src/core/app.cpp @@ -68,34 +68,44 @@ #include #endif -/* options */ -enum { - OPEN_GFX_FILE, -}; - -struct Option +class Option { - int type; - char *data; -}; + int m_type; + jstring m_data; -struct AppHook -{ - void (*proc)(void *); - void *data; +public: - AppHook(void (*proc)(void *), void *data) { - this->proc = proc; - this->data = data; + enum { + OpenSprite, + }; + + Option(int type, const char* data) + { + m_type = type; + m_data = data; } + + int type() const { return m_type; } + const char* data() const { return m_data.c_str(); } + +}; + +class App::Pimpl +{ +public: + const char* m_exe_name; + std::vector m_options; + CommandsModule m_commands_modules; + UIContext m_ui_context; + int m_return_code; + std::vector > m_apphooks; + + Pimpl() { } + ~Pimpl() { } }; App* App::m_instance = NULL; -static char *exe_name; /* name of the program */ - -static JList apphooks[APP_EVENTS]; - static JWidget top_window = NULL; /* top level window (the desktop) */ static JWidget box_menubar = NULL; /* box where the menu bar is */ static JWidget box_colorbar = NULL; /* box where the color bar is */ @@ -108,26 +118,10 @@ static JWidget colorbar = NULL; /* the color bar widget */ static JWidget toolbar = NULL; /* the tool bar widget */ static JWidget tabsbar = NULL; /* the tabs bar widget */ -static JList options; /* list of "Option" structures (options to execute) */ static char *palette_filename = NULL; static void tabsbar_select_callback(JWidget tabs, void *data, int button); -static void check_args(int argc, char *argv[]); -static void usage(int status); - -static Option *option_new(int type, const char *data); -static void option_free(Option *option); - -class App::Pimpl -{ - CommandsModule m_commands_modules; - UIContext m_ui_context; -public: - Pimpl() { } - ~Pimpl() { } -}; - /** * Initializes the application loading the modules, setting the * graphics mode, loading the configuration and resources, etc. @@ -137,11 +131,11 @@ App::App(int argc, char *argv[]) assert(m_instance == NULL); m_instance = this; - exe_name = argv[0]; - - /* initialize application hooks */ - for (int c=0; cm_exe_name = argv[0]; + m_pimpl->m_return_code = 0; + m_pimpl->m_apphooks.resize(AppEvent::NumEvents); /* initialize language suppport */ intl_init(); @@ -155,7 +149,7 @@ App::App(int argc, char *argv[]) /* init configuration */ ase_config_init(); - /* load the language file */ + // load the language file intl_load_lang(); /* search options in the arguments */ @@ -168,11 +162,8 @@ App::App(int argc, char *argv[]) /* install 'raster' stuff */ gfxobj_init(); - // create singletons - m_pimpl = new Pimpl; - // install the modules - modules_init(REQUIRE_INTERFACE); + modules_init(ase_mode & MODE_GUI ? REQUIRE_INTERFACE: 0); /* custom default palette? */ if (palette_filename) { @@ -197,11 +188,8 @@ App::App(int argc, char *argv[]) * Runs the ASE application. In GUI mode it's the top-level window, in * console/scripting it just runs the specified scripts. */ -void App::run() +int App::run() { - Option *option; - JLink link; - /* initialize GUI interface */ if (ase_mode & MODE_GUI) { JWidget view, editor; @@ -217,7 +205,7 @@ void App::run() if (!top_window) { allegro_message("Error loading data data/jids/main.jid file.\n" "You have to reinstall the program.\n"); - exit(1); + return 1; } box_menubar = jwidget_find_name(top_window, "menubar"); @@ -285,23 +273,24 @@ void App::run() /* set_display_switch_mode(SWITCH_BACKAMNESIA); */ set_display_switch_mode(SWITCH_BACKGROUND); - /* procress options */ + // procress options PRINTF("Processing options...\n"); + + for (std::vector::iterator + it = m_pimpl->m_options.begin(); it != m_pimpl->m_options.end(); ++it) { + Option* option = *it; - JI_LIST_FOR_EACH(options, link) { - option = reinterpret_cast(link->data); + switch (option->type()) { - switch (option->type) { - - case OPEN_GFX_FILE: { + case Option::OpenSprite: { /* load the sprite */ - Sprite *sprite = sprite_load(option->data); + Sprite *sprite = sprite_load(option->data()); if (!sprite) { /* error */ if (ase_mode & MODE_GUI) - jalert(_("Error<data); + jalert(_("Error<data()); else - user_printf(_("Error loading file \"%s\"\n"), option->data); + user_printf(_("Error loading file \"%s\"\n"), option->data()); } else { /* mount and select the sprite */ @@ -314,16 +303,15 @@ void App::run() set_sprite_in_more_reliable_editor(context->get_first_sprite()); /* recent file */ - recent_file(option->data); + recent_file(option->data()); } } break; } } - option_free(option); + delete option; } - - jlist_free(options); + m_pimpl->m_options.clear(); /* just batch mode */ if (ase_mode & MODE_BATCH) { @@ -357,6 +345,7 @@ void App::run() jwidget_free(top_window); top_window = NULL; } + return 0; } /** @@ -364,63 +353,63 @@ void App::run() */ App::~App() { - assert(m_instance == this); + try { + assert(m_instance == this); - // remove ase handlers - PRINTF("Uninstalling ASE\n"); + // remove ase handlers + PRINTF("Uninstalling ASE\n"); - app_trigger_event(APP_EXIT); + App::trigger_event(AppEvent::Exit); - // destroy application hooks - for (int c=0; c(link->data); + // destroy application hooks + for (int c=0; c::iterator + it = m_pimpl->m_apphooks[c].begin(); + it != m_pimpl->m_apphooks[c].end(); ++it) { + IAppHook* apphook = *it; delete apphook; } - jlist_free(apphooks[c]); - apphooks[c] = NULL; + + // clear the list of hooks (so nobody can call the deleted hooks) + m_pimpl->m_apphooks[c].clear(); } - } - // finalize modules, configuration and core - modules_exit(); - delete m_pimpl; - editor_cursor_exit(); - boundary_exit(); + // finalize modules, configuration and core + modules_exit(); + delete m_pimpl; + editor_cursor_exit(); + boundary_exit(); - gfxobj_exit(); - ase_config_exit(); - file_system_exit(); - core_exit(); - intl_exit(); + gfxobj_exit(); + ase_config_exit(); + file_system_exit(); + core_exit(); + intl_exit(); - m_instance = NULL; + m_instance = NULL; + } + catch (...) { + allegro_message("Uncaught exception in ~App"); + // no throw + } } -void app_add_hook(int app_event, void (*proc)(void *data), void *data) +void App::add_hook(AppEvent::Type event, IAppHook* hook) { - assert(app_event >= 0 && app_event < APP_EVENTS); + assert(event >= 0 && event < AppEvent::NumEvents); - if (apphooks[app_event] == NULL) - apphooks[app_event] = jlist_new(); - - jlist_append(apphooks[app_event], new AppHook(proc, data)); + m_pimpl->m_apphooks[event].push_back(hook); } -void app_trigger_event(int app_event) +void App::trigger_event(AppEvent::Type event) { - assert(app_event >= 0 && app_event < APP_EVENTS); + assert(event >= 0 && event < AppEvent::NumEvents); - if (apphooks[app_event] != NULL) { - JList list = apphooks[app_event]; - JLink link; - - JI_LIST_FOR_EACH(list, link) { - AppHook *h = (AppHook *)link->data; - (h->proc)(h->data); - } + for (std::vector::iterator + it = m_pimpl->m_apphooks[event].begin(); + it != m_pimpl->m_apphooks[event].end(); ++it) { + IAppHook* apphook = *it; + apphook->on_event(); } } @@ -589,14 +578,12 @@ static void tabsbar_select_callback(JWidget tabs, void *data, int button) /** * Looks the inpunt arguments in the command line. */ -static void check_args(int argc, char *argv[]) +void App::check_args(int argc, char *argv[]) { Console console; int i, n, len; char *arg; - options = jlist_new(); - for (i=1; im_exe_name); + usage(false); } } /* verbose mode */ @@ -656,7 +644,7 @@ static void check_args(int argc, char *argv[]) } /* show help */ else if (strncmp(arg+n, "help", len) == 0) { - usage(0); + usage(true); } /* show version */ else if (strncmp(arg+n, "version", len) == 0) { @@ -666,34 +654,38 @@ static void check_args(int argc, char *argv[]) } /* invalid argument */ else { - usage(1); + usage(false); } } /* graphic file to open */ else if (n == 0) - jlist_append(options, option_new(OPEN_GFX_FILE, argv[i])); + m_pimpl->m_options.push_back(new Option(Option::OpenSprite, argv[i])); } } /** * Shows the available options for the program */ -static void usage(int status) +void App::usage(bool show_help) { Console console; - /* show options */ - if (!status) { - /* copyright */ - console.printf - ("ase %s -- allegro-sprite-editor, %s\n" - COPYRIGHT "\n\n", - VERSION, _("The Ultimate Sprites Factory")); + ase_mode |= MODE_BATCH; + if (!show_help) + m_pimpl->m_return_code = 1; - /* usage */ + // show options + if (show_help) { + // copyright + console.printf + ("ase %s -- Allegro Sprite Editor, %s\n" + COPYRIGHT "\n\n", + VERSION, _("Just another tool to create sprites")); + + // usage console.printf ("%s\n %s [%s] [%s]...\n\n", - _("Usage:"), exe_name, _("OPTION"), _("FILE")); + _("Usage:"), m_pimpl->m_exe_name, _("OPTION"), _("FILE")); /* options */ console.printf @@ -713,28 +705,12 @@ static void usage(int status) /* web-site */ console.printf - ("%s: %s\n%s\n\n %s\n\n", + ("%s: %s\n\n", _("Find more information in the ASE's official web site at:"), WEBSITE); } /* how to show options */ else { - console.printf(_("Try \"%s --help\" for more information.\n"), exe_name); + console.printf(_("Try \"%s --help\" for more information.\n"), + m_pimpl->m_exe_name); } - exit(status); -} - -static Option *option_new(int type, const char *data) -{ - Option *option = new Option; - - option->type = type; - option->data = jstrdup(data); - - return option; -} - -static void option_free(Option* option) -{ - jfree(option->data); - delete option; } diff --git a/src/core/app.h b/src/core/app.h index 13a93b0e0..cbe13c960 100644 --- a/src/core/app.h +++ b/src/core/app.h @@ -21,19 +21,30 @@ #include "jinete/jbase.h" -// enumeration of ASE events in the highest application level -enum { - APP_EXIT, - APP_PALETTE_CHANGE, - APP_EVENTS -}; - class Layer; class Sprite; class Params; class Command; class CommandsModule; +class AppEvent +{ +public: + // enumeration of ASE events in the highest application level + enum Type { + Exit, + PaletteChange, + NumEvents + }; +}; + +class IAppHook +{ +public: + virtual ~IAppHook() { } + virtual void on_event() = 0; +}; + class App { static App* m_instance; @@ -47,11 +58,16 @@ public: static App* instance() { return m_instance; } - void run(); -}; + int run(); -void app_add_hook(int app_event, void (*proc)(void *data), void *data); -void app_trigger_event(int app_event); + void add_hook(AppEvent::Type event, IAppHook* hook); + void trigger_event(AppEvent::Type event); + +private: + void check_args(int argc, char *argv[]); + void usage(bool show_help); + +}; void app_refresh_screen(const Sprite* sprite); diff --git a/src/core/modules.cpp b/src/core/modules.cpp index 1b148d9b4..0eda9a6c7 100644 --- a/src/core/modules.cpp +++ b/src/core/modules.cpp @@ -30,7 +30,7 @@ #include "modules/tools.h" #define DEF_MODULE(name, reqs) \ - { #name, init_module_##name, exit_module_##name, (reqs), FALSE } + { #name, init_module_##name, exit_module_##name, (reqs), false } typedef struct Module { @@ -38,7 +38,7 @@ typedef struct Module int (*init)(); void (*exit)(); int reqs; - int installed; + bool installed; } Module; static Module module[] = @@ -46,9 +46,9 @@ static Module module[] = /* This sorting is very important because last modules depend of first ones. */ - DEF_MODULE(palette, REQUIRE_INTERFACE), - DEF_MODULE(effect, REQUIRE_INTERFACE), - DEF_MODULE(tools, REQUIRE_INTERFACE), + DEF_MODULE(palette, 0), + DEF_MODULE(effect, 0), + DEF_MODULE(tools, 0), DEF_MODULE(graphics, REQUIRE_INTERFACE), DEF_MODULE(gui, REQUIRE_INTERFACE), DEF_MODULE(recent, REQUIRE_INTERFACE), @@ -61,13 +61,13 @@ static int modules = sizeof(module) / sizeof(Module); void modules_init(int requirements) { for (int c=0; c(jlist_free), - navigation_history); + App::instance()->add_hook(AppEvent::Exit, + new FreeList(navigation_history)); } // we have to find where the user should begin to browse files (start_folder) diff --git a/src/main.cpp b/src/main.cpp index 6a24d143b..9e7ca54c7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,13 +52,14 @@ public: */ int main(int argc, char *argv[]) { + int status = 1; // 1 = error try { Allegro allegro; try { Jinete jinete; App app(argc, argv); - app.run(); + status = app.run(); } catch (std::exception& e) { allegro_message(e.what()); @@ -70,7 +71,7 @@ int main(int argc, char *argv[]) catch (...) { printf("Uncaught exception"); } - return 0; + return status; } END_OF_MAIN(); diff --git a/src/modules/gfx.cpp b/src/modules/gfx.cpp index 304a3d72c..c5f003405 100644 --- a/src/modules/gfx.cpp +++ b/src/modules/gfx.cpp @@ -68,34 +68,32 @@ static void convert_data_to_bitmap(DATA *data, BITMAP **bmp) } } -static void gen_gfx(void *data) +class GenGfx : public IAppHook { - int c; +public: + void on_event() + { + for (int c=0; cadd_hook(AppEvent::PaletteChange, new GenGfx); return 0; } void exit_module_graphics() { - int c; - - for (c=0; cadd_hook(AppEvent::PaletteChange, new RegenIcons()); /* icon buttons */ icon_buttons = jlist_new(); @@ -955,9 +959,9 @@ void* get_monitor_data(Monitor* monitor) return monitor->data; } -/**********************************************************************/ -/* manager event handler */ - +/** + * Manager event handler. + */ static bool manager_msg_proc(JWidget widget, JMessage msg) { switch (msg->type) { @@ -1069,10 +1073,10 @@ static bool manager_msg_proc(JWidget widget, JMessage msg) return false; } -/**********************************************************************/ -/* graphics */ - -static void regen_theme_and_fixup_icons(void *data) +/** + * IAppHook to regenerate graphics when the App palette is changed. + */ +void RegenIcons::on_event() { JWidget button; JLink link; diff --git a/src/modules/palettes.cpp b/src/modules/palettes.cpp index caef32e26..20251600d 100644 --- a/src/modules/palettes.cpp +++ b/src/modules/palettes.cpp @@ -195,8 +195,8 @@ bool set_current_palette(Palette *_palette, bool forced) create_rgb_table(my_rgb_map, rgbpal, NULL); set_palette(rgbpal); /* change system color palette */ - /* call hooks */ - app_trigger_event(APP_PALETTE_CHANGE); + // call hooks + App::instance()->trigger_event(AppEvent::PaletteChange); ret = TRUE; } diff --git a/src/modules/tools.cpp b/src/modules/tools.cpp index 5cf555348..8cbf4590a 100644 --- a/src/modules/tools.cpp +++ b/src/modules/tools.cpp @@ -137,7 +137,7 @@ static AlgoHLine inks_hline[][3] = /* CURSOR COLOR */ /***********************************************************/ -static void update_cursor_color(void *data) +static void update_cursor_color() { if (ji_screen) _cursor_color = get_color_for_allegro(bitmap_color_depth(ji_screen), @@ -148,6 +148,15 @@ static void update_cursor_color(void *data) _cursor_mask = (color_type(cursor_color) == COLOR_TYPE_MASK); } +class UpdateCursorColor : public IAppHook +{ +public: + void on_event() + { + update_cursor_color(); + } +}; + /***********************************************************/ /* TOOLS */ /***********************************************************/ @@ -192,7 +201,7 @@ int init_module_tools() air_speed = MID(1, air_speed, 100); tiled_mode = (tiled_t)MID(0, (int)tiled_mode, TILED_BOTH); - app_add_hook(APP_PALETTE_CHANGE, update_cursor_color, NULL); + App::instance()->add_hook(AppEvent::PaletteChange, new UpdateCursorColor); return 0; } @@ -309,7 +318,7 @@ color_t get_cursor_color() void set_cursor_color(color_t color) { cursor_color = color; - update_cursor_color(NULL); + update_cursor_color(); } /* returns the size which use the current tool */ diff --git a/src/raster/gfxobj.cpp b/src/raster/gfxobj.cpp index 0d8448d9c..dd22ce697 100644 --- a/src/raster/gfxobj.cpp +++ b/src/raster/gfxobj.cpp @@ -35,8 +35,6 @@ static std::map* objects_map; // graphics objects map static void insert_gfxobj(GfxObj* gfxobj); static void erase_gfxobj(GfxObj* gfxobj); -////////////////////////////////////////////////////////////////////// - void gfxobj_init() { objects_map = new std::map; @@ -52,7 +50,7 @@ void gfxobj_exit() ////////////////////////////////////////////////////////////////////// // GfxObj class - + GfxObj::GfxObj(int type) { this->type = type; @@ -89,7 +87,6 @@ void GfxObj::assign_id() } ////////////////////////////////////////////////////////////////////// - GfxObj* gfxobj_find(gfxobj_id id) { diff --git a/src/util/clipboard.cpp b/src/util/clipboard.cpp index 544e13bdd..e431fe234 100644 --- a/src/util/clipboard.cpp +++ b/src/util/clipboard.cpp @@ -79,7 +79,6 @@ enum { ACTION_ROTATE_BR, }; -static void destroy_clipboard(void* data); static void set_clipboard(Image* image, Palette* palette, bool set_system_clipboard); static bool copy_from_sprite(const Sprite* sprite); @@ -106,17 +105,21 @@ static bool first_time = true; static Palette* clipboard_palette = NULL; static Image* clipboard_image = NULL; -static void destroy_clipboard(void* data) +class DestroyClipboard : public IAppHook { - delete clipboard_palette; - delete clipboard_image; -} +public: + void on_event() + { + delete clipboard_palette; + delete clipboard_image; + } +}; static void set_clipboard(Image* image, Palette* palette, bool set_system_clipboard) { if (first_time) { first_time = false; - app_add_hook(APP_EXIT, destroy_clipboard, NULL); + App::instance()->add_hook(AppEvent::Exit, new DestroyClipboard()); } delete clipboard_palette;