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 dark = tint_color(menuColor, B_DARKEN_2_TINT); 49 rgb_color vlight = tint_color(menuColor, B_LIGHTEN_2_TINT); 50 bounds.bottom = bounds.top + kHeaderSize; 51 52 // Draw the header background 53 if (be_control_look != NULL) { 54 SetHighColor(tint_color(menuColor, 1.22)); 55 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 56 StrokeLine(bounds.LeftTop(), bounds.LeftBottom()); 57 uint32 borders = BControlLook::B_TOP_BORDER 58 | BControlLook::B_BOTTOM_BORDER | BControlLook::B_RIGHT_BORDER; 59 60 be_control_look->DrawButtonBackground(this, bounds, bounds, menuColor, 61 0, borders); 62 } else { 63 SetHighColor(vlight); 64 StrokeLine(bounds.LeftTop(), bounds.RightTop()); 65 StrokeLine(BPoint(bounds.left, bounds.top + 1), bounds.LeftBottom()); 66 SetHighColor(hilite); 67 StrokeLine(BPoint(bounds.left + 1, bounds.bottom), 68 bounds.RightBottom()); 69 } 70 71 // Draw the buttons 72 fCollapseRect.top = (kHeaderSize - kExpandSize) / 2; 73 fCollapseRect.left = kEdgePadding * 2; 74 fCollapseRect.right = fCollapseRect.left + 1.5 * kExpandSize; 75 fCollapseRect.bottom = fCollapseRect.top + kExpandSize; 76 77 fCloseRect = bounds; 78 fCloseRect.top = (kHeaderSize - kExpandSize) / 2; 79 fCloseRect.right -= kEdgePadding * 2; 80 fCloseRect.left = fCloseRect.right - kCloseSize; 81 fCloseRect.bottom = fCloseRect.top + kCloseSize; 82 83 if (be_control_look != NULL) { 84 uint32 arrowDirection = fCollapsed 85 ? BControlLook::B_DOWN_ARROW : BControlLook::B_UP_ARROW; 86 be_control_look->DrawArrowShape(this, fCollapseRect, fCollapseRect, 87 LowColor(), arrowDirection, 0, B_DARKEN_3_TINT); 88 } else { 89 rgb_color outlineColor = {80, 80, 80, 255}; 90 rgb_color middleColor = {200, 200, 200, 255}; 91 92 SetDrawingMode(B_OP_OVER); 93 94 if (fCollapsed) { 95 BeginLineArray(6); 96 97 AddLine(BPoint(fCollapseRect.left + 3, fCollapseRect.top + 1), 98 BPoint(fCollapseRect.left + 3, fCollapseRect.bottom - 1), outlineColor); 99 AddLine(BPoint(fCollapseRect.left + 3, fCollapseRect.top + 1), 100 BPoint(fCollapseRect.left + 7, fCollapseRect.top + 5), outlineColor); 101 AddLine(BPoint(fCollapseRect.left + 7, fCollapseRect.top + 5), 102 BPoint(fCollapseRect.left + 3, fCollapseRect.bottom - 1), outlineColor); 103 104 AddLine(BPoint(fCollapseRect.left + 4, fCollapseRect.top + 3), 105 BPoint(fCollapseRect.left + 4, fCollapseRect.bottom - 3), middleColor); 106 AddLine(BPoint(fCollapseRect.left + 5, fCollapseRect.top + 4), 107 BPoint(fCollapseRect.left + 5, fCollapseRect.bottom - 4), middleColor); 108 AddLine(BPoint(fCollapseRect.left + 5, fCollapseRect.top + 5), 109 BPoint(fCollapseRect.left + 6, fCollapseRect.top + 5), middleColor); 110 EndLineArray(); 111 } else { 112 // expanded state 113 114 BeginLineArray(6); 115 AddLine(BPoint(fCollapseRect.left + 1, fCollapseRect.top + 3), 116 BPoint(fCollapseRect.right - 3, fCollapseRect.top + 3), outlineColor); 117 AddLine(BPoint(fCollapseRect.left + 1, fCollapseRect.top + 3), 118 BPoint(fCollapseRect.left + 5, fCollapseRect.top + 7), outlineColor); 119 AddLine(BPoint(fCollapseRect.left + 5, fCollapseRect.top + 7), 120 BPoint(fCollapseRect.right - 3, fCollapseRect.top + 3), outlineColor); 121 122 AddLine(BPoint(fCollapseRect.left + 3, fCollapseRect.top + 4), 123 BPoint(fCollapseRect.right - 5, fCollapseRect.top + 4), middleColor); 124 AddLine(BPoint(fCollapseRect.left + 4, fCollapseRect.top + 5), 125 BPoint(fCollapseRect.right - 6, fCollapseRect.top + 5), middleColor); 126 AddLine(BPoint(fCollapseRect.left + 5, fCollapseRect.top + 5), 127 BPoint(fCollapseRect.left + 5, fCollapseRect.top + 6), middleColor); 128 EndLineArray(); 129 } 130 } 131 132 SetPenSize(kPenSize); 133 134 // Draw the dismiss widget 135 BRect closeCross = fCloseRect; 136 closeCross.InsetBy(kSmallPadding, kSmallPadding); 137 rgb_color detailCol = ui_color(B_CONTROL_BORDER_COLOR); 138 detailCol = tint_color(detailCol, B_LIGHTEN_2_TINT); 139 140 StrokeRoundRect(fCloseRect, kSmallPadding, kSmallPadding); 141 StrokeLine(closeCross.LeftTop(), closeCross.RightBottom()); 142 StrokeLine(closeCross.RightTop(), closeCross.LeftBottom()); 143 144 // Draw the label 145 SetHighColor(ui_color(B_PANEL_TEXT_COLOR)); 146 BString label = fLabel; 147 if (fCollapsed) 148 label << " (" << fInfo.size() << ")"; 149 150 SetFont(be_bold_font); 151 152 DrawString(label.String(), BPoint(fCollapseRect.right + 2 * kEdgePadding, 153 fCloseRect.bottom)); 154 } 155 156 157 void 158 AppGroupView::MouseDown(BPoint point) 159 { 160 bool changed = false; 161 if (fCloseRect.Contains(point)) { 162 changed = true; 163 164 int32 children = fInfo.size(); 165 for (int32 i = 0; i < children; i++) { 166 GetLayout()->RemoveView(fInfo[i]); 167 delete fInfo[i]; 168 } 169 170 fInfo.clear(); 171 172 // Remove ourselves from the parent view 173 BMessage message(kRemoveView); 174 message.AddPointer("view", this); 175 fParent->PostMessage(&message); 176 } 177 178 if (fCollapseRect.Contains(point)) { 179 fCollapsed = !fCollapsed; 180 int32 children = fInfo.size(); 181 if (fCollapsed) { 182 for (int32 i = 0; i < children; i++) { 183 if (!fInfo[i]->IsHidden()) 184 fInfo[i]->Hide(); 185 } 186 } else { 187 for (int32 i = 0; i < children; i++) { 188 if (fInfo[i]->IsHidden()) 189 fInfo[i]->Show(); 190 } 191 } 192 changed = true; 193 Invalidate(); // Need to redraw the collapse indicator and title 194 195 BMessage message(kRemoveView); 196 // Do not actually remive anything, but update size 197 fParent->PostMessage(&message); 198 } 199 200 if (changed) { 201 _ResizeViews(); 202 } 203 } 204 205 206 void 207 AppGroupView::MessageReceived(BMessage* msg) 208 { 209 switch (msg->what) { 210 case kRemoveView: 211 { 212 NotificationView* view = NULL; 213 if (msg->FindPointer("view", (void**)&view) != B_OK) 214 return; 215 216 infoview_t::iterator vIt = find(fInfo.begin(), fInfo.end(), view); 217 218 if (vIt != fInfo.end()) { 219 fInfo.erase(vIt); 220 GetLayout()->RemoveView(view); 221 delete view; 222 } 223 224 _ResizeViews(); 225 226 if (Window() != NULL) 227 Window()->PostMessage(msg); 228 break; 229 } 230 default: 231 BView::MessageReceived(msg); 232 } 233 } 234 235 236 void 237 AppGroupView::AddInfo(NotificationView* view) 238 { 239 BString id = view->MessageID(); 240 bool found = false; 241 242 if (id.Length() > 0) { 243 int32 children = fInfo.size(); 244 245 for (int32 i = 0; i < children; i++) { 246 if (id == fInfo[i]->MessageID()) { 247 GetLayout()->RemoveView(fInfo[i]); 248 delete fInfo[i]; 249 250 fInfo[i] = view; 251 found = true; 252 253 break; 254 } 255 } 256 } 257 258 if (!found) { 259 fInfo.push_back(view); 260 } 261 GetLayout()->AddView(view); 262 263 if (IsHidden()) 264 Show(); 265 if (view->IsHidden() && !fCollapsed) 266 view->Show(); 267 } 268 269 270 void 271 AppGroupView::_ResizeViews() 272 { 273 int32 children = fInfo.size(); 274 275 if (!fCollapsed) { 276 for (int32 i = 0; i < children; i++) { 277 if (fInfo[i]->IsHidden()) 278 fInfo[i]->Show(); 279 } 280 } else { 281 for (int32 i = 0; i < children; i++) 282 if (!fInfo[i]->IsHidden()) 283 fInfo[i]->Hide(); 284 } 285 286 if (!IsHidden() && !HasChildren()) 287 Hide(); 288 fParent->Layout(true); 289 } 290 291 292 bool 293 AppGroupView::HasChildren() 294 { 295 return !fInfo.empty(); 296 } 297