bin/pc: Mark non-returning function as void
[haiku.git] / src / servers / notification / AppGroupView.cpp
blobb7d286568ba4c5cadde6b348c1c6369cc1ffcda4
1 /*
2 * Copyright 2010-2017, 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.
8 * Authors:
9 * Michael Davidson, slaad@bong.com.au
10 * Mikael Eiman, mikael@eiman.tv
11 * Pier Luigi Fiorini, pierluigi.fiorini@gmail.com
12 * Brian Hill, supernova@tycho.email
15 #include <algorithm>
17 #include <ControlLook.h>
18 #include <GroupLayout.h>
19 #include <GroupView.h>
21 #include "AppGroupView.h"
23 #include "NotificationWindow.h"
24 #include "NotificationView.h"
26 const float kCloseSize = 6;
27 const float kEdgePadding = 2;
30 AppGroupView::AppGroupView(const BMessenger& messenger, const char* label)
32 BGroupView("appGroup", B_VERTICAL, 0),
33 fLabel(label),
34 fMessenger(messenger),
35 fCollapsed(false),
36 fCloseClicked(false),
37 fPreviewModeOn(false)
39 SetFlags(Flags() | B_WILL_DRAW);
41 fHeaderSize = be_bold_font->Size()
42 + be_control_look->ComposeSpacing(B_USE_ITEM_SPACING);
43 static_cast<BGroupLayout*>(GetLayout())->SetInsets(0, fHeaderSize, 0, 0);
47 void
48 AppGroupView::Draw(BRect updateRect)
50 rgb_color menuColor = ViewColor();
51 BRect bounds = Bounds();
52 rgb_color hilite = tint_color(menuColor, B_DARKEN_1_TINT);
53 rgb_color vlight = tint_color(menuColor, B_LIGHTEN_2_TINT);
54 bounds.bottom = bounds.top + fHeaderSize;
56 // Draw the header background
57 SetHighColor(tint_color(menuColor, 1.22));
58 SetLowColor(ui_color(B_PANEL_BACKGROUND_COLOR));
59 StrokeLine(bounds.LeftTop(), bounds.LeftBottom());
60 uint32 borders = BControlLook::B_TOP_BORDER
61 | BControlLook::B_BOTTOM_BORDER | BControlLook::B_RIGHT_BORDER;
62 be_control_look->DrawButtonBackground(this, bounds, bounds, menuColor,
63 0, borders);
65 // Draw the buttons
66 fCollapseRect.top = (fHeaderSize - kExpandSize) / 2;
67 fCollapseRect.left = kEdgePadding * 3;
68 fCollapseRect.right = fCollapseRect.left + 1.5 * kExpandSize;
69 fCollapseRect.bottom = fCollapseRect.top + kExpandSize;
71 fCloseRect = bounds;
72 fCloseRect.top = (fHeaderSize - kCloseSize) / 2;
73 // Take off the 1 to line this up with the close button on the
74 // notification view
75 fCloseRect.right -= kEdgePadding * 3 - 1;
76 fCloseRect.left = fCloseRect.right - kCloseSize;
77 fCloseRect.bottom = fCloseRect.top + kCloseSize;
79 uint32 arrowDirection = fCollapsed
80 ? BControlLook::B_DOWN_ARROW : BControlLook::B_UP_ARROW;
81 be_control_look->DrawArrowShape(this, fCollapseRect, fCollapseRect,
82 LowColor(), arrowDirection, 0, B_DARKEN_3_TINT);
84 SetPenSize(kPenSize);
86 // Draw the dismiss widget
87 _DrawCloseButton(updateRect);
89 // Draw the label
90 SetHighColor(ui_color(B_PANEL_TEXT_COLOR));
91 BString label = fLabel;
92 if (fCollapsed)
93 label << " (" << fInfo.size() << ")";
95 SetFont(be_bold_font);
96 font_height fontHeight;
97 GetFontHeight(&fontHeight);
98 float y = (bounds.top + bounds.bottom - ceilf(fontHeight.ascent)
99 - ceilf(fontHeight.descent)) / 2.0 + ceilf(fontHeight.ascent);
101 DrawString(label.String(),
102 BPoint(fCollapseRect.right + 4 * kEdgePadding, y));
106 void
107 AppGroupView::_DrawCloseButton(const BRect& updateRect)
109 PushState();
110 BRect closeRect = fCloseRect;
112 rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
113 float tint = B_DARKEN_2_TINT;
115 if (fCloseClicked) {
116 BRect buttonRect(closeRect.InsetByCopy(-4, -4));
117 be_control_look->DrawButtonFrame(this, buttonRect, updateRect,
118 base, base,
119 BControlLook::B_ACTIVATED | BControlLook::B_BLEND_FRAME);
120 be_control_look->DrawButtonBackground(this, buttonRect, updateRect,
121 base, BControlLook::B_ACTIVATED);
122 tint *= 1.2;
123 closeRect.OffsetBy(1, 1);
126 base = tint_color(base, tint);
127 SetHighColor(base);
128 SetPenSize(2);
129 StrokeLine(closeRect.LeftTop(), closeRect.RightBottom());
130 StrokeLine(closeRect.LeftBottom(), closeRect.RightTop());
131 PopState();
135 void
136 AppGroupView::MouseDown(BPoint point)
138 // Preview Mode ignores any mouse clicks
139 if (fPreviewModeOn)
140 return;
142 if (BRect(fCloseRect).InsetBySelf(-5, -5).Contains(point)) {
143 int32 children = fInfo.size();
144 for (int32 i = 0; i < children; i++) {
145 fInfo[i]->RemoveSelf();
146 delete fInfo[i];
149 fInfo.clear();
151 // Remove ourselves from the parent view
152 BMessage message(kRemoveGroupView);
153 message.AddPointer("view", this);
154 fMessenger.SendMessage(&message);
155 } else if (BRect(fCollapseRect).InsetBySelf(-5, -5).Contains(point)) {
156 fCollapsed = !fCollapsed;
157 int32 children = fInfo.size();
158 if (fCollapsed) {
159 for (int32 i = 0; i < children; i++) {
160 if (!fInfo[i]->IsHidden())
161 fInfo[i]->Hide();
163 GetLayout()->SetExplicitMaxSize(GetLayout()->MinSize());
164 } else {
165 for (int32 i = 0; i < children; i++) {
166 if (fInfo[i]->IsHidden())
167 fInfo[i]->Show();
169 GetLayout()->SetExplicitMaxSize(BSize(B_SIZE_UNSET, B_SIZE_UNSET));
172 InvalidateLayout();
173 Invalidate(); // Need to redraw the collapse indicator and title
178 void
179 AppGroupView::MessageReceived(BMessage* msg)
181 switch (msg->what) {
182 case kRemoveView:
184 NotificationView* view = NULL;
185 if (msg->FindPointer("view", (void**)&view) != B_OK)
186 return;
188 infoview_t::iterator vIt = find(fInfo.begin(), fInfo.end(), view);
189 if (vIt == fInfo.end())
190 break;
192 fInfo.erase(vIt);
193 view->RemoveSelf();
194 delete view;
196 fMessenger.SendMessage(msg);
198 if (!this->HasChildren()) {
199 Hide();
200 BMessage removeSelfMessage(kRemoveGroupView);
201 removeSelfMessage.AddPointer("view", this);
202 fMessenger.SendMessage(&removeSelfMessage);
205 break;
207 default:
208 BView::MessageReceived(msg);
213 void
214 AppGroupView::AddInfo(NotificationView* view)
216 BString id = view->MessageID();
217 bool found = false;
219 if (id.Length() > 0) {
220 int32 children = fInfo.size();
221 for (int32 i = 0; i < children; i++) {
222 if (id == fInfo[i]->MessageID()) {
223 NotificationView* oldView = fInfo[i];
224 oldView->RemoveSelf();
225 delete oldView;
226 fInfo[i] = view;
227 found = true;
228 break;
233 // Invalidate all children to show or hide the close buttons in the
234 // notification view
235 int32 children = fInfo.size();
236 for (int32 i = 0; i < children; i++) {
237 fInfo[i]->Invalidate();
240 if (!found) {
241 fInfo.push_back(view);
243 GetLayout()->AddView(view);
245 if (IsHidden())
246 Show();
247 if (view->IsHidden(view) && !fCollapsed)
248 view->Show();
252 void
253 AppGroupView::SetPreviewModeOn(bool enabled)
255 fPreviewModeOn = enabled;
259 const BString&
260 AppGroupView::Group() const
262 return fLabel;
266 void
267 AppGroupView::SetGroup(const char* group)
269 fLabel.SetTo(group);
270 Invalidate();
274 bool
275 AppGroupView::HasChildren()
277 return !fInfo.empty();
281 int32
282 AppGroupView::ChildrenCount()
284 return fInfo.size();