From 4fd570d3077a142a11ceac82e4f2230fffd3e5c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Sun, 24 Oct 2010 16:36:27 +0000 Subject: [PATCH] * Fixed another pet peeve of mine: you can now always zoom, no matter if you have enabled the shrink/stretch option. * Renamed "zoom to window" to "stretch to window". * Readded the shrink/stretch options to the full screen context menu only. * Renamed GetShrinkToBounds() to ShrinkToBounds() as it's a simple getter. * Changed how and when the shrink/stretch options come into play. Shrinking is now only set once, when the image is first shown. * Added snapping in ZoomIn(), and ZoomOut(): they will now always choose 1.0, and the "fit to window" zoom level when they are close. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39129 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/showimage/ShowImageConstants.h | 2 +- src/apps/showimage/ShowImageView.cpp | 183 +++++++++++++++--------- src/apps/showimage/ShowImageView.h | 27 ++-- src/apps/showimage/ShowImageWindow.cpp | 46 +++--- src/apps/showimage/ShowImageWindow.h | 4 +- 5 files changed, 151 insertions(+), 111 deletions(-) diff --git a/src/apps/showimage/ShowImageConstants.h b/src/apps/showimage/ShowImageConstants.h index 028f0d4fdc..e26e192064 100644 --- a/src/apps/showimage/ShowImageConstants.h +++ b/src/apps/showimage/ShowImageConstants.h @@ -38,7 +38,7 @@ enum { MSG_FILE_NEXT = 'mFLN', MSG_FILE_PREV = 'mFLP', MSG_SHRINK_TO_WINDOW = 'mSTW', - MSG_ZOOM_TO_WINDOW = 'mZTW', + MSG_STRETCH_TO_WINDOW = 'mZTW', MSG_ROTATE_90 = 'mR90', MSG_ROTATE_270 = 'mR27', MSG_FLIP_LEFT_TO_RIGHT = 'mFLR', diff --git a/src/apps/showimage/ShowImageView.cpp b/src/apps/showimage/ShowImageView.cpp index 87a222ff18..9a91e5f8f6 100644 --- a/src/apps/showimage/ShowImageView.cpp +++ b/src/apps/showimage/ShowImageView.cpp @@ -197,8 +197,8 @@ ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode, fBitmapLocationInView(0.0, 0.0), fShrinkToBounds(true), - fZoomToBounds(true), - fShrinkOrZoomToBounds(true), + fStretchToBounds(false), + fFitToBoundsZoom(1.0), fFullScreen(false), fScrollingBitmap(false), fCreatingSelection(false), @@ -218,7 +218,7 @@ ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode, settings = my_app->Settings(); if (settings->Lock()) { fShrinkToBounds = settings->GetBool("ShrinkToBounds", fShrinkToBounds); - fZoomToBounds = settings->GetBool("ZoomToBounds", fZoomToBounds); + fStretchToBounds = settings->GetBool("ZoomToBounds", fStretchToBounds); fSlideShowDelay = settings->GetInt32("SlideShowDelay", fSlideShowDelay); fScaleBilinear = settings->GetBool("ScaleBilinear", fScaleBilinear); settings->Unlock(); @@ -382,7 +382,7 @@ ShowImageView::_DeleteSelectionBitmap() status_t -ShowImageView::SetImage(const entry_ref *ref) +ShowImageView::SetImage(const entry_ref* ref) { // If no file was specified, load the specified page of // the current file. @@ -502,7 +502,9 @@ ShowImageView::SetImage(const entry_ref *ref) fCaption << ", " << fDocumentIndex << "/" << fDocumentCount; fCaption << ", " << fImageType; - fZoom = 1.0; + + fFitToBoundsZoom = _FitToBoundsZoom(); + ResetZoom(); be_roster->AddToRecentDocuments(&fCurrentRef, kApplicationSignature); @@ -571,20 +573,20 @@ ShowImageView::SetShrinkToBounds(bool enable) if (fShrinkToBounds != enable) { _SettingsSetBool("ShrinkToBounds", enable); fShrinkToBounds = enable; - FixupScrollBars(); - Invalidate(); + if (enable) + SetZoom(fFitToBoundsZoom); } } void -ShowImageView::SetZoomToBounds(bool enable) +ShowImageView::SetStretchToBounds(bool enable) { - if (fZoomToBounds != enable) { + if (fStretchToBounds != enable) { _SettingsSetBool("ZoomToBounds", enable); - fZoomToBounds = enable; - FixupScrollBars(); - Invalidate(); + fStretchToBounds = enable; + if (enable) + SetZoom(fFitToBoundsZoom); } } @@ -641,6 +643,7 @@ ShowImageView::SetScaleBilinear(bool enabled) void ShowImageView::AttachedToWindow() { + ResetZoom(); fUndo.SetWindow(Window()); FixupScrollBars(); @@ -656,6 +659,42 @@ ShowImageView::DetachedFromWindow() } +bool +ShowImageView::_ShouldShrink() const +{ + return fShrinkToBounds && fBitmap->Bounds().Width() > Bounds().Width() + && fBitmap->Bounds().Height() > Bounds().Height(); +} + + +bool +ShowImageView::_ShouldStretch() const +{ + return fStretchToBounds && fBitmap->Bounds().Width() < Bounds().Width() + && fBitmap->Bounds().Height() < Bounds().Height(); +} + + +float +ShowImageView::_FitToBoundsZoom() const +{ + // the width/height of the bitmap (in pixels) + float bitmapWidth = fBitmap->Bounds().Width() + 1; + float bitmapHeight = fBitmap->Bounds().Height() + 1; + + // the available width/height for layouting the bitmap (in pixels) + float width = Bounds().Width() + 1; + float height = Bounds().Height() + 1; + + float zoom = width / bitmapWidth; + + if (zoom * bitmapHeight <= height) + return zoom; + + return height / bitmapHeight; +} + + BRect ShowImageView::_AlignBitmap() { @@ -672,54 +711,25 @@ ShowImageView::_AlignBitmap() if (width == 0 || height == 0) return rect; - fShrinkOrZoomToBounds = (fShrinkToBounds - && (bitmapWidth >= width || bitmapHeight >= height)) - || (fZoomToBounds && (bitmapWidth < width && bitmapHeight < height)); - if (fShrinkOrZoomToBounds) { - float s = width / bitmapWidth; + // zoom image + rect.right = floorf(bitmapWidth * fZoom) - 1; + rect.bottom = floorf(bitmapHeight * fZoom) - 1; - if (s * bitmapHeight <= height) { - rect.right = width - 1; - rect.bottom = static_cast(s * bitmapHeight) - 1; - // center vertically - rect.OffsetBy(0, static_cast((height - rect.Height()) / 2)); - } else { - s = height / bitmapHeight; - rect.right = static_cast(s * bitmapWidth) - 1; - rect.bottom = height - 1; - // center horizontally - rect.OffsetBy(static_cast((width - rect.Width()) / 2), 0); - } - } else { - // zoom image - rect.right = floorf(bitmapWidth * fZoom) - 1; - rect.bottom = floorf(bitmapHeight * fZoom) - 1; + // update the bitmap size after the zoom + bitmapWidth = rect.Width() + 1.0; + bitmapHeight = rect.Height() + 1.0; - // update the bitmap size after the zoom - bitmapWidth = rect.Width() + 1.0; - bitmapHeight = rect.Height() + 1.0; + // always align in the center if the bitmap is smaller than the window + if (width > bitmapWidth) + rect.OffsetBy(floorf((width - bitmapWidth) / 2.0), 0); - // always align in the center - if (width > bitmapWidth) - rect.OffsetBy(floorf((width - bitmapWidth) / 2.0), 0); - - if (height > bitmapHeight) - rect.OffsetBy(0, floorf((height - bitmapHeight) / 2.0)); - } + if (height > bitmapHeight) + rect.OffsetBy(0, floorf((height - bitmapHeight) / 2.0)); return rect; } -void -ShowImageView::_Setup(BRect rect) -{ - fBitmapLocationInView.x = floorf(rect.left); - fBitmapLocationInView.y = floorf(rect.top); - fZoom = (rect.Width() + 1.0) / (fBitmap->Bounds().Width() + 1.0); -} - - void ShowImageView::_DrawBackground(BRect border) { @@ -825,7 +835,8 @@ ShowImageView::Draw(BRect updateRect) } BRect rect = _AlignBitmap(); - _Setup(rect); + fBitmapLocationInView.x = floorf(rect.left); + fBitmapLocationInView.y = floorf(rect.top); _DrawBackground(rect); _DrawImage(rect); @@ -847,9 +858,10 @@ ShowImageView::Draw(BRect updateRect) void -ShowImageView::FrameResized(float /* width */, float /* height */) +ShowImageView::FrameResized(float /*width*/, float /*height*/) { - FixupScrollBars(); + fFitToBoundsZoom = _FitToBoundsZoom(); + SetZoom(_ShouldStretch() ? fFitToBoundsZoom : fZoom); } @@ -1910,8 +1922,19 @@ ShowImageView::_FirstFile() void -ShowImageView::SetZoom(BPoint where, float zoom) +ShowImageView::SetZoom(float zoom, BPoint where) { + if (zoom > 32) + zoom = 32; + if (zoom < fFitToBoundsZoom / 2) + zoom = fFitToBoundsZoom / 2; + + if (zoom == fZoom) { + // window size might have changed + FixupScrollBars(); + return; + } + // Invalidate before scrolling, as that prevents the app_server // to do the scrolling server side Invalidate(); @@ -1941,16 +1964,48 @@ ShowImageView::SetZoom(BPoint where, float zoom) void ShowImageView::ZoomIn(BPoint where) { - if (fZoom < 16) - SetZoom(where, fZoom * 1.2); + // snap zoom to "fit to bounds", and "original size" + float zoom = fZoom * 1.2; + float zoomSnap = fZoom * 1.25; + if (fZoom < fFitToBoundsZoom && zoomSnap > fFitToBoundsZoom) + zoom = fFitToBoundsZoom; + if (fZoom < 1.0 && zoomSnap > 1.0) + zoom = 1.0; + + SetZoom(zoom, where); } void ShowImageView::ZoomOut(BPoint where) { - if (fZoom > 0.25) - SetZoom(where, fZoom * 0.8); + // snap zoom to "fit to bounds", and "original size" + float zoom = fZoom / 1.2; + float zoomSnap = fZoom / 1.25; + if (fZoom > fFitToBoundsZoom && zoomSnap < fFitToBoundsZoom) + zoom = fFitToBoundsZoom; + if (fZoom > 1.0 && zoomSnap < 1.0) + zoom = 1.0; + + SetZoom(zoom, where); +} + + +/*! Resets the zoom to what it should be when opening an image, depending + on the current settings. +*/ +void +ShowImageView::ResetZoom() +{ + if (fBitmap == NULL) + return; + + fFitToBoundsZoom = _FitToBoundsZoom(); + + if (_ShouldShrink() || _ShouldStretch()) + SetZoom(fFitToBoundsZoom); + else + SetZoom(1.0); } @@ -2006,10 +2061,10 @@ ShowImageView::_DoImageOperation(ImageProcessor::operation op, bool quiet) // update orientation state if (op != ImageProcessor::kInvert) { // Note: If one of these fails, check its definition in class ImageProcessor. - ASSERT(ImageProcessor::kRotateClockwise < ImageProcessor::kNumberOfAffineTransformations); - ASSERT(ImageProcessor::kRotateCounterClockwise < ImageProcessor::kNumberOfAffineTransformations); - ASSERT(ImageProcessor::kFlipLeftToRight < ImageProcessor::kNumberOfAffineTransformations); - ASSERT(ImageProcessor::kFlipTopToBottom < ImageProcessor::kNumberOfAffineTransformations); +// ASSERT(ImageProcessor::kRotateClockwise < ImageProcessor::kNumberOfAffineTransformations); +// ASSERT(ImageProcessor::kRotateCounterClockwise < ImageProcessor::kNumberOfAffineTransformations); +// ASSERT(ImageProcessor::kFlipLeftToRight < ImageProcessor::kNumberOfAffineTransformations); +// ASSERT(ImageProcessor::kFlipTopToBottom < ImageProcessor::kNumberOfAffineTransformations); fImageOrientation = fTransformation[op][fImageOrientation]; } diff --git a/src/apps/showimage/ShowImageView.h b/src/apps/showimage/ShowImageView.h index e2058a1656..0c99b64aaf 100644 --- a/src/apps/showimage/ShowImageView.h +++ b/src/apps/showimage/ShowImageView.h @@ -70,11 +70,11 @@ public: bool GetScaleBilinear() { return fScaleBilinear; } void SetShowCaption(bool show); void SetShrinkToBounds(bool enable); - bool GetShrinkToBounds() const + bool ShrinkToBounds() const { return fShrinkToBounds; } - void SetZoomToBounds(bool enable); - bool GetZoomToBounds() const - { return fZoomToBounds; } + void SetStretchToBounds(bool enable); + bool StretchToBounds() const + { return fStretchToBounds; } void SetFullScreen(bool fullScreen); BBitmap* GetBitmap(); @@ -111,9 +111,11 @@ public: bool SlideShowStarted() const { return fSlideShow; } void StartSlideShow(); void StopSlideShow(); - void SetZoom(BPoint where, float zoom); + void SetZoom(float zoom, + BPoint where = BPoint(-1, -1)); void ZoomIn(BPoint where = BPoint(-1, -1)); void ZoomOut(BPoint where = BPoint(-1, -1)); + void ResetZoom(); // Image manipulation void Rotate(int degree); // 90 and 270 only @@ -155,21 +157,16 @@ private: void _DeleteBitmap(); void _DeleteSelectionBitmap(); - int32 _BytesPerPixel(color_space cs) const; - void _CopyPixel(uchar* dest, int32 destX, - int32 destY, int32 destBPR, uchar* src, - int32 x, int32 y, int32 bpr, int32 bpp); - void _InvertPixel(int32 x, int32 y, uchar* dest, - int32 destBPR, uchar* src, int32 bpr, - int32 bpp); void _DoImageOperation( enum ImageProcessor::operation op, bool quiet = false); void _UserDoImageOperation( enum ImageProcessor::operation op, bool quiet = false); + bool _ShouldShrink() const; + bool _ShouldStretch() const; + float _FitToBoundsZoom() const; BRect _AlignBitmap(); - void _Setup(BRect r); bool _IsImage(const entry_ref* pref); static int _CompareEntries(const void* a, const void* b); void _FreeEntries(BList* entries); @@ -235,8 +232,8 @@ private: BPoint fBitmapLocationInView; bool fShrinkToBounds; - bool fZoomToBounds; - bool fShrinkOrZoomToBounds; + bool fStretchToBounds; + float fFitToBoundsZoom; bool fFullScreen; bool fScrollingBitmap; bool fCreatingSelection; diff --git a/src/apps/showimage/ShowImageWindow.cpp b/src/apps/showimage/ShowImageWindow.cpp index 8407a98f03..61c546dbed 100644 --- a/src/apps/showimage/ShowImageWindow.cpp +++ b/src/apps/showimage/ShowImageWindow.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2003-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2003-2010, Haiku, Inc. All Rights Reserved. * Copyright 2004-2005 yellowTAB GmbH. All Rights Reserverd. * Copyright 2006 Bernd Korz. All Rights Reserved * Distributed under the terms of the MIT License. @@ -12,6 +12,7 @@ * Bernd Korz */ + #include "ShowImageWindow.h" #include @@ -213,6 +214,7 @@ ShowImageWindow::ShowImageWindow(const entry_ref* ref, // every 1/10 second; ShowImageView needs it for marching ants WindowRedimension(fImageView->GetBitmap()); + fImageView->ResetZoom(); fImageView->MakeFocus(true); // to receive KeyDown messages Show(); @@ -292,7 +294,7 @@ ShowImageWindow::_BuildViewMenu(BMenu* menu, bool popupMenu) menu->AddSeparatorItem(); - if (!popupMenu) { + if (!popupMenu || fFullScreen) { _AddItemMenu(menu, B_TRANSLATE("High-quality zooming"), MSG_SCALE_BILINEAR, 0, 0, this); @@ -300,8 +302,8 @@ ShowImageWindow::_BuildViewMenu(BMenu* menu, bool popupMenu) _AddItemMenu(menu, B_TRANSLATE("Shrink to window"), MSG_SHRINK_TO_WINDOW, 0, 0, this); - _AddItemMenu(menu, B_TRANSLATE("Zoom to window"), - MSG_ZOOM_TO_WINDOW, 0, 0, this); + _AddItemMenu(menu, B_TRANSLATE("Stretch to window"), + MSG_STRETCH_TO_WINDOW, 0, 0, this); menu->AddSeparatorItem(); } @@ -315,18 +317,8 @@ ShowImageWindow::_BuildViewMenu(BMenu* menu, bool popupMenu) _MarkMenuItem(menu, MSG_SHOW_CAPTION, fShowCaption); _MarkMenuItem(menu, MSG_SCALE_BILINEAR, fImageView->GetScaleBilinear()); - - bool shrink, zoom, enabled; - - shrink = fImageView->GetShrinkToBounds(); - zoom = fImageView->GetZoomToBounds(); - _MarkMenuItem(menu, MSG_SHRINK_TO_WINDOW, shrink); - _MarkMenuItem(menu, MSG_ZOOM_TO_WINDOW, zoom); - - enabled = !(shrink || zoom); - _EnableMenuItem(menu, MSG_ORIGINAL_SIZE, enabled); - _EnableMenuItem(menu, MSG_ZOOM_IN, enabled); - _EnableMenuItem(menu, MSG_ZOOM_OUT, enabled); + _MarkMenuItem(menu, MSG_SHRINK_TO_WINDOW, fImageView->ShrinkToBounds()); + _MarkMenuItem(menu, MSG_STRETCH_TO_WINDOW, fImageView->StretchToBounds()); if (popupMenu) { menu->AddSeparatorItem(); @@ -361,7 +353,7 @@ ShowImageWindow::AddMenus(BMenuBar* bar) MSG_PREPARE_PRINT, 'P', 0, this); menu->AddSeparatorItem(); _AddItemMenu(menu, B_TRANSLATE("About ShowImage" B_UTF8_ELLIPSIS), - B_ABOUT_REQUESTED, 0, 0, be_app); + B_ABOUT_REQUESTED, 0, 0, be_app); menu->AddSeparatorItem(); _AddItemMenu(menu, B_TRANSLATE("Quit"), B_QUIT_REQUESTED, 'Q', 0, be_app); bar->AddItem(menu); @@ -418,9 +410,10 @@ ShowImageWindow::AddMenus(BMenuBar* bar) BMenuItem* ShowImageWindow::_AddItemMenu(BMenu* menu, const char* label, uint32 what, - const char shortcut, uint32 modifier, const BHandler* target, bool enabled) + char shortcut, uint32 modifier, const BHandler* target, bool enabled) { - BMenuItem* item = new BMenuItem(label, new BMessage(what), shortcut, modifier); + BMenuItem* item = new BMenuItem(label, new BMessage(what), shortcut, + modifier); menu->AddItem(item); item->SetTarget(target); @@ -553,12 +546,7 @@ ShowImageWindow::_ResizeToWindow(bool shrink, uint32 what) if (shrink) fImageView->SetShrinkToBounds(enabled); else - fImageView->SetZoomToBounds(enabled); - - enabled = !(fImageView->GetShrinkToBounds() || fImageView->GetZoomToBounds()); - _EnableMenuItem(fBar, MSG_ORIGINAL_SIZE, enabled); - _EnableMenuItem(fBar, MSG_ZOOM_IN, enabled); - _EnableMenuItem(fBar, MSG_ZOOM_OUT, enabled); + fImageView->SetStretchToBounds(enabled); } @@ -657,8 +645,8 @@ ShowImageWindow::MessageReceived(BMessage* message) if (messageProvidesSize) { _UpdateResizerWindow(fWidth, fHeight); - if (!fImageView->GetZoomToBounds() - && !fImageView->GetShrinkToBounds() + if (!fImageView->StretchToBounds() + && !fImageView->ShrinkToBounds() && !fFullScreen) WindowRedimension(fImageView->GetBitmap()); } @@ -766,7 +754,7 @@ ShowImageWindow::MessageReceived(BMessage* message) _ResizeToWindow(true, message->what); break; - case MSG_ZOOM_TO_WINDOW: + case MSG_STRETCH_TO_WINDOW: _ResizeToWindow(false, message->what); break; @@ -866,7 +854,7 @@ ShowImageWindow::MessageReceived(BMessage* message) break; case MSG_ORIGINAL_SIZE: - fImageView->SetZoom(BPoint(-1, -1), 1.0); + fImageView->SetZoom(1.0); break; case MSG_SCALE_BILINEAR: diff --git a/src/apps/showimage/ShowImageWindow.h b/src/apps/showimage/ShowImageWindow.h index afae323471..31d41fd58e 100644 --- a/src/apps/showimage/ShowImageWindow.h +++ b/src/apps/showimage/ShowImageWindow.h @@ -48,8 +48,8 @@ private: void _BuildViewMenu(BMenu* menu, bool popupMenu); BMenuItem* _AddItemMenu(BMenu* menu, const char* label, - uint32 what, const char shortcut, - uint32 modifier, const BHandler* target, + uint32 what, char shortcut, uint32 modifier, + const BHandler* target, bool enabled = true); BMenuItem* _AddDelayItem(BMenu* menu, const char* label, float value);