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
33CPUButton::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
44CPUButton::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
59CPUButton::~CPUButton()
60{
61}
62
63
64void
65CPUButton::_InitData()
66{
67	fOffColor.red = fOffColor.green = fOffColor.blue = 184;
68	fOffColor.alpha = 255;
69
70	fCPU = atoi(Label()) - 1;
71}
72
73
74void
75CPUButton::_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
87void
88CPUButton::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
187void
188CPUButton::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
215void
216CPUButton::MouseUp(BPoint point)
217{
218	if (IsTracking()) {
219		if (Bounds().Contains(point))
220			Invoke();
221
222		SetTracking(false);
223	}
224}
225
226
227void
228CPUButton::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
237status_t
238CPUButton::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
255CPUButton *
256CPUButton::Instantiate(BMessage *data)
257{
258	if (!validate_instantiation(data, "CPUButton"))
259		return NULL;
260
261	return new CPUButton(data);
262}
263
264
265status_t
266CPUButton::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
275void
276CPUButton::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
300void
301CPUButton::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
310void
311CPUButton::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
343void
344CPUButton::DetachedFromWindow()
345{
346	delete fPulseRunner;
347}
348