diff options
Diffstat (limited to 'gui/console.cpp')
-rw-r--r-- | gui/console.cpp | 426 |
1 files changed, 426 insertions, 0 deletions
diff --git a/gui/console.cpp b/gui/console.cpp new file mode 100644 index 000000000..aad392ca3 --- /dev/null +++ b/gui/console.cpp @@ -0,0 +1,426 @@ +// console.cpp - GUIConsole object + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/reboot.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <time.h> +#include <unistd.h> +#include <stdlib.h> + +#include <string> + +extern "C" { +#include "../twcommon.h" +#include "../minuitwrp/minui.h" +} + +#include "rapidxml.hpp" +#include "objects.hpp" + + +static std::vector<std::string> gConsole; +static std::vector<std::string> gConsoleColor; +static FILE* ors_file; + +extern "C" void __gui_print(const char *color, char *buf) +{ + char *start, *next; + + if (buf[0] == '\n' && strlen(buf) < 2) { + // This prevents the double lines bug seen in the console during zip installs + return; + } + + for (start = next = buf; *next != '\0';) + { + if (*next == '\n') + { + *next = '\0'; + gConsole.push_back(start); + gConsoleColor.push_back(color); + + start = ++next; + } + else + ++next; + } + + // The text after last \n (or whole string if there is no \n) + if(*start) { + gConsole.push_back(start); + gConsoleColor.push_back(color); + } + if (ors_file) { + fprintf(ors_file, "%s\n", buf); + fflush(ors_file); + } +} + +extern "C" void gui_print(const char *fmt, ...) +{ + char buf[512]; // We're going to limit a single request to 512 bytes + + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, 512, fmt, ap); + va_end(ap); + + fputs(buf, stdout); + + __gui_print("normal", buf); + return; +} + +extern "C" void gui_print_color(const char *color, const char *fmt, ...) +{ + char buf[512]; // We're going to limit a single request to 512 bytes + + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, 512, fmt, ap); + va_end(ap); + + fputs(buf, stdout); + + __gui_print(color, buf); + return; +} + +extern "C" void gui_set_FILE(FILE* f) +{ + ors_file = f; +} + +GUIConsole::GUIConsole(xml_node<>* node) : GUIObject(node) +{ + xml_attribute<>* attr; + xml_node<>* child; + + mFont = NULL; + mCurrentLine = -1; + memset(&mForegroundColor, 255, sizeof(COLOR)); + memset(&mBackgroundColor, 0, sizeof(COLOR)); + mBackgroundColor.alpha = 255; + memset(&mScrollColor, 0x08, sizeof(COLOR)); + mScrollColor.alpha = 255; + mLastCount = 0; + mSlideout = 0; + RenderCount = 0; + mSlideoutState = hidden; + mRender = true; + + mRenderX = 0; mRenderY = 0; mRenderW = gr_fb_width(); mRenderH = gr_fb_height(); + + if (!node) + { + mSlideoutX = 0; mSlideoutY = 0; mSlideoutW = 0; mSlideoutH = 0; + mConsoleX = 0; mConsoleY = 0; mConsoleW = gr_fb_width(); mConsoleH = gr_fb_height(); + } + else + { + child = node->first_node("font"); + if (child) + { + attr = child->first_attribute("resource"); + if (attr) + mFont = PageManager::FindResource(attr->value()); + } + + child = node->first_node("color"); + if (child) + { + attr = child->first_attribute("foreground"); + if (attr) + { + std::string color = attr->value(); + ConvertStrToColor(color, &mForegroundColor); + } + attr = child->first_attribute("background"); + if (attr) + { + std::string color = attr->value(); + ConvertStrToColor(color, &mBackgroundColor); + } + attr = child->first_attribute("scroll"); + if (attr) + { + std::string color = attr->value(); + ConvertStrToColor(color, &mScrollColor); + } + } + + // Load the placement + LoadPlacement(node->first_node("placement"), &mConsoleX, &mConsoleY, &mConsoleW, &mConsoleH); + + child = node->first_node("slideout"); + if (child) + { + mSlideout = 1; + LoadPlacement(child, &mSlideoutX, &mSlideoutY); + + attr = child->first_attribute("resource"); + if (attr) mSlideoutImage = PageManager::FindResource(attr->value()); + + if (mSlideoutImage && mSlideoutImage->GetResource()) + { + mSlideoutW = gr_get_width(mSlideoutImage->GetResource()); + mSlideoutH = gr_get_height(mSlideoutImage->GetResource()); + } + } + } + + mFontHeight = gr_getMaxFontHeight(mFont ? mFont->GetResource() : NULL); + SetActionPos(mRenderX, mRenderY, mRenderW, mRenderH); + SetRenderPos(mConsoleX, mConsoleY); + return; +} + +int GUIConsole::RenderSlideout(void) +{ + if (!mSlideoutImage || !mSlideoutImage->GetResource()) + return -1; + + gr_blit(mSlideoutImage->GetResource(), 0, 0, mSlideoutW, mSlideoutH, mSlideoutX, mSlideoutY); + return 0; +} + +int GUIConsole::RenderConsole(void) +{ + void* fontResource = NULL; + if (mFont) + fontResource = mFont->GetResource(); + + // We fill the background + gr_color(mBackgroundColor.red, mBackgroundColor.green, mBackgroundColor.blue, 255); + gr_fill(mConsoleX, mConsoleY, mConsoleW, mConsoleH); + + gr_color(mScrollColor.red, mScrollColor.green, mScrollColor.blue, mScrollColor.alpha); + gr_fill(mConsoleX + (mConsoleW * 9 / 10), mConsoleY, (mConsoleW / 10), mConsoleH); + + // Don't try to continue to render without data + int prevCount = mLastCount; + mLastCount = gConsole.size(); + mRender = false; + if (mLastCount == 0) + return (mSlideout ? RenderSlideout() : 0); + + // Due to word wrap, figure out what / how the newly added text needs to be added to the render vector that is word wrapped + // Note, that multiple consoles on different GUI pages may be different widths or use different fonts, so the word wrapping + // may different in different console windows + for (int i = prevCount; i < mLastCount; i++) { + string curr_line = gConsole[i]; + string curr_color = gConsoleColor[i]; + int line_char_width; + for(;;) { + line_char_width = gr_maxExW(curr_line.c_str(), fontResource, mConsoleW); + if (line_char_width < curr_line.size()) { + rConsole.push_back(curr_line.substr(0, line_char_width)); + rConsoleColor.push_back(curr_color); + curr_line = curr_line.substr(line_char_width); + } else { + rConsole.push_back(curr_line); + rConsoleColor.push_back(curr_color); + break; + } + } + } + RenderCount = rConsole.size(); + + // Find the start point + int start; + int curLine = mCurrentLine; // Thread-safing (Another thread updates this value) + if (curLine == -1) + { + start = RenderCount - mMaxRows; + } + else + { + if (curLine > (int) RenderCount) + curLine = (int) RenderCount; + if ((int) mMaxRows > curLine) + curLine = (int) mMaxRows; + start = curLine - mMaxRows; + } + + unsigned int line; + for (line = 0; line < mMaxRows; line++) + { + if ((start + (int) line) >= 0 && (start + (int) line) < (int) RenderCount) { + if (rConsoleColor[start + line] == "normal") { + gr_color(mForegroundColor.red, mForegroundColor.green, mForegroundColor.blue, mForegroundColor.alpha); + } else { + COLOR mFontColor; + std::string color = rConsoleColor[start + line]; + ConvertStrToColor(color, &mFontColor); + mFontColor.alpha = 255; + gr_color(mFontColor.red, mFontColor.green, mFontColor.blue, mFontColor.alpha); + } + gr_textExW(mConsoleX, mStartY + (line * mFontHeight), rConsole[start + line].c_str(), fontResource, mConsoleW + mConsoleX); + } + } + return (mSlideout ? RenderSlideout() : 0); +} + +int GUIConsole::Render(void) +{ + if(!isConditionTrue()) + return 0; + + if (mSlideout && mSlideoutState == hidden) + return RenderSlideout(); + + return RenderConsole(); +} + +int GUIConsole::Update(void) +{ + if(!isConditionTrue()) + return 0; + + if (mSlideout && mSlideoutState != visible) + { + if (mSlideoutState == hidden) + return 0; + + if (mSlideoutState == request_hide) + mSlideoutState = hidden; + + if (mSlideoutState == request_show) + mSlideoutState = visible; + + // Any time we activate the slider, we reset the position + mCurrentLine = -1; + return 2; + } + + if (mCurrentLine == -1 && mLastCount != gConsole.size()) + { + // We can use Render, and return for just a flip + Render(); + return 2; + } + else if (mRender) + { + // They're still touching, so re-render + Render(); + return 2; + } + return 0; +} + +int GUIConsole::SetRenderPos(int x, int y, int w, int h) +{ + // Adjust the stub position accordingly + mSlideoutX += (x - mConsoleX); + mSlideoutY += (y - mConsoleY); + + mConsoleX = x; + mConsoleY = y; + if (w || h) + { + mConsoleW = w; + mConsoleH = h; + } + + // Calculate the max rows + mMaxRows = mConsoleH / mFontHeight; + + // Adjust so we always fit to bottom + mStartY = mConsoleY + (mConsoleH % mFontHeight); + return 0; +} + +// IsInRegion - Checks if the request is handled by this object +// Return 0 if this object handles the request, 1 if not +int GUIConsole::IsInRegion(int x, int y) +{ + if (mSlideout) + { + // Check if they tapped the slideout button + if (x >= mSlideoutX && x <= mSlideoutX + mSlideoutW && y >= mSlideoutY && y < mSlideoutY + mSlideoutH) + return 1; + + // If we're only rendering the slideout, bail now + if (mSlideoutState == hidden) + return 0; + } + + return (x < mConsoleX || x > mConsoleX + mConsoleW || y < mConsoleY || y > mConsoleY + mConsoleH) ? 0 : 1; +} + +// NotifyTouch - Notify of a touch event +// Return 0 on success, >0 to ignore remainder of touch, and <0 on error +int GUIConsole::NotifyTouch(TOUCH_STATE state, int x, int y) +{ + if(!isConditionTrue()) + return -1; + + if (mSlideout && mSlideoutState == hidden) + { + if (state == TOUCH_START) + { + mSlideoutState = request_show; + return 1; + } + } + else if (mSlideout && mSlideoutState == visible) + { + // Are we sliding it back in? + if (state == TOUCH_START && x > mSlideoutX && x < (mSlideoutX + mSlideoutW) && y > mSlideoutY && y < (mSlideoutY + mSlideoutH)) + { + mSlideoutState = request_hide; + return 1; + } + } + + // If we don't have enough lines to scroll, throw this away. + if (RenderCount < mMaxRows) return 1; + + // We are scrolling!!! + switch (state) + { + case TOUCH_START: + mLastTouchX = x; + mLastTouchY = y; + break; + + case TOUCH_DRAG: + if (x < mConsoleX || x > mConsoleX + mConsoleW || y < mConsoleY || y > mConsoleY + mConsoleH) + break; // touch is outside of the console area -- do nothing + if (y > mLastTouchY + mFontHeight) { + while (y > mLastTouchY + mFontHeight) { + if (mCurrentLine == -1) + mCurrentLine = RenderCount - 1; + else if (mCurrentLine > mMaxRows) + mCurrentLine--; + mLastTouchY += mFontHeight; + } + mRender = true; + } else if (y < mLastTouchY - mFontHeight) { + while (y < mLastTouchY - mFontHeight) { + if (mCurrentLine >= 0) + mCurrentLine++; + mLastTouchY -= mFontHeight; + } + if (mCurrentLine >= (int) RenderCount) + mCurrentLine = -1; + mRender = true; + } + break; + + case TOUCH_RELEASE: + mLastTouchY = -1; + case TOUCH_REPEAT: + case TOUCH_HOLD: + break; + } + return 0; +} |