diff --git a/src/apps/showimage/Filter.cpp b/src/apps/showimage/Filter.cpp new file mode 100644 index 0000000000..290bb9c9a9 --- /dev/null +++ b/src/apps/showimage/Filter.cpp @@ -0,0 +1,134 @@ +/*****************************************************************************/ +// Filter +// Written by Michael Pfeiffer +// +// Filter.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 +#include "Filter.h" +#include "Scale.h" + +Filter::Filter(BBitmap* image, BMessenger listener, uint32 what) + : fListener(listener) + , fWhat(what) + , fIsRunning(false) + , fWorkerThread(-1) + , fSrcImage(image) + , fDestImage(NULL) +{ +} + +Filter::~Filter() +{ + Stop(); + delete fDestImage; +} + +BBitmap* +Filter::GetBitmap() +{ + if (fDestImage == NULL) { + fDestImage = CreateDestImage(fSrcImage); + } + return fDestImage; +} + +status_t +Filter::worker_thread(void* data) +{ + Filter* filter = (Filter*)data; + filter->Run(); + if (filter->fIsRunning) { + filter->fListener.SendMessage(filter->fWhat); + filter->fIsRunning = false; + } + return B_OK; +} + +void +Filter::Start() +{ + GetBitmap(); + if (fSrcImage == NULL || fDestImage == NULL) return; + fWorkerThread = spawn_thread(worker_thread, "filter", suggest_thread_priority(B_STATUS_RENDERING), this); + if (fWorkerThread >= 0) { + fIsRunning = true; + resume_thread(fWorkerThread); + } +} + +void +Filter::Stop() +{ + if (fIsRunning) { + fIsRunning = false; + status_t st; + wait_for_thread(fWorkerThread, &st); + } +} + +bool +Filter::IsRunning() const +{ + return fIsRunning; +} + +BBitmap* +Filter::GetSrcImage() +{ + return fSrcImage; +} + +BBitmap* +Filter::GetDestImage() +{ + return fDestImage; +} + +Scaler::Scaler(BBitmap* image, float scale, BMessenger listener, uint32 what) + : Filter(image, listener, what) + , fScale(scale) +{ +} + +Scaler::~Scaler() +{ +} + +BBitmap* +Scaler::CreateDestImage(BBitmap* srcImage) +{ + if (srcImage == NULL || srcImage->ColorSpace() != B_RGB32 && srcImage->ColorSpace() !=B_RGBA32) return NULL; + BRect src(srcImage->Bounds()); + BRect dest(0, 0, (src.Width()+1)*fScale - 1, (src.Height()+1)*fScale - 1); + BBitmap* destImage = new BBitmap(dest, srcImage->ColorSpace()); + return destImage; +} + +void +Scaler::Run() +{ + scale(GetSrcImage(), GetDestImage(), IsRunningAddr(), fScale, fScale); +} diff --git a/src/apps/showimage/Filter.h b/src/apps/showimage/Filter.h new file mode 100644 index 0000000000..52da652497 --- /dev/null +++ b/src/apps/showimage/Filter.h @@ -0,0 +1,77 @@ +/*****************************************************************************/ +// Filter +// Written by Michael Pfeiffer +// +// Filter.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 _Filter_h +#define _Filter_h + +#include +#include +#include + +class Filter { +public: + Filter(BBitmap* image, BMessenger listener, uint32 what); + virtual ~Filter(); + + BBitmap* GetBitmap(); + + void Start(); + void Stop(); + bool IsRunning() const; + volatile bool *IsRunningAddr() { return &fIsRunning; } + + virtual BBitmap* CreateDestImage(BBitmap* srcImage) = 0; + virtual void Run() = 0; + +protected: + BBitmap* GetSrcImage(); + BBitmap* GetDestImage(); + +private: + BMessenger fListener; + uint32 fWhat; + static status_t worker_thread(void* data); + volatile bool fIsRunning; + thread_id fWorkerThread; + BBitmap* fSrcImage; + BBitmap* fDestImage; +}; + +class Scaler : public Filter { +public: + Scaler(BBitmap* image, float scale, BMessenger listener, uint32 what); + ~Scaler(); + + BBitmap* CreateDestImage(BBitmap* srcImage); + void Run(); + float Scale() const { return fScale; } +private: + float fScale; +}; + +#endif diff --git a/src/apps/showimage/Jamfile b/src/apps/showimage/Jamfile index c8445788a1..6e8b14a4d9 100644 --- a/src/apps/showimage/Jamfile +++ b/src/apps/showimage/Jamfile @@ -8,6 +8,8 @@ App ShowImage : ShowImageApp.cpp ShowImageView.cpp ShowImageWindow.cpp PrintOptionsWindow.cpp + Filter.cpp + Scale.cpp ; LinkSharedOSLibs ShowImage : be tracker translation ; diff --git a/src/apps/showimage/PrintOptionsWindow.cpp b/src/apps/showimage/PrintOptionsWindow.cpp index 1a2ed71a52..b186708aec 100644 --- a/src/apps/showimage/PrintOptionsWindow.cpp +++ b/src/apps/showimage/PrintOptionsWindow.cpp @@ -1,6 +1,6 @@ /*****************************************************************************/ // PrintOptionsWindow -// Written by Fernando Francisco de Oliveira, Michael Wilber, Michael Pfeiffer +// Written by Michael Pfeiffer // // PrintOptionsWindow.cpp // diff --git a/src/apps/showimage/PrintOptionsWindow.h b/src/apps/showimage/PrintOptionsWindow.h index 56c1e4bde0..1c8b5a1e23 100644 --- a/src/apps/showimage/PrintOptionsWindow.h +++ b/src/apps/showimage/PrintOptionsWindow.h @@ -1,6 +1,6 @@ /*****************************************************************************/ // PrintOptionsWindow -// Written by Fernando Francisco de Oliveira, Michael Wilber, Michael Pfeiffer +// Written by Michael Pfeiffer // // PrintOptionsWindow.h // diff --git a/src/apps/showimage/Scale.cpp b/src/apps/showimage/Scale.cpp new file mode 100644 index 0000000000..78055fcdcc --- /dev/null +++ b/src/apps/showimage/Scale.cpp @@ -0,0 +1,253 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#include "Scale.h" +#include +#include + +typedef struct { + long x_i; + float p; + float p1; +} row_values; + +static void +scale_bilinear_8(const BBitmap *src, BBitmap *dest, + const float xFactor, const float yFactor, + volatile bool *running) +{ + register long drows, dcols, srows, scols; + register unsigned char *spixptr, *dpixptr, *spix1, *spix2, *dpix; + register unsigned long slb, dlb; + register long i, j; + float p, q, p1, q1; + float xfac, yfac; + float xfac_inv, yfac_inv; + float src_y_f; + long src_y_i, src_x_i; + register unsigned char a, b, c, d; + row_values *r, *rptr; + float x_f; + float result; + + // Get values from image + dpix = dpixptr = (unsigned char *)dest->Bits(); + spixptr = (unsigned char *)src->Bits(); + srows = src->Bounds().IntegerHeight()+1; + scols = src->Bounds().IntegerWidth()+1; + drows = dest->Bounds().IntegerHeight()+1; + dcols = dest->Bounds().IntegerWidth()+1; + slb = src->BytesPerRow(); + dlb = dest->BytesPerRow(); + + // Compute scale factors and inverse scale factors + xfac = xFactor; + yfac = yFactor; + + if (xfac < 0.0) + xfac = (float) dcols / (float) scols; + if (yfac < 0.0) + yfac = (float) drows / (float) srows; + + xfac_inv = 1.0 / xfac; + yfac_inv = 1.0 / yfac; + + + // Allocate buffer for storing the values of ma and m1 + rptr = r = (row_values *)malloc (sizeof(row_values) * dcols); + + // Fill up the buffer once, to be used for each row + for (i=0; ix_i = (long)x_f; + rptr->p = x_f - (float) rptr->x_i; + rptr->p1 = 1.0 - rptr->p; + rptr++; + } + + // Perform the scaling by inverse mapping from dest to source + // That is, for each point in the destination, find the + // corresponding point in the source. + for (i=0; *running && ix_i; + p = rptr->p; + p1 = rptr->p1; + + // Get the four corner pixels + a = *(spix1 + src_x_i); + b = *(spix1 + src_x_i + 1); + c = *(spix2 + src_x_i); + d = *(spix2 + src_x_i + 1); + + // Compute the interpolated pixel value + result = (((float)8*p1 + (float)b*p)*q1 + + ((float)c*p1 + (float)d*p)*q); + + *dpix++ = (unsigned char) result; + } + + // Advance to the next destination line + dpix = (dpixptr += dlb); + } + + free(r); +} + +static void +scale_bilinear_32(const BBitmap *src, BBitmap *dest, + const float xFactor, const float yFactor, + volatile bool *running) +{ + register long drows, dcols, srows, scols; + register unsigned long *spixptr, *spix1, *spix2; + register unsigned char *dpixptr, *dpix; + register unsigned long slb, dlb; + register long i, j; + float p, q, p1, q1; + float xfac = xFactor, yfac = yFactor; + float xfac_inv, yfac_inv; + float src_y_f; + long src_y_i, src_x_i; + register unsigned char *a, *b, *c, *d; + row_values *r, *rptr; + float x_f; + float rred, rgreen, rblue; + + srows = src->Bounds().IntegerHeight()+1; + scols = src->Bounds().IntegerWidth()+1; + drows = dest->Bounds().IntegerHeight()+1; + dcols = dest->Bounds().IntegerWidth()+1; + + if (xFactor < 0.0) + xfac = (float) dcols / (float) scols; + else + dcols = (long) ceil(scols * xfac); + + if (yFactor < 0.0) + yfac = (float) drows / (float) srows; + else + drows = (long) ceil(srows * yfac); + + + + // Get values from image + dpixptr = (unsigned char *)dest->Bits(); + dpix = (unsigned char *)dpixptr; + spixptr = (unsigned long *)src->Bits(); + slb = src->BytesPerRow()/4; + dlb = dest->BytesPerRow(); + + + xfac_inv = 1.0 / xfac; + yfac_inv = 1.0 / yfac; + + + // Allocate buffer for storing the values of ma and m1 + rptr = r = (row_values *)malloc (sizeof(row_values) * dcols); + + // Fill up the buffer once, to be used for each row + for (i=0; ix_i = (long)x_f; + rptr->p = x_f - (float) rptr->x_i; + rptr->p1 = 1.0 - rptr->p; + rptr++; + } + + // Perform the scaling by inverse mapping from dest to source + // That is, for each point in the destination, find the + // corresponding point in the source. + for (i=0; *running && ix_i; + p = rptr->p; + p1 = rptr->p1; + + // Get the four corner pixels + a = (unsigned char *)(spix1 + src_x_i); + b = (unsigned char *)(spix1 + src_x_i + 1); + c = (unsigned char *)(spix2 + src_x_i); + d = (unsigned char *)(spix2 + src_x_i + 1); + + // Compute the interpolated pixel value + rblue = (((float)a[0]*p1 + (float)b[0]*p)*q1 + + ((float)c[0]*p1 + (float)d[0]*p)*q); + rgreen = (((float)a[1]*p1 + (float)b[1]*p)*q1 + + ((float)c[1]*p1 + (float)d[1]*p)*q); + rred = (((float)a[2]*p1 + (float)b[2]*p)*q1 + + ((float)c[2]*p1 + (float)d[2]*p)*q); + + dpix[0] = (unsigned char) rblue; + dpix[1] = (unsigned char) rgreen; + dpix[2] = (unsigned char) rred; + dpix += 4; + } + + // Advance to the next destination line + dpix = (dpixptr += dlb); + } + + free(r); +} + +status_t scale(const BBitmap *src, BBitmap *dst, + volatile bool* running, + const float xFactor, const float yFactor, + scale_method scmethod) +{ + if (src->ColorSpace() != dst->ColorSpace()) + return -1; + + + switch (scmethod) + { + case IMG_SCALE_BILINEAR: + { + switch (src->ColorSpace()) + { + case B_COLOR_8_BIT: + case B_GRAYSCALE_8_BIT: + scale_bilinear_8(src, dst, xFactor, yFactor, running); + break; + + case B_RGB32: + case B_RGBA32: + scale_bilinear_32(src, dst, xFactor, yFactor, running); + break; + + default: // color space we can't deal with + return -1; + break; + } + } + } + + return B_NO_ERROR; +} diff --git a/src/apps/showimage/Scale.h b/src/apps/showimage/Scale.h new file mode 100644 index 0000000000..cb3f84d873 --- /dev/null +++ b/src/apps/showimage/Scale.h @@ -0,0 +1,22 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#include + +enum scale_method { + IMG_SCALE_BILINEAR = 1 +}; + +class BBitmap; + +// Scale an image. It will work in either direction. +// Scaling up or down. Scaling by integer values will be +// most optimal. + +status_t scale(const BBitmap *source, BBitmap *dst, + volatile bool *running, + const float xFactor = -1, const float yFactor = -1, + scale_method = IMG_SCALE_BILINEAR); + diff --git a/src/apps/showimage/ShowImageConstants.h b/src/apps/showimage/ShowImageConstants.h index 6e757d6860..1adacdedb3 100644 --- a/src/apps/showimage/ShowImageConstants.h +++ b/src/apps/showimage/ShowImageConstants.h @@ -67,6 +67,8 @@ const uint32 MSG_PRINT = 'mPRT'; const uint32 MSG_ZOOM_IN = 'mZIN'; const uint32 MSG_ZOOM_OUT = 'mZOU'; const uint32 MSG_ORIGINAL_SIZE = 'mOSZ'; +const uint32 MSG_INVALIDATE = 'mIVD'; +const uint32 MSG_SCALE_BILINEAR = 'mSBL'; extern const char *APP_SIG; diff --git a/src/apps/showimage/ShowImageView.cpp b/src/apps/showimage/ShowImageView.cpp index 9ff5c7d08e..5d9a5ffd15 100644 --- a/src/apps/showimage/ShowImageView.cpp +++ b/src/apps/showimage/ShowImageView.cpp @@ -167,6 +167,8 @@ ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode, fShowCaption = false; fZoom = 1.0; fMovesImage = false; + fScaleBilinear = false; + fScaler = NULL; SetViewColor(B_TRANSPARENT_COLOR); SetHighColor(kborderColor); @@ -176,8 +178,7 @@ ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode, ShowImageView::~ShowImageView() { - delete fpBitmap; - fpBitmap = NULL; + DeleteBitmap(); } bool @@ -225,10 +226,20 @@ ShowImageView::AddToRecentDocuments() } void -ShowImageView::SetImage(const entry_ref *pref) +ShowImageView::DeleteBitmap() { + if (fScaler) { + delete fScaler; + fScaler = NULL; + } delete fpBitmap; fpBitmap = NULL; +} + +void +ShowImageView::SetImage(const entry_ref *pref) +{ + DeleteBitmap(); fbHasSelection = false; fMakesSelection = false; @@ -355,6 +366,14 @@ ShowImageView::FlushToLeftTop() ScrollTo(p); } +void +ShowImageView::SetScaleBilinear(bool s) +{ + if (fScaleBilinear != s) { + fScaleBilinear = s; Invalidate(); + } +} + void ShowImageView::AttachedToWindow() { @@ -362,7 +381,7 @@ ShowImageView::AttachedToWindow() } BRect -ShowImageView::AlignBitmap() const +ShowImageView::AlignBitmap() { BRect rect(fpBitmap->Bounds()); float width, height; @@ -374,20 +393,22 @@ ShowImageView::AlignBitmap() const s = width / rect.Width(); if (s * rect.Height() <= height) { + fZoom = s; rect.right = width; rect.bottom = s * rect.Height(); // center vertically rect.OffsetBy(0, (height - rect.Height()) / 2); } else { - rect.right = height / rect.Height() * rect.Width(); + fZoom = height / rect.Height(); + rect.right = fZoom * rect.Width(); rect.bottom = height; // center horizontally rect.OffsetBy((width - rect.Width()) / 2, 0); } } else { // zoom image - rect.right = (rect.right+1)*fZoom-1; - rect.bottom = (rect.bottom+1)*fZoom-1; + rect.right = ((int)(rect.right+1)*fZoom)-1; + rect.bottom = ((int)(rect.bottom+1)*fZoom)-1; // align switch (fHAlignment) { case B_ALIGN_CENTER: @@ -423,11 +444,8 @@ ShowImageView::Setup(BRect rect) { fLeft = rect.left; fTop = rect.top; - fScaleX = rect.Width() / fpBitmap->Bounds().Width(); - fScaleY = rect.Height() / fpBitmap->Bounds().Height(); -// XXX Is Width/Height off by one? -// fScaleX = (rect.Width()+1) / (fpBitmap->Bounds().Width()+1); -// fScaleY = (rect.Width()+1) / (fpBitmap->Bounds().Height()+1); + fScaleX = (rect.Width()+1.0) / (fpBitmap->Bounds().Width()+1.0); + fScaleY = (rect.Height()+1.0) / (fpBitmap->Bounds().Height()+1.0); } BPoint @@ -511,6 +529,32 @@ ShowImageView::DrawCaption() PopState(); } +Scaler* +ShowImageView::GetScaler() +{ + if (fScaler == NULL || fScaler->Scale() != fZoom) { + delete fScaler; + BMessenger msgr(this, Window()); + fScaler = new Scaler(fpBitmap, fZoom, msgr, MSG_INVALIDATE); + fScaler->Start(); + } + return fScaler; +} + +void +ShowImageView::DrawImage(BRect rect) +{ + if (fScaleBilinear) { + Scaler* scaler = GetScaler(); + if (scaler != NULL && scaler->GetBitmap() != NULL && !scaler->IsRunning()) { + BBitmap* bitmap = scaler->GetBitmap(); + DrawBitmap(bitmap, BPoint(rect.left, rect.top)); + return; + } + } + DrawBitmap(fpBitmap, fpBitmap->Bounds(), rect); +} + void ShowImageView::Draw(BRect updateRect) { @@ -527,8 +571,8 @@ ShowImageView::Draw(BRect updateRect) // Draw black rectangle around image StrokeRect(border); - // Draw image - DrawBitmap(fpBitmap, fpBitmap->Bounds(), rect); + // Draw image + DrawImage(rect); if (fShowCaption && !fMovesImage) { // to avoid flickering, disabled during moving with mouse @@ -1020,6 +1064,9 @@ ShowImageView::MessageReceived(BMessage *pmsg) case B_MOUSE_WHEEL_CHANGED: MouseWheelChanged(pmsg); break; + case MSG_INVALIDATE: + Invalidate(); + break; default: BView::MessageReceived(pmsg); break; @@ -1284,6 +1331,9 @@ ShowImageView::FirstFile() void ShowImageView::SetZoom(float zoom) { + if (fScaleBilinear && fZoom != zoom) { + delete fScaler; fScaler = NULL; + } fZoom = zoom; FixupScrollBars(); Invalidate(); @@ -1453,7 +1503,8 @@ ShowImageView::DoImageOperation(image_operation op) } // set new bitmap - delete fpBitmap; fpBitmap = bm; + DeleteBitmap(); + fpBitmap = bm; // remove selection fbHasSelection = false; Notify(NULL); diff --git a/src/apps/showimage/ShowImageView.h b/src/apps/showimage/ShowImageView.h index d675c277e0..b9054ad841 100644 --- a/src/apps/showimage/ShowImageView.h +++ b/src/apps/showimage/ShowImageView.h @@ -35,6 +35,8 @@ #include #include +#include "Filter.h" + class ShowImageView : public BView { public: ShowImageView(BRect rect, const char *name, uint32 resizingMode, @@ -52,6 +54,8 @@ public: void GetName(BString *name); void GetPath(BString *name); void FlushToLeftTop(); + void SetScaleBilinear(bool b); + bool GetScaleBilinear() { return fScaleBilinear; } virtual void AttachedToWindow(); virtual void Draw(BRect updateRect); @@ -106,11 +110,12 @@ private: void AnimateSelection(bool a); void Notify(const char* status); void AddToRecentDocuments(); + void DeleteBitmap(); int32 BytesPerPixel(color_space cs) const; inline void CopyPixel(uchar* dest, int32 destX, int32 destY, int32 destBPR, uchar* src, int32 x, int32 y, int32 bpr, int32 bpp); inline void InvertPixel(int32 x, int32 y, uchar* dest, int32 destBPR, uchar* src, int32 bpr, int32 bpp); void DoImageOperation(image_operation op); - BRect AlignBitmap() const; + BRect AlignBitmap(); void Setup(BRect r); BPoint ImageToView(BPoint p) const; BPoint ViewToImage(BPoint p) const; @@ -135,6 +140,8 @@ private: void DrawBorder(BRect border); void DrawCaption(); void DrawSelectionBox(BRect &rect); + Scaler* GetScaler(); + void DrawImage(BRect rect); float LimitToRange(float v, orientation o, bool absolute); void ScrollRestricted(float x, float y, bool absolute); void ScrollRestrictedTo(float x, float y); @@ -147,6 +154,8 @@ private: int32 fDocumentCount; BBitmap *fpBitmap; float fZoom; + bool fScaleBilinear; + Scaler* fScaler; bool fResizeToViewBounds; alignment fHAlignment; vertical_alignment fVAlignment; diff --git a/src/apps/showimage/ShowImageWindow.cpp b/src/apps/showimage/ShowImageWindow.cpp index bbcfd220fd..959e5f68e2 100644 --- a/src/apps/showimage/ShowImageWindow.cpp +++ b/src/apps/showimage/ShowImageWindow.cpp @@ -166,12 +166,13 @@ ShowImageWindow::UpdateRecentDocumentsMenu() be_roster->GetRecentDocuments(&list, 20, NULL, APP_SIG); for (int i = 0; list.FindRef("refs", i, &ref) == B_OK; i++) { BEntry entry(&ref); - entry.GetName(name); - msg = new BMessage(B_REFS_RECEIVED); - msg->AddRef("refs", &ref); - item = new BMenuItem(name, msg, 0, 0); - fpOpenMenu->AddItem(item); - item->SetTarget(be_app, NULL); + if (entry.GetName(name) == B_OK) { + msg = new BMessage(B_REFS_RECEIVED); + msg->AddRef("refs", &ref); + item = new BMenuItem(name, msg, 0, 0); + fpOpenMenu->AddItem(item); + item->SetTarget(be_app, NULL); + } } } @@ -209,13 +210,16 @@ ShowImageWindow::BuildViewMenu(BMenu *pmenu) AddItemMenu(pmenu, "Original Size", MSG_ORIGINAL_SIZE, 0, 0, 'W', true); AddItemMenu(pmenu, "Zoom In", MSG_ZOOM_IN, '+', 0, 'W', true); AddItemMenu(pmenu, "Zoom Out", MSG_ZOOM_OUT, '-', 0, 'W', true); + AddItemMenu(pmenu, "Scale Bilinear", MSG_SCALE_BILINEAR, 0, 0, 'W', true); pmenu->AddSeparatorItem(); AddItemMenu(pmenu, "Fit To Window Size", MSG_FIT_TO_WINDOW_SIZE, 0, 0, 'W', true); AddItemMenu(pmenu, "Full Screen", MSG_FULL_SCREEN, B_ENTER, 0, 'W', true); + MarkMenuItem(pmenu, MSG_FULL_SCREEN, fFullScreen); AddItemMenu(pmenu, "Show Caption in Full Screen Mode", MSG_SHOW_CAPTION, 0, 0, 'W', true); MarkMenuItem(pmenu, MSG_SHOW_CAPTION, fShowCaption); if (fpImageView) { + MarkMenuItem(pmenu, MSG_SCALE_BILINEAR, fpImageView->GetScaleBilinear()); bool resize = fpImageView->GetResizeToViewBounds(); MarkMenuItem(pmenu, MSG_FIT_TO_WINDOW_SIZE, resize); EnableMenuItem(pmenu, MSG_ORIGINAL_SIZE, !resize); @@ -640,6 +644,9 @@ ShowImageWindow::MessageReceived(BMessage *pmsg) case MSG_ORIGINAL_SIZE: fpImageView->SetZoom(1.0); break; + case MSG_SCALE_BILINEAR: + fpImageView->SetScaleBilinear(ToggleMenuItem(pmsg->what)); + break; default: BWindow::MessageReceived(pmsg); diff --git a/src/apps/showimage/ShowImageX.proj b/src/apps/showimage/ShowImageX.proj index 7ec5b85f44..59e978f2c7 100644 Binary files a/src/apps/showimage/ShowImageX.proj and b/src/apps/showimage/ShowImageX.proj differ