xref: /haiku/src/apps/pulse/CPUButton.cpp (revision 1026b0a1a76dc88927bb8175c470f638dc5464ee)
1 //*****************************************************************************
2 //
3 //	File:		CPUButton.cpp
4 //
5 //	Written by:	Daniel Switkin
6 //
7 //	Copyright 1999, Be Incorporated
8 //
9 //*****************************************************************************
10 
11 #include "CPUButton.h"
12 
13 #include <stdlib.h>
14 #include <string.h>
15 
16 #include <Alert.h>
17 #include <Catalog.h>
18 #include <Dragger.h>
19 #include <PopUpMenu.h>
20 #include <TextView.h>
21 #include <ViewPrivate.h>
22 
23 #include <syscalls.h>
24 
25 #include "PulseApp.h"
26 #include "PulseView.h"
27 #include "Common.h"
28 
29 #undef B_TRANSLATION_CONTEXT
30 #define B_TRANSLATION_CONTEXT "CPUButton"
31 
32 
33 CPUButton::CPUButton(BRect rect, const char *name, const char *label, BMessage *message)
34 	: BControl(rect, name, label, message, B_FOLLOW_NONE, B_WILL_DRAW)
35 {
36 	SetValue(B_CONTROL_ON);
37 	SetViewColor(B_TRANSPARENT_COLOR);
38 	fReplicant = false;
39 
40 	_InitData();
41 }
42 
43 
44 CPUButton::CPUButton(BMessage *message)
45 	: BControl(message)
46 {
47 	fReplicant = true;
48 
49 	/* We remove the dragger if we are in deskbar */
50 	if (CountChildren() > 1)
51 		RemoveChild(ChildAt(1));
52 
53 	ResizeTo(CPUBUTTON_WIDTH, CPUBUTTON_HEIGHT);
54 
55 	_InitData();
56 }
57 
58 
59 CPUButton::~CPUButton()
60 {
61 }
62 
63 
64 void
65 CPUButton::_InitData()
66 {
67 	fOffColor.red = fOffColor.green = fOffColor.blue = 184;
68 	fOffColor.alpha = 255;
69 
70 	fCPU = atoi(Label()) - 1;
71 }
72 
73 
74 void
75 CPUButton::_AddDragger()
76 {
77 	BRect rect(Bounds());
78 	rect.top = rect.bottom - 7;
79 	rect.left = rect.right - 7;
80 	BDragger* dragger = new BDragger(rect, this,
81 		B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
82 	AddChild(dragger);
83 }
84 
85 
86 //! Redraw the button depending on whether it's up or down
87 void
88 CPUButton::Draw(BRect rect)
89 {
90 	bool value = (bool)Value();
91 	SetHighColor(value ? fOnColor : fOffColor);
92 
93 	if (!fReplicant) {
94 		SetLowColor(Parent()->LowColor());
95 		FillRect(Bounds(), B_SOLID_LOW);
96 	}
97 
98 	BRect bounds = Bounds();
99 	if (fReplicant && !fReplicantInDeskbar) {
100 		bounds.bottom -= 4;
101 		bounds.right -= 4;
102 	} else if (!fReplicant) {
103 		bounds.bottom -= 7;
104 		bounds.right -= 7;
105 	}
106 	BRect color_rect(bounds);
107 	color_rect.InsetBy(2, 2);
108 	if (value) {
109 		color_rect.bottom -= 1;
110 		color_rect.right -= 1;
111 	}
112 	FillRect(bounds);
113 
114 	if (value)
115 		SetHighColor(80, 80, 80);
116 	else
117 		SetHighColor(255, 255, 255);
118 
119 	BPoint start(0, 0);
120 	BPoint end(bounds.right, 0);
121 	StrokeLine(start, end);
122 	end.Set(0, bounds.bottom);
123 	StrokeLine(start, end);
124 
125 	if (value)
126 		SetHighColor(32, 32, 32);
127 	else
128 		SetHighColor(216, 216, 216);
129 
130 	start.Set(1, 1);
131 	end.Set(bounds.right - 1, 1);
132 	StrokeLine(start, end);
133 	end.Set(1, bounds.bottom - 1);
134 	StrokeLine(start, end);
135 
136 	if (value)
137 		SetHighColor(216, 216, 216);
138 	else
139 		SetHighColor(80, 80, 80);
140 
141 	start.Set(bounds.left + 1, bounds.bottom - 1);
142 	end.Set(bounds.right - 1, bounds.bottom - 1);
143 	StrokeLine(start, end);
144 	start.Set(bounds.right - 1, bounds.top + 1);
145 	StrokeLine(start, end);
146 
147 	if (value)
148 		SetHighColor(255, 255, 255);
149 	else
150 		SetHighColor(32, 32, 32);
151 
152 	start.Set(bounds.left, bounds.bottom);
153 	end.Set(bounds.right, bounds.bottom);
154 	StrokeLine(start, end);
155 	start.Set(bounds.right, bounds.top);
156 	StrokeLine(start, end);
157 
158 	if (value) {
159 		SetHighColor(0, 0, 0);
160 		start.Set(bounds.left + 2, bounds.bottom - 2);
161 		end.Set(bounds.right - 2, bounds.bottom - 2);
162 		StrokeLine(start, end);
163 		start.Set(bounds.right - 2, bounds.top + 2);
164 		StrokeLine(start, end);
165 	}
166 
167 	// Try to keep the text centered
168 	BFont font;
169 	GetFont(&font);
170 	int label_width = (int)font.StringWidth(Label());
171 	int rect_width = bounds.IntegerWidth() - 1;
172 	int rect_height = bounds.IntegerHeight();
173 	font_height fh;
174 	font.GetHeight(&fh);
175 	int label_height = (int)fh.ascent;
176 	int x_pos = (int)(((double)(rect_width - label_width) / 2.0) + 0.5);
177 	int y_pos = (rect_height - label_height) / 2 + label_height;
178 
179 	MovePenTo(x_pos, y_pos);
180 	SetHighColor(0, 0, 0);
181 	SetDrawingMode(B_OP_OVER);
182 	DrawString(Label());
183 }
184 
185 
186 //! Track the mouse without blocking the window
187 void
188 CPUButton::MouseDown(BPoint point)
189 {
190 	BPoint mousePosition;
191 	uint32 mouseButtons;
192 
193 	GetMouse(&mousePosition, &mouseButtons);
194 
195 	if ((B_PRIMARY_MOUSE_BUTTON & mouseButtons) != 0) {
196 		SetValue(!Value());
197 		SetTracking(true);
198 		SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
199 	} else if ((B_SECONDARY_MOUSE_BUTTON & mouseButtons) != 0
200 		&& fReplicantInDeskbar) {
201 		BPopUpMenu *menu = new BPopUpMenu(B_TRANSLATE("Deskbar menu"));
202 		menu->AddItem(new BMenuItem(B_TRANSLATE("About Pulse" B_UTF8_ELLIPSIS),
203 			new BMessage(B_ABOUT_REQUESTED)));
204 		menu->AddSeparatorItem();
205 		menu->AddItem(new BMenuItem(B_TRANSLATE("Remove replicant"),
206 			new BMessage(kDeleteReplicant)));
207 		menu->SetTargetForItems(this);
208 
209 		ConvertToScreen(&point);
210 		menu->Go(point, true, true, true);
211 	}
212 }
213 
214 
215 void
216 CPUButton::MouseUp(BPoint point)
217 {
218 	if (IsTracking()) {
219 		if (Bounds().Contains(point))
220 			Invoke();
221 
222 		SetTracking(false);
223 	}
224 }
225 
226 
227 void
228 CPUButton::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
229 {
230 	if (IsTracking()) {
231 		if (transit == B_ENTERED_VIEW || transit == B_EXITED_VIEW)
232 			SetValue(!Value());
233 	}
234 }
235 
236 
237 status_t
238 CPUButton::Invoke(BMessage *message)
239 {
240 	if (!LastEnabledCPU(fCPU)) {
241 		_kern_set_cpu_enabled(fCPU, Value());
242 	} else {
243 		BAlert *alert = new BAlert(B_TRANSLATE("Info"),
244 			B_TRANSLATE("You can't disable the last active CPU."),
245 			B_TRANSLATE("OK"));
246 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
247 		alert->Go(NULL);
248 		SetValue(!Value());
249 	}
250 
251 	return B_OK;
252 }
253 
254 
255 CPUButton *
256 CPUButton::Instantiate(BMessage *data)
257 {
258 	if (!validate_instantiation(data, "CPUButton"))
259 		return NULL;
260 
261 	return new CPUButton(data);
262 }
263 
264 
265 status_t
266 CPUButton::Archive(BMessage *data, bool deep) const
267 {
268 	BControl::Archive(data, deep);
269 	data->AddString("add_on", APP_SIGNATURE);
270 	data->AddString("class", "CPUButton");
271 	return B_OK;
272 }
273 
274 
275 void
276 CPUButton::MessageReceived(BMessage *message)
277 {
278 	switch (message->what) {
279 		case B_ABOUT_REQUESTED: {
280 			PulseApp::ShowAbout(false);
281 			break;
282 		}
283 		case PV_REPLICANT_PULSE: {
284 			// Make sure we're consistent with our CPU
285 			if (_kern_cpu_enabled(fCPU) != Value() && !IsTracking())
286 				SetValue(!Value());
287 			break;
288 		}
289 		case kDeleteReplicant: {
290 			Window()->PostMessage(kDeleteReplicant, this, NULL);
291 			break;
292 		}
293 		default:
294 			BControl::MessageReceived(message);
295 			break;
296 	}
297 }
298 
299 
300 void
301 CPUButton::UpdateColors(int32 color)
302 {
303 	fOnColor.red = (color & 0xff000000) >> 24;
304 	fOnColor.green = (color & 0x00ff0000) >> 16;
305 	fOnColor.blue = (color & 0x0000ff00) >> 8;
306 	Draw(Bounds());
307 }
308 
309 
310 void
311 CPUButton::AttachedToWindow()
312 {
313 	SetTarget(this);
314 	SetFont(be_plain_font);
315 	SetFontSize(10);
316 
317 	fReplicantInDeskbar = false;
318 
319 	if (fReplicant) {
320 		if (strcmp(Window()->Title(), B_TRANSLATE("Deskbar"))) {
321 			// Make room for dragger
322 			ResizeBy(4, 4);
323 
324 			_AddDragger();
325 		} else
326 			fReplicantInDeskbar = true;
327 
328 		Prefs *prefs = new Prefs();
329 		UpdateColors(prefs->normal_bar_color);
330 		delete prefs;
331 	} else {
332 		PulseApp *pulseapp = (PulseApp *)be_app;
333 		UpdateColors(pulseapp->prefs->normal_bar_color);
334 		_AddDragger();
335 	}
336 
337 	BMessenger messenger(this);
338 	fPulseRunner = new BMessageRunner(messenger, new BMessage(PV_REPLICANT_PULSE),
339 		200000, -1);
340 }
341 
342 
343 void
344 CPUButton::DetachedFromWindow()
345 {
346 	delete fPulseRunner;
347 }
348