- Rewrote bilinear scaling algorithm. The version that uses fixed point calculations is at least two times faster than the version that uses floating point calculations!
- Fixed off by one bugs. - Replace "Fit to Window" with "Shrink to Window" and "Zoom to Window". git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5409 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
+374
-31
@@ -28,21 +28,62 @@
|
|||||||
|
|
||||||
#include <scheduler.h>
|
#include <scheduler.h>
|
||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
#include "Scale.h"
|
|
||||||
|
|
||||||
|
// Implementation of FilterThread
|
||||||
|
FilterThread::FilterThread(Filter* filter, int i)
|
||||||
|
: fWorkerThread(-1)
|
||||||
|
, fFilter(filter)
|
||||||
|
, fI(i)
|
||||||
|
{
|
||||||
|
fWorkerThread = spawn_thread(worker_thread, "filter", suggest_thread_priority(B_STATUS_RENDERING), this);
|
||||||
|
if (fWorkerThread >= 0) {
|
||||||
|
resume_thread(fWorkerThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterThread::~FilterThread()
|
||||||
|
{
|
||||||
|
fFilter->Done();
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
FilterThread::worker_thread(void* data)
|
||||||
|
{
|
||||||
|
FilterThread* thread = (FilterThread*)data;
|
||||||
|
return thread->Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
FilterThread::Run()
|
||||||
|
{
|
||||||
|
fFilter->Run(fI, fFilter->CPUCount());
|
||||||
|
delete this;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implementation of Filter
|
||||||
Filter::Filter(BBitmap* image, BMessenger listener, uint32 what)
|
Filter::Filter(BBitmap* image, BMessenger listener, uint32 what)
|
||||||
: fListener(listener)
|
: fListener(listener)
|
||||||
, fWhat(what)
|
, fWhat(what)
|
||||||
|
, fStarted(false)
|
||||||
|
, fNumberOfThreads(0)
|
||||||
, fIsRunning(false)
|
, fIsRunning(false)
|
||||||
, fWorkerThread(-1)
|
|
||||||
, fSrcImage(image)
|
, fSrcImage(image)
|
||||||
, fDestImage(NULL)
|
, fDestImage(NULL)
|
||||||
{
|
{
|
||||||
|
system_info info;
|
||||||
|
get_system_info(&info);
|
||||||
|
fCPUCount = info.cpu_count;
|
||||||
|
fWaitForThreads = create_sem(0, "wait_for_threads");
|
||||||
|
#if TIME_FILTER
|
||||||
|
fStopWatch = NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Filter::~Filter()
|
Filter::~Filter()
|
||||||
{
|
{
|
||||||
delete fDestImage;
|
delete fDestImage;
|
||||||
|
delete_sem(fWaitForThreads);
|
||||||
}
|
}
|
||||||
|
|
||||||
BBitmap*
|
BBitmap*
|
||||||
@@ -54,40 +95,54 @@ Filter::GetBitmap()
|
|||||||
return fDestImage;
|
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
|
void
|
||||||
Filter::Start()
|
Filter::Start()
|
||||||
{
|
{
|
||||||
GetBitmap();
|
GetBitmap();
|
||||||
if (fSrcImage == NULL || fDestImage == NULL) return;
|
if (fStarted || fSrcImage == NULL || fDestImage == NULL) return;
|
||||||
fWorkerThread = spawn_thread(worker_thread, "filter", suggest_thread_priority(B_STATUS_RENDERING), this);
|
|
||||||
if (fWorkerThread >= 0) {
|
#if TIME_FILTER
|
||||||
fIsRunning = true;
|
fStopWatch = new BStopWatch("Filter Time");
|
||||||
resume_thread(fWorkerThread);
|
#endif
|
||||||
}
|
|
||||||
|
fNumberOfThreads = fCPUCount;
|
||||||
|
fIsRunning = true;
|
||||||
|
fStarted = true;
|
||||||
|
|
||||||
|
// start filter threads
|
||||||
|
for (int i = 0; i < fCPUCount; i ++) {
|
||||||
|
new FilterThread(this, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Filter::Stop()
|
Filter::Stop()
|
||||||
{
|
{
|
||||||
if (fIsRunning) {
|
if (fStarted) {
|
||||||
|
// tell FilterThreads to stop calculations
|
||||||
fIsRunning = false;
|
fIsRunning = false;
|
||||||
status_t st;
|
// wait for threads to exit
|
||||||
wait_for_thread(fWorkerThread, &st);
|
acquire_sem_etc(fWaitForThreads, fCPUCount, 0, 0);
|
||||||
|
// ready to start again
|
||||||
|
fStarted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Filter::Done()
|
||||||
|
{
|
||||||
|
if (atomic_add(&fNumberOfThreads, -1) == 1) {
|
||||||
|
#if TIME_FILTER
|
||||||
|
delete fStopWatch; fStopWatch = NULL;
|
||||||
|
#endif
|
||||||
|
if (fIsRunning) {
|
||||||
|
fListener.SendMessage(fWhat);
|
||||||
|
}
|
||||||
|
fIsRunning = false;
|
||||||
|
}
|
||||||
|
release_sem(fWaitForThreads);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Filter::IsRunning() const
|
Filter::IsRunning() const
|
||||||
{
|
{
|
||||||
@@ -106,9 +161,10 @@ Filter::GetDestImage()
|
|||||||
return fDestImage;
|
return fDestImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaler::Scaler(BBitmap* image, float scale, BMessenger listener, uint32 what)
|
// Implementation of (bilinear) Scaler
|
||||||
|
Scaler::Scaler(BBitmap* image, BRect rect, BMessenger listener, uint32 what)
|
||||||
: Filter(image, listener, what)
|
: Filter(image, listener, what)
|
||||||
, fScale(scale)
|
, fRect(rect)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,14 +176,301 @@ BBitmap*
|
|||||||
Scaler::CreateDestImage(BBitmap* srcImage)
|
Scaler::CreateDestImage(BBitmap* srcImage)
|
||||||
{
|
{
|
||||||
if (srcImage == NULL || srcImage->ColorSpace() != B_RGB32 && srcImage->ColorSpace() !=B_RGBA32) return NULL;
|
if (srcImage == NULL || srcImage->ColorSpace() != B_RGB32 && srcImage->ColorSpace() !=B_RGBA32) return NULL;
|
||||||
BRect src(srcImage->Bounds());
|
BRect dest(0, 0, fRect.IntegerWidth(), fRect.IntegerHeight());
|
||||||
BRect dest(0, 0, (src.Width()+1)*fScale - 1, (src.Height()+1)*fScale - 1);
|
|
||||||
BBitmap* destImage = new BBitmap(dest, srcImage->ColorSpace());
|
BBitmap* destImage = new BBitmap(dest, srcImage->ColorSpace());
|
||||||
return destImage;
|
return destImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
Scaler::Run()
|
Scaler::Matches(BRect rect) const {
|
||||||
{
|
return fRect.IntegerWidth() == rect.IntegerWidth() &&
|
||||||
scale(GetSrcImage(), GetDestImage(), IsRunningAddr(), fScale, fScale);
|
fRect.IntegerHeight() == rect.IntegerHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Scale bilinear using floating point calculations
|
||||||
|
typedef int32 intType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
intType srcColumn;
|
||||||
|
float alpha0;
|
||||||
|
float alpha1;
|
||||||
|
} ColumnData;
|
||||||
|
|
||||||
|
void
|
||||||
|
Scaler::ScaleBilinear(intType fromRow, int32 toRow)
|
||||||
|
{
|
||||||
|
BBitmap* src;
|
||||||
|
BBitmap* dest;
|
||||||
|
intType srcW, srcH;
|
||||||
|
intType destW, destH;
|
||||||
|
intType x, y, i;
|
||||||
|
ColumnData* columnData;
|
||||||
|
ColumnData* cd;
|
||||||
|
const uchar* srcBits;
|
||||||
|
uchar* destBits;
|
||||||
|
intType srcBPR, destBPR;
|
||||||
|
const uchar* srcData;
|
||||||
|
uchar* destDataRow;
|
||||||
|
uchar* destData;
|
||||||
|
const int32 kBPP = 4;
|
||||||
|
|
||||||
|
src = GetSrcImage();
|
||||||
|
dest = GetDestImage();
|
||||||
|
|
||||||
|
srcW = src->Bounds().IntegerWidth();
|
||||||
|
srcH = src->Bounds().IntegerHeight();
|
||||||
|
destW = dest->Bounds().IntegerWidth();
|
||||||
|
destH = dest->Bounds().IntegerHeight();
|
||||||
|
|
||||||
|
srcBits = (uchar*)src->Bits();
|
||||||
|
destBits = (uchar*)dest->Bits();
|
||||||
|
srcBPR = src->BytesPerRow();
|
||||||
|
destBPR = dest->BytesPerRow();
|
||||||
|
|
||||||
|
columnData = new ColumnData[destW];
|
||||||
|
cd = columnData;
|
||||||
|
for (i = 0; i < destW; i ++, cd++) {
|
||||||
|
float column = (float)i * (float)srcW / (float)destW;
|
||||||
|
cd->srcColumn = (intType)column;
|
||||||
|
cd->alpha1 = column - cd->srcColumn;
|
||||||
|
cd->alpha0 = 1.0 - cd->alpha1;
|
||||||
|
}
|
||||||
|
|
||||||
|
destDataRow = destBits + fromRow * destBPR;
|
||||||
|
|
||||||
|
for (y = fromRow; IsRunning() && y <= toRow; y ++, destDataRow += destBPR) {
|
||||||
|
float row;
|
||||||
|
intType srcRow;
|
||||||
|
float alpha0, alpha1;
|
||||||
|
|
||||||
|
row = (float)y * (float)srcH / (float)destH;
|
||||||
|
srcRow = (intType)row;
|
||||||
|
alpha1 = row - srcRow;
|
||||||
|
alpha0 = 1.0 - alpha1;
|
||||||
|
|
||||||
|
srcData = srcBits + srcRow * srcBPR;
|
||||||
|
destData = destDataRow;
|
||||||
|
|
||||||
|
if (y < destH) {
|
||||||
|
float a0, a1;
|
||||||
|
const uchar *a, *b, *c, *d;
|
||||||
|
|
||||||
|
for (x = 0; x < destW; x ++, destData += kBPP) {
|
||||||
|
a = srcData + columnData[x].srcColumn * kBPP;
|
||||||
|
b = a + kBPP;
|
||||||
|
c = a + srcBPR;
|
||||||
|
d = c + kBPP;
|
||||||
|
|
||||||
|
a0 = columnData[x].alpha0;
|
||||||
|
a1 = columnData[x].alpha1;
|
||||||
|
|
||||||
|
destData[0] = static_cast<uchar>(
|
||||||
|
(a[0] * a0 + b[0] * a1) * alpha0 +
|
||||||
|
(c[0] * a0 + d[0] * a1) * alpha1);
|
||||||
|
destData[1] = static_cast<uchar>(
|
||||||
|
(a[1] * a0 + b[1] * a1) * alpha0 +
|
||||||
|
(c[1] * a0 + d[1] * a1) * alpha1);
|
||||||
|
destData[2] = static_cast<uchar>(
|
||||||
|
(a[2] * a0 + b[2] * a1) * alpha0 +
|
||||||
|
(c[2] * a0 + d[2] * a1) * alpha1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// right column
|
||||||
|
a = srcData + srcW * kBPP;
|
||||||
|
c = a + srcBPR;
|
||||||
|
|
||||||
|
destData[0] = static_cast<uchar>(a[0] * alpha0 + c[0] * alpha1);
|
||||||
|
destData[1] = static_cast<uchar>(a[1] * alpha0 + c[1] * alpha1);
|
||||||
|
destData[2] = static_cast<uchar>(a[2] * alpha0 + c[2] * alpha1);
|
||||||
|
} else {
|
||||||
|
float a0, a1;
|
||||||
|
const uchar *a, *b;
|
||||||
|
for (x = 0; x < destW; x ++, destData += kBPP) {
|
||||||
|
a = srcData + columnData[x].srcColumn * kBPP;
|
||||||
|
b = a + kBPP;
|
||||||
|
|
||||||
|
a0 = columnData[x].alpha0;
|
||||||
|
a1 = columnData[x].alpha1;
|
||||||
|
|
||||||
|
destData[0] = static_cast<uchar>(a[0] * a0 + b[0] * a1);
|
||||||
|
destData[1] = static_cast<uchar>(a[1] * a0 + b[1] * a1);
|
||||||
|
destData[2] = static_cast<uchar>(a[2] * a0 + b[2] * a1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom, right pixel
|
||||||
|
a = srcData + srcW * kBPP;
|
||||||
|
|
||||||
|
destData[0] = a[0];
|
||||||
|
destData[1] = a[1];
|
||||||
|
destData[2] = a[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] columnData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scale bilinear using fixed point calculations
|
||||||
|
// Is already more than two times faster than floating point version
|
||||||
|
// on AMD Athlon 1 GHz and Intel Pentium III 866 MHz.
|
||||||
|
typedef int64 long_fixed_point;
|
||||||
|
typedef int32 fixed_point;
|
||||||
|
|
||||||
|
// Could use shift operator instead of multiplication and division,
|
||||||
|
// but compiler will optimize it for use anyway.
|
||||||
|
#define to_fixed_point(number) static_cast<fixed_point>((number) * kFPPrecisionFactor)
|
||||||
|
#define from_fixed_point(number) ((number) / kFPPrecisionFactor)
|
||||||
|
#define to_float(number) from_fixed_point(static_cast<float>(number))
|
||||||
|
|
||||||
|
#define int_value(number) ((number) & kFPInverseMask)
|
||||||
|
#define tail_value(number) ((number) & kFPPrecisionMask)
|
||||||
|
|
||||||
|
// Has to be called after muliplication of two fixed point values
|
||||||
|
#define mult_correction(number) ((number) / kFPPrecisionFactor)
|
||||||
|
|
||||||
|
const int32 kFPPrecision = 8; // (32-kFPPrecision).kFPPrecision
|
||||||
|
const int32 kFPPrecisionFactor = (1 << kFPPrecision);
|
||||||
|
const int32 kFPPrecisionMask = ((kFPPrecisionFactor)-1);
|
||||||
|
const int32 kFPInverseMask = (~kFPPrecisionMask);
|
||||||
|
const int32 kFPOne = to_fixed_point(1);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32 srcColumn;
|
||||||
|
fixed_point alpha0;
|
||||||
|
fixed_point alpha1;
|
||||||
|
} ColumnDataFP;
|
||||||
|
|
||||||
|
void
|
||||||
|
Scaler::ScaleBilinearFP(intType fromRow, int32 toRow)
|
||||||
|
{
|
||||||
|
BBitmap* src;
|
||||||
|
BBitmap* dest;
|
||||||
|
intType srcW, srcH;
|
||||||
|
intType destW, destH;
|
||||||
|
intType x, y, i;
|
||||||
|
ColumnDataFP* columnData;
|
||||||
|
ColumnDataFP* cd;
|
||||||
|
const uchar* srcBits;
|
||||||
|
uchar* destBits;
|
||||||
|
intType srcBPR, destBPR;
|
||||||
|
const uchar* srcData;
|
||||||
|
uchar* destDataRow;
|
||||||
|
uchar* destData;
|
||||||
|
const int32 kBPP = 4;
|
||||||
|
|
||||||
|
src = GetSrcImage();
|
||||||
|
dest = GetDestImage();
|
||||||
|
|
||||||
|
srcW = src->Bounds().IntegerWidth();
|
||||||
|
srcH = src->Bounds().IntegerHeight();
|
||||||
|
destW = dest->Bounds().IntegerWidth();
|
||||||
|
destH = dest->Bounds().IntegerHeight();
|
||||||
|
|
||||||
|
srcBits = (uchar*)src->Bits();
|
||||||
|
destBits = (uchar*)dest->Bits();
|
||||||
|
srcBPR = src->BytesPerRow();
|
||||||
|
destBPR = dest->BytesPerRow();
|
||||||
|
|
||||||
|
fixed_point fpSrcW = to_fixed_point(srcW);
|
||||||
|
fixed_point fpDestW = to_fixed_point(destW);
|
||||||
|
fixed_point fpSrcH = to_fixed_point(srcH);
|
||||||
|
fixed_point fpDestH = to_fixed_point(destH);
|
||||||
|
|
||||||
|
columnData = new ColumnDataFP[destW];
|
||||||
|
cd = columnData;
|
||||||
|
for (i = 0; i < destW; i ++, cd++) {
|
||||||
|
fixed_point column = to_fixed_point(i) * (long_fixed_point)fpSrcW / fpDestW;
|
||||||
|
cd->srcColumn = from_fixed_point(column);
|
||||||
|
cd->alpha1 = tail_value(column); // weigth for left pixel value
|
||||||
|
cd->alpha0 = kFPOne - cd->alpha1; // weigth for right pixel value
|
||||||
|
}
|
||||||
|
|
||||||
|
destDataRow = destBits + fromRow * destBPR;
|
||||||
|
|
||||||
|
for (y = fromRow; IsRunning() && y <= toRow; y ++, destDataRow += destBPR) {
|
||||||
|
fixed_point row;
|
||||||
|
intType srcRow;
|
||||||
|
fixed_point alpha0, alpha1;
|
||||||
|
|
||||||
|
row = to_fixed_point(y) * (long_fixed_point)fpSrcH / fpDestH;
|
||||||
|
srcRow = from_fixed_point(row);
|
||||||
|
alpha1 = tail_value(row); // weight for row y+1
|
||||||
|
alpha0 = kFPOne - alpha1; // weight for row y
|
||||||
|
|
||||||
|
srcData = srcBits + srcRow * srcBPR;
|
||||||
|
destData = destDataRow;
|
||||||
|
|
||||||
|
// Need mult_correction for "outer" multiplication only
|
||||||
|
#define I4(i) from_fixed_point(mult_correction(\
|
||||||
|
(a[i] * a0 + b[i] * a1) * alpha0 + \
|
||||||
|
(c[i] * a0 + d[i] * a1) * alpha1))
|
||||||
|
#define V2(i) from_fixed_point(a[i] * alpha0 + c[i] * alpha1);
|
||||||
|
#define H2(i) from_fixed_point(a[i] * a0 + b[i] * a1);
|
||||||
|
|
||||||
|
if (y < destH) {
|
||||||
|
fixed_point a0, a1;
|
||||||
|
const uchar *a, *b, *c, *d;
|
||||||
|
|
||||||
|
for (x = 0; x < destW; x ++, destData += kBPP) {
|
||||||
|
a = srcData + columnData[x].srcColumn * kBPP;
|
||||||
|
b = a + kBPP;
|
||||||
|
c = a + srcBPR;
|
||||||
|
d = c + kBPP;
|
||||||
|
|
||||||
|
a0 = columnData[x].alpha0;
|
||||||
|
a1 = columnData[x].alpha1;
|
||||||
|
|
||||||
|
destData[0] = I4(0);
|
||||||
|
destData[1] = I4(1);
|
||||||
|
destData[2] = I4(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// right column
|
||||||
|
a = srcData + srcW * kBPP;
|
||||||
|
c = a + srcBPR;
|
||||||
|
|
||||||
|
destData[0] = V2(0);
|
||||||
|
destData[1] = V2(1);
|
||||||
|
destData[2] = V2(2);
|
||||||
|
} else {
|
||||||
|
fixed_point a0, a1;
|
||||||
|
const uchar *a, *b;
|
||||||
|
for (x = 0; x < destW; x ++, destData += kBPP) {
|
||||||
|
a = srcData + columnData[x].srcColumn * kBPP;
|
||||||
|
b = a + kBPP;
|
||||||
|
|
||||||
|
a0 = columnData[x].alpha0;
|
||||||
|
a1 = columnData[x].alpha1;
|
||||||
|
|
||||||
|
destData[0] = H2(0);
|
||||||
|
destData[1] = H2(1);
|
||||||
|
destData[2] = H2(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom, right pixel
|
||||||
|
a = srcData + srcW * kBPP;
|
||||||
|
|
||||||
|
destData[0] = a[0];
|
||||||
|
destData[1] = a[1];
|
||||||
|
destData[2] = a[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] columnData;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Scaler::Run(int i, int n)
|
||||||
|
{
|
||||||
|
int32 from, to, height;
|
||||||
|
height = (GetDestImage()->Bounds().IntegerHeight()+1)/n;
|
||||||
|
from = i * height;
|
||||||
|
if (i+1 == n) {
|
||||||
|
to = (int32)GetDestImage()->Bounds().bottom;
|
||||||
|
} else {
|
||||||
|
to = from + height - 1;
|
||||||
|
}
|
||||||
|
ScaleBilinearFP(from, to);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,21 +32,66 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
#include <Bitmap.h>
|
#include <Bitmap.h>
|
||||||
#include <Messenger.h>
|
#include <Messenger.h>
|
||||||
|
#include <StopWatch.h>
|
||||||
|
|
||||||
|
#define TIME_FILTER 0
|
||||||
|
|
||||||
|
class Filter;
|
||||||
|
|
||||||
|
// Used by class Filter
|
||||||
|
class FilterThread {
|
||||||
|
public:
|
||||||
|
FilterThread(Filter* filter, int i);
|
||||||
|
~FilterThread();
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t Run();
|
||||||
|
static status_t worker_thread(void* data);
|
||||||
|
thread_id fWorkerThread;
|
||||||
|
Filter* fFilter;
|
||||||
|
int fI;
|
||||||
|
};
|
||||||
|
|
||||||
class Filter {
|
class Filter {
|
||||||
public:
|
public:
|
||||||
|
// The filter uses the input "image" as source image
|
||||||
|
// for an operation executed in Run() method which
|
||||||
|
// writes into the destination image, that can be
|
||||||
|
// retrieve using GetBitmap() method.
|
||||||
|
// GetBitmap() can be called any time, but it
|
||||||
|
// may contain "invalid" pixels.
|
||||||
|
// To start the operation Start() method has to
|
||||||
|
// be called. The operation is executed in as many
|
||||||
|
// threads as CPUs are active.
|
||||||
|
// IsRunning() is true as long as there are any
|
||||||
|
// threads running.
|
||||||
|
// The operation is complete when IsRunning() is false
|
||||||
|
// and Stop() has not been called.
|
||||||
|
// To abort an operation Stop() method has to
|
||||||
|
// be called. Stop() has to be called after Start().
|
||||||
|
// When the operation is done (and has not been aborted).
|
||||||
|
// Then listener receives a message with the specified "what" value.
|
||||||
Filter(BBitmap* image, BMessenger listener, uint32 what);
|
Filter(BBitmap* image, BMessenger listener, uint32 what);
|
||||||
virtual ~Filter();
|
virtual ~Filter();
|
||||||
|
|
||||||
|
// The bitmap the filter writes into
|
||||||
BBitmap* GetBitmap();
|
BBitmap* GetBitmap();
|
||||||
|
|
||||||
|
// Starts one or more FilterThreads
|
||||||
void Start();
|
void Start();
|
||||||
|
// Has to be called after Start() (even if IsRunning() is false)
|
||||||
void Stop();
|
void Stop();
|
||||||
|
// Are there any running FilterThreads?
|
||||||
bool IsRunning() const;
|
bool IsRunning() const;
|
||||||
volatile bool *IsRunningAddr() { return &fIsRunning; }
|
|
||||||
|
|
||||||
|
// To be implemented by inherited class
|
||||||
virtual BBitmap* CreateDestImage(BBitmap* srcImage) = 0;
|
virtual BBitmap* CreateDestImage(BBitmap* srcImage) = 0;
|
||||||
virtual void Run() = 0;
|
// Should calculate part i of n of the image. i starts with zero
|
||||||
|
virtual void Run(int i, int n) = 0;
|
||||||
|
|
||||||
|
// Used by FilterThread only!
|
||||||
|
void Done();
|
||||||
|
int32 CPUCount() const { return fCPUCount; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
BBitmap* GetSrcImage();
|
BBitmap* GetSrcImage();
|
||||||
@@ -55,23 +100,32 @@ protected:
|
|||||||
private:
|
private:
|
||||||
BMessenger fListener;
|
BMessenger fListener;
|
||||||
uint32 fWhat;
|
uint32 fWhat;
|
||||||
static status_t worker_thread(void* data);
|
int32 fCPUCount;
|
||||||
|
bool fStarted;
|
||||||
|
sem_id fWaitForThreads;
|
||||||
|
volatile int32 fNumberOfThreads;
|
||||||
volatile bool fIsRunning;
|
volatile bool fIsRunning;
|
||||||
thread_id fWorkerThread;
|
|
||||||
BBitmap* fSrcImage;
|
BBitmap* fSrcImage;
|
||||||
BBitmap* fDestImage;
|
BBitmap* fDestImage;
|
||||||
|
#if TIME_FILTER
|
||||||
|
BStopWatch* fStopWatch;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
class Scaler : public Filter {
|
class Scaler : public Filter {
|
||||||
public:
|
public:
|
||||||
Scaler(BBitmap* image, float scale, BMessenger listener, uint32 what);
|
Scaler(BBitmap* image, BRect rect, BMessenger listener, uint32 what);
|
||||||
~Scaler();
|
~Scaler();
|
||||||
|
|
||||||
BBitmap* CreateDestImage(BBitmap* srcImage);
|
BBitmap* CreateDestImage(BBitmap* srcImage);
|
||||||
void Run();
|
void Run(int i, int n);
|
||||||
float Scale() const { return fScale; }
|
bool Matches(BRect rect) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float fScale;
|
void ScaleBilinear(int32 fromRow, int32 toRow);
|
||||||
|
void ScaleBilinearFP(int32 fromRow, int32 toRow);
|
||||||
|
|
||||||
|
BRect fRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ const uint32 MSG_PAGE_PREV = 'mPGP';
|
|||||||
const uint32 MSG_GOTO_PAGE = 'mGTP';
|
const uint32 MSG_GOTO_PAGE = 'mGTP';
|
||||||
const uint32 MSG_FILE_NEXT = 'mFLN';
|
const uint32 MSG_FILE_NEXT = 'mFLN';
|
||||||
const uint32 MSG_FILE_PREV = 'mFLP';
|
const uint32 MSG_FILE_PREV = 'mFLP';
|
||||||
const uint32 MSG_FIT_TO_WINDOW_SIZE = 'mFWS';
|
const uint32 MSG_SHRINK_TO_WINDOW = 'mSTW';
|
||||||
|
const uint32 MSG_ZOOM_TO_WINDOW = 'mZTW';
|
||||||
const uint32 MSG_ROTATE_90 = 'mR90';
|
const uint32 MSG_ROTATE_90 = 'mR90';
|
||||||
const uint32 MSG_ROTATE_270 = 'mR27';
|
const uint32 MSG_ROTATE_270 = 'mR27';
|
||||||
const uint32 MSG_MIRROR_VERTICAL = 'mMIV';
|
const uint32 MSG_MIRROR_VERTICAL = 'mMIV';
|
||||||
|
|||||||
@@ -159,7 +159,9 @@ ShowImageView::ShowImageView(BRect rect, const char *name, uint32 resizingMode,
|
|||||||
fDocumentCount = 1;
|
fDocumentCount = 1;
|
||||||
fAnimateSelection = true;
|
fAnimateSelection = true;
|
||||||
fbHasSelection = false;
|
fbHasSelection = false;
|
||||||
fResizeToViewBounds = false;
|
fShrinkToBounds = false;
|
||||||
|
fZoomToBounds = false;
|
||||||
|
fHasBorder = true;
|
||||||
fHAlignment = B_ALIGN_LEFT;
|
fHAlignment = B_ALIGN_LEFT;
|
||||||
fVAlignment = B_ALIGN_TOP;
|
fVAlignment = B_ALIGN_TOP;
|
||||||
fSlideShow = false;
|
fSlideShow = false;
|
||||||
@@ -317,10 +319,30 @@ ShowImageView::SetShowCaption(bool show)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ShowImageView::ResizeToViewBounds(bool resize)
|
ShowImageView::SetShrinkToBounds(bool enable)
|
||||||
{
|
{
|
||||||
if (fResizeToViewBounds != resize) {
|
if (fShrinkToBounds != enable) {
|
||||||
fResizeToViewBounds = resize;
|
fShrinkToBounds = enable;
|
||||||
|
FixupScrollBars();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ShowImageView::SetZoomToBounds(bool enable)
|
||||||
|
{
|
||||||
|
if (fZoomToBounds != enable) {
|
||||||
|
fZoomToBounds = enable;
|
||||||
|
FixupScrollBars();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ShowImageView::SetBorder(bool hasBorder)
|
||||||
|
{
|
||||||
|
if (fHasBorder != hasBorder) {
|
||||||
|
fHasBorder = hasBorder;
|
||||||
FixupScrollBars();
|
FixupScrollBars();
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
@@ -402,29 +424,27 @@ ShowImageView::AlignBitmap()
|
|||||||
width = Bounds().Width()-2*PEN_SIZE+1;
|
width = Bounds().Width()-2*PEN_SIZE+1;
|
||||||
height = Bounds().Height()-2*PEN_SIZE+1;
|
height = Bounds().Height()-2*PEN_SIZE+1;
|
||||||
if (width == 0 || height == 0) return rect;
|
if (width == 0 || height == 0) return rect;
|
||||||
if (fResizeToViewBounds) {
|
if (fShrinkToBounds && (rect.Width() >= Bounds().Width() || rect.Height() >= Bounds().Height()) ||
|
||||||
|
fZoomToBounds && rect.Width() < Bounds().Width() && rect.Height() < Bounds().Height()) {
|
||||||
float s;
|
float s;
|
||||||
s = width / (rect.Width()+1);
|
s = width / (rect.Width()+1.0);
|
||||||
|
|
||||||
if (s * rect.Height() <= height) {
|
if (s * (rect.Height()+1.0) <= height) {
|
||||||
// XXX temporary solution, fZoom should not be changed here
|
|
||||||
fZoom = s;
|
|
||||||
rect.right = width-1;
|
rect.right = width-1;
|
||||||
rect.bottom = static_cast<int>(s * (rect.Height()+1))-1;
|
rect.bottom = static_cast<int>(s * (rect.Height()+1.0))-1;
|
||||||
// center vertically
|
// center vertically
|
||||||
rect.OffsetBy(0, (height - rect.Height()) / 2);
|
rect.OffsetBy(0, (height - rect.Height()) / 2);
|
||||||
} else {
|
} else {
|
||||||
// XXX temporary solution, fZoom should not be changed here
|
s = height / (rect.Height()+1.0);
|
||||||
fZoom = height / (rect.Height()+1);
|
rect.right = static_cast<int>(s * (rect.Width()+1.0))-1;
|
||||||
rect.right = static_cast<int>(fZoom * (rect.Width()+1))-1;
|
|
||||||
rect.bottom = height-1;
|
rect.bottom = height-1;
|
||||||
// center horizontally
|
// center horizontally
|
||||||
rect.OffsetBy((width - rect.Width()) / 2, 0);
|
rect.OffsetBy((width - rect.Width()) / 2, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// zoom image
|
// zoom image
|
||||||
rect.right = static_cast<int>((rect.right+1)*fZoom)-1;
|
rect.right = static_cast<int>((rect.right+1.0)*fZoom)-1;
|
||||||
rect.bottom = static_cast<int>((rect.bottom+1)*fZoom)-1;
|
rect.bottom = static_cast<int>((rect.bottom+1.0)*fZoom)-1;
|
||||||
// align
|
// align
|
||||||
switch (fHAlignment) {
|
switch (fHAlignment) {
|
||||||
case B_ALIGN_CENTER:
|
case B_ALIGN_CENTER:
|
||||||
@@ -435,7 +455,9 @@ ShowImageView::AlignBitmap()
|
|||||||
// fall through
|
// fall through
|
||||||
default:
|
default:
|
||||||
case B_ALIGN_LEFT:
|
case B_ALIGN_LEFT:
|
||||||
rect.OffsetBy(BORDER_WIDTH, 0);
|
if (fHasBorder) {
|
||||||
|
rect.OffsetBy(BORDER_WIDTH, 0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
switch (fVAlignment) {
|
switch (fVAlignment) {
|
||||||
@@ -447,7 +469,9 @@ ShowImageView::AlignBitmap()
|
|||||||
// fall through
|
// fall through
|
||||||
default:
|
default:
|
||||||
case B_ALIGN_TOP:
|
case B_ALIGN_TOP:
|
||||||
rect.OffsetBy(0, BORDER_WIDTH);
|
if (fHasBorder) {
|
||||||
|
rect.OffsetBy(0, BORDER_WIDTH);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -460,8 +484,8 @@ ShowImageView::Setup(BRect rect)
|
|||||||
{
|
{
|
||||||
fLeft = rect.left;
|
fLeft = rect.left;
|
||||||
fTop = rect.top;
|
fTop = rect.top;
|
||||||
fScaleX = (rect.Width()+1.0) / (fBitmap->Bounds().Width()+1.0);
|
fScaleX = rect.Width() / fBitmap->Bounds().Width();
|
||||||
fScaleY = (rect.Height()+1.0) / (fBitmap->Bounds().Height()+1.0);
|
fScaleY = rect.Height() / fBitmap->Bounds().Height();
|
||||||
}
|
}
|
||||||
|
|
||||||
BPoint
|
BPoint
|
||||||
@@ -572,12 +596,12 @@ ShowImageView::EraseCaption()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Scaler*
|
Scaler*
|
||||||
ShowImageView::GetScaler()
|
ShowImageView::GetScaler(BRect rect)
|
||||||
{
|
{
|
||||||
if (fScaler == NULL || fScaler->Scale() != fZoom) {
|
if (fScaler == NULL || !fScaler->Matches(rect)) {
|
||||||
DeleteScaler();
|
DeleteScaler();
|
||||||
BMessenger msgr(this, Window());
|
BMessenger msgr(this, Window());
|
||||||
fScaler = new Scaler(fBitmap, fZoom, msgr, MSG_INVALIDATE);
|
fScaler = new Scaler(fBitmap, rect, msgr, MSG_INVALIDATE);
|
||||||
fScaler->Start();
|
fScaler->Start();
|
||||||
}
|
}
|
||||||
return fScaler;
|
return fScaler;
|
||||||
@@ -587,7 +611,7 @@ void
|
|||||||
ShowImageView::DrawImage(BRect rect)
|
ShowImageView::DrawImage(BRect rect)
|
||||||
{
|
{
|
||||||
if (fScaleBilinear) {
|
if (fScaleBilinear) {
|
||||||
Scaler* scaler = GetScaler();
|
Scaler* scaler = GetScaler(rect);
|
||||||
if (scaler != NULL && scaler->GetBitmap() != NULL && !scaler->IsRunning()) {
|
if (scaler != NULL && scaler->GetBitmap() != NULL && !scaler->IsRunning()) {
|
||||||
BBitmap* bitmap = scaler->GetBitmap();
|
BBitmap* bitmap = scaler->GetBitmap();
|
||||||
DrawBitmap(bitmap, BPoint(rect.left, rect.top));
|
DrawBitmap(bitmap, BPoint(rect.left, rect.top));
|
||||||
@@ -847,10 +871,6 @@ ShowImageView::HandleDrop(BMessage* msg)
|
|||||||
|
|
||||||
sendInMessage = (!saveToFile) && msg->FindString("be:types", &type) == B_OK;
|
sendInMessage = (!saveToFile) && msg->FindString("be:types", &type) == B_OK;
|
||||||
|
|
||||||
fprintf(stderr, "HandleDrop saveToFile %s, sendInMessage %s\n",
|
|
||||||
saveToFile ? "yes" : "no",
|
|
||||||
sendInMessage ? "yes" : "no");
|
|
||||||
|
|
||||||
bitmap = CopySelection();
|
bitmap = CopySelection();
|
||||||
if (bitmap == NULL) return;
|
if (bitmap == NULL) return;
|
||||||
|
|
||||||
@@ -1109,8 +1129,6 @@ ShowImageView::LimitToRange(float v, orientation o, bool absolute)
|
|||||||
void
|
void
|
||||||
ShowImageView::ScrollRestricted(float x, float y, bool absolute)
|
ShowImageView::ScrollRestricted(float x, float y, bool absolute)
|
||||||
{
|
{
|
||||||
if (fResizeToViewBounds) return;
|
|
||||||
|
|
||||||
if (x != 0) {
|
if (x != 0) {
|
||||||
x = LimitToRange(x, B_HORIZONTAL, absolute);
|
x = LimitToRange(x, B_HORIZONTAL, absolute);
|
||||||
}
|
}
|
||||||
@@ -1247,46 +1265,41 @@ ShowImageView::MessageReceived(BMessage *pmsg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ShowImageView::FixupScrollBars()
|
ShowImageView::FixupScrollBar(orientation o, float bitmapLength, float viewLength)
|
||||||
{
|
{
|
||||||
|
float prop, range;
|
||||||
BScrollBar *psb;
|
BScrollBar *psb;
|
||||||
|
|
||||||
if (fResizeToViewBounds) {
|
psb = ScrollBar(o);
|
||||||
psb = ScrollBar(B_HORIZONTAL);
|
if (psb) {
|
||||||
if (psb) psb->SetRange(0, 0);
|
if (fHasBorder) {
|
||||||
psb = ScrollBar(B_VERTICAL);
|
bitmapLength += BORDER_WIDTH*2;
|
||||||
if (psb) psb->SetRange(0, 0);
|
}
|
||||||
return;
|
range = bitmapLength - viewLength;
|
||||||
|
if (range < 0.0) {
|
||||||
|
range = 0.0;
|
||||||
|
}
|
||||||
|
prop = viewLength / bitmapLength;
|
||||||
|
if (prop > 1.0) {
|
||||||
|
prop = 1.0;
|
||||||
|
}
|
||||||
|
psb->SetRange(0, range);
|
||||||
|
psb->SetProportion(prop);
|
||||||
|
psb->SetSteps(10, 100);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ShowImageView::FixupScrollBars()
|
||||||
|
{
|
||||||
BRect rctview = Bounds(), rctbitmap(0, 0, 0, 0);
|
BRect rctview = Bounds(), rctbitmap(0, 0, 0, 0);
|
||||||
if (fBitmap) {
|
if (fBitmap) {
|
||||||
BRect rect(AlignBitmap());
|
BRect rect(AlignBitmap());
|
||||||
rctbitmap.Set(0, 0, rect.Width(), rect.Height());
|
rctbitmap.Set(0, 0, rect.Width(), rect.Height());
|
||||||
}
|
}
|
||||||
|
|
||||||
float prop, range;
|
FixupScrollBar(B_HORIZONTAL, rctbitmap.Width(), rctview.Width());
|
||||||
psb = ScrollBar(B_HORIZONTAL);
|
FixupScrollBar(B_VERTICAL, rctbitmap.Height(), rctview.Height());
|
||||||
if (psb) {
|
|
||||||
range = rctbitmap.Width() + (BORDER_WIDTH * 2) - rctview.Width();
|
|
||||||
if (range < 0) range = 0;
|
|
||||||
prop = rctview.Width() / (rctbitmap.Width() + (BORDER_WIDTH * 2));
|
|
||||||
if (prop > 1.0f) prop = 1.0f;
|
|
||||||
psb->SetRange(0, range);
|
|
||||||
psb->SetProportion(prop);
|
|
||||||
psb->SetSteps(10, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
psb = ScrollBar(B_VERTICAL);
|
|
||||||
if (psb) {
|
|
||||||
range = rctbitmap.Height() + (BORDER_HEIGHT * 2) - rctview.Height();
|
|
||||||
if (range < 0) range = 0;
|
|
||||||
prop = rctview.Height() / (rctbitmap.Height() + (BORDER_HEIGHT * 2));
|
|
||||||
if (prop > 1.0f) prop = 1.0f;
|
|
||||||
psb->SetRange(0, range);
|
|
||||||
psb->SetProportion(prop);
|
|
||||||
psb->SetSteps(10, 100);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32
|
int32
|
||||||
|
|||||||
@@ -47,8 +47,12 @@ public:
|
|||||||
|
|
||||||
void SetImage(const entry_ref *pref);
|
void SetImage(const entry_ref *pref);
|
||||||
void SetShowCaption(bool show);
|
void SetShowCaption(bool show);
|
||||||
void ResizeToViewBounds(bool resize);
|
void SetShrinkToBounds(bool enable);
|
||||||
bool GetResizeToViewBounds() const { return fResizeToViewBounds; }
|
bool GetShrinkToBounds() const { return fShrinkToBounds; }
|
||||||
|
void SetZoomToBounds(bool enable);
|
||||||
|
bool GetZoomToBounds() const { return fZoomToBounds; }
|
||||||
|
void SetBorder(bool hasBorder);
|
||||||
|
bool HasBorder() const { return fHasBorder; }
|
||||||
void SetAlignment(alignment horizontal, vertical_alignment vertical);
|
void SetAlignment(alignment horizontal, vertical_alignment vertical);
|
||||||
BBitmap *GetBitmap();
|
BBitmap *GetBitmap();
|
||||||
void GetName(BString *name);
|
void GetName(BString *name);
|
||||||
@@ -67,6 +71,7 @@ public:
|
|||||||
|
|
||||||
virtual void MessageReceived(BMessage *pmsg);
|
virtual void MessageReceived(BMessage *pmsg);
|
||||||
|
|
||||||
|
void FixupScrollBar(orientation o, float bitmapLength, float viewLength);
|
||||||
void FixupScrollBars();
|
void FixupScrollBars();
|
||||||
|
|
||||||
int32 CurrentPage();
|
int32 CurrentPage();
|
||||||
@@ -148,7 +153,7 @@ private:
|
|||||||
void DrawCaption();
|
void DrawCaption();
|
||||||
void EraseCaption();
|
void EraseCaption();
|
||||||
void DrawSelectionBox(BRect &rect);
|
void DrawSelectionBox(BRect &rect);
|
||||||
Scaler* GetScaler();
|
Scaler* GetScaler(BRect rect);
|
||||||
void DrawImage(BRect rect);
|
void DrawImage(BRect rect);
|
||||||
float LimitToRange(float v, orientation o, bool absolute);
|
float LimitToRange(float v, orientation o, bool absolute);
|
||||||
void ScrollRestricted(float x, float y, bool absolute);
|
void ScrollRestricted(float x, float y, bool absolute);
|
||||||
@@ -157,22 +162,24 @@ private:
|
|||||||
void MouseWheelChanged(BMessage* msg);
|
void MouseWheelChanged(BMessage* msg);
|
||||||
void ShowPopUpMenu(BPoint screen);
|
void ShowPopUpMenu(BPoint screen);
|
||||||
|
|
||||||
entry_ref fCurrentRef;
|
entry_ref fCurrentRef; // of the image
|
||||||
int32 fDocumentIndex;
|
int32 fDocumentIndex; // of the image in the file
|
||||||
int32 fDocumentCount;
|
int32 fDocumentCount; // number of images in the file
|
||||||
BBitmap *fBitmap;
|
BBitmap *fBitmap; // to be displayed
|
||||||
BBitmap *fSelBitmap;
|
BBitmap *fSelBitmap; // the bitmap in the selection
|
||||||
float fZoom;
|
float fZoom; // factor to be used to display the image
|
||||||
bool fScaleBilinear;
|
bool fScaleBilinear; // use bilinear scaling?
|
||||||
Scaler* fScaler;
|
Scaler* fScaler; // holds the scaled image if bilinear scaling is enabled
|
||||||
bool fResizeToViewBounds;
|
bool fShrinkToBounds; // shrink images to view bounds that are larger than the view
|
||||||
alignment fHAlignment;
|
bool fZoomToBounds; // zoom images to view bounds that are smaller than the view
|
||||||
vertical_alignment fVAlignment;
|
bool fHasBorder; // should the image have a border?
|
||||||
|
alignment fHAlignment; // horizontal alignment (left and centered only)
|
||||||
|
vertical_alignment fVAlignment; // vertical alignment (left and centered only)
|
||||||
float fLeft; // the origin of the image in the view
|
float fLeft; // the origin of the image in the view
|
||||||
float fTop;
|
float fTop;
|
||||||
float fScaleX;
|
float fScaleX; // to convert image from/to view coordinates
|
||||||
float fScaleY;
|
float fScaleY;
|
||||||
bool fMovesImage;
|
bool fMovesImage; // is the image being moved with the mouse
|
||||||
bool fMakesSelection; // is a selection being made
|
bool fMakesSelection; // is a selection being made
|
||||||
BPoint fFirstPoint; // first point in image space of selection
|
BPoint fFirstPoint; // first point in image space of selection
|
||||||
bool fAnimateSelection; // marching ants
|
bool fAnimateSelection; // marching ants
|
||||||
@@ -182,12 +189,12 @@ private:
|
|||||||
// the portion of the background bitmap the selection is made from
|
// the portion of the background bitmap the selection is made from
|
||||||
pattern fPatternUp, fPatternDown, fPatternLeft, fPatternRight;
|
pattern fPatternUp, fPatternDown, fPatternLeft, fPatternRight;
|
||||||
|
|
||||||
bool fSlideShow;
|
bool fSlideShow; // is slide show enabled?
|
||||||
int fSlideShowDelay;
|
int fSlideShowDelay; // in pulse rate units
|
||||||
int fSlideShowCountDown;
|
int fSlideShowCountDown; // shows next image if it reaches zero
|
||||||
|
|
||||||
bool fShowCaption;
|
bool fShowCaption; // display caption?
|
||||||
BString fCaption;
|
BString fCaption; // caption text
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _ShowImageView_h */
|
#endif /* _ShowImageView_h */
|
||||||
|
|||||||
@@ -212,19 +212,24 @@ ShowImageWindow::BuildViewMenu(BMenu *pmenu)
|
|||||||
AddItemMenu(pmenu, "Zoom Out", MSG_ZOOM_OUT, '-', 0, 'W', true);
|
AddItemMenu(pmenu, "Zoom Out", MSG_ZOOM_OUT, '-', 0, 'W', true);
|
||||||
AddItemMenu(pmenu, "Scale Bilinear", MSG_SCALE_BILINEAR, 0, 0, 'W', true);
|
AddItemMenu(pmenu, "Scale Bilinear", MSG_SCALE_BILINEAR, 0, 0, 'W', true);
|
||||||
pmenu->AddSeparatorItem();
|
pmenu->AddSeparatorItem();
|
||||||
AddItemMenu(pmenu, "Fit To Window Size", MSG_FIT_TO_WINDOW_SIZE, 0, 0, 'W', true);
|
AddItemMenu(pmenu, "Shrink to Window", MSG_SHRINK_TO_WINDOW, 0, 0, 'W', true);
|
||||||
|
AddItemMenu(pmenu, "Zoom to Window", MSG_ZOOM_TO_WINDOW, 0, 0, 'W', true);
|
||||||
AddItemMenu(pmenu, "Full Screen", MSG_FULL_SCREEN, B_ENTER, 0, 'W', true);
|
AddItemMenu(pmenu, "Full Screen", MSG_FULL_SCREEN, B_ENTER, 0, 'W', true);
|
||||||
MarkMenuItem(pmenu, MSG_FULL_SCREEN, fFullScreen);
|
MarkMenuItem(pmenu, MSG_FULL_SCREEN, fFullScreen);
|
||||||
AddItemMenu(pmenu, "Show Caption in Full Screen Mode", MSG_SHOW_CAPTION, 0, 0, 'W', true);
|
AddItemMenu(pmenu, "Show Caption in Full Screen Mode", MSG_SHOW_CAPTION, 0, 0, 'W', true);
|
||||||
MarkMenuItem(pmenu, MSG_SHOW_CAPTION, fShowCaption);
|
MarkMenuItem(pmenu, MSG_SHOW_CAPTION, fShowCaption);
|
||||||
|
|
||||||
if (fpImageView) {
|
if (fpImageView) {
|
||||||
|
bool shrink, zoom, enabled;
|
||||||
MarkMenuItem(pmenu, MSG_SCALE_BILINEAR, fpImageView->GetScaleBilinear());
|
MarkMenuItem(pmenu, MSG_SCALE_BILINEAR, fpImageView->GetScaleBilinear());
|
||||||
bool resize = fpImageView->GetResizeToViewBounds();
|
shrink = fpImageView->GetShrinkToBounds();
|
||||||
MarkMenuItem(pmenu, MSG_FIT_TO_WINDOW_SIZE, resize);
|
zoom = fpImageView->GetZoomToBounds();
|
||||||
EnableMenuItem(pmenu, MSG_ORIGINAL_SIZE, !resize);
|
MarkMenuItem(pmenu, MSG_SHRINK_TO_WINDOW, shrink);
|
||||||
EnableMenuItem(pmenu, MSG_ZOOM_IN, !resize);
|
MarkMenuItem(pmenu, MSG_ZOOM_TO_WINDOW, zoom);
|
||||||
EnableMenuItem(pmenu, MSG_ZOOM_OUT, !resize);
|
enabled = !(shrink || zoom);
|
||||||
|
EnableMenuItem(pmenu, MSG_ORIGINAL_SIZE, enabled);
|
||||||
|
EnableMenuItem(pmenu, MSG_ZOOM_IN, enabled);
|
||||||
|
EnableMenuItem(pmenu, MSG_ZOOM_OUT, enabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,6 +418,23 @@ ShowImageWindow::MarkSlideShowDelay(float value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ShowImageWindow::ResizeToWindow(bool shrink, uint32 what)
|
||||||
|
{
|
||||||
|
bool enabled;
|
||||||
|
enabled = ToggleMenuItem(what);
|
||||||
|
if (shrink) {
|
||||||
|
fpImageView->SetShrinkToBounds(enabled);
|
||||||
|
} else {
|
||||||
|
fpImageView->SetZoomToBounds(enabled);
|
||||||
|
}
|
||||||
|
enabled = !(fpImageView->GetShrinkToBounds() || fpImageView->GetZoomToBounds());
|
||||||
|
EnableMenuItem(fpBar, MSG_ORIGINAL_SIZE, enabled);
|
||||||
|
EnableMenuItem(fpBar, MSG_ZOOM_IN, enabled);
|
||||||
|
EnableMenuItem(fpBar, MSG_ZOOM_OUT, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ShowImageWindow::MessageReceived(BMessage *pmsg)
|
ShowImageWindow::MessageReceived(BMessage *pmsg)
|
||||||
{
|
{
|
||||||
@@ -571,15 +593,11 @@ ShowImageWindow::MessageReceived(BMessage *pmsg)
|
|||||||
ToggleMenuItem(pmsg->what);
|
ToggleMenuItem(pmsg->what);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_FIT_TO_WINDOW_SIZE:
|
case MSG_SHRINK_TO_WINDOW:
|
||||||
{
|
ResizeToWindow(true, pmsg->what);
|
||||||
bool resize;
|
break;
|
||||||
resize = ToggleMenuItem(pmsg->what);
|
case MSG_ZOOM_TO_WINDOW:
|
||||||
fpImageView->ResizeToViewBounds(resize);
|
ResizeToWindow(false, pmsg->what);
|
||||||
EnableMenuItem(fpBar, MSG_ORIGINAL_SIZE, !resize);
|
|
||||||
EnableMenuItem(fpBar, MSG_ZOOM_IN, !resize);
|
|
||||||
EnableMenuItem(fpBar, MSG_ZOOM_OUT, !resize);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MSG_FILE_PREV:
|
case MSG_FILE_PREV:
|
||||||
@@ -768,6 +786,7 @@ ShowImageWindow::ToggleFullScreen()
|
|||||||
SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_MOVABLE));
|
SetFlags(Flags() & ~(B_NOT_RESIZABLE | B_NOT_MOVABLE));
|
||||||
fpImageView->SetAlignment(B_ALIGN_LEFT, B_ALIGN_TOP);
|
fpImageView->SetAlignment(B_ALIGN_LEFT, B_ALIGN_TOP);
|
||||||
}
|
}
|
||||||
|
fpImageView->SetBorder(!fFullScreen);
|
||||||
fpImageView->SetShowCaption(fFullScreen && fShowCaption);
|
fpImageView->SetShowCaption(fFullScreen && fShowCaption);
|
||||||
MoveTo(frame.left, frame.top);
|
MoveTo(frame.left, frame.top);
|
||||||
ResizeTo(frame.Width(), frame.Height());
|
ResizeTo(frame.Width(), frame.Height());
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ private:
|
|||||||
void EnableMenuItem(BMenu *menu, uint32 what, bool enable);
|
void EnableMenuItem(BMenu *menu, uint32 what, bool enable);
|
||||||
void MarkMenuItem(BMenu *menu, uint32 what, bool marked);
|
void MarkMenuItem(BMenu *menu, uint32 what, bool marked);
|
||||||
void MarkSlideShowDelay(float value);
|
void MarkSlideShowDelay(float value);
|
||||||
|
void ResizeToWindow(bool shrink, uint32 what);
|
||||||
|
|
||||||
void SaveAs(BMessage *pmsg);
|
void SaveAs(BMessage *pmsg);
|
||||||
// Handle Save As submenu choice
|
// Handle Save As submenu choice
|
||||||
|
|||||||
Reference in New Issue
Block a user