xref: /haiku/src/servers/notification/NotificationView.cpp (revision fce034d2ce0ef3aa4e130df594474f2d3d986b13)
1de9dcd41SStephan Aßmus /*
26aa05872SBrian Hill  * Copyright 2010-2017, Haiku, Inc. All Rights Reserved.
3de9dcd41SStephan Aßmus  * Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved.
4de9dcd41SStephan Aßmus  * Copyright 2004-2008, Michael Davidson. All Rights Reserved.
5de9dcd41SStephan Aßmus  * Copyright 2004-2007, Mikael Eiman. All Rights Reserved.
6de9dcd41SStephan Aßmus  * Distributed under the terms of the MIT License.
7de9dcd41SStephan Aßmus  *
8de9dcd41SStephan Aßmus  * Authors:
9de9dcd41SStephan Aßmus  *		Michael Davidson, slaad@bong.com.au
10de9dcd41SStephan Aßmus  *		Mikael Eiman, mikael@eiman.tv
11de9dcd41SStephan Aßmus  *		Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
12f33637d9SStephan Aßmus  *		Stephan Aßmus <superstippi@gmx.de>
13f2fc3a86SAdrien Destugues  *		Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
146aa05872SBrian Hill  *		Brian Hill, supernova@tycho.email
15de9dcd41SStephan Aßmus  */
16de9dcd41SStephan Aßmus 
17259ffc02SAlex Wilson 
18259ffc02SAlex Wilson #include "NotificationView.h"
19259ffc02SAlex Wilson 
20259ffc02SAlex Wilson 
21259ffc02SAlex Wilson #include <Bitmap.h>
2282a67460SAdrien Destugues - PulkoMandy #include <ControlLook.h>
23e0890a26SAdrien Destugues #include <GroupLayout.h>
244ec6c3a0SAdrien Destugues #include <LayoutUtils.h>
25259ffc02SAlex Wilson #include <MessageRunner.h>
26de9dcd41SStephan Aßmus #include <Messenger.h>
27259ffc02SAlex Wilson #include <Notification.h>
28*fce034d2SEmir SARI #include <NumberFormat.h>
294ec6c3a0SAdrien Destugues #include <Path.h>
30259ffc02SAlex Wilson #include <PropertyInfo.h>
31de9dcd41SStephan Aßmus #include <Roster.h>
32beeda306SAdrien Destugues #include <StatusBar.h>
33de9dcd41SStephan Aßmus 
342a740449SFrançois Revol #include <Notifications.h>
352a740449SFrançois Revol 
36f6afd3e9SRyan Leavengood #include "AppGroupView.h"
37de9dcd41SStephan Aßmus #include "NotificationWindow.h"
38de9dcd41SStephan Aßmus 
39259ffc02SAlex Wilson 
406aa05872SBrian Hill const int kIconStripeWidth			= 32;
416aa05872SBrian Hill const float kCloseSize				= 6;
426aa05872SBrian Hill const float kEdgePadding			= 2;
436aa05872SBrian Hill const float kSmallPadding			= 2;
449dcd41a8SAdrien Destugues 
45de9dcd41SStephan Aßmus property_info message_prop_list[] = {
46de9dcd41SStephan Aßmus 	{ "type", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
47de9dcd41SStephan Aßmus 		{B_DIRECT_SPECIFIER, 0}, "get the notification type"},
48de9dcd41SStephan Aßmus 	{ "app", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
49de9dcd41SStephan Aßmus 		{B_DIRECT_SPECIFIER, 0}, "get notification's app"},
50de9dcd41SStephan Aßmus 	{ "title", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
51de9dcd41SStephan Aßmus 		{B_DIRECT_SPECIFIER, 0}, "get notification's title"},
52de9dcd41SStephan Aßmus 	{ "content", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
53de9dcd41SStephan Aßmus 		{B_DIRECT_SPECIFIER, 0}, "get notification's contents"},
54de9dcd41SStephan Aßmus 	{ "icon", {B_GET_PROPERTY, 0},
55de9dcd41SStephan Aßmus 		{B_DIRECT_SPECIFIER, 0}, "get icon as an archived bitmap"},
56de9dcd41SStephan Aßmus 	{ "progress", {B_GET_PROPERTY, B_SET_PROPERTY, 0},
57de9dcd41SStephan Aßmus 		{B_DIRECT_SPECIFIER, 0}, "get the progress (between 0.0 and 1.0)"},
5816af9b4cSHumdinger 
5916af9b4cSHumdinger 	{ 0 }
60de9dcd41SStephan Aßmus };
61de9dcd41SStephan Aßmus 
62de9dcd41SStephan Aßmus 
NotificationView(BNotification * notification,bigtime_t timeout,float iconSize,bool disableTimeout)636aa05872SBrian Hill NotificationView::NotificationView(BNotification* notification, bigtime_t timeout,
646aa05872SBrian Hill 	float iconSize, bool disableTimeout)
65de9dcd41SStephan Aßmus 	:
6644c6e69bSAdrien Destugues 	BView("NotificationView", B_WILL_DRAW),
674ec6c3a0SAdrien Destugues 	fNotification(notification),
684ec6c3a0SAdrien Destugues 	fTimeout(timeout),
696aa05872SBrian Hill 	fIconSize(iconSize),
706aa05872SBrian Hill 	fDisableTimeout(disableTimeout),
71de9dcd41SStephan Aßmus 	fRunner(NULL),
7282a67460SAdrien Destugues - PulkoMandy 	fBitmap(NULL),
736aa05872SBrian Hill 	fCloseClicked(false),
746aa05872SBrian Hill 	fPreviewModeOn(false)
75de9dcd41SStephan Aßmus {
764ec6c3a0SAdrien Destugues 	if (fNotification->Icon() != NULL)
774ec6c3a0SAdrien Destugues 		fBitmap = new BBitmap(fNotification->Icon());
78de9dcd41SStephan Aßmus 
79e0890a26SAdrien Destugues 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL);
80e0890a26SAdrien Destugues 	SetLayout(layout);
81e0890a26SAdrien Destugues 
821a8c00c1Slooncraz 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
8348d90a50SAdrien Destugues 	SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
8448d90a50SAdrien Destugues 
854ec6c3a0SAdrien Destugues 	switch (fNotification->Type()) {
86de9dcd41SStephan Aßmus 		case B_IMPORTANT_NOTIFICATION:
8748d90a50SAdrien Destugues 			fStripeColor = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
88de9dcd41SStephan Aßmus 			break;
89de9dcd41SStephan Aßmus 		case B_ERROR_NOTIFICATION:
9048d90a50SAdrien Destugues 			fStripeColor = ui_color(B_FAILURE_COLOR);
91de9dcd41SStephan Aßmus 			break;
92beeda306SAdrien Destugues 		case B_PROGRESS_NOTIFICATION:
93beeda306SAdrien Destugues 		{
94e0890a26SAdrien Destugues 			BStatusBar* progress = new BStatusBar("progress");
95beeda306SAdrien Destugues 			progress->SetBarHeight(12.0f);
96beeda306SAdrien Destugues 			progress->SetMaxValue(1.0f);
974ec6c3a0SAdrien Destugues 			progress->Update(fNotification->Progress());
98beeda306SAdrien Destugues 
99*fce034d2SEmir SARI 			BNumberFormat numberFormat;
100*fce034d2SEmir SARI 			BString label;
101*fce034d2SEmir SARI 			double progressPercent = fNotification->Progress();
102beeda306SAdrien Destugues 
103*fce034d2SEmir SARI 			if (numberFormat.FormatPercent(label, progressPercent) != B_OK)
104*fce034d2SEmir SARI 				label.SetToFormat("%d%%", (int)(progressPercent * 100));
105*fce034d2SEmir SARI 
106*fce034d2SEmir SARI 			progress->SetTrailingText(label.String());
10744c6e69bSAdrien Destugues 			layout->AddView(progress);
108beeda306SAdrien Destugues 		}
10948d90a50SAdrien Destugues 		// fall through.
11048d90a50SAdrien Destugues 		case B_INFORMATION_NOTIFICATION:
11148d90a50SAdrien Destugues 			fStripeColor = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
11248d90a50SAdrien Destugues 				B_DARKEN_1_TINT);
11348d90a50SAdrien Destugues 			break;
114de9dcd41SStephan Aßmus 	}
115de9dcd41SStephan Aßmus }
116de9dcd41SStephan Aßmus 
117de9dcd41SStephan Aßmus 
~NotificationView()118de9dcd41SStephan Aßmus NotificationView::~NotificationView()
119de9dcd41SStephan Aßmus {
120de9dcd41SStephan Aßmus 	delete fRunner;
121de9dcd41SStephan Aßmus 	delete fBitmap;
1224ec6c3a0SAdrien Destugues 	delete fNotification;
123de9dcd41SStephan Aßmus 
124de9dcd41SStephan Aßmus 	LineInfoList::iterator lIt;
125de9dcd41SStephan Aßmus 	for (lIt = fLines.begin(); lIt != fLines.end(); lIt++)
126de9dcd41SStephan Aßmus 		delete (*lIt);
127de9dcd41SStephan Aßmus }
128de9dcd41SStephan Aßmus 
129de9dcd41SStephan Aßmus 
130de9dcd41SStephan Aßmus void
AttachedToWindow()131de9dcd41SStephan Aßmus NotificationView::AttachedToWindow()
132de9dcd41SStephan Aßmus {
1332a740449SFrançois Revol 	SetText();
1342a740449SFrançois Revol 
1356aa05872SBrian Hill 	if (!fDisableTimeout) {
136de9dcd41SStephan Aßmus 		BMessage msg(kRemoveView);
137de9dcd41SStephan Aßmus 		msg.AddPointer("view", this);
1384ec6c3a0SAdrien Destugues 		fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1);
139de9dcd41SStephan Aßmus 	}
1406aa05872SBrian Hill }
141de9dcd41SStephan Aßmus 
142de9dcd41SStephan Aßmus 
143de9dcd41SStephan Aßmus void
MessageReceived(BMessage * msg)144de9dcd41SStephan Aßmus NotificationView::MessageReceived(BMessage* msg)
145de9dcd41SStephan Aßmus {
146de9dcd41SStephan Aßmus 	switch (msg->what) {
147de9dcd41SStephan Aßmus 		case B_GET_PROPERTY:
148de9dcd41SStephan Aßmus 		{
149de9dcd41SStephan Aßmus 			BMessage specifier;
150de9dcd41SStephan Aßmus 			const char* property;
151de9dcd41SStephan Aßmus 			BMessage reply(B_REPLY);
152de9dcd41SStephan Aßmus 			bool msgOkay = true;
153de9dcd41SStephan Aßmus 
154de9dcd41SStephan Aßmus 			if (msg->FindMessage("specifiers", 0, &specifier) != B_OK)
155de9dcd41SStephan Aßmus 				msgOkay = false;
156de9dcd41SStephan Aßmus 			if (specifier.FindString("property", &property) != B_OK)
157de9dcd41SStephan Aßmus 				msgOkay = false;
158de9dcd41SStephan Aßmus 
159de9dcd41SStephan Aßmus 			if (msgOkay) {
160de9dcd41SStephan Aßmus 				if (strcmp(property, "type") == 0)
1614ec6c3a0SAdrien Destugues 					reply.AddInt32("result", fNotification->Type());
162de9dcd41SStephan Aßmus 
1634ec6c3a0SAdrien Destugues 				if (strcmp(property, "group") == 0)
1644ec6c3a0SAdrien Destugues 					reply.AddString("result", fNotification->Group());
165de9dcd41SStephan Aßmus 
166de9dcd41SStephan Aßmus 				if (strcmp(property, "title") == 0)
1674ec6c3a0SAdrien Destugues 					reply.AddString("result", fNotification->Title());
168de9dcd41SStephan Aßmus 
169de9dcd41SStephan Aßmus 				if (strcmp(property, "content") == 0)
1704ec6c3a0SAdrien Destugues 					reply.AddString("result", fNotification->Content());
171de9dcd41SStephan Aßmus 
172de9dcd41SStephan Aßmus 				if (strcmp(property, "progress") == 0)
1734ec6c3a0SAdrien Destugues 					reply.AddFloat("result", fNotification->Progress());
174de9dcd41SStephan Aßmus 
175de9dcd41SStephan Aßmus 				if ((strcmp(property, "icon") == 0) && fBitmap) {
176de9dcd41SStephan Aßmus 					BMessage archive;
177de9dcd41SStephan Aßmus 					if (fBitmap->Archive(&archive) == B_OK)
178de9dcd41SStephan Aßmus 						reply.AddMessage("result", &archive);
179de9dcd41SStephan Aßmus 				}
180de9dcd41SStephan Aßmus 
181de9dcd41SStephan Aßmus 				reply.AddInt32("error", B_OK);
182de9dcd41SStephan Aßmus 			} else {
183de9dcd41SStephan Aßmus 				reply.what = B_MESSAGE_NOT_UNDERSTOOD;
184de9dcd41SStephan Aßmus 				reply.AddInt32("error", B_ERROR);
185de9dcd41SStephan Aßmus 			}
186de9dcd41SStephan Aßmus 
187de9dcd41SStephan Aßmus 			msg->SendReply(&reply);
188de9dcd41SStephan Aßmus 			break;
189de9dcd41SStephan Aßmus 		}
190de9dcd41SStephan Aßmus 		case B_SET_PROPERTY:
191de9dcd41SStephan Aßmus 		{
192de9dcd41SStephan Aßmus 			BMessage specifier;
193de9dcd41SStephan Aßmus 			const char* property;
194de9dcd41SStephan Aßmus 			BMessage reply(B_REPLY);
195de9dcd41SStephan Aßmus 			bool msgOkay = true;
196de9dcd41SStephan Aßmus 
197de9dcd41SStephan Aßmus 			if (msg->FindMessage("specifiers", 0, &specifier) != B_OK)
198de9dcd41SStephan Aßmus 				msgOkay = false;
199de9dcd41SStephan Aßmus 			if (specifier.FindString("property", &property) != B_OK)
200de9dcd41SStephan Aßmus 				msgOkay = false;
201de9dcd41SStephan Aßmus 
202de9dcd41SStephan Aßmus 			if (msgOkay) {
2034ec6c3a0SAdrien Destugues 				const char* value = NULL;
2044ec6c3a0SAdrien Destugues 
2054ec6c3a0SAdrien Destugues 				if (strcmp(property, "group") == 0)
2064ec6c3a0SAdrien Destugues 					if (msg->FindString("data", &value) == B_OK)
2074ec6c3a0SAdrien Destugues 						fNotification->SetGroup(value);
208de9dcd41SStephan Aßmus 
209de9dcd41SStephan Aßmus 				if (strcmp(property, "title") == 0)
2104ec6c3a0SAdrien Destugues 					if (msg->FindString("data", &value) == B_OK)
2114ec6c3a0SAdrien Destugues 						fNotification->SetTitle(value);
212de9dcd41SStephan Aßmus 
213de9dcd41SStephan Aßmus 				if (strcmp(property, "content") == 0)
2144ec6c3a0SAdrien Destugues 					if (msg->FindString("data", &value) == B_OK)
2154ec6c3a0SAdrien Destugues 						fNotification->SetContent(value);
216de9dcd41SStephan Aßmus 
217de9dcd41SStephan Aßmus 				if (strcmp(property, "icon") == 0) {
218de9dcd41SStephan Aßmus 					BMessage archive;
219de9dcd41SStephan Aßmus 					if (msg->FindMessage("data", &archive) == B_OK) {
220de9dcd41SStephan Aßmus 						delete fBitmap;
221de9dcd41SStephan Aßmus 						fBitmap = new BBitmap(&archive);
222de9dcd41SStephan Aßmus 					}
223de9dcd41SStephan Aßmus 				}
224de9dcd41SStephan Aßmus 
2254ec6c3a0SAdrien Destugues 				SetText();
226de9dcd41SStephan Aßmus 				Invalidate();
227de9dcd41SStephan Aßmus 
228de9dcd41SStephan Aßmus 				reply.AddInt32("error", B_OK);
229de9dcd41SStephan Aßmus 			} else {
230de9dcd41SStephan Aßmus 				reply.what = B_MESSAGE_NOT_UNDERSTOOD;
231de9dcd41SStephan Aßmus 				reply.AddInt32("error", B_ERROR);
232de9dcd41SStephan Aßmus 			}
233de9dcd41SStephan Aßmus 
234de9dcd41SStephan Aßmus 			msg->SendReply(&reply);
235de9dcd41SStephan Aßmus 			break;
236de9dcd41SStephan Aßmus 		}
237de9dcd41SStephan Aßmus 		default:
238de9dcd41SStephan Aßmus 			BView::MessageReceived(msg);
239de9dcd41SStephan Aßmus 	}
240de9dcd41SStephan Aßmus }
241de9dcd41SStephan Aßmus 
242de9dcd41SStephan Aßmus 
243de9dcd41SStephan Aßmus void
Draw(BRect updateRect)244de9dcd41SStephan Aßmus NotificationView::Draw(BRect updateRect)
245de9dcd41SStephan Aßmus {
246de9dcd41SStephan Aßmus 	BRect progRect;
247de9dcd41SStephan Aßmus 
248de9dcd41SStephan Aßmus 	SetDrawingMode(B_OP_ALPHA);
249de9dcd41SStephan Aßmus 	SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY);
250de9dcd41SStephan Aßmus 
2519dcd41a8SAdrien Destugues 	BRect stripeRect = Bounds();
2520e07be06SAdrien Destugues 	stripeRect.right = kIconStripeWidth;
25369631a6aSAdrien Destugues 	SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
25469631a6aSAdrien Destugues 		B_DARKEN_1_TINT));
25569631a6aSAdrien Destugues 	FillRect(stripeRect);
25669631a6aSAdrien Destugues 
25748d90a50SAdrien Destugues 	SetHighColor(fStripeColor);
25869631a6aSAdrien Destugues 	stripeRect.right = 2;
2599dcd41a8SAdrien Destugues 	FillRect(stripeRect);
2609dcd41a8SAdrien Destugues 
2619dcd41a8SAdrien Destugues 	SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
262de9dcd41SStephan Aßmus 	// Rectangle for icon and overlay icon
263de9dcd41SStephan Aßmus 	BRect iconRect(0, 0, 0, 0);
264de9dcd41SStephan Aßmus 
265de9dcd41SStephan Aßmus 	// Draw icon
266de9dcd41SStephan Aßmus 	if (fBitmap) {
2675414f4dcSAdrien Destugues 		float ix = 18;
2686aa05872SBrian Hill 		float iy = (Bounds().Height() - fIconSize) / 4.0;
2690e07be06SAdrien Destugues 			// Icon is vertically centered in view
270de9dcd41SStephan Aßmus 
271cd6365c7SJérôme Duval 		if (fNotification->Type() == B_PROGRESS_NOTIFICATION) {
272de9dcd41SStephan Aßmus 			// Move icon up by half progress bar height if it's present
2730e07be06SAdrien Destugues 			iy -= (progRect.Height() + kEdgePadding);
2740e07be06SAdrien Destugues 		}
275de9dcd41SStephan Aßmus 
2766aa05872SBrian Hill 		iconRect.Set(ix, iy, ix + fIconSize - 1.0, iy + fIconSize - 1.0);
277bdde2d30SPhilippe Houdoin 		DrawBitmapAsync(fBitmap, fBitmap->Bounds(), iconRect);
278de9dcd41SStephan Aßmus 	}
279de9dcd41SStephan Aßmus 
280de9dcd41SStephan Aßmus 	// Draw content
281de9dcd41SStephan Aßmus 	LineInfoList::iterator lIt;
282de9dcd41SStephan Aßmus 	for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) {
283de9dcd41SStephan Aßmus 		LineInfo *l = (*lIt);
284de9dcd41SStephan Aßmus 
285de9dcd41SStephan Aßmus 		SetFont(&l->font);
28663a4690eSAdrien Destugues 		// Truncate the string. We have already line-wrapped the text but if
28763a4690eSAdrien Destugues 		// there is a very long 'word' we can only truncate it.
2886aa05872SBrian Hill 		BString text(l->text);
2896aa05872SBrian Hill 		TruncateString(&text, B_TRUNCATE_END,
29084e1c7faSAdrien Destugues 			Bounds().Width() - l->location.x);
2916aa05872SBrian Hill 		DrawString(text.String(), text.Length(), l->location);
292de9dcd41SStephan Aßmus 	}
293de9dcd41SStephan Aßmus 
294f6afd3e9SRyan Leavengood 	AppGroupView* groupView = dynamic_cast<AppGroupView*>(Parent());
295f6afd3e9SRyan Leavengood 	if (groupView != NULL && groupView->ChildrenCount() > 1)
29682a67460SAdrien Destugues - PulkoMandy 		_DrawCloseButton(updateRect);
297de9dcd41SStephan Aßmus 
2985414f4dcSAdrien Destugues 	SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT));
29944c6e69bSAdrien Destugues 	BPoint left(Bounds().left, Bounds().top);
30044c6e69bSAdrien Destugues 	BPoint right(Bounds().right, Bounds().top);
3015414f4dcSAdrien Destugues 	StrokeLine(left, right);
3025414f4dcSAdrien Destugues 
303de9dcd41SStephan Aßmus 	Sync();
304de9dcd41SStephan Aßmus }
305de9dcd41SStephan Aßmus 
306de9dcd41SStephan Aßmus 
307de9dcd41SStephan Aßmus void
_DrawCloseButton(const BRect & updateRect)30882a67460SAdrien Destugues - PulkoMandy NotificationView::_DrawCloseButton(const BRect& updateRect)
30982a67460SAdrien Destugues - PulkoMandy {
31082a67460SAdrien Destugues - PulkoMandy 	PushState();
31182a67460SAdrien Destugues - PulkoMandy 	BRect closeRect = Bounds();
31282a67460SAdrien Destugues - PulkoMandy 
31382a67460SAdrien Destugues - PulkoMandy 	closeRect.InsetBy(3 * kEdgePadding, 3 * kEdgePadding);
31482a67460SAdrien Destugues - PulkoMandy 	closeRect.left = closeRect.right - kCloseSize;
31582a67460SAdrien Destugues - PulkoMandy 	closeRect.bottom = closeRect.top + kCloseSize;
31682a67460SAdrien Destugues - PulkoMandy 
31782a67460SAdrien Destugues - PulkoMandy 	rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
31882a67460SAdrien Destugues - PulkoMandy 	float tint = B_DARKEN_2_TINT;
31982a67460SAdrien Destugues - PulkoMandy 
32082a67460SAdrien Destugues - PulkoMandy 	if (fCloseClicked) {
32182a67460SAdrien Destugues - PulkoMandy 		BRect buttonRect(closeRect.InsetByCopy(-4, -4));
32282a67460SAdrien Destugues - PulkoMandy 		be_control_look->DrawButtonFrame(this, buttonRect, updateRect,
32382a67460SAdrien Destugues - PulkoMandy 			base, base,
32482a67460SAdrien Destugues - PulkoMandy 			BControlLook::B_ACTIVATED | BControlLook::B_BLEND_FRAME);
32582a67460SAdrien Destugues - PulkoMandy 		be_control_look->DrawButtonBackground(this, buttonRect, updateRect,
32682a67460SAdrien Destugues - PulkoMandy 			base, BControlLook::B_ACTIVATED);
32782a67460SAdrien Destugues - PulkoMandy 		tint *= 1.2;
32882a67460SAdrien Destugues - PulkoMandy 		closeRect.OffsetBy(1, 1);
32982a67460SAdrien Destugues - PulkoMandy 	}
33082a67460SAdrien Destugues - PulkoMandy 
33182a67460SAdrien Destugues - PulkoMandy 	base = tint_color(base, tint);
33282a67460SAdrien Destugues - PulkoMandy 	SetHighColor(base);
33382a67460SAdrien Destugues - PulkoMandy 	SetPenSize(2);
33482a67460SAdrien Destugues - PulkoMandy 	StrokeLine(closeRect.LeftTop(), closeRect.RightBottom());
33582a67460SAdrien Destugues - PulkoMandy 	StrokeLine(closeRect.LeftBottom(), closeRect.RightTop());
33682a67460SAdrien Destugues - PulkoMandy 	PopState();
33782a67460SAdrien Destugues - PulkoMandy }
33882a67460SAdrien Destugues - PulkoMandy 
33982a67460SAdrien Destugues - PulkoMandy 
34082a67460SAdrien Destugues - PulkoMandy void
MouseDown(BPoint point)341de9dcd41SStephan Aßmus NotificationView::MouseDown(BPoint point)
342de9dcd41SStephan Aßmus {
3436aa05872SBrian Hill 	// Preview Mode ignores any mouse clicks
3446aa05872SBrian Hill 	if (fPreviewModeOn)
3456aa05872SBrian Hill 		return;
3466aa05872SBrian Hill 
347de9dcd41SStephan Aßmus 	int32 buttons;
348de9dcd41SStephan Aßmus 	Window()->CurrentMessage()->FindInt32("buttons", &buttons);
349de9dcd41SStephan Aßmus 
350de9dcd41SStephan Aßmus 	switch (buttons) {
351de9dcd41SStephan Aßmus 		case B_PRIMARY_MOUSE_BUTTON:
352de9dcd41SStephan Aßmus 		{
353de9dcd41SStephan Aßmus 			BRect closeRect = Bounds().InsetByCopy(2,2);
354de9dcd41SStephan Aßmus 			closeRect.left = closeRect.right - kCloseSize;
355de9dcd41SStephan Aßmus 			closeRect.bottom = closeRect.top + kCloseSize;
356de9dcd41SStephan Aßmus 
357de9dcd41SStephan Aßmus 			if (!closeRect.Contains(point)) {
358de9dcd41SStephan Aßmus 				entry_ref launchRef;
359de9dcd41SStephan Aßmus 				BString launchString;
360de9dcd41SStephan Aßmus 				BMessage argMsg(B_ARGV_RECEIVED);
361de9dcd41SStephan Aßmus 				BMessage refMsg(B_REFS_RECEIVED);
362de9dcd41SStephan Aßmus 				entry_ref appRef;
363de9dcd41SStephan Aßmus 				bool useArgv = false;
364de9dcd41SStephan Aßmus 				BList messages;
365de9dcd41SStephan Aßmus 				entry_ref ref;
366de9dcd41SStephan Aßmus 
3674ec6c3a0SAdrien Destugues 				if (fNotification->OnClickApp() != NULL
3684ec6c3a0SAdrien Destugues 					&& be_roster->FindApp(fNotification->OnClickApp(), &appRef)
3694ec6c3a0SAdrien Destugues 				   		== B_OK) {
370de9dcd41SStephan Aßmus 					useArgv = true;
371de9dcd41SStephan Aßmus 				}
372de9dcd41SStephan Aßmus 
3734ec6c3a0SAdrien Destugues 				if (fNotification->OnClickFile() != NULL
3744ec6c3a0SAdrien Destugues 					&& be_roster->FindApp(
3754ec6c3a0SAdrien Destugues 							(entry_ref*)fNotification->OnClickFile(), &appRef)
3764ec6c3a0SAdrien Destugues 				   		== B_OK) {
3774ec6c3a0SAdrien Destugues 					useArgv = true;
3784ec6c3a0SAdrien Destugues 				}
379de9dcd41SStephan Aßmus 
3804ec6c3a0SAdrien Destugues 				for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++)
3814ec6c3a0SAdrien Destugues 					refMsg.AddRef("refs", fNotification->OnClickRefAt(i));
382de9dcd41SStephan Aßmus 				messages.AddItem((void*)&refMsg);
383de9dcd41SStephan Aßmus 
384de9dcd41SStephan Aßmus 				if (useArgv) {
3854ec6c3a0SAdrien Destugues 					int32 argc = fNotification->CountOnClickArgs() + 1;
386de9dcd41SStephan Aßmus 					BString arg;
387de9dcd41SStephan Aßmus 
388de9dcd41SStephan Aßmus 					BPath p(&appRef);
389de9dcd41SStephan Aßmus 					argMsg.AddString("argv", p.Path());
390de9dcd41SStephan Aßmus 
3914ec6c3a0SAdrien Destugues 					argMsg.AddInt32("argc", argc);
392de9dcd41SStephan Aßmus 
3934ec6c3a0SAdrien Destugues 					for (int32 i = 0; i < argc - 1; i++) {
3944ec6c3a0SAdrien Destugues 						argMsg.AddString("argv",
3954ec6c3a0SAdrien Destugues 							fNotification->OnClickArgAt(i));
3964ec6c3a0SAdrien Destugues 					}
397de9dcd41SStephan Aßmus 
398de9dcd41SStephan Aßmus 					messages.AddItem((void*)&argMsg);
399de9dcd41SStephan Aßmus 				}
400de9dcd41SStephan Aßmus 
4014ec6c3a0SAdrien Destugues 				if (fNotification->OnClickApp() != NULL)
4024ec6c3a0SAdrien Destugues 					be_roster->Launch(fNotification->OnClickApp(), &messages);
403de9dcd41SStephan Aßmus 				else
4044ec6c3a0SAdrien Destugues 					be_roster->Launch(fNotification->OnClickFile(), &messages);
40582a67460SAdrien Destugues - PulkoMandy 			} else {
40682a67460SAdrien Destugues - PulkoMandy 				fCloseClicked = true;
407de9dcd41SStephan Aßmus 			}
408de9dcd41SStephan Aßmus 
409de9dcd41SStephan Aßmus 			// Remove the info view after a click
410de9dcd41SStephan Aßmus 			BMessage remove_msg(kRemoveView);
411de9dcd41SStephan Aßmus 			remove_msg.AddPointer("view", this);
412de9dcd41SStephan Aßmus 
413de9dcd41SStephan Aßmus 			BMessenger msgr(Parent());
414de9dcd41SStephan Aßmus 			msgr.SendMessage(&remove_msg);
415de9dcd41SStephan Aßmus 			break;
416de9dcd41SStephan Aßmus 		}
417de9dcd41SStephan Aßmus 	}
418de9dcd41SStephan Aßmus }
419de9dcd41SStephan Aßmus 
420de9dcd41SStephan Aßmus 
421de9dcd41SStephan Aßmus BHandler*
ResolveSpecifier(BMessage * msg,int32 index,BMessage * spec,int32 form,const char * prop)4224ec6c3a0SAdrien Destugues NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec,
4234ec6c3a0SAdrien Destugues 	int32 form, const char* prop)
424de9dcd41SStephan Aßmus {
425de9dcd41SStephan Aßmus 	BPropertyInfo prop_info(message_prop_list);
426de9dcd41SStephan Aßmus 	if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) {
427de9dcd41SStephan Aßmus 		msg->PopSpecifier();
428de9dcd41SStephan Aßmus 		return this;
429de9dcd41SStephan Aßmus 	}
430de9dcd41SStephan Aßmus 
431de9dcd41SStephan Aßmus 	return BView::ResolveSpecifier(msg, index, spec, form, prop);
432de9dcd41SStephan Aßmus }
433de9dcd41SStephan Aßmus 
434de9dcd41SStephan Aßmus 
435de9dcd41SStephan Aßmus status_t
GetSupportedSuites(BMessage * msg)436de9dcd41SStephan Aßmus NotificationView::GetSupportedSuites(BMessage* msg)
437de9dcd41SStephan Aßmus {
438de9dcd41SStephan Aßmus 	msg->AddString("suites", "suite/x-vnd.Haiku-notification_server");
439de9dcd41SStephan Aßmus 	BPropertyInfo prop_info(message_prop_list);
440de9dcd41SStephan Aßmus 	msg->AddFlat("messages", &prop_info);
441de9dcd41SStephan Aßmus 	return BView::GetSupportedSuites(msg);
442de9dcd41SStephan Aßmus }
443de9dcd41SStephan Aßmus 
444de9dcd41SStephan Aßmus 
445de9dcd41SStephan Aßmus void
SetText(float newMaxWidth)4464ec6c3a0SAdrien Destugues NotificationView::SetText(float newMaxWidth)
447de9dcd41SStephan Aßmus {
4482a740449SFrançois Revol 	if (newMaxWidth < 0 && Parent())
4492a740449SFrançois Revol 		newMaxWidth = Parent()->Bounds().IntegerWidth();
4502a740449SFrançois Revol 	if (newMaxWidth <= 0)
4512a740449SFrançois Revol 		newMaxWidth = kDefaultWidth;
452de9dcd41SStephan Aßmus 
453de9dcd41SStephan Aßmus 	// Delete old lines
454de9dcd41SStephan Aßmus 	LineInfoList::iterator lIt;
455de9dcd41SStephan Aßmus 	for (lIt = fLines.begin(); lIt != fLines.end(); lIt++)
456de9dcd41SStephan Aßmus 		delete (*lIt);
457de9dcd41SStephan Aßmus 	fLines.clear();
458de9dcd41SStephan Aßmus 
4590e07be06SAdrien Destugues 	float iconRight = kIconStripeWidth;
460de9dcd41SStephan Aßmus 	if (fBitmap != NULL)
4616aa05872SBrian Hill 		iconRight += fIconSize;
4620e07be06SAdrien Destugues 	else
4635414f4dcSAdrien Destugues 		iconRight += 32;
464de9dcd41SStephan Aßmus 
465de9dcd41SStephan Aßmus 	font_height fh;
466a657e677SBrian Hill 	be_bold_font->GetHeight(&fh);
467de9dcd41SStephan Aßmus 	float fontHeight = ceilf(fh.leading) + ceilf(fh.descent)
468de9dcd41SStephan Aßmus 		+ ceilf(fh.ascent);
4696aa05872SBrian Hill 	float y = fontHeight + kEdgePadding * 2;
470de9dcd41SStephan Aßmus 
471de9dcd41SStephan Aßmus 	// Title
472de9dcd41SStephan Aßmus 	LineInfo* titleLine = new LineInfo;
4734ec6c3a0SAdrien Destugues 	titleLine->text = fNotification->Title();
474a657e677SBrian Hill 	titleLine->font = *be_bold_font;
475de9dcd41SStephan Aßmus 
476569a7bfcSAdrien Destugues 	titleLine->location = BPoint(iconRight + kEdgePadding, y);
477de9dcd41SStephan Aßmus 
478de9dcd41SStephan Aßmus 	fLines.push_front(titleLine);
479de9dcd41SStephan Aßmus 	y += fontHeight;
480de9dcd41SStephan Aßmus 
481de9dcd41SStephan Aßmus 	// Rest of text is rendered with be_plain_font.
482de9dcd41SStephan Aßmus 	be_plain_font->GetHeight(&fh);
483de9dcd41SStephan Aßmus 	fontHeight = ceilf(fh.leading) + ceilf(fh.descent)
484de9dcd41SStephan Aßmus 		+ ceilf(fh.ascent);
485de9dcd41SStephan Aßmus 
486de9dcd41SStephan Aßmus 	// Split text into chunks between certain characters and compose the lines.
487e0890a26SAdrien Destugues 	const char kSeparatorCharacters[] = " \n-\\";
4884ec6c3a0SAdrien Destugues 	BString textBuffer = fNotification->Content();
489de9dcd41SStephan Aßmus 	textBuffer.ReplaceAll("\t", "    ");
490de9dcd41SStephan Aßmus 	const char* chunkStart = textBuffer.String();
491de9dcd41SStephan Aßmus 	float maxWidth = newMaxWidth - kEdgePadding - iconRight;
492de9dcd41SStephan Aßmus 	LineInfo* line = NULL;
493de9dcd41SStephan Aßmus 	ssize_t length = textBuffer.Length();
494de9dcd41SStephan Aßmus 	while (chunkStart - textBuffer.String() < length) {
495de9dcd41SStephan Aßmus 		size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1;
496de9dcd41SStephan Aßmus 
4974ec6c3a0SAdrien Destugues 		// Start a new line if we didn't start one before
49831a3c4e8SJérôme Duval 		BString tempText;
49931a3c4e8SJérôme Duval 		if (line != NULL)
50031a3c4e8SJérôme Duval 			tempText.SetTo(line->text);
501de9dcd41SStephan Aßmus 		tempText.Append(chunkStart, chunkLength);
502de9dcd41SStephan Aßmus 
503de9dcd41SStephan Aßmus 		if (line == NULL || chunkStart[0] == '\n'
504de9dcd41SStephan Aßmus 			|| StringWidth(tempText) > maxWidth) {
505de9dcd41SStephan Aßmus 			line = new LineInfo;
506de9dcd41SStephan Aßmus 			line->font = *be_plain_font;
507de9dcd41SStephan Aßmus 			line->location = BPoint(iconRight + kEdgePadding, y);
508de9dcd41SStephan Aßmus 
509de9dcd41SStephan Aßmus 			fLines.push_front(line);
510de9dcd41SStephan Aßmus 			y += fontHeight;
511de9dcd41SStephan Aßmus 
5124ec6c3a0SAdrien Destugues 			// Skip the eventual new-line character at the beginning of this chunk
513de9dcd41SStephan Aßmus 			if (chunkStart[0] == '\n') {
514de9dcd41SStephan Aßmus 				chunkStart++;
515de9dcd41SStephan Aßmus 				chunkLength--;
516de9dcd41SStephan Aßmus 			}
5174ec6c3a0SAdrien Destugues 
5184ec6c3a0SAdrien Destugues 			// Skip more new-line characters and move the line further down
519de9dcd41SStephan Aßmus 			while (chunkStart[0] == '\n') {
520de9dcd41SStephan Aßmus 				chunkStart++;
521de9dcd41SStephan Aßmus 				chunkLength--;
522de9dcd41SStephan Aßmus 				line->location.y += fontHeight;
523de9dcd41SStephan Aßmus 				y += fontHeight;
524de9dcd41SStephan Aßmus 			}
5254ec6c3a0SAdrien Destugues 
5264ec6c3a0SAdrien Destugues 			// Strip space at beginning of a new line
527de9dcd41SStephan Aßmus 			while (chunkStart[0] == ' ') {
528de9dcd41SStephan Aßmus 				chunkLength--;
529de9dcd41SStephan Aßmus 				chunkStart++;
530de9dcd41SStephan Aßmus 			}
531de9dcd41SStephan Aßmus 		}
532de9dcd41SStephan Aßmus 
533de9dcd41SStephan Aßmus 		if (chunkStart[0] == '\0')
534de9dcd41SStephan Aßmus 			break;
535de9dcd41SStephan Aßmus 
536de9dcd41SStephan Aßmus 		// Append the chunk to the current line, which was either a new
5374ec6c3a0SAdrien Destugues 		// line or the one from the previous iteration
538de9dcd41SStephan Aßmus 		line->text.Append(chunkStart, chunkLength);
539de9dcd41SStephan Aßmus 
540de9dcd41SStephan Aßmus 		chunkStart += chunkLength;
541de9dcd41SStephan Aßmus 	}
542de9dcd41SStephan Aßmus 
543de9dcd41SStephan Aßmus 	fHeight = y + (kEdgePadding * 2);
544de9dcd41SStephan Aßmus 
545de9dcd41SStephan Aßmus 	// Make sure icon fits
546de9dcd41SStephan Aßmus 	if (fBitmap != NULL) {
5474ec6c3a0SAdrien Destugues 		float minHeight = fBitmap->Bounds().Height() + 2 * kEdgePadding;
548de9dcd41SStephan Aßmus 
549de9dcd41SStephan Aßmus 		if (fHeight < minHeight)
550de9dcd41SStephan Aßmus 			fHeight = minHeight;
551de9dcd41SStephan Aßmus 	}
552e0890a26SAdrien Destugues 
553e0890a26SAdrien Destugues 	// Make sure the progress bar is below the text, and the window is big
554e0890a26SAdrien Destugues 	// enough.
555e0890a26SAdrien Destugues 	static_cast<BGroupLayout*>(GetLayout())->SetInsets(kIconStripeWidth + 8,
556e0890a26SAdrien Destugues 		fHeight, 8, 8);
55744c6e69bSAdrien Destugues 
55844c6e69bSAdrien Destugues 	_CalculateSize();
559de9dcd41SStephan Aßmus }
560de9dcd41SStephan Aßmus 
561de9dcd41SStephan Aßmus 
5626aa05872SBrian Hill void
SetPreviewModeOn(bool enabled)5636aa05872SBrian Hill NotificationView::SetPreviewModeOn(bool enabled)
5646aa05872SBrian Hill {
5656aa05872SBrian Hill 	fPreviewModeOn = enabled;
5666aa05872SBrian Hill }
5676aa05872SBrian Hill 
5686aa05872SBrian Hill 
569de9dcd41SStephan Aßmus const char*
MessageID() const5704ec6c3a0SAdrien Destugues NotificationView::MessageID() const
571de9dcd41SStephan Aßmus {
5724ec6c3a0SAdrien Destugues 	return fNotification->MessageID();
573de9dcd41SStephan Aßmus }
574de9dcd41SStephan Aßmus 
575de9dcd41SStephan Aßmus 
576c2fbfb1dSAlex Wilson void
_CalculateSize()5774ec6c3a0SAdrien Destugues NotificationView::_CalculateSize()
578de9dcd41SStephan Aßmus {
579c2fbfb1dSAlex Wilson 	float height = fHeight;
5804ec6c3a0SAdrien Destugues 
5814ec6c3a0SAdrien Destugues 	if (fNotification->Type() == B_PROGRESS_NOTIFICATION) {
5824ec6c3a0SAdrien Destugues 		font_height fh;
5834ec6c3a0SAdrien Destugues 		be_plain_font->GetHeight(&fh);
5844ec6c3a0SAdrien Destugues 		float fontHeight = fh.ascent + fh.descent + fh.leading;
585c2fbfb1dSAlex Wilson 		height += 9 + (kSmallPadding * 2) + (kEdgePadding * 1)
58644c6e69bSAdrien Destugues 			+ fontHeight * 2;
587de9dcd41SStephan Aßmus 	}
588de9dcd41SStephan Aßmus 
589c2fbfb1dSAlex Wilson 	SetExplicitMinSize(BSize(0, height));
590c2fbfb1dSAlex Wilson 	SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, height));
591de9dcd41SStephan Aßmus }
592