xref: /haiku/src/apps/resedit/BitmapView.cpp (revision bab64f65bb775dc23060e276f1f1c4498ab7af6c)
122c6ae69SDarkWyrm #include "BitmapView.h"
209a03cb8SDarkWyrm #include <Alert.h>
309a03cb8SDarkWyrm #include <BitmapStream.h>
409a03cb8SDarkWyrm #include <Clipboard.h>
509a03cb8SDarkWyrm #include <Font.h>
609a03cb8SDarkWyrm #include <MenuItem.h>
722c6ae69SDarkWyrm #include <Entry.h>
822c6ae69SDarkWyrm #include <TranslationUtils.h>
922c6ae69SDarkWyrm #include <TranslatorRoster.h>
1022c6ae69SDarkWyrm #include <TranslatorFormats.h>
1122c6ae69SDarkWyrm 
1222c6ae69SDarkWyrm // TODO: Add support for labels
1322c6ae69SDarkWyrm 
1422c6ae69SDarkWyrm #define M_REMOVE_IMAGE 'mrmi'
1522c6ae69SDarkWyrm #define M_PASTE_IMAGE 'mpsi'
1622c6ae69SDarkWyrm 
1722c6ae69SDarkWyrm enum
1822c6ae69SDarkWyrm {
1922c6ae69SDarkWyrm 	CLIP_NONE = 0,
2022c6ae69SDarkWyrm 	CLIP_BEOS = 1,
2122c6ae69SDarkWyrm 	CLIP_SHOWIMAGE = 2,
2222c6ae69SDarkWyrm 	CLIP_PRODUCTIVE = 3
2322c6ae69SDarkWyrm };
2422c6ae69SDarkWyrm 
2509a03cb8SDarkWyrm 
2622c6ae69SDarkWyrm inline void SetRGBColor(rgb_color *col, uint8 r, uint8 g, uint8 b, uint8 a = 255);
2722c6ae69SDarkWyrm 
2809a03cb8SDarkWyrm 
2909a03cb8SDarkWyrm void
SetRGBColor(rgb_color * col,uint8 r,uint8 g,uint8 b,uint8 a)3009a03cb8SDarkWyrm SetRGBColor(rgb_color *col, uint8 r, uint8 g, uint8 b, uint8 a)
3122c6ae69SDarkWyrm {
3209a03cb8SDarkWyrm 	if (col) {
3322c6ae69SDarkWyrm 		col->red = r;
3422c6ae69SDarkWyrm 		col->green = g;
3522c6ae69SDarkWyrm 		col->blue = b;
3622c6ae69SDarkWyrm 		col->alpha = a;
3722c6ae69SDarkWyrm 	}
3822c6ae69SDarkWyrm }
3922c6ae69SDarkWyrm 
4009a03cb8SDarkWyrm 
BitmapView(BRect frame,const char * name,BMessage * mod,BBitmap * bitmap,const char * label,border_style borderstyle,int32 resize,int32 flags)4122c6ae69SDarkWyrm BitmapView::BitmapView(BRect frame, const char *name, BMessage *mod, BBitmap *bitmap,
4222c6ae69SDarkWyrm 						const char *label, border_style borderstyle, int32 resize, int32 flags)
4322c6ae69SDarkWyrm   :	BView(frame, name, resize, flags)
4422c6ae69SDarkWyrm {
45*fa19dd44Slooncraz 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
4622c6ae69SDarkWyrm 
4722c6ae69SDarkWyrm 	if (bitmap && bitmap->IsValid())
4822c6ae69SDarkWyrm 		fBitmap = bitmap;
4922c6ae69SDarkWyrm 	else
5022c6ae69SDarkWyrm 		fBitmap = NULL;
5122c6ae69SDarkWyrm 
5222c6ae69SDarkWyrm 	if (mod)
5322c6ae69SDarkWyrm 		SetMessage(mod);
5422c6ae69SDarkWyrm 
5522c6ae69SDarkWyrm 	fLabel = label;
5622c6ae69SDarkWyrm 	fBorderStyle = borderstyle;
5722c6ae69SDarkWyrm 	fFixedSize = false;
5822c6ae69SDarkWyrm 	fEnabled = true;
5922c6ae69SDarkWyrm 	fRemovableBitmap = false;
6022c6ae69SDarkWyrm 	fAcceptDrops = true;
6122c6ae69SDarkWyrm 	fAcceptPaste = true;
6222c6ae69SDarkWyrm 	fConstrainDrops = true;
6322c6ae69SDarkWyrm 	fMaxWidth = 100;
6422c6ae69SDarkWyrm 	fMaxHeight = 100;
6522c6ae69SDarkWyrm 
6622c6ae69SDarkWyrm 	fPopUpMenu = new BPopUpMenu("deletepopup", false, false);
6722c6ae69SDarkWyrm 	fPopUpMenu->AddItem(new BMenuItem("Close This Menu", new BMessage(B_CANCEL)));
6822c6ae69SDarkWyrm 	fPopUpMenu->AddSeparatorItem();
6922c6ae69SDarkWyrm 
7022c6ae69SDarkWyrm 	fPasteItem = new BMenuItem("Paste Photo from Clipboard", new BMessage(M_PASTE_IMAGE));
7122c6ae69SDarkWyrm 	fPopUpMenu->AddItem(fPasteItem);
7222c6ae69SDarkWyrm 
7322c6ae69SDarkWyrm 	fPopUpMenu->AddSeparatorItem();
7422c6ae69SDarkWyrm 
7522c6ae69SDarkWyrm 	fRemoveItem = new BMenuItem("Remove Photo", new BMessage(M_REMOVE_IMAGE));
7622c6ae69SDarkWyrm 	fPopUpMenu->AddItem(fRemoveItem);
7722c6ae69SDarkWyrm 
7822c6ae69SDarkWyrm 	CalculateBitmapRect();
7922c6ae69SDarkWyrm 
8022c6ae69SDarkWyrm 	// Calculate the offsets for each of the words -- the phrase will be center justified
8122c6ae69SDarkWyrm 	fNoPhotoWidths[0] = StringWidth("Drop");
8222c6ae69SDarkWyrm 	fNoPhotoWidths[1] = StringWidth("a");
8322c6ae69SDarkWyrm 	fNoPhotoWidths[2] = StringWidth("Photo");
8422c6ae69SDarkWyrm 	fNoPhotoWidths[3] = StringWidth("Here");
8522c6ae69SDarkWyrm 
8622c6ae69SDarkWyrm 	font_height fh;
8722c6ae69SDarkWyrm 	GetFontHeight(&fh);
8822c6ae69SDarkWyrm 	float totalheight = fh.ascent + fh.descent + fh.leading;
8922c6ae69SDarkWyrm 	float yoffset = (Bounds().Height() - 10 - (totalheight * 4)) / 2;
9022c6ae69SDarkWyrm 	fNoPhotoOffsets[0].Set((Bounds().Width() - fNoPhotoWidths[0]) / 2, totalheight + yoffset);
9109a03cb8SDarkWyrm 	fNoPhotoOffsets[1].Set((Bounds().Width() - fNoPhotoWidths[1]) / 2,
9209a03cb8SDarkWyrm 							fNoPhotoOffsets[0].y + totalheight);
9309a03cb8SDarkWyrm 	fNoPhotoOffsets[2].Set((Bounds().Width() - fNoPhotoWidths[2]) / 2,
9409a03cb8SDarkWyrm 							fNoPhotoOffsets[1].y + totalheight);
9509a03cb8SDarkWyrm 	fNoPhotoOffsets[3].Set((Bounds().Width() - fNoPhotoWidths[3]) / 2,
9609a03cb8SDarkWyrm 							fNoPhotoOffsets[2].y + totalheight);
9722c6ae69SDarkWyrm }
9822c6ae69SDarkWyrm 
9909a03cb8SDarkWyrm 
~BitmapView(void)10022c6ae69SDarkWyrm BitmapView::~BitmapView(void)
10122c6ae69SDarkWyrm {
10222c6ae69SDarkWyrm 	delete fPopUpMenu;
10322c6ae69SDarkWyrm }
10422c6ae69SDarkWyrm 
10509a03cb8SDarkWyrm 
10609a03cb8SDarkWyrm void
AttachedToWindow(void)10709a03cb8SDarkWyrm BitmapView::AttachedToWindow(void)
10822c6ae69SDarkWyrm {
10922c6ae69SDarkWyrm 	SetTarget((BHandler*)Window());
11022c6ae69SDarkWyrm 	fPopUpMenu->SetTargetForItems(this);
11122c6ae69SDarkWyrm }
11222c6ae69SDarkWyrm 
11309a03cb8SDarkWyrm 
11409a03cb8SDarkWyrm void
SetBitmap(BBitmap * bitmap)11509a03cb8SDarkWyrm BitmapView::SetBitmap(BBitmap *bitmap)
11622c6ae69SDarkWyrm {
11709a03cb8SDarkWyrm 	if (bitmap && bitmap->IsValid()) {
11822c6ae69SDarkWyrm 		if (fBitmap == bitmap)
11922c6ae69SDarkWyrm 			return;
12022c6ae69SDarkWyrm 		fBitmap = bitmap;
12109a03cb8SDarkWyrm 	} else {
12209a03cb8SDarkWyrm 		if (!fBitmap)
12322c6ae69SDarkWyrm 			return;
12422c6ae69SDarkWyrm 		fBitmap = NULL;
12522c6ae69SDarkWyrm 	}
12622c6ae69SDarkWyrm 
12722c6ae69SDarkWyrm 	CalculateBitmapRect();
12822c6ae69SDarkWyrm 	if (!IsHidden())
12922c6ae69SDarkWyrm 		Invalidate();
13022c6ae69SDarkWyrm }
13122c6ae69SDarkWyrm 
13209a03cb8SDarkWyrm 
13309a03cb8SDarkWyrm void
SetEnabled(bool value)13409a03cb8SDarkWyrm BitmapView::SetEnabled(bool value)
13522c6ae69SDarkWyrm {
13609a03cb8SDarkWyrm 	if (fEnabled != value) {
13722c6ae69SDarkWyrm 		fEnabled = value;
13822c6ae69SDarkWyrm 		Invalidate();
13922c6ae69SDarkWyrm 	}
14022c6ae69SDarkWyrm }
14122c6ae69SDarkWyrm 
14209a03cb8SDarkWyrm 
14322c6ae69SDarkWyrm /*
14409a03cb8SDarkWyrm void
14509a03cb8SDarkWyrm BitmapView::SetLabel(const char *label)
14622c6ae69SDarkWyrm {
14709a03cb8SDarkWyrm 	if (fLabel.Compare(label) != 0)	{
14822c6ae69SDarkWyrm 		fLabel = label;
14922c6ae69SDarkWyrm 
15022c6ae69SDarkWyrm 		CalculateBitmapRect();
15122c6ae69SDarkWyrm 		if (!IsHidden())
15222c6ae69SDarkWyrm 			Invalidate();
15322c6ae69SDarkWyrm 	}
15422c6ae69SDarkWyrm }
15522c6ae69SDarkWyrm */
15622c6ae69SDarkWyrm 
15709a03cb8SDarkWyrm 
15809a03cb8SDarkWyrm void
SetStyle(border_style style)15909a03cb8SDarkWyrm BitmapView::SetStyle(border_style style)
16022c6ae69SDarkWyrm {
16109a03cb8SDarkWyrm 	if (fBorderStyle != style) {
16222c6ae69SDarkWyrm 		fBorderStyle = style;
16322c6ae69SDarkWyrm 
16422c6ae69SDarkWyrm 		CalculateBitmapRect();
16522c6ae69SDarkWyrm 		if (!IsHidden())
16622c6ae69SDarkWyrm 			Invalidate();
16722c6ae69SDarkWyrm 	}
16822c6ae69SDarkWyrm }
16922c6ae69SDarkWyrm 
17009a03cb8SDarkWyrm 
17109a03cb8SDarkWyrm void
SetFixedSize(bool isfixed)17209a03cb8SDarkWyrm BitmapView::SetFixedSize(bool isfixed)
17322c6ae69SDarkWyrm {
17409a03cb8SDarkWyrm 	if (fFixedSize != isfixed) {
17522c6ae69SDarkWyrm 		fFixedSize = isfixed;
17622c6ae69SDarkWyrm 
17722c6ae69SDarkWyrm 		CalculateBitmapRect();
17822c6ae69SDarkWyrm 		if (!IsHidden())
17922c6ae69SDarkWyrm 			Invalidate();
18022c6ae69SDarkWyrm 	}
18122c6ae69SDarkWyrm }
18222c6ae69SDarkWyrm 
18309a03cb8SDarkWyrm 
18409a03cb8SDarkWyrm void
MessageReceived(BMessage * msg)18509a03cb8SDarkWyrm BitmapView::MessageReceived(BMessage *msg)
18622c6ae69SDarkWyrm {
18709a03cb8SDarkWyrm 	if (msg->WasDropped() && AcceptsDrops()) {
18822c6ae69SDarkWyrm 		// We'll handle two types of drops: those from Tracker and those from ShowImage
18909a03cb8SDarkWyrm 		if (msg->what == B_SIMPLE_DATA) {
19022c6ae69SDarkWyrm 			int32 actions;
19109a03cb8SDarkWyrm 			if (msg->FindInt32("be:actions", &actions) == B_OK) {
19222c6ae69SDarkWyrm 				// ShowImage drop. This is a negotiated drag&drop, so send a reply
19322c6ae69SDarkWyrm 				BMessage reply(B_COPY_TARGET), response;
19422c6ae69SDarkWyrm 				reply.AddString("be:types", "image/jpeg");
19522c6ae69SDarkWyrm 				reply.AddString("be:types", "image/png");
19622c6ae69SDarkWyrm 
19722c6ae69SDarkWyrm 				msg->SendReply(&reply, &response);
19822c6ae69SDarkWyrm 
19922c6ae69SDarkWyrm 				// now, we've gotten the response
20009a03cb8SDarkWyrm 				if (response.what == B_MIME_DATA) {
20122c6ae69SDarkWyrm 					// Obtain and translate the received data
20222c6ae69SDarkWyrm 					uint8 *imagedata;
20322c6ae69SDarkWyrm 					ssize_t datasize;
20422c6ae69SDarkWyrm 
20522c6ae69SDarkWyrm 					// Try JPEG first
20609a03cb8SDarkWyrm 					if (response.FindData("image/jpeg", B_MIME_DATA,
20709a03cb8SDarkWyrm 						(const void **)&imagedata, &datasize) != B_OK) {
20822c6ae69SDarkWyrm 						// Try PNG next and piddle out if unsuccessful
20909a03cb8SDarkWyrm 						if (response.FindData("image/png", B_PNG_FORMAT,
21009a03cb8SDarkWyrm 							(const void **)&imagedata, &datasize) != B_OK)
21122c6ae69SDarkWyrm 							return;
21222c6ae69SDarkWyrm 					}
21322c6ae69SDarkWyrm 
21422c6ae69SDarkWyrm 					// Set up to decode into memory
21522c6ae69SDarkWyrm 					BMemoryIO memio(imagedata, datasize);
21622c6ae69SDarkWyrm 					BTranslatorRoster *roster = BTranslatorRoster::Default();
21722c6ae69SDarkWyrm 					BBitmapStream bstream;
21822c6ae69SDarkWyrm 
21922c6ae69SDarkWyrm 					if (roster->Translate(&memio, NULL, NULL, &bstream, B_TRANSLATOR_BITMAP) == B_OK)
22022c6ae69SDarkWyrm 					{
22122c6ae69SDarkWyrm 						BBitmap *bmp;
22222c6ae69SDarkWyrm 						if (bstream.DetachBitmap(&bmp) != B_OK)
22322c6ae69SDarkWyrm 							return;
22422c6ae69SDarkWyrm 						SetBitmap(bmp);
22522c6ae69SDarkWyrm 
22622c6ae69SDarkWyrm 						if (fConstrainDrops)
22722c6ae69SDarkWyrm 							ConstrainBitmap();
22822c6ae69SDarkWyrm 						Invoke();
22922c6ae69SDarkWyrm 					}
23022c6ae69SDarkWyrm 				}
23122c6ae69SDarkWyrm 				return;
23222c6ae69SDarkWyrm 			}
23322c6ae69SDarkWyrm 
23422c6ae69SDarkWyrm 			entry_ref ref;
23509a03cb8SDarkWyrm 			if (msg->FindRef("refs", &ref) == B_OK) {
23622c6ae69SDarkWyrm 				// Tracker drop
23722c6ae69SDarkWyrm 				BBitmap *bmp = BTranslationUtils::GetBitmap(&ref);
23809a03cb8SDarkWyrm 				if (bmp) {
23922c6ae69SDarkWyrm 					SetBitmap(bmp);
24022c6ae69SDarkWyrm 
24122c6ae69SDarkWyrm 					if (fConstrainDrops)
24222c6ae69SDarkWyrm 						ConstrainBitmap();
24322c6ae69SDarkWyrm 					Invoke();
24422c6ae69SDarkWyrm 				}
24522c6ae69SDarkWyrm 			}
24622c6ae69SDarkWyrm 		}
24722c6ae69SDarkWyrm 		return;
24822c6ae69SDarkWyrm 	}
24922c6ae69SDarkWyrm 
25022c6ae69SDarkWyrm 	switch (msg->what)
25122c6ae69SDarkWyrm 	{
25209a03cb8SDarkWyrm 		case M_REMOVE_IMAGE: {
2534d99b24dSHumdinger 			BAlert *alert = new BAlert("ResEdit", "This cannot be undone. "
254aed35104SHumdinger 				"Remove the image?", "Remove", "Cancel");
255aed35104SHumdinger 			alert->SetShortcut(1, B_ESCAPE);
25622c6ae69SDarkWyrm 			int32 value = alert->Go();
25709a03cb8SDarkWyrm 			if (value == 0) {
25822c6ae69SDarkWyrm 				SetBitmap(NULL);
25922c6ae69SDarkWyrm 
26009a03cb8SDarkWyrm 				if (Target()) {
26122c6ae69SDarkWyrm 					BMessenger msgr(Target());
26222c6ae69SDarkWyrm 
26322c6ae69SDarkWyrm 					msgr.SendMessage(new BMessage(M_BITMAP_REMOVED));
26422c6ae69SDarkWyrm 					return;
26522c6ae69SDarkWyrm 				}
26622c6ae69SDarkWyrm 			}
26722c6ae69SDarkWyrm 		}
26822c6ae69SDarkWyrm 		case M_PASTE_IMAGE:
26922c6ae69SDarkWyrm 		{
27022c6ae69SDarkWyrm 			PasteBitmap();
27122c6ae69SDarkWyrm 			Invoke();
27222c6ae69SDarkWyrm 		}
27322c6ae69SDarkWyrm 	}
27422c6ae69SDarkWyrm 	BView::MessageReceived(msg);
27522c6ae69SDarkWyrm }
27622c6ae69SDarkWyrm 
27709a03cb8SDarkWyrm 
27809a03cb8SDarkWyrm void
Draw(BRect rect)27909a03cb8SDarkWyrm BitmapView::Draw(BRect rect)
28022c6ae69SDarkWyrm {
28122c6ae69SDarkWyrm 	if (fBitmap)
28222c6ae69SDarkWyrm 		DrawBitmap(fBitmap, fBitmap->Bounds(), fBitmapRect);
28309a03cb8SDarkWyrm 	else {
28422c6ae69SDarkWyrm 		SetHighColor(0, 0, 0, 80);
28522c6ae69SDarkWyrm 		SetDrawingMode(B_OP_ALPHA);
28622c6ae69SDarkWyrm 		DrawString("Drop", fNoPhotoOffsets[0]);
28722c6ae69SDarkWyrm 		DrawString("a", fNoPhotoOffsets[1]);
28822c6ae69SDarkWyrm 		DrawString("Photo", fNoPhotoOffsets[2]);
28922c6ae69SDarkWyrm 		DrawString("Here", fNoPhotoOffsets[3]);
29022c6ae69SDarkWyrm 		SetDrawingMode(B_OP_COPY);
29122c6ae69SDarkWyrm 	}
29222c6ae69SDarkWyrm 
29309a03cb8SDarkWyrm 	if (fBorderStyle == B_FANCY_BORDER) {
29422c6ae69SDarkWyrm 		rgb_color base= { 216, 216, 216, 255 };
29522c6ae69SDarkWyrm 		rgb_color work;
29622c6ae69SDarkWyrm 
29722c6ae69SDarkWyrm 		SetHighColor(base);
29822c6ae69SDarkWyrm 		StrokeRect(Bounds().InsetByCopy(2, 2));
29922c6ae69SDarkWyrm 
30022c6ae69SDarkWyrm 		BeginLineArray(12);
30122c6ae69SDarkWyrm 
30222c6ae69SDarkWyrm 		BRect r(Bounds());
30322c6ae69SDarkWyrm 
30422c6ae69SDarkWyrm 		work = tint_color(base, B_DARKEN_2_TINT);
30522c6ae69SDarkWyrm 		AddLine(r.LeftTop(), r.RightTop(), work);
30622c6ae69SDarkWyrm 		AddLine(r.LeftTop(), r.LeftBottom(), work);
30722c6ae69SDarkWyrm 		r.left++;
30822c6ae69SDarkWyrm 
30922c6ae69SDarkWyrm 		work = tint_color(base, B_DARKEN_4_TINT);
31022c6ae69SDarkWyrm 		AddLine(r.RightTop(), r.RightBottom(), work);
31122c6ae69SDarkWyrm 		AddLine(r.LeftBottom(), r.RightBottom(), work);
31222c6ae69SDarkWyrm 
31322c6ae69SDarkWyrm 		r.right--;
31422c6ae69SDarkWyrm 		r.top++;
31522c6ae69SDarkWyrm 		r.bottom--;
31622c6ae69SDarkWyrm 
31722c6ae69SDarkWyrm 
31822c6ae69SDarkWyrm 		work = tint_color(base, B_LIGHTEN_MAX_TINT);
31922c6ae69SDarkWyrm 		AddLine(r.LeftTop(), r.RightTop(), work);
32022c6ae69SDarkWyrm 		AddLine(r.LeftTop(), r.LeftBottom(), work);
32122c6ae69SDarkWyrm 		r.left++;
32222c6ae69SDarkWyrm 
32322c6ae69SDarkWyrm 		work = tint_color(base, B_DARKEN_3_TINT);
32422c6ae69SDarkWyrm 		AddLine(r.RightTop(), r.RightBottom(), work);
32522c6ae69SDarkWyrm 		AddLine(r.LeftBottom(), r.RightBottom(), work);
32622c6ae69SDarkWyrm 
32722c6ae69SDarkWyrm 		// this rect handled by the above StrokeRect, so inset a total of 2 pixels
32822c6ae69SDarkWyrm 		r.left++;
32922c6ae69SDarkWyrm 		r.right -= 2;
33022c6ae69SDarkWyrm 		r.top += 2;
33122c6ae69SDarkWyrm 		r.bottom -= 2;
33222c6ae69SDarkWyrm 
33322c6ae69SDarkWyrm 
33422c6ae69SDarkWyrm 		work = tint_color(base, B_DARKEN_3_TINT);
33522c6ae69SDarkWyrm 		AddLine(r.LeftTop(), r.RightTop(), work);
33622c6ae69SDarkWyrm 		AddLine(r.LeftTop(), r.LeftBottom(), work);
33722c6ae69SDarkWyrm 		r.left++;
33822c6ae69SDarkWyrm 
33922c6ae69SDarkWyrm 		work = tint_color(base, B_LIGHTEN_MAX_TINT);
34022c6ae69SDarkWyrm 		AddLine(r.RightTop(), r.RightBottom(), work);
34122c6ae69SDarkWyrm 		AddLine(r.LeftBottom(), r.RightBottom(), work);
34222c6ae69SDarkWyrm 
34322c6ae69SDarkWyrm 		r.right--;
34422c6ae69SDarkWyrm 		r.top++;
34522c6ae69SDarkWyrm 		r.bottom--;
34622c6ae69SDarkWyrm 		EndLineArray();
34722c6ae69SDarkWyrm 
34822c6ae69SDarkWyrm 		SetHighColor(tint_color(base, B_DARKEN_2_TINT));
34922c6ae69SDarkWyrm 		StrokeRect(r);
35009a03cb8SDarkWyrm 	} else {
35122c6ae69SDarkWyrm 		// Plain border
35222c6ae69SDarkWyrm 		SetHighColor(0, 0, 0);
35322c6ae69SDarkWyrm 		StrokeRect(fBitmapRect);
35422c6ae69SDarkWyrm 	}
35522c6ae69SDarkWyrm }
35622c6ae69SDarkWyrm 
35709a03cb8SDarkWyrm 
35809a03cb8SDarkWyrm void
MouseDown(BPoint pt)35909a03cb8SDarkWyrm BitmapView::MouseDown(BPoint pt)
36022c6ae69SDarkWyrm {
36122c6ae69SDarkWyrm 	BPoint mousept;
36222c6ae69SDarkWyrm 	uint32 buttons;
36322c6ae69SDarkWyrm 
36422c6ae69SDarkWyrm 	GetMouse(&mousept, &buttons);
36509a03cb8SDarkWyrm 	if (buttons & B_SECONDARY_MOUSE_BUTTON) {
36622c6ae69SDarkWyrm 		ConvertToScreen(&mousept);
36722c6ae69SDarkWyrm 
36822c6ae69SDarkWyrm 		mousept.x= (mousept.x>5) ? mousept.x-5 : 0;
36922c6ae69SDarkWyrm 		mousept.y= (mousept.y>5) ? mousept.y-5 : 0;
37022c6ae69SDarkWyrm 
37122c6ae69SDarkWyrm 		if (AcceptsPaste() && ClipboardHasBitmap())
37222c6ae69SDarkWyrm 			fPasteItem->SetEnabled(true);
37322c6ae69SDarkWyrm 		else
37422c6ae69SDarkWyrm 			fPasteItem->SetEnabled(false);
37522c6ae69SDarkWyrm 
37622c6ae69SDarkWyrm 		if (fRemovableBitmap && fBitmap)
37722c6ae69SDarkWyrm 			fRemoveItem->SetEnabled(true);
37822c6ae69SDarkWyrm 		else
37922c6ae69SDarkWyrm 			fRemoveItem->SetEnabled(false);
38022c6ae69SDarkWyrm 
38122c6ae69SDarkWyrm 		fPopUpMenu->Go(mousept, true, true, true);
38222c6ae69SDarkWyrm 	}
38322c6ae69SDarkWyrm }
38422c6ae69SDarkWyrm 
38509a03cb8SDarkWyrm 
38609a03cb8SDarkWyrm void
FrameResized(float w,float h)38709a03cb8SDarkWyrm BitmapView::FrameResized(float w, float h)
38822c6ae69SDarkWyrm {
38922c6ae69SDarkWyrm 	CalculateBitmapRect();
39022c6ae69SDarkWyrm }
39122c6ae69SDarkWyrm 
39209a03cb8SDarkWyrm 
39309a03cb8SDarkWyrm void
CalculateBitmapRect(void)39409a03cb8SDarkWyrm BitmapView::CalculateBitmapRect(void)
39522c6ae69SDarkWyrm {
39609a03cb8SDarkWyrm 	if (!fBitmap || fFixedSize) {
39722c6ae69SDarkWyrm 		fBitmapRect = Bounds().InsetByCopy(1, 1);
39822c6ae69SDarkWyrm 		return;
39922c6ae69SDarkWyrm 	}
40022c6ae69SDarkWyrm 
40122c6ae69SDarkWyrm 	uint8 borderwidth = (fBorderStyle == B_FANCY_BORDER) ? 5 : 1;
40222c6ae69SDarkWyrm 
40322c6ae69SDarkWyrm 	BRect r(Bounds());
40422c6ae69SDarkWyrm 	fBitmapRect= ScaleRectToFit(fBitmap->Bounds(), r.InsetByCopy(borderwidth, borderwidth));
40522c6ae69SDarkWyrm }
40622c6ae69SDarkWyrm 
40709a03cb8SDarkWyrm 
40809a03cb8SDarkWyrm void
SetAcceptDrops(bool accept)40909a03cb8SDarkWyrm BitmapView::SetAcceptDrops(bool accept)
41022c6ae69SDarkWyrm {
41122c6ae69SDarkWyrm 	fAcceptDrops = accept;
41222c6ae69SDarkWyrm }
41322c6ae69SDarkWyrm 
41409a03cb8SDarkWyrm 
41509a03cb8SDarkWyrm void
SetAcceptPaste(bool accept)41609a03cb8SDarkWyrm BitmapView::SetAcceptPaste(bool accept)
41722c6ae69SDarkWyrm {
41822c6ae69SDarkWyrm 	fAcceptPaste = accept;
41922c6ae69SDarkWyrm }
42022c6ae69SDarkWyrm 
42109a03cb8SDarkWyrm 
42209a03cb8SDarkWyrm void
SetConstrainDrops(bool value)42309a03cb8SDarkWyrm BitmapView::SetConstrainDrops(bool value)
42422c6ae69SDarkWyrm {
42522c6ae69SDarkWyrm 	fConstrainDrops = value;
42622c6ae69SDarkWyrm }
42722c6ae69SDarkWyrm 
42809a03cb8SDarkWyrm 
42909a03cb8SDarkWyrm void
MaxBitmapSize(float * width,float * height) const43009a03cb8SDarkWyrm BitmapView::MaxBitmapSize(float *width, float *height) const
43122c6ae69SDarkWyrm {
43222c6ae69SDarkWyrm 	*width = fMaxWidth;
43322c6ae69SDarkWyrm 	*height = fMaxHeight;
43422c6ae69SDarkWyrm }
43522c6ae69SDarkWyrm 
43609a03cb8SDarkWyrm 
43709a03cb8SDarkWyrm void
SetMaxBitmapSize(const float & width,const float & height)43809a03cb8SDarkWyrm BitmapView::SetMaxBitmapSize(const float &width, const float &height)
43922c6ae69SDarkWyrm {
44022c6ae69SDarkWyrm 	fMaxWidth = width;
44122c6ae69SDarkWyrm 	fMaxHeight = height;
44222c6ae69SDarkWyrm 
44322c6ae69SDarkWyrm 	ConstrainBitmap();
44422c6ae69SDarkWyrm }
44522c6ae69SDarkWyrm 
44609a03cb8SDarkWyrm 
44709a03cb8SDarkWyrm void
SetBitmapRemovable(bool isremovable)44809a03cb8SDarkWyrm BitmapView::SetBitmapRemovable(bool isremovable)
44922c6ae69SDarkWyrm {
45022c6ae69SDarkWyrm 	fRemovableBitmap = isremovable;
45122c6ae69SDarkWyrm }
45222c6ae69SDarkWyrm 
45309a03cb8SDarkWyrm 
45409a03cb8SDarkWyrm void
ConstrainBitmap(void)45509a03cb8SDarkWyrm BitmapView::ConstrainBitmap(void)
45622c6ae69SDarkWyrm {
45722c6ae69SDarkWyrm 	if (!fBitmap || fMaxWidth < 1 || fMaxHeight < 1)
45822c6ae69SDarkWyrm 		return;
45922c6ae69SDarkWyrm 
46022c6ae69SDarkWyrm 	BRect r = ScaleRectToFit(fBitmap->Bounds(), BRect(0, 0, fMaxWidth - 1, fMaxHeight - 1));
46122c6ae69SDarkWyrm 	r.OffsetTo(0, 0);
46222c6ae69SDarkWyrm 
46322c6ae69SDarkWyrm 	BBitmap *scaled = new BBitmap(r, fBitmap->ColorSpace(), true);
46422c6ae69SDarkWyrm 	BView *view = new BView(r, "drawview", 0, 0);
46522c6ae69SDarkWyrm 
46622c6ae69SDarkWyrm 	scaled->Lock();
46722c6ae69SDarkWyrm 	scaled->AddChild(view);
46822c6ae69SDarkWyrm 	view->DrawBitmap(fBitmap, fBitmap->Bounds(), scaled->Bounds());
46922c6ae69SDarkWyrm 	scaled->Unlock();
47022c6ae69SDarkWyrm 
47122c6ae69SDarkWyrm 	delete fBitmap;
47222c6ae69SDarkWyrm 	fBitmap = new BBitmap(scaled, false);
47322c6ae69SDarkWyrm }
47422c6ae69SDarkWyrm 
47509a03cb8SDarkWyrm 
47609a03cb8SDarkWyrm bool
ClipboardHasBitmap(void)47709a03cb8SDarkWyrm BitmapView::ClipboardHasBitmap(void)
47822c6ae69SDarkWyrm {
47922c6ae69SDarkWyrm 	BMessage *clip = NULL, flattened;
48022c6ae69SDarkWyrm 	uint8 clipval = CLIP_NONE;
48122c6ae69SDarkWyrm 	bool returnval;
48222c6ae69SDarkWyrm 
48309a03cb8SDarkWyrm 	if (be_clipboard->Lock()) {
48422c6ae69SDarkWyrm 		clip = be_clipboard->Data();
48509a03cb8SDarkWyrm 		if (!clip->IsEmpty()) {
48622c6ae69SDarkWyrm 			returnval = (clip->FindMessage("image/bitmap", &flattened) == B_OK);
48722c6ae69SDarkWyrm 			if (returnval)
48822c6ae69SDarkWyrm 				clipval = CLIP_BEOS;
48909a03cb8SDarkWyrm 			else {
49022c6ae69SDarkWyrm 				BString string;
49122c6ae69SDarkWyrm 				returnval = (clip->FindString("class", &string) == B_OK && string == "BBitmap");
49222c6ae69SDarkWyrm 
49322c6ae69SDarkWyrm 				// Try method Gobe Productive uses if that, too, didn't work
49422c6ae69SDarkWyrm 				if (returnval)
49522c6ae69SDarkWyrm 					clipval = CLIP_SHOWIMAGE;
49609a03cb8SDarkWyrm 				else {
49722c6ae69SDarkWyrm 					returnval = (clip->FindMessage("image/x-vnd.Be-bitmap", &flattened) == B_OK);
49822c6ae69SDarkWyrm 					if (returnval)
49922c6ae69SDarkWyrm 						clipval = CLIP_SHOWIMAGE;
50022c6ae69SDarkWyrm 					else
50122c6ae69SDarkWyrm 						clipval = CLIP_NONE;
50222c6ae69SDarkWyrm 				}
50322c6ae69SDarkWyrm 			}
50422c6ae69SDarkWyrm 		}
50522c6ae69SDarkWyrm 		be_clipboard->Unlock();
50622c6ae69SDarkWyrm 	}
50722c6ae69SDarkWyrm 	return (clipval != CLIP_NONE)?true:false;
50822c6ae69SDarkWyrm }
50922c6ae69SDarkWyrm 
51009a03cb8SDarkWyrm 
51109a03cb8SDarkWyrm BBitmap *
BitmapFromClipboard(void)51209a03cb8SDarkWyrm BitmapView::BitmapFromClipboard(void)
51322c6ae69SDarkWyrm {
51422c6ae69SDarkWyrm 	BMessage *clip = NULL, flattened;
51522c6ae69SDarkWyrm 	BBitmap *bitmap;
51622c6ae69SDarkWyrm 
51722c6ae69SDarkWyrm 	if (!be_clipboard->Lock())
51822c6ae69SDarkWyrm 		return NULL;
51922c6ae69SDarkWyrm 
52022c6ae69SDarkWyrm 	clip = be_clipboard->Data();
52122c6ae69SDarkWyrm 	if (!clip)
52222c6ae69SDarkWyrm 		return NULL;
52322c6ae69SDarkWyrm 
52422c6ae69SDarkWyrm 	uint8 clipval = CLIP_NONE;
52522c6ae69SDarkWyrm 
52622c6ae69SDarkWyrm 	// Try ArtPaint-style storage
52722c6ae69SDarkWyrm 	status_t status = clip->FindMessage("image/bitmap", &flattened);
52822c6ae69SDarkWyrm 
52922c6ae69SDarkWyrm 	// If that didn't work, try ShowImage-style
53009a03cb8SDarkWyrm 	if (status != B_OK) {
53122c6ae69SDarkWyrm 		BString string;
53222c6ae69SDarkWyrm 		status = clip->FindString("class", &string);
53322c6ae69SDarkWyrm 
53422c6ae69SDarkWyrm 		// Try method Gobe Productive uses if that, too, didn't work
53522c6ae69SDarkWyrm 		if (status == B_OK && string == "BBitmap")
53622c6ae69SDarkWyrm 			clipval = CLIP_SHOWIMAGE;
53709a03cb8SDarkWyrm 		else {
53822c6ae69SDarkWyrm 			status = clip->FindMessage("image/x-vnd.Be-bitmap", &flattened);
53922c6ae69SDarkWyrm 			if (status == B_OK)
54022c6ae69SDarkWyrm 				clipval = CLIP_PRODUCTIVE;
54122c6ae69SDarkWyrm 			else
54222c6ae69SDarkWyrm 				clipval = CLIP_NONE;
54322c6ae69SDarkWyrm 		}
54422c6ae69SDarkWyrm 	}
54522c6ae69SDarkWyrm 	else
54622c6ae69SDarkWyrm 		clipval = CLIP_BEOS;
54722c6ae69SDarkWyrm 
54822c6ae69SDarkWyrm 	be_clipboard->Unlock();
54922c6ae69SDarkWyrm 
55009a03cb8SDarkWyrm 	switch (clipval) {
55109a03cb8SDarkWyrm 		case CLIP_SHOWIMAGE: {
55222c6ae69SDarkWyrm 			// Showimage does it a slightly different way -- it dumps the BBitmap
55322c6ae69SDarkWyrm 			// data directly to the clipboard message instead of packaging it in
55422c6ae69SDarkWyrm 			// a bitmap like everyone else.
55522c6ae69SDarkWyrm 
55622c6ae69SDarkWyrm 			if (!be_clipboard->Lock())
55722c6ae69SDarkWyrm 				return NULL;
55822c6ae69SDarkWyrm 
55922c6ae69SDarkWyrm 			BMessage datamsg(*be_clipboard->Data());
56022c6ae69SDarkWyrm 
56122c6ae69SDarkWyrm 			be_clipboard->Unlock();
56222c6ae69SDarkWyrm 
56322c6ae69SDarkWyrm 			const void *buffer;
56474349b4fSAlexander von Gluck IV 			ssize_t bufferLength;
56522c6ae69SDarkWyrm 
56622c6ae69SDarkWyrm 			BRect frame;
56722c6ae69SDarkWyrm 			color_space cspace = B_NO_COLOR_SPACE;
56822c6ae69SDarkWyrm 
56922c6ae69SDarkWyrm 			status = datamsg.FindRect("_frame", &frame);
57022c6ae69SDarkWyrm 			if (status != B_OK)
57122c6ae69SDarkWyrm 				return NULL;
57222c6ae69SDarkWyrm 
57322c6ae69SDarkWyrm 			status = datamsg.FindInt32("_cspace", (int32)cspace);
57422c6ae69SDarkWyrm 			if (status != B_OK)
57522c6ae69SDarkWyrm 				return NULL;
57622c6ae69SDarkWyrm 			cspace = B_RGBA32;
57722c6ae69SDarkWyrm 			bitmap = new BBitmap(frame, cspace, true);
57822c6ae69SDarkWyrm 
57922c6ae69SDarkWyrm 			status = datamsg.FindData("_data", B_RAW_TYPE, (const void **)&buffer, &bufferLength);
58009a03cb8SDarkWyrm 			if (status != B_OK) {
58122c6ae69SDarkWyrm 				delete bitmap;
58222c6ae69SDarkWyrm 				return NULL;
58322c6ae69SDarkWyrm 			}
58422c6ae69SDarkWyrm 
58522c6ae69SDarkWyrm 			memcpy(bitmap->Bits(), buffer, bufferLength);
58622c6ae69SDarkWyrm 			return bitmap;
58722c6ae69SDarkWyrm 		}
58822c6ae69SDarkWyrm 		case CLIP_PRODUCTIVE:
58922c6ae69SDarkWyrm 		// Productive doesn't name the packaged BBitmap data message the same, but
59022c6ae69SDarkWyrm 		// uses exactly the same data format.
59122c6ae69SDarkWyrm 
59209a03cb8SDarkWyrm 		case CLIP_BEOS: {
59322c6ae69SDarkWyrm 			const void *buffer;
59474349b4fSAlexander von Gluck IV 			ssize_t bufferLength;
59522c6ae69SDarkWyrm 
59622c6ae69SDarkWyrm 			BRect frame;
59722c6ae69SDarkWyrm 			color_space cspace = B_NO_COLOR_SPACE;
59822c6ae69SDarkWyrm 
59922c6ae69SDarkWyrm 			status = flattened.FindRect("_frame", &frame);
60022c6ae69SDarkWyrm 			if (status != B_OK)
60122c6ae69SDarkWyrm 				return NULL;
60222c6ae69SDarkWyrm 
60322c6ae69SDarkWyrm 			status = flattened.FindInt32("_cspace", (int32)cspace);
60422c6ae69SDarkWyrm 			if (status != B_OK)
60522c6ae69SDarkWyrm 				return NULL;
60622c6ae69SDarkWyrm 			cspace = B_RGBA32;
60722c6ae69SDarkWyrm 			bitmap = new BBitmap(frame, cspace, true);
60822c6ae69SDarkWyrm 
60922c6ae69SDarkWyrm 			status = flattened.FindData("_data", B_RAW_TYPE, (const void **)&buffer, &bufferLength);
61009a03cb8SDarkWyrm 			if (status != B_OK) {
61122c6ae69SDarkWyrm 				delete bitmap;
61222c6ae69SDarkWyrm 				return NULL;
61322c6ae69SDarkWyrm 			}
61422c6ae69SDarkWyrm 
61522c6ae69SDarkWyrm 			memcpy(bitmap->Bits(), buffer, bufferLength);
61622c6ae69SDarkWyrm 			return bitmap;
61722c6ae69SDarkWyrm 		}
61822c6ae69SDarkWyrm 		default:
61922c6ae69SDarkWyrm 			return NULL;
62022c6ae69SDarkWyrm 	}
62122c6ae69SDarkWyrm 
62222c6ae69SDarkWyrm 	// shut the compiler up
62322c6ae69SDarkWyrm 	return NULL;
62422c6ae69SDarkWyrm }
62522c6ae69SDarkWyrm 
62609a03cb8SDarkWyrm 
62709a03cb8SDarkWyrm BRect
ScaleRectToFit(const BRect & from,const BRect & to)62809a03cb8SDarkWyrm ScaleRectToFit(const BRect &from, const BRect &to)
62922c6ae69SDarkWyrm {
63022c6ae69SDarkWyrm 	// Dynamic sizing algorithm
63122c6ae69SDarkWyrm 	// 1) Check to see if either dimension is bigger than the view's display area
63222c6ae69SDarkWyrm 	// 2) If smaller along both axes, make bitmap rect centered and return
63322c6ae69SDarkWyrm 	// 3) Check to see if scaling is to be horizontal or vertical on basis of longer axis
63422c6ae69SDarkWyrm 	// 4) Calculate scaling factor
63522c6ae69SDarkWyrm 	// 5) Scale both axes down by scaling factor, accounting for border width
63622c6ae69SDarkWyrm 	// 6) Center the rectangle in the direction of the smaller axis
63722c6ae69SDarkWyrm 
63822c6ae69SDarkWyrm 	if (!to.IsValid())
63922c6ae69SDarkWyrm 		return from;
64022c6ae69SDarkWyrm 	if (!from.IsValid())
64122c6ae69SDarkWyrm 		return to;
64222c6ae69SDarkWyrm 
64322c6ae69SDarkWyrm 	BRect r(to);
64422c6ae69SDarkWyrm 
64509a03cb8SDarkWyrm 	if ((from.Width() <= r.Width()) && (from.Height() <= r.Height())) {
64622c6ae69SDarkWyrm 		// Smaller than view, so just center and return
64722c6ae69SDarkWyrm 		r = from;
64822c6ae69SDarkWyrm 		r.OffsetBy((to.Width() - r.Width()) / 2, (to.Height() - r.Height()) / 2);
64922c6ae69SDarkWyrm 		return r;
65022c6ae69SDarkWyrm 	}
65122c6ae69SDarkWyrm 
65222c6ae69SDarkWyrm 	float multiplier = from.Width()/from.Height();
65309a03cb8SDarkWyrm 	if (multiplier > 1)	{
65422c6ae69SDarkWyrm 		// Landscape orientation
65522c6ae69SDarkWyrm 
65622c6ae69SDarkWyrm 		// Scale rectangle to bounds width and center height
65722c6ae69SDarkWyrm 		r.bottom = r.top + (r.Width() / multiplier);
65822c6ae69SDarkWyrm 		r.OffsetBy(0, (to.Height() - r.Height()) / 2);
65909a03cb8SDarkWyrm 	} else {
66022c6ae69SDarkWyrm 		// Portrait orientation
66122c6ae69SDarkWyrm 
66222c6ae69SDarkWyrm 		// Scale rectangle to bounds height and center width
66322c6ae69SDarkWyrm 		r.right = r.left + (r.Height() * multiplier);
66422c6ae69SDarkWyrm 		r.OffsetBy((to.Width() - r.Width()) / 2, 0);
66522c6ae69SDarkWyrm 	}
66622c6ae69SDarkWyrm 	return r;
66722c6ae69SDarkWyrm }
66822c6ae69SDarkWyrm 
66909a03cb8SDarkWyrm 
67009a03cb8SDarkWyrm void
RemoveBitmap(void)67109a03cb8SDarkWyrm BitmapView::RemoveBitmap(void)
67222c6ae69SDarkWyrm {
67322c6ae69SDarkWyrm 	SetBitmap(NULL);
67422c6ae69SDarkWyrm }
67522c6ae69SDarkWyrm 
67609a03cb8SDarkWyrm 
67709a03cb8SDarkWyrm void
PasteBitmap(void)67809a03cb8SDarkWyrm BitmapView::PasteBitmap(void)
67922c6ae69SDarkWyrm {
68022c6ae69SDarkWyrm 	BBitmap *bmp = BitmapFromClipboard();
68122c6ae69SDarkWyrm 	if (bmp)
68222c6ae69SDarkWyrm 		SetBitmap(bmp);
68322c6ae69SDarkWyrm 
68422c6ae69SDarkWyrm 	if (fConstrainDrops)
68522c6ae69SDarkWyrm 		ConstrainBitmap();
68622c6ae69SDarkWyrm }
687