mirror of https://github.com/aseprite/aseprite.git
				
				
				
			Merge branch '1.0'
This commit is contained in:
		
						commit
						bf3c0890e9
					
				|  | @ -131,9 +131,6 @@ void osx_mouse_handler(int ax, int ay, int x, int y, int z, int buttons) | |||
|    _mouse_y = ay; | ||||
|    _mouse_z += z; | ||||
| 
 | ||||
|    _mouse_x = CLAMP(mouse_minx, _mouse_x, mouse_maxx); | ||||
|    _mouse_y = CLAMP(mouse_miny, _mouse_y, mouse_maxy); | ||||
| 
 | ||||
|    _handle_mouse_input(); | ||||
| } | ||||
| 
 | ||||
|  | @ -219,26 +216,24 @@ static void osx_mouse_exit(void) | |||
|  */ | ||||
| static void osx_mouse_position(int x, int y) | ||||
| { | ||||
|    CGPoint point; | ||||
|    NSRect frame; | ||||
|    int screen_height; | ||||
|    int scale, view_scale; | ||||
|    NSPoint pt; | ||||
|    CGPoint pos; | ||||
|    CGEventRef event; | ||||
|    NSView* view = [osx_window contentView]; | ||||
| 
 | ||||
|    _unix_lock_mutex(osx_event_mutex); | ||||
| 
 | ||||
|    _mouse_x = point.x = x; | ||||
|    _mouse_y = point.y = y; | ||||
|    pt = NSMakePoint(x, y); | ||||
|    pt = [view convertPoint:pt toView:view]; | ||||
|    pt = [view convertPoint:pt toView:nil]; | ||||
|    pt = [osx_window convertBaseToScreen:pt]; | ||||
|    pt.y = [[osx_window screen] frame].size.height - pt.y; | ||||
| 
 | ||||
|    if (osx_window) { | ||||
|       CFNumberGetValue(CFDictionaryGetValue(CGDisplayCurrentMode(kCGDirectMainDisplay), kCGDisplayHeight), kCFNumberSInt32Type, &screen_height); | ||||
|       frame = [osx_window frame]; | ||||
|       point.x += frame.origin.x; | ||||
|       point.y += (screen_height - (frame.origin.y + gfx_driver->h)); | ||||
|    } | ||||
| 
 | ||||
|    CGDisplayMoveCursorToPoint(kCGDirectMainDisplay, point); | ||||
| 
 | ||||
|    mymickey_x = mymickey_y = 0; | ||||
|    osx_mouse_warped = TRUE; | ||||
|    pos = CGPointMake(pt.x, pt.y); | ||||
|    event = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, pos, 0); | ||||
|    CGEventPost(kCGHIDEventTap, event); | ||||
|    CFRelease(event); | ||||
| 
 | ||||
|    _unix_unlock_mutex(osx_event_mutex); | ||||
| } | ||||
|  |  | |||
|  | @ -153,25 +153,14 @@ static RETSIGTYPE osx_signal_handler(int num) | |||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| static BOOL handle_mouse_enter( | ||||
|   NSRect frame, NSRect view, NSPoint point, | ||||
|   int* mx, int* my, int* buttons) | ||||
| static void handle_mouse_enter() | ||||
| { | ||||
|   if (_mouse_installed && !_mouse_on && | ||||
|       (osx_window) && (NSPointInRect(point, view))) { | ||||
|     *mx = point.x; | ||||
|     *my = frame.size.height - point.y; | ||||
|     *buttons = 0; | ||||
| 
 | ||||
|   if (_mouse_installed && !_mouse_on && osx_window) { | ||||
|     _mouse_on = TRUE; | ||||
|     osx_hide_native_mouse(); | ||||
|     if (osx_mouse_enter_callback) | ||||
|       osx_mouse_enter_callback(); | ||||
| 
 | ||||
|     return YES; | ||||
|   } | ||||
|   else | ||||
|     return NO; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -200,9 +189,8 @@ void osx_event_handler() | |||
| { | ||||
|    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | ||||
|    NSEvent *event; | ||||
|    NSDate *distant_past = [NSDate distantPast]; | ||||
|    NSPoint point; | ||||
|    NSRect frame, view; | ||||
|    NSView* view; | ||||
|    int dx = 0, dy = 0, dz = 0; | ||||
|    int mx = _mouse_x; | ||||
|    int my = _mouse_y; | ||||
|  | @ -211,10 +199,12 @@ void osx_event_handler() | |||
|    BOOL gotmouseevent = NO; | ||||
| 
 | ||||
|    while ((event = [NSApp nextEventMatchingMask: NSAnyEventMask | ||||
|          untilDate: distant_past | ||||
|                                       untilDate: [NSDate distantPast] | ||||
|                                          inMode: NSDefaultRunLoopMode | ||||
|          dequeue: YES]) != nil) | ||||
|                                         dequeue: YES])) | ||||
|    { | ||||
|      BOOL send_event = YES; | ||||
| 
 | ||||
|       _unix_lock_mutex(osx_skip_events_processing_mutex); | ||||
|       int skip_events_processing = osx_skip_events_processing; | ||||
|       _unix_unlock_mutex(osx_skip_events_processing_mutex); | ||||
|  | @ -224,16 +214,15 @@ void osx_event_handler() | |||
|          continue; | ||||
|       } | ||||
| 
 | ||||
|       view = NSMakeRect(0, 0, gfx_driver->w, gfx_driver->h); | ||||
|       view = [osx_window contentView]; | ||||
|       point = [event locationInWindow]; | ||||
|       if (osx_window) | ||||
|       { | ||||
|          frame = [[osx_window contentView] frame]; | ||||
|       } | ||||
|       else | ||||
|       { | ||||
|          frame = [[NSScreen mainScreen] frame]; | ||||
|       if (osx_window) { | ||||
|          if ([event window] == nil) | ||||
|             point = [osx_window convertScreenToBase:point]; | ||||
| 
 | ||||
|          point = [view convertPoint:point fromView:nil]; | ||||
|       } | ||||
| 
 | ||||
|       event_type = [event type]; | ||||
|       switch (event_type) { | ||||
| 
 | ||||
|  | @ -241,10 +230,11 @@ void osx_event_handler() | |||
|             if (_keyboard_installed) | ||||
|                osx_keyboard_handler(TRUE, event); | ||||
| 
 | ||||
| #if 0 // Avoid beeps TODO uncomment this when the OS X menus are ready | ||||
|             if ([event modifierFlags] & NSCommandKeyMask && ) | ||||
| #if 0 // Avoid beeps TODO comment this when the OS X menus are ready | ||||
|             if ([event modifierFlags] & NSCommandKeyMask) | ||||
|                [NSApp sendEvent: event]; | ||||
| #endif | ||||
|             send_event = NO; | ||||
|             break; | ||||
| 
 | ||||
|          case NSKeyUp: | ||||
|  | @ -255,6 +245,7 @@ void osx_event_handler() | |||
|             if ([event modifierFlags] & NSCommandKeyMask) | ||||
|                [NSApp sendEvent: event]; | ||||
| #endif | ||||
|             send_event = NO; | ||||
|             break; | ||||
| 
 | ||||
|          case NSFlagsChanged: | ||||
|  | @ -267,87 +258,109 @@ void osx_event_handler() | |||
|          case NSRightMouseDown: | ||||
|             /* App is regaining focus */ | ||||
|             if (![NSApp isActive]) { | ||||
|                handle_mouse_enter(frame, view, point, &mx, &my, &buttons); | ||||
|                handle_mouse_enter(); | ||||
| 
 | ||||
|                if (osx_window) | ||||
|                   [osx_window invalidateCursorRectsForView: [osx_window contentView]]; | ||||
|                   [osx_window invalidateCursorRectsForView:view]; | ||||
| 
 | ||||
|                if (_keyboard_installed) | ||||
|                   osx_keyboard_focused(TRUE, 0); | ||||
| 
 | ||||
|                _switch_in(); | ||||
|                gotmouseevent = YES; | ||||
|                [NSApp sendEvent: event]; | ||||
|                break; | ||||
|             } | ||||
| 
 | ||||
|             if (_mouse_on) { | ||||
|                buttons |= ((event_type == NSLeftMouseDown) ? 0x1 : 0); | ||||
|                buttons |= ((event_type == NSRightMouseDown) ? 0x2 : 0); | ||||
|                buttons |= ((event_type == NSOtherMouseDown) ? 0x4 : 0); | ||||
|                mx = point.x; | ||||
|                my = point.y; | ||||
| 
 | ||||
|             [NSApp sendEvent: event]; | ||||
|                gotmouseevent = YES; | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|          case NSLeftMouseUp: | ||||
|          case NSOtherMouseUp: | ||||
|          case NSRightMouseUp: | ||||
|             if ([NSApp isActive]) | ||||
|                handle_mouse_enter(frame, view, point, &mx, &my, &buttons); | ||||
|                handle_mouse_enter(); | ||||
| 
 | ||||
|             if (_mouse_on) { | ||||
|                buttons &= ~((event_type == NSLeftMouseUp) ? 0x1 : 0); | ||||
|                buttons &= ~((event_type == NSRightMouseUp) ? 0x2 : 0); | ||||
|                buttons &= ~((event_type == NSOtherMouseUp) ? 0x4 : 0); | ||||
| 
 | ||||
|             [NSApp sendEvent: event]; | ||||
|                mx = point.x; | ||||
|                my = point.y; | ||||
| 
 | ||||
|                gotmouseevent = YES; | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|          case NSLeftMouseDragged: | ||||
|          case NSRightMouseDragged: | ||||
|          case NSOtherMouseDragged: | ||||
|          case NSMouseMoved: | ||||
|             if ([NSApp isActive]) | ||||
|                handle_mouse_enter(frame, view, point, &mx, &my, &buttons); | ||||
|             if ([NSApp isActive] && [view mouse:point inRect:[view frame]]) | ||||
|                handle_mouse_enter(); | ||||
| 
 | ||||
|             if (_mouse_on) { | ||||
|                dx += [event deltaX]; | ||||
|                dy += [event deltaY]; | ||||
| 
 | ||||
|                mx = point.x; | ||||
|             my = frame.size.height - point.y; | ||||
|                my = point.y; | ||||
| 
 | ||||
|             [NSApp sendEvent: event]; | ||||
|                gotmouseevent = YES; | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|          case NSScrollWheel: | ||||
|             if (_mouse_on) | ||||
|                dz += [event deltaY]; | ||||
| 
 | ||||
|             mx = point.x; | ||||
|             my = point.y; | ||||
| 
 | ||||
|             gotmouseevent = YES; | ||||
|             break; | ||||
| 
 | ||||
|          case NSMouseEntered: | ||||
|             if (([event trackingNumber] == osx_mouse_tracking_rect) && ([NSApp isActive])) { | ||||
|                if (handle_mouse_enter(frame, view, point, &mx, &my, &buttons)) | ||||
|             if ([event window] == osx_window && | ||||
|                 [event trackingNumber] == osx_mouse_tracking_rect) { | ||||
|                handle_mouse_enter(); | ||||
| 
 | ||||
|                if (_mouse_on) { | ||||
|                   mx = point.x; | ||||
|                   my = point.y; | ||||
|                   gotmouseevent = YES; | ||||
|                } | ||||
|             [NSApp sendEvent: event]; | ||||
|             } | ||||
|             break; | ||||
| 
 | ||||
|          case NSMouseExited: | ||||
|             if ([event trackingNumber] == osx_mouse_tracking_rect) { | ||||
|                if (handle_mouse_leave()) | ||||
|             if (handle_mouse_leave()) { | ||||
|                mx = point.x; | ||||
|                my = point.y; | ||||
|                gotmouseevent = YES; | ||||
|             } | ||||
|             [NSApp sendEvent: event]; | ||||
|             break; | ||||
| 
 | ||||
|          case NSAppKitDefined: | ||||
|             switch ([event subtype]) { | ||||
|                case NSApplicationActivatedEventType: | ||||
|                   if (osx_window) { | ||||
|                      [osx_window invalidateCursorRectsForView: [osx_window contentView]]; | ||||
|                      [osx_window invalidateCursorRectsForView:view]; | ||||
|                      if (_keyboard_installed) | ||||
|                         osx_keyboard_focused(TRUE, 0); | ||||
| 
 | ||||
|                      handle_mouse_enter(frame, view, point, &mx, &my, &buttons); | ||||
|                      handle_mouse_enter(); | ||||
| 
 | ||||
|                      if (_mouse_on) { | ||||
|                         mx = point.x; | ||||
|                         my = point.y; | ||||
|                         gotmouseevent = YES; | ||||
|                      } | ||||
|                   } | ||||
|                   _switch_in(); | ||||
|                   break; | ||||
|  | @ -355,6 +368,7 @@ void osx_event_handler() | |||
|                case NSApplicationDeactivatedEventType: | ||||
|                   if (osx_window && _keyboard_installed) | ||||
|                      osx_keyboard_focused(FALSE, 0); | ||||
| 
 | ||||
|                   handle_mouse_leave(); | ||||
|                   _switch_out(); | ||||
|                   break; | ||||
|  | @ -370,20 +384,20 @@ void osx_event_handler() | |||
|                      osx_window_first_expose = FALSE; | ||||
|                      [osx_window setHasShadow: NO]; | ||||
|                      [osx_window setHasShadow: YES]; | ||||
|                      [osx_window invalidateCursorRectsForView: [osx_window contentView]]; | ||||
|                      [osx_window invalidateCursorRectsForView:view]; | ||||
|                   } | ||||
|                   break; | ||||
|             } | ||||
|             [NSApp sendEvent: event]; | ||||
|             break; | ||||
|       } | ||||
| 
 | ||||
|          default: | ||||
|       if (send_event == YES) | ||||
|          [NSApp sendEvent: event]; | ||||
|             break; | ||||
|       } | ||||
|    } | ||||
| 
 | ||||
|       if (gotmouseevent == YES) | ||||
|          osx_mouse_handler(mx, my, dx, dy, dz, buttons); | ||||
|    } | ||||
| 
 | ||||
|    [pool release]; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -227,6 +227,7 @@ add_library(app-lib | |||
|   file/tga_format.cpp | ||||
|   file_selector.cpp | ||||
|   file_system.cpp | ||||
|   filename_formatter.cpp | ||||
|   flatten.cpp | ||||
|   gui_xml.cpp | ||||
|   handle_anidir.cpp | ||||
|  |  | |||
|  | @ -37,6 +37,7 @@ | |||
| #include "app/file/file_formats_manager.h" | ||||
| #include "app/file/palette_file.h" | ||||
| #include "app/file_system.h" | ||||
| #include "app/filename_formatter.h" | ||||
| #include "app/find_widget.h" | ||||
| #include "app/gui_xml.h" | ||||
| #include "app/ini_file.h" | ||||
|  | @ -226,6 +227,7 @@ void App::initialize(const AppOptions& options) | |||
|     bool splitLayersSaveAs = false; | ||||
|     std::string importLayer; | ||||
|     std::string importLayerSaveAs; | ||||
|     std::string filenameFormat; | ||||
| 
 | ||||
|     for (const auto& value : options.values()) { | ||||
|       const AppOptions::Option* opt = value.option(); | ||||
|  | @ -271,6 +273,10 @@ void App::initialize(const AppOptions& options) | |||
|         else if (opt == &options.ignoreEmpty()) { | ||||
|           ignoreEmpty = true; | ||||
|         } | ||||
|         // --filename-format
 | ||||
|         else if (opt == &options.filenameFormat()) { | ||||
|           filenameFormat = value.value(); | ||||
|         } | ||||
|         // --save-as <filename>
 | ||||
|         else if (opt == &options.saveAs()) { | ||||
|           Document* doc = NULL; | ||||
|  | @ -283,30 +289,35 @@ void App::initialize(const AppOptions& options) | |||
|           else { | ||||
|             ctx->setActiveDocument(doc); | ||||
| 
 | ||||
|             std::string format = filenameFormat; | ||||
| 
 | ||||
|             Command* command = CommandsModule::instance()->getCommandByName(CommandId::SaveFileCopyAs); | ||||
|             if (splitLayersSaveAs) { | ||||
|               std::vector<Layer*> layers; | ||||
|               doc->sprite()->getLayersList(layers); | ||||
| 
 | ||||
|               std::string fn, fmt; | ||||
|               if (format.empty()) { | ||||
|                 if (doc->sprite()->totalFrames() > frame_t(1)) | ||||
|                   format = "{path}/{title} ({layer}) {frame}.{extension}"; | ||||
|                 else | ||||
|                   format = "{path}/{title} ({layer}).{extension}"; | ||||
|               } | ||||
| 
 | ||||
|               // For each layer, hide other ones and save the sprite.
 | ||||
|               for (Layer* show : layers) { | ||||
|                 for (Layer* hide : layers) | ||||
|                   hide->setVisible(hide == show); | ||||
| 
 | ||||
|                 std::string frameStr; | ||||
|                 if (doc->sprite()->totalFrames() > frame_t(1)) | ||||
|                   frameStr += " 1"; | ||||
|                 fn = filename_formatter(format, | ||||
|                   value.value(), show->name()); | ||||
|                 fmt = filename_formatter(format, | ||||
|                   value.value(), show->name(), -1, false); | ||||
| 
 | ||||
|                 std::string fn = value.value(); | ||||
|                 fn = | ||||
|                   base::join_path( | ||||
|                     base::get_file_path(fn), | ||||
|                     base::get_file_title(fn)) | ||||
|                   + " (" + show->name() + ")" + frameStr + "." + | ||||
|                   base::get_file_extension(fn); | ||||
| 
 | ||||
|                 static_cast<SaveFileBaseCommand*>(command)->setFilename(fn); | ||||
|                 ctx->executeCommand(command); | ||||
|                 Params params; | ||||
|                 params.set("filename", fn.c_str()); | ||||
|                 params.set("filename-format", fmt.c_str()); | ||||
|                 ctx->executeCommand(command, ¶ms); | ||||
|               } | ||||
|             } | ||||
|             else { | ||||
|  | @ -319,8 +330,10 @@ void App::initialize(const AppOptions& options) | |||
|                   layer->setVisible(layer->name() == importLayerSaveAs); | ||||
|               } | ||||
| 
 | ||||
|               static_cast<SaveFileBaseCommand*>(command)->setFilename(value.value()); | ||||
|               ctx->executeCommand(command); | ||||
|               Params params; | ||||
|               params.set("filename", value.value().c_str()); | ||||
|               params.set("filename-format", format.c_str()); | ||||
|               ctx->executeCommand(command, ¶ms); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|  | @ -387,6 +400,9 @@ void App::initialize(const AppOptions& options) | |||
|           splitLayers = false; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if (m_exporter && !filenameFormat.empty()) | ||||
|       m_exporter->setFilenameFormat(filenameFormat); | ||||
|   } | ||||
| 
 | ||||
|   // Export
 | ||||
|  |  | |||
|  | @ -49,6 +49,7 @@ AppOptions::AppOptions(int argc, const char* argv[]) | |||
|   , m_splitLayers(m_po.add("split-layers").description("Import each layer of the next given sprite as\na separated image in the sheet")) | ||||
|   , m_importLayer(m_po.add("import-layer").requiresValue("<name>").description("Import just one layer of the next given sprite")) | ||||
|   , m_ignoreEmpty(m_po.add("ignore-empty").description("Do not export empty frames/cels")) | ||||
|   , m_filenameFormat(m_po.add("filename-format").requiresValue("<fmt>").description("Special format to generate filenames")) | ||||
|   , m_verbose(m_po.add("verbose").description("Explain what is being done")) | ||||
|   , m_help(m_po.add("help").mnemonic('?').description("Display this help and exits")) | ||||
|   , m_version(m_po.add("version").description("Output version information and exit")) | ||||
|  |  | |||
|  | @ -57,6 +57,7 @@ public: | |||
|   const Option& splitLayers() const { return m_splitLayers; } | ||||
|   const Option& importLayer() const { return m_importLayer; } | ||||
|   const Option& ignoreEmpty() const { return m_ignoreEmpty; } | ||||
|   const Option& filenameFormat() const { return m_filenameFormat; } | ||||
| 
 | ||||
|   bool hasExporterParams() const; | ||||
| 
 | ||||
|  | @ -84,6 +85,7 @@ private: | |||
|   Option& m_splitLayers; | ||||
|   Option& m_importLayer; | ||||
|   Option& m_ignoreEmpty; | ||||
|   Option& m_filenameFormat; | ||||
| 
 | ||||
|   Option& m_verbose; | ||||
|   Option& m_help; | ||||
|  |  | |||
|  | @ -20,6 +20,8 @@ | |||
| #include "config.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "app/commands/cmd_save_file.h" | ||||
| 
 | ||||
| #include "app/app.h" | ||||
| #include "app/commands/command.h" | ||||
| #include "app/commands/params.h" | ||||
|  | @ -79,9 +81,11 @@ private: | |||
|   FileOp* m_fop; | ||||
| }; | ||||
| 
 | ||||
| static void save_document_in_background(Context* context, Document* document, bool mark_as_saved) | ||||
| static void save_document_in_background(Context* context, Document* document, | ||||
|   bool mark_as_saved, const std::string& fn_format) | ||||
| { | ||||
|   base::UniquePtr<FileOp> fop(fop_to_save_document(context, document)); | ||||
|   base::UniquePtr<FileOp> fop(fop_to_save_document(context, document, | ||||
|       fn_format.c_str())); | ||||
|   if (!fop) | ||||
|     return; | ||||
| 
 | ||||
|  | @ -113,25 +117,26 @@ static void save_document_in_background(Context* context, Document* document, bo | |||
| 
 | ||||
| //////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| class SaveFileBaseCommand : public Command { | ||||
| public: | ||||
|   SaveFileBaseCommand(const char* short_name, const char* friendly_name, CommandFlags flags) | ||||
|     : Command(short_name, friendly_name, flags) { | ||||
|   } | ||||
| SaveFileBaseCommand::SaveFileBaseCommand(const char* short_name, const char* friendly_name, CommandFlags flags) | ||||
|   : Command(short_name, friendly_name, flags) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| protected: | ||||
|   void onLoadParams(Params* params) override { | ||||
| void SaveFileBaseCommand::onLoadParams(Params* params) | ||||
| { | ||||
|   m_filename = params->get("filename"); | ||||
|   } | ||||
|   m_filenameFormat = params->get("filename-format"); | ||||
| } | ||||
| 
 | ||||
|   // Returns true if there is a current sprite to save.
 | ||||
|   // [main thread]
 | ||||
|   bool onEnabled(Context* context) override { | ||||
| // Returns true if there is a current sprite to save.
 | ||||
| // [main thread]
 | ||||
| bool SaveFileBaseCommand::onEnabled(Context* context) | ||||
| { | ||||
|   return context->checkFlags(ContextFlags::ActiveDocumentIsWritable); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|   void saveAsDialog(const ContextReader& reader, const char* dlgTitle, bool markAsSaved) | ||||
|   { | ||||
| void SaveFileBaseCommand::saveAsDialog(const ContextReader& reader, const char* dlgTitle, bool markAsSaved) | ||||
| { | ||||
|   const Document* document = reader.document(); | ||||
|   std::string filename; | ||||
| 
 | ||||
|  | @ -190,17 +195,19 @@ protected: | |||
|     m_selectedFilename = filename; | ||||
| 
 | ||||
|     // Save the document
 | ||||
|       save_document_in_background(writer.context(), documentWriter, markAsSaved); | ||||
|     save_document_in_background(writer.context(), documentWriter, | ||||
|       markAsSaved, m_filenameFormat); | ||||
| 
 | ||||
|     if (documentWriter->isModified()) | ||||
|       documentWriter->setFilename(oldFilename); | ||||
| 
 | ||||
|     update_screen_for_document(documentWriter); | ||||
|   } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|   static bool confirmReadonly(const std::string& filename) | ||||
|   { | ||||
| //static
 | ||||
| bool SaveFileBaseCommand::confirmReadonly(const std::string& filename) | ||||
| { | ||||
|   if (!base::has_readonly_attr(filename)) | ||||
|     return true; | ||||
| 
 | ||||
|  | @ -213,11 +220,9 @@ protected: | |||
|   } | ||||
|   else | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|   std::string m_filename; | ||||
|   std::string m_selectedFilename; | ||||
| }; | ||||
| //////////////////////////////////////////////////////////////////////
 | ||||
| 
 | ||||
| class SaveFileCommand : public SaveFileBaseCommand { | ||||
| public: | ||||
|  | @ -249,7 +254,8 @@ void SaveFileCommand::onExecute(Context* context) | |||
|     if (!confirmReadonly(documentWriter->filename())) | ||||
|       return; | ||||
| 
 | ||||
|     save_document_in_background(context, documentWriter, true); | ||||
|     save_document_in_background(context, documentWriter, true, | ||||
|       m_filenameFormat.c_str()); | ||||
|     update_screen_for_document(documentWriter); | ||||
|   } | ||||
|   // If the document isn't associated to a file, we must to show the
 | ||||
|  |  | |||
|  | @ -35,10 +35,6 @@ namespace app { | |||
|       return m_selectedFilename; | ||||
|     } | ||||
| 
 | ||||
|     void setFilename(const std::string& fn) { | ||||
|       m_filename = fn; | ||||
|     } | ||||
| 
 | ||||
|   protected: | ||||
|     void onLoadParams(Params* params) override; | ||||
|     bool onEnabled(Context* context) override; | ||||
|  | @ -48,6 +44,7 @@ namespace app { | |||
|     static bool confirmReadonly(const std::string& filename); | ||||
| 
 | ||||
|     std::string m_filename; | ||||
|     std::string m_filenameFormat; | ||||
|     std::string m_selectedFilename; | ||||
|   }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ | |||
| #include "app/console.h" | ||||
| #include "app/document.h" | ||||
| #include "app/file/file.h" | ||||
| #include "app/filename_formatter.h" | ||||
| #include "app/ui_context.h" | ||||
| #include "base/convert_to.h" | ||||
| #include "base/path.h" | ||||
|  | @ -272,24 +273,28 @@ void DocumentExporter::captureSamples(Samples& samples) | |||
|     Document* doc = item.doc; | ||||
|     Sprite* sprite = doc->sprite(); | ||||
|     Layer* layer = item.layer; | ||||
|     bool hasFrames = (doc->sprite()->totalFrames() > frame_t(1)); | ||||
|     bool hasLayer = (layer != NULL); | ||||
| 
 | ||||
|     std::string format = m_filenameFormat; | ||||
|     if (format.empty()) { | ||||
|       if (hasFrames && hasLayer) | ||||
|         format = "{title} ({layer}) {frame}.{extension}"; | ||||
|       else if (hasFrames) | ||||
|         format = "{title} {frame}.{extension}"; | ||||
|       else if (hasLayer) | ||||
|         format = "{title} ({layer}).{extension}"; | ||||
|       else | ||||
|         format = "{fullname}"; | ||||
|     } | ||||
| 
 | ||||
|     for (frame_t frame=frame_t(0); | ||||
|          frame<sprite->totalFrames(); ++frame) { | ||||
|       std::string filename = doc->filename(); | ||||
| 
 | ||||
|       if (sprite->totalFrames() > frame_t(1)) { | ||||
|         std::string path = base::get_file_path(filename); | ||||
|         std::string title = base::get_file_title(filename); | ||||
|         if (layer) { | ||||
|           title += " ("; | ||||
|           title += layer->name(); | ||||
|           title += ") "; | ||||
|         } | ||||
| 
 | ||||
|         filename = base::join_path(path, title + | ||||
|             base::convert_to<std::string>((int)frame + 1) | ||||
|             + "." + base::get_file_extension(filename)); | ||||
|       } | ||||
|       std::string filename = | ||||
|         filename_formatter(format, | ||||
|           doc->filename(), | ||||
|           layer ? layer->name(): "", | ||||
|           (sprite->totalFrames() > frame_t(1)) ? frame: frame_t(-1)); | ||||
| 
 | ||||
|       Sample sample(doc, sprite, layer, frame, filename); | ||||
| 
 | ||||
|  |  | |||
|  | @ -93,6 +93,10 @@ namespace app { | |||
|       m_ignoreEmptyCels = ignore; | ||||
|     } | ||||
| 
 | ||||
|     void setFilenameFormat(const std::string& format) { | ||||
|       m_filenameFormat = format; | ||||
|     } | ||||
| 
 | ||||
|     void addDocument(Document* document, doc::Layer* layer = NULL) { | ||||
|       m_documents.push_back(Item(document, layer)); | ||||
|     } | ||||
|  | @ -133,6 +137,7 @@ namespace app { | |||
|     ScaleMode m_scaleMode; | ||||
|     bool m_ignoreEmptyCels; | ||||
|     Items m_documents; | ||||
|     std::string m_filenameFormat; | ||||
| 
 | ||||
|     DISABLE_COPYING(DocumentExporter); | ||||
|   }; | ||||
|  |  | |||
|  | @ -29,6 +29,7 @@ | |||
| #include "app/file/file_formats_manager.h" | ||||
| #include "app/file/format_options.h" | ||||
| #include "app/file/split_filename.h" | ||||
| #include "app/filename_formatter.h" | ||||
| #include "app/modules/gui.h" | ||||
| #include "app/modules/palettes.h" | ||||
| #include "app/ui/status_bar.h" | ||||
|  | @ -120,7 +121,8 @@ int save_document(Context* context, doc::Document* document) | |||
|   ASSERT(dynamic_cast<app::Document*>(document)); | ||||
| 
 | ||||
|   int ret; | ||||
|   FileOp* fop = fop_to_save_document(context, static_cast<app::Document*>(document)); | ||||
|   FileOp* fop = fop_to_save_document(context, | ||||
|     static_cast<app::Document*>(document), ""); | ||||
|   if (!fop) | ||||
|     return -1; | ||||
| 
 | ||||
|  | @ -235,7 +237,7 @@ done:; | |||
|   return fop; | ||||
| } | ||||
| 
 | ||||
| FileOp* fop_to_save_document(Context* context, Document* document) | ||||
| FileOp* fop_to_save_document(Context* context, Document* document, const char* fn_format_arg) | ||||
| { | ||||
|   FileOp *fop; | ||||
|   bool fatal; | ||||
|  | @ -359,26 +361,59 @@ FileOp* fop_to_save_document(Context* context, Document* document) | |||
|   if (fop->format->support(FILE_SUPPORT_SEQUENCES)) { | ||||
|     fop_prepare_for_sequence(fop); | ||||
| 
 | ||||
|     // To save one frame
 | ||||
|     if (fop->document->sprite()->totalFrames() == 1) { | ||||
|       fop->seq.filename_list.push_back(fop->document->filename()); | ||||
|     } | ||||
|     // To save more frames
 | ||||
|     else { | ||||
|       std::string left, right; | ||||
|       int width, start_from; | ||||
|     std::string fn = fop->document->filename(); | ||||
|     std::string fn_format = fn_format_arg; | ||||
|     bool default_format = false; | ||||
| 
 | ||||
|       start_from = split_filename(fop->document->filename().c_str(), left, right, width); | ||||
|     if (fn_format.empty()) { | ||||
|       if (fop->document->sprite()->totalFrames() == 1) | ||||
|         fn_format = "{fullname}"; | ||||
|       else { | ||||
|         fn_format = "{path}/{title}{frame}.{extension}"; | ||||
|         default_format = true; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     // Save one frame
 | ||||
|     if (fop->document->sprite()->totalFrames() == 1) { | ||||
|       fn = filename_formatter(fn_format, fn); | ||||
|       fop->seq.filename_list.push_back(fn); | ||||
|     } | ||||
|     // Save multiple frames
 | ||||
|     else { | ||||
|       int width = 0; | ||||
|       int start_from = 0; | ||||
| 
 | ||||
|       if (default_format) { | ||||
|         std::string left, right; | ||||
|         start_from = split_filename(fn.c_str(), left, right, width); | ||||
|         if (start_from < 0) { | ||||
|           start_from = 1; | ||||
|           width = 1; | ||||
|         } | ||||
|         else { | ||||
|           fn = left; | ||||
|           fn += right; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       std::vector<char> buf(32); | ||||
|       std::sprintf(&buf[0], "{frame%0*d}", width, 0); | ||||
|       if (default_format) | ||||
|         fn_format = set_frame_format(fn_format, &buf[0]); | ||||
|       else if (fop->document->sprite()->totalFrames() > 1) | ||||
|         fn_format = add_frame_format(fn_format, &buf[0]); | ||||
| 
 | ||||
|       printf("start_from = %d\n", start_from); | ||||
|       printf("fn_format = %s\n", fn_format.c_str()); | ||||
|       printf("fn = %s\n", fn.c_str()); | ||||
| 
 | ||||
|       for (frame_t frame(0); frame<fop->document->sprite()->totalFrames(); ++frame) { | ||||
|         // Get the name for this frame
 | ||||
|         char buf[4096]; | ||||
|         sprintf(buf, "%s%0*d%s", left.c_str(), width, start_from+frame, right.c_str()); | ||||
|         fop->seq.filename_list.push_back(buf); | ||||
|         std::string frame_fn = | ||||
|           filename_formatter(fn_format, fn, "", start_from+frame); | ||||
| 
 | ||||
|         printf("frame_fn = %s\n", frame_fn.c_str()); | ||||
|         fop->seq.filename_list.push_back(frame_fn); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -134,7 +134,7 @@ namespace app { | |||
|   // Low-level routines to load/save documents.
 | ||||
| 
 | ||||
|   FileOp* fop_to_load_document(Context* context, const char* filename, int flags); | ||||
|   FileOp* fop_to_save_document(Context* context, Document* document); | ||||
|   FileOp* fop_to_save_document(Context* context, Document* document, const char* fn_format); | ||||
|   void fop_operate(FileOp* fop, IFileOpProgress* progress); | ||||
|   void fop_done(FileOp* fop); | ||||
|   void fop_stop(FileOp* fop); | ||||
|  |  | |||
|  | @ -0,0 +1,105 @@ | |||
| /* Aseprite
 | ||||
|  * Copyright (C) 2001-2015  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 | ||||
|  */ | ||||
| 
 | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "config.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "app/filename_formatter.h" | ||||
| 
 | ||||
| #include "base/convert_to.h" | ||||
| #include "base/path.h" | ||||
| #include "base/replace_string.h" | ||||
| 
 | ||||
| #include <vector> | ||||
| 
 | ||||
| namespace app { | ||||
| 
 | ||||
| std::string filename_formatter( | ||||
|   const std::string& format, | ||||
|   const std::string& filename, | ||||
|   const std::string& layerName, | ||||
|   int frame, bool replaceFrame) | ||||
| { | ||||
|   std::string output = format; | ||||
|   base::replace_string(output, "{fullname}", filename); | ||||
|   base::replace_string(output, "{path}", base::get_file_path(filename)); | ||||
|   base::replace_string(output, "{name}", base::get_file_name(filename)); | ||||
|   base::replace_string(output, "{title}", base::get_file_title(filename)); | ||||
|   base::replace_string(output, "{extension}", base::get_file_extension(filename)); | ||||
|   base::replace_string(output, "{layer}", layerName); | ||||
| 
 | ||||
|   if (replaceFrame) { | ||||
|     size_t i = output.find("{frame"); | ||||
|     if (i != std::string::npos) { | ||||
|       size_t j = output.find("}", i+6); | ||||
|       if (j != std::string::npos) { | ||||
|         std::string from = output.substr(i, j - i + 1); | ||||
|         if (frame >= 0) { | ||||
|           std::vector<char> to(32); | ||||
|           int offset = std::strtol(from.c_str()+6, NULL, 10); | ||||
| 
 | ||||
|           std::sprintf(&to[0], "%0*d", (int(j)-int(i+6)), frame + offset); | ||||
|           base::replace_string(output, from, &to[0]); | ||||
|         } | ||||
|         else | ||||
|           base::replace_string(output, from, ""); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return output; | ||||
| } | ||||
| 
 | ||||
| std::string set_frame_format( | ||||
|   const std::string& format, | ||||
|   const std::string& newFrameFormat) | ||||
| { | ||||
|   std::string output = format; | ||||
| 
 | ||||
|   size_t i = output.find("{frame"); | ||||
|   if (i != std::string::npos) { | ||||
|     size_t j = output.find("}", i+6); | ||||
|     if (j != std::string::npos) { | ||||
|       output.replace(i, j - i + 1, newFrameFormat); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return output; | ||||
| } | ||||
| 
 | ||||
| std::string add_frame_format( | ||||
|   const std::string& format, | ||||
|   const std::string& newFrameFormat) | ||||
| { | ||||
|   std::string output = format; | ||||
| 
 | ||||
|   size_t i = output.find("{frame"); | ||||
|   if (i == std::string::npos) { | ||||
|     output = | ||||
|       base::join_path( | ||||
|         base::get_file_path(format), | ||||
|         base::get_file_title(format)) | ||||
|       + newFrameFormat + "." +  | ||||
|       base::get_file_extension(format); | ||||
|   } | ||||
| 
 | ||||
|   return output; | ||||
| } | ||||
| 
 | ||||
| } // namespace app
 | ||||
|  | @ -0,0 +1,44 @@ | |||
| /* Aseprite
 | ||||
|  * Copyright (C) 2001-2015  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 APP_FILENAME_FORMATTER_H_INCLUDED | ||||
| #define APP_FILENAME_FORMATTER_H_INCLUDED | ||||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace app { | ||||
| 
 | ||||
|   std::string filename_formatter( | ||||
|     const std::string& format, | ||||
|     const std::string& filename, | ||||
|     const std::string& layerName = "", | ||||
|     int frame = -1, | ||||
|     bool replaceFrame = true); | ||||
| 
 | ||||
|   std::string set_frame_format( | ||||
|     const std::string& format, | ||||
|     const std::string& newFrameFormat); | ||||
| 
 | ||||
|   std::string add_frame_format( | ||||
|     const std::string& format, | ||||
|     const std::string& newFrameFormat); | ||||
| 
 | ||||
| } // namespace app
 | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,142 @@ | |||
| /* Aseprite
 | ||||
|  * Copyright (C) 2001-2015  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 | ||||
|  */ | ||||
| 
 | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "config.h" | ||||
| #endif | ||||
| 
 | ||||
| #include <gtest/gtest.h> | ||||
| 
 | ||||
| #include "app/filename_formatter.h" | ||||
| 
 | ||||
| #include "base/path.h" | ||||
| 
 | ||||
| using namespace app; | ||||
| 
 | ||||
| TEST(FilenameFormatter, Basic) | ||||
| { | ||||
|   EXPECT_EQ("C:/temp/file.png", | ||||
|     filename_formatter("{fullname}", | ||||
|       "C:/temp/file.png")); | ||||
| 
 | ||||
|   EXPECT_EQ("file.png", | ||||
|     filename_formatter("{name}", | ||||
|       "C:/temp/file.png")); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/other.png", | ||||
|     filename_formatter("{path}/other.png", | ||||
|       "C:/temp/file.png")); | ||||
| } | ||||
| 
 | ||||
| TEST(FilenameFormatter, WithoutFrame) | ||||
| { | ||||
|   EXPECT_EQ("C:/temp/file.png", | ||||
|     filename_formatter("{path}/{title}.png", | ||||
|       "C:/temp/file.ase")); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file.png", | ||||
|     filename_formatter("{path}/{title}{frame}.{extension}", | ||||
|       "C:/temp/file.png")); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file{frame}.png", | ||||
|     filename_formatter("{path}/{title}{frame}.{extension}", | ||||
|       "C:/temp/file.png", "", -1, false)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file (Background).png", | ||||
|     filename_formatter("{path}/{title} ({layer}).{extension}", | ||||
|       "C:/temp/file.png", "Background")); | ||||
| } | ||||
| 
 | ||||
| TEST(FilenameFormatter, WithFrame) | ||||
| { | ||||
|   EXPECT_EQ("C:/temp/file0.png", | ||||
|     filename_formatter("{path}/{title}{frame}.{extension}", | ||||
|       "C:/temp/file.png", "", 0)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file1.png", | ||||
|     filename_formatter("{path}/{title}{frame}.{extension}", | ||||
|       "C:/temp/file.png", "", 1)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file10.png", | ||||
|     filename_formatter("{path}/{title}{frame}.{extension}", | ||||
|       "C:/temp/file.png", "", 10)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file0.png", | ||||
|     filename_formatter("{path}/{title}{frame0}.{extension}", | ||||
|       "C:/temp/file.png", "", 0)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file1.png", | ||||
|     filename_formatter("{path}/{title}{frame1}.{extension}", | ||||
|       "C:/temp/file.png", "", 0)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file2.png", | ||||
|     filename_formatter("{path}/{title}{frame1}.{extension}", | ||||
|       "C:/temp/file.png", "", 1)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file00.png", | ||||
|     filename_formatter("{path}/{title}{frame00}.{extension}", | ||||
|       "C:/temp/file.png", "", 0)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file01.png", | ||||
|     filename_formatter("{path}/{title}{frame01}.{extension}", | ||||
|       "C:/temp/file.png", "", 0)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file002.png", | ||||
|     filename_formatter("{path}/{title}{frame000}.{extension}", | ||||
|       "C:/temp/file.png", "", 2)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file0032.png", | ||||
|     filename_formatter("{path}/{title}{frame0032}.{extension}", | ||||
|       "C:/temp/file.png", "", 0)); | ||||
| 
 | ||||
|   EXPECT_EQ("C:/temp/file-Background-2.png", | ||||
|     filename_formatter("{path}/{title}-{layer}-{frame}.{extension}", | ||||
|       "C:/temp/file.png", "Background", 2)); | ||||
| } | ||||
| 
 | ||||
| TEST(SetFrameFormat, Tests) | ||||
| { | ||||
|   EXPECT_EQ("{path}/{title}{frame1}.{extension}", | ||||
|     set_frame_format("{path}/{title}{frame}.{extension}", | ||||
|       "{frame1}")); | ||||
| 
 | ||||
|   EXPECT_EQ("{path}/{title}{frame01}.{extension}", | ||||
|     set_frame_format("{path}/{title}{frame}.{extension}", | ||||
|       "{frame01}")); | ||||
| 
 | ||||
|   EXPECT_EQ("{path}/{title}{frame}.{extension}", | ||||
|     set_frame_format("{path}/{title}{frame01}.{extension}", | ||||
|       "{frame}")); | ||||
| } | ||||
| 
 | ||||
| TEST(AddFrameFormat, Tests) | ||||
| { | ||||
|   EXPECT_EQ(base::fix_path_separators("{path}/{title}{frame001}.{extension}"), | ||||
|     add_frame_format("{path}/{title}.{extension}", | ||||
|       "{frame001}")); | ||||
| 
 | ||||
|   EXPECT_EQ("{path}/{title}{frame1}.{extension}", | ||||
|     add_frame_format("{path}/{title}{frame1}.{extension}", | ||||
|       "{frame001}")); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
|   ::testing::InitGoogleTest(&argc, argv); | ||||
|   return RUN_ALL_TESTS(); | ||||
| } | ||||
|  | @ -800,7 +800,7 @@ gfx::Point Editor::autoScroll(MouseMessage* msg, AutoScroll dir, bool blit_valid | |||
|     } | ||||
|     setEditorScroll(scroll, blit_valid_rgn); | ||||
| 
 | ||||
| #ifdef WIN32 | ||||
| #if defined(WIN32) || defined(__APPLE__) | ||||
|     mousePos -= delta; | ||||
|     ui::set_mouse_position(mousePos); | ||||
| #endif | ||||
|  |  | |||
|  | @ -32,6 +32,7 @@ set(BASE_SOURCES | |||
|   mutex.cpp | ||||
|   path.cpp | ||||
|   program_options.cpp | ||||
|   replace_string.cpp | ||||
|   serialization.cpp | ||||
|   sha1.cpp | ||||
|   sha1_rfc3174.c | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| Copyright (c) 2001-2014 David Capello | ||||
| Copyright (c) 2001-2015 David Capello | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining | ||||
| a copy of this software and associated documentation files (the | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| # Aseprite Base Library | ||||
| *Copyright (C) 2001-2013 David Capello* | ||||
| *Copyright (C) 2001-2015 David Capello* | ||||
| 
 | ||||
| > Distributed under [MIT license](LICENSE.txt) | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,33 @@ | |||
| // Aseprite Base Library
 | ||||
| // Copyright (c) 2001-2015 David Capello
 | ||||
| //
 | ||||
| // This file is released under the terms of the MIT license.
 | ||||
| // Read LICENSE.txt for more information.
 | ||||
| 
 | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include "config.h" | ||||
| #endif | ||||
| 
 | ||||
| #include "base/replace_string.h" | ||||
| 
 | ||||
| namespace base { | ||||
| 
 | ||||
| void replace_string( | ||||
|   std::string& subject, | ||||
|   const std::string& replace_this, | ||||
|   const std::string& with_that) | ||||
| { | ||||
|   if (replace_this.empty())     // Do nothing case
 | ||||
|     return; | ||||
| 
 | ||||
|   size_t i = 0; | ||||
|   while (true) { | ||||
|     i = subject.find(replace_this, i); | ||||
|     if (i == std::string::npos) | ||||
|       break; | ||||
|     subject.replace(i, replace_this.size(), with_that); | ||||
|     i += with_that.size(); | ||||
|   } | ||||
| } | ||||
|    | ||||
| } // namespace base
 | ||||
|  | @ -0,0 +1,22 @@ | |||
| // Aseprite Base Library
 | ||||
| // Copyright (c) 2001-2015 David Capello
 | ||||
| //
 | ||||
| // This file is released under the terms of the MIT license.
 | ||||
| // Read LICENSE.txt for more information.
 | ||||
| 
 | ||||
| #ifndef BASE_REPLACE_STRING_H_INCLUDED | ||||
| #define BASE_REPLACE_STRING_H_INCLUDED | ||||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| namespace base { | ||||
| 
 | ||||
|   void replace_string( | ||||
|     std::string& subject, | ||||
|     const std::string& replace_this, | ||||
|     const std::string& with_that); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  | @ -0,0 +1,31 @@ | |||
| // Aseprite Base Library
 | ||||
| // Copyright (c) 2001-2015 David Capello
 | ||||
| //
 | ||||
| // This file is released under the terms of the MIT license.
 | ||||
| // Read LICENSE.txt for more information.
 | ||||
| 
 | ||||
| #include <gtest/gtest.h> | ||||
| 
 | ||||
| #include "base/replace_string.h" | ||||
| 
 | ||||
| inline std::string rs(const std::string& s, const std::string& a, const std::string& b) { | ||||
|   std::string res = s; | ||||
|   base::replace_string(res, a, b); | ||||
|   return res; | ||||
| } | ||||
| 
 | ||||
| TEST(ReplaceString, Basic) | ||||
| { | ||||
|   EXPECT_EQ("", rs("", "", "")); | ||||
|   EXPECT_EQ("aa", rs("ab", "b", "a")); | ||||
|   EXPECT_EQ("abc", rs("accc", "cc", "b")); | ||||
|   EXPECT_EQ("abb", rs("acccc", "cc", "b")); | ||||
|   EXPECT_EQ("aabbbbaabbbb", rs("aabbaabb", "bb", "bbbb")); | ||||
|   EXPECT_EQ("123123123", rs("111", "1", "123")); | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char** argv) | ||||
| { | ||||
|   ::testing::InitGoogleTest(&argc, argv); | ||||
|   return RUN_ALL_TESTS(); | ||||
| } | ||||
|  | @ -42,7 +42,7 @@ | |||
| #define WEBSITE_DOWNLOAD        WEBSITE "download/" | ||||
| #define WEBSITE_CONTRIBUTORS    WEBSITE "contributors/" | ||||
| #define UPDATE_URL              WEBSITE "update/?xml=1" | ||||
| #define COPYRIGHT               "Copyright (C) 2001-2014 David Capello" | ||||
| #define COPYRIGHT               "Copyright (C) 2001-2015 David Capello" | ||||
| 
 | ||||
| #define PRINTF                  verbose_printf | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,7 +23,7 @@ BEGIN | |||
|             VALUE "FileDescription", "Aseprite - Animated sprites editor & pixel art tool" | ||||
|             VALUE "FileVersion", "1,1,0,0" | ||||
|             VALUE "InternalName", "aseprite" | ||||
|             VALUE "LegalCopyright", "Copyright (C) 2001-2014 by David Capello" | ||||
|             VALUE "LegalCopyright", "Copyright (C) 2001-2015 by David Capello" | ||||
|             VALUE "OriginalFilename", "aseprite.exe" | ||||
|             VALUE "ProductName", "ASEPRITE" | ||||
|             VALUE "ProductVersion", "1,1,0,0" | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue