blob: 7631e4336fc111e32ae4adaa7d4174cb58477291 [file] [log] [blame]
Dees_Troy51a0e822012-09-05 15:24:24 -04001// console.cpp - GUIConsole object
2
3#include <stdarg.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <fcntl.h>
8#include <sys/reboot.h>
9#include <sys/stat.h>
10#include <sys/time.h>
11#include <sys/mman.h>
12#include <sys/types.h>
13#include <sys/ioctl.h>
14#include <time.h>
15#include <unistd.h>
16#include <stdlib.h>
17
18#include <string>
19
20extern "C" {
21#include "../common.h"
22#include "../minuitwrp/minui.h"
23#include "../recovery_ui.h"
24}
25
26#include "rapidxml.hpp"
27#include "objects.hpp"
28
29
30static std::vector<std::string> gConsole;
31
32extern "C" void gui_print(const char *fmt, ...)
33{
34 char buf[512]; // We're going to limit a single request to 512 bytes
35
36 va_list ap;
37 va_start(ap, fmt);
38 vsnprintf(buf, 512, fmt, ap);
39 va_end(ap);
40
Dees_Troy32c8eb82012-09-11 15:28:06 -040041 fputs(buf, stdout);
42
Dees_Troy51a0e822012-09-05 15:24:24 -040043 char *start, *next;
44
45 if (buf[0] == '\n' && strlen(buf) < 2) {
46 // This prevents the double lines bug seen in the console during zip installs
47 return;
48 }
49
50 for (start = next = buf; *next != '\0'; next++)
51 {
52 if (*next == '\n')
53 {
54 *next = '\0';
55 next++;
56
57 std::string line = start;
58 gConsole.push_back(line);
59 start = next;
60
61 // Handle the normal \n\0 case
62 if (*next == '\0')
63 return;
64 }
65 }
66 std::string line = start;
67 gConsole.push_back(line);
68 return;
69}
70
71extern "C" void gui_print_overwrite(const char *fmt, ...)
72{
73 char buf[512]; // We're going to limit a single request to 512 bytes
74
75 va_list ap;
76 va_start(ap, fmt);
77 vsnprintf(buf, 512, fmt, ap);
78 va_end(ap);
79
Dees_Troy32c8eb82012-09-11 15:28:06 -040080 fputs(buf, stdout);
81
Dees_Troy51a0e822012-09-05 15:24:24 -040082 // Pop the last line, and we can continue
83 if (!gConsole.empty()) gConsole.pop_back();
84
85 char *start, *next;
86 for (start = next = buf; *next != '\0'; next++)
87 {
88 if (*next == '\n')
89 {
90 *next = '\0';
91 next++;
92
93 std::string line = start;
94 gConsole.push_back(line);
95 start = next;
96
97 // Handle the normal \n\0 case
98 if (*next == '\0')
99 return;
100 }
101 }
102 std::string line = start;
103 gConsole.push_back(line);
104 return;
105}
106
107GUIConsole::GUIConsole(xml_node<>* node)
108{
109 xml_attribute<>* attr;
110 xml_node<>* child;
111
112 mFont = NULL;
113 mCurrentLine = -1;
114 memset(&mForegroundColor, 255, sizeof(COLOR));
115 memset(&mBackgroundColor, 0, sizeof(COLOR));
116 mBackgroundColor.alpha = 255;
117 memset(&mScrollColor, 0x08, sizeof(COLOR));
118 mScrollColor.alpha = 255;
119 mLastCount = 0;
120 mSlideout = 0;
121 mSlideoutState = hidden;
122
123 mRenderX = 0; mRenderY = 0; mRenderW = gr_fb_width(); mRenderH = gr_fb_height();
124
125 if (!node)
126 {
127 mSlideoutX = 0; mSlideoutY = 0; mSlideoutW = 0; mSlideoutH = 0;
128 mConsoleX = 0; mConsoleY = 0; mConsoleW = gr_fb_width(); mConsoleH = gr_fb_height();
129 }
130 else
131 {
132 child = node->first_node("font");
133 if (child)
134 {
135 attr = child->first_attribute("resource");
136 if (attr)
137 mFont = PageManager::FindResource(attr->value());
138 }
139
140 child = node->first_node("color");
141 if (child)
142 {
143 attr = child->first_attribute("foreground");
144 if (attr)
145 {
146 std::string color = attr->value();
147 ConvertStrToColor(color, &mForegroundColor);
148 }
149 attr = child->first_attribute("background");
150 if (attr)
151 {
152 std::string color = attr->value();
153 ConvertStrToColor(color, &mBackgroundColor);
154 }
155 attr = child->first_attribute("scroll");
156 if (attr)
157 {
158 std::string color = attr->value();
159 ConvertStrToColor(color, &mScrollColor);
160 }
161 }
162
163 // Load the placement
164 LoadPlacement(node->first_node("placement"), &mConsoleX, &mConsoleY, &mConsoleW, &mConsoleH);
165
166 child = node->first_node("slideout");
167 if (child)
168 {
169 mSlideout = 1;
170 LoadPlacement(child, &mSlideoutX, &mSlideoutY);
171
172 attr = child->first_attribute("resource");
173 if (attr) mSlideoutImage = PageManager::FindResource(attr->value());
174
175 if (mSlideoutImage && mSlideoutImage->GetResource())
176 {
177 mSlideoutW = gr_get_width(mSlideoutImage->GetResource());
178 mSlideoutH = gr_get_height(mSlideoutImage->GetResource());
179 }
180 }
181 }
182
183 gr_getFontDetails(mFont, &mFontHeight, NULL);
184 SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH);
185 SetRenderPos(mConsoleX, mConsoleY);
186 return;
187}
188
189int GUIConsole::RenderSlideout(void)
190{
191 if (!mSlideoutImage || !mSlideoutImage->GetResource()) return -1;
192
193 gr_blit(mSlideoutImage->GetResource(), 0, 0, mSlideoutW, mSlideoutH, mSlideoutX, mSlideoutY);
194 return 0;
195}
196
197int GUIConsole::RenderConsole(void)
198{
199 void* fontResource = NULL;
200 if (mFont) fontResource = mFont->GetResource();
201
202 // We fill the background
203 gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255);
204 gr_fill(mConsoleX, mConsoleY, mConsoleW, mConsoleH);
205
206 gr_color(mScrollColor.red, mScrollColor.green, mScrollColor.blue, mScrollColor.alpha);
207 gr_fill(mConsoleX + (mConsoleW * 9 / 10), mConsoleY, (mConsoleW / 10), mConsoleH);
208
209 // Render the lines
210 gr_color(mForegroundColor.red, mForegroundColor.green, mForegroundColor.blue, mForegroundColor.alpha);
211
212 // Don't try to continue to render without data
213 mLastCount = gConsole.size();
214 if (mLastCount == 0) return (mSlideout ? RenderSlideout() : 0);
215
216 // Find the start point
217 int start;
218 int curLine = mCurrentLine; // Thread-safing (Another thread updates this value)
219 if (curLine == -1)
220 {
221 start = mLastCount - mMaxRows;
222 }
223 else
224 {
225 if (curLine > (int) mLastCount) curLine = (int) mLastCount;
226 if ((int) mMaxRows > curLine) curLine = (int) mMaxRows;
227 start = curLine - mMaxRows;
228 }
229
230 unsigned int line;
231 for (line = 0; line < mMaxRows; line++)
232 {
233 if ((start + (int) line) >= 0 && (start + (int) line) < (int) mLastCount)
234 {
235 gr_textExW(mConsoleX, mStartY + (line * mFontHeight), gConsole[start + line].c_str(), fontResource, mConsoleW + mConsoleX);
236 }
237 }
238 return (mSlideout ? RenderSlideout() : 0);
239}
240
241int GUIConsole::Render(void)
242{
243 if (mSlideout && mSlideoutState == hidden)
244 {
245 return RenderSlideout();
246 }
247 return RenderConsole();
248}
249
250int GUIConsole::Update(void)
251{
252 if (mSlideout && mSlideoutState != visible)
253 {
254 if (mSlideoutState == hidden)
255 return 0;
256
257 if (mSlideoutState == request_hide)
258 mSlideoutState = hidden;
259
260 if (mSlideoutState == request_show)
261 mSlideoutState = visible;
262
263 // Any time we activate the slider, we reset the position
264 mCurrentLine = -1;
265 return 2;
266 }
267
268 if (mCurrentLine == -1 && mLastCount != gConsole.size())
269 {
270 // We can use Render, and return for just a flip
271 Render();
272 return 2;
273 }
274 else if (mLastTouchY >= 0)
275 {
276 // They're still touching, so re-render
277 Render();
278 return 2;
279 }
280 return 0;
281}
282
283int GUIConsole::SetRenderPos(int x, int y, int w, int h)
284{
285 // Adjust the stub position accordingly
286 mSlideoutX += (x - mConsoleX);
287 mSlideoutY += (y - mConsoleY);
288
289 mConsoleX = x;
290 mConsoleY = y;
291 if (w || h)
292 {
293 mConsoleW = w;
294 mConsoleH = h;
295 }
296
297 // Calculate the max rows
298 mMaxRows = mConsoleH / mFontHeight;
299
300 // Adjust so we always fit to bottom
301 mStartY = mConsoleY + (mConsoleH % mFontHeight);
302 return 0;
303}
304
305// IsInRegion - Checks if the request is handled by this object
306// Return 0 if this object handles the request, 1 if not
307int GUIConsole::IsInRegion(int x, int y)
308{
309 if (mSlideout)
310 {
311 // Check if they tapped the slideout button
312 if (x >= mSlideoutX && x <= mSlideoutX + mSlideoutW && y >= mSlideoutY && y < mSlideoutY + mSlideoutH)
313 return 1;
314
315 // If we're only rendering the slideout, bail now
316 if (mSlideoutState == hidden)
317 return 0;
318 }
319
320 return (x < mConsoleX || x > mConsoleX + mConsoleW || y < mConsoleY || y > mConsoleY + mConsoleH) ? 0 : 1;
321}
322
323// NotifyTouch - Notify of a touch event
324// Return 0 on success, >0 to ignore remainder of touch, and <0 on error
325int GUIConsole::NotifyTouch(TOUCH_STATE state, int x, int y)
326{
327 if (mSlideout && mSlideoutState == hidden)
328 {
329 if (state == TOUCH_START)
330 {
331 mSlideoutState = request_show;
332 return 1;
333 }
334 }
335 else if (mSlideout && mSlideoutState == visible)
336 {
337 // Are we sliding it back in?
338 if (state == TOUCH_START && x > mSlideoutX && x < (mSlideoutX + mSlideoutW) && y > mSlideoutY && y < (mSlideoutY + mSlideoutH))
339 {
340 mSlideoutState = request_hide;
341 return 1;
342 }
343 }
344
345 // If we don't have enough lines to scroll, throw this away.
346 if (mLastCount < mMaxRows) return 1;
347
348 // We are scrolling!!!
349 switch (state)
350 {
351 case TOUCH_START:
352 mLastTouchX = x;
353 mLastTouchY = y;
354 if ((x - mConsoleX) > ((9 * mConsoleW) / 10))
355 mSlideMultiplier = 10;
356 else
357 mSlideMultiplier = 1;
358 break;
359
360 case TOUCH_DRAG:
361 // This handles tapping
362 if (x == mLastTouchX && y == mLastTouchY) break;
363 mLastTouchX = -1;
364
365 if (y > mLastTouchY + 5)
366 {
367 mLastTouchY = y;
368 if (mCurrentLine == -1)
Dees_Troy293d7272012-09-26 10:43:46 -0400369 mCurrentLine = mLastCount - 1;
Dees_Troy51a0e822012-09-05 15:24:24 -0400370 else if (mCurrentLine > mSlideMultiplier)
371 mCurrentLine -= mSlideMultiplier;
372 else
373 mCurrentLine = mMaxRows;
374
375 if (mCurrentLine < (int) mMaxRows)
376 mCurrentLine = mMaxRows;
377 }
378 else if (y < mLastTouchY - 5)
379 {
380 mLastTouchY = y;
381 if (mCurrentLine >= 0)
382 {
383 mCurrentLine += mSlideMultiplier;
384 if (mCurrentLine >= (int) mLastCount)
385 mCurrentLine = -1;
386 }
387 }
388 break;
389
390 case TOUCH_RELEASE:
391 // On a tap, we jump to the tail
392 if (mLastTouchX >= 0)
393 mCurrentLine = -1;
394
395 mLastTouchY = -1;
396 case TOUCH_REPEAT:
397 case TOUCH_HOLD:
398 break;
399 }
400 return 0;
401}
402