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