xref: /haiku/src/servers/notification/AppGroupView.cpp (revision 7a74a5df454197933bc6e80a542102362ee98703)
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