1 /* 2 * Copyright 2010, Haiku, Inc. All Rights Reserved. 3 * Copyright 2008-2009, Pier Luigi Fiorini. All Rights Reserved. 4 * Copyright 2004-2008, Michael Davidson. All Rights Reserved. 5 * Copyright 2004-2007, Mikael Eiman. All Rights Reserved. 6 * Distributed under the terms of the MIT License. 7 * 8 * Authors: 9 * Michael Davidson, slaad@bong.com.au 10 * Mikael Eiman, mikael@eiman.tv 11 * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com 12 */ 13 14 #include <algorithm> 15 16 #include <ControlLook.h> 17 #include <GroupLayout.h> 18 #include <GroupView.h> 19 20 #include "AppGroupView.h" 21 22 #include "NotificationWindow.h" 23 #include "NotificationView.h" 24 25 26 static const int kHeaderSize = 20; 27 28 29 AppGroupView::AppGroupView(NotificationWindow* win, const char* label) 30 : 31 BGroupView("appGroup", B_VERTICAL, 0), 32 fLabel(label), 33 fParent(win), 34 fCollapsed(false) 35 { 36 SetFlags(Flags() | B_WILL_DRAW); 37 38 static_cast<BGroupLayout*>(GetLayout())->SetInsets(0, kHeaderSize, 0, 0); 39 } 40 41 42 void 43 AppGroupView::Draw(BRect updateRect) 44 { 45 rgb_color menuColor = ViewColor(); 46 BRect bounds = Bounds(); 47 rgb_color hilite = tint_color(menuColor, B_DARKEN_1_TINT); 48 rgb_color vlight = tint_color(menuColor, B_LIGHTEN_2_TINT); 49 bounds.bottom = bounds.top + kHeaderSize; 50 51 // Draw the header background 52 SetHighColor(tint_color(menuColor, 1.22)); 53 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 54 StrokeLine(bounds.LeftTop(), bounds.LeftBottom()); 55 uint32 borders = BControlLook::B_TOP_BORDER 56 | BControlLook::B_BOTTOM_BORDER | BControlLook::B_RIGHT_BORDER; 57 58 be_control_look->DrawButtonBackground(this, bounds, bounds, menuColor, 59 0, borders); 60 61 // Draw the buttons 62 fCollapseRect.top = (kHeaderSize - kExpandSize) / 2; 63 fCollapseRect.left = kEdgePadding * 2; 64 fCollapseRect.right = fCollapseRect.left + 1.5 * kExpandSize; 65 fCollapseRect.bottom = fCollapseRect.top + kExpandSize; 66 67 fCloseRect = bounds; 68 fCloseRect.top = (kHeaderSize - kExpandSize) / 2; 69 fCloseRect.right -= kEdgePadding * 2; 70 fCloseRect.left = fCloseRect.right - kCloseSize; 71 fCloseRect.bottom = fCloseRect.top + kCloseSize; 72 73 uint32 arrowDirection = fCollapsed 74 ? BControlLook::B_DOWN_ARROW : BControlLook::B_UP_ARROW; 75 be_control_look->DrawArrowShape(this, fCollapseRect, fCollapseRect, 76 LowColor(), arrowDirection, 0, B_DARKEN_3_TINT); 77 78 SetPenSize(kPenSize); 79 80 // Draw the dismiss widget 81 BRect closeCross = fCloseRect; 82 closeCross.InsetBy(kSmallPadding, kSmallPadding); 83 rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR); 84 detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT); 85 86 StrokeRoundRect(fCloseRect, kSmallPadding, kSmallPadding); 87 StrokeLine(closeCross.LeftTop(), closeCross.RightBottom()); 88 StrokeLine(closeCross.RightTop(), closeCross.LeftBottom()); 89 90 // Draw the label 91 SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); 92 BString label = fLabel; 93 if (fCollapsed) 94 label << " (" << fInfo.size() << ")"; 95 96 SetFont(be_bold_font); 97 98 DrawString(label.String(), BPoint(fCollapseRect.right + 2 * kEdgePadding, 99 fCloseRect.bottom)); 100 } 101 102 103 void 104 AppGroupView::MouseDown(BPoint point) 105 { 106 if (BRect(fCloseRect).InsetBySelf(-5, -5).Contains(point)) { 107 int32 children = fInfo.size(); 108 for (int32 i = 0; i < children; i++) { 109 GetLayout()->RemoveView(fInfo[i]); 110 delete fInfo[i]; 111 } 112 113 fInfo.clear(); 114 115 // Remove ourselves from the parent view 116 BMessage message(kRemoveGroupView); 117 message.AddPointer("view", this); 118 fParent->PostMessage(&message); 119 } else if (BRect(fCollapseRect).InsetBySelf(-5, -5).Contains(point)) { 120 fCollapsed = !fCollapsed; 121 int32 children = fInfo.size(); 122 if (fCollapsed) { 123 for (int32 i = 0; i < children; i++) { 124 if (!fInfo[i]->IsHidden()) 125 fInfo[i]->Hide(); 126 } 127 GetLayout()->SetExplicitMaxSize(GetLayout()->MinSize()); 128 } else { 129 for (int32 i = 0; i < children; i++) { 130 if (fInfo[i]->IsHidden()) 131 fInfo[i]->Show(); 132 } 133 GetLayout()->SetExplicitMaxSize(BSize(B_SIZE_UNSET, B_SIZE_UNSET)); 134 } 135 136 InvalidateLayout(); 137 Invalidate(); // Need to redraw the collapse indicator and title 138 } 139 } 140 141 142 void 143 AppGroupView::MessageReceived(BMessage* msg) 144 { 145 switch (msg->what) { 146 case kRemoveView: 147 { 148 NotificationView* view = NULL; 149 if (msg->FindPointer("view", (void**)&view) != B_OK) 150 return; 151 152 infoview_t::iterator vIt = find(fInfo.begin(), fInfo.end(), view); 153 if (vIt == fInfo.end()) 154 break; 155 156 fInfo.erase(vIt); 157 GetLayout()->RemoveView(view); 158 delete view; 159 160 fParent->PostMessage(msg); 161 162 if (!this->HasChildren()) { 163 Hide(); 164 BMessage removeSelfMessage(kRemoveGroupView); 165 removeSelfMessage.AddPointer("view", this); 166 fParent->PostMessage(&removeSelfMessage); 167 } 168 169 break; 170 } 171 default: 172 BView::MessageReceived(msg); 173 } 174 } 175 176 177 void 178 AppGroupView::AddInfo(NotificationView* view) 179 { 180 BString id = view->MessageID(); 181 bool found = false; 182 183 if (id.Length() > 0) { 184 int32 children = fInfo.size(); 185 186 for (int32 i = 0; i < children; i++) { 187 if (id == fInfo[i]->MessageID()) { 188 NotificationView* oldView = fInfo[i]; 189 fParent->NotificationViewSwapped(oldView, view); 190 GetLayout()->RemoveView(oldView); 191 delete oldView; 192 193 fInfo[i] = view; 194 found = true; 195 196 break; 197 } 198 } 199 } 200 201 if (!found) { 202 fInfo.push_back(view); 203 } 204 GetLayout()->AddView(view); 205 206 if (IsHidden()) 207 Show(); 208 if (view->IsHidden(view) && !fCollapsed) 209 view->Show(); 210 } 211 212 213 const BString& 214 AppGroupView::Group() const 215 { 216 return fLabel; 217 } 218 219 220 bool 221 AppGroupView::HasChildren() 222 { 223 return !fInfo.empty(); 224 } 225