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