Added initial implementation of Undo for OBOS ShowImage! Now, users can Undo/Redo merge/paste operations. Still need to enhance Undo further so that other operations can be undone, also need to account for image rotations and similar operations.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5693 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Matthew Wilber
2003-12-18 03:31:28 +00:00
parent a08013c09a
commit 7598450e4f
7 changed files with 286 additions and 12 deletions
+1
View File
@@ -6,6 +6,7 @@ App ShowImage : ShowImageApp.cpp
ShowImageConstants.cpp ShowImageConstants.cpp
ShowImageSettings.cpp ShowImageSettings.cpp
ShowImageStatusView.cpp ShowImageStatusView.cpp
ShowImageUndo.cpp
ShowImageView.cpp ShowImageView.cpp
ShowImageWindow.cpp ShowImageWindow.cpp
PrintOptionsWindow.cpp PrintOptionsWindow.cpp
+1
View File
@@ -44,6 +44,7 @@ const uint32 MSG_CLIPBOARD_CHANGED = 'mCLP';
const uint32 MSG_DITHER_IMAGE = 'mDIM'; const uint32 MSG_DITHER_IMAGE = 'mDIM';
const uint32 MSG_MODIFIED = 'mMOD'; const uint32 MSG_MODIFIED = 'mMOD';
const uint32 MSG_UPDATE_STATUS = 'mUPS'; const uint32 MSG_UPDATE_STATUS = 'mUPS';
const uint32 MSG_UNDO_STATE = 'mUNS';
const uint32 MSG_SELECTION = 'mSEL'; const uint32 MSG_SELECTION = 'mSEL';
const uint32 MSG_SELECTION_BITMAP = 'mSBT'; const uint32 MSG_SELECTION_BITMAP = 'mSBT';
const uint32 MSG_PAGE_FIRST = 'mPGF'; const uint32 MSG_PAGE_FIRST = 'mPGF';
+98
View File
@@ -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
}
+79
View File
@@ -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 <Rect.h>
#include <Bitmap.h>
#include <Window.h>
#include <Message.h>
#include <Messenger.h>
#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 */
+92 -12
View File
@@ -299,6 +299,7 @@ void ShowImageView::DeleteSelBitmap()
void void
ShowImageView::SetImage(const entry_ref *pref) ShowImageView::SetImage(const entry_ref *pref)
{ {
fUndo.Clear();
DeleteBitmap(); DeleteBitmap();
SetHasSelection(false); SetHasSelection(false);
fMakesSelection = false; fMakesSelection = false;
@@ -509,6 +510,7 @@ ShowImageView::SetScaleBilinear(bool s)
void void
ShowImageView::AttachedToWindow() ShowImageView::AttachedToWindow()
{ {
fUndo.SetWindow(Window());
FixupScrollBars(); FixupScrollBars();
} }
@@ -814,6 +816,25 @@ ShowImageView::ConstrainToImage(BRect &rect)
rect.SetRightBottom(rightBottom); 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* BBitmap*
ShowImageView::CopySelection(uchar alpha, bool imageSize) ShowImageView::CopySelection(uchar alpha, bool imageSize)
{ {
@@ -1038,12 +1059,12 @@ ShowImageView::GetMouseButtons()
} }
void void
ShowImageView::GetSelMergeRects(BRect &srcBits, BRect &destRect) ShowImageView::GetMergeRects(BBitmap *merge, BRect selection, BRect &srcBits, BRect &destRect)
{ {
destRect = fSelectionRect; destRect = selection;
ConstrainToImage(destRect); ConstrainToImage(destRect);
srcBits = fSelectionRect; srcBits = selection;
if (srcBits.left < 0) if (srcBits.left < 0)
srcBits.left = -(srcBits.left); srcBits.left = -(srcBits.left);
else else
@@ -1055,20 +1076,22 @@ ShowImageView::GetSelMergeRects(BRect &srcBits, BRect &destRect)
if (srcBits.right > fBitmap->Bounds().right) if (srcBits.right > fBitmap->Bounds().right)
srcBits.right = srcBits.left + destRect.Width(); srcBits.right = srcBits.left + destRect.Width();
else else
srcBits.right = fSelBitmap->Bounds().right; srcBits.right = merge->Bounds().right;
if (srcBits.bottom > fBitmap->Bounds().bottom) if (srcBits.bottom > fBitmap->Bounds().bottom)
srcBits.bottom = srcBits.top + destRect.Height(); srcBits.bottom = srcBits.top + destRect.Height();
else else
srcBits.bottom = fSelBitmap->Bounds().bottom; srcBits.bottom = merge->Bounds().bottom;
} }
void void
ShowImageView::MergeSelection() ShowImageView::GetSelMergeRects(BRect &srcBits, BRect &destRect)
{ {
if (!HasSelection() || !fSelBitmap) GetMergeRects(fSelBitmap, fSelectionRect, srcBits, destRect);
return; }
// Merge selection with background void
ShowImageView::MergeWithBitmap(BBitmap *merge, BRect selection)
{
BView view(fBitmap->Bounds(), NULL, B_FOLLOW_NONE, B_WILL_DRAW); BView view(fBitmap->Bounds(), NULL, B_FOLLOW_NONE, B_WILL_DRAW);
BBitmap *bitmap = new BBitmap(fBitmap->Bounds(), fBitmap->ColorSpace(), true); BBitmap *bitmap = new BBitmap(fBitmap->Bounds(), fBitmap->ColorSpace(), true);
if (bitmap == NULL) if (bitmap == NULL)
@@ -1077,10 +1100,9 @@ ShowImageView::MergeSelection()
if (bitmap->Lock()) { if (bitmap->Lock()) {
bitmap->AddChild(&view); bitmap->AddChild(&view);
view.DrawBitmap(fBitmap, fBitmap->Bounds()); view.DrawBitmap(fBitmap, fBitmap->Bounds());
BRect srcBits, destRect; BRect srcBits, destRect;
GetSelMergeRects(srcBits, destRect); GetMergeRects(merge, selection, srcBits, destRect);
view.DrawBitmap(fSelBitmap, srcBits, destRect); view.DrawBitmap(merge, srcBits, destRect);
view.Sync(); view.Sync();
bitmap->RemoveChild(&view); bitmap->RemoveChild(&view);
@@ -1095,6 +1117,25 @@ ShowImageView::MergeSelection()
delete bitmap; 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 void
ShowImageView::MouseDown(BPoint position) ShowImageView::MouseDown(BPoint position)
{ {
@@ -1485,6 +1526,45 @@ ShowImageView::PageCount()
return fDocumentCount; 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 void
ShowImageView::AddWhiteRect(BRect &rect) ShowImageView::AddWhiteRect(BRect &rect)
{ {
+6
View File
@@ -37,6 +37,7 @@
#include <TranslatorRoster.h> #include <TranslatorRoster.h>
#include "Filter.h" #include "Filter.h"
#include "ShowImageUndo.h"
#define DELAYED_SCALING 1 #define DELAYED_SCALING 1
@@ -82,6 +83,7 @@ public:
int32 CurrentPage(); int32 CurrentPage();
int32 PageCount(); int32 PageCount();
void Undo();
void Cut(); void Cut();
void Paste(); void Paste();
void SelectAll(); void SelectAll();
@@ -113,6 +115,7 @@ public:
void SetIcon(bool clear); void SetIcon(bool clear);
private: private:
ShowImageUndo fUndo;
enum image_orientation { enum image_orientation {
k0, // 0 k0, // 0
k90, // 1 k90, // 1
@@ -132,8 +135,10 @@ private:
void Notify(const char* status); void Notify(const char* status);
void AddToRecentDocuments(); void AddToRecentDocuments();
void AddWhiteRect(BRect &rect); void AddWhiteRect(BRect &rect);
void GetMergeRects(BBitmap *merge, BRect selection, BRect &srcBits, BRect &destRect);
void GetSelMergeRects(BRect &srcBits, BRect &destRect); void GetSelMergeRects(BRect &srcBits, BRect &destRect);
void PasteBitmap(BBitmap *bitmap, BPoint point); void PasteBitmap(BBitmap *bitmap, BPoint point);
void MergeWithBitmap(BBitmap *merge, BRect selection);
void MergeSelection(); void MergeSelection();
void DeleteScaler(); void DeleteScaler();
void DeleteBitmap(); void DeleteBitmap();
@@ -155,6 +160,7 @@ private:
bool FirstFile(); bool FirstFile();
void ConstrainToImage(BPoint &point); void ConstrainToImage(BPoint &point);
void ConstrainToImage(BRect &rect); void ConstrainToImage(BRect &rect);
BBitmap* CopyFromRect(BRect srcRect);
BBitmap* CopySelection(uchar alpha = 255, bool imageSize = true); BBitmap* CopySelection(uchar alpha = 255, bool imageSize = true);
bool AddSupportedTypes(BMessage* msg, BBitmap* bitmap); bool AddSupportedTypes(BMessage* msg, BBitmap* bitmap);
void BeginDrag(BPoint sourcePoint); void BeginDrag(BPoint sourcePoint);
+9
View File
@@ -568,6 +568,14 @@ ShowImageWindow::MessageReceived(BMessage *pmsg)
break; 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: case MSG_CLIPBOARD_CHANGED:
{ {
// The app sends this message after it examines // The app sends this message after it examines
@@ -580,6 +588,7 @@ ShowImageWindow::MessageReceived(BMessage *pmsg)
} }
case B_UNDO: case B_UNDO:
fImageView->Undo();
break; break;
case B_CUT: case B_CUT:
fImageView->Cut(); fImageView->Cut();