diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/Acrylic_Dialog.pro b/Acrylic_Dialog.pro new file mode 100644 index 0000000..f4136f2 --- /dev/null +++ b/Acrylic_Dialog.pro @@ -0,0 +1,52 @@ +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +CONFIG += c++11 + +# You can make your code fail to compile if it uses deprecated APIs. +# In order to do so, uncomment the following line. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + ConvertFunc.cpp \ + additiontabwidget.cpp \ + hashmap.cpp \ + historypage.cpp \ + infopage.cpp \ + main.cpp \ + acrylic.cpp \ + qtransparentbutton.cpp \ + scrollareacustom.cpp \ + scrollindicator.cpp \ + scrolllistcontainer.cpp \ + stackpage.cpp \ + tabicons.cpp \ + tabindicator.cpp \ + tabpage.cpp + +HEADERS += \ + ConvertFunc.h \ + Stack.h \ + WindowCompositionAttribute.h \ + acrylic.h \ + additiontabwidget.h \ + hashmap.h \ + historypage.h \ + infopage.h \ + qtransparentbutton.h \ + scrollareacustom.h \ + scrollindicator.h \ + scrolllistcontainer.h \ + stackpage.h \ + tabicons.h \ + tabindicator.h \ + tabpage.h + +FORMS += \ + acrylic.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/ConvertFunc.cpp b/ConvertFunc.cpp new file mode 100644 index 0000000..ef27698 --- /dev/null +++ b/ConvertFunc.cpp @@ -0,0 +1,293 @@ +#include "ConvertFunc.h" + +double calc(const double& num1, const double& num2, const char& op){ + double res; + switch(op){ + case '+': + res = num1 + num2; + break; + case '-': + res = num1 - num2; + break; + case '*': + res = num1 * num2; + break; + case '/': + res = num1 / num2; + break; + case '%': + //may occur error answer! + if((int)num2 == 0) + res = std::nanf("1"); + else + res = (int)num1 % (int)num2; + break; + case '^': + res = pow(num1, num2); + break; + case '.': { + QString integer(QString::asprintf("%d", (int)num1)); + QString fracture(QString::asprintf("%d", (int)num2)); + fracture.remove(0, 1); //remove the first 0 + QString num; + num.append(integer); + num.append('.'); + num.append(fracture); + res = num.toDouble(); + break; + } + default: + res = 0; + break; + } + return res; +} + +void Expression::rebuildStacks(){ + QString tempString = expString; + opStack.Empty(); + numStack.Empty(); + errorInput.Empty(); + expString.clear(); + inputCons = 0b101011; + for(int i = 0; i < tempString.length(); i++){ + insert(tempString[i].toLatin1()); + } +} + +void Expression::update(int index = -1){ + while(numStack.Size() > 1 && !opStack.IsEmpty() && opMap[opStack.TopElement()] >= index && opStack.TopElement() != '('){ + double num2 = numStack.PopBack(); + double num1 = numStack.PopBack(); + char op = opStack.PopBack(); + double res = calc(num1, num2, op); + numStack.PushBack(res); + + //count the differences in stacks + numChange.append('o'); + numChange.append('o'); + opChange.append('o'); + numChange.append(QString::asprintf("i%lf", res)); + } + //enable fracture + inputCons |= 0b000010; +} + +void Expression::insert(char c){ + //clear last step differences in stacks + opChange.clear(); + numChange.clear(); + + if(c == '#'){ + update(); + return; + } + if(!errorInput.IsEmpty()) + //Error stack is not empty, regard as error input. + errorInput.PushBack(c); + else if(c == '('){ + if(inputCons & 0b100000){ + opStack.PushBack(c); + + opChange.append(QString::asprintf("i%c", c)); + + //allow minus numbers + inputCons |= 0b000001; + } + else + errorInput.PushBack(c); + } + else if(c == ')'){ + if(inputCons & 0b010000){ + update(); + if(opStack.TopElement() == '('){ + opStack.PopBack(); + + opChange.append('o'); + + //set constraints + inputCons &= 0b010110; + } + else + errorInput.PushBack(c); + } + else + errorInput.PushBack(c); + } + else if(c == '.'){ + if((inputCons & 0b000110) == 0b000110){ + //accept dot + opStack.PushBack(c); + numStack.PushBack(1); + + opChange.append(QString::asprintf("i%c", c)); + numChange.append("i1"); + + //stop accept dots and operators + inputCons &= 0b001010; + } + else + errorInput.PushBack(c); + } + else if(c >= '0' && c <= '9'){ + if(inputCons & 0b001000){ + if(inputCons & 0b010000 || opStack.TopElement() == '.'){ + //not the first number + double i = numStack.PopBack(); + i *= 10; + i += (c - '0'); + numStack.PushBack(i); + + numChange.append(QString::asprintf("oi%lf", i)); + } + else{ + double i = c - '0'; + numStack.PushBack(i); + //qDebug() << c - '0' << "\n"; + numChange.append(QString::asprintf("i%lf", i)); + } + inputCons &= 0b011110; + inputCons |= 0b010000; + if(opStack.TopElement() != '.') + inputCons |= 0b000100; + } + else + errorInput.PushBack(c); + } + else if(opMap[c] >= 0){ + if(inputCons & 0b010000){ + //if(opStack.TopElement() == '.'){ + // double fracture = numStack.PopBack(); + // double integer = numStack.PopBack(); + // double res = calc(integer, fracture, opStack.PopBack()); + // numStack.PushBack(res); + //} + update(opMap[c]); + if(c == '%' && numStack.TopElement() != (int)numStack.TopElement()) + errorInput.PushBack(c); + else{ + opStack.PushBack(c); + + opChange.append(QString::asprintf("i%c", c)); + + //set constraints + inputCons &= 0b101010; + inputCons |= 0b101000; + if(c == '%') + inputCons &= 0b111101; + } + } + else{ + if(c == '-' && inputCons & 0b000001){ + //adjust exp string + if(opStack.TopElement() != '(') + expString.append('0'); + //accept minus number + numStack.PushBack(0); + opStack.PushBack('-'); + + numChange.append("i0"); + opChange.append("i-"); + + //stop accepting minus numbers and operators + inputCons &= 0b101110; + //allow integers and dots + inputCons |= 0b101000; + } + else + errorInput.PushBack(c); + } + } + expString.append(c); +} + +void Expression::backSpace(){ + opChange.clear(); + numChange.clear(); + expString.chop(1); + if(!errorInput.IsEmpty()) + errorInput.PopBack(); + else{ + rebuildStacks(); + } +} + +QString Expression::expStr(){ + return expString; +} + +QString Expression::expToHtml(){ + QString output = expString; + if(!errorInput.IsEmpty()){ + output.insert(expString.length() - errorInput.Size(), ""); + output.append(""); + } + return output; +} + +QString Expression::resToHtml(){ + QString res; + if(opStack.IsEmpty() && numStack.Size() == 1 && errorInput.IsEmpty()) + res.append(QString::asprintf("%g", numStack.TopElement())); + else + res.append("Syntax Error!"); + return res; +} + +void Expression::clr(){ + opStack.Empty(); + numStack.Empty(); + errorInput.Empty(); + expString.clear(); + inputCons = 0b101011; + numChange.clear(); + opChange.clear(); +} + +bool Expression::prepare(){ + expString.clear(); + if(opStack.IsEmpty() && numStack.Size() == 1 && errorInput.IsEmpty()){ + expString.append(QString::asprintf("%g", numStack.TopElement())); + return false; + } + else{ + clr(); + return true; + } +} + +QString Expression::numDifStr(){ + return numChange; +} + +QString Expression::opDifStr(){ + return opChange; +} + +QString Expression::numStackToStr(){ + QString numStr; + Stack cpy(numStack); + QVector reverse; + int n = cpy.Size(); + for(int i = 0; i < n; i++){ + reverse.push_back(cpy.PopBack()); + } + for(int i = 0; i < n; i++){ + numStr.append(QString::asprintf("i%lf", reverse[n - i - 1])); + } + return numStr; +} + +QString Expression::opStackToStr(){ + QString opStr; + Stack cpy(opStack); + QVector reverse; + int n = cpy.Size(); + for(int i = 0; i < n; i++){ + reverse.push_back(cpy.PopBack()); + } + for(int i = 0; i < n; i++){ + opStr.append(QString::asprintf("i%c", reverse[n - i - 1])); + } + return opStr; +} diff --git a/ConvertFunc.h b/ConvertFunc.h new file mode 100644 index 0000000..791e08c --- /dev/null +++ b/ConvertFunc.h @@ -0,0 +1,51 @@ +#include "Stack.h" +#include "hashmap.h" +#include +#include +#include + +#ifndef CONVERTFUNC_H +#define CONVERTFUNC_H + +double calc(const double& num1, const double& num2, const char& op); + +class Expression{ +private: + Stack opStack; //stack that stores the operators, updates lively + Stack numStack; //stack that stores the numbers, updates lively + Stack errorInput; //stack that stores error inputs in order to simple backspace operation + QString expString; //string of the expression, used for html convertion and backspace operation (rebuilds the state of stacks) + QString opChange; + QString numChange; + + int inputCons; //constraint of next input num, used for % + /*Constraint map: + * 000000 Nothing acceptable + * 100000 accept ( + * 010000 accept operators + * 001000 accept integer + * 000100 accept dot + * 000010 accept fracture + * 000001 accept minus + */ + + void rebuildStacks(); //rebuild stacks from the exp string + void update(int index); //calculate the objects in the stack and update the stack for new operations + +public: + Expression() : inputCons(0b101011){} + Expression(QString exp) : expString(exp), inputCons(0b101011) { rebuildStacks(); } //build an expression from a string + void insert(char c); //insert new character to the expression + void backSpace(); //delete one character from the expString + void clr(); //clear the current expression + bool prepare(); //true if stack refresh is needed + QString expStr(); + QString numDifStr(); + QString opDifStr(); + QString numStackToStr(); + QString opStackToStr(); + QString expToHtml(); //convert the expString to html syntax + QString resToHtml(); //convert the result to html syntax +}; + +#endif // CONVERTFUNC_H diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..15f75cf --- /dev/null +++ b/LICENSE @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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 this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/Stack.cpp b/Stack.cpp new file mode 100644 index 0000000..b2012e0 --- /dev/null +++ b/Stack.cpp @@ -0,0 +1,97 @@ +#include "Stack.h" + +template +bool Stack::Resize(int _capacity){ + capacity = _capacity; + T* newStack = (T*)realloc(stack, sizeof(T) * capacity); + if(!newStack){ + //Error + return false; + } + stack = newStack; + return true; +} + +template +Stack::Stack() : capacity(DEFAULT_CAPACITY), size(0) { + stack = (T*)malloc(sizeof(T) * capacity); + if(!stack){ + //Error + } +} + +template +Stack::Stack(int _capacity) : capacity(_capacity), size(0) { + stack = (T*)malloc(sizeof(T) * capacity); + if(!stack){ + //Error + } +} + +template +Stack::Stack(const Stack & s){ + //construct + capacity = s.capacity; + size = s.size; + stack = (T*)malloc(sizeof(T) * capacity); + if(!stack){ + //Error + } + //copy + for(int i = 0; i < size; i++) + stack[i] = s.stack[i]; +} + +template +Stack::~Stack(){ + free(stack); + stack = nullptr; +} + +template +void Stack::PushBack(T val){ + stack[size++] = val; + if(size == capacity){ + bool res = Resize(capacity * 2); + if(!res){ + //Resize Error + } + } +} + +template +T Stack::PopBack(){ + if(size == 0){ + //Tries to pop from an empty stack + //throw an error? + T emptyT; + return emptyT; + } + else{ + T res = stack[--size]; + return res; + } +} + +template +T Stack::TopElement(){ + if(size == 0){ + //Tries to get an element from an empty stack + //throw an error? + T emptyT; + return emptyT; + } + else{ + return stack[size - 1]; + } +} + +template +int Stack::Size(){ + return size; +} + +template +bool Stack::IsEmpty(){ + return size == 0; +} diff --git a/Stack.h b/Stack.h new file mode 100644 index 0000000..e0ee697 --- /dev/null +++ b/Stack.h @@ -0,0 +1,135 @@ +#ifndef STACK_H +#define STACK_H + +#include + +#define DEFAULT_CAPACITY 256 + +template +class Stack{ +private: + int capacity; //default capacity, will enlarge when full + int size; //current size of the stack + + T* stack; //the stack itself + + bool Resize(int _capacity); //resize the stack to new capacity, return false when out of memory + +public: + Stack(); //create stack with default capacity + Stack(int _capacity); //create stack with <_capacity> capacity + Stack(const Stack & s); //create stack from (duplicate) + ~Stack(); //destructor + + void PushBack(T val); //push element of val to the top of the stack + T PopBack(); //pop out the top element of the stack and delete it + T TopElement(); //get the top element of the stack without deleting it + void Empty(); //empty the stack + + int Size(); //return the size of the stack + bool IsEmpty(); //return true if the stack is empty +}; + +template +bool Stack::Resize(int _capacity){ + capacity = _capacity; + T* newStack = (T*)realloc(stack, sizeof(T) * capacity); + if(!newStack){ + //Error + return false; + } + stack = newStack; + return true; +} + +template +Stack::Stack() : capacity(DEFAULT_CAPACITY), size(0) { + stack = (T*)malloc(sizeof(T) * capacity); + if(!stack){ + //Error + } +} + +template +Stack::Stack(int _capacity) : capacity(_capacity), size(0) { + stack = (T*)malloc(sizeof(T) * capacity); + if(!stack){ + //Error + } +} + +template +Stack::Stack(const Stack & s){ + //construct + capacity = s.capacity; + size = s.size; + stack = (T*)malloc(sizeof(T) * capacity); + if(!stack){ + //Error + } + //copy + for(int i = 0; i < size; i++) + stack[i] = s.stack[i]; +} + +template +Stack::~Stack(){ + free(stack); + stack = nullptr; +} + +template +void Stack::PushBack(T val){ + stack[size++] = val; + if(size == capacity){ + bool res = Resize(capacity * 2); + if(!res){ + //Resize Error + } + } +} + +template +T Stack::PopBack(){ + if(size == 0){ + //Tries to pop from an empty stack + //throw an error? + T emptyT; + return emptyT; + } + else{ + T res = stack[--size]; + return res; + } +} + +template +T Stack::TopElement(){ + if(size == 0){ + //Tries to get an element from an empty stack + //throw an error? + T emptyT; + return emptyT; + } + else{ + return stack[size - 1]; + } +} + +template +void Stack::Empty(){ + size = 0; +} + +template +int Stack::Size(){ + return size; +} + +template +bool Stack::IsEmpty(){ + return size == 0; +} + + +#endif // STACK_H diff --git a/WindowCompositionAttribute.h b/WindowCompositionAttribute.h new file mode 100644 index 0000000..8ff748e --- /dev/null +++ b/WindowCompositionAttribute.h @@ -0,0 +1,73 @@ +#pragma once +#include + +typedef enum _WINDOWCOMPOSITIONATTRIB +{ + WCA_UNDEFINED = 0, + WCA_NCRENDERING_ENABLED = 1, + WCA_NCRENDERING_POLICY = 2, + WCA_TRANSITIONS_FORCEDISABLED = 3, + WCA_ALLOW_NCPAINT = 4, + WCA_CAPTION_BUTTON_BOUNDS = 5, + WCA_NONCLIENT_RTL_LAYOUT = 6, + WCA_FORCE_ICONIC_REPRESENTATION = 7, + WCA_EXTENDED_FRAME_BOUNDS = 8, + WCA_HAS_ICONIC_BITMAP = 9, + WCA_THEME_ATTRIBUTES = 10, + WCA_NCRENDERING_EXILED = 11, + WCA_NCADORNMENTINFO = 12, + WCA_EXCLUDED_FROM_LIVEPREVIEW = 13, + WCA_VIDEO_OVERLAY_ACTIVE = 14, + WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15, + WCA_DISALLOW_PEEK = 16, + WCA_CLOAK = 17, + WCA_CLOAKED = 18, + WCA_ACCENT_POLICY = 19, + WCA_FREEZE_REPRESENTATION = 20, + WCA_EVER_UNCLOAKED = 21, + WCA_VISUAL_OWNER = 22, + WCA_LAST = 23 +} WINDOWCOMPOSITIONATTRIB; + +typedef struct _WINDOWCOMPOSITIONATTRIBDATA +{ + WINDOWCOMPOSITIONATTRIB Attrib; + PVOID pvData; + SIZE_T cbData; +} WINDOWCOMPOSITIONATTRIBDATA; + +typedef enum _ACCENT_STATE +{ + ACCENT_DISABLED = 0, + ACCENT_ENABLE_GRADIENT = 1, + ACCENT_ENABLE_TRANSPARENTGRADIENT = 2, + ACCENT_ENABLE_BLURBEHIND = 3, + ACCENT_ENABLE_ACRYLICBLURBEHIND = 4, + ACCENT_INVALID_STATE = 5 +} ACCENT_STATE; + +typedef struct _ACCENT_POLICY +{ + ACCENT_STATE AccentState; + DWORD AccentFlags; + DWORD GradientColor; + DWORD AnimationId; +} ACCENT_POLICY; + +WINUSERAPI +BOOL +WINAPI +GetWindowCompositionAttribute( + _In_ HWND hWnd, + _Inout_ WINDOWCOMPOSITIONATTRIBDATA* pAttrData); + +typedef BOOL(WINAPI*pfnGetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); + +WINUSERAPI +BOOL +WINAPI +SetWindowCompositionAttribute( + _In_ HWND hWnd, + _Inout_ WINDOWCOMPOSITIONATTRIBDATA* pAttrData); + +typedef BOOL(WINAPI*pfnSetWindowCompositionAttribute)(HWND, WINDOWCOMPOSITIONATTRIBDATA*); diff --git a/acrylic.cpp b/acrylic.cpp new file mode 100644 index 0000000..3c04ac9 --- /dev/null +++ b/acrylic.cpp @@ -0,0 +1,282 @@ +#include "acrylic.h" +#include "ui_acrylic.h" +#include + +#include +#include +#include +#include +#include + +Acrylic::Acrylic(QWidget *parent) + : QDialog(parent) + , ui(new Ui::Acrylic), + _width(345), + _height(500) +{ + ui->setupUi(this); + ui->verticalLayout->setAlignment(Qt::AlignTop); + this->resize(_width, _height); + + /****************************************************************************/ + /********************Things to do with the Acrylic Window********************/ + /******************** Do Not Touch ********************/ + /****************************************************************************/ + + //Configurations of Acrylic Effect + acryBackground = QColor(240, 240, 240, 150); + acryOpacity = 50; + hwnd = HWND(winId()); + huser = GetModuleHandle(L"user32.dll"); + + //Areo Effect + if(huser){ + setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(huser, "SetWindowCompositionAttribute"); + if(setWindowCompositionAttribute){ + //DWORD gradientColor = DWORD(0x50FFFFFF); + ACCENT_POLICY accent = { ACCENT_ENABLE_BLURBEHIND, 0, 0, 0 }; + WINDOWCOMPOSITIONATTRIBDATA data; + data.Attrib = WCA_ACCENT_POLICY; + data.pvData = &accent; + data.cbData = sizeof(accent); + setWindowCompositionAttribute(hwnd, &data); + } + } + + //Acrylic Effect + //Warning: Due to the API proplem, this effect is laggy when dragging | resizing + + //if(huser){ + // setWindowCompositionAttribute = (pfnSetWindowCompositionAttribute)GetProcAddress(huser, "SetWindowCompositionAttribute"); + // if(setWindowCompositionAttribute){ + // DWORD gradientColor = DWORD(0x50F5F5F5); + // ACCENT_POLICY accent = { ACCENT_ENABLE_ACRYLICBLURBEHIND, 0, gradientColor, 0 }; + // WINDOWCOMPOSITIONATTRIBDATA data; + // data.Attrib = WCA_ACCENT_POLICY; + // data.pvData = &accent; + // data.cbData = sizeof(accent); + // setWindowCompositionAttribute(hwnd, &data); + // } + //} + + //Configurations of Drag resizing + this->setMouseTracking(true); + + //Some old time trash + //QWidget* titleBar = new QWidget(this); + //QLabel* text = new QLabel("Calculator", titleBar); + //text->setGeometry(this->rect().x() + 10, this->rect().y(), 500, 50); + //QFont font; + //font.setPointSize(20); + //font.setFamily("FuturaNo2DDemBol"); + //text->setFont(font); + + //ui->mainLayout->setAlignment(Qt::AlignTop); + + ui->opEqual->setColor(QColor(75, 156, 222, 200)); + ui->opEqual->setHoverColor(QColor(50, 156, 222, 210)); + ui->opEqual->setClickedColor(QColor(0, 120, 215, 200)); + + tabPage = new AdditionTabWidget(this); + tabPage->setMinimumWidth(200); + tabPage->setMaximumWidth(350); + ui->mainHLayout->addWidget(tabPage); + tabPage->hide(); + + connect(ui->maximumWindow, SIGNAL(clicked()), this, SLOT(windowMaximum())); + //connect(ui->maximumWindow, SIGNAL(clicked()), this, SLOT(windowMinimum())); + + /****************************************************************************/ + + /****************************************************************************/ + /******************** Things to do with the Calculator ********************/ + /****************************************************************************/ + + initOpMap(); + //ui->displayCur->setAlignment(Qt::AlignRight | Qt::AlignBottom); + //ui->displayCur->setAlignment(Qt::AlignBottom); + ui->displayCur->setTextFormat(Qt::RichText); + ui->displayCur->setAttribute(Qt::WA_TransparentForMouseEvents); + ui->displayHis->setTextFormat(Qt::RichText); + ui->displayHis->setAttribute(Qt::WA_TransparentForMouseEvents); + + //Connect the buttons with input + connect(ui->num0, &QPushButton::clicked, [=](){expr.insert('0'); RfrInput(); UpdStack();}); + connect(ui->num1, &QPushButton::clicked, [=](){expr.insert('1'); RfrInput(); UpdStack();}); + connect(ui->num2, &QPushButton::clicked, [=](){expr.insert('2'); RfrInput(); UpdStack();}); + connect(ui->num3, &QPushButton::clicked, [=](){expr.insert('3'); RfrInput(); UpdStack();}); + connect(ui->num4, &QPushButton::clicked, [=](){expr.insert('4'); RfrInput(); UpdStack();}); + connect(ui->num5, &QPushButton::clicked, [=](){expr.insert('5'); RfrInput(); UpdStack();}); + connect(ui->num6, &QPushButton::clicked, [=](){expr.insert('6'); RfrInput(); UpdStack();}); + connect(ui->num7, &QPushButton::clicked, [=](){expr.insert('7'); RfrInput(); UpdStack();}); + connect(ui->num8, &QPushButton::clicked, [=](){expr.insert('8'); RfrInput(); UpdStack();}); + connect(ui->num9, &QPushButton::clicked, [=](){expr.insert('9'); RfrInput(); UpdStack();}); + connect(ui->opDot, &QPushButton::clicked, [=](){expr.insert('.'); RfrInput(); UpdStack();}); + connect(ui->opAdd, &QPushButton::clicked, [=](){expr.insert('+'); RfrInput(); UpdStack();}); + connect(ui->opSub, &QPushButton::clicked, [=](){expr.insert('-'); RfrInput(); UpdStack();}); + connect(ui->opMulti, &QPushButton::clicked, [=](){expr.insert('*'); RfrInput(); UpdStack();}); + connect(ui->opDiv, &QPushButton::clicked, [=](){expr.insert('/'); RfrInput(); UpdStack();}); + connect(ui->opSqr, &QPushButton::clicked, [=](){expr.insert('^'); RfrInput(); UpdStack(); expr.insert('2'); RfrInput(); UpdStack(); }); + connect(ui->opPow, &QPushButton::clicked, [=](){expr.insert('^'); RfrInput(); UpdStack();}); + connect(ui->opMod, &QPushButton::clicked, [=](){expr.insert('%'); RfrInput(); UpdStack();}); + connect(ui->opBrckL, &QPushButton::clicked, [=](){expr.insert('('); RfrInput(); UpdStack();}); + connect(ui->opBrckR, &QPushButton::clicked, [=](){expr.insert(')'); RfrInput(); UpdStack();}); + connect(ui->opEqual, &QPushButton::clicked, [=](){expr.insert('#'); UpdStack(); RfrInput(); RfrResult(); UpdHistory();}); + connect(ui->opClear, &QPushButton::clicked, [=](){expr.clr(); RfrInput(); UpdStack(true);}); + connect(ui->bckSpace, &QPushButton::clicked, [=](){expr.backSpace(); RfrInput(); UpdStack(true);}); + + connect(this, SIGNAL(addHistoryTerm(const QString &, const QString &, const QString &)), tabPage, SLOT(Controller_AddHistoryTerm(const QString &, const QString &, const QString &))); + connect(this, SIGNAL(updateStackPage(const QString &, const QString &)), tabPage, SLOT(Controller_UpdateStackPage(const QString &, const QString &))); + + +} + +Acrylic::~Acrylic() +{ + delete ui; +} + +void Acrylic::paintEvent(QPaintEvent *event){ + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + QPen pen; + pen.setColor(QColor(0,0,0,255)); + pen.setStyle(Qt::SolidLine); + pen.setWidth(1); + painter.setPen(pen); + painter.setBrush(acryBackground); + painter.drawRect(this->rect()); + ui->TitleBar->resize(this->rect().width() - 10, ui->TitleBar->height()); +} + +void Acrylic::mouseMoveEvent(QMouseEvent *event){ + if(pressed){ + if(mouseState == 0){ + QPoint displacement = event->globalPos() - mousePos_strt; + this->move(displacement); + } + else if(mouseState == 1){ + //resize width + int displacementX = event->pos().x() - this->rect().width(); + if(this->rect().width() + displacementX >= _width){ + this->resize(this->rect().width() + displacementX, this->rect().height()); + } + } + else if(mouseState == 2){ + //resize height + int displacementY = event->pos().y() - this->rect().height(); + if(this->rect().height() + displacementY >= _height) + this->resize(this->rect().width(), this->rect().height() + displacementY); + } + else{ + int displacementX = event->pos().x() - this->rect().width(); + if(this->rect().width() + displacementX >= _width) + this->resize(this->rect().width() + displacementX, this->rect().height()); + int displacementY = event->pos().y() - this->rect().height(); + if(this->rect().height() + displacementY >= _height) + this->resize(this->rect().width(), this->rect().height() + displacementY); + } + if(!tabShown && this->rect().width() >= 595){ + tabPage->show(); + tabShown = true; + } + if(tabShown && this->rect().width() < 595){ + tabPage->hide(); + tabShown = false; + } + } + else{ + int _x = abs(event->pos().x()- this->rect().width()); + int _y = abs(event->pos().y() - this->rect().height()); + //qDebug() << _x << "," << _y; + if(_x < 10 && _y < 10){ + this->setCursor(Qt::SizeFDiagCursor); + mouseState = 3; + } + else if(_x < 5 && _y > 5 && event->pos().y() > ui->TitleBar->height()){ + this->setCursor(Qt::SizeHorCursor); + mouseState = 1; + } + else if(_x > 5 && _y < 5){ + this->setCursor(Qt::SizeVerCursor); + mouseState = 2; + } + else{ + this->setCursor(Qt::ArrowCursor); + mouseState = 0; + } + } +} + +void Acrylic::mousePressEvent(QMouseEvent *event){ + mousePos_strt = event->pos(); + pressed = true; +} + +void Acrylic::mouseReleaseEvent(QMouseEvent *event){ + pressed = false; + this->setCursor(Qt::ArrowCursor); + mouseState = 0; +} + +void Acrylic::RfrInput(){ + ui->displayHis->setText(""); + if(expr.expToHtml().isEmpty()){ + ui->displayCur->setText("0"); + ui->displayHis->clear(); + } + else + ui->displayCur->setText(expr.expToHtml().replace('/', "÷").replace('*', "×")); +} + +void Acrylic::RfrResult(){ + ui->displayHis->setText(expr.expToHtml().replace('/', "÷").replace('*', "×")); + ui->displayCur->setText(expr.resToHtml()); +} + +void Acrylic::UpdStack(bool r){ + QString numDif; + if(r){ + numDif.append('r'); + numDif.append(expr.numStackToStr()); + } + else{ + numDif = expr.numDifStr(); + } + QString opDif; + if(r){ + opDif.append('r'); + opDif.append(expr.opStackToStr()); + } + else{ + opDif = expr.opDifStr(); + } + //qDebug() << opDif << "\n"; + emit updateStackPage(numDif, opDif); + update(); +} + +void Acrylic::UpdHistory(){ + //qDebug() << expr.resToHtml() << "\n"; + emit addHistoryTerm(expr.expStr(), expr.expToHtml(), expr.resToHtml()); + if(expr.prepare()) + UpdStack(true); + update(); +} + + +void Acrylic::windowMaximum(){ + if(!isMaximum){ + lastWidth = this->width(); + lastHeight = this->height(); + this->showFullScreen(); + ui->maximumWindow->setText("▽"); + isMaximum = true; + } + else{ + this->showNormal(); + this->resize(lastWidth, lastHeight); + ui->maximumWindow->setText("□"); + isMaximum = false; + } +} diff --git a/acrylic.h b/acrylic.h new file mode 100644 index 0000000..7b2f288 --- /dev/null +++ b/acrylic.h @@ -0,0 +1,71 @@ +#ifndef ACRYLIC_H +#define ACRYLIC_H + +#include +#include "WindowCompositionAttribute.h" +#include "additiontabwidget.h" +#include "ConvertFunc.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class Acrylic; } +QT_END_NAMESPACE + +class Acrylic : public QDialog +{ + Q_OBJECT + +public: + Acrylic(QWidget *parent = nullptr); + ~Acrylic(); + void paintEvent(QPaintEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mousePressEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + void leaveEvent(QEvent *event){this->setCursor(Qt::ArrowCursor); pressed = false; mouseState = 0;} + +private: + + //Variables of Acrylic | aero window + /****************************************************************************/ + + HWND hwnd; + HMODULE huser; + pfnSetWindowCompositionAttribute setWindowCompositionAttribute; + AdditionTabWidget* tabPage; + + Ui::Acrylic *ui; + QPoint mousePos_strt; + QColor acryBackground; + int acryOpacity; + + int _width; + int _height; + + bool isMaximum = false; + int lastWidth; + int lastHeight; + + bool pressed = false; + bool tabShown = false; + int mouseState = 0; //0 for move, 1 for width, 2 for height, 3 for width and height + + /****************************************************************************/ + + //Variables and functions for the calculator + /****************************************************************************/ + Expression expr; + void RfrInput(); + void RfrResult(); + void UpdStack(bool r = false); + void UpdHistory(); + +signals: + void addHistoryTerm(const QString &, const QString &, const QString &); + void updateStackPage(const QString &, const QString &); + +private slots: + void windowMaximum(); + //void windowMinimum(); + +}; +#endif // ACRYLIC_H diff --git a/acrylic.ui b/acrylic.ui new file mode 100644 index 0000000..8092119 --- /dev/null +++ b/acrylic.ui @@ -0,0 +1,955 @@ + + + Acrylic + + + + 0 + 0 + 549 + 511 + + + + true + + + Acrylic + + + + 0 + + + 5 + + + 5 + + + 5 + + + 5 + + + + + true + + + + 0 + 0 + + + + + 335 + 30 + + + + + 0 + 0 + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 5 + + + + + + Arita Sans Medium + 10 + + + + Calculator + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 30 + 30 + + + + + 30 + 16777215 + + + + - + + + true + + + + + + + + 0 + 0 + + + + + 30 + 30 + + + + + 30 + 16777215 + + + + + + + true + + + + + + + + 0 + 0 + + + + + 30 + 30 + + + + + 30 + 16777215 + + + + + Arita Sans + true + + + + false + + + background-color: rgba(255, 255, 255, 50); + + + x + + + + 16 + 16 + + + + false + + + true + + + + + + + + + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 5 + + + + + + 0 + 30 + + + + + 16777215 + 30 + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 10 + + + + + + 等线 + 19 + 75 + true + PreferAntialias + + + + Expression Calculator + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 16777215 + 180 + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + + 0 + 0 + + + + + 等线 + 9 + PreferAntialias + + + + true + + + + + + Qt::AlignBottom|Qt::AlignRight|Qt::AlignTrailing + + + 5 + + + + + + + + 0 + 0 + + + + + 等线 + 30 + 75 + true + PreferAntialias + + + + true + + + 0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 5 + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 310 + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 3 + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 1 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + . + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + / + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 7 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 3 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + ^ + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 0 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + = + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + * + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 8 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 6 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 5 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 2 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + + + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + - + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 4 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + 9 + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + C + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + Sqr + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + + 16777215 + 16777215 + + + + ( + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + ) + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + BackSpace + + + + + + + + 0 + 0 + + + + + 0 + 45 + + + + % + + + + + + + + + + + + + + + + + + + + + + + QTransparentButton + QPushButton +
qtransparentbutton.h
+
+
+ + + + closeWindow + clicked() + Acrylic + close() + + + 303 + 15 + + + 159 + 249 + + + + + hideWindow + clicked() + Acrylic + showMinimized() + + + 231 + 15 + + + 159 + 249 + + + + +
diff --git a/additiontabwidget.cpp b/additiontabwidget.cpp new file mode 100644 index 0000000..793303c --- /dev/null +++ b/additiontabwidget.cpp @@ -0,0 +1,216 @@ +#include "additiontabwidget.h" + +AdditionTabWidget::AdditionTabWidget(QWidget *parent) : QWidget(parent) +{ + this->setMouseTracking(true); + //this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + //initialize main layout + QVBoxLayout* mainLayout = new QVBoxLayout; + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->setSpacing(15); + this->setLayout(mainLayout); + + //initialize tab bar + //tabBar = new QWidget(this); + //QVBoxLayout* tabBarVLayout = new QVBoxLayout; + //tabBarVLayout->setContentsMargins(5, 5, 5, 5); + //tabBar->setLayout(tabBarVLayout); + iconContents = new QWidget(this); + QHBoxLayout* iconHLayout = new QHBoxLayout; + iconHLayout->setContentsMargins(0, 0, 0, 0); + iconHLayout->setSpacing(0); + iconHLayout->setAlignment(Qt::AlignLeft); + iconContents->setLayout(iconHLayout); + iconContents->setMouseTracking(true); + //tabBarVLayout->addWidget(iconContents); + + //initialize indicator + indicator = new TabIndicator(this); + indicator->resize(0, 3); + //indicator->move(-indicator->x(), iconContents->height() + 10); + //tabBarVLayout->addWidget(indicator); + + //initialize page container + pageContainer = new QWidget(this); + //QGridLayout* pageLayout = new QGridLayout; + //pageLayout->setContentsMargins(0, 0, 0, 0); + //pageContainer->setLayout(pageLayout); + pageContainer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + pageContainer->setMouseTracking(true); + + mainLayout->addWidget(iconContents); + mainLayout->addWidget(pageContainer); + + /*********************************************************/ + + /* Add your pages here + * Remember to add icon in addition to pages + * + * Add a page like this: + * ------------------------------------------------------------------ + * YourPage* newPage = new YourPage(pageContainer); + * TabIcons* newPageLabel = new TabIcons("YourPageName", iconContents); + * pages.push_back(newPage); + * tabButtons.push_back(newPageLabel); + * + * QObject::connect() if you need + * ------------------------------------------------------------------ + * And everything else just leave for the controller XD + * + */ + + HistoryPage* historyPg = new HistoryPage(pageContainer); + TabIcons* hisIcon = new TabIcons("History", iconContents); + pages.push_back(historyPg); + tabButtons.push_back(hisIcon); + //iconHLayout->addWidget(hisIcon); + //QObject::connect(hisIcon, SIGNAL(SelectPage(TabIcons*)), this, SLOT(ShiftPage(TabIcons*))); + QObject::connect(this, SIGNAL(sig_AddHistory(const QString &, const QString &, const QString &)), historyPg, SLOT(AddHistory(const QString &, const QString &, const QString &))); + + StackPage* stackPg = new StackPage(pageContainer); + TabIcons* stckIcon = new TabIcons("Stacks", iconContents); + pages.push_back(stackPg); + tabButtons.push_back(stckIcon); + //iconHLayout->addWidget(stckIcon); + //QObject::connect(stckIcon, SIGNAL(SelectPage(TabIcons*)), this, SLOT(ShiftPage(TabIcons*))); + QObject::connect(this, SIGNAL(sig_UpdateStackPage(const QString &, const QString &)), stackPg, SLOT(RfrStack(const QString &, const QString &))); + + InfoPage* infoPg = new InfoPage(pageContainer); + TabIcons* infoIcon = new TabIcons("About", iconContents); + pages.push_back(infoPg); + tabButtons.push_back(infoIcon); + + //StackPage* stackPg2 = new StackPage(pageContainer); + //TabIcons* stckIcon2 = new TabIcons("Stack2", iconContents); + //pages.push_back(stackPg2); + //tabButtons.push_back(stckIcon2); + + /*********************************************************/ + + //Initialize all pages + for(int i = 0; i < pages.size(); i++){ + pages[i]->move(0, 0); + pages[i]->resize(pageContainer->size()); + pages[i]->hide(); + } + + for(int i = 0; i < tabButtons.size(); i++){ + iconHLayout->addWidget(tabButtons[i]); + QObject::connect(tabButtons[i], SIGNAL(SelectPage(TabIcons*)), this, SLOT(ShiftPage(TabIcons*))); + } + + //Initialize default shown page and indicator + pages[0]->show(); + tabButtons[0]->SetFocus(true); + indicator->resize(tabButtons[0]->size().width() - 30, 3); + indicator->move(15, iconContents->height() + 10); + indicator->raise(); + currentPageIndex = 0; + +} + +void AdditionTabWidget::paintEvent(QPaintEvent *event){ + if(currentPageIndex != -1){ + //qDebug() << "resizing" << currentPageIndex << "\n"; + //qDebug() << "Page container:[" << pageContainer->x() << "," << pageContainer->y() << "," << pageContainer->width() << "," << pageContainer->height() << "]\n"; + //qDebug() << "this Page:[" << pages[currentPageIndex]->x() << "," << pages[currentPageIndex]->y() << "," << pages[currentPageIndex]->width() << "," << pages[currentPageIndex]->height() << "]\n"; + pages[currentPageIndex]->resize(pageContainer->size()); + //pages[currentPageIndex]->setMinimumWidth(pageContainer->width()); + //pages[currentPageIndex]->setMaximumSize(pageContainer->size()); + } + +} + +void AdditionTabWidget::ShiftPage(TabIcons* sel){ + //get index + int index = tabButtons.indexOf(sel); + if(index == currentPageIndex) + return; + + //choose new page and Add to page container + TabPage* newPage = pages[index]; + TabPage* curPage = pages[currentPageIndex]; + + //prepare for animation + QGraphicsOpacityEffect* newPageOpac = new QGraphicsOpacityEffect; + QGraphicsOpacityEffect* curPageOpac = new QGraphicsOpacityEffect; + newPageOpac->setOpacity(0); + curPageOpac->setOpacity(1); + newPage->setGraphicsEffect(newPageOpac); + curPage->setGraphicsEffect(curPageOpac); + newPage->show(); + newPage->raise(); + indicator->raise(); + QParallelAnimationGroup* switchPages = new QParallelAnimationGroup(pageContainer); + QSequentialAnimationGroup* FadeIn = new QSequentialAnimationGroup(pageContainer); + QPropertyAnimation* newPageFadeIn = new QPropertyAnimation(newPageOpac, "opacity", newPage); + QPropertyAnimation* newPageMove = new QPropertyAnimation(newPage, "pos"); + QPropertyAnimation* curPageFadeOut = new QPropertyAnimation(curPageOpac, "opacity", curPage); + QPropertyAnimation* curPageMove = new QPropertyAnimation(curPage, "pos"); + QPropertyAnimation* indicatorScale = new QPropertyAnimation(indicator, "geometry"); + if(currentPageIndex < index){ + //newPage->raise(); + newPageFadeIn->setDuration(600); + newPageFadeIn->setStartValue(0); + newPageFadeIn->setEndValue(1); + newPageFadeIn->setEasingCurve(QEasingCurve::Linear); + FadeIn->addPause(300); + FadeIn->addAnimation(newPageFadeIn); + newPageMove->setDuration(1200); + newPageMove->setStartValue(QPoint(50, newPage->y())); + newPageMove->setEndValue(QPoint(0, newPage->y())); + newPageMove->setEasingCurve(QEasingCurve::InOutQuad); + curPageFadeOut->setDuration(500); + curPageFadeOut->setStartValue(1); + curPageFadeOut->setEndValue(0); + curPageFadeOut->setEasingCurve(QEasingCurve::Linear); + curPageMove->setDuration(800); + curPageMove->setStartValue(QPoint(0, curPage->y())); + curPageMove->setEndValue(QPoint(-30, curPage->y())); + curPageMove->setEasingCurve(QEasingCurve::InOutQuad); + indicatorScale->setDuration(800); + indicatorScale->setStartValue(QRect(indicator->x(), indicator->y(), indicator->width(), indicator->height())); + indicatorScale->setEndValue(QRect(tabButtons[index]->x() + 15, indicator->y(), tabButtons[index]->size().width() - 30, indicator->height())); + indicatorScale->setEasingCurve(QEasingCurve::InOutQuad); + } + else{ + //curPage->raise(); + newPageFadeIn->setDuration(600); + newPageFadeIn->setStartValue(0); + newPageFadeIn->setEndValue(1); + newPageFadeIn->setEasingCurve(QEasingCurve::Linear); + FadeIn->addPause(300); + FadeIn->addAnimation(newPageFadeIn); + newPageMove->setDuration(1200); + newPageMove->setStartValue(QPoint(-50, newPage->y())); + newPageMove->setEndValue(QPoint(0, newPage->y())); + newPageMove->setEasingCurve(QEasingCurve::InOutQuad); + curPageFadeOut->setDuration(500); + curPageFadeOut->setStartValue(1); + curPageFadeOut->setEndValue(0); + curPageFadeOut->setEasingCurve(QEasingCurve::Linear); + curPageMove->setDuration(800); + curPageMove->setStartValue(QPoint(0, curPage->y())); + curPageMove->setEndValue(QPoint(50, curPage->y())); + curPageMove->setEasingCurve(QEasingCurve::InOutQuad); + indicatorScale->setDuration(800); + indicatorScale->setStartValue(QRect(indicator->x(), indicator->y(), indicator->width(), indicator->height())); + indicatorScale->setEndValue(QRect(tabButtons[index]->x() + 15, indicator->y(), tabButtons[index]->size().width() - 30, indicator->height())); + indicatorScale->setEasingCurve(QEasingCurve::InOutQuad); + } + switchPages->addAnimation(FadeIn); + switchPages->addAnimation(newPageMove); + switchPages->addAnimation(curPageFadeOut); + switchPages->addAnimation(curPageMove); + switchPages->addAnimation(indicatorScale); + + //start animation + switchPages->start(); + connect(switchPages,&QPropertyAnimation::finished,[=](){newPageOpac->deleteLater();}); + //indicator->resize(tabButtons[index]->size().width() - 30, indicator->height()); + tabButtons[currentPageIndex]->SetFocus(false); + currentPageIndex = index; + tabButtons[index]->SetFocus(true); + update(); +} diff --git a/additiontabwidget.h b/additiontabwidget.h new file mode 100644 index 0000000..4696a74 --- /dev/null +++ b/additiontabwidget.h @@ -0,0 +1,72 @@ +/* A simple tab widget written by Jonathan Zhang + * Github: haven't uploaded yet + * + * About this widget: + * A simple controller for different pages + * containing a tab bar to choose and a tiny indicator XD + * ALSO HAS ANIMATIONS! yes! + */ + +#ifndef ADDITIONTABWIDGET_H +#define ADDITIONTABWIDGET_H + +#include +#include +#include +#include +#include +#include "tabicons.h" +#include "tabindicator.h" +#include "tabpage.h" +#include "historypage.h" +#include "stackpage.h" +#include "infopage.h" +#include +#include +#include +#include +#include +#include + +class AdditionTabWidget : public QWidget +{ + Q_OBJECT + +private: + QVBoxLayout* widgetLayout; + //QWidget* tabBar; + QWidget* iconContents; + TabIndicator* indicator; + QWidget* pageContainer; + QVector tabButtons; + QVector pages; + int currentPageIndex = -1; + + void paintEvent(QPaintEvent* event); + +public: + explicit AdditionTabWidget(QWidget *parent = nullptr); + +signals: + /* Add Signals for pages here + * E.g. + * void YourSignal(); + */ + void sig_AddHistory(const QString &, const QString &, const QString &); + void sig_UpdateStackPage(const QString &, const QString &); + +private slots: + void ShiftPage(TabIcons* sel); + + /* Add Slots for pages here + * + * These slots are used for receiving msg from outside this controller + * Remember to emit a signal from main dialog! + * + * REMEMBER TO CHECK THIS CONTROLLER'S PARENT IS SET TO YOUR SIGNAL WIDGET + */ + void Controller_AddHistoryTerm(const QString & expStr, const QString & expStrHtml, const QString & resStrHtml){emit sig_AddHistory(expStr, expStrHtml, resStrHtml);} + void Controller_UpdateStackPage(const QString & numDif, const QString & opDif){emit sig_UpdateStackPage(numDif, opDif);} +}; + +#endif // ADDITIONTABWIDGET_H diff --git a/hashmap.cpp b/hashmap.cpp new file mode 100644 index 0000000..c5f9fc5 --- /dev/null +++ b/hashmap.cpp @@ -0,0 +1,68 @@ +#include "hashmap.h" + +HashMap::HashMap() : size(DEFAULT_MAP_SIZE) +{ + headList = new struct hashNode[size]; +} + +HashMap::HashMap(int _size) : size(_size) +{ + headList = new struct hashNode[size]; +} + +HashMap::~HashMap(){ + for(int i = 0; i < size; i++){ + delete headList[i].next; + } + delete [] headList; +} + +int HashMap::hashAddr(char key){ + return key % 10; +} + +struct hashNode* HashMap::find(char key){ + int addr = hashAddr(key); + struct hashNode* ptr = headList[addr].next; + while(ptr != nullptr){ + if(ptr->key == key) + return ptr; + ptr = ptr->next; + } + return ptr; +} + +bool HashMap::insert(char key, int val){ + struct hashNode* ptr = find(key); + if(ptr == nullptr){ + int addr = hashAddr(key); + struct hashNode* newNode = new struct hashNode(key, val); + newNode->next = headList[addr].next; + headList[addr].next = newNode; + return true; + } + else + return false; +} + +int HashMap::getVal(char key){ + struct hashNode* ptr = find(key); + if(ptr == nullptr) + return -1; + else + return ptr->val; +} + +int HashMap::operator[](char key){ + return getVal(key); +} + +void initOpMap(){ + opMap.insert('+', 0); + opMap.insert('-', 0); + opMap.insert('*', 1); + opMap.insert('/', 1); + opMap.insert('%', 1); + opMap.insert('^', 2); + opMap.insert('.', 3); +} diff --git a/hashmap.h b/hashmap.h new file mode 100644 index 0000000..fba8d73 --- /dev/null +++ b/hashmap.h @@ -0,0 +1,34 @@ +#ifndef HASHMAP_H +#define HASHMAP_H + +#define DEFAULT_MAP_SIZE 10 + +struct hashNode{ + char key; + int val; + struct hashNode* next; + hashNode() : next(nullptr){} + hashNode(char _key, int _val) : key(_key), val(_val), next(nullptr){} + ~hashNode(){if(next == nullptr) return; else delete next;} +}; + +class HashMap +{ +private: + int size; + struct hashNode* headList; + int hashAddr(char key); + struct hashNode* find(char key); +public: + HashMap(); + HashMap(int size); + ~HashMap(); + bool insert(char key, int val); + int getVal(char key); + int operator [](char key); //equals to getVal +}; + +extern HashMap opMap; +void initOpMap(); + +#endif // HASHMAP_H diff --git a/historypage.cpp b/historypage.cpp new file mode 100644 index 0000000..190145d --- /dev/null +++ b/historypage.cpp @@ -0,0 +1,38 @@ +#include "historypage.h" + +HistoryPage::HistoryPage(QWidget* parent) : TabPage(parent) +{ + this->setMouseTracking(true); + QVBoxLayout* pageLayout = new QVBoxLayout; + pageLayout->setContentsMargins(0, 0, 0, 0); + this->setLayout(pageLayout); + scrollArea = new ScrollAreaCustom(this); + pageLayout->addWidget(scrollArea); +} + +void HistoryPage::AddHistory(const QString & expStr, const QString & expStrHtml, const QString & resStrHtml){ + QWidget* newHistoryTerm = new QWidget(this); + //newHistoryTerm->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); + QVBoxLayout* newLayout = new QVBoxLayout; + newHistoryTerm->setLayout(newLayout); + QLabel* expLabel = new QLabel(newHistoryTerm); + expLabel->setTextFormat(Qt::RichText); + expLabel->setAlignment(Qt::AlignRight | Qt::AlignBottom); + expLabel->setFont(QFont("DengXian", 10)); + expLabel->setAttribute(Qt::WA_TransparentForMouseEvents); + QString expStrCpy = expStrHtml; + expLabel->setText(expStrCpy.append('=')); + QLabel* resLabel = new QLabel(newHistoryTerm); + //resLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + resLabel->setTextFormat(Qt::RichText); + resLabel->setAlignment(Qt::AlignRight | Qt::AlignBottom); + resLabel->setAttribute(Qt::WA_TransparentForMouseEvents); + QFont font("DengXian", 20); + font.setBold(true); + resLabel->setFont(font); + resLabel->setText(resStrHtml); + newHistoryTerm->resize(newHistoryTerm->width(), expLabel->height() + resLabel->height() + 20); + newLayout->addWidget(expLabel); + newLayout->addWidget(resLabel); + scrollArea->addWidget(newHistoryTerm); +} diff --git a/historypage.h b/historypage.h new file mode 100644 index 0000000..c3baeff --- /dev/null +++ b/historypage.h @@ -0,0 +1,26 @@ +#ifndef HISTORYPAGE_H +#define HISTORYPAGE_H + +#include "tabpage.h" +#include +#include +#include +#include +#include +#include "scrollareacustom.h" + +class HistoryPage : public TabPage +{ + Q_OBJECT + +private: + ScrollAreaCustom* scrollArea; + +public: + HistoryPage(QWidget* parent = nullptr); + +private slots: + void AddHistory(const QString & expStr, const QString & expStrHtml, const QString & resStrHtml); +}; + +#endif // HISTORYPAGE_H diff --git a/infopage.cpp b/infopage.cpp new file mode 100644 index 0000000..a0fb575 --- /dev/null +++ b/infopage.cpp @@ -0,0 +1,28 @@ +#include "infopage.h" + +InfoPage::InfoPage(QWidget* parent) : TabPage(parent) +{ + QVBoxLayout* mainLayout = new QVBoxLayout; + mainLayout->setContentsMargins(0, 0, 0, 0); + this->setLayout(mainLayout); + mainLayout->setAlignment(Qt::AlignCenter); + QTextBrowser* InfoBrowser = new QTextBrowser(this); + InfoBrowser->setHtml("

\ + About This Application:\ +

\ +

\ + Author: Jonathan Zhang ( Linloir ) \ +

\ +

\ + Version: 1.0\ +

\ +

\ + GitHub: https://github.com/Linloir\ +

\ +

\ +
\ +

"); + InfoBrowser->setStyleSheet("background:transparent;border-width:0;border-style:outset"); + InfoBrowser->setOpenExternalLinks(true); + mainLayout->addWidget(InfoBrowser); +} diff --git a/infopage.h b/infopage.h new file mode 100644 index 0000000..e94b1b8 --- /dev/null +++ b/infopage.h @@ -0,0 +1,17 @@ +#ifndef INFOPAGE_H +#define INFOPAGE_H + +#include "tabpage.h" +#include +#include +#include +#include + +class InfoPage : public TabPage +{ + Q_OBJECT +public: + InfoPage(QWidget* parent = nullptr); +}; + +#endif // INFOPAGE_H diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..a7542aa --- /dev/null +++ b/main.cpp @@ -0,0 +1,15 @@ +#include "acrylic.h" + +#include + +HashMap opMap; + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + Acrylic w; + w.setWindowFlags(Qt::FramelessWindowHint); + w.setAttribute(Qt::WA_TranslucentBackground); + w.show(); + return a.exec(); +} diff --git a/qtransparentbutton.cpp b/qtransparentbutton.cpp new file mode 100644 index 0000000..ef240f3 --- /dev/null +++ b/qtransparentbutton.cpp @@ -0,0 +1,62 @@ +#include "qtransparentbutton.h" + +QTransparentButton::QTransparentButton(QWidget* parent) : QPushButton(parent) +{ + bgColor = bgColor_default; + buttonText = this->text(); +} + +void QTransparentButton::paintEvent(QPaintEvent *event){ + QPainter bgPainter(this); + bgPainter.setPen(Qt::NoPen); + bgPainter.setBrush(bgColor); + bgPainter.drawRect(this->rect()); + buttonText = this->text(); + + + //QPainter test(this); + //test.setPen(Qt::SolidLine); + //test.setBrush(Qt::NoBrush); + + QPainter textPainter(this); + QFont textFont("FuturaNo2D", 14); + textPainter.setFont(textFont); + int widthOfText = textPainter.fontMetrics().size(Qt::TextSingleLine, buttonText).width(); + int heightOfText = textPainter.fontMetrics().ascent() - textPainter.fontMetrics().descent() + textPainter.fontMetrics().leading(); + //test.drawRect(this->width() / 2 - widthOfText / 2, this->height() / 2 - heightOfText / 2, widthOfText, heightOfText); + textPainter.drawText(this->width() / 2 - widthOfText / 2, this->height() / 2 + heightOfText / 2, buttonText); +} + +void QTransparentButton::enterEvent(QEnterEvent *event){ + bgColor = bgColor_Hover; + update(); +} + +void QTransparentButton::leaveEvent(QEvent *event){ + bgColor = bgColor_default; + update(); +} + +void QTransparentButton::mousePressEvent(QMouseEvent *event){ + emit clicked(); + bgColor = bgColor_Clicked; + update(); +} + +void QTransparentButton::mouseReleaseEvent(QMouseEvent *event){ + bgColor = bgColor_Hover; + update(); +} + +void QTransparentButton::setColor(QColor c){ + bgColor_default = c; + bgColor = bgColor_default; +} + +void QTransparentButton::setHoverColor(QColor c){ + bgColor_Hover = c; +} + +void QTransparentButton::setClickedColor(QColor c){ + bgColor_Clicked = c; +} diff --git a/qtransparentbutton.h b/qtransparentbutton.h new file mode 100644 index 0000000..c66cc54 --- /dev/null +++ b/qtransparentbutton.h @@ -0,0 +1,35 @@ +#ifndef QTRANSPARENTBUTTON_H +#define QTRANSPARENTBUTTON_H + +#include +#include +#include +#include +#include + +class QTransparentButton : public QPushButton +{ + Q_OBJECT + +protected: + void paintEvent(QPaintEvent* event); + void enterEvent(QEnterEvent *event); + void leaveEvent(QEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + +private: + QString buttonText; + QColor bgColor; + QColor bgColor_default = QColor(255, 255, 255, 220); + QColor bgColor_Hover = QColor(190, 190, 190, 70); + QColor bgColor_Clicked = QColor(170, 170, 170, 70); + +public: + QTransparentButton(QWidget* parent = nullptr); + void setColor(QColor c); + void setClickedColor(QColor c); + void setHoverColor(QColor c); +}; + +#endif // QTRANSPARENTBUTTON_H diff --git a/scrollareacustom.cpp b/scrollareacustom.cpp new file mode 100644 index 0000000..19a2591 --- /dev/null +++ b/scrollareacustom.cpp @@ -0,0 +1,244 @@ +#include "scrollareacustom.h" + +ScrollAreaCustom::ScrollAreaCustom(QWidget *parent) : QWidget(parent) +{ + //initialize list container and timer + container = new ScrollListContainer(this); + container->move(0, 0); + container->resize(this->width(), 3); + //container->setMinimumWidth(this->width()); + //container->setMaximumWidth(this->width()); + getCord = new QTimer; + getCord->setSingleShot(true); + rfrshView = new QTimer; + getCord->setSingleShot(true); + + indicator = new ScrollIndicator(this); + indicator->resize(indicator->width(), (int)((double)this->height() * this->height() / (double)container->height())); + indicator->move(this->width() - indicator->width() - 3, 0); + + this->setMouseTracking(true); + container->setMouseTracking(true); + indicator->setMouseTracking(true); + + bounce = new QPropertyAnimation(container, "pos"); + + QObject::connect(getCord, SIGNAL(timeout()), this, SLOT(updateSpd())); + QObject::connect(rfrshView, SIGNAL(timeout()), this, SLOT(scrollContainer())); + QObject::connect(indicator, SIGNAL(scrollPage(int)), this, SLOT(scrollIndicator(int))); +} + +void ScrollAreaCustom::paintEvent(QPaintEvent *event){ + //keep container the same size as parent widget + //qDebug() << "scrollAreaWidth:[" << this->x() << "," << this->y() << "," << this->width() << "," << this->height() << "]\n"; + //qDebug() << "containerWidth:[" << container->x() << "," << container->y() << "," << container->width() << "," << container->height() << "]\n"; + //qDebug() << "speed:" << curSpd << "\n"; + //container->setMinimumWidth(this->width()); + //container->setMaximumWidth(this->width()); + container->resize(this->width(), container->height()); + if(container->height() > this->height() && container->y() < this->height() - container->height() && curSpd == 0 && bounce->state() == QAbstractAnimation::Stopped) + container->move(container->x(), this->height() - container->height()); + if(container->height() <= this->height()){ + container->move(container->x(), 0); + indicator->hide(); + } + else{ + indicator->show(); + } + indicator->resize(indicator->width(), (int)((double)this->height() * this->height() / (double)container->height())); + indicator->move(this->width() - indicator->width() - 3, -container->y() * this->height() / container->height()); +} + +void ScrollAreaCustom::mousePressEvent(QMouseEvent *event){ + if(container->height() > this->height()){ + if(container->y() <= 0 && container->y() + container->height() >= this->height()) + pressed = true; + lastY = event->pos().y(); + } + getCord->stop(); + rfrshView->stop(); + curSpd = 0; + outOfEdge = false; + moveStored = 0; + nextMove = 1; +} + +void ScrollAreaCustom::mouseMoveEvent(QMouseEvent *event){ + setCursor(Qt::ArrowCursor); + if(pressed){ + //qDebug() << "move\n"; + //start scroll + if(!getCord->isActive() && event->pos().y() - lastY != 0){ + //start 30ms timer + //qDebug() << "timer Start\n"; + getCord->start(30); + strtY = event->pos().y(); + } + if(container->y() <= 0 && container->y() + container->height() >= this->height()){ + //qDebug() << "in\n" ; + container->move(container->x(), container->y() + event->pos().y() - lastY); + //qDebug() << -container->y() * this->height() / container->height() << "\n"; + } + else{ + //qDebug() << "outOfEdge\n"; + //qDebug() << event->pos().y() << "\n"; + //qDebug() << "nextMove:" << nextMove << "Stored: " << moveStored << "\n"; + if(!outOfEdge){ + bfEdgeY = event->pos().y(); + container->move(container->x(), container->y() + event->pos().y() - lastY); + outOfEdge = true; + } + else{ + //qDebug() << "Damp\n" << "bfEdgeY: " << bfEdgeY << "\n"; + int pos = container->y() >= 0 ? 1 : -1; + //qDebug() << "pos:" << pos << "\n"; + int dp = event->pos().y() - bfEdgeY; + if(dp == 0){ + outOfEdge = false; + nextMove = 1; + moveStored = 0; + if(container->y() >= 0) + container->move(container->x(), 0); + else + container->move(container->x(), this->height() - container->height()); + } + else if(dp / abs(dp) != pos){ + //qDebug() << "X"; + outOfEdge = false; + + container->move(container->x(), this->y() + event->pos().y() - bfEdgeY); + nextMove = 1; + moveStored = 0; + } + else{ + while(abs(moveStored) + nextMove <= abs(event->pos().y() - bfEdgeY)){ + //qDebug() << "add\n"; + moveStored += nextMove * pos; + container->move(container->x(), container->y() + pos); + nextMove++; + } + while(nextMove > 1 && abs(moveStored) > abs(event->pos().y() - bfEdgeY)){ + //qDebug() << "dec\n"; + nextMove--; + moveStored -= nextMove * pos; + container->move(container->x(), container->y() - pos); + } + if(moveStored == 0){ + outOfEdge = false; + if(container->y() >= 0) + container->move(container->x(), 0); + else + container->move(container->x(), this->height() - container->height()); + nextMove = 1; + moveStored = 0; + } + } + } + } + lastY = event->pos().y(); + } +} + +void ScrollAreaCustom::mouseReleaseEvent(QMouseEvent *event){ + //start scrolling + //qDebug() << "mouseRelease\n"; + if(container->y() > 0 || container->y() + container->height() < this->height()) + bounceBack(); + else + rfrshView->start(30); + pressed = false; +} + +void ScrollAreaCustom::bounceBack(){ + rfrshView->stop(); + getCord->stop(); + bounce->setDuration(500); + bounce->setStartValue(container->pos()); + if(container->y() > 0) + bounce->setEndValue(QPoint(container->x(), 0)); + else + bounce->setEndValue(QPoint(container->x(), this->height() - container->height())); + bounce->setEasingCurve(QEasingCurve::OutQuad); + bounce->start(); +} + +void ScrollAreaCustom::scrollContainer(){ + //scroll + if(curSpd > 0){ + if(curSpd > MAXSPEED) + curSpd = MAXSPEED; + int dp = scrollDown ? curSpd : -curSpd; + container->move(container->x(), container->y() + dp); + } + else + return; + if(container->y() <= 0 && container->y() + container->height() >= this->height()){ + curSpd -= damp; + curSpd = curSpd < 0 ? 0 : curSpd; + } + else + curSpd /= 2; + if(curSpd == 0 && (container->y() > 0 || container->y() + container->height() < this->height())) + bounceBack(); + else + rfrshView->start(30); + + //qDebug() << "spd2:" << curSpd << "\n"; +} + +void ScrollAreaCustom::updateSpd(){ + int spd = lastY - strtY; + //qDebug() << "spd:" << spd << "\n"; + scrollDown = spd >= 0; + strtY = lastY; + curSpd = abs(spd); +} + +void ScrollAreaCustom::addWidget(QWidget *newWidget){ + newWidget->setParent(container); + container->AddWidget(newWidget); +} + +void ScrollAreaCustom::removeWidget(QWidget *w){ + //container->layout()->removeWidget(w); + + //qDebug() << "good\n"; + container->RemoveWidget(w); +} + +void ScrollAreaCustom::clear(){ + container->clear(); +} + +void ScrollAreaCustom::scrollIndicator(int dp){ + //qDebug() << "dp=" << dp << "\n"; + int newY = container->y() - dp * container->height() / this->height(); + if(newY > 0) + newY = 0; + else if(newY < this->height() - container->height()) + newY = this->height() - container->height(); + container->move(container->x(), newY); + update(); +} + +void ScrollAreaCustom::wheelEvent(QWheelEvent *event){ + //qDebug() << "wheel" << event->angleDelta().y() * 100 / 360 << "\n"; + //int newY = container->y() + event->angleDelta().y() * 100 / 360 * container->height() / this->height(); + //if(newY > 0) + // newY = 0; + //else if(newY < this->height() - container->height()) + // newY = this->height() - container->height(); + //container->move(container->x(), newY); + if(container->y() > 0 || container->y() + container->height() < this->height()) + return; + curSpd += 5; + bool newDirection = event->angleDelta().y() > 0; + if(newDirection != scrollDown) + curSpd = 5; + if(curSpd > MAXSPEED) + curSpd = MAXSPEED; + scrollDown = newDirection; + if(!rfrshView->isActive()) + rfrshView->start(30); + update(); +} diff --git a/scrollareacustom.h b/scrollareacustom.h new file mode 100644 index 0000000..1570588 --- /dev/null +++ b/scrollareacustom.h @@ -0,0 +1,68 @@ +#ifndef SCROLLAREACUSTOM_H +#define SCROLLAREACUSTOM_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "scrolllistcontainer.h" +#include "scrollindicator.h" +#include +#include + +#define MAXSPEED 50 + +class ScrollAreaCustom : public QWidget +{ + Q_OBJECT + +private: + QTimer* getCord; + QTimer* rfrshView; + + ScrollListContainer* container; + ScrollIndicator* indicator; + + QPropertyAnimation* bounce; + + bool pressed = false; + bool scrollDown = true; + bool outOfEdge = false; + + int strtY; + int lastY; + int bfEdgeY; //last y value before out of edge + + int curSpd = 0; + int damp = 1; + int moveStored = 0; + int nextMove = 1; + + void paintEvent(QPaintEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + void wheelEvent(QWheelEvent* event); + void bounceBack(); + + +public: + explicit ScrollAreaCustom(QWidget *parent = nullptr); + void addWidget(QWidget* newWidget); + void removeWidget(QWidget* w = nullptr); + void clear(); + +signals: + +private slots: + void scrollContainer(); + void updateSpd(); + void scrollIndicator(int dp); + +}; + +#endif // SCROLLAREACUSTOM_H diff --git a/scrollcontainer.cpp b/scrollcontainer.cpp new file mode 100644 index 0000000..45fdbbf --- /dev/null +++ b/scrollcontainer.cpp @@ -0,0 +1,6 @@ +#include "scrollcontainer.h" + +ScrollContainer::ScrollContainer(QWidget *parent) : QWidget(parent) +{ + +} diff --git a/scrollcontainer.h b/scrollcontainer.h new file mode 100644 index 0000000..b7f1b77 --- /dev/null +++ b/scrollcontainer.h @@ -0,0 +1,17 @@ +#ifndef SCROLLCONTAINER_H +#define SCROLLCONTAINER_H + +#include +#include +#include + +class ScrollContainer : public QWidget +{ + Q_OBJECT +public: + explicit ScrollContainer(QWidget *parent = nullptr); +signals: + +}; + +#endif // SCROLLCONTAINER_H diff --git a/scrollindicator.cpp b/scrollindicator.cpp new file mode 100644 index 0000000..6e4b55b --- /dev/null +++ b/scrollindicator.cpp @@ -0,0 +1,76 @@ +#include "scrollindicator.h" + +ScrollIndicator::ScrollIndicator(QWidget *parent) : QWidget(parent) +{ + this->resize(defaultWidth, 0); + hovTimer = new QTimer(this); + hovTimer->setSingleShot(true); + aniPause = new QTimer(this); + aniPause->setSingleShot(true); + QObject::connect(hovTimer, SIGNAL(timeout()), this, SLOT(setHoverActive())); + this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + this->curColor = defaultColor; + + this->setMouseTracking(true); +} + +void ScrollIndicator::paintEvent(QPaintEvent *event){ + QPainter painter(this); + painter.setPen(Qt::NoPen); + painter.setBrush(curColor); + painter.drawRect(this->rect()); +} + +void ScrollIndicator::enterEvent(QEnterEvent *event){ + if(!pressed){ + hovTimer->start(100); + curColor = hoverColor; + update(); + } +} + +void ScrollIndicator::leaveEvent(QEvent *event){ + //qDebug() << "leave"; + hovTimer->stop(); + curColor = defaultColor; + QPropertyAnimation* narrow = new QPropertyAnimation(this, "geometry"); + narrow->setDuration(300); + narrow->setStartValue(QRect(this->x(), this->y(), this->width(), this->height())); + narrow->setEndValue(QRect(this->parentWidget()->width() - margin - defaultWidth, this->y(), defaultWidth, this->height())); + narrow->setEasingCurve(QEasingCurve::InOutQuad); + narrow->start(QAbstractAnimation::DeleteWhenStopped); + aniPause->start(300); + update(); +} + +void ScrollIndicator::mousePressEvent(QMouseEvent *event){ + //qDebug() << "press\n"; + curColor = pressColor; + pressed = true; + lastY = event->globalPos().y(); + update(); +} + +void ScrollIndicator::mouseMoveEvent(QMouseEvent *event){ + if(pressed && !aniPause->isActive()){ + int dp = event->globalPos().y() - lastY; + emit scrollPage(dp); + lastY = event->globalPos().y(); + } +} + +void ScrollIndicator::mouseReleaseEvent(QMouseEvent *event){ + pressed = false; + curColor = hoverColor; + update(); +} + +void ScrollIndicator::setHoverActive(){ + QPropertyAnimation* widen = new QPropertyAnimation(this, "geometry"); + widen->setDuration(300); + widen->setStartValue(QRect(this->x(), this->y(), this->width(), this->height())); + widen->setEndValue(QRect(this->parentWidget()->width() - margin - defaultWidthAtFocus, this->y(), defaultWidthAtFocus, this->height())); + widen->setEasingCurve(QEasingCurve::InOutQuad); + widen->start(QAbstractAnimation::DeleteWhenStopped); + aniPause->start(300); +} diff --git a/scrollindicator.h b/scrollindicator.h new file mode 100644 index 0000000..512a096 --- /dev/null +++ b/scrollindicator.h @@ -0,0 +1,51 @@ +#ifndef SCROLLINDICATOR_H +#define SCROLLINDICATOR_H + +#include +#include +#include +#include +#include +#include + +class ScrollIndicator : public QWidget +{ + Q_OBJECT + +private: + QColor curColor; + QColor defaultColor = QColor(100, 100, 100, 130); + QColor hoverColor = QColor(70, 70, 70, 150); + QColor pressColor = QColor(50, 50, 50, 170); + + QTimer* hovTimer; + QTimer* aniPause; + + int lastY; + + int defaultWidth = 2; + int defaultWidthAtFocus = 9; + int margin = 3; + + bool pressed = false; + +public: + explicit ScrollIndicator(QWidget *parent = nullptr); + +private: + void paintEvent(QPaintEvent* event); + void enterEvent(QEnterEvent* event); + void leaveEvent(QEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + +signals: + void scrollPage(int); + +private slots: + void setHoverActive(); + +}; + +#endif // SCROLLINDICATOR_H diff --git a/scrolllistcontainer.cpp b/scrolllistcontainer.cpp new file mode 100644 index 0000000..11ea8e0 --- /dev/null +++ b/scrolllistcontainer.cpp @@ -0,0 +1,155 @@ +#include "scrolllistcontainer.h" + +ScrollListContainer::ScrollListContainer(QWidget *parent) : QWidget(parent) +{ + //QVBoxLayout* mainLayout = new QVBoxLayout; + //this->setLayout(mainLayout); + //mainLayout->setContentsMargins(0, 0, 0, 0); + //this->setLayout(nullptr); + //newWidgetFade = new QTimer(this); + //newWidgetFade->setSingleShot(true); + //QObject::connect(newWidgetFade, SIGNAL(timsout()), this, SLOT(fadeIn())); + //QWidget* nullWidget = new QWidget(this); + //ys.push_back(1); + //widgets.push_back(nullWidget); + //nullWidget->resize(this->width(), 1); +} + +void ScrollListContainer::paintEvent(QPaintEvent *event){ + for(int i = 0; i < widgets.size(); i++){ + widgets[i]->resize(this->width(), widgets[i]->height()); + } +} + +void ScrollListContainer::AddWidget(QWidget *widget){ + //Add animation for all widgets current + + //qDebug() << "Adding2" << "\n"; + this->resize(this->width(), this->height() + widget->height() + spacing); + //qDebug() << "containerHeight:" << this->height() << "\n"; + widgets.push_back(widget); + size++; + //qDebug() << "current widgets size (i): " << widgets.size() << "\n"; + ys.push_back(0); + //qDebug() << "Widget wh" << widget->width() << "," << widget->height() << "\n"; + //qDebug() << "Widget xy" << widget->x() << "," << widget->y() << "\n"; + //widget->setParent(this); + widget->resize(this->width(), widget->height()); + widget->show(); + QGraphicsOpacityEffect* widgetOpac = new QGraphicsOpacityEffect(widget); + widgetOpac->setOpacity(0); + widget->setGraphicsEffect(widgetOpac); + //this->layout()->addWidget(widget); + QParallelAnimationGroup* dpGroup = new QParallelAnimationGroup; + QSequentialAnimationGroup* newWidgetFadeIn = new QSequentialAnimationGroup; + //for(int i = 0; i < widgets.size() - 1; i++){ + for(int i = 0; i < size - 1; i++){ + ys[i] += widget->height() + spacing; + QPropertyAnimation* move = new QPropertyAnimation(widgets[i], "pos"); + move->setDuration(750); + move->setStartValue(widgets[i]->pos()); + move->setEndValue(QPoint(widgets[i]->x(), ys[i])); + move->setEasingCurve(QEasingCurve::InOutQuart); + dpGroup->addAnimation(move); + } + newWidgetFadeIn->addPause(300); + QPropertyAnimation* fade = new QPropertyAnimation(widgetOpac, "opacity", widget); + fade->setDuration(300); + fade->setStartValue(0); + fade->setEndValue(1); + newWidgetFadeIn->addAnimation(fade); + dpGroup->addAnimation(newWidgetFadeIn); + dpGroup->start(); + connect(dpGroup, &QPropertyAnimation::stateChanged, [=](){ + if(dpGroup->state() == QAbstractAnimation::Stopped){ + if(widgetOpac->opacity() != 1){ + fade->start(QAbstractAnimation::DeleteWhenStopped); + connect(fade,&QPropertyAnimation::finished,[=](){widgetOpac->deleteLater();}); + //qDebug() << "paused\n"; + } + else{ + dpGroup->deleteLater(); + widgetOpac->deleteLater(); + } + } + }); + +} + +void ScrollListContainer::RemoveWidget(QWidget *widget){ + int index; + if(widget == nullptr){ + index = size - 1; + if(index != -1) + widget = widgets[index]; + } + else + index = widgets.indexOf(widget); + if(index == -1 || widget == nullptr){ + //qDebug() << "returnning"; + return; + } + //qDebug() << "deleting index:" << index << "\n"; +// QGraphicsOpacityEffect* widgetOpac = new QGraphicsOpacityEffect(widget); +// widgetOpac->setOpacity(1); +// widget->setGraphicsEffect(widgetOpac); + //this->layout()->addWidget(widget); + this->resize(this->width(), this->height() - widget->height() - spacing); + this->parentWidget()->update(); + widget->hide(); + widget->setParent(nullptr); +// widget->deleteLater(); + QParallelAnimationGroup* dpGroup = new QParallelAnimationGroup; +// QSequentialAnimationGroup* oldWidgetFadeOut = new QSequentialAnimationGroup; + for(int i = index - 1; i >= 0; i--){ + //qDebug() << "adding Posani to index:" << i << "\n"; + ys[i] -= (widget->height() + spacing); + QPropertyAnimation* move = new QPropertyAnimation(widgets[i], "pos"); + move->setDuration(750); + move->setStartValue(widgets[i]->pos()); + move->setEndValue(QPoint(widgets[i]->x(), ys[i])); + move->setEasingCurve(QEasingCurve::InOutQuart); + dpGroup->addAnimation(move); + } +// oldWidgetFadeOut->addPause(300); +// QPropertyAnimation* fade = new QPropertyAnimation(widgetOpac, "opacity", widget); +// fade->setDuration(300); +// fade->setStartValue(1); +// fade->setEndValue(0); +// oldWidgetFadeOut->addAnimation(fade); +// dpGroup->addAnimation(oldWidgetFadeOut); + dpGroup->start(QAbstractAnimation::DeleteWhenStopped); + widgets.remove(index); + size--; +// qDebug() << "current widgets size (o): " << widgets.size() << "\n"; + ys.remove(index); + //qDebug() << "[f]size: " << size << "\n"; +// connect(dpGroup, &QPropertyAnimation::stateChanged, [=](){ +// if(dpGroup->state() == QAbstractAnimation::Stopped){ +// if(widgetOpac->opacity() != 0){ +// fade->start(QAbstractAnimation::DeleteWhenStopped); +// connect(fade,&QPropertyAnimation::finished,[=](){ +// widgetOpac->deleteLater(); +// dpGroup->deleteLater(); +// widget->setParent(nullptr); +// widget->deleteLater();}); +// //qDebug() << "paused\n"; +// } +// else{ +// dpGroup->deleteLater(); +// widgetOpac->deleteLater(); +// widget->setParent(nullptr); +// widget->deleteLater(); +// } +// } +// }); +} + +void ScrollListContainer::clear(){ + //qDebug() << "size:" << size << "\n"; + int n = size; + for(int i = 0; i < n; i++){ + //qDebug() << "[D]size:" << size << "\n"; + RemoveWidget(); + } +} diff --git a/scrolllistcontainer.h b/scrolllistcontainer.h new file mode 100644 index 0000000..258ff36 --- /dev/null +++ b/scrolllistcontainer.h @@ -0,0 +1,39 @@ +#ifndef SCROLLLISTCONTAINER_H +#define SCROLLLISTCONTAINER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class ScrollListContainer : public QWidget +{ + Q_OBJECT +public: + explicit ScrollListContainer(QWidget *parent = nullptr); + void AddWidget(QWidget* widget); + void RemoveWidget(QWidget* widget = nullptr); + void clear(); + //void RemoveWidget(QWidget* widget); + +private: + //QTimer* newWidgetFade; + int spacing = 3; + QVector widgets; + int size = 0; + QVector ys; + + void paintEvent(QPaintEvent* event); + +signals: + +private slots: + +}; + +#endif // SCROLLLISTCONTAINER_H diff --git a/stackpage.cpp b/stackpage.cpp new file mode 100644 index 0000000..1ec55cc --- /dev/null +++ b/stackpage.cpp @@ -0,0 +1,104 @@ +#include "stackpage.h" + +StackPage::StackPage(QWidget* parent) : TabPage(parent) +{ + this->setMouseTracking(true); + //this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + QVBoxLayout* mainLayout = new QVBoxLayout; + mainLayout->setContentsMargins(0, 0, 0, 0); + this->setLayout(mainLayout); + + QLabel* labNum = new QLabel; + QFont labFont("DengXian", 13); + labFont.setBold(true); + labNum->setText("Num Stack"); + labNum->setFont(labFont); + labNum->setAlignment(Qt::AlignRight | Qt::AlignTop); + labNum->setStyleSheet("color:#E75E5E5E;"); + labNum->setMaximumHeight(20); + mainLayout->addWidget(labNum); + + numStackScrollArea = new ScrollAreaCustom(this); + mainLayout->addWidget(numStackScrollArea); + + QLabel* labOp = new QLabel; + labFont.setBold(true); + labOp->setText("Operator Stack"); + labOp->setFont(labFont); + labOp->setAlignment(Qt::AlignRight | Qt::AlignTop); + labOp->setStyleSheet("color:#E75E5E5E;"); + labOp->setMaximumHeight(20); + mainLayout->addWidget(labOp); + + opStackScrollArea = new ScrollAreaCustom(this); + mainLayout->addWidget(opStackScrollArea); + + //qDebug() << "StackPageWidth:[" << this->x() << "," << this->y() << "," << this->width() << "," << this->height() << "]\n"; +} + +void StackPage::RfrStack(const QString & numDif, const QString & opDif){ + //qDebug() << "Rfr p1\n"; + QString numDifCpy = numDif; + if(!numDif.isEmpty()){ + QTextStream numStream(&numDifCpy); + if(numDif[0] == 'r'){ + numStackScrollArea->clear(); + numDifCpy.remove(0, 1); + } + while(!numStream.atEnd()){ + char op; + numStream >> op; + if(op == 'o'){ + numStackScrollArea->removeWidget(); + } + else if(op == 'i'){ + double num; + numStream >> num; + QLabel* newNum = new QLabel; + QFont font("DengXian", 20); + font.setBold(true); + newNum->setFont(font); + newNum->setAlignment(Qt::AlignRight); + newNum->resize(newNum->width(), 30); + newNum->setText(QString::asprintf("%g", num)); + numStackScrollArea->addWidget(newNum); + } + } + } + QString opDifCpy = opDif; + if(!opDif.isEmpty()){ + QTextStream opStream(&opDifCpy); + if(opDif[0] == 'r'){ + opStackScrollArea->clear(); + opDifCpy.remove(0, 1); + } + while(!opStream.atEnd()){ + //qDebug() << "opStream" << "\n"; + char op; + opStream >> op; + //qDebug() << "op = " << op << "\n"; + if(op == 'o'){ + opStackScrollArea->removeWidget(); + } + else if(op == 'i'){ + char c; + opStream >> c; + //qDebug() << c << "\n"; + QLabel* newChar = new QLabel; + QFont font("DengXian", 20); + font.setBold(false); + newChar->setFont(font); + newChar->setAlignment(Qt::AlignRight); + newChar->resize(newChar->width(), 30); + newChar->setText(QString::asprintf("%c", c)); + opStackScrollArea->addWidget(newChar); + } + } + } +} + +void StackPage::paintEvent(QPaintEvent *event){ + //newScrollArea->setMinimumWidth(this->width()); + //newScrollArea->setMinimumHeight(this->height()); + //newScrollArea->resize(this->size()); +} diff --git a/stackpage.h b/stackpage.h new file mode 100644 index 0000000..b6286bd --- /dev/null +++ b/stackpage.h @@ -0,0 +1,30 @@ +#ifndef STACKPAGE_H +#define STACKPAGE_H + +#include "tabpage.h" +#include +#include +#include +#include +#include +#include +#include "scrollareacustom.h" +#include "qtransparentbutton.h" + +class StackPage : public TabPage +{ + Q_OBJECT +public: + StackPage(QWidget* parent = nullptr); + +private: + ScrollAreaCustom* numStackScrollArea; + ScrollAreaCustom* opStackScrollArea; + + void paintEvent(QPaintEvent* event); + +private slots: + void RfrStack(const QString &, const QString &); +}; + +#endif // STACKPAGE_H diff --git a/tabbar.cpp b/tabbar.cpp new file mode 100644 index 0000000..53e2d04 --- /dev/null +++ b/tabbar.cpp @@ -0,0 +1,6 @@ +#include "tabbar.h" + +TabBar::TabBar(QWidget *parent) : QWidget(parent) +{ + +} diff --git a/tabbar.h b/tabbar.h new file mode 100644 index 0000000..361f30c --- /dev/null +++ b/tabbar.h @@ -0,0 +1,16 @@ +#ifndef TABBAR_H +#define TABBAR_H + +#include + +class TabBar : public QWidget +{ + Q_OBJECT +public: + explicit TabBar(QWidget *parent = nullptr); + +signals: + +}; + +#endif // TABBAR_H diff --git a/tabicons.cpp b/tabicons.cpp new file mode 100644 index 0000000..47debab --- /dev/null +++ b/tabicons.cpp @@ -0,0 +1,78 @@ +#include "tabicons.h" + +TabIcons::TabIcons(QWidget* parent): QPushButton(parent) +{ + this->setMouseTracking(true); + QFont textFont; + textFont.setFamily("FuturaNo2DMed"); + textFont.setPointSize(15); + QFontMetrics fm(textFont); + this->setMinimumSize(fm.boundingRect(this->text()).width() + 30, fm.ascent() - fm.descent() + fm.leading() + 20); + this->resize(fm.boundingRect(this->text()).width() + 30, fm.ascent() - fm.descent() + fm.leading()); + + this->setStyleSheet("background-color = background-color: rgba(255, 255, 255, 0);"); + this->setFlat(true); + + currentColor = defaultColorNotAtFocus; + + //QObject::connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); +} + +TabIcons::TabIcons(const QString & name, QWidget* parent) : QPushButton(parent){ + this->setMouseTracking(true); + this->setText(name); + QFont textFont; + textFont.setFamily("FuturaNo2DMed"); + textFont.setPointSize(15); + QFontMetrics fm(textFont); + this->setMinimumSize(fm.boundingRect(this->text()).width() + 30, fm.ascent() - fm.descent() + fm.leading() + 20); + this->resize(fm.boundingRect(this->text()).width() + 30, fm.ascent() - fm.descent() + fm.leading() + 20); + + this->setStyleSheet("background-color = background-color: rgba(255, 255, 255, 0);"); + this->setFlat(true); + + currentColor = defaultColorNotAtFocus; + //qDebug() << "init" << this->width() << "\n"; + + //QObject::connect(this, SIGNAL(clicked()), this, SLOT(on_clicked())); +} + +void TabIcons::paintEvent(QPaintEvent *event){ + QPainter textPainter(this); + textPainter.setPen(currentColor); + QFont textFont("FuturaNo2DMed", 15); + textPainter.setFont(textFont); + int widthOfText = textPainter.fontMetrics().size(Qt::TextSingleLine, this->text()).width(); + //qDebug()<<"icon!"; + //int heightOfText = textPainter.fontMetrics().ascent() - textPainter.fontMetrics().descent() + textPainter.fontMetrics().leading(); + //test.drawRect(this->width() / 2 - widthOfText / 2, this->height() / 2 - heightOfText / 2, widthOfText, heightOfText); + textPainter.drawText(this->width() / 2 - widthOfText / 2, this->height() - 5, this->text()); + //qDebug() << "paint" << this->width() << "\n"; +} + +void TabIcons::enterEvent(QEnterEvent *event){ + currentColor = hoverColor; + update(); +} + +void TabIcons::leaveEvent(QEvent *event){ + currentColor = atFocus ? defaultColorAtFocus : defaultColorNotAtFocus; + update(); +} + +void TabIcons::mousePressEvent(QMouseEvent *event){ + currentColor = pressColor; + update(); + emit SelectPage(this); +} + +void TabIcons::mouseReleaseEvent(QMouseEvent *event){ + currentColor = atFocus ? defaultColorAtFocus : hoverColor; + update(); +} + +void TabIcons::SetFocus(bool status){ + atFocus = status; + currentColor = atFocus ? defaultColorAtFocus : defaultColorNotAtFocus; + update(); +} diff --git a/tabicons.h b/tabicons.h new file mode 100644 index 0000000..30ca6dd --- /dev/null +++ b/tabicons.h @@ -0,0 +1,40 @@ +#ifndef TABICONS_H +#define TABICONS_H + +#include +#include +#include +#include + +class TabIcons : public QPushButton +{ + Q_OBJECT + +private: + bool atFocus = false; + + QColor currentColor; + QColor defaultColorAtFocus = QColor(0, 0, 0, 255); + QColor defaultColorNotAtFocus = QColor(100, 100, 100, 180); + QColor hoverColor = QColor(50, 50, 50, 230); + QColor pressColor = QColor(20, 20, 20, 230); + + void paintEvent(QPaintEvent* event); + void enterEvent(QEnterEvent* event); + void leaveEvent(QEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + +public: + TabIcons(QWidget* parent = nullptr); + TabIcons(const QString & name, QWidget* parent = nullptr); + void SetFocus(bool status); + +signals: + void SelectPage(TabIcons* icon); + +private slots: + void on_clicked(){emit SelectPage(this);} +}; + +#endif // TABICONS_H diff --git a/tabindicator.cpp b/tabindicator.cpp new file mode 100644 index 0000000..ea9fffd --- /dev/null +++ b/tabindicator.cpp @@ -0,0 +1,14 @@ +#include "tabindicator.h" + +TabIndicator::TabIndicator(QWidget *parent) : QWidget(parent) +{ + this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + this->setMouseTracking(true); +} + +void TabIndicator::paintEvent(QPaintEvent *event){ + QPainter painter(this); + painter.setPen(QColor(0, 120, 215, 200)); + painter.setBrush(QColor(0, 120, 215, 200)); + painter.drawRect(this->rect()); +} diff --git a/tabindicator.h b/tabindicator.h new file mode 100644 index 0000000..c653c96 --- /dev/null +++ b/tabindicator.h @@ -0,0 +1,18 @@ +#ifndef TABINDICATOR_H +#define TABINDICATOR_H + +#include +#include + +class TabIndicator : public QWidget +{ + Q_OBJECT + +protected: + void paintEvent(QPaintEvent* event); + +public: + explicit TabIndicator(QWidget *parent = nullptr); +}; + +#endif // TABINDICATOR_H diff --git a/tabpage.cpp b/tabpage.cpp new file mode 100644 index 0000000..ec2780b --- /dev/null +++ b/tabpage.cpp @@ -0,0 +1,6 @@ +#include "tabpage.h" + +TabPage::TabPage(QWidget *parent) : QWidget(parent) +{ + this->setMouseTracking(true); +} diff --git a/tabpage.h b/tabpage.h new file mode 100644 index 0000000..8173777 --- /dev/null +++ b/tabpage.h @@ -0,0 +1,16 @@ +#ifndef TABPAGE_H +#define TABPAGE_H + +#include + +class TabPage : public QWidget +{ + Q_OBJECT +public: + explicit TabPage(QWidget *parent = nullptr); + +signals: + +}; + +#endif // TABPAGE_H