| /* |
| Copyright 2012 to 2020 TeamWin |
| This file is part of TWRP/TeamWin Recovery Project. |
| |
| TWRP is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| TWRP is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with TWRP. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| // slidervalue.cpp - GUISliderValue 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 "../minuitwrp/truetype.hpp" |
| |
| #include "rapidxml.hpp" |
| #include "objects.hpp" |
| |
| GUISliderValue::GUISliderValue(xml_node<>* node) : GUIObject(node) |
| { |
| xml_attribute<>* attr; |
| xml_node<>* child; |
| |
| mMin = 0; |
| mMax = 100; |
| mValue = 0; |
| mLineH = 2; |
| mLinePadding = 10; |
| mSliderW = 5; |
| mSliderH = 30; |
| mLineX = 0; |
| mLineY = 0; |
| mValueStr = NULL; |
| mAction = NULL; |
| mShowCurr = true; |
| mShowRange = false; |
| mChangeOnDrag = false; |
| mRendered = false; |
| mBackgroundImage = NULL; |
| mHandleImage = NULL; |
| mHandleHoverImage = NULL; |
| mDragging = false; |
| |
| mLabel = NULL; |
| ConvertStrToColor("white", &mTextColor); |
| ConvertStrToColor("white", &mLineColor); |
| ConvertStrToColor("blue", &mSliderColor); |
| |
| if (!node) |
| { |
| LOGERR("GUISliderValue created without XML node\n"); |
| return; |
| } |
| |
| mLabel = new GUIText(node); |
| if (mLabel->Render() < 0) |
| { |
| delete mLabel; |
| mLabel = NULL; |
| } |
| |
| mAction = new GUIAction(node); |
| |
| child = FindNode(node, "font"); |
| if (child) |
| { |
| mFont = LoadAttrFont(child, "resource"); |
| mTextColor = LoadAttrColor(child, "color", mTextColor); |
| } |
| |
| // Load the placement |
| LoadPlacement(FindNode(node, "placement"), &mRenderX, &mRenderY, &mRenderW); |
| |
| child = FindNode(node, "colors"); |
| if (child) |
| { |
| mLineColor = LoadAttrColor(child, "line"); |
| mSliderColor = LoadAttrColor(child, "slider"); |
| } |
| |
| child = FindNode(node, "resource"); |
| if (child) |
| { |
| mBackgroundImage = LoadAttrImage(child, "background"); |
| mHandleImage = LoadAttrImage(child, "handle"); |
| mHandleHoverImage = LoadAttrImage(child, "handlehover"); |
| } |
| |
| child = FindNode(node, "data"); |
| if (child) |
| { |
| attr = child->first_attribute("variable"); |
| if (attr) |
| mVariable = attr->value(); |
| |
| attr = child->first_attribute("min"); |
| if (attr) |
| { |
| mMinStr = gui_parse_text(attr->value()); |
| mMin = atoi(mMinStr.c_str()); |
| } |
| |
| attr = child->first_attribute("max"); |
| if (attr) |
| { |
| mMaxStr = gui_parse_text(attr->value()); |
| mMax = atoi(mMaxStr.c_str()); |
| } |
| |
| if (mMin > mMax) |
| mMin = mMax; |
| |
| attr = child->first_attribute("default"); |
| if (attr) |
| { |
| string parsevalue = gui_parse_text(attr->value()); |
| int def = atoi(parsevalue.c_str()); |
| |
| if (def < mMin) |
| def = mMin; |
| else if (def > mMax) |
| def = mMax; |
| DataManager::SetValue(mVariable, def); |
| } |
| |
| attr = child->first_attribute("showrange"); |
| if (attr) |
| mShowRange = atoi(attr->value()); |
| |
| attr = child->first_attribute("showcurr"); |
| if (attr) |
| mShowCurr = atoi(attr->value()); |
| |
| attr = child->first_attribute("changeondrag"); |
| if (attr) |
| mChangeOnDrag = atoi(attr->value()); |
| } |
| |
| child = FindNode(node, "dimensions"); |
| if (child) |
| { |
| mLineH = LoadAttrIntScaleY(child, "lineh", mLineH); |
| mLinePadding = LoadAttrIntScaleX(child, "linepadding", mLinePadding); |
| mSliderW = LoadAttrIntScaleX(child, "sliderw", mSliderW); |
| mSliderH = LoadAttrIntScaleY(child, "sliderh", mSliderH); |
| } |
| |
| if (mFont && mFont->GetResource()) |
| mFontHeight = mFont->GetHeight(); |
| else |
| mFontHeight = 0; |
| |
| if (mShowCurr) |
| { |
| int maxLen = std::max(strlen(mMinStr.c_str()), strlen(mMaxStr.c_str())); |
| mValueStr = new char[maxLen+1]; |
| } |
| |
| loadValue(true); |
| |
| if (mShowRange) |
| { |
| int textW = std::max(measureText(mMaxStr), measureText(mMinStr)); |
| mLinePadding += textW; |
| } |
| |
| SetRenderPos(mRenderX, mRenderY, mRenderW); |
| } |
| |
| GUISliderValue::~GUISliderValue() |
| { |
| delete mLabel; |
| delete mAction; |
| delete[] mValueStr; |
| } |
| |
| void GUISliderValue::loadValue(bool force) |
| { |
| if (!mVariable.empty()) |
| { |
| int value = DataManager::GetIntValue(mVariable); |
| if (mValue == value && !force) |
| return; |
| |
| mValue = value; |
| } |
| |
| mValue = std::max(mValue, mMin); |
| mValue = std::min(mValue, mMax); |
| mValuePct = pctFromValue(mValue); |
| mRendered = false; |
| } |
| |
| int GUISliderValue::SetRenderPos(int x, int y, int w, int h) |
| { |
| mRenderX = x; |
| mRenderY = y; |
| if (w || h) |
| { |
| mRenderW = w; |
| mRenderH = h; |
| } |
| |
| mRenderH = mSliderH; |
| if (mShowCurr) |
| mRenderH += mFontHeight; |
| |
| if (mLabel) |
| { |
| int lw, lh; |
| mLabel->GetCurrentBounds(lw, lh); |
| int textX = mRenderX + (mRenderW/2 - lw/2); |
| |
| mLabel->SetRenderPos(textX, mRenderY); |
| |
| y += lh; |
| mRenderH += lh; |
| } |
| |
| mSliderY = y; |
| |
| mActionX = mRenderX; |
| mActionY = mRenderY; |
| mActionW = mRenderW; |
| mActionH = mRenderH; |
| |
| if (mBackgroundImage && mBackgroundImage->GetResource()) |
| { |
| mLineW = mBackgroundImage->GetWidth(); |
| mLineH = mBackgroundImage->GetHeight(); |
| } |
| else |
| mLineW = mRenderW - (mLinePadding * 2); |
| |
| mLineY = y + (mSliderH/2 - mLineH/2); |
| mLineX = mRenderX + (mRenderW/2 - mLineW/2); |
| |
| return 0; |
| } |
| |
| int GUISliderValue::measureText(const std::string& str) |
| { |
| void* fontResource = NULL; |
| if (mFont) fontResource = mFont->GetResource(); |
| |
| return twrpTruetype::gr_ttf_measureEx(str.c_str(), fontResource); |
| } |
| |
| int GUISliderValue::Render(void) |
| { |
| if (!isConditionTrue()) |
| { |
| mRendered = false; |
| return 0; |
| } |
| |
| if (mLabel) |
| { |
| int w, h; |
| mLabel->GetCurrentBounds(w, h); |
| if (w != mLabelW) { |
| mLabelW = w; |
| int textX = mRenderX + (mRenderW/2 - mLabelW/2); |
| mLabel->SetRenderPos(textX, mRenderY); |
| } |
| int res = mLabel->Render(); |
| if (res < 0) |
| return res; |
| } |
| |
| // line |
| if (mBackgroundImage && mBackgroundImage->GetResource()) |
| { |
| gr_blit(mBackgroundImage->GetResource(), 0, 0, mLineW, mLineH, mLineX, mLineY); |
| } |
| else |
| { |
| gr_color(mLineColor.red, mLineColor.green, mLineColor.blue, mLineColor.alpha); |
| gr_fill(mLineX, mLineY, mLineW, mLineH); |
| } |
| |
| // slider |
| uint32_t sliderX = mLineX + (mValuePct*(mLineW - mSliderW))/100; |
| |
| if (mHandleImage && mHandleImage->GetResource()) |
| { |
| gr_surface s = mHandleImage->GetResource(); |
| if (mDragging && mHandleHoverImage && mHandleHoverImage->GetResource()) |
| s = mHandleHoverImage->GetResource(); |
| gr_blit(s, 0, 0, mSliderW, mSliderH, sliderX, mLineY + (mLineH/2 - mSliderH/2)); |
| } |
| else |
| { |
| gr_color(mSliderColor.red, mSliderColor.green, mSliderColor.blue, mSliderColor.alpha); |
| gr_fill(sliderX, mSliderY, mSliderW, mSliderH); |
| } |
| |
| void *fontResource = NULL; |
| if (mFont) fontResource = mFont->GetResource(); |
| gr_color(mTextColor.red, mTextColor.green, mTextColor.blue, mTextColor.alpha); |
| if (mShowRange) |
| { |
| int rangeY = (mLineY - mLineH/2) - mFontHeight/2; |
| gr_textEx_scaleW(mRenderX + mPadding/2, rangeY, mMinStr.c_str(), fontResource, mRenderW, TOP_LEFT, 0); |
| gr_textEx_scaleW(mLineX + mLineW + mPadding/2, rangeY, mMaxStr.c_str(), fontResource, mRenderW, TOP_LEFT, 0); |
| } |
| |
| if (mValueStr && mShowCurr) |
| { |
| sprintf(mValueStr, "%d", mValue); |
| int textW = measureText(mValueStr); |
| gr_textEx_scaleW(mRenderX + (mRenderW/2 - textW/2), mSliderY+mSliderH, mValueStr, fontResource, mRenderW, TOP_LEFT, 0); |
| } |
| |
| mRendered = true; |
| return 0; |
| } |
| |
| int GUISliderValue::Update(void) |
| { |
| if (!isConditionTrue()) |
| return mRendered ? 2 : 0; |
| if (!mRendered) |
| return 2; |
| |
| if (mLabel) |
| return mLabel->Update(); |
| return 0; |
| } |
| |
| int GUISliderValue::valueFromPct(float pct) |
| { |
| int range = abs(mMax - mMin); |
| return mMin + (pct * range) / 100; |
| } |
| |
| float GUISliderValue::pctFromValue(int value) |
| { |
| return float((value - mMin) * 100) / abs(mMax - mMin); |
| } |
| |
| int GUISliderValue::NotifyTouch(TOUCH_STATE state, int x, int y) |
| { |
| if (!isConditionTrue()) |
| return -1; |
| |
| switch (state) |
| { |
| case TOUCH_START: |
| if (x >= mLineX && x <= mLineX + mLineW && |
| y >= mRenderY && y <= mRenderY + mRenderH) |
| { |
| mDragging = true; |
| } |
| // no break |
| case TOUCH_DRAG: |
| { |
| if (!mDragging) return 0; |
| |
| x = std::max(mLineX + mSliderW/2, x); |
| x = std::min(mLineX + mLineW - mSliderW/2, x); |
| |
| mValuePct = float(((x - (mLineX + mSliderW/2)) * 100) / (mLineW - mSliderW)); |
| int newVal = valueFromPct(mValuePct); |
| if (newVal != mValue) { |
| mRendered = false; |
| mValue = newVal; |
| if (mChangeOnDrag) { |
| if (!mVariable.empty()) |
| DataManager::SetValue(mVariable, mValue); |
| if (mAction) |
| mAction->doActions(); |
| } |
| } |
| break; |
| } |
| case TOUCH_RELEASE: |
| { |
| if (!mDragging) return 0; |
| mDragging = false; |
| |
| if (!mVariable.empty()) |
| DataManager::SetValue(mVariable, mValue); |
| if (mAction) |
| mAction->doActions(); |
| break; |
| } |
| case TOUCH_REPEAT: |
| case TOUCH_HOLD: |
| break; |
| } |
| return 0; |
| } |
| |
| int GUISliderValue::NotifyVarChange(const std::string& varName, const std::string& value) |
| { |
| GUIObject::NotifyVarChange(varName, value); |
| |
| if (mLabel) |
| mLabel->NotifyVarChange(varName, value); |
| if (varName == mVariable) { |
| int newVal = atoi(value.c_str()); |
| if (newVal != mValue) { |
| mValue = newVal; |
| mValuePct = pctFromValue(mValue); |
| mRendered = false; |
| } |
| } |
| return 0; |
| } |
| |
| void GUISliderValue::SetPageFocus(int inFocus) |
| { |
| if (inFocus) |
| loadValue(); |
| } |