diff --git a/src/apps/showimage/ShowImageConstants.h b/src/apps/showimage/ShowImageConstants.h index a9462d9cda..3aaeff1669 100644 --- a/src/apps/showimage/ShowImageConstants.h +++ b/src/apps/showimage/ShowImageConstants.h @@ -40,9 +40,9 @@ const uint32 MSG_OUTPUT_TYPE = 'BTMN'; const uint32 MSG_SAVE_PANEL = 'mFSP'; const uint32 MSG_CLEAR_SELECT = 'mCSL'; const uint32 MSG_SELECT_ALL = 'mSAL'; -const uint32 MSG_SELECT_NONE = 'mSNO'; const uint32 MSG_DITHER_IMAGE = 'mDIM'; const uint32 MSG_UPDATE_STATUS = 'mUPS'; +const uint32 MSG_SELECTION = 'mSEL'; const uint32 MSG_PAGE_FIRST = 'mPGF'; const uint32 MSG_PAGE_LAST = 'mPGL'; const uint32 MSG_PAGE_NEXT = 'mPGN'; diff --git a/src/apps/showimage/ShowImageView.cpp b/src/apps/showimage/ShowImageView.cpp index 1a7f74241f..fe3b80667b 100644 --- a/src/apps/showimage/ShowImageView.cpp +++ b/src/apps/showimage/ShowImageView.cpp @@ -625,30 +625,10 @@ ShowImageView::Draw(BRect updateRect) if (HasSelection()) { if (fSelBitmap) { - BRect clippedRect, bounds; - clippedRect = fSelectionRect; - ConstrainToImage(clippedRect); - clippedRect = ImageToView(clippedRect); - - bounds = fSelectionRect; - if (bounds.left < 0) - bounds.left = -(bounds.left); - else - bounds.left = 0; - if (bounds.top < 0) - bounds.top = -(bounds.top); - else - bounds.top = 0; - if (bounds.right > fBitmap->Bounds().right) - bounds.right = bounds.left + clippedRect.Width(); - else - bounds.right = fSelBitmap->Bounds().right; - if (bounds.bottom > fBitmap->Bounds().bottom) - bounds.bottom = bounds.top + clippedRect.Height(); - else - bounds.bottom = fSelBitmap->Bounds().bottom; - - DrawBitmap(fSelBitmap, bounds, clippedRect); + BRect srcBits, destRect; + GetSelMergeRects(srcBits, destRect); + destRect = ImageToView(destRect); + DrawBitmap(fSelBitmap, srcBits, destRect); } DrawSelectionBox(fSelectionRect); } @@ -924,6 +904,61 @@ ShowImageView::GetMouseButtons() return buttons; } +void +ShowImageView::GetSelMergeRects(BRect &srcBits, BRect &destRect) +{ + destRect = fSelectionRect; + ConstrainToImage(destRect); + + srcBits = fSelectionRect; + if (srcBits.left < 0) + srcBits.left = -(srcBits.left); + else + srcBits.left = 0; + if (srcBits.top < 0) + srcBits.top = -(srcBits.top); + else + srcBits.top = 0; + if (srcBits.right > fBitmap->Bounds().right) + srcBits.right = srcBits.left + destRect.Width(); + else + srcBits.right = fSelBitmap->Bounds().right; + if (srcBits.bottom > fBitmap->Bounds().bottom) + srcBits.bottom = srcBits.top + destRect.Height(); + else + srcBits.bottom = fSelBitmap->Bounds().bottom; +} + +void +ShowImageView::MergeSelection() +{ + if (!HasSelection() || !fSelBitmap) + return; + + // Merge selection with background + BView view(fBitmap->Bounds(), NULL, B_FOLLOW_NONE, B_WILL_DRAW); + BBitmap *bitmap = new BBitmap(fBitmap->Bounds(), fBitmap->ColorSpace(), true); + if (bitmap == NULL) + return; + + if (bitmap->Lock()) { + bitmap->AddChild(&view); + view.DrawBitmap(fBitmap, fBitmap->Bounds()); + + BRect srcBits, destRect; + GetSelMergeRects(srcBits, destRect); + view.DrawBitmap(fSelBitmap, srcBits, destRect); + + view.Sync(); + bitmap->RemoveChild(&view); + bitmap->Unlock(); + + DeleteBitmap(); + fBitmap = bitmap; + } else + delete bitmap; +} + void ShowImageView::MouseDown(BPoint position) { @@ -971,6 +1006,11 @@ ShowImageView::MouseDown(BPoint position) AnimateSelection(true); } else if (buttons == B_PRIMARY_MOUSE_BUTTON) { + if (HasSelection()) + // If there is an existing selection, + // Make it part of the background image + MergeSelection(); + // begin new selection SetHasSelection(true); fMakesSelection = true; @@ -1271,7 +1311,7 @@ ShowImageView::SelectAll() } void -ShowImageView::Unselect() +ShowImageView::ClearSelection() { if (HasSelection()) { SetHasSelection(false); @@ -1284,6 +1324,11 @@ ShowImageView::SetHasSelection(bool bHasSelection) { DeleteSelBitmap(); fbHasSelection = bHasSelection; + + BMessage msg(MSG_SELECTION); + msg.AddBool("has_selection", fbHasSelection); + BMessenger msgr(Window()); + msgr.SendMessage(&msg); } void diff --git a/src/apps/showimage/ShowImageView.h b/src/apps/showimage/ShowImageView.h index 2029fed3c8..dfee3ed558 100644 --- a/src/apps/showimage/ShowImageView.h +++ b/src/apps/showimage/ShowImageView.h @@ -73,7 +73,7 @@ public: int32 PageCount(); void SelectAll(); - void Unselect(); + void ClearSelection(); void CopySelectionToClipboard(); @@ -112,6 +112,8 @@ private: void AnimateSelection(bool a); void Notify(const char* status); void AddToRecentDocuments(); + void GetSelMergeRects(BRect &srcBits, BRect &destRect); + void MergeSelection(); void DeleteScaler(); void DeleteBitmap(); void DeleteSelBitmap(); diff --git a/src/apps/showimage/ShowImageWindow.cpp b/src/apps/showimage/ShowImageWindow.cpp index b6a5654ae2..f72ffad26a 100644 --- a/src/apps/showimage/ShowImageWindow.cpp +++ b/src/apps/showimage/ShowImageWindow.cpp @@ -258,12 +258,11 @@ ShowImageWindow::LoadMenus(BMenuBar *pbar) AddItemMenu(pmenu, "Undo", B_UNDO, 'Z', 0, 'W', false); pmenu->AddSeparatorItem(); AddItemMenu(pmenu, "Cut", B_CUT, 'X', 0, 'W', false); - AddItemMenu(pmenu, "Copy", B_COPY, 'C', 0, 'W', true); + AddItemMenu(pmenu, "Copy", B_COPY, 'C', 0, 'W', false); AddItemMenu(pmenu, "Paste", B_PASTE, 'V', 0, 'W', false); AddItemMenu(pmenu, "Clear", MSG_CLEAR_SELECT, 0, 0, 'W', false); pmenu->AddSeparatorItem(); AddItemMenu(pmenu, "Select All", MSG_SELECT_ALL, 'A', 0, 'W', true); - AddItemMenu(pmenu, "Select None", MSG_SELECT_NONE, 0, 0, 'W', true); pbar->AddItem(pmenu); pmenu = fpBrowseMenu = new BMenu("Browse"); @@ -500,6 +499,20 @@ ShowImageWindow::MessageReceived(BMessage *pmsg) UpdateTitle(); break; } + + case MSG_SELECTION: + { + // The view sends this message when a selection is + // made or the selection is cleared so that the window + // can update the state of the appropriate menu items + bool benable; + if (pmsg->FindBool("has_selection", &benable) == B_OK) { + EnableMenuItem(fpBar, B_CUT, benable); + EnableMenuItem(fpBar, B_COPY, benable); + EnableMenuItem(fpBar, MSG_CLEAR_SELECT, benable); + } + break; + } case B_UNDO: break; @@ -511,13 +524,11 @@ ShowImageWindow::MessageReceived(BMessage *pmsg) case B_PASTE: break; case MSG_CLEAR_SELECT: + fpImageView->ClearSelection(); break; case MSG_SELECT_ALL: fpImageView->SelectAll(); break; - case MSG_SELECT_NONE: - fpImageView->Unselect(); - break; case MSG_PAGE_FIRST: fpImageView->FirstPage();