1139823Simp/*
21541Srgrimes * Copyright 2006-2007, 2011, Stephan A��mus <superstippi@gmx.de>
31541Srgrimes * All rights reserved. Distributed under the terms of the MIT License.
41541Srgrimes */
51541Srgrimes
61541Srgrimes
71541Srgrimes#include "CanvasView.h"
81541Srgrimes
91541Srgrimes#include <Bitmap.h>
101541Srgrimes#include <Cursor.h>
111541Srgrimes#include <Message.h>
121541Srgrimes#include <Region.h>
131541Srgrimes#include <Window.h>
141541Srgrimes
151541Srgrimes#include <stdio.h>
161541Srgrimes
171541Srgrimes#include "cursors.h"
181541Srgrimes#include "ui_defines.h"
191541Srgrimes
201541Srgrimes#include "CommandStack.h"
211541Srgrimes#include "IconRenderer.h"
221541Srgrimes
231541Srgrimes
241541Srgrimesusing std::nothrow;
251541Srgrimes
261541Srgrimes
271541SrgrimesCanvasView::CanvasView(BRect frame)
281541Srgrimes	:
291541Srgrimes	StateView(frame, "canvas view", B_FOLLOW_ALL,
301541Srgrimes		B_WILL_DRAW | B_FRAME_EVENTS),
311541Srgrimes	fBitmap(new BBitmap(BRect(0, 0, 63, 63), 0, B_RGB32)),
3236503Speter	fBackground(new BBitmap(BRect(0, 0, 63, 63), 0, B_RGB32)),
331541Srgrimes	fIcon(NULL),
341541Srgrimes	fRenderer(new IconRenderer(fBitmap)),
3583651Speter	fDirtyIconArea(fBitmap->Bounds()),
3683651Speter
3783651Speter	fCanvasOrigin(0.0, 0.0),
381541Srgrimes	fZoomLevel(8.0),
391541Srgrimes
401541Srgrimes	fSpaceHeldDown(false),
411541Srgrimes	fInScrollTo(false),
421541Srgrimes	fScrollTracking(false),
4383651Speter	fScrollTrackingStart(0.0, 0.0),
44190380Srwatson
45190380Srwatson	fMouseFilterMode(SNAPPING_OFF)
461541Srgrimes{
4748274Speter	_MakeBackground();
4848274Speter	fRenderer->SetBackground(fBackground);
4960041Sphk}
5031886Sbde
511541Srgrimes
521541SrgrimesCanvasView::~CanvasView()
531541Srgrimes{
541541Srgrimes	SetIcon(NULL);
551541Srgrimes	delete fRenderer;
561541Srgrimes	delete fBitmap;
571541Srgrimes	delete fBackground;
589336Sdfr}
592997Swollman
602997Swollman
6183651Speter// #pragma mark -
62212506Skib
631541Srgrimes
643305Sphkvoid
6512662SdgCanvasView::AttachedToWindow()
6612662Sdg{
6792783Sjeff	StateView::AttachedToWindow();
683305Sphk
699336Sdfr	SetViewColor(B_TRANSPARENT_COLOR);
7083651Speter	SetLowColor(kStripesHigh);
7183651Speter	SetHighColor(kStripesLow);
72221543Srmacklem
731541Srgrimes	// init data rect for scrolling and center bitmap in the view
7483651Speter	BRect dataRect = _LayoutCanvas();
7583651Speter	SetDataRect(dataRect);
761541Srgrimes	BRect bounds(Bounds());
771541Srgrimes	BPoint dataRectCenter((dataRect.left + dataRect.right) / 2,
781541Srgrimes		(dataRect.top + dataRect.bottom) / 2);
791541Srgrimes	BPoint boundsCenter((bounds.left + bounds.right) / 2,
80158739Smohans		(bounds.top + bounds.bottom) / 2);
81158739Smohans	BPoint offset = ScrollOffset();
82158739Smohans	offset.x = roundf(offset.x + dataRectCenter.x - boundsCenter.x);
83158739Smohans	offset.y = roundf(offset.y + dataRectCenter.y - boundsCenter.y);
84158739Smohans	SetScrollOffset(offset);
85190380Srwatson}
86190380Srwatson
87190380Srwatson
88190380Srwatsonvoid
89190380SrwatsonCanvasView::FrameResized(float width, float height)
90190380Srwatson{
91190380Srwatson	// keep canvas centered
92190380Srwatson	BPoint oldCanvasOrigin = fCanvasOrigin;
93190380Srwatson	SetDataRect(_LayoutCanvas());
94190380Srwatson	if (oldCanvasOrigin != fCanvasOrigin)
95190380Srwatson		Invalidate();
96190380Srwatson}
97190380Srwatson
98190380Srwatson
99190380Srwatsonvoid
100190380SrwatsonCanvasView::Draw(BRect updateRect)
101190380Srwatson{
102190380Srwatson	_DrawInto(this, updateRect);
103158739Smohans}
1041541Srgrimes
1051541Srgrimes
1061541Srgrimes// #pragma mark -
10783651Speter
10883651Speter
1091541Srgrimesvoid
1101541SrgrimesCanvasView::MouseDown(BPoint where)
111176224Sjhb{
11212911Sphk	if (!IsFocus())
11383651Speter		MakeFocus(true);
11412911Sphk
11512911Sphk	int32 buttons;
11683651Speter	if (Window()->CurrentMessage()->FindInt32("buttons", &buttons) < B_OK)
11783651Speter		buttons = 0;
1189336Sdfr
11983651Speter	// handle clicks of the third mouse button ourselves (panning),
120176224Sjhb	// otherwise have StateView handle it (normal clicks)
121212506Skib	if (fSpaceHeldDown || (buttons & B_TERTIARY_MOUSE_BUTTON) != 0) {
1229759Sbde		// switch into scrolling mode and update cursor
1239336Sdfr		fScrollTracking = true;
1249336Sdfr		where.x = roundf(where.x);
1259336Sdfr		where.y = roundf(where.y);
1269336Sdfr		fScrollOffsetStart = ScrollOffset();
1279336Sdfr		fScrollTrackingStart = where - fScrollOffsetStart;
1289336Sdfr		_UpdateToolCursor();
1299336Sdfr		SetMouseEventMask(B_POINTER_EVENTS,
1309336Sdfr			B_LOCK_WINDOW_FOCUS | B_SUSPEND_VIEW_FOCUS);
1319336Sdfr	} else {
1329336Sdfr		StateView::MouseDown(where);
1339336Sdfr	}
1349336Sdfr}
1359336Sdfr
1369336Sdfr
1379336Sdfrvoid
1389336SdfrCanvasView::MouseUp(BPoint where)
1399336Sdfr{
1409336Sdfr	if (fScrollTracking) {
1419336Sdfr		// stop scroll tracking and update cursor
1429336Sdfr		fScrollTracking = false;
1439336Sdfr		_UpdateToolCursor();
1449336Sdfr		// update StateView mouse position
1459336Sdfr		uint32 transit = Bounds().Contains(where) ?
1469336Sdfr			B_INSIDE_VIEW : B_OUTSIDE_VIEW;
1479336Sdfr		StateView::MouseMoved(where, transit, NULL);
1489336Sdfr	} else {
1499336Sdfr		StateView::MouseUp(where);
1509336Sdfr	}
1519336Sdfr}
15260938Sjake
1533664Sphk
154176224Sjhbvoid
155176224SjhbCanvasView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
156176224Sjhb{
157176224Sjhb	if (fScrollTracking) {
158176224Sjhb		uint32 buttons;
159176224Sjhb		GetMouse(&where, &buttons, false);
160176224Sjhb		if (!buttons) {
161176224Sjhb			MouseUp(where);
162176224Sjhb			return;
163176224Sjhb		}
164176224Sjhb		where.x = roundf(where.x);
165176224Sjhb		where.y = roundf(where.y);
166176224Sjhb		where -= ScrollOffset();
167176224Sjhb		BPoint offset = where - fScrollTrackingStart;
168176224Sjhb		SetScrollOffset(fScrollOffsetStart - offset);
169176224Sjhb	} else {
170176224Sjhb		// normal mouse movement handled by StateView
171176224Sjhb		if (!fSpaceHeldDown)
172176224Sjhb			StateView::MouseMoved(where, transit, dragMessage);
173176224Sjhb	}
1741541Srgrimes}
1751541Srgrimes
1761541Srgrimes
1771541Srgrimesvoid
1781541SrgrimesCanvasView::FilterMouse(BPoint* where) const
1791541Srgrimes{
18083651Speter	switch (fMouseFilterMode) {
1811541Srgrimes
18283651Speter		case SNAPPING_64:
1831541Srgrimes			ConvertToCanvas(where);
184177599Sru			where->x = floorf(where->x + 0.5);
1851541Srgrimes			where->y = floorf(where->y + 0.5);
186177599Sru			ConvertFromCanvas(where);
1871541Srgrimes			break;
1881541Srgrimes
1891541Srgrimes		case SNAPPING_32:
1901541Srgrimes			ConvertToCanvas(where);
1911541Srgrimes			where->x /= 2.0;
19217186Sdfr			where->y /= 2.0;
19317186Sdfr			where->x = floorf(where->x + 0.5);
1941541Srgrimes			where->y = floorf(where->y + 0.5);
1951549Srgrimes			where->x *= 2.0;
19683651Speter			where->y *= 2.0;
1971541Srgrimes			ConvertFromCanvas(where);
19883651Speter			break;
19983651Speter
20083651Speter		case SNAPPING_16:
2011541Srgrimes			ConvertToCanvas(where);
2021541Srgrimes			where->x /= 4.0;
2031541Srgrimes			where->y /= 4.0;
204209120Skib			where->x = floorf(where->x + 0.5);
20517186Sdfr			where->y = floorf(where->y + 0.5);
2061541Srgrimes			where->x *= 4.0;
2071541Srgrimes			where->y *= 4.0;
2081541Srgrimes			ConvertFromCanvas(where);
2091541Srgrimes			break;
2101541Srgrimes
2111541Srgrimes		case SNAPPING_OFF:
2121541Srgrimes		default:
2131541Srgrimes			break;
2141541Srgrimes	}
2151541Srgrimes}
2161541Srgrimes
2171541Srgrimes
2181541Srgrimesbool
2191541SrgrimesCanvasView::MouseWheelChanged(BPoint where, float x, float y)
2201541Srgrimes{
221177599Sru	if (!Bounds().Contains(where))
2221541Srgrimes		return false;
223177599Sru
2241541Srgrimes	if (y > 0.0) {
2251541Srgrimes		_SetZoom(_NextZoomOutLevel(fZoomLevel), true);
2261541Srgrimes		return true;
2271541Srgrimes	} else if (y < 0.0) {
2281541Srgrimes		_SetZoom(_NextZoomInLevel(fZoomLevel), true);
2291541Srgrimes		return true;
2301541Srgrimes	}
2311541Srgrimes	return false;
2321541Srgrimes}
2331541Srgrimes
2341541Srgrimes
2351541Srgrimes// #pragma mark -
2361541Srgrimes
2371541Srgrimes
2381541Srgrimesvoid
2391541SrgrimesCanvasView::SetScrollOffset(BPoint newOffset)
2401541Srgrimes{
2411541Srgrimes	if (fInScrollTo)
2421541Srgrimes		return;
2431541Srgrimes
2441541Srgrimes	fInScrollTo = true;
2451541Srgrimes
2461541Srgrimes	newOffset = ValidScrollOffsetFor(newOffset);
247104908Smike	if (!fScrollTracking) {
248104908Smike		BPoint mouseOffset = newOffset - ScrollOffset();
24917186Sdfr		MouseMoved(fMouseInfo.position + mouseOffset, fMouseInfo.transit,
2501541Srgrimes			NULL);
2511541Srgrimes	}
2521541Srgrimes
2531541Srgrimes	Scrollable::SetScrollOffset(newOffset);
254177599Sru
2551541Srgrimes	fInScrollTo = false;
2561541Srgrimes}
2571541Srgrimes
2581541Srgrimes
2591541Srgrimesvoid
2601541SrgrimesCanvasView::ScrollOffsetChanged(BPoint oldOffset, BPoint newOffset)
2611541Srgrimes{
2621541Srgrimes	BPoint offset = newOffset - oldOffset;
2631541Srgrimes
2641541Srgrimes	if (offset == B_ORIGIN) {
2651541Srgrimes		// prevent circular code (MouseMoved might call ScrollBy...)
2661541Srgrimes		return;
2671541Srgrimes	}
2681541Srgrimes
2691541Srgrimes	ScrollBy(offset.x, offset.y);
2701541Srgrimes}
2711541Srgrimes
2721549Srgrimes
27383651Spetervoid
2741541SrgrimesCanvasView::VisibleSizeChanged(float oldWidth, float oldHeight, float newWidth,
27583651Speter	float newHeight)
2761541Srgrimes{
27736541Speter	BRect dataRect(_LayoutCanvas());
2781541Srgrimes	SetDataRect(dataRect);
2791541Srgrimes}
2801541Srgrimes
2811541Srgrimes
2821541Srgrimes// #pragma mark -
2831541Srgrimes
28436541Speter
2851541Srgrimesvoid
2861541SrgrimesCanvasView::AreaInvalidated(const BRect& area)
2871541Srgrimes{
2881541Srgrimes	if (fDirtyIconArea.Contains(area))
2891541Srgrimes		return;
2901541Srgrimes
2911541Srgrimes	fDirtyIconArea = fDirtyIconArea | area;
2921541Srgrimes
2931541Srgrimes	BRect viewArea(area);
2941541Srgrimes	ConvertFromCanvas(&viewArea);
2951541Srgrimes	Invalidate(viewArea);
2961541Srgrimes}
2971541Srgrimes
2981541Srgrimes
299177599Sru// #pragma mark -
3001541Srgrimes
301177599Sru
3021541Srgrimesvoid
3031541SrgrimesCanvasView::SetIcon(Icon* icon)
3041541Srgrimes{
30536541Speter	if (fIcon == icon)
3061541Srgrimes		return;
3071541Srgrimes
3081541Srgrimes	if (fIcon)
3091541Srgrimes		fIcon->RemoveListener(this);
3101541Srgrimes
3111541Srgrimes	fIcon = icon;
3121541Srgrimes	fRenderer->SetIcon(icon);
3131541Srgrimes
3141541Srgrimes	if (fIcon)
3151541Srgrimes		fIcon->AddListener(this);
3161541Srgrimes}
3171541Srgrimes
3181541Srgrimes
3191541Srgrimesvoid
3201541SrgrimesCanvasView::SetMouseFilterMode(uint32 mode)
3211541Srgrimes{
3221541Srgrimes	if (fMouseFilterMode == mode)
3231541Srgrimes		return;
3241541Srgrimes
3251541Srgrimes	fMouseFilterMode = mode;
3261541Srgrimes	Invalidate(_CanvasRect());
3271541Srgrimes}
3281541Srgrimes
3291541Srgrimes
3301541Srgrimesvoid
3311541SrgrimesCanvasView::ConvertFromCanvas(BPoint* point) const
3321541Srgrimes{
3331541Srgrimes	point->x = point->x * fZoomLevel + fCanvasOrigin.x;
3341549Srgrimes	point->y = point->y * fZoomLevel + fCanvasOrigin.y;
33583651Speter}
3361541Srgrimes
33783651Speter
3381541Srgrimesvoid
33992783SjeffCanvasView::ConvertToCanvas(BPoint* point) const
34092783Sjeff{
3411541Srgrimes	point->x = (point->x - fCanvasOrigin.x) / fZoomLevel;
3421541Srgrimes	point->y = (point->y - fCanvasOrigin.y) / fZoomLevel;
3433664Sphk}
3449336Sdfr
3459336Sdfr
3469336Sdfrvoid
3471541SrgrimesCanvasView::ConvertFromCanvas(BRect* r) const
34819449Sdfr{
349203072Srmacklem	r->left = r->left * fZoomLevel + fCanvasOrigin.x;
35099797Sdillon	r->top = r->top * fZoomLevel + fCanvasOrigin.y;
35119449Sdfr	r->right++;
3521541Srgrimes	r->bottom++;
3531541Srgrimes	r->right = r->right * fZoomLevel + fCanvasOrigin.x;
3541541Srgrimes	r->bottom = r->bottom * fZoomLevel + fCanvasOrigin.y;
3551541Srgrimes	r->right--;
3561541Srgrimes	r->bottom--;
357158739Smohans}
358172600Smohans
359212506Skib
36016365Sphkvoid
36142957SdillonCanvasView::ConvertToCanvas(BRect* r) const
36242957Sdillon{
3631549Srgrimes	r->left = (r->left - fCanvasOrigin.x) / fZoomLevel;
3641541Srgrimes	r->top = (r->top - fCanvasOrigin.y) / fZoomLevel;
3651541Srgrimes	r->right = (r->right - fCanvasOrigin.x) / fZoomLevel;
36638894Sbde	r->bottom = (r->bottom - fCanvasOrigin.y) / fZoomLevel;
36783651Speter}
36838894Sbde
369128111Speadar
37038894Sbde// #pragma mark -
371128111Speadar
372128111Speadar
373128111Speadarbool
374212506SkibCanvasView::_HandleKeyDown(uint32 key, uint32 modifiers)
375128111Speadar{
376158739Smohans	switch (key) {
377128111Speadar		case 'z':
378212506Skib		case 'y':
379212506Skib			if (modifiers & B_SHIFT_KEY)
380212506Skib				CommandStack()->Redo();
381128111Speadar			else
382203072Srmacklem				CommandStack()->Undo();
383128111Speadar			break;
384128111Speadar
385128111Speadar		case '+':
386158739Smohans			_SetZoom(_NextZoomInLevel(fZoomLevel));
387158739Smohans			break;
388128111Speadar		case '-':
389128111Speadar			_SetZoom(_NextZoomOutLevel(fZoomLevel));
39038894Sbde			break;
39138894Sbde
39238894Sbde		case B_SPACE:
393158739Smohans			fSpaceHeldDown = true;
394158739Smohans			_UpdateToolCursor();
395158739Smohans			break;
396158739Smohans
397158739Smohans		default:
398158739Smohans			return StateView::_HandleKeyDown(key, modifiers);
399158739Smohans	}
400158739Smohans
401158739Smohans	return true;
402158739Smohans}
403158739Smohans
404158739Smohans
405158739Smohansbool
406158739SmohansCanvasView::_HandleKeyUp(uint32 key, uint32 modifiers)
407158739Smohans{
408158739Smohans	switch (key) {
409158739Smohans		case B_SPACE:
410158739Smohans			fSpaceHeldDown = false;
411158739Smohans			_UpdateToolCursor();
412158739Smohans			break;
413176134Sattilio
414158739Smohans		default:
415158739Smohans			return StateView::_HandleKeyUp(key, modifiers);
416196205Skib	}
417196205Skib
418196205Skib	return true;
419196205Skib}
420196205Skib
421196205Skib
422196205SkibBRect
423196205SkibCanvasView::_CanvasRect() const
424158739Smohans{
425196205Skib	BRect r;
426158739Smohans	if (fBitmap == NULL)
427158739Smohans		return r;
428158739Smohans	r = fBitmap->Bounds();
429176134Sattilio	ConvertFromCanvas(&r);
430158739Smohans	return r;
431158739Smohans}
432196205Skib
433196205Skib
434196205Skibvoid
435158739SmohansCanvasView::_DrawInto(BView* view, BRect updateRect)
436158739Smohans{
437158739Smohans	if (fDirtyIconArea.IsValid()) {
438158739Smohans		fRenderer->Render(fDirtyIconArea, true);
439158739Smohans		fDirtyIconArea.Set(LONG_MAX, LONG_MAX, LONG_MIN, LONG_MIN);
440158739Smohans	}
441158739Smohans
442158739Smohans	// icon
443158739Smohans	BRect canvas(_CanvasRect());
444158739Smohans	view->DrawBitmap(fBitmap, fBitmap->Bounds(), canvas);
445220595Sru
446158739Smohans	// grid
447158739Smohans	int32 gridLines = 0;
448158739Smohans	int32 scale = 1;
449158739Smohans	switch (fMouseFilterMode) {
4501541Srgrimes		case SNAPPING_64:
4511541Srgrimes			gridLines = 63;
4521541Srgrimes			break;
4531541Srgrimes		case SNAPPING_32:
4541541Srgrimes			gridLines = 31;
4551541Srgrimes			scale = 2;
4561541Srgrimes			break;
4571541Srgrimes		case SNAPPING_16:
4581541Srgrimes			gridLines = 15;
4591541Srgrimes			scale = 4;
4601541Srgrimes			break;
4611541Srgrimes		case SNAPPING_OFF:
4621541Srgrimes		default:
4631541Srgrimes			break;
4641549Srgrimes	}
46583651Speter	view->SetDrawingMode(B_OP_BLEND);
466158739Smohans	for (int32 i = 1; i <= gridLines; i++) {
4671541Srgrimes		BPoint cross(i * scale, i * scale);
46883651Speter		ConvertFromCanvas(&cross);
46983651Speter		view->StrokeLine(BPoint(canvas.left, cross.y),
47083651Speter						 BPoint(canvas.right, cross.y));
471190380Srwatson		view->StrokeLine(BPoint(cross.x, canvas.top),
47283651Speter						 BPoint(cross.x, canvas.bottom));
4739336Sdfr	}
47484057Speter	view->SetDrawingMode(B_OP_COPY);
4751541Srgrimes
4761541Srgrimes	// outside icon
4771541Srgrimes	BRegion outside(Bounds() & updateRect);
478171190Sjhb	outside.Exclude(canvas);
4799336Sdfr	view->FillRegion(&outside, kStripes);
480190380Srwatson
4811541Srgrimes	StateView::Draw(view, updateRect);
4821541Srgrimes}
4839336Sdfr
484177599Sru
485190380Srwatsonvoid
486190380SrwatsonCanvasView::_MakeBackground()
487190380Srwatson{
488190380Srwatson	uint8* row = (uint8*)fBackground->Bits();
4899336Sdfr	uint32 bpr = fBackground->BytesPerRow();
4909336Sdfr	uint32 width = fBackground->Bounds().IntegerWidth() + 1;
4919336Sdfr	uint32 height = fBackground->Bounds().IntegerHeight() + 1;
4929336Sdfr
493130640Sphk	const GammaTable& lut = fRenderer->GammaTable();
49416634Sbde	uint8 redLow = lut.dir(kAlphaLow.red);
4959336Sdfr	uint8 greenLow = lut.dir(kAlphaLow.blue);
4961541Srgrimes	uint8 blueLow = lut.dir(kAlphaLow.green);
4979336Sdfr	uint8 redHigh = lut.dir(kAlphaHigh.red);
4989336Sdfr	uint8 greenHigh = lut.dir(kAlphaHigh.blue);
4999336Sdfr	uint8 blueHigh = lut.dir(kAlphaHigh.green);
5009336Sdfr
5019336Sdfr	for (uint32 y = 0; y < height; y++) {
5029336Sdfr		uint8* p = row;
5039336Sdfr		for (uint32 x = 0; x < width; x++) {
5049336Sdfr			p[3] = 255;
5059336Sdfr			if (x % 8 >= 4) {
5069336Sdfr				if (y % 8 >= 4) {
5079336Sdfr					p[0] = blueLow;
5089336Sdfr					p[1] = greenLow;
5099336Sdfr					p[2] = redLow;
5109336Sdfr				} else {
5119336Sdfr					p[0] = blueHigh;
5129336Sdfr					p[1] = greenHigh;
5139336Sdfr					p[2] = redHigh;
5149336Sdfr				}
5159336Sdfr			} else {
5169336Sdfr				if (y % 8 >= 4) {
5179336Sdfr					p[0] = blueHigh;
5189336Sdfr					p[1] = greenHigh;
5199336Sdfr					p[2] = redHigh;
52036541Speter				} else {
5219336Sdfr					p[0] = blueLow;
5229336Sdfr					p[1] = greenLow;
5239336Sdfr					p[2] = redLow;
5249336Sdfr				}
5259336Sdfr			}
5269336Sdfr			p += 4;
5279336Sdfr		}
5281541Srgrimes		row += bpr;
5299336Sdfr	}
5301541Srgrimes}
5311541Srgrimes
5328876Srgrimes
5331541Srgrimesvoid
5341541SrgrimesCanvasView::_UpdateToolCursor()
5351541Srgrimes{
5361541Srgrimes	if (fIcon) {
5371541Srgrimes		if (fScrollTracking || fSpaceHeldDown) {
538158739Smohans			// indicate scrolling mode
53910219Sdfr			const uchar* cursorData = fScrollTracking ? kGrabCursor : kHandCursor;
5409336Sdfr			BCursor cursor(cursorData);
541126851Sphk			SetViewCursor(&cursor, true);
542138290Sphk		} else {
543138473Sps			// pass on to current state of StateView
5441541Srgrimes			UpdateStateCursor();
5451541Srgrimes		}
5461541Srgrimes	} else {
5471541Srgrimes		BCursor cursor(kStopCursor);
54847028Sphk		SetViewCursor(&cursor, true);
549171190Sjhb	}
5501541Srgrimes}
5511541Srgrimes
5529336Sdfr
5539336Sdfr// #pragma mark -
5549336Sdfr
5559336Sdfr
55647751Speterdouble
5579336SdfrCanvasView::_NextZoomInLevel(double zoom) const
55847751Speter{
55936541Speter	if (zoom < 1)
56036541Speter		return 1;
5619336Sdfr	if (zoom < 1.5)
5629336Sdfr		return 1.5;
5639336Sdfr	if (zoom < 2)
5649336Sdfr		return 2;
5651541Srgrimes	if (zoom < 3)
5669336Sdfr		return 3;
5679336Sdfr	if (zoom < 4)
5689336Sdfr		return 4;
56936541Speter	if (zoom < 6)
57036541Speter		return 6;
57147751Speter	if (zoom < 8)
57236541Speter		return 8;
57336541Speter	if (zoom < 16)
5749336Sdfr		return 16;
5751541Srgrimes	if (zoom < 32)
57636541Speter		return 32;
57736541Speter	return 64;
57818397Snate}
57983651Speter
5801541Srgrimes
5811541Srgrimesdouble
58267486SdwmaloneCanvasView::_NextZoomOutLevel(double zoom) const
5831541Srgrimes{
5841541Srgrimes	if (zoom > 32)
58567486Sdwmalone		return 32;
58667486Sdwmalone	if (zoom > 16)
58767486Sdwmalone		return 16;
58867486Sdwmalone	if (zoom > 8)
58967486Sdwmalone		return 8;
59067486Sdwmalone	if (zoom > 6)
59167486Sdwmalone		return 6;
59267486Sdwmalone	if (zoom > 4)
593190380Srwatson		return 4;
59467486Sdwmalone	if (zoom > 3)
595128263Speadar		return 3;
596128263Speadar	if (zoom > 2)
597128263Speadar		return 2;
598128263Speadar	if (zoom > 1.5)
599128263Speadar		return 1.5;
6001541Srgrimes	return 1;
601128263Speadar}
6021541Srgrimes
603128263Speadar
604128263Speadarvoid
60554480SdillonCanvasView::_SetZoom(double zoomLevel, bool mouseIsAnchor)
6061541Srgrimes{
607128263Speadar	if (fZoomLevel == zoomLevel)
60854480Sdillon		return;
60941026Speter
61054480Sdillon	BPoint anchor;
6111541Srgrimes	if (mouseIsAnchor) {
61254480Sdillon		// zoom into mouse position
6131541Srgrimes		anchor = MouseInfo()->position;
614171190Sjhb	} else {
615171190Sjhb		// zoom into center of view
616171190Sjhb		BRect bounds(Bounds());
617171190Sjhb		anchor.x = (bounds.left + bounds.right + 1) / 2.0;
618171190Sjhb		anchor.y = (bounds.top + bounds.bottom + 1) / 2.0;
619171190Sjhb	}
620171190Sjhb
621171190Sjhb	BPoint canvasAnchor = anchor;
622171190Sjhb	ConvertToCanvas(&canvasAnchor);
623171190Sjhb
624171190Sjhb	fZoomLevel = zoomLevel;
625171190Sjhb	BRect dataRect = _LayoutCanvas();
626190380Srwatson
627171190Sjhb	ConvertFromCanvas(&canvasAnchor);
628171190Sjhb
629190380Srwatson	BPoint offset = ScrollOffset();
630190380Srwatson	offset.x = roundf(offset.x + canvasAnchor.x - anchor.x);
6311541Srgrimes	offset.y = roundf(offset.y + canvasAnchor.y - anchor.y);
6321541Srgrimes
6331541Srgrimes	Invalidate();
6349336Sdfr
6359336Sdfr	SetDataRectAndScrollOffset(dataRect, offset);
6369336Sdfr}
6379336Sdfr
6381541Srgrimes
6391541SrgrimesBRect
640190396SrwatsonCanvasView::_LayoutCanvas()
641190396Srwatson{
642190396Srwatson	// size of zoomed bitmap
643190396Srwatson	BRect r(_CanvasRect());
644190396Srwatson	r.OffsetTo(B_ORIGIN);
645158739Smohans
646190380Srwatson	// ask current view state to extend size
647190396Srwatson	// TODO: Ask StateViewState to extend bounds...
648190396Srwatson	BRect stateBounds = r; //ViewStateBounds();
649190396Srwatson
650190380Srwatson	// resize for empty area around bitmap
651190380Srwatson	// (the size we want, but might still be much smaller than view)
6521541Srgrimes	r.InsetBy(-50, -50);
6531541Srgrimes
65436176Speter	// center data rect in bounds
65536176Speter	BRect bounds(Bounds());
656221973Srmacklem	if (bounds.Width() > r.Width())
65736176Speter		r.InsetBy(-ceilf((bounds.Width() - r.Width()) / 2), 0);
658221973Srmacklem	if (bounds.Height() > r.Height())
659220595Sru		r.InsetBy(0, -ceilf((bounds.Height() - r.Height()) / 2));
66036176Speter
66136176Speter	if (stateBounds.IsValid()) {
6621541Srgrimes		stateBounds.InsetBy(-20, -20);
6631541Srgrimes		r = r | stateBounds;
6641541Srgrimes	}
6651541Srgrimes
6661541Srgrimes	return r;
6671549Srgrimes}
66883651Speter
6691541Srgrimes