xref: /haiku/src/apps/powerstatus/ExtendedInfoWindow.cpp (revision 344ded80d400028c8f561b4b876257b94c12db4a)
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_NOT_CHARGING) != 0)
106 				string = B_TRANSLATE("Battery not charging");
107 			else if ((fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0
108 				&& fBatteryExtendedInfo.model_number[0] == '\0'
109 				&& fBatteryExtendedInfo.serial_number[0] == '\0'
110 				&& fBatteryExtendedInfo.type[0] == '\0'
111 				&& fBatteryExtendedInfo.oem_info[0] == '\0')
112 				string = B_TRANSLATE("Empty battery slot");
113 			else if ((fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0)
114 				string = B_TRANSLATE("Damaged or missing battery");
115 			else
116 				string = B_TRANSLATE("Battery unused");
117 			break;
118 		}
119 		case 1:
120 			string = B_TRANSLATE("Capacity: ");
121 			string << fBatteryInfo.capacity;
122 			string << powerUnit;
123 			break;
124 		case 2:
125 			string = B_TRANSLATE("Last full charge: ");
126 			string << fBatteryInfo.full_capacity;
127 			string << powerUnit;
128 			break;
129 		case 3:
130 			string = B_TRANSLATE("Current rate: ");
131 			string << fBatteryInfo.current_rate;
132 			string << rateUnit;
133 			break;
134 		// case 4 missed intentionally
135 		case 5:
136 			string = B_TRANSLATE("Design capacity: ");
137 			string << fBatteryExtendedInfo.design_capacity;
138 			string << powerUnit;
139 			break;
140 		case 6:
141 			string = B_TRANSLATE("Technology: ");
142 			if (fBatteryExtendedInfo.technology == 0)
143 				string << B_TRANSLATE("non-rechargeable");
144 			else if (fBatteryExtendedInfo.technology == 1)
145 				string << B_TRANSLATE("rechargeable");
146 			else
147 				string << "?";
148 			break;
149 		case 7:
150 			string = B_TRANSLATE("Design voltage: ");
151 			string << fBatteryExtendedInfo.design_voltage;
152 			string << B_TRANSLATE(" mV");
153 			break;
154 		case 8:
155 			string = B_TRANSLATE("Design capacity warning: ");
156 			string << fBatteryExtendedInfo.design_capacity_warning;
157 			string << powerUnit;
158 			break;
159 		case 9:
160 			string = B_TRANSLATE("Design capacity low warning: ");
161 			string << fBatteryExtendedInfo.design_capacity_low;
162 			string << powerUnit;
163 			break;
164 		case 10:
165 			string = B_TRANSLATE("Capacity granularity 1: ");
166 			string << fBatteryExtendedInfo.capacity_granularity_1;
167 			string << powerUnit;
168 			break;
169 		case 11:
170 			string = B_TRANSLATE("Capacity granularity 2: ");
171 			string << fBatteryExtendedInfo.capacity_granularity_2;
172 			string << powerUnit;
173 			break;
174 		case 12:
175 			string = B_TRANSLATE("Model number: ");
176 			string << fBatteryExtendedInfo.model_number;
177 			break;
178 		case 13:
179 			string = B_TRANSLATE("Serial number: ");
180 			string << fBatteryExtendedInfo.serial_number;
181 			break;
182 		case 14:
183 			string = B_TRANSLATE("Type: ");
184 			string += fBatteryExtendedInfo.type;
185 			break;
186 		case 15:
187 			string = B_TRANSLATE("OEM info: ");
188 			string += fBatteryExtendedInfo.oem_info;
189 			break;
190 		default:
191 			string = "";
192 			break;
193 	}
194 	return string;
195 }
196 
197 
198 //	#pragma mark -
199 
200 
201 BatteryTab::BatteryTab(BatteryInfoView* target,
202 		ExtPowerStatusView* view)
203 	:
204 	fBatteryView(view)
205 {
206 }
207 
208 
209 BatteryTab::~BatteryTab()
210 {
211 }
212 
213 
214 void
215 BatteryTab::Select(BView* owner)
216 {
217 	BTab::Select(owner);
218 	fBatteryView->Select();
219 }
220 
221 void
222 BatteryTab::DrawFocusMark(BView* owner, BRect frame)
223 {
224 	float vertOffset = IsSelected() ? 3 : 2;
225 	float horzOffset = IsSelected() ? 2 : 4;
226 	float width = frame.Width() - horzOffset * 2;
227 	BPoint pt1((frame.left + frame.right - width) / 2.0 + horzOffset,
228 		frame.bottom - vertOffset);
229 	BPoint pt2((frame.left + frame.right + width) / 2.0,
230 		frame.bottom - vertOffset);
231 	owner->SetHighUIColor(B_KEYBOARD_NAVIGATION_COLOR);
232 	owner->StrokeLine(pt1, pt2);
233 }
234 
235 
236 void
237 BatteryTab::DrawLabel(BView* owner, BRect frame)
238 {
239 	BRect rect = frame;
240 	float size = std::min(rect.Width(), rect.Height());
241 	rect.right = rect.left + size;
242 	rect.bottom = rect.top + size;
243 	if (frame.Width() > rect.Height()) {
244 		rect.OffsetBy((frame.Width() - size) / 2.0f, 0.0f);
245 	} else {
246 		rect.OffsetBy(0.0f, (frame.Height() - size) / 2.0f);
247 	}
248 	fBatteryView->DrawTo(owner, rect);
249 }
250 
251 
252 BatteryTabView::BatteryTabView(const char* name)
253 	:
254 	BTabView(name)
255 {
256 }
257 
258 
259 BatteryTabView::~BatteryTabView()
260 {
261 }
262 
263 
264 BRect
265 BatteryTabView::TabFrame(int32 index) const
266 {
267 	BRect bounds(Bounds());
268 	float width = TabHeight();
269 	float height = TabHeight();
270 	float offset = BControlLook::ComposeSpacing(B_USE_WINDOW_SPACING);
271 	switch (TabSide()) {
272 		case kTopSide:
273 			return BRect(offset + index * width, 0.0f,
274 				offset + index * width + width, height);
275 		case kBottomSide:
276 			return BRect(offset + index * width, bounds.bottom - height,
277 				offset + index * width + width, bounds.bottom);
278 		case kLeftSide:
279 			return BRect(0.0f, offset + index * width, height,
280 				offset + index * width + width);
281 		case kRightSide:
282 			return BRect(bounds.right - height, offset + index * width,
283 				bounds.right, offset + index * width + width);
284 		default:
285 			return BRect();
286 	}
287 }
288 
289 
290 ExtPowerStatusView::ExtPowerStatusView(PowerStatusDriverInterface* interface,
291 		BRect frame, int32 resizingMode, int batteryID,
292 		BatteryInfoView* batteryInfoView, ExtendedInfoWindow* window)
293 	:
294 	PowerStatusView(interface, frame, resizingMode, batteryID),
295 	fExtendedInfoWindow(window),
296 	fBatteryInfoView(batteryInfoView),
297 	fBatteryTabView(window->GetBatteryTabView())
298 {
299 }
300 
301 
302 void
303 ExtPowerStatusView::Select(bool select)
304 {
305 	fSelected = select;
306 	Update(true);
307 }
308 
309 
310 bool
311 ExtPowerStatusView::IsCritical()
312 {
313 	return (fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0;
314 }
315 
316 
317 void
318 ExtPowerStatusView::Update(bool force, bool notify)
319 {
320 	PowerStatusView::Update(force);
321 	if (!fSelected)
322 		return;
323 
324 	acpi_extended_battery_info extInfo;
325 	fDriverInterface->GetExtendedBatteryInfo(fBatteryID, &extInfo);
326 
327 	fBatteryInfoView->Update(fBatteryInfo, extInfo);
328 	fBatteryInfoView->Invalidate();
329 
330 	fBatteryTabView->Invalidate();
331 }
332 
333 
334 //	#pragma mark -
335 
336 
337 ExtendedInfoWindow::ExtendedInfoWindow(PowerStatusDriverInterface* interface)
338 	:
339 	BWindow(BRect(100, 150, 500, 500), B_TRANSLATE("Extended battery info"),
340 		B_TITLED_WINDOW,
341 		B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_AVOID_FRONT
342 			| B_ASYNCHRONOUS_CONTROLS),
343 	fDriverInterface(interface),
344 	fSelectedView(NULL)
345 {
346 	fDriverInterface->AcquireReference();
347 
348 	BRect batteryRect(BPoint(0, 0), be_control_look->ComposeIconSize(50));
349 	float tabHeight = ceilf(batteryRect.Height() * 1.4f);
350 	fBatteryTabView = new BatteryTabView("tabview");
351 	fBatteryTabView->SetBorder(B_NO_BORDER);
352 	fBatteryTabView->SetTabHeight(tabHeight);
353 	fBatteryTabView->SetTabSide(BTabView::kLeftSide);
354 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
355 		.SetInsets(B_USE_DEFAULT_SPACING, 0, B_USE_DEFAULT_SPACING, 0)
356 		.Add(fBatteryTabView);
357 
358 	for (int i = 0; i < interface->GetBatteryCount(); i++) {
359 		BatteryInfoView* batteryInfoView = new BatteryInfoView();
360 		ExtPowerStatusView* view = new ExtPowerStatusView(interface,
361 			batteryRect, B_FOLLOW_NONE, i, batteryInfoView, this);
362 		BatteryTab* tab = new BatteryTab(batteryInfoView, view);
363 		fBatteryTabView->AddTab(batteryInfoView, tab);
364 		// Has to be added, otherwise it won't get info updates
365 		view->Hide();
366 		AddChild(view);
367 
368 		fBatteryViewList.AddItem(view);
369 		fDriverInterface->StartWatching(view);
370 		if (!view->IsCritical())
371 			fSelectedView = view;
372 	}
373 
374 	if (!fSelectedView && fBatteryViewList.CountItems() > 0)
375 		fSelectedView = fBatteryViewList.ItemAt(0);
376 	fSelectedView->Select();
377 
378 	BSize size = GetLayout()->PreferredSize();
379 	ResizeTo(size.width, size.height);
380 }
381 
382 
383 ExtendedInfoWindow::~ExtendedInfoWindow()
384 {
385 	for (int i = 0; i < fBatteryViewList.CountItems(); i++)
386 		fDriverInterface->StopWatching(fBatteryViewList.ItemAt(i));
387 
388 	fDriverInterface->ReleaseReference();
389 }
390 
391 
392 BatteryTabView*
393 ExtendedInfoWindow::GetBatteryTabView()
394 {
395 	return fBatteryTabView;
396 }
397