1de9dcd41SStephan Aßmus /* 2beeda306SAdrien Destugues * Copyright 2010-2011, 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> 14de9dcd41SStephan Aßmus */ 15de9dcd41SStephan Aßmus 165414f4dcSAdrien Destugues #include <ControlLook.h> 17e0890a26SAdrien Destugues #include <GroupLayout.h> 18e0890a26SAdrien Destugues #include <GroupLayoutBuilder.h> 19e0890a26SAdrien Destugues #include <Layout.h> 204ec6c3a0SAdrien Destugues #include <LayoutUtils.h> 21de9dcd41SStephan Aßmus #include <Messenger.h> 224ec6c3a0SAdrien Destugues #include <Path.h> 23de9dcd41SStephan Aßmus #include <Roster.h> 24beeda306SAdrien Destugues #include <StatusBar.h> 25de9dcd41SStephan Aßmus 26de9dcd41SStephan Aßmus #include "NotificationView.h" 27de9dcd41SStephan Aßmus #include "NotificationWindow.h" 28de9dcd41SStephan Aßmus 290e07be06SAdrien Destugues static const int kIconStripeWidth = 32; 309dcd41a8SAdrien Destugues 31de9dcd41SStephan Aßmus property_info message_prop_list[] = { 32de9dcd41SStephan Aßmus { "type", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 33de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the notification type"}, 34de9dcd41SStephan Aßmus { "app", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 35de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's app"}, 36de9dcd41SStephan Aßmus { "title", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 37de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's title"}, 38de9dcd41SStephan Aßmus { "content", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 39de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get notification's contents"}, 40de9dcd41SStephan Aßmus { "icon", {B_GET_PROPERTY, 0}, 41de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get icon as an archived bitmap"}, 42de9dcd41SStephan Aßmus { "progress", {B_GET_PROPERTY, B_SET_PROPERTY, 0}, 43de9dcd41SStephan Aßmus {B_DIRECT_SPECIFIER, 0}, "get the progress (between 0.0 and 1.0)"}, 44de9dcd41SStephan Aßmus { NULL } 45de9dcd41SStephan Aßmus }; 46de9dcd41SStephan Aßmus 47de9dcd41SStephan Aßmus 48de9dcd41SStephan Aßmus NotificationView::NotificationView(NotificationWindow* win, 494ec6c3a0SAdrien Destugues BNotification* notification, bigtime_t timeout) 50de9dcd41SStephan Aßmus : 51*44c6e69bSAdrien Destugues BView("NotificationView", B_WILL_DRAW), 52de9dcd41SStephan Aßmus fParent(win), 534ec6c3a0SAdrien Destugues fNotification(notification), 544ec6c3a0SAdrien Destugues fTimeout(timeout), 55de9dcd41SStephan Aßmus fRunner(NULL), 564ec6c3a0SAdrien Destugues fBitmap(NULL) 57de9dcd41SStephan Aßmus { 584ec6c3a0SAdrien Destugues if (fNotification->Icon() != NULL) 594ec6c3a0SAdrien Destugues fBitmap = new BBitmap(fNotification->Icon()); 60de9dcd41SStephan Aßmus 614ec6c3a0SAdrien Destugues if (fTimeout <= 0) 624ec6c3a0SAdrien Destugues fTimeout = fParent->Timeout() * 1000000; 63de9dcd41SStephan Aßmus 64e0890a26SAdrien Destugues BGroupLayout* layout = new BGroupLayout(B_VERTICAL); 65e0890a26SAdrien Destugues SetLayout(layout); 66e0890a26SAdrien Destugues 674ec6c3a0SAdrien Destugues switch (fNotification->Type()) { 68de9dcd41SStephan Aßmus case B_IMPORTANT_NOTIFICATION: 69de9dcd41SStephan Aßmus SetViewColor(255, 255, 255); 70de9dcd41SStephan Aßmus SetLowColor(255, 255, 255); 71de9dcd41SStephan Aßmus break; 72de9dcd41SStephan Aßmus case B_ERROR_NOTIFICATION: 73de9dcd41SStephan Aßmus SetViewColor(ui_color(B_FAILURE_COLOR)); 74de9dcd41SStephan Aßmus SetLowColor(ui_color(B_FAILURE_COLOR)); 75de9dcd41SStephan Aßmus break; 76beeda306SAdrien Destugues case B_PROGRESS_NOTIFICATION: 77beeda306SAdrien Destugues { 78e0890a26SAdrien Destugues BStatusBar* progress = new BStatusBar("progress"); 79beeda306SAdrien Destugues progress->SetBarHeight(12.0f); 80beeda306SAdrien Destugues progress->SetMaxValue(1.0f); 814ec6c3a0SAdrien Destugues progress->Update(fNotification->Progress()); 82beeda306SAdrien Destugues 83beeda306SAdrien Destugues BString label = ""; 844ec6c3a0SAdrien Destugues label << (int)(fNotification->Progress() * 100) << " %"; 85beeda306SAdrien Destugues progress->SetTrailingText(label); 86beeda306SAdrien Destugues 87*44c6e69bSAdrien Destugues layout->AddView(progress); 88beeda306SAdrien Destugues } 894ec6c3a0SAdrien Destugues // fall through 90de9dcd41SStephan Aßmus default: 91de9dcd41SStephan Aßmus SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 92de9dcd41SStephan Aßmus SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 93de9dcd41SStephan Aßmus } 94*44c6e69bSAdrien Destugues 95*44c6e69bSAdrien Destugues SetText(); 96de9dcd41SStephan Aßmus } 97de9dcd41SStephan Aßmus 98de9dcd41SStephan Aßmus 99de9dcd41SStephan Aßmus NotificationView::~NotificationView() 100de9dcd41SStephan Aßmus { 101de9dcd41SStephan Aßmus delete fRunner; 102de9dcd41SStephan Aßmus delete fBitmap; 1034ec6c3a0SAdrien Destugues delete fNotification; 104de9dcd41SStephan Aßmus 105de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 106de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 107de9dcd41SStephan Aßmus delete (*lIt); 108de9dcd41SStephan Aßmus } 109de9dcd41SStephan Aßmus 110de9dcd41SStephan Aßmus 111de9dcd41SStephan Aßmus void 112de9dcd41SStephan Aßmus NotificationView::AttachedToWindow() 113de9dcd41SStephan Aßmus { 114de9dcd41SStephan Aßmus BMessage msg(kRemoveView); 115de9dcd41SStephan Aßmus msg.AddPointer("view", this); 116de9dcd41SStephan Aßmus 1174ec6c3a0SAdrien Destugues fRunner = new BMessageRunner(BMessenger(Parent()), &msg, fTimeout, 1); 118de9dcd41SStephan Aßmus } 119de9dcd41SStephan Aßmus 120de9dcd41SStephan Aßmus 121de9dcd41SStephan Aßmus void 122de9dcd41SStephan Aßmus NotificationView::MessageReceived(BMessage* msg) 123de9dcd41SStephan Aßmus { 124de9dcd41SStephan Aßmus switch (msg->what) { 125de9dcd41SStephan Aßmus case B_GET_PROPERTY: 126de9dcd41SStephan Aßmus { 127de9dcd41SStephan Aßmus BMessage specifier; 128de9dcd41SStephan Aßmus const char* property; 129de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 130de9dcd41SStephan Aßmus bool msgOkay = true; 131de9dcd41SStephan Aßmus 132de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 133de9dcd41SStephan Aßmus msgOkay = false; 134de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 135de9dcd41SStephan Aßmus msgOkay = false; 136de9dcd41SStephan Aßmus 137de9dcd41SStephan Aßmus if (msgOkay) { 138de9dcd41SStephan Aßmus if (strcmp(property, "type") == 0) 1394ec6c3a0SAdrien Destugues reply.AddInt32("result", fNotification->Type()); 140de9dcd41SStephan Aßmus 1414ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 1424ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Group()); 143de9dcd41SStephan Aßmus 144de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 1454ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Title()); 146de9dcd41SStephan Aßmus 147de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 1484ec6c3a0SAdrien Destugues reply.AddString("result", fNotification->Content()); 149de9dcd41SStephan Aßmus 150de9dcd41SStephan Aßmus if (strcmp(property, "progress") == 0) 1514ec6c3a0SAdrien Destugues reply.AddFloat("result", fNotification->Progress()); 152de9dcd41SStephan Aßmus 153de9dcd41SStephan Aßmus if ((strcmp(property, "icon") == 0) && fBitmap) { 154de9dcd41SStephan Aßmus BMessage archive; 155de9dcd41SStephan Aßmus if (fBitmap->Archive(&archive) == B_OK) 156de9dcd41SStephan Aßmus reply.AddMessage("result", &archive); 157de9dcd41SStephan Aßmus } 158de9dcd41SStephan Aßmus 159de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 160de9dcd41SStephan Aßmus } else { 161de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 162de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 163de9dcd41SStephan Aßmus } 164de9dcd41SStephan Aßmus 165de9dcd41SStephan Aßmus msg->SendReply(&reply); 166de9dcd41SStephan Aßmus break; 167de9dcd41SStephan Aßmus } 168de9dcd41SStephan Aßmus case B_SET_PROPERTY: 169de9dcd41SStephan Aßmus { 170de9dcd41SStephan Aßmus BMessage specifier; 171de9dcd41SStephan Aßmus const char* property; 172de9dcd41SStephan Aßmus BMessage reply(B_REPLY); 173de9dcd41SStephan Aßmus bool msgOkay = true; 174de9dcd41SStephan Aßmus 175de9dcd41SStephan Aßmus if (msg->FindMessage("specifiers", 0, &specifier) != B_OK) 176de9dcd41SStephan Aßmus msgOkay = false; 177de9dcd41SStephan Aßmus if (specifier.FindString("property", &property) != B_OK) 178de9dcd41SStephan Aßmus msgOkay = false; 179de9dcd41SStephan Aßmus 180de9dcd41SStephan Aßmus if (msgOkay) { 1814ec6c3a0SAdrien Destugues const char* value = NULL; 1824ec6c3a0SAdrien Destugues 1834ec6c3a0SAdrien Destugues if (strcmp(property, "group") == 0) 1844ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 1854ec6c3a0SAdrien Destugues fNotification->SetGroup(value); 186de9dcd41SStephan Aßmus 187de9dcd41SStephan Aßmus if (strcmp(property, "title") == 0) 1884ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 1894ec6c3a0SAdrien Destugues fNotification->SetTitle(value); 190de9dcd41SStephan Aßmus 191de9dcd41SStephan Aßmus if (strcmp(property, "content") == 0) 1924ec6c3a0SAdrien Destugues if (msg->FindString("data", &value) == B_OK) 1934ec6c3a0SAdrien Destugues fNotification->SetContent(value); 194de9dcd41SStephan Aßmus 195de9dcd41SStephan Aßmus if (strcmp(property, "icon") == 0) { 196de9dcd41SStephan Aßmus BMessage archive; 197de9dcd41SStephan Aßmus if (msg->FindMessage("data", &archive) == B_OK) { 198de9dcd41SStephan Aßmus delete fBitmap; 199de9dcd41SStephan Aßmus fBitmap = new BBitmap(&archive); 200de9dcd41SStephan Aßmus } 201de9dcd41SStephan Aßmus } 202de9dcd41SStephan Aßmus 2034ec6c3a0SAdrien Destugues SetText(); 204de9dcd41SStephan Aßmus Invalidate(); 205de9dcd41SStephan Aßmus 206de9dcd41SStephan Aßmus reply.AddInt32("error", B_OK); 207de9dcd41SStephan Aßmus } else { 208de9dcd41SStephan Aßmus reply.what = B_MESSAGE_NOT_UNDERSTOOD; 209de9dcd41SStephan Aßmus reply.AddInt32("error", B_ERROR); 210de9dcd41SStephan Aßmus } 211de9dcd41SStephan Aßmus 212de9dcd41SStephan Aßmus msg->SendReply(&reply); 213de9dcd41SStephan Aßmus break; 214de9dcd41SStephan Aßmus } 215de9dcd41SStephan Aßmus default: 216de9dcd41SStephan Aßmus BView::MessageReceived(msg); 217de9dcd41SStephan Aßmus } 218de9dcd41SStephan Aßmus } 219de9dcd41SStephan Aßmus 220de9dcd41SStephan Aßmus 221de9dcd41SStephan Aßmus void 222de9dcd41SStephan Aßmus NotificationView::Draw(BRect updateRect) 223de9dcd41SStephan Aßmus { 224de9dcd41SStephan Aßmus BRect progRect; 225de9dcd41SStephan Aßmus 226de9dcd41SStephan Aßmus SetDrawingMode(B_OP_ALPHA); 227de9dcd41SStephan Aßmus SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); 228de9dcd41SStephan Aßmus 229de9dcd41SStephan Aßmus // Icon size 230de9dcd41SStephan Aßmus float iconSize = (float)fParent->IconSize(); 231de9dcd41SStephan Aßmus 2329dcd41a8SAdrien Destugues BRect stripeRect = Bounds(); 2330e07be06SAdrien Destugues stripeRect.right = kIconStripeWidth; 2349dcd41a8SAdrien Destugues SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 2359dcd41a8SAdrien Destugues FillRect(stripeRect); 2369dcd41a8SAdrien Destugues 2379dcd41a8SAdrien Destugues SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); 238de9dcd41SStephan Aßmus // Rectangle for icon and overlay icon 239de9dcd41SStephan Aßmus BRect iconRect(0, 0, 0, 0); 240de9dcd41SStephan Aßmus 241de9dcd41SStephan Aßmus // Draw icon 242de9dcd41SStephan Aßmus if (fBitmap) { 2435414f4dcSAdrien Destugues float ix = 18; 2445414f4dcSAdrien Destugues float iy = (Bounds().Height() - iconSize) / 4.0; 2450e07be06SAdrien Destugues // Icon is vertically centered in view 246de9dcd41SStephan Aßmus 2474ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) 2480e07be06SAdrien Destugues { 249de9dcd41SStephan Aßmus // Move icon up by half progress bar height if it's present 2500e07be06SAdrien Destugues iy -= (progRect.Height() + kEdgePadding); 2510e07be06SAdrien Destugues } 252de9dcd41SStephan Aßmus 2537dd47a9bSPhilippe Houdoin iconRect.Set(ix, iy, ix + iconSize - 1.0, iy + iconSize - 1.0); 254bdde2d30SPhilippe Houdoin DrawBitmapAsync(fBitmap, fBitmap->Bounds(), iconRect); 255de9dcd41SStephan Aßmus } 256de9dcd41SStephan Aßmus 257de9dcd41SStephan Aßmus // Draw content 258de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 259de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) { 260de9dcd41SStephan Aßmus LineInfo *l = (*lIt); 261de9dcd41SStephan Aßmus 262de9dcd41SStephan Aßmus SetFont(&l->font); 263de9dcd41SStephan Aßmus DrawString(l->text.String(), l->text.Length(), l->location); 264de9dcd41SStephan Aßmus } 265de9dcd41SStephan Aßmus 266de9dcd41SStephan Aßmus rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR); 267de9dcd41SStephan Aßmus detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT); 268de9dcd41SStephan Aßmus 269de9dcd41SStephan Aßmus // Draw the close widget 270de9dcd41SStephan Aßmus BRect closeRect = Bounds(); 2710e07be06SAdrien Destugues closeRect.InsetBy(2 * kEdgePadding, 2 * kEdgePadding); 272de9dcd41SStephan Aßmus closeRect.left = closeRect.right - kCloseSize; 273de9dcd41SStephan Aßmus closeRect.bottom = closeRect.top + kCloseSize; 274de9dcd41SStephan Aßmus 275de9dcd41SStephan Aßmus PushState(); 276de9dcd41SStephan Aßmus SetHighColor(detailCol); 277de9dcd41SStephan Aßmus StrokeRoundRect(closeRect, kSmallPadding, kSmallPadding); 278de9dcd41SStephan Aßmus BRect closeCross = closeRect.InsetByCopy(kSmallPadding, kSmallPadding); 279de9dcd41SStephan Aßmus StrokeLine(closeCross.LeftTop(), closeCross.RightBottom()); 280de9dcd41SStephan Aßmus StrokeLine(closeCross.LeftBottom(), closeCross.RightTop()); 281de9dcd41SStephan Aßmus PopState(); 282de9dcd41SStephan Aßmus 2835414f4dcSAdrien Destugues SetHighColor(tint_color(ViewColor(), B_DARKEN_1_TINT)); 284*44c6e69bSAdrien Destugues BPoint left(Bounds().left, Bounds().top); 285*44c6e69bSAdrien Destugues BPoint right(Bounds().right, Bounds().top); 2865414f4dcSAdrien Destugues StrokeLine(left, right); 2875414f4dcSAdrien Destugues 288de9dcd41SStephan Aßmus Sync(); 289de9dcd41SStephan Aßmus } 290de9dcd41SStephan Aßmus 291de9dcd41SStephan Aßmus 292de9dcd41SStephan Aßmus void 293de9dcd41SStephan Aßmus NotificationView::MouseDown(BPoint point) 294de9dcd41SStephan Aßmus { 295de9dcd41SStephan Aßmus int32 buttons; 296de9dcd41SStephan Aßmus Window()->CurrentMessage()->FindInt32("buttons", &buttons); 297de9dcd41SStephan Aßmus 298de9dcd41SStephan Aßmus switch (buttons) { 299de9dcd41SStephan Aßmus case B_PRIMARY_MOUSE_BUTTON: 300de9dcd41SStephan Aßmus { 301de9dcd41SStephan Aßmus BRect closeRect = Bounds().InsetByCopy(2,2); 302de9dcd41SStephan Aßmus closeRect.left = closeRect.right - kCloseSize; 303de9dcd41SStephan Aßmus closeRect.bottom = closeRect.top + kCloseSize; 304de9dcd41SStephan Aßmus 305de9dcd41SStephan Aßmus if (!closeRect.Contains(point)) { 306de9dcd41SStephan Aßmus entry_ref launchRef; 307de9dcd41SStephan Aßmus BString launchString; 308de9dcd41SStephan Aßmus BMessage argMsg(B_ARGV_RECEIVED); 309de9dcd41SStephan Aßmus BMessage refMsg(B_REFS_RECEIVED); 310de9dcd41SStephan Aßmus entry_ref appRef; 311de9dcd41SStephan Aßmus bool useArgv = false; 312de9dcd41SStephan Aßmus BList messages; 313de9dcd41SStephan Aßmus entry_ref ref; 314de9dcd41SStephan Aßmus 3154ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL 3164ec6c3a0SAdrien Destugues && be_roster->FindApp(fNotification->OnClickApp(), &appRef) 3174ec6c3a0SAdrien Destugues == B_OK) { 318de9dcd41SStephan Aßmus useArgv = true; 319de9dcd41SStephan Aßmus } 320de9dcd41SStephan Aßmus 3214ec6c3a0SAdrien Destugues if (fNotification->OnClickFile() != NULL 3224ec6c3a0SAdrien Destugues && be_roster->FindApp( 3234ec6c3a0SAdrien Destugues (entry_ref*)fNotification->OnClickFile(), &appRef) 3244ec6c3a0SAdrien Destugues == B_OK) { 3254ec6c3a0SAdrien Destugues useArgv = true; 3264ec6c3a0SAdrien Destugues } 327de9dcd41SStephan Aßmus 3284ec6c3a0SAdrien Destugues for (int32 i = 0; i < fNotification->CountOnClickRefs(); i++) 3294ec6c3a0SAdrien Destugues refMsg.AddRef("refs", fNotification->OnClickRefAt(i)); 330de9dcd41SStephan Aßmus messages.AddItem((void*)&refMsg); 331de9dcd41SStephan Aßmus 332de9dcd41SStephan Aßmus if (useArgv) { 3334ec6c3a0SAdrien Destugues int32 argc = fNotification->CountOnClickArgs() + 1; 334de9dcd41SStephan Aßmus BString arg; 335de9dcd41SStephan Aßmus 336de9dcd41SStephan Aßmus BPath p(&appRef); 337de9dcd41SStephan Aßmus argMsg.AddString("argv", p.Path()); 338de9dcd41SStephan Aßmus 3394ec6c3a0SAdrien Destugues argMsg.AddInt32("argc", argc); 340de9dcd41SStephan Aßmus 3414ec6c3a0SAdrien Destugues for (int32 i = 0; i < argc - 1; i++) { 3424ec6c3a0SAdrien Destugues argMsg.AddString("argv", 3434ec6c3a0SAdrien Destugues fNotification->OnClickArgAt(i)); 3444ec6c3a0SAdrien Destugues } 345de9dcd41SStephan Aßmus 346de9dcd41SStephan Aßmus messages.AddItem((void*)&argMsg); 347de9dcd41SStephan Aßmus } 348de9dcd41SStephan Aßmus 3494ec6c3a0SAdrien Destugues if (fNotification->OnClickApp() != NULL) 3504ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickApp(), &messages); 351de9dcd41SStephan Aßmus else 3524ec6c3a0SAdrien Destugues be_roster->Launch(fNotification->OnClickFile(), &messages); 353de9dcd41SStephan Aßmus } 354de9dcd41SStephan Aßmus 355de9dcd41SStephan Aßmus // Remove the info view after a click 356de9dcd41SStephan Aßmus BMessage remove_msg(kRemoveView); 357de9dcd41SStephan Aßmus remove_msg.AddPointer("view", this); 358de9dcd41SStephan Aßmus 359de9dcd41SStephan Aßmus BMessenger msgr(Parent()); 360de9dcd41SStephan Aßmus msgr.SendMessage(&remove_msg); 361de9dcd41SStephan Aßmus break; 362de9dcd41SStephan Aßmus } 363de9dcd41SStephan Aßmus } 364de9dcd41SStephan Aßmus } 365de9dcd41SStephan Aßmus 366de9dcd41SStephan Aßmus 367*44c6e69bSAdrien Destugues /* 3684ec6c3a0SAdrien Destugues BSize 3694ec6c3a0SAdrien Destugues NotificationView::MinSize() 370de9dcd41SStephan Aßmus { 371*44c6e69bSAdrien Destugues // return BLayoutUtils::ComposeSize(ExplicitMinSize(), _CalculateSize()); 372*44c6e69bSAdrien Destugues return _CalculateSize(); 3734ec6c3a0SAdrien Destugues } 3744ec6c3a0SAdrien Destugues 3754ec6c3a0SAdrien Destugues 3764ec6c3a0SAdrien Destugues BSize 3774ec6c3a0SAdrien Destugues NotificationView::MaxSize() 3784ec6c3a0SAdrien Destugues { 379*44c6e69bSAdrien Destugues return _CalculateSize(); 3804ec6c3a0SAdrien Destugues } 3814ec6c3a0SAdrien Destugues 3824ec6c3a0SAdrien Destugues 3834ec6c3a0SAdrien Destugues BSize 3844ec6c3a0SAdrien Destugues NotificationView::PreferredSize() 3854ec6c3a0SAdrien Destugues { 3864ec6c3a0SAdrien Destugues return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), 3874ec6c3a0SAdrien Destugues _CalculateSize()); 388de9dcd41SStephan Aßmus } 389*44c6e69bSAdrien Destugues */ 390de9dcd41SStephan Aßmus 391de9dcd41SStephan Aßmus 392de9dcd41SStephan Aßmus BHandler* 3934ec6c3a0SAdrien Destugues NotificationView::ResolveSpecifier(BMessage* msg, int32 index, BMessage* spec, 3944ec6c3a0SAdrien Destugues int32 form, const char* prop) 395de9dcd41SStephan Aßmus { 396de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 397de9dcd41SStephan Aßmus if (prop_info.FindMatch(msg, index, spec, form, prop) >= 0) { 398de9dcd41SStephan Aßmus msg->PopSpecifier(); 399de9dcd41SStephan Aßmus return this; 400de9dcd41SStephan Aßmus } 401de9dcd41SStephan Aßmus 402de9dcd41SStephan Aßmus return BView::ResolveSpecifier(msg, index, spec, form, prop); 403de9dcd41SStephan Aßmus } 404de9dcd41SStephan Aßmus 405de9dcd41SStephan Aßmus 406de9dcd41SStephan Aßmus status_t 407de9dcd41SStephan Aßmus NotificationView::GetSupportedSuites(BMessage* msg) 408de9dcd41SStephan Aßmus { 409de9dcd41SStephan Aßmus msg->AddString("suites", "suite/x-vnd.Haiku-notification_server"); 410de9dcd41SStephan Aßmus BPropertyInfo prop_info(message_prop_list); 411de9dcd41SStephan Aßmus msg->AddFlat("messages", &prop_info); 412de9dcd41SStephan Aßmus return BView::GetSupportedSuites(msg); 413de9dcd41SStephan Aßmus } 414de9dcd41SStephan Aßmus 415de9dcd41SStephan Aßmus 416de9dcd41SStephan Aßmus void 4174ec6c3a0SAdrien Destugues NotificationView::SetText(float newMaxWidth) 418de9dcd41SStephan Aßmus { 419e0890a26SAdrien Destugues if (newMaxWidth < 0) { 420e0890a26SAdrien Destugues newMaxWidth = 200; 421e0890a26SAdrien Destugues } 422de9dcd41SStephan Aßmus 423de9dcd41SStephan Aßmus // Delete old lines 424de9dcd41SStephan Aßmus LineInfoList::iterator lIt; 425de9dcd41SStephan Aßmus for (lIt = fLines.begin(); lIt != fLines.end(); lIt++) 426de9dcd41SStephan Aßmus delete (*lIt); 427de9dcd41SStephan Aßmus fLines.clear(); 428de9dcd41SStephan Aßmus 4290e07be06SAdrien Destugues float iconRight = kIconStripeWidth; 430de9dcd41SStephan Aßmus if (fBitmap != NULL) 4315414f4dcSAdrien Destugues iconRight += fParent->IconSize(); 4320e07be06SAdrien Destugues else 4335414f4dcSAdrien Destugues iconRight += 32; 434de9dcd41SStephan Aßmus 435de9dcd41SStephan Aßmus font_height fh; 436de9dcd41SStephan Aßmus be_bold_font->GetHeight(&fh); 437de9dcd41SStephan Aßmus float fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 438de9dcd41SStephan Aßmus + ceilf(fh.ascent); 4390e07be06SAdrien Destugues float y = 2 * fontHeight; 440de9dcd41SStephan Aßmus 441de9dcd41SStephan Aßmus // Title 442de9dcd41SStephan Aßmus LineInfo* titleLine = new LineInfo; 4434ec6c3a0SAdrien Destugues titleLine->text = fNotification->Title(); 444de9dcd41SStephan Aßmus titleLine->font = *be_bold_font; 445de9dcd41SStephan Aßmus 446de9dcd41SStephan Aßmus titleLine->location = BPoint(iconRight, y); 447de9dcd41SStephan Aßmus 448de9dcd41SStephan Aßmus fLines.push_front(titleLine); 449de9dcd41SStephan Aßmus y += fontHeight; 450de9dcd41SStephan Aßmus 451de9dcd41SStephan Aßmus // Rest of text is rendered with be_plain_font. 452de9dcd41SStephan Aßmus be_plain_font->GetHeight(&fh); 453de9dcd41SStephan Aßmus fontHeight = ceilf(fh.leading) + ceilf(fh.descent) 454de9dcd41SStephan Aßmus + ceilf(fh.ascent); 455de9dcd41SStephan Aßmus 456de9dcd41SStephan Aßmus // Split text into chunks between certain characters and compose the lines. 457e0890a26SAdrien Destugues const char kSeparatorCharacters[] = " \n-\\"; 4584ec6c3a0SAdrien Destugues BString textBuffer = fNotification->Content(); 459de9dcd41SStephan Aßmus textBuffer.ReplaceAll("\t", " "); 460de9dcd41SStephan Aßmus const char* chunkStart = textBuffer.String(); 461de9dcd41SStephan Aßmus float maxWidth = newMaxWidth - kEdgePadding - iconRight; 462de9dcd41SStephan Aßmus LineInfo* line = NULL; 463de9dcd41SStephan Aßmus ssize_t length = textBuffer.Length(); 464de9dcd41SStephan Aßmus while (chunkStart - textBuffer.String() < length) { 465de9dcd41SStephan Aßmus size_t chunkLength = strcspn(chunkStart, kSeparatorCharacters) + 1; 466de9dcd41SStephan Aßmus 4674ec6c3a0SAdrien Destugues // Start a new line if we didn't start one before 46831a3c4e8SJérôme Duval BString tempText; 46931a3c4e8SJérôme Duval if (line != NULL) 47031a3c4e8SJérôme Duval tempText.SetTo(line->text); 471de9dcd41SStephan Aßmus tempText.Append(chunkStart, chunkLength); 472de9dcd41SStephan Aßmus 473de9dcd41SStephan Aßmus if (line == NULL || chunkStart[0] == '\n' 474de9dcd41SStephan Aßmus || StringWidth(tempText) > maxWidth) { 475de9dcd41SStephan Aßmus line = new LineInfo; 476de9dcd41SStephan Aßmus line->font = *be_plain_font; 477de9dcd41SStephan Aßmus line->location = BPoint(iconRight + kEdgePadding, y); 478de9dcd41SStephan Aßmus 479de9dcd41SStephan Aßmus fLines.push_front(line); 480de9dcd41SStephan Aßmus y += fontHeight; 481de9dcd41SStephan Aßmus 4824ec6c3a0SAdrien Destugues // Skip the eventual new-line character at the beginning of this chunk 483de9dcd41SStephan Aßmus if (chunkStart[0] == '\n') { 484de9dcd41SStephan Aßmus chunkStart++; 485de9dcd41SStephan Aßmus chunkLength--; 486de9dcd41SStephan Aßmus } 4874ec6c3a0SAdrien Destugues 4884ec6c3a0SAdrien Destugues // Skip more new-line characters and move the line further down 489de9dcd41SStephan Aßmus while (chunkStart[0] == '\n') { 490de9dcd41SStephan Aßmus chunkStart++; 491de9dcd41SStephan Aßmus chunkLength--; 492de9dcd41SStephan Aßmus line->location.y += fontHeight; 493de9dcd41SStephan Aßmus y += fontHeight; 494de9dcd41SStephan Aßmus } 4954ec6c3a0SAdrien Destugues 4964ec6c3a0SAdrien Destugues // Strip space at beginning of a new line 497de9dcd41SStephan Aßmus while (chunkStart[0] == ' ') { 498de9dcd41SStephan Aßmus chunkLength--; 499de9dcd41SStephan Aßmus chunkStart++; 500de9dcd41SStephan Aßmus } 501de9dcd41SStephan Aßmus } 502de9dcd41SStephan Aßmus 503de9dcd41SStephan Aßmus if (chunkStart[0] == '\0') 504de9dcd41SStephan Aßmus break; 505de9dcd41SStephan Aßmus 506de9dcd41SStephan Aßmus // Append the chunk to the current line, which was either a new 5074ec6c3a0SAdrien Destugues // line or the one from the previous iteration 508de9dcd41SStephan Aßmus line->text.Append(chunkStart, chunkLength); 509de9dcd41SStephan Aßmus 510de9dcd41SStephan Aßmus chunkStart += chunkLength; 511de9dcd41SStephan Aßmus } 512de9dcd41SStephan Aßmus 513de9dcd41SStephan Aßmus fHeight = y + (kEdgePadding * 2); 514de9dcd41SStephan Aßmus 515de9dcd41SStephan Aßmus // Make sure icon fits 516de9dcd41SStephan Aßmus if (fBitmap != NULL) { 5174ec6c3a0SAdrien Destugues float minHeight = fBitmap->Bounds().Height() + 2 * kEdgePadding; 518de9dcd41SStephan Aßmus 519de9dcd41SStephan Aßmus if (fHeight < minHeight) 520de9dcd41SStephan Aßmus fHeight = minHeight; 521de9dcd41SStephan Aßmus } 522e0890a26SAdrien Destugues 523e0890a26SAdrien Destugues // Make sure the progress bar is below the text, and the window is big 524e0890a26SAdrien Destugues // enough. 525e0890a26SAdrien Destugues static_cast<BGroupLayout*>(GetLayout())->SetInsets(kIconStripeWidth + 8, 526e0890a26SAdrien Destugues fHeight, 8, 8); 527*44c6e69bSAdrien Destugues 528*44c6e69bSAdrien Destugues _CalculateSize(); 529de9dcd41SStephan Aßmus } 530de9dcd41SStephan Aßmus 531de9dcd41SStephan Aßmus 532de9dcd41SStephan Aßmus const char* 5334ec6c3a0SAdrien Destugues NotificationView::MessageID() const 534de9dcd41SStephan Aßmus { 5354ec6c3a0SAdrien Destugues return fNotification->MessageID(); 536de9dcd41SStephan Aßmus } 537de9dcd41SStephan Aßmus 538de9dcd41SStephan Aßmus 5394ec6c3a0SAdrien Destugues BSize 5404ec6c3a0SAdrien Destugues NotificationView::_CalculateSize() 541de9dcd41SStephan Aßmus { 5424ec6c3a0SAdrien Destugues BSize size; 5434ec6c3a0SAdrien Destugues 544*44c6e69bSAdrien Destugues size.width = 300; 5454ec6c3a0SAdrien Destugues size.height = fHeight; 5464ec6c3a0SAdrien Destugues 5474ec6c3a0SAdrien Destugues if (fNotification->Type() == B_PROGRESS_NOTIFICATION) { 5484ec6c3a0SAdrien Destugues font_height fh; 5494ec6c3a0SAdrien Destugues be_plain_font->GetHeight(&fh); 5504ec6c3a0SAdrien Destugues float fontHeight = fh.ascent + fh.descent + fh.leading; 551*44c6e69bSAdrien Destugues size.height += 9 + (kSmallPadding * 2) + (kEdgePadding * 1) 552*44c6e69bSAdrien Destugues + fontHeight * 2; 553de9dcd41SStephan Aßmus } 554de9dcd41SStephan Aßmus 555*44c6e69bSAdrien Destugues SetExplicitMinSize(size); 556*44c6e69bSAdrien Destugues SetExplicitMaxSize(size); 557*44c6e69bSAdrien Destugues 5584ec6c3a0SAdrien Destugues return size; 559de9dcd41SStephan Aßmus } 560