diff --git a/src/apps/icon-o-matic/IconEditorApp.cpp b/src/apps/icon-o-matic/IconEditorApp.cpp index fc8c171172..355f90d0cd 100644 --- a/src/apps/icon-o-matic/IconEditorApp.cpp +++ b/src/apps/icon-o-matic/IconEditorApp.cpp @@ -12,11 +12,7 @@ #include #include -#include -#include -#include #include -#include #include #include #include @@ -24,30 +20,10 @@ #include "support_settings.h" -#include "AttributeSaver.h" #include "AutoLocker.h" -#include "BitmapExporter.h" -#include "BitmapSetSaver.h" -#include "CommandStack.h" #include "Defines.h" -#include "Document.h" -#include "FlatIconExporter.h" -#include "FlatIconFormat.h" -#include "FlatIconImporter.h" -#include "Icon.h" #include "MainWindow.h" -#include "MessageExporter.h" -#include "MessageImporter.h" -#include "MessengerSaver.h" -#include "NativeSaver.h" -#include "PathContainer.h" -#include "RDefExporter.h" #include "SavePanel.h" -#include "ShapeContainer.h" -#include "SimpleFileSaver.h" -#include "SourceExporter.h" -#include "SVGExporter.h" -#include "SVGImporter.h" #undef B_TRANSLATE_CONTEXT @@ -60,33 +36,36 @@ static const char* kAppSig = "application/x-vnd.haiku-icon_o_matic"; IconEditorApp::IconEditorApp() - : BApplication(kAppSig), - fMainWindow(NULL), - fDocument(new Document("test")), + : + BApplication(kAppSig), + fWindowCount(0), + fLastWindowFrame(50, 50, 900, 750), - fOpenPanel(NULL), - fSavePanel(NULL), + fOpenPanel(NULL), + fSavePanel(NULL), - fLastOpenPath(""), - fLastSavePath(""), - fLastExportPath(""), - - fMessageAfterSave(NULL) + fLastOpenPath(""), + fLastSavePath(""), + fLastExportPath("") { + // create file panels + BMessenger messenger(this, this); + BMessage message(B_REFS_RECEIVED); + fOpenPanel = new BFilePanel(B_OPEN_PANEL, &messenger, NULL, B_FILE_NODE, + true, &message); + + message.what = MSG_SAVE_AS; + fSavePanel = new SavePanel("save panel", &messenger, NULL, B_FILE_NODE + | B_DIRECTORY_NODE | B_SYMLINK_NODE, false, &message); + + _RestoreSettings(); } IconEditorApp::~IconEditorApp() { - // NOTE: it is important that the GUI has been deleted - // at this point, so that all the listener/observer - // stuff is properly detached - delete fDocument; - delete fOpenPanel; delete fSavePanel; - - delete fMessageAfterSave; } @@ -96,15 +75,33 @@ IconEditorApp::~IconEditorApp() bool IconEditorApp::QuitRequested() { - if (!_CheckSaveIcon(CurrentMessage())) + // Run the QuitRequested() hook in each window's own thread. Otherwise + // the BAlert which a window shows when an icon is not saved will not + // repaint the window. (BAlerts check which thread is running Go() and + // will repaint windows when it's a BWindow.) + bool quit = true; + for (int32 i = 0; BWindow* window = WindowAt(i); i++) { + if (!window->Lock()) + continue; + // Try to cast the window while the pointer must be valid. + MainWindow* mainWindow = dynamic_cast(window); + window->Unlock(); + if (mainWindow == NULL) + continue; + BMessenger messenger(window, window); + BMessage reply; + if (messenger.SendMessage(B_QUIT_REQUESTED, &reply) != B_OK) + continue; + bool result; + if (reply.FindBool("result", &result) == B_OK && !result) + quit = false; + } + + if (!quit) return false; _StoreSettings(); - fMainWindow->Lock(); - fMainWindow->Quit(); - fMainWindow = NULL; - return true; } @@ -114,7 +111,7 @@ IconEditorApp::MessageReceived(BMessage* message) { switch (message->what) { case MSG_NEW: - _MakeIconEmpty(); + _NewWindow()->Show(); break; case MSG_OPEN: { BMessage openMessage(B_REFS_RECEIVED); @@ -123,80 +120,18 @@ IconEditorApp::MessageReceived(BMessage* message) break; } case MSG_APPEND: { + MainWindow* window; + if (message->FindPointer("window", (void**)&window) != B_OK) + break; BMessage openMessage(B_REFS_RECEIVED); openMessage.AddBool("append", true); + openMessage.AddPointer("window", window); fOpenPanel->SetMessage(&openMessage); fOpenPanel->Show(); break; } - case MSG_SAVE: - case MSG_EXPORT: { - DocumentSaver* saver; - if (message->what == MSG_SAVE) - saver = fDocument->NativeSaver(); - else - saver = fDocument->ExportSaver(); - if (saver != NULL) { - saver->Save(fDocument); - _PickUpActionBeforeSave(); - break; - } // else fall through - } - case MSG_SAVE_AS: - case MSG_EXPORT_AS: { - int32 exportMode; - if (message->FindInt32("export mode", &exportMode) < B_OK) - exportMode = EXPORT_MODE_MESSAGE; - entry_ref ref; - const char* name; - if (message->FindRef("directory", &ref) == B_OK - && message->FindString("name", &name) == B_OK) { - // this message comes from the file panel - BDirectory dir(&ref); - BEntry entry; - if (dir.InitCheck() >= B_OK - && entry.SetTo(&dir, name, true) >= B_OK - && entry.GetRef(&ref) >= B_OK) { - - // create the document saver and remember it for later - DocumentSaver* saver = _CreateSaver(ref, exportMode); - if (saver) { - if (exportMode == EXPORT_MODE_MESSAGE) - fDocument->SetNativeSaver(saver); - else - fDocument->SetExportSaver(saver); - saver->Save(fDocument); - _PickUpActionBeforeSave(); - } - } - _SyncPanels(fSavePanel, fOpenPanel); - } else { - printf("configure file panel\n"); - // configure the file panel - const char* saveText = NULL; - FileSaver* saver = dynamic_cast( - fDocument->NativeSaver()); - if (saver != NULL) - saveText = saver->Ref()->name; - - bool isExportMode = message->what == MSG_EXPORT_AS - || message->what == MSG_EXPORT; - if (isExportMode) { - saver = dynamic_cast( - fDocument->ExportSaver()); - if (saver != NULL && saver->Ref()->name != NULL) - saveText = saver->Ref()->name; - } - - fSavePanel->SetExportMode(isExportMode); -// fSavePanel->Refresh(); - if (saveText != NULL) - fSavePanel->SetSaveText(saveText); - fSavePanel->Show(); - } - break; - } - case B_EDIT_ICON_DATA: { + case B_EDIT_ICON_DATA: + { BMessenger messenger; if (message->FindMessenger("reply to", &messenger) < B_OK) { // required @@ -210,7 +145,41 @@ IconEditorApp::MessageReceived(BMessage* message) data = NULL; size = 0; } - _Open(messenger, data, size); + MainWindow* window = _NewWindow(); + window->Open(messenger, data, size); + window->Show(); + break; + } + case MSG_SAVE_AS: + case MSG_EXPORT_AS: + { + BMessenger messenger; + if (message->FindMessenger("target", &messenger) != B_OK) + break; + + fSavePanel->SetExportMode(message->what == MSG_EXPORT_AS); +// fSavePanel->Refresh(); + const char* saveText; + if (message->FindString("save text", &saveText) == B_OK) + fSavePanel->SetSaveText(saveText); + fSavePanel->SetTarget(messenger); + fSavePanel->Show(); + break; + } + + case MSG_WINDOW_CLOSED: + { + fWindowCount--; + if (fWindowCount == 0) + PostMessage(B_QUIT_REQUESTED); + BMessage settings; + if (message->FindMessage("settings", &settings) == B_OK) + fLastWindowSettings = settings; + BRect frame; + if (message->FindRect("window frame", &frame) == B_OK) { + fLastWindowFrame = frame; + fLastWindowFrame.OffsetBy(-10, -10); + } break; } @@ -224,22 +193,9 @@ IconEditorApp::MessageReceived(BMessage* message) void IconEditorApp::ReadyToRun() { - // create file panels - BMessenger messenger(this, this); - BMessage message(B_REFS_RECEIVED); - fOpenPanel = new BFilePanel(B_OPEN_PANEL, &messenger, NULL, B_FILE_NODE, - true, &message); - - message.what = MSG_SAVE_AS; - fSavePanel = new SavePanel("save panel", &messenger, NULL, - B_FILE_NODE | B_DIRECTORY_NODE | B_SYMLINK_NODE, false, &message); - // create main window - BMessage settings('stns'); - _RestoreSettings(settings); - - fMainWindow = new MainWindow(this, fDocument, &settings); - fMainWindow->Show(); + if (fWindowCount == 0) + _NewWindow()->Show(); _InstallDocumentMimeType(); } @@ -248,15 +204,28 @@ IconEditorApp::ReadyToRun() void IconEditorApp::RefsReceived(BMessage* message) { - // TODO: multiple documents (iterate over refs) bool append; if (message->FindBool("append", &append) < B_OK) append = false; entry_ref ref; - if (message->FindRef("refs", &ref) == B_OK) - _Open(ref, append); + if (append) { + MainWindow* window; + if (message->FindPointer("window", (void**)&window) != B_OK) + return; + if (!window->Lock()) + return; + for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) + window->Open(ref, true); + window->Unlock(); + } else { + for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { + MainWindow* window = _NewWindow(); + window->Open(ref, false); + window->Show(); + } + } - if (fOpenPanel && fSavePanel) + if (fOpenPanel != NULL && fSavePanel != NULL) _SyncPanels(fOpenPanel, fSavePanel); } @@ -267,357 +236,29 @@ IconEditorApp::ArgvReceived(int32 argc, char** argv) if (argc < 2) return; - // TODO: multiple documents (iterate over argv) entry_ref ref; - if (get_ref_for_path(argv[1], &ref) == B_OK) - _Open(ref); + + for (int32 i = 1; i < argc; i++) { + if (get_ref_for_path(argv[i], &ref) == B_OK) { + MainWindow* window = _NewWindow(); + window->Open(ref); + window->Show(); + } + } } // #pragma mark - -bool -IconEditorApp::_CheckSaveIcon(const BMessage* currentMessage) +MainWindow* +IconEditorApp::_NewWindow() { - if (fDocument->IsEmpty() || fDocument->CommandStack()->IsSaved()) - return true; - - BAlert* alert = new BAlert("save", - B_TRANSLATE("Save changes to current icon?"), B_TRANSLATE("Discard"), - B_TRANSLATE("Cancel"), B_TRANSLATE("Save")); - int32 choice = alert->Go(); - switch (choice) { - case 0: - // discard - return true; - case 1: - // cancel - return false; - case 2: - default: - // cancel (save first) but pick what we were doing before - PostMessage(MSG_SAVE); - if (currentMessage) { - delete fMessageAfterSave; - fMessageAfterSave = new BMessage(*currentMessage); - } - return false; - } -} - - -void -IconEditorApp::_PickUpActionBeforeSave() -{ - if (fDocument->WriteLock()) { - fDocument->CommandStack()->Save(); - fDocument->WriteUnlock(); - } - - if (fMessageAfterSave == NULL) - return; - - PostMessage(fMessageAfterSave); - delete fMessageAfterSave; - fMessageAfterSave = NULL; -} - - -// #pragma mark - - - -void -IconEditorApp::_MakeIconEmpty() -{ - if (!_CheckSaveIcon(CurrentMessage())) - return; - - bool mainWindowLocked = fMainWindow && fMainWindow->Lock(); - - AutoWriteLocker locker(fDocument); - - if (fMainWindow) - fMainWindow->MakeEmpty(); - - fDocument->MakeEmpty(); - - locker.Unlock(); - - if (mainWindowLocked) - fMainWindow->Unlock(); -} - - -void -IconEditorApp::_Open(const entry_ref& ref, bool append) -{ - if (!_CheckSaveIcon(CurrentMessage())) - return; - - BFile file(&ref, B_READ_ONLY); - if (file.InitCheck() < B_OK) - return; - - Icon* icon; - if (append) - icon = new (nothrow) Icon(*fDocument->Icon()); - else - icon = new (nothrow) Icon(); - - if (!icon) - return; - - enum { - REF_NONE = 0, - REF_MESSAGE, - REF_FLAT, - REF_FLAT_ATTR, - REF_SVG - }; - uint32 refMode = REF_NONE; - - // try different file types - FlatIconImporter flatImporter; - status_t ret = flatImporter.Import(icon, &file); - if (ret >= B_OK) { - refMode = REF_FLAT; - } else { - file.Seek(0, SEEK_SET); - MessageImporter msgImporter; - ret = msgImporter.Import(icon, &file); - if (ret >= B_OK) { - refMode = REF_MESSAGE; - } else { - file.Seek(0, SEEK_SET); - SVGImporter svgImporter; - ret = svgImporter.Import(icon, &ref); - if (ret >= B_OK) { - refMode = REF_SVG; - } else { - // fall back to flat icon format but use the icon attribute - ret = B_OK; - attr_info attrInfo; - if (file.GetAttrInfo(kVectorAttrNodeName, &attrInfo) == B_OK) { - if (attrInfo.type != B_VECTOR_ICON_TYPE) - ret = B_ERROR; - // If the attribute is there, we must succeed in reading - // an icon! Otherwise we may overwrite an existing icon - // when the user saves. - uint8* buffer = NULL; - if (ret == B_OK) { - buffer = new(nothrow) uint8[attrInfo.size]; - if (buffer == NULL) - ret = B_NO_MEMORY; - } - if (ret == B_OK) { - ssize_t bytesRead = file.ReadAttr(kVectorAttrNodeName, - B_VECTOR_ICON_TYPE, 0, buffer, attrInfo.size); - if (bytesRead != (ssize_t)attrInfo.size) { - ret = bytesRead < 0 ? (status_t)bytesRead - : B_IO_ERROR; - } - } - if (ret == B_OK) { - ret = flatImporter.Import(icon, buffer, attrInfo.size); - if (ret == B_OK) - refMode = REF_FLAT_ATTR; - } - - delete[] buffer; - } else { - // If there is no icon attribute, simply fall back - // to creating an icon for this file. TODO: We may or may - // not want to display an alert asking the user if that is - // what he wants to do. - refMode = REF_FLAT_ATTR; - } - } - } - } - - if (ret < B_OK) { - // inform user of failure at this point - BString helper(B_TRANSLATE("Opening the document failed!")); - helper << "\n\n" << B_TRANSLATE("Error: ") << strerror(ret); - BAlert* alert = new BAlert( - B_TRANSLATE_WITH_CONTEXT("bad news", "Title of error alert"), - helper.String(), - B_TRANSLATE_WITH_CONTEXT("Bummer", - "Cancel button - error alert"), - NULL, NULL); - // launch alert asynchronously - alert->Go(NULL); - - delete icon; - return; - } - - // keep the mainwindow locked while switching icons - bool mainWindowLocked = fMainWindow && fMainWindow->Lock(); - - AutoWriteLocker locker(fDocument); - - if (mainWindowLocked) - fMainWindow->SetIcon(NULL); - - // incorporate the loaded icon into the document - // (either replace it or append to it) - fDocument->MakeEmpty(!append); - // if append, the document savers are preserved - fDocument->SetIcon(icon); - if (!append) { - // document got replaced, but we have at - // least one ref already - switch (refMode) { - case REF_MESSAGE: - fDocument->SetNativeSaver(new NativeSaver(ref)); - break; - case REF_FLAT: - fDocument->SetExportSaver( - new SimpleFileSaver(new FlatIconExporter(), ref)); - break; - case REF_FLAT_ATTR: - fDocument->SetNativeSaver( - new AttributeSaver(ref, kVectorAttrNodeName)); - break; - case REF_SVG: - fDocument->SetExportSaver( - new SimpleFileSaver(new SVGExporter(), ref)); - break; - } - } - - locker.Unlock(); - - if (mainWindowLocked) { - fMainWindow->Unlock(); - // cause the mainwindow to adopt icon in - // it's own thread - fMainWindow->PostMessage(MSG_SET_ICON); - } -} - - -void -IconEditorApp::_Open(const BMessenger& externalObserver, const uint8* data, - size_t size) -{ - if (!_CheckSaveIcon(CurrentMessage())) - return; - - if (!externalObserver.IsValid()) - return; - - Icon* icon = new (nothrow) Icon(); - if (!icon) - return; - - if (data && size > 0) { - // try to open the icon from the provided data - FlatIconImporter flatImporter; - status_t ret = flatImporter.Import(icon, const_cast(data), - size); - // NOTE: the const_cast is a bit ugly, but no harm is done - // the reason is that the LittleEndianBuffer knows read and write - // mode, in this case it is used read-only, and it does not assume - // ownership of the buffer - - if (ret < B_OK) { - // inform user of failure at this point - BString helper(B_TRANSLATE("Opening the icon failed!")); - helper << "\n\n" << B_TRANSLATE("Error: ") << strerror(ret); - BAlert* alert = new BAlert( - B_TRANSLATE_WITH_CONTEXT("bad news", "Title of error alert"), - helper.String(), - B_TRANSLATE_WITH_CONTEXT("Bummer", - "Cancel button - error alert"), - NULL, NULL); - // launch alert asynchronously - alert->Go(NULL); - - delete icon; - return; - } - } - - // keep the mainwindow locked while switching icons - bool mainWindowLocked = fMainWindow && fMainWindow->Lock(); - - AutoWriteLocker locker(fDocument); - - if (mainWindowLocked) - fMainWindow->SetIcon(NULL); - - // incorporate the loaded icon into the document - // (either replace it or append to it) - fDocument->MakeEmpty(); - fDocument->SetIcon(icon); - - fDocument->SetNativeSaver(new MessengerSaver(externalObserver)); - - locker.Unlock(); - - if (mainWindowLocked) { - fMainWindow->Unlock(); - // cause the mainwindow to adopt icon in - // it's own thread - fMainWindow->PostMessage(MSG_SET_ICON); - } -} - - -DocumentSaver* -IconEditorApp::_CreateSaver(const entry_ref& ref, uint32 exportMode) -{ - DocumentSaver* saver; - - switch (exportMode) { - case EXPORT_MODE_FLAT_ICON: - saver = new SimpleFileSaver(new FlatIconExporter(), ref); - break; - - case EXPORT_MODE_ICON_ATTR: - case EXPORT_MODE_ICON_MIME_ATTR: { - const char* attrName - = exportMode == EXPORT_MODE_ICON_ATTR ? - kVectorAttrNodeName : kVectorAttrMimeName; - saver = new AttributeSaver(ref, attrName); - break; - } - - case EXPORT_MODE_ICON_RDEF: - saver = new SimpleFileSaver(new RDefExporter(), ref); - break; - case EXPORT_MODE_ICON_SOURCE: - saver = new SimpleFileSaver(new SourceExporter(), ref); - break; - - case EXPORT_MODE_BITMAP_16: - saver = new SimpleFileSaver(new BitmapExporter(16), ref); - break; - case EXPORT_MODE_BITMAP_32: - saver = new SimpleFileSaver(new BitmapExporter(32), ref); - break; - case EXPORT_MODE_BITMAP_64: - saver = new SimpleFileSaver(new BitmapExporter(64), ref); - break; - - case EXPORT_MODE_BITMAP_SET: - saver = new BitmapSetSaver(ref); - break; - - case EXPORT_MODE_SVG: - saver = new SimpleFileSaver(new SVGExporter(), ref); - break; - - case EXPORT_MODE_MESSAGE: - default: - saver = new NativeSaver(ref); - break; - } - - return saver; + fLastWindowFrame.OffsetBy(10, 10); + MainWindow* window = new MainWindow(fLastWindowFrame, this, + &fLastWindowSettings); + fWindowCount++; + return window; } @@ -687,20 +328,28 @@ IconEditorApp::_StoreSettings() { BMessage settings('stns'); - fMainWindow->StoreSettings(&settings); - - if (settings.ReplaceInt32("export mode", fSavePanel->ExportMode()) < B_OK) - settings.AddInt32("export mode", fSavePanel->ExportMode()); + settings.AddRect("window frame", fLastWindowFrame); + settings.AddMessage("window settings", &fLastWindowSettings); + settings.AddInt32("export mode", fSavePanel->ExportMode()); save_settings(&settings, "Icon-O-Matic"); } void -IconEditorApp::_RestoreSettings(BMessage& settings) +IconEditorApp::_RestoreSettings() { + BMessage settings('stns'); load_settings(&settings, "Icon-O-Matic"); + BRect frame; + if (settings.FindRect("window frame", &frame) == B_OK) { + fLastWindowFrame = frame; + // Compensate offset for next window... + fLastWindowFrame.OffsetBy(-10, -10); + } + settings.FindMessage("window settings", &fLastWindowSettings); + int32 mode; if (settings.FindInt32("export mode", &mode) >= B_OK) fSavePanel->SetExportMode(mode); @@ -765,3 +414,4 @@ IconEditorApp::_InstallDocumentMimeType() parseError.String()); } } + diff --git a/src/apps/icon-o-matic/IconEditorApp.h b/src/apps/icon-o-matic/IconEditorApp.h index 2ebaea61d4..44df93a1e1 100644 --- a/src/apps/icon-o-matic/IconEditorApp.h +++ b/src/apps/icon-o-matic/IconEditorApp.h @@ -11,23 +11,15 @@ class BFilePanel; -class Document; -class DocumentSaver; class MainWindow; class SavePanel; enum { MSG_NEW = 'newi', - - MSG_OPEN = 'open', - MSG_APPEND = 'apnd', - - MSG_SAVE = 'save', MSG_SAVE_AS = 'svas', - - MSG_EXPORT = 'xprt', MSG_EXPORT_AS = 'xpas', + MSG_WINDOW_CLOSED = 'wndc', }; @@ -68,16 +60,7 @@ public: // IconEditorApp private: - bool _CheckSaveIcon(const BMessage* currentMessage); - void _PickUpActionBeforeSave(); - - void _MakeIconEmpty(); - void _Open(const entry_ref& ref, - bool append = false); - void _Open(const BMessenger& externalObserver, - const uint8* data, size_t size); - DocumentSaver* _CreateSaver(const entry_ref& ref, - uint32 exportMode); + MainWindow* _NewWindow(); void _SyncPanels(BFilePanel* from, BFilePanel* to); @@ -85,12 +68,13 @@ private: const char* _LastFilePath(path_kind which); void _StoreSettings(); - void _RestoreSettings(BMessage& settings); + void _RestoreSettings(); void _InstallDocumentMimeType(); private: - MainWindow* fMainWindow; - Document* fDocument; + int32 fWindowCount; + BMessage fLastWindowSettings; + BRect fLastWindowFrame; BFilePanel* fOpenPanel; SavePanel* fSavePanel; @@ -98,8 +82,6 @@ private: BString fLastOpenPath; BString fLastSavePath; BString fLastExportPath; - - BMessage* fMessageAfterSave; }; diff --git a/src/apps/icon-o-matic/MainWindow.cpp b/src/apps/icon-o-matic/MainWindow.cpp index 21f7eeac02..93cea0a853 100644 --- a/src/apps/icon-o-matic/MainWindow.cpp +++ b/src/apps/icon-o-matic/MainWindow.cpp @@ -8,38 +8,57 @@ #include #include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include #include #include #include #include #include #include -#include -#include #include "support_ui.h" #include "AddPathsCommand.h" #include "AddShapesCommand.h" #include "AddStylesCommand.h" +#include "AttributeSaver.h" +#include "BitmapExporter.h" +#include "BitmapSetSaver.h" #include "CanvasView.h" #include "CommandStack.h" #include "CompoundCommand.h" #include "CurrentColor.h" #include "Document.h" -#include "Exporter.h" +#include "FlatIconExporter.h" +#include "FlatIconFormat.h" +#include "FlatIconImporter.h" #include "IconObjectListView.h" #include "IconEditorApp.h" #include "IconView.h" +#include "MessageExporter.h" +#include "MessageImporter.h" +#include "MessengerSaver.h" +#include "NativeSaver.h" #include "PathListView.h" +#include "RDefExporter.h" #include "ScrollView.h" +#include "SimpleFileSaver.h" #include "ShapeListView.h" +#include "SourceExporter.h" #include "StyleListView.h" #include "StyleView.h" +#include "SVGExporter.h" +#include "SVGImporter.h" #include "SwatchGroup.h" #include "TransformerListView.h" #include "TransformGradientBox.h" @@ -87,15 +106,17 @@ enum { }; -MainWindow::MainWindow(IconEditorApp* app, Document* document, +MainWindow::MainWindow(BRect frame, IconEditorApp* app, const BMessage* settings) : - BWindow(BRect(50, 50, 900, 750), B_TRANSLATE_SYSTEM_NAME("Icon-O-Matic"), + BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Icon-O-Matic"), B_DOCUMENT_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS), fApp(app), - fDocument(document), - fIcon(NULL) + fDocument(new Document(B_TRANSLATE("Untitled"))), + fCurrentColor(new CurrentColor()), + fIcon(NULL), + fMessageAfterSave(NULL) { _Init(); @@ -107,10 +128,22 @@ MainWindow::~MainWindow() { delete fState; - if (fIcon != NULL) - fIcon->Release(); + SetIcon(NULL); + + // Make sure there are no listeners attached to the document anymore. + while (BView* child = ChildAt(0L)) { + child->RemoveSelf(); + delete child; + } fDocument->CommandStack()->RemoveObserver(this); + + // NOTE: it is important that the GUI has been deleted + // at this point, so that all the listener/observer + // stuff is properly detached + delete fDocument; + + delete fMessageAfterSave; } @@ -122,19 +155,32 @@ MainWindow::MessageReceived(BMessage* message) { bool discard = false; - if (!fDocument || !fDocument->WriteLock()) { + // Figure out if we need the write lock on the Document. For most + // messages we do, but exporting takes place in another thread and + // locking is taken care of there. + bool requiresWriteLock = true; + switch (message->what) { + case MSG_SAVE: + case MSG_EXPORT: + case MSG_SAVE_AS: + case MSG_EXPORT_AS: + requiresWriteLock = false; + break; + default: + break; + } + if (requiresWriteLock && !fDocument->WriteLock()) { BWindow::MessageReceived(message); return; } if (message->WasDropped()) { - const rgb_color *color; - int32 len; - int32 i; + const rgb_color* color; + int32 length; // create styles from dropped colors - for (i = 0; message->FindData("RGBColor", B_RGB_COLOR_TYPE, i, - (const void **)&color, &len) == B_OK; i++) { - if (len != sizeof(rgb_color)) + for (int32 i = 0; message->FindData("RGBColor", B_RGB_COLOR_TYPE, i, + (const void**)&color, &length) == B_OK; i++) { + if (length != sizeof(rgb_color)) continue; char name[30]; sprintf(name, @@ -159,15 +205,17 @@ MainWindow::MessageReceived(BMessage* message) case B_REFS_RECEIVED: case B_SIMPLE_DATA: message->what = B_REFS_RECEIVED; - if (modifiers() & B_SHIFT_KEY) + if (modifiers() & B_SHIFT_KEY) { message->AddBool("append", true); + message->AddPointer("window", this); + } be_app->PostMessage(message); break; case B_PASTE: case B_MIME_DATA: { - BMessage *clip = message; + BMessage* clip = message; status_t err; if (discard) @@ -185,22 +233,21 @@ MainWindow::MessageReceived(BMessage* message) break; } - Icon* icon; - icon = new (nothrow) Icon(*fDocument->Icon()); - if (icon) { + Icon* icon = new (std::nothrow) Icon(*fDocument->Icon()); + if (icon != NULL) { StyledTextImporter importer; err = importer.Import(icon, clip); if (err >= B_OK) { - AutoWriteLocker locker(fDocument); + AutoWriteLocker locker(fDocument); - SetIcon(NULL); + SetIcon(NULL); - // incorporate the loaded icon into the document - // (either replace it or append to it) - fDocument->MakeEmpty(false); - // if append, the document savers are preserved - fDocument->SetIcon(icon); - SetIcon(icon); + // incorporate the loaded icon into the document + // (either replace it or append to it) + fDocument->MakeEmpty(false); + // if append, the document savers are preserved + fDocument->SetIcon(icon); + SetIcon(icon); } } @@ -209,6 +256,83 @@ MainWindow::MessageReceived(BMessage* message) break; } + case MSG_SAVE: + case MSG_EXPORT: + { + DocumentSaver* saver; + if (message->what == MSG_SAVE) + saver = fDocument->NativeSaver(); + else + saver = fDocument->ExportSaver(); + if (saver != NULL) { + saver->Save(fDocument); + _PickUpActionBeforeSave(); + break; + } // else fall through + } + case MSG_SAVE_AS: + case MSG_EXPORT_AS: + { + int32 exportMode; + if (message->FindInt32("export mode", &exportMode) < B_OK) + exportMode = EXPORT_MODE_MESSAGE; + entry_ref ref; + const char* name; + if (message->FindRef("directory", &ref) == B_OK + && message->FindString("name", &name) == B_OK) { + // this message comes from the file panel + printf("file panel result\n"); + BDirectory dir(&ref); + BEntry entry; + if (dir.InitCheck() >= B_OK + && entry.SetTo(&dir, name, true) >= B_OK + && entry.GetRef(&ref) >= B_OK) { + + // create the document saver and remember it for later + DocumentSaver* saver = _CreateSaver(ref, exportMode); + if (saver != NULL) { + if (fDocument->WriteLock()) { + if (exportMode == EXPORT_MODE_MESSAGE) + fDocument->SetNativeSaver(saver); + else + fDocument->SetExportSaver(saver); + fDocument->WriteUnlock(); + } + saver->Save(fDocument); + _PickUpActionBeforeSave(); + } + } +// TODO: ... +// _SyncPanels(fSavePanel, fOpenPanel); + } else { + printf("configure file panel\n"); + // configure the file panel + const char* saveText = NULL; + FileSaver* saver = dynamic_cast( + fDocument->NativeSaver()); + if (saver != NULL) + saveText = saver->Ref()->name; + + uint32 requestRefWhat = MSG_SAVE_AS; + bool isExportMode = message->what == MSG_EXPORT_AS + || message->what == MSG_EXPORT; + if (isExportMode) { + requestRefWhat = MSG_EXPORT_AS; + saver = dynamic_cast( + fDocument->ExportSaver()); + if (saver != NULL && saver->Ref()->name != NULL) + saveText = saver->Ref()->name; + } + + BMessage requestRef(requestRefWhat); + if (saveText != NULL) + requestRef.AddString("save text", saveText); + requestRef.AddMessenger("target", BMessenger(this, this)); + be_app->PostMessage(&requestRef); + } + break; + } + case MSG_UNDO: fDocument->CommandStack()->Undo(); break; @@ -247,16 +371,12 @@ MainWindow::MessageReceived(BMessage* message) break; } - case MSG_SET_ICON: - SetIcon(fDocument->Icon()); - break; - case MSG_ADD_SHAPE: { AddStylesCommand* styleCommand = NULL; Style* style = NULL; if (message->HasBool("style")) { - new_style(CurrentColor::Default()->Color(), - fDocument->Icon()->Styles(), &style, &styleCommand); + new_style(fCurrentColor->Color(), + fDocument->Icon()->Styles(), &style, &styleCommand); } AddPathsCommand* pathCommand = NULL; @@ -351,12 +471,9 @@ case MSG_STYLE_TYPE_CHANGED: { fState->DeleteManipulators(); Gradient* gradient = style ? style->Gradient() : NULL; - - if (gradient) { + if (gradient != NULL) { TransformGradientBox* transformBox - = new (nothrow) TransformGradientBox(fCanvasView, - gradient, - NULL); + = new (nothrow) TransformGradientBox(fCanvasView, gradient, NULL); fState->AddManipulator(transformBox); } break; @@ -400,18 +517,27 @@ case MSG_SHAPE_SELECTED: { BWindow::MessageReceived(message); } - fDocument->WriteUnlock(); + if (requiresWriteLock) + fDocument->WriteUnlock(); } bool MainWindow::QuitRequested() { - // forward this to app but return "false" in order - // to have a single code path for quitting - be_app->PostMessage(B_QUIT_REQUESTED); + if (!_CheckSaveIcon(CurrentMessage())) + return false; - return false; + BMessage message(MSG_WINDOW_CLOSED); + + BMessage settings; + StoreSettings(&settings); + message.AddMessage("settings", &settings); + message.AddRect("window frame", Frame()); + + be_app->PostMessage(&message); + + return true; } @@ -483,6 +609,203 @@ MainWindow::MakeEmpty() } +void +MainWindow::Open(const entry_ref& ref, bool append) +{ + BFile file(&ref, B_READ_ONLY); + if (file.InitCheck() < B_OK) + return; + + Icon* icon; + if (append) + icon = new (nothrow) Icon(*fDocument->Icon()); + else + icon = new (nothrow) Icon(); + + if (icon == NULL) { + // TODO: Report error to user. + return; + } + + enum { + REF_NONE = 0, + REF_MESSAGE, + REF_FLAT, + REF_FLAT_ATTR, + REF_SVG + }; + uint32 refMode = REF_NONE; + + // try different file types + FlatIconImporter flatImporter; + status_t ret = flatImporter.Import(icon, &file); + if (ret >= B_OK) { + refMode = REF_FLAT; + } else { + file.Seek(0, SEEK_SET); + MessageImporter msgImporter; + ret = msgImporter.Import(icon, &file); + if (ret >= B_OK) { + refMode = REF_MESSAGE; + } else { + file.Seek(0, SEEK_SET); + SVGImporter svgImporter; + ret = svgImporter.Import(icon, &ref); + if (ret >= B_OK) { + refMode = REF_SVG; + } else { + // fall back to flat icon format but use the icon attribute + ret = B_OK; + attr_info attrInfo; + if (file.GetAttrInfo(kVectorAttrNodeName, &attrInfo) == B_OK) { + if (attrInfo.type != B_VECTOR_ICON_TYPE) + ret = B_ERROR; + // If the attribute is there, we must succeed in reading + // an icon! Otherwise we may overwrite an existing icon + // when the user saves. + uint8* buffer = NULL; + if (ret == B_OK) { + buffer = new(nothrow) uint8[attrInfo.size]; + if (buffer == NULL) + ret = B_NO_MEMORY; + } + if (ret == B_OK) { + ssize_t bytesRead = file.ReadAttr(kVectorAttrNodeName, + B_VECTOR_ICON_TYPE, 0, buffer, attrInfo.size); + if (bytesRead != (ssize_t)attrInfo.size) { + ret = bytesRead < 0 ? (status_t)bytesRead + : B_IO_ERROR; + } + } + if (ret == B_OK) { + ret = flatImporter.Import(icon, buffer, attrInfo.size); + if (ret == B_OK) + refMode = REF_FLAT_ATTR; + } + + delete[] buffer; + } else { + // If there is no icon attribute, simply fall back + // to creating an icon for this file. TODO: We may or may + // not want to display an alert asking the user if that is + // what he wants to do. + refMode = REF_FLAT_ATTR; + } + } + } + } + + if (ret < B_OK) { + // inform user of failure at this point + BString helper(B_TRANSLATE("Opening the document failed!")); + helper << "\n\n" << B_TRANSLATE("Error: ") << strerror(ret); + BAlert* alert = new BAlert( + B_TRANSLATE_WITH_CONTEXT("bad news", "Title of error alert"), + helper.String(), + B_TRANSLATE_WITH_CONTEXT("Bummer", + "Cancel button - error alert"), + NULL, NULL); + // launch alert asynchronously + alert->Go(NULL); + + delete icon; + return; + } + + AutoWriteLocker locker(fDocument); + + // incorporate the loaded icon into the document + // (either replace it or append to it) + fDocument->MakeEmpty(!append); + // if append, the document savers are preserved + fDocument->SetIcon(icon); + if (!append) { + // document got replaced, but we have at + // least one ref already + switch (refMode) { + case REF_MESSAGE: + fDocument->SetNativeSaver(new NativeSaver(ref)); + break; + case REF_FLAT: + fDocument->SetExportSaver( + new SimpleFileSaver(new FlatIconExporter(), ref)); + break; + case REF_FLAT_ATTR: + fDocument->SetNativeSaver( + new AttributeSaver(ref, kVectorAttrNodeName)); + break; + case REF_SVG: + fDocument->SetExportSaver( + new SimpleFileSaver(new SVGExporter(), ref)); + break; + } + } + + locker.Unlock(); + + SetIcon(icon); +} + + +void +MainWindow::Open(const BMessenger& externalObserver, const uint8* data, + size_t size) +{ + if (!_CheckSaveIcon(CurrentMessage())) + return; + + if (!externalObserver.IsValid()) + return; + + Icon* icon = new (nothrow) Icon(); + if (!icon) + return; + + if (data && size > 0) { + // try to open the icon from the provided data + FlatIconImporter flatImporter; + status_t ret = flatImporter.Import(icon, const_cast(data), + size); + // NOTE: the const_cast is a bit ugly, but no harm is done + // the reason is that the LittleEndianBuffer knows read and write + // mode, in this case it is used read-only, and it does not assume + // ownership of the buffer + + if (ret < B_OK) { + // inform user of failure at this point + BString helper(B_TRANSLATE("Opening the icon failed!")); + helper << "\n\n" << B_TRANSLATE("Error: ") << strerror(ret); + BAlert* alert = new BAlert( + B_TRANSLATE_WITH_CONTEXT("bad news", "Title of error alert"), + helper.String(), + B_TRANSLATE_WITH_CONTEXT("Bummer", + "Cancel button - error alert"), + NULL, NULL); + // launch alert asynchronously + alert->Go(NULL); + + delete icon; + return; + } + } + + AutoWriteLocker locker(fDocument); + + SetIcon(NULL); + + // incorporate the loaded icon into the document + // (either replace it or append to it) + fDocument->MakeEmpty(); + fDocument->SetIcon(icon); + + fDocument->SetNativeSaver(new MessengerSaver(externalObserver)); + + locker.Unlock(); + + SetIcon(icon); +} + + void MainWindow::SetIcon(Icon* icon) { @@ -493,20 +816,20 @@ MainWindow::SetIcon(Icon* icon) fIcon = icon; - if (fIcon) + if (fIcon != NULL) fIcon->Acquire(); else MakeEmpty(); fCanvasView->SetIcon(fIcon); - fPathListView->SetPathContainer(fIcon ? fIcon->Paths() : NULL); - fPathListView->SetShapeContainer(fIcon ? fIcon->Shapes() : NULL); + fPathListView->SetPathContainer(fIcon != NULL ? fIcon->Paths() : NULL); + fPathListView->SetShapeContainer(fIcon != NULL ? fIcon->Shapes() : NULL); - fStyleListView->SetStyleContainer(fIcon ? fIcon->Styles() : NULL); - fStyleListView->SetShapeContainer(fIcon ? fIcon->Shapes() : NULL); + fStyleListView->SetStyleContainer(fIcon != NULL ? fIcon->Styles() : NULL); + fStyleListView->SetShapeContainer(fIcon != NULL ? fIcon->Shapes() : NULL); - fShapeListView->SetShapeContainer(fIcon ? fIcon->Shapes() : NULL); + fShapeListView->SetShapeContainer(fIcon != NULL ? fIcon->Shapes() : NULL); // icon previews fIconPreview16Folder->SetIcon(fIcon); @@ -517,7 +840,7 @@ MainWindow::SetIcon(Icon* icon) fIconPreview64->SetIcon(fIcon); // keep this last - if (oldIcon) + if (oldIcon != NULL) oldIcon->Release(); } @@ -528,8 +851,6 @@ MainWindow::SetIcon(Icon* icon) void MainWindow::StoreSettings(BMessage* archive) { - if (archive->ReplaceRect("main window frame", Frame()) != B_OK) - archive->AddRect("main window frame", Frame()); if (archive->ReplaceUInt32("mouse filter mode", fCanvasView->MouseFilterMode()) != B_OK) { archive->AddUInt32("mouse filter mode", @@ -541,15 +862,14 @@ MainWindow::StoreSettings(BMessage* archive) void MainWindow::RestoreSettings(const BMessage* archive) { - BRect frame; - if (archive->FindRect("main window frame", &frame) == B_OK) { - make_sure_frame_is_on_screen(frame, this); - MoveTo(frame.LeftTop()); - ResizeTo(frame.Width(), frame.Height()); - } uint32 mouseFilterMode; - if (archive->FindUInt32("mouse filter mode", &mouseFilterMode) == B_OK) + if (archive->FindUInt32("mouse filter mode", &mouseFilterMode) == B_OK) { fCanvasView->SetMouseFilterMode(mouseFilterMode); + fMouseFilterOffMI->SetMarked(mouseFilterMode == SNAPPING_OFF); + fMouseFilter64MI->SetMarked(mouseFilterMode == SNAPPING_64); + fMouseFilter32MI->SetMarked(mouseFilterMode == SNAPPING_32); + fMouseFilter16MI->SetMarked(mouseFilterMode == SNAPPING_16); + } } @@ -575,6 +895,7 @@ MainWindow::_Init() fCanvasView->SetCatchAllEvents(true); fCanvasView->SetCommandStack(fDocument->CommandStack()); fCanvasView->SetMouseFilterMode(SNAPPING_64); + fMouseFilter64MI->SetMarked(true); // fCanvasView->SetSelection(fDocument->Selection()); fPathListView->SetMenu(fPathMenu); @@ -584,9 +905,10 @@ MainWindow::_Init() fStyleListView->SetMenu(fStyleMenu); fStyleListView->SetCommandStack(fDocument->CommandStack()); fStyleListView->SetSelection(fDocument->Selection()); + fStyleListView->SetCurrentColor(fCurrentColor); fStyleView->SetCommandStack(fDocument->CommandStack()); - fStyleView->SetCurrentColor(CurrentColor::Default()); + fStyleView->SetCurrentColor(fCurrentColor); fShapeListView->SetMenu(fShapeMenu); fShapeListView->SetCommandStack(fDocument->CommandStack()); @@ -602,7 +924,7 @@ MainWindow::_Init() fDocument->CommandStack()->AddObserver(this); - fSwatchGroup->SetCurrentColor(CurrentColor::Default()); + fSwatchGroup->SetCurrentColor(fCurrentColor); SetIcon(fDocument->Icon()); @@ -821,13 +1143,21 @@ MainWindow::_CreateMenuBar() #undef B_TRANSLATE_CONTEXT #define B_TRANSLATE_CONTEXT "Icon-O-Matic-Menu-File" - - fileMenu->AddItem(new BMenuItem(B_TRANSLATE("New"), - new BMessage(MSG_NEW), 'N')); - fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Open"B_UTF8_ELLIPSIS), - new BMessage(MSG_OPEN), 'O')); - fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Append"B_UTF8_ELLIPSIS), - new BMessage(MSG_APPEND), 'O', B_SHIFT_KEY)); + + BMenuItem* item = new BMenuItem(B_TRANSLATE("New"), + new BMessage(MSG_NEW), 'N'); + fileMenu->AddItem(item); + item->SetTarget(be_app); + item = new BMenuItem(B_TRANSLATE("Open"B_UTF8_ELLIPSIS), + new BMessage(MSG_OPEN), 'O'); + fileMenu->AddItem(item); + item->SetTarget(be_app); + BMessage* appendMessage = new BMessage(MSG_APPEND); + appendMessage->AddPointer("window", this); + item = new BMenuItem(B_TRANSLATE("Append"B_UTF8_ELLIPSIS), + appendMessage, 'O', B_SHIFT_KEY); + fileMenu->AddItem(item); + item->SetTarget(be_app); fileMenu->AddSeparatorItem(); fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Save"), new BMessage(MSG_SAVE), 'S')); @@ -839,10 +1169,12 @@ MainWindow::_CreateMenuBar() fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Export as"B_UTF8_ELLIPSIS), new BMessage(MSG_EXPORT_AS), 'P', B_SHIFT_KEY)); fileMenu->AddSeparatorItem(); - fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Quit"), - new BMessage(B_QUIT_REQUESTED), 'Q')); - fileMenu->SetTargetForItems(be_app); - + fileMenu->AddItem(new BMenuItem(B_TRANSLATE("Close"), + new BMessage(B_QUIT_REQUESTED), 'W')); + item = new BMenuItem(B_TRANSLATE("Quit"), + new BMessage(B_QUIT_REQUESTED), 'Q'); + fileMenu->AddItem(item); + item->SetTarget(be_app); // Edit #undef B_TRANSLATE_CONTEXT @@ -869,21 +1201,24 @@ MainWindow::_CreateMenuBar() BMenu* filterModeMenu = new BMenu(B_TRANSLATE("Snap to grid")); BMessage* message = new BMessage(MSG_MOUSE_FILTER_MODE); message->AddInt32("mode", SNAPPING_OFF); - filterModeMenu->AddItem(new BMenuItem(B_TRANSLATE("Off"), message, '4')); + fMouseFilterOffMI = new BMenuItem(B_TRANSLATE("Off"), message, '4'); + filterModeMenu->AddItem(fMouseFilterOffMI); message = new BMessage(MSG_MOUSE_FILTER_MODE); message->AddInt32("mode", SNAPPING_64); - filterModeMenu->AddItem(new BMenuItem("64 x 64", message, '3')); + fMouseFilter64MI = new BMenuItem("64 x 64", message, '3'); + filterModeMenu->AddItem(fMouseFilter64MI); message = new BMessage(MSG_MOUSE_FILTER_MODE); message->AddInt32("mode", SNAPPING_32); - filterModeMenu->AddItem(new BMenuItem("32 x 32", message, '2')); + fMouseFilter32MI = new BMenuItem("32 x 32", message, '2'); + filterModeMenu->AddItem(fMouseFilter32MI); message = new BMessage(MSG_MOUSE_FILTER_MODE); message->AddInt32("mode", SNAPPING_16); - filterModeMenu->AddItem(new BMenuItem("16 x 16", message, '1')); + fMouseFilter16MI = new BMenuItem("16 x 16", message, '1'); + filterModeMenu->AddItem(fMouseFilter16MI); - filterModeMenu->ItemAt(1)->SetMarked(true); filterModeMenu->SetRadioMode(true); settingsMenu->AddItem(filterModeMenu); @@ -907,3 +1242,131 @@ MainWindow::_ImproveScrollBarLayout(BView* target) scrollBar->ResizeBy(0, 1); } } + + +// #pragma mark - + + +bool +MainWindow::_CheckSaveIcon(const BMessage* currentMessage) +{ + if (fDocument->IsEmpty() || fDocument->CommandStack()->IsSaved()) + return true; + + // Make sure the user sees us. + Activate(); + + BAlert* alert = new BAlert("save", + B_TRANSLATE("Save changes to current icon?"), B_TRANSLATE("Discard"), + B_TRANSLATE("Cancel"), B_TRANSLATE("Save")); + int32 choice = alert->Go(); + switch (choice) { + case 0: + // discard + return true; + case 1: + // cancel + return false; + case 2: + default: + // cancel (save first) but pick up what we were doing before + PostMessage(MSG_SAVE); + if (currentMessage != NULL) { + delete fMessageAfterSave; + fMessageAfterSave = new BMessage(*currentMessage); + } + return false; + } +} + + +void +MainWindow::_PickUpActionBeforeSave() +{ + if (fDocument->WriteLock()) { + fDocument->CommandStack()->Save(); + fDocument->WriteUnlock(); + } + + if (fMessageAfterSave == NULL) + return; + + PostMessage(fMessageAfterSave); + delete fMessageAfterSave; + fMessageAfterSave = NULL; +} + + +// #pragma mark - + + +void +MainWindow::_MakeIconEmpty() +{ + if (!_CheckSaveIcon(CurrentMessage())) + return; + + AutoWriteLocker locker(fDocument); + + MakeEmpty(); + fDocument->MakeEmpty(); + + locker.Unlock(); +} + + +DocumentSaver* +MainWindow::_CreateSaver(const entry_ref& ref, uint32 exportMode) +{ + DocumentSaver* saver; + + switch (exportMode) { + case EXPORT_MODE_FLAT_ICON: + saver = new SimpleFileSaver(new FlatIconExporter(), ref); + break; + + case EXPORT_MODE_ICON_ATTR: + case EXPORT_MODE_ICON_MIME_ATTR: { + const char* attrName + = exportMode == EXPORT_MODE_ICON_ATTR ? + kVectorAttrNodeName : kVectorAttrMimeName; + saver = new AttributeSaver(ref, attrName); + break; + } + + case EXPORT_MODE_ICON_RDEF: + saver = new SimpleFileSaver(new RDefExporter(), ref); + break; + case EXPORT_MODE_ICON_SOURCE: + saver = new SimpleFileSaver(new SourceExporter(), ref); + break; + + case EXPORT_MODE_BITMAP_16: + saver = new SimpleFileSaver(new BitmapExporter(16), ref); + break; + case EXPORT_MODE_BITMAP_32: + saver = new SimpleFileSaver(new BitmapExporter(32), ref); + break; + case EXPORT_MODE_BITMAP_64: + saver = new SimpleFileSaver(new BitmapExporter(64), ref); + break; + + case EXPORT_MODE_BITMAP_SET: + saver = new BitmapSetSaver(ref); + break; + + case EXPORT_MODE_SVG: + saver = new SimpleFileSaver(new SVGExporter(), ref); + break; + + case EXPORT_MODE_MESSAGE: + default: + saver = new NativeSaver(ref); + break; + } + + return saver; +} + + + diff --git a/src/apps/icon-o-matic/MainWindow.h b/src/apps/icon-o-matic/MainWindow.h index 109069f127..d859d50c31 100644 --- a/src/apps/icon-o-matic/MainWindow.h +++ b/src/apps/icon-o-matic/MainWindow.h @@ -17,7 +17,9 @@ class BMenu; class BMenuBar; class BMenuItem; class CanvasView; +class CurrentColor; class Document; +class DocumentSaver; class IconObjectListView; class IconEditorApp; class IconView; @@ -38,14 +40,16 @@ _USING_ICON_NAMESPACE class MultipleManipulatorState; enum { - MSG_SET_ICON = 'sicn', + MSG_OPEN = 'open', + MSG_APPEND = 'apnd', + MSG_SAVE = 'save', + MSG_EXPORT = 'xprt', }; class MainWindow : public BWindow, public Observer { public: - MainWindow(IconEditorApp* app, - Document* document, + MainWindow(BRect frame, IconEditorApp* app, const BMessage* settings); virtual ~MainWindow(); @@ -64,6 +68,11 @@ public: void MakeEmpty(); void SetIcon(Icon* icon); + void Open(const entry_ref& ref, + bool append = false); + void Open(const BMessenger& externalObserver, + const uint8* data, size_t size); + void StoreSettings(BMessage* archive); void RestoreSettings(const BMessage* archive); @@ -74,10 +83,20 @@ private: void _ImproveScrollBarLayout(BView* target); + bool _CheckSaveIcon(const BMessage* currentMessage); + void _PickUpActionBeforeSave(); + + void _MakeIconEmpty(); + DocumentSaver* _CreateSaver(const entry_ref& ref, + uint32 exportMode); + private: IconEditorApp* fApp; Document* fDocument; + CurrentColor* fCurrentColor; Icon* fIcon; + + BMessage* fMessageAfterSave; BMenu* fPathMenu; BMenu* fStyleMenu; @@ -88,6 +107,10 @@ private: BMenuItem* fUndoMI; BMenuItem* fRedoMI; + BMenuItem* fMouseFilterOffMI; + BMenuItem* fMouseFilter64MI; + BMenuItem* fMouseFilter32MI; + BMenuItem* fMouseFilter16MI; CanvasView* fCanvasView; SwatchGroup* fSwatchGroup; diff --git a/src/apps/icon-o-matic/gui/GradientControl.cpp b/src/apps/icon-o-matic/gui/GradientControl.cpp index 5d071ad18e..be88d4e183 100644 --- a/src/apps/icon-o-matic/gui/GradientControl.cpp +++ b/src/apps/icon-o-matic/gui/GradientControl.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -338,10 +339,10 @@ GradientControl::Draw(BRect updateRect) bool isFocus = IsFocus() && Window()->IsActive(); rgb_color bg = LowColor(); + rgb_color black; rgb_color shadow; rgb_color darkShadow; rgb_color light; - rgb_color black; if (fEnabled) { shadow = tint_color(bg, B_DARKEN_1_TINT); @@ -355,16 +356,25 @@ GradientControl::Draw(BRect updateRect) black = tint_color(bg, B_DARKEN_2_TINT); } - rgb_color focus = isFocus ? ui_color(B_KEYBOARD_NAVIGATION_COLOR) - : black; + rgb_color focus = isFocus ? ui_color(B_KEYBOARD_NAVIGATION_COLOR) : black; - stroke_frame(this, b, shadow, shadow, light, light); - b.InsetBy(1.0, 1.0); - if (isFocus) - stroke_frame(this, b, focus, focus, focus, focus); - else - stroke_frame(this, b, darkShadow, darkShadow, bg, bg); - b.InsetBy(1.0, 1.0); + uint32 flags = 0; + + if (be_control_look != NULL) { + if (!fEnabled) + flags |= BControlLook::B_DISABLED; + if (isFocus) + flags |= BControlLook::B_FOCUSED; + be_control_look->DrawTextControlBorder(this, b, updateRect, bg, flags); + } else { + stroke_frame(this, b, shadow, shadow, light, light); + b.InsetBy(1.0, 1.0); + if (isFocus) + stroke_frame(this, b, focus, focus, focus, focus); + else + stroke_frame(this, b, darkShadow, darkShadow, bg, bg); + b.InsetBy(1.0, 1.0); + } // DrawBitmapAsync(fGradientBitmap, b.LeftTop()); // Sync(); @@ -399,22 +409,30 @@ GradientControl::Draw(BRect updateRect) if (i == fDropIndex) SetLowColor(255, 0, 0, 255); - StrokeTriangle(markerPos, markerPos + leftBottom, - markerPos + rightBottom, B_SOLID_LOW); - if (fEnabled) { - SetHighColor(step->color); + if (be_control_look != NULL) { + // TODO: Drop indication! + BRect rect(markerPos.x + leftBottom.x, markerPos.y, + markerPos.x + rightBottom.x, markerPos.y + rightBottom.y); + be_control_look->DrawSliderTriangle(this, rect, updateRect, bg, + step->color, flags, B_HORIZONTAL); } else { - rgb_color c = step->color; - c.red = (uint8)(((uint32)bg.red + (uint32)c.red) / 2); - c.green = (uint8)(((uint32)bg.green + (uint32)c.green) / 2); - c.blue = (uint8)(((uint32)bg.blue + (uint32)c.blue) / 2); - SetHighColor(c); + StrokeTriangle(markerPos, markerPos + leftBottom, + markerPos + rightBottom, B_SOLID_LOW); + if (fEnabled) { + SetHighColor(step->color); + } else { + rgb_color c = step->color; + c.red = (uint8)(((uint32)bg.red + (uint32)c.red) / 2); + c.green = (uint8)(((uint32)bg.green + (uint32)c.green) / 2); + c.blue = (uint8)(((uint32)bg.blue + (uint32)c.blue) / 2); + SetHighColor(c); + } + FillTriangle(markerPos + BPoint(0.0, 1.0), + markerPos + leftBottom + BPoint(1.0, 0.0), + markerPos + rightBottom + BPoint(-1.0, 0.0)); + StrokeLine(markerPos + leftBottom + BPoint(0.0, 1.0), + markerPos + rightBottom + BPoint(0.0, 1.0), B_SOLID_LOW); } - FillTriangle(markerPos + BPoint(0.0, 1.0), - markerPos + leftBottom + BPoint(1.0, 0.0), - markerPos + rightBottom + BPoint(-1.0, 0.0)); - StrokeLine(markerPos + leftBottom + BPoint(0.0, 1.0), - markerPos + rightBottom + BPoint(0.0, 1.0), B_SOLID_LOW); } } diff --git a/src/apps/icon-o-matic/gui/StyleListView.cpp b/src/apps/icon-o-matic/gui/StyleListView.cpp index d479ff2f05..03132f7910 100644 --- a/src/apps/icon-o-matic/gui/StyleListView.cpp +++ b/src/apps/icon-o-matic/gui/StyleListView.cpp @@ -1,11 +1,9 @@ /* - * Copyright 2006-2009, Haiku, Inc. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Authors: - * Stephan Aßmus + * Copyright 2006-2009, 2011, Stephan Aßmus . + * All rights reserved. Distributed under the terms of the MIT License. */ + #include "StyleListView.h" #include @@ -255,6 +253,7 @@ StyleListView::StyleListView(BRect frame, fStyleContainer(NULL), fShapeContainer(NULL), fCommandStack(NULL), + fCurrentColor(NULL), fCurrentShape(NULL), fShapeListener(new ShapeStyleListener(this)), @@ -289,8 +288,16 @@ StyleListView::MessageReceived(BMessage* message) case MSG_ADD: { Style* style; AddStylesCommand* command; - new_style(CurrentColor::Default()->Color(), - fStyleContainer, &style, &command); + rgb_color color; + if (fCurrentColor != NULL) + color = fCurrentColor->Color(); + else { + color.red = 0; + color.green = 0; + color.blue = 0; + color.alpha = 255; + } + new_style(color, fStyleContainer, &style, &command); fCommandStack->Perform(command); break; } @@ -672,6 +679,13 @@ StyleListView::SetCommandStack(CommandStack* stack) fCommandStack = stack; } +// SetCurrentColor +void +StyleListView::SetCurrentColor(CurrentColor* color) +{ + fCurrentColor = color; +} + // SetCurrentShape void StyleListView::SetCurrentShape(Shape* shape) diff --git a/src/apps/icon-o-matic/gui/StyleListView.h b/src/apps/icon-o-matic/gui/StyleListView.h index 642257963e..5029dce926 100644 --- a/src/apps/icon-o-matic/gui/StyleListView.h +++ b/src/apps/icon-o-matic/gui/StyleListView.h @@ -1,9 +1,6 @@ /* - * Copyright 2006-2007, Haiku. + * Copyright 2006-2007, 2011, Stephan Aßmus . * Distributed under the terms of the MIT License. - * - * Authors: - * Stephan Aßmus */ #ifndef STYLE_LIST_VIEW_H #define STYLE_LIST_VIEW_H @@ -16,6 +13,7 @@ class BMenu; class BMenuItem; class CommandStack; +class CurrentColor; class Selection; class ShapeStyleListener; class StyleListItem; @@ -30,13 +28,11 @@ _END_ICON_NAMESPACE _USING_ICON_NAMESPACE -class StyleListView : public SimpleListView, - public StyleContainerListener { - public: - StyleListView(BRect frame, - const char* name, - BMessage* selectionMessage = NULL, - BHandler* target = NULL); +class StyleListView : public SimpleListView, public StyleContainerListener { +public: + StyleListView(BRect frame, const char* name, + BMessage* selectionMessage = NULL, + BHandler* target = NULL); virtual ~StyleListView(); // SimpleListView interface @@ -48,9 +44,10 @@ class StyleListView : public SimpleListView, virtual void MakeDragMessage(BMessage* message) const; - virtual bool AcceptDragMessage(const BMessage* message) const; + virtual bool AcceptDragMessage( + const BMessage* message) const; virtual void SetDropTargetRect(const BMessage* message, - BPoint where); + BPoint where); virtual void MoveItems(BList& items, int32 toIndex); virtual void CopyItems(BList& items, int32 toIndex); @@ -70,18 +67,19 @@ class StyleListView : public SimpleListView, void SetStyleContainer(StyleContainer* container); void SetShapeContainer(ShapeContainer* container); void SetCommandStack(CommandStack* stack); + void SetCurrentColor(CurrentColor* color); void SetCurrentShape(Shape* shape); Shape* CurrentShape() const { return fCurrentShape; } - private: +private: bool _AddStyle(Style* style, int32 index); bool _RemoveStyle(Style* style); StyleListItem* _ItemForStyle(Style* style) const; - friend class ShapeStyleListener; + friend class ShapeStyleListener; void _UpdateMarks(); void _SetStyleMarked(Style* style, bool marked); void _UpdateMenu(); @@ -91,6 +89,7 @@ class StyleListView : public SimpleListView, StyleContainer* fStyleContainer; ShapeContainer* fShapeContainer; CommandStack* fCommandStack; + CurrentColor* fCurrentColor; Shape* fCurrentShape; // the style item will be marked that @@ -105,4 +104,5 @@ class StyleListView : public SimpleListView, BMenuItem* fRemoveMI; }; + #endif // STYLE_LIST_VIEW_H diff --git a/src/apps/icon-o-matic/gui/SwatchGroup.cpp b/src/apps/icon-o-matic/gui/SwatchGroup.cpp index 8ca4e05086..38f6ba1b18 100644 --- a/src/apps/icon-o-matic/gui/SwatchGroup.cpp +++ b/src/apps/icon-o-matic/gui/SwatchGroup.cpp @@ -52,7 +52,9 @@ SwatchGroup::SwatchGroup(BRect frame) float v = 1.0; rgb_color color; color.alpha = 255; - float r, g, b; + float r = 0.0f; + float g = 0.0f; + float b = 0.0f; for (int32 i = 0; i < 20; i++) { if (i < 10) { h = ((float)i / 9.0) * 6.0; @@ -295,7 +297,9 @@ SwatchGroup::_SetColor(rgb_color color) void SwatchGroup::_SetColor(float h, float s, float v, uint8 a) { - float r, g, b; + float r = 0.0f; + float g = 0.0f; + float b = 0.0f; HSV_to_RGB(h, s, v, r, g, b); rgb_color color; diff --git a/src/apps/icon-o-matic/style/CurrentColor.cpp b/src/apps/icon-o-matic/style/CurrentColor.cpp index d506469418..da2001d869 100644 --- a/src/apps/icon-o-matic/style/CurrentColor.cpp +++ b/src/apps/icon-o-matic/style/CurrentColor.cpp @@ -1,11 +1,9 @@ /* - * Copyright 2006, Haiku. - * Distributed under the terms of the MIT License. - * - * Authors: - * Stephan Aßmus + * Copyright 2006, 2011, Stephan Aßmus . + * All rights reserved. Distributed under the terms of the MIT License. */ + #include "CurrentColor.h" #include @@ -14,31 +12,19 @@ #include "ui_defines.h" -// init global CurrentColor instance -CurrentColor -CurrentColor::fDefaultInstance; - -// constructor CurrentColor::CurrentColor() : Observable(), fColor(kBlack) { } -// destructor + CurrentColor::~CurrentColor() { } -// Default -CurrentColor* -CurrentColor::Default() -{ - return &fDefaultInstance; -} -// SetColor void CurrentColor::SetColor(rgb_color color) { diff --git a/src/apps/icon-o-matic/style/CurrentColor.h b/src/apps/icon-o-matic/style/CurrentColor.h index 8b3000fcb7..2e5eaf9c0d 100644 --- a/src/apps/icon-o-matic/style/CurrentColor.h +++ b/src/apps/icon-o-matic/style/CurrentColor.h @@ -1,33 +1,28 @@ /* - * Copyright 2006, Haiku. - * Distributed under the terms of the MIT License. - * - * Authors: - * Stephan Aßmus + * Copyright 2006, 2011, Stephan Aßmus . + * All rights reserved. Distributed under the terms of the MIT License. */ - #ifndef CURRENT_COLOR_H #define CURRENT_COLOR_H + #include #include "Observable.h" + class CurrentColor : public Observable { - public: +public: CurrentColor(); virtual ~CurrentColor(); - static CurrentColor* Default(); - void SetColor(rgb_color color); inline rgb_color Color() const { return fColor; } - private: +private: rgb_color fColor; - - static CurrentColor fDefaultInstance; }; + #endif // CURRENT_COLOR_H