diff --git a/src/apps/showimage/Jamfile b/src/apps/showimage/Jamfile index 7506214a9a..45e62aa5bc 100644 --- a/src/apps/showimage/Jamfile +++ b/src/apps/showimage/Jamfile @@ -6,6 +6,7 @@ App ShowImage : ShowImageApp.cpp ShowImageConstants.cpp ShowImageSettings.cpp ShowImageStatusView.cpp + ShowImageUndo.cpp ShowImageView.cpp ShowImageWindow.cpp PrintOptionsWindow.cpp diff --git a/src/apps/showimage/ShowImageConstants.h b/src/apps/showimage/ShowImageConstants.h index a820551900..5b2f05446e 100644 --- a/src/apps/showimage/ShowImageConstants.h +++ b/src/apps/showimage/ShowImageConstants.h @@ -44,6 +44,7 @@ const uint32 MSG_CLIPBOARD_CHANGED = 'mCLP'; const uint32 MSG_DITHER_IMAGE = 'mDIM'; const uint32 MSG_MODIFIED = 'mMOD'; const uint32 MSG_UPDATE_STATUS = 'mUPS'; +const uint32 MSG_UNDO_STATE = 'mUNS'; const uint32 MSG_SELECTION = 'mSEL'; const uint32 MSG_SELECTION_BITMAP = 'mSBT'; const uint32 MSG_PAGE_FIRST = 'mPGF'; diff --git a/src/apps/showimage/ShowImageUndo.cpp b/src/apps/showimage/ShowImageUndo.cpp new file mode 100644 index 0000000000..d1ce6f5d7d --- /dev/null +++ b/src/apps/showimage/ShowImageUndo.cpp @@ -0,0 +1,98 @@ +/*****************************************************************************/ +// ShowImageUndo +// Written by Michael Wilber +// +// ShowImageUndo.cpp +// +// +// Copyright (c) 2003 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#include "ShowImageUndo.h" + +ShowImageUndo::ShowImageUndo() +{ + fWindow = NULL; + fUndoType = 0; + fRestore = NULL; + fSelection = NULL; +} + +ShowImageUndo::~ShowImageUndo() +{ + InternalClear(); +} + +void +ShowImageUndo::InternalClear() +{ + fUndoType = 0; + delete fRestore; + fRestore = NULL; + delete fSelection; + fSelection = NULL; +} + +void +ShowImageUndo::Clear() +{ + InternalClear(); + SendUndoStateMessage(false); +} + +void +ShowImageUndo::SendUndoStateMessage(bool bCanUndo) +{ + if (fWindow) { + BMessage msg(MSG_UNDO_STATE); + msg.AddBool("can_undo", bCanUndo); + BMessenger msgr(fWindow); + msgr.SendMessage(&msg); + } +} + +void +ShowImageUndo::SetTo(BRect rect, BBitmap *restore, BBitmap *selection) +{ + // NOTE: THIS FUNCTION DOES NOT MAKE COPIES OF THE BITMAPS PASSED TO IT + InternalClear(); + + fUndoType = UNDO_UNDO; + fRect = rect; + fRestore = restore; + fSelection = selection; + + SendUndoStateMessage(true); +} + +void +ShowImageUndo::Undo(BRect rect, BBitmap *restore, BBitmap *selection) +{ + // NOTE: THIS FUNCTION DOES NOT MAKE COPIES OF THE BITMAPS PASSED TO IT + fUndoType = UNDO_REDO; + fRect = rect; + delete fRestore; + fRestore = restore; + fSelection = selection; + // NOTE: fSelection isn't deleted here because ShowImageView + // takes ownership of it during an Undo +} + diff --git a/src/apps/showimage/ShowImageUndo.h b/src/apps/showimage/ShowImageUndo.h new file mode 100644 index 0000000000..d5bf046998 --- /dev/null +++ b/src/apps/showimage/ShowImageUndo.h @@ -0,0 +1,79 @@ +/*****************************************************************************/ +// ShowImageUndo +// Written by Michael Wilber +// +// ShowImageUndo.h +// +// +// Copyright (c) 2003 OpenBeOS Project +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +/*****************************************************************************/ + +#ifndef _ShowImageUndo_h +#define _ShowImageUndo_h + +#include +#include +#include +#include +#include +#include "ShowImageConstants.h" + +// for Undo +#define UNDO_UNDO 1 +#define UNDO_REDO 2 + +class ShowImageUndo { +public: + ShowImageUndo(); + ~ShowImageUndo(); + + void SetWindow(BWindow *win) { fWindow = win; } + + void Clear(); + + // NOTE: THESE TWO FUNCTIONS DO NOT MAKE COPIES OF THE + // BITMAPS PASSED TO THEM + void SetTo(BRect rect, BBitmap *restore, BBitmap *selection); + void Undo(BRect rect, BBitmap *restore, BBitmap *selection); + + int32 GetType() { return fUndoType; } + BRect GetRect() { return fRect; } + BBitmap *GetRestoreBitmap() { return fRestore; } + BBitmap *GetSelectionBitmap() { return fSelection; } + +private: + void InternalClear(); + void SendUndoStateMessage(bool bCanUndo); + + BWindow *fWindow; + // Window to which notification messages are sent + int32 fUndoType; + // Nothing, Undo or Redo + BRect fRect; + // Area of background bitmap where change took place + BBitmap *fRestore; + // Changed portion of background bitmap, before change took place + BBitmap *fSelection; + // Selection present before change took place +}; + +#endif /* _ShowImageUndo_h */ + diff --git a/src/apps/showimage/ShowImageView.cpp b/src/apps/showimage/ShowImageView.cpp index fa3023d323..10eb4e70a4 100644 --- a/src/apps/showimage/ShowImageView.cpp +++ b/src/apps/showimage/ShowImageView.cpp @@ -299,6 +299,7 @@ void ShowImageView::DeleteSelBitmap() void ShowImageView::SetImage(const entry_ref *pref) { + fUndo.Clear(); DeleteBitmap(); SetHasSelection(false); fMakesSelection = false; @@ -509,6 +510,7 @@ ShowImageView::SetScaleBilinear(bool s) void ShowImageView::AttachedToWindow() { + fUndo.SetWindow(Window()); FixupScrollBars(); } @@ -814,6 +816,25 @@ ShowImageView::ConstrainToImage(BRect &rect) rect.SetRightBottom(rightBottom); } +BBitmap* +ShowImageView::CopyFromRect(BRect srcRect) +{ + BRect rect(0, 0, srcRect.Width(), srcRect.Height()); + BView view(rect, NULL, B_FOLLOW_NONE, B_WILL_DRAW); + BBitmap *bitmap = new BBitmap(rect, fBitmap->ColorSpace(), true); + if (bitmap == NULL) return NULL; + + if (bitmap->Lock()) { + bitmap->AddChild(&view); + view.DrawBitmap(fBitmap, srcRect, rect); + view.Sync(); + bitmap->RemoveChild(&view); + bitmap->Unlock(); + } + + return bitmap; +} + BBitmap* ShowImageView::CopySelection(uchar alpha, bool imageSize) { @@ -1038,12 +1059,12 @@ ShowImageView::GetMouseButtons() } void -ShowImageView::GetSelMergeRects(BRect &srcBits, BRect &destRect) +ShowImageView::GetMergeRects(BBitmap *merge, BRect selection, BRect &srcBits, BRect &destRect) { - destRect = fSelectionRect; + destRect = selection; ConstrainToImage(destRect); - srcBits = fSelectionRect; + srcBits = selection; if (srcBits.left < 0) srcBits.left = -(srcBits.left); else @@ -1055,20 +1076,22 @@ ShowImageView::GetSelMergeRects(BRect &srcBits, BRect &destRect) if (srcBits.right > fBitmap->Bounds().right) srcBits.right = srcBits.left + destRect.Width(); else - srcBits.right = fSelBitmap->Bounds().right; + srcBits.right = merge->Bounds().right; if (srcBits.bottom > fBitmap->Bounds().bottom) srcBits.bottom = srcBits.top + destRect.Height(); else - srcBits.bottom = fSelBitmap->Bounds().bottom; + srcBits.bottom = merge->Bounds().bottom; } void -ShowImageView::MergeSelection() +ShowImageView::GetSelMergeRects(BRect &srcBits, BRect &destRect) { - if (!HasSelection() || !fSelBitmap) - return; + GetMergeRects(fSelBitmap, fSelectionRect, srcBits, destRect); +} - // Merge selection with background +void +ShowImageView::MergeWithBitmap(BBitmap *merge, BRect selection) +{ BView view(fBitmap->Bounds(), NULL, B_FOLLOW_NONE, B_WILL_DRAW); BBitmap *bitmap = new BBitmap(fBitmap->Bounds(), fBitmap->ColorSpace(), true); if (bitmap == NULL) @@ -1077,10 +1100,9 @@ ShowImageView::MergeSelection() if (bitmap->Lock()) { bitmap->AddChild(&view); view.DrawBitmap(fBitmap, fBitmap->Bounds()); - BRect srcBits, destRect; - GetSelMergeRects(srcBits, destRect); - view.DrawBitmap(fSelBitmap, srcBits, destRect); + GetMergeRects(merge, selection, srcBits, destRect); + view.DrawBitmap(merge, srcBits, destRect); view.Sync(); bitmap->RemoveChild(&view); @@ -1095,6 +1117,25 @@ ShowImageView::MergeSelection() delete bitmap; } +void +ShowImageView::MergeSelection() +{ + if (!HasSelection()) + return; + + if (!fSelBitmap) { + // Even though the merge will not change + // the background image, I still need to save + // some undo information here + fUndo.SetTo(fSelectionRect, NULL, CopySelection()); + return; + } + + // Merge selection with background + fUndo.SetTo(fSelectionRect, CopyFromRect(fSelectionRect), CopySelection()); + MergeWithBitmap(fSelBitmap, fSelectionRect); +} + void ShowImageView::MouseDown(BPoint position) { @@ -1485,6 +1526,45 @@ ShowImageView::PageCount() return fDocumentCount; } +void +ShowImageView::Undo() +{ + int32 undoType = fUndo.GetType(); + if (undoType != UNDO_UNDO && undoType != UNDO_REDO) + return; + + // backup current selection + BRect undoneSelRect; + BBitmap *undoneSelection; + undoneSelRect = fSelectionRect; + undoneSelection = CopySelection(); + + if (undoType == UNDO_UNDO) { + BBitmap *undoRestore; + undoRestore = fUndo.GetRestoreBitmap(); + if (undoRestore) + MergeWithBitmap(undoRestore, fUndo.GetRect()); + } + + // restore previous image/selection + BBitmap *undoSelection; + undoSelection = fUndo.GetSelectionBitmap(); + // NOTE: ShowImageView is responsible for deleting this bitmap + // (Which it will, as it would with a fSelBitmap that it allocated itself) + if (!undoSelection) + SetHasSelection(false); + else { + SetHasSelection(true); + fCopyFromRect = BRect(); + fSelectionRect = fUndo.GetRect(); + fSelBitmap = undoSelection; + } + + fUndo.Undo(undoneSelRect, NULL, undoneSelection); + + Invalidate(); +} + void ShowImageView::AddWhiteRect(BRect &rect) { diff --git a/src/apps/showimage/ShowImageView.h b/src/apps/showimage/ShowImageView.h index 1cf8c596b2..bd37c17567 100644 --- a/src/apps/showimage/ShowImageView.h +++ b/src/apps/showimage/ShowImageView.h @@ -37,6 +37,7 @@ #include #include "Filter.h" +#include "ShowImageUndo.h" #define DELAYED_SCALING 1 @@ -82,6 +83,7 @@ public: int32 CurrentPage(); int32 PageCount(); + void Undo(); void Cut(); void Paste(); void SelectAll(); @@ -113,6 +115,7 @@ public: void SetIcon(bool clear); private: + ShowImageUndo fUndo; enum image_orientation { k0, // 0 k90, // 1 @@ -132,8 +135,10 @@ private: void Notify(const char* status); void AddToRecentDocuments(); void AddWhiteRect(BRect &rect); + void GetMergeRects(BBitmap *merge, BRect selection, BRect &srcBits, BRect &destRect); void GetSelMergeRects(BRect &srcBits, BRect &destRect); void PasteBitmap(BBitmap *bitmap, BPoint point); + void MergeWithBitmap(BBitmap *merge, BRect selection); void MergeSelection(); void DeleteScaler(); void DeleteBitmap(); @@ -155,6 +160,7 @@ private: bool FirstFile(); void ConstrainToImage(BPoint &point); void ConstrainToImage(BRect &rect); + BBitmap* CopyFromRect(BRect srcRect); BBitmap* CopySelection(uchar alpha = 255, bool imageSize = true); bool AddSupportedTypes(BMessage* msg, BBitmap* bitmap); void BeginDrag(BPoint sourcePoint); diff --git a/src/apps/showimage/ShowImageWindow.cpp b/src/apps/showimage/ShowImageWindow.cpp index 07b313213e..d7f88f57f6 100644 --- a/src/apps/showimage/ShowImageWindow.cpp +++ b/src/apps/showimage/ShowImageWindow.cpp @@ -568,6 +568,14 @@ ShowImageWindow::MessageReceived(BMessage *pmsg) break; } + case MSG_UNDO_STATE: + { + bool benable; + if (pmsg->FindBool("can_undo", &benable) == B_OK) + EnableMenuItem(fBar, B_UNDO, benable); + break; + } + case MSG_CLIPBOARD_CHANGED: { // The app sends this message after it examines @@ -580,6 +588,7 @@ ShowImageWindow::MessageReceived(BMessage *pmsg) } case B_UNDO: + fImageView->Undo(); break; case B_CUT: fImageView->Cut();