* Fixed storage of image data in the system clipboard. According to the

comments in the code, different programs do it differently. However, I
   believe we should follow the BeBook documentation. This is the method which
   WonderBrush uses as well, and that one had been tested with other apps like
   Refraction. Potentially, copy&paste could work across GoBe Productive now
   also, but I didn't test.
 * Handle the case where the selection bitmap that gets restored from the
   clipboard has a bounds rectangle with an offset. Use this offset as an
   alternative to the "be:location" hack.
 * Fix the drag bitmap to be semi-transparent on Haiku. B_OP_SELECT does not
   affect the alpha channel on Haiku like it apparently did on BeOS, though
   I am not inclined to change that behavior.
 * Fixed some coding style violations, but tried to mix as little cleanup as
   possible.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37118 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2010-06-12 17:03:53 +00:00
parent 03732070d7
commit 5ab8434cae
3 changed files with 119 additions and 100 deletions
+2 -5
View File
@@ -226,11 +226,8 @@ ShowImageApp::CheckClipboard()
if (be_clipboard->Lock()) {
BMessage* clip = be_clipboard->Data();
if (clip != NULL) {
BString className;
if (clip->FindString("class", &className) == B_OK) {
if (className == "BBitmap")
dataAvailable = true;
}
dataAvailable = clip->HasMessage("image/bitmap")
|| clip->HasMessage("image/x-be-bitmap");
}
be_clipboard->Unlock();
+115 -93
View File
@@ -189,7 +189,7 @@ ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode,
fDocumentCount(1),
fBitmap(NULL),
fDisplayBitmap(NULL),
fSelBitmap(NULL),
fSelectionBitmap(NULL),
fZoom(1.0),
fScaleBilinear(true),
fScaler(NULL),
@@ -475,8 +475,8 @@ ShowImageView::_DeleteBitmap()
void
ShowImageView::_DeleteSelectionBitmap()
{
delete fSelBitmap;
fSelBitmap = NULL;
delete fSelectionBitmap;
fSelectionBitmap = NULL;
}
@@ -1007,11 +1007,12 @@ ShowImageView::Draw(BRect updateRect)
_DrawCaption();
if (_HasSelection()) {
if (fSelBitmap) {
BRect srcBits, destRect;
_GetSelMergeRects(srcBits, destRect);
destRect = _ImageToView(destRect);
DrawBitmap(fSelBitmap, srcBits, destRect);
if (fSelectionBitmap != NULL) {
BRect srcRect;
BRect dstRect;
_GetSelectionMergeRects(srcRect, dstRect);
dstRect = _ImageToView(dstRect);
DrawBitmap(fSelectionBitmap, srcRect, dstRect);
}
_DrawSelectionBox();
}
@@ -1098,7 +1099,8 @@ ShowImageView::_CopySelection(uchar alpha, bool imageSize)
rect.bottom = floorf((rect.bottom + 1.0) * fZoom - 1.0);
}
BView view(rect, NULL, B_FOLLOW_NONE, B_WILL_DRAW);
BBitmap *bitmap = new(nothrow) BBitmap(rect, hasAlpha ? B_RGBA32 : fBitmap->ColorSpace(), true);
BBitmap* bitmap = new(nothrow) BBitmap(rect, hasAlpha ? B_RGBA32
: fBitmap->ColorSpace(), true);
if (bitmap == NULL || !bitmap->IsValid()) {
delete bitmap;
return NULL;
@@ -1106,15 +1108,33 @@ ShowImageView::_CopySelection(uchar alpha, bool imageSize)
if (bitmap->Lock()) {
bitmap->AddChild(&view);
if (fSelBitmap)
view.DrawBitmap(fSelBitmap, fSelBitmap->Bounds(), rect);
else
#ifdef __HAIKU__
// On Haiku, B_OP_SUBSTRACT does not affect alpha like it did on BeOS.
// Don't know if it's better to fix it or not (stippi).
if (hasAlpha) {
view.SetHighColor(0, 0, 0, 0);
view.FillRect(view.Bounds());
view.SetDrawingMode(B_OP_ALPHA);
view.SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_COMPOSITE);
view.SetHighColor(0, 0, 0, alpha);
}
if (fSelectionBitmap) {
view.DrawBitmap(fSelectionBitmap,
fSelectionBitmap->Bounds().OffsetToCopy(B_ORIGIN), rect);
} else
view.DrawBitmap(fBitmap, fCopyFromRect, rect);
#else
if (fSelectionBitmap) {
view.DrawBitmap(fSelectionBitmap,
fSelectionBitmap->Bounds().OffsetToCopy(B_ORIGIN), rect);
} else
view.DrawBitmap(fBitmap, fCopyFromRect, rect);
if (hasAlpha) {
view.SetDrawingMode(B_OP_SUBTRACT);
view.SetHighColor(0, 0, 0, 255-alpha);
view.SetHighColor(0, 0, 0, 255 - alpha);
view.FillRect(rect, B_SOLID_HIGH);
}
#endif
view.Sync();
bitmap->RemoveChild(&view);
bitmap->Unlock();
@@ -1383,47 +1403,41 @@ ShowImageView::_GetMouseButtons()
void
ShowImageView::_GetMergeRects(BBitmap *merge, BRect selection, BRect &srcBits,
BRect &destRect)
ShowImageView::_GetMergeRects(BBitmap* merge, BRect selection, BRect& srcRect,
BRect& dstRect)
{
destRect = selection;
_ConstrainToImage(destRect);
// Constrain dstRect to target image size and apply the same edge offsets
// to the srcRect.
srcBits = selection;
if (srcBits.left < 0)
srcBits.left = -(srcBits.left);
else
srcBits.left = 0;
dstRect = selection;
if (srcBits.top < 0)
srcBits.top = -(srcBits.top);
else
srcBits.top = 0;
BRect clippedDstRect(dstRect);
_ConstrainToImage(clippedDstRect);
if (srcBits.right > fBitmap->Bounds().right)
srcBits.right = srcBits.left + destRect.Width();
else
srcBits.right = merge->Bounds().right;
srcRect = merge->Bounds().OffsetToCopy(B_ORIGIN);
if (srcBits.bottom > fBitmap->Bounds().bottom)
srcBits.bottom = srcBits.top + destRect.Height();
else
srcBits.bottom = merge->Bounds().bottom;
srcRect.left += clippedDstRect.left - dstRect.left;
srcRect.top += clippedDstRect.top - dstRect.top;
srcRect.right += clippedDstRect.right - dstRect.right;
srcRect.bottom += clippedDstRect.bottom - dstRect.bottom;
dstRect = clippedDstRect;
}
void
ShowImageView::_GetSelMergeRects(BRect &srcBits, BRect &destRect)
ShowImageView::_GetSelectionMergeRects(BRect& srcRect, BRect& dstRect)
{
_GetMergeRects(fSelBitmap, fSelectionRect, srcBits, destRect);
_GetMergeRects(fSelectionBitmap, fSelectionRect, srcRect, dstRect);
}
void
ShowImageView::_MergeWithBitmap(BBitmap *merge, BRect selection)
ShowImageView::_MergeWithBitmap(BBitmap* merge, BRect selection)
{
BView view(fBitmap->Bounds(), NULL, B_FOLLOW_NONE, B_WILL_DRAW);
BBitmap *bitmap = new(nothrow) BBitmap(fBitmap->Bounds(), fBitmap->ColorSpace(), true);
BBitmap* bitmap = new(nothrow) BBitmap(fBitmap->Bounds(),
fBitmap->ColorSpace(), true);
if (bitmap == NULL || !bitmap->IsValid()) {
delete bitmap;
return;
@@ -1432,9 +1446,10 @@ ShowImageView::_MergeWithBitmap(BBitmap *merge, BRect selection)
if (bitmap->Lock()) {
bitmap->AddChild(&view);
view.DrawBitmap(fBitmap, fBitmap->Bounds());
BRect srcBits, destRect;
_GetMergeRects(merge, selection, srcBits, destRect);
view.DrawBitmap(merge, srcBits, destRect);
BRect srcRect;
BRect dstRect;
_GetMergeRects(merge, selection, srcRect, dstRect);
view.DrawBitmap(merge, srcRect, dstRect);
view.Sync();
bitmap->RemoveChild(&view);
@@ -1455,17 +1470,17 @@ 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
if (fSelectionBitmap == NULL) {
// Even though the merge will not change the background image,
// undo information still needs to be saved here.
fUndo.SetTo(fSelectionRect, NULL, _CopySelection());
return;
}
// Merge selection with background
fUndo.SetTo(fSelectionRect, _CopyFromRect(fSelectionRect), _CopySelection());
_MergeWithBitmap(fSelBitmap, fSelectionRect);
fUndo.SetTo(fSelectionRect, _CopyFromRect(fSelectionRect),
_CopySelection());
_MergeWithBitmap(fSelectionBitmap, fSelectionRect);
}
@@ -1481,8 +1496,8 @@ ShowImageView::MouseDown(BPoint position)
if (_HasSelection() && fSelectionRect.Contains(point)
&& (buttons & (B_PRIMARY_MOUSE_BUTTON | B_SECONDARY_MOUSE_BUTTON))) {
if (!fSelBitmap)
fSelBitmap = _CopySelection();
if (!fSelectionBitmap)
fSelectionBitmap = _CopySelection();
BPoint sourcePoint = point;
_BeginDrag(sourcePoint);
@@ -1966,14 +1981,14 @@ ShowImageView::Undo()
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)
// (Which it will, as it would with a fSelectionBitmap that it allocated itself)
if (!undoSelection)
_SetHasSelection(false);
else {
fCopyFromRect = BRect();
fSelectionRect = fUndo.GetRect();
_SetHasSelection(true);
fSelBitmap = undoSelection;
fSelectionBitmap = undoSelection;
}
fUndo.Undo(undoneSelRect, NULL, undoneSelection);
@@ -2020,7 +2035,7 @@ ShowImageView::_RemoveSelection(bool toClipboard, bool neverCutBackground)
return;
BRect rect = fSelectionRect;
bool cutBackground = (fSelBitmap) ? false : true;
bool cutBackground = (fSelectionBitmap) ? false : true;
BBitmap* selection = _CopySelection();
BBitmap* restore = NULL;
@@ -2051,48 +2066,60 @@ ShowImageView::Cut()
status_t
ShowImageView::_PasteBitmap(BBitmap *bitmap, BPoint point)
ShowImageView::_PasteBitmap(BBitmap* bitmap, BPoint point)
{
if (bitmap && bitmap->IsValid()) {
_MergeSelection();
if (bitmap == NULL || !bitmap->IsValid())
return B_BAD_VALUE;
fCopyFromRect = BRect();
fSelectionRect = bitmap->Bounds();
_SetHasSelection(true);
fSelBitmap = bitmap;
_MergeSelection();
BRect offsetRect = fSelectionRect;
offsetRect.OffsetBy(point);
if (fBitmap->Bounds().Intersects(offsetRect))
// Move the selection rectangle to desired origin,
// but only if the resulting selection rectangle
// intersects with the background bitmap rectangle
fSelectionRect = offsetRect;
fCopyFromRect = BRect();
fSelectionRect = bitmap->Bounds().OffsetToCopy(B_ORIGIN);
_SetHasSelection(true);
delete fSelectionBitmap;
fSelectionBitmap = bitmap;
Invalidate();
return B_OK;
BRect offsetRect(fSelectionRect.OffsetToCopy(point));
if (fBitmap->Bounds().Intersects(offsetRect)) {
// Move the selection rectangle to desired origin,
// but only if the resulting selection rectangle
// intersects with the background bitmap rectangle
fSelectionRect = offsetRect;
}
printf("bitmap: "); bitmap->Bounds().PrintToStream();
printf("selection: "); fSelectionRect.PrintToStream();
printf("point: "); point.PrintToStream();
return B_ERROR;
Invalidate();
return B_OK;
}
void
ShowImageView::Paste()
{
if (be_clipboard->Lock()) {
BMessage *pclip;
if ((pclip = be_clipboard->Data()) != NULL) {
BPoint point(0, 0);
pclip->FindPoint("be:location", &point);
BBitmap *pbits;
pbits = dynamic_cast<BBitmap *>(BBitmap::Instantiate(pclip));
_PasteBitmap(pbits, point);
}
if (!be_clipboard->Lock())
return;
be_clipboard->Unlock();
BMessage* data = be_clipboard->Data();
if (data != NULL) {
BMessage bitmapArchive;
if (data->FindMessage("image/bitmap", &bitmapArchive) == B_OK
|| data->FindMessage("image/x-be-bitmap", &bitmapArchive)
== B_OK) {
BBitmap* bitmap = dynamic_cast<BBitmap*>(
BBitmap::Instantiate(&bitmapArchive));
if (bitmap != NULL) {
BPoint point;
if (data->FindPoint("be:location", &point) != B_OK)
point = bitmap->Bounds().LeftTop();
_PasteBitmap(bitmap, point);
}
}
}
be_clipboard->Unlock();
}
@@ -2143,21 +2170,16 @@ ShowImageView::CopySelectionToClipboard()
if (data != NULL) {
BBitmap* bitmap = _CopySelection();
if (bitmap != NULL) {
#if 0
// According to BeBook and Becasso, Gobe Productive do the
// following. Paste works in Productive, but not in Becasso and
// original ShowImage.
BMessage msg(B_OK);
// Becasso uses B_TRANSLATOR_BITMAP, BeBook says its unused.
bitmap->Archive(&msg);
data->AddMessage("image/x-be-bitmap", &msg);
#else
// Original ShowImage performs this.
bitmap->Archive(data);
// original ShowImage uses be:location for insertion point
BMessage bitmapArchive;
bitmap->Archive(&bitmapArchive);
// NOTE: Possibly "image/x-be-bitmap" is more correct.
// This works with WonderBrush, though, which in turn had been
// tested with other apps.
data->AddMessage("image/bitmap", &bitmapArchive);
data->AddPoint("be:location", fSelectionRect.LeftTop());
#endif
delete bitmap;
be_clipboard->Commit();
}
}
+2 -2
View File
@@ -143,7 +143,7 @@ class ShowImageView : public BView {
void _AddToRecentDocuments();
void _AddWhiteRect(BRect &rect);
void _GetMergeRects(BBitmap *merge, BRect selection, BRect &srcBits, BRect &destRect);
void _GetSelMergeRects(BRect &srcBits, BRect &destRect);
void _GetSelectionMergeRects(BRect &srcBits, BRect &destRect);
status_t _SetSelection(const entry_ref *pref, BPoint point);
status_t _PasteBitmap(BBitmap *bitmap, BPoint point);
void _MergeWithBitmap(BBitmap *merge, BRect selection);
@@ -211,7 +211,7 @@ class ShowImageView : public BView {
BBitmap *fDisplayBitmap;
// the image to be displayed
// (== fBitmap if the bitmap can be displayed as is)
BBitmap *fSelBitmap; // the bitmap in the selection
BBitmap *fSelectionBitmap; // the bitmap in the selection
float fZoom; // factor to be used to display the image
bool fScaleBilinear; // use bilinear scaling?
Scaler* fScaler; // holds the scaled image if bilinear scaling is enabled