xref: /haiku/src/apps/powerstatus/ExtendedInfoWindow.cpp (revision 4a55cc230cf7566cadcbb23b1928eefff8aea9a2)
1 /*
2  * Copyright 2009-2017, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Clemens Zeidler, haiku@Clemens-Zeidler.de
7  *		Kacper Kasper, kacperkasper@gmail.com
8  */
9 
10 
11 #include "ExtendedInfoWindow.h"
12 
13 #include <ControlLook.h>
14 #include <Catalog.h>
15 #include <GroupView.h>
16 #include <LayoutBuilder.h>
17 #include <SpaceLayoutItem.h>
18 #include <TabView.h>
19 
20 
21 #include <algorithm>
22 
23 
24 #undef B_TRANSLATION_CONTEXT
25 #define B_TRANSLATION_CONTEXT "PowerStatus"
26 
27 
28 const size_t kLinesCount = 16;
29 
30 
31 //	#pragma mark -
32 
33 
34 BatteryInfoView::BatteryInfoView()
35 	:
36 	BView("battery info view", B_AUTO_UPDATE_SIZE_LIMITS)
37 {
38 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
39 
40 	BGroupLayout* layout = new BGroupLayout(B_VERTICAL, 0);
41 	layout->SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING,
42 		0, B_USE_DEFAULT_SPACING);
43 	SetLayout(layout);
44 
45 	for (size_t i = 0; i < kLinesCount; i++) {
46 		BStringView* view = new BStringView("info", "");
47 		AddChild(view);
48 		fStringList.AddItem(view);
49 	}
50 	fStringList.ItemAt(0)->SetFont(be_bold_font);
51 	AddChild(BSpaceLayoutItem::CreateGlue());
52 }
53 
54 
55 BatteryInfoView::~BatteryInfoView()
56 {
57 	for (int32 i = 0; i < fStringList.CountItems(); i++)
58 		delete fStringList.ItemAt(i);
59 }
60 
61 
62 void
63 BatteryInfoView::Update(battery_info& info, acpi_extended_battery_info& extInfo)
64 {
65 	fBatteryInfo = info;
66 	fBatteryExtendedInfo = extInfo;
67 
68 	for (size_t i = 0; i < kLinesCount; i++) {
69 		fStringList.ItemAt(i)->SetText(_GetTextForLine(i));
70 	}
71 }
72 
73 
74 void
75 BatteryInfoView::AttachedToWindow()
76 {
77 	Window()->CenterOnScreen();
78 }
79 
80 
81 BString
82 BatteryInfoView::_GetTextForLine(size_t line)
83 {
84 	BString powerUnit;
85 	BString rateUnit;
86 	switch (fBatteryExtendedInfo.power_unit) {
87 		case 0:
88 			powerUnit = B_TRANSLATE(" mWh");
89 			rateUnit = B_TRANSLATE(" mW");
90 			break;
91 
92 		case 1:
93 			powerUnit = B_TRANSLATE(" mAh");
94 			rateUnit = B_TRANSLATE(" mA");
95 			break;
96 	}
97 
98 	BString string;
99 	switch (line) {
100 		case 0: {
101 			if ((fBatteryInfo.state & BATTERY_CHARGING) != 0)
102 				string = B_TRANSLATE("Battery charging");
103 			else if ((fBatteryInfo.state & BATTERY_DISCHARGING) != 0)
104 				string = B_TRANSLATE("Battery discharging");
105 			else if ((fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0
106 				&& fBatteryExtendedInfo.model_number[0] == '\0'
107 				&& fBatteryExtendedInfo.serial_number[0] == '\0'
108 				&& fBatteryExtendedInfo.type[0] == '\0'
109 				&& fBatteryExtendedInfo.oem_info[0] == '\0')
110 				string = B_TRANSLATE("Empty battery slot");
111 			else if ((fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0)
112 				string = B_TRANSLATE("Damaged battery");
113 			else
114 				string = B_TRANSLATE("Battery unused");
115 			break;
116 		}
117 		case 1:
118 			string = B_TRANSLATE("Capacity: ");
119 			string << fBatteryInfo.capacity;
120 			string << powerUnit;
121 			break;
122 		case 2:
123 			string = B_TRANSLATE("Last full charge: ");
124 			string << fBatteryInfo.full_capacity;
125 			string << powerUnit;
126 			break;
127 		case 3:
128 			string = B_TRANSLATE("Current rate: ");
129 			string << fBatteryInfo.current_rate;
130 			string << rateUnit;
131 			break;
132 		// case 4 missed intentionally
133 		case 5:
134 			string = B_TRANSLATE("Design capacity: ");
135 			string << fBatteryExtendedInfo.design_capacity;
136 			string << powerUnit;
137 			break;
138 		case 6:
139 			string = B_TRANSLATE("Technology: ");
140 			if (fBatteryExtendedInfo.technology == 0)
141 				string << B_TRANSLATE("non-rechargeable");
142 			else if (fBatteryExtendedInfo.technology == 1)
143 				string << B_TRANSLATE("rechargeable");
144 			else
145 				string << "?";
146 			break;
147 		case 7:
148 			string = B_TRANSLATE("Design voltage: ");
149 			string << fBatteryExtendedInfo.design_voltage;
150 			string << B_TRANSLATE(" mV");
151 			break;
152 		case 8:
153 			string = B_TRANSLATE("Design capacity warning: ");
154 			string << fBatteryExtendedInfo.design_capacity_warning;
155 			string << powerUnit;
156 			break;
157 		case 9:
158 			string = B_TRANSLATE("Design capacity low warning: ");
159 			string << fBatteryExtendedInfo.design_capacity_low;
160 			string << powerUnit;
161 			break;
162 		case 10:
163 			string = B_TRANSLATE("Capacity granularity 1: ");
164 			string << fBatteryExtendedInfo.capacity_granularity_1;
165 			string << powerUnit;
166 			break;
167 		case 11:
168 			string = B_TRANSLATE("Capacity granularity 2: ");
169 			string << fBatteryExtendedInfo.capacity_granularity_2;
170 			string << powerUnit;
171 			break;
172 		case 12:
173 			string = B_TRANSLATE("Model number: ");
174 			string << fBatteryExtendedInfo.model_number;
175 			break;
176 		case 13:
177 			string = B_TRANSLATE("Serial number: ");
178 			string << fBatteryExtendedInfo.serial_number;
179 			break;
180 		case 14:
181 			string = B_TRANSLATE("Type: ");
182 			string += fBatteryExtendedInfo.type;
183 			break;
184 		case 15:
185 			string = B_TRANSLATE("OEM info: ");
186 			string += fBatteryExtendedInfo.oem_info;
187 			break;
188 		default:
189 			string = "";
190 			break;
191 	}
192 	return string;
193 }
194 
195 
196 //	#pragma mark -
197 
198 
199 BatteryTab::BatteryTab(BatteryInfoView* target,
200 		ExtPowerStatusView* view)
201 	:
202 	fBatteryView(view)
203 {
204 }
205 
206 
207 BatteryTab::~BatteryTab()
208 {
209 }
210 
211 
212 void
213 BatteryTab::Select(BView* owner)
214 {
215 	BTab::Select(owner);
216 	fBatteryView->Select();
217 }
218 
219 void
220 BatteryTab::DrawFocusMark(BView* owner, BRect frame)
221 {
222 	float vertOffset = IsSelected() ? 3 : 2;
223 	float horzOffset = IsSelected() ? 2 : 4;
224 	float width = frame.Width() - horzOffset * 2;
225 	BPoint pt1((frame.left + frame.right - width) / 2.0 + horzOffset,
226 		frame.bottom - vertOffset);
227 	BPoint pt2((frame.left + frame.right + width) / 2.0,
228 		frame.bottom - vertOffset);
229 	owner->SetHighUIColor(B_KEYBOARD_NAVIGATION_COLOR);
230 	owner->StrokeLine(pt1, pt2);
231 }
232 
233 
234 void
235 BatteryTab::DrawLabel(BView* owner, BRect frame)
236 {
237 	BRect rect = frame;
238 	float size = std::min(rect.Width(), rect.Height());
239 	rect.right = rect.left + size;
240 	rect.bottom = rect.top + size;
241 	if (frame.Width() > rect.Height()) {
242 		rect.OffsetBy((frame.Width() - size) / 2.0f, 0.0f);
243 	} else {
244 		rect.OffsetBy(0.0f, (frame.Height() - size) / 2.0f);
245 	}
246 	fBatteryView->DrawTo(owner, rect);
247 }
248 
249 
250 BatteryTabView::BatteryTabView(const char* name)
251 	:
252 	BTabView(name)
253 {
254 }
255 
256 
257 BatteryTabView::~BatteryTabView()
258 {
259 }
260 
261 
262 BRect
263 BatteryTabView::TabFrame(int32 index) const
264 {
265 	BRect bounds(Bounds());
266 	float width = TabHeight();
267 	float height = TabHeight();
268 	float offset = BControlLook::ComposeSpacing(B_USE_WINDOW_SPACING);
269 	switch (TabSide()) {
270 		case kTopSide:
271 			return BRect(offset + index * width, 0.0f,
272 				offset + index * width + width, height);
273 		case kBottomSide:
274 			return BRect(offset + index * width, bounds.bottom - height,
275 				offset + index * width + width, bounds.bottom);
276 		case kLeftSide:
277 			return BRect(0.0f, offset + index * width, height,
278 				offset + index * width + width);
279 		case kRightSide:
280 			return BRect(bounds.right - height, offset + index * width,
281 				bounds.right, offset + index * width + width);
282 		default:
283 			return BRect();
284 	}
285 }
286 
287 
288 ExtPowerStatusView::ExtPowerStatusView(PowerStatusDriverInterface* interface,
289 		BRect frame, int32 resizingMode, int batteryID,
290 		BatteryInfoView* batteryInfoView, ExtendedInfoWindow* window)
291 	:
292 	PowerStatusView(interface, frame, resizingMode, batteryID),
293 	fExtendedInfoWindow(window),
294 	fBatteryInfoView(batteryInfoView),
295 	fBatteryTabView(window->GetBatteryTabView())
296 {
297 }
298 
299 
300 void
301 ExtPowerStatusView::Select(bool select)
302 {
303 	fSelected = select;
304 	Update(true);
305 }
306 
307 
308 bool
309 ExtPowerStatusView::IsCritical()
310 {
311 	return (fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0;
312 }
313 
314 
315 void
316 ExtPowerStatusView::Update(bool force, bool notify)
317 {
318 	PowerStatusView::Update(force);
319 	if (!fSelected)
320 		return;
321 
322 	acpi_extended_battery_info extInfo;
323 	fDriverInterface->GetExtendedBatteryInfo(fBatteryID, &extInfo);
324 
325 	fBatteryInfoView->Update(fBatteryInfo, extInfo);
326 	fBatteryInfoView->Invalidate();
327 
328 	fBatteryTabView->Invalidate();
329 }
330 
331 
332 //	#pragma mark -
333 
334 
335 ExtendedInfoWindow::ExtendedInfoWindow(PowerStatusDriverInterface* interface)
336 	:
337 	BWindow(BRect(100, 150, 500, 500), B_TRANSLATE("Extended battery info"),
338 		B_TITLED_WINDOW,
339 		B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AVOID_FRONT
340 			| B_ASYNCHRONOUS_CONTROLS),
341 	fDriverInterface(interface),
342 	fSelectedView(NULL)
343 {
344 	fDriverInterface->AcquireReference();
345 
346 	BRect batteryRect(BPoint(0, 0), be_control_look->ComposeIconSize(50));
347 	float tabHeight = ceilf(batteryRect.Height() * 1.4f);
348 	fBatteryTabView = new BatteryTabView("tabview");
349 	fBatteryTabView->SetBorder(B_NO_BORDER);
350 	fBatteryTabView->SetTabHeight(tabHeight);
351 	fBatteryTabView->SetTabSide(BTabView::kLeftSide);
352 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
353 		.SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING, 0)
354 		.Add(fBatteryTabView);
355 
356 	for (int i = 0; i < interface->GetBatteryCount(); i++) {
357 		BatteryInfoView* batteryInfoView = new BatteryInfoView();
358 		ExtPowerStatusView* view = new ExtPowerStatusView(interface,
359 			batteryRect, B_FOLLOW_NONE, i, batteryInfoView, this);
360 		BatteryTab* tab = new BatteryTab(batteryInfoView, view);
361 		fBatteryTabView->AddTab(batteryInfoView, tab);
362 		// Has to be added, otherwise it won't get info updates
363 		view->Hide();
364 		AddChild(view);
365 
366 		fBatteryViewList.AddItem(view);
367 		fDriverInterface->StartWatching(view);
368 		if (!view->IsCritical())
369 			fSelectedView = view;
370 	}
371 
372 	if (!fSelectedView && fBatteryViewList.CountItems() > 0)
373 		fSelectedView = fBatteryViewList.ItemAt(0);
374 	fSelectedView->Select();
375 
376 	BSize size = GetLayout()->PreferredSize();
377 	ResizeTo(size.width, size.height);
378 }
379 
380 
381 ExtendedInfoWindow::~ExtendedInfoWindow()
382 {
383 	for (int i = 0; i < fBatteryViewList.CountItems(); i++)
384 		fDriverInterface->StopWatching(fBatteryViewList.ItemAt(i));
385 
386 	fDriverInterface->ReleaseReference();
387 }
388 
389 
390 BatteryTabView*
391 ExtendedInfoWindow::GetBatteryTabView()
392 {
393 	return fBatteryTabView;
394 }
395