1/*
2 * Copyright 2000, Georges-Edouard Berenger. All rights reserved.
3 * Copyright 2022, Haiku, Inc. All rights reserved.
4 * Distributed under the terms of the MIT License.
5 */
6#include "MemoryBarMenuItem.h"
7
8#include "Colors.h"
9#include "MemoryBarMenu.h"
10#include "ProcessController.h"
11
12#include <Bitmap.h>
13#include <ControlLook.h>
14#include <StringForSize.h>
15
16#include <stdio.h>
17
18
19MemoryBarMenuItem::MemoryBarMenuItem(const char *label, team_id team,
20		BBitmap* icon, bool deleteIcon, BMessage* message)
21	:
22	IconMenuItem(icon, label, message, true, deleteIcon),
23	fTeamID(team)
24{
25	Init();
26}
27
28
29MemoryBarMenuItem::~MemoryBarMenuItem()
30{
31}
32
33
34void
35MemoryBarMenuItem::Init()
36{
37	fWriteMemory = -1;
38	fAllMemory = -1;
39	fGrenze1 = -1;
40	fGrenze2 = -1;
41	fLastCommitted = -1;
42	fLastWrite = -1;
43	fLastAll = -1;
44}
45
46
47void
48MemoryBarMenuItem::DrawContent()
49{
50	DrawIcon();
51
52	if (fWriteMemory < 0)
53		BarUpdate();
54	else
55		DrawBar(true);
56
57	BPoint loc = ContentLocation();
58	loc.x += ceilf(be_control_look->DefaultLabelSpacing() * 3.3f);
59	Menu()->MovePenTo(loc);
60	BMenuItem::DrawContent();
61}
62
63
64void
65MemoryBarMenuItem::DrawBar(bool force)
66{
67	// only draw anything if something has changed
68	if (!force && fWriteMemory == fLastWrite && fAllMemory == fLastAll
69		&& fCommittedMemory == fLastCommitted)
70		return;
71
72	bool selected = IsSelected();
73	BRect frame = Frame();
74	BMenu* menu = Menu();
75	rgb_color highColor = menu->HighColor();
76
77	BFont font;
78	menu->GetFont(&font);
79	BRect rect = bar_rect(frame, &font);
80
81	// draw the bar itself
82	if (fWriteMemory < 0)
83		return;
84
85	if (fGrenze1 < 0)
86		force = true;
87
88	if (force) {
89		if (selected)
90			menu->SetHighColor(gFrameColorSelected);
91		else
92			menu->SetHighColor(gFrameColor);
93		menu->StrokeRect(rect);
94	}
95
96	rect.InsetBy(1, 1);
97	BRect r = rect;
98	double grenze1 = rect.left + (rect.right - rect.left) * float(fWriteMemory)
99		/ fCommittedMemory;
100	double grenze2 = rect.left + (rect.right - rect.left) * float(fAllMemory)
101		/ fCommittedMemory;
102	if (grenze1 > rect.right)
103		grenze1 = rect.right;
104	if (grenze2 > rect.right)
105		grenze2 = rect.right;
106	r.right = grenze1;
107	if (!force)
108		r.left = fGrenze1;
109	if (r.left < r.right) {
110		if (selected)
111			menu->SetHighColor(gKernelColorSelected);
112		else
113			menu->SetHighColor(gKernelColor);
114		menu->FillRect(r);
115	}
116
117	r.left = grenze1;
118	r.right = grenze2;
119
120	if (!force) {
121		if (fGrenze2 > r.left && r.left >= fGrenze1)
122			r.left = fGrenze2;
123		if (fGrenze1 < r.right && r.right  <= fGrenze2)
124			r.right = fGrenze1;
125	}
126
127	if (r.left < r.right) {
128		if (selected)
129			menu->SetHighColor(gUserColorSelected);
130		else
131			menu->SetHighColor(gUserColor);
132		menu->FillRect(r);
133	}
134
135	r.left = grenze2;
136	r.right = rect.right;
137
138	if (!force)
139		r.right = fGrenze2;
140
141	if (r.left < r.right) {
142		if (selected)
143			menu->SetHighColor(gWhiteSelected);
144		else
145			menu->SetHighColor(kWhite);
146		menu->FillRect(r);
147	}
148
149	menu->SetHighColor(highColor);
150	fGrenze1 = grenze1;
151	fGrenze2 = grenze2;
152
153	fLastCommitted = fCommittedMemory;
154
155	// Draw the values if necessary; if only fCommitedMemory changes, only
156	// the bar might have to be updated
157
158	if (!force && fWriteMemory == fLastWrite && fAllMemory == fLastAll)
159		return;
160
161	if (selected)
162		menu->SetLowColor(gMenuBackColorSelected);
163	else
164		menu->SetLowColor(gMenuBackColor);
165
166	BRect textRect(rect.left - kMargin - gMemoryTextWidth, frame.top,
167		rect.left - kMargin, frame.bottom);
168	menu->FillRect(textRect, B_SOLID_LOW);
169
170	fLastWrite = fWriteMemory;
171	fLastAll = fAllMemory;
172
173	if (selected)
174		menu->SetHighColor(ui_color(B_MENU_SELECTED_ITEM_TEXT_COLOR));
175	else
176		menu->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
177
178	char infos[128];
179	string_for_size(fWriteMemory * 1024.0, infos, sizeof(infos));
180
181	BPoint loc(rect.left - kMargin - gMemoryTextWidth / 2 - menu->StringWidth(infos),
182		rect.bottom + 1);
183	menu->DrawString(infos, loc);
184
185	string_for_size(fAllMemory * 1024.0, infos, sizeof(infos));
186	loc.x = rect.left - kMargin - menu->StringWidth(infos);
187	menu->DrawString(infos, loc);
188	menu->SetHighColor(highColor);
189}
190
191
192void
193MemoryBarMenuItem::GetContentSize(float* _width, float* _height)
194{
195	IconMenuItem::GetContentSize(_width, _height);
196	*_width += ceilf(be_control_look->DefaultLabelSpacing() * 2.0f)
197		+ kBarWidth + kMargin + gMemoryTextWidth;
198}
199
200
201int
202MemoryBarMenuItem::UpdateSituation(int64 committedMemory)
203{
204	fCommittedMemory = committedMemory;
205	BarUpdate();
206	return fWriteMemory;
207}
208
209
210void
211MemoryBarMenuItem::BarUpdate()
212{
213	area_info areaInfo;
214	ssize_t cookie = 0;
215	int64 lram_size = 0;
216	int64 lwram_size = 0;
217	bool exists = false;
218
219	while (get_next_area_info(fTeamID, &cookie, &areaInfo) == B_OK) {
220		exists = true;
221		lram_size += areaInfo.ram_size;
222
223		// TODO: this won't work this way anymore under Haiku!
224//		int zone = (int (areaInfo.address) & 0xf0000000) >> 24;
225		if ((areaInfo.protection & B_WRITE_AREA) != 0)
226			lwram_size += areaInfo.ram_size;
227//			&& (zone & 0xf0) != 0xA0			// Exclude media buffers
228//			&& (fTeamID != gAppServerTeamID || zone != 0x90))	// Exclude app_server side of bitmaps
229	}
230	if (!exists) {
231		team_info info;
232		exists = get_team_info(fTeamID, &info) == B_OK;
233	}
234	if (exists) {
235		fWriteMemory = lwram_size / 1024;
236		fAllMemory = lram_size / 1024;
237		DrawBar(false);
238	} else
239		fWriteMemory = -1;
240}
241
242
243void
244MemoryBarMenuItem::Reset(char* name, team_id team, BBitmap* icon,
245	bool deleteIcon)
246{
247	SetLabel(name);
248	fTeamID = team;
249	IconMenuItem::Reset(icon, deleteIcon);
250
251	Init();
252}
253