* A whole buch of refactoring and other changes to make Icon-O-Matic

a multi-document application. This is already more useful than
   before, but will be even more useful once it is possible to copy
   more types of objects to the system clipboard and paste them into
   other open icons.
 * Fixed wrong snapping menu item being marked when restoring settings
   that enable a different snapping mode from the default.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@41212 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2011-04-10 22:32:51 +00:00
parent 490b4a9481
commit 61ee19d10f
10 changed files with 802 additions and 667 deletions

View File

@ -12,11 +12,7 @@
#include <Alert.h>
#include <Catalog.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FilePanel.h>
#include <fs_attr.h>
#include <IconEditorProtocol.h>
#include <Locale.h>
#include <Message.h>
@ -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<MainWindow*>(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<FileSaver*>(
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<FileSaver*>(
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<uint8*>(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());
}
}

View File

@ -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;
};

View File

@ -8,38 +8,57 @@
#include <new>
#include <stdio.h>
#include <Alert.h>
#include <Catalog.h>
#include <Clipboard.h>
#include <GridLayout.h>
#include <GroupLayout.h>
#include <GroupView.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <fs_attr.h>
#include <Locale.h>
#include <Menu.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <Message.h>
#include <Screen.h>
#include <ScrollView.h>
#include <Catalog.h>
#include <Locale.h>
#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<FileSaver*>(
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<FileSaver*>(
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<uint8*>(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;
}

View File

@ -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;

View File

@ -12,6 +12,7 @@
#include <AppDefs.h>
#include <Bitmap.h>
#include <ControlLook.h>
#include <Message.h>
#include <Window.h>
@ -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);
}
}

View File

@ -1,11 +1,9 @@
/*
* Copyright 2006-2009, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2006-2009, 2011, Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "StyleListView.h"
#include <new>
@ -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)

View File

@ -1,9 +1,6 @@
/*
* Copyright 2006-2007, Haiku.
* Copyright 2006-2007, 2011, Stephan Aßmus <superstippi@gmx.de>.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
*/
#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

View File

@ -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;

View File

@ -1,11 +1,9 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2006, 2011, Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "CurrentColor.h"
#include <stdio.h>
@ -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)
{

View File

@ -1,33 +1,28 @@
/*
* Copyright 2006, Haiku.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stephan Aßmus <superstippi@gmx.de>
* Copyright 2006, 2011, Stephan Aßmus <superstippi@gmx.de>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef CURRENT_COLOR_H
#define CURRENT_COLOR_H
#include <GraphicsDefs.h>
#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