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
28const size_t kLinesCount = 16;
29
30
31//	#pragma mark -
32
33
34BatteryInfoView::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
55BatteryInfoView::~BatteryInfoView()
56{
57	for (int32 i = 0; i < fStringList.CountItems(); i++)
58		delete fStringList.ItemAt(i);
59}
60
61
62void
63BatteryInfoView::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
74void
75BatteryInfoView::AttachedToWindow()
76{
77	Window()->CenterOnScreen();
78}
79
80
81BString
82BatteryInfoView::_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 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
201BatteryTab::BatteryTab(BatteryInfoView* target,
202		ExtPowerStatusView* view)
203	:
204	fBatteryView(view)
205{
206}
207
208
209BatteryTab::~BatteryTab()
210{
211}
212
213
214void
215BatteryTab::Select(BView* owner)
216{
217	BTab::Select(owner);
218	fBatteryView->Select();
219}
220
221void
222BatteryTab::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
236void
237BatteryTab::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
252BatteryTabView::BatteryTabView(const char* name)
253	:
254	BTabView(name)
255{
256}
257
258
259BatteryTabView::~BatteryTabView()
260{
261}
262
263
264BRect
265BatteryTabView::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
290ExtPowerStatusView::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
302void
303ExtPowerStatusView::Select(bool select)
304{
305	fSelected = select;
306	Update(true);
307}
308
309
310bool
311ExtPowerStatusView::IsCritical()
312{
313	return (fBatteryInfo.state & BATTERY_CRITICAL_STATE) != 0;
314}
315
316
317void
318ExtPowerStatusView::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
337ExtendedInfoWindow::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
383ExtendedInfoWindow::~ExtendedInfoWindow()
384{
385	for (int i = 0; i < fBatteryViewList.CountItems(); i++)
386		fDriverInterface->StopWatching(fBatteryViewList.ItemAt(i));
387
388	fDriverInterface->ReleaseReference();
389}
390
391
392BatteryTabView*
393ExtendedInfoWindow::GetBatteryTabView()
394{
395	return fBatteryTabView;
396}
397