diff --git a/.checkstyle b/.checkstyle new file mode 100644 index 0000000..34ed486 --- /dev/null +++ b/.checkstyle @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..d43dd0c --- /dev/null +++ b/.classpath @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d075be7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +/bin/ +/Operator/ +/DrawerProperties/ +*.pdfd +*.dbc +SchedulerConfig.txt +scenicView.properties +ScenariumConfig.txt +*.class +*~ +*.bck +build.number +/extern/ +/out/ +/.settings/ +/junit/ +/target/ diff --git a/.project b/.project new file mode 100644 index 0000000..00ecbe4 --- /dev/null +++ b/.project @@ -0,0 +1,24 @@ + + + atriasoft-ewol + + + atriasoft-ewol + + + + org.eclipse.jdt.core.javabuilder + + + + + net.sf.eclipsecs.core.CheckstyleBuilder + + + + + + org.eclipse.jdt.core.javanature + net.sf.eclipsecs.core.CheckstyleNature + + diff --git a/CheckStyle.xml b/CheckStyle.xml new file mode 100755 index 0000000..d68aedd --- /dev/null +++ b/CheckStyle.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CleanUp.xml b/CleanUp.xml new file mode 100644 index 0000000..6cf4cba --- /dev/null +++ b/CleanUp.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Formatter.xml b/Formatter.xml new file mode 100644 index 0000000..14a5d6c --- /dev/null +++ b/Formatter.xml @@ -0,0 +1,390 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a612ad9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/src/module-info.java b/src/module-info.java new file mode 100644 index 0000000..fd1ce90 --- /dev/null +++ b/src/module-info.java @@ -0,0 +1,9 @@ +/** Basic module interface. + * + * @author Edouard DUPIN */ + +open module org.atriasoft.etk { + exports org.atriasoft.etk; + exports org.atriasoft.etk.math; + requires transitive io.scenarium.logger; +} diff --git a/src/org/atriasoft/ewol/DrawProperty.cpp b/src/org/atriasoft/ewol/DrawProperty.cpp new file mode 100644 index 0000000..4d04f8e --- /dev/null +++ b/src/org/atriasoft/ewol/DrawProperty.cpp @@ -0,0 +1,24 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::DrawProperty); + +etk::Stream& ewol::operator <<(etk::Stream& _os, const ewol::DrawProperty& _obj) { + _os << "{ windowsSize=" << _obj.m_windowsSize << " start=" << _obj.m_origin << " stop=" << (_obj.m_origin+_obj.m_size) << "}"; + return _os; +} + +void ewol::DrawProperty::limit(const vec2& _origin, const vec2& _size) { + m_size += m_origin; + m_origin.setMax(_origin); + m_size.setMin(_origin+_size); + m_size -= m_origin; +} + diff --git a/src/org/atriasoft/ewol/DrawProperty.java b/src/org/atriasoft/ewol/DrawProperty.java new file mode 100644 index 0000000..659bad6 --- /dev/null +++ b/src/org/atriasoft/ewol/DrawProperty.java @@ -0,0 +1,48 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ewol { + /** + * @not_in_doc + */ + class DrawProperty{ + /* + /--> m_windowsSize + *--------------------------------------------------* + | g | + | | + | m_size | + | / | + | o-------------------o | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | | | | + | o-------------------o | + | / | + | m_origin | + | | + *--------------------------------------------------* + / + (0,0) + */ + public : + ivec2 m_windowsSize; //!< Windows compleate size + ivec2 m_origin; //!< Windows clipping upper widget (can not be <0) + ivec2 m_size; //!< Windows clipping upper widget (can not be <0 and >m_windowsSize) + void limit(const vec2& _origin, const vec2& _size); + }; + etk::Stream& operator <<(etk::Stream& _os, const ewol::DrawProperty& _obj); + +} diff --git a/src/org/atriasoft/ewol/Padding.cpp b/src/org/atriasoft/ewol/Padding.cpp new file mode 100644 index 0000000..36a5a92 --- /dev/null +++ b/src/org/atriasoft/ewol/Padding.cpp @@ -0,0 +1,93 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +ETK_DECLARE_TYPE(ewol::Padding); + +ewol::Padding::Padding() { + // nothing to do... +} + +ewol::Padding::Padding(float _xl, float _yt, float _xr, float _yb) { + setValue(_xl, _yt, _xr, _yb); +} + +void ewol::Padding::setValue(float _xl, float _yt, float _xr, float _yb) { + m_value[0] = _xl; + m_value[1] = _yt; + m_value[2] = _xr; + m_value[3] = _yb; +} + +float ewol::Padding::x() const { + return m_value[0] + m_value[2]; +} + +float ewol::Padding::y() const { + return m_value[1] + m_value[3]; +} + +float ewol::Padding::xLeft() const { + return m_value[0]; +} + +void ewol::Padding::setXLeft(float _val) { + m_value[0] = _val; +} + +float ewol::Padding::xRight() const { + return m_value[2]; +} + +void ewol::Padding::setXRight(float _val) { + m_value[2] = _val; +} + +float ewol::Padding::yTop() const { + return m_value[1]; +} + +void ewol::Padding::setYTop(float _val) { + m_value[1] = _val; +} + +float ewol::Padding::yButtom() const { + return m_value[3]; +} + +void ewol::Padding::setYButtom(float _val) { + m_value[3] = _val; +} + +ewol::Padding& ewol::Padding::operator+=(const Padding& _v) { + m_value[0] += _v.m_value[0]; + m_value[1] += _v.m_value[1]; + m_value[2] += _v.m_value[2]; + m_value[3] += _v.m_value[3]; + return *this; +} + +ewol::Padding ewol::Padding::operator+(const Padding& _v) { + return Padding(m_value[0] + _v.m_value[0], + m_value[1] + _v.m_value[1], + m_value[2] + _v.m_value[2], + m_value[3] + _v.m_value[3]); +} + +etk::Stream& ewol::operator <<(etk::Stream& _os, const ewol::Padding& _obj) { + _os << "{"; + _os << _obj.xLeft(); + _os << ","; + _os << _obj.yTop(); + _os << ","; + _os << _obj.xRight(); + _os << ","; + _os << _obj.yButtom(); + _os << "}"; + return _os; +} + diff --git a/src/org/atriasoft/ewol/Padding.java b/src/org/atriasoft/ewol/Padding.java new file mode 100644 index 0000000..b03d61c --- /dev/null +++ b/src/org/atriasoft/ewol/Padding.java @@ -0,0 +1,43 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ewol { + /** + * @breif Simple class to abstarct the padding porperty. + */ + class Padding { + private: + float m_value[4]; //!< this represent the 4 padding value Left top right buttom (like css) + public: + Padding(); + Padding(float _xl, float _yt=0.0f, float _xr=0.0f, float _yb=0.0f); + void setValue(float _xl, float _yt=0.0f, float _xr=0.0f, float _yb=0.0f); + float x() const; + float y() const; + float xLeft() const; + void setXLeft(float _val); + float xRight() const; + void setXRight(float _val); + float yTop() const; + void setYTop(float _val); + float yButtom() const; + void setYButtom(float _val); + /** + * @brief Add a vector to this one + * @param _v The vector to add to this one + */ + Padding& operator+=(const Padding& _v); + //! @previous + Padding operator+(const Padding& _v); + + }; + etk::Stream& operator <<(etk::Stream& _os, const ewol::Padding& _obj); +}; + diff --git a/src/org/atriasoft/ewol/compositing/Area.cpp b/src/org/atriasoft/ewol/compositing/Area.cpp new file mode 100644 index 0000000..70bab49 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Area.cpp @@ -0,0 +1,142 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +ETK_DECLARE_TYPE(ewol::compositing::Area); + +// VBO table property: +const int32_t ewol::compositing::Area::m_vboIdCoord(0); +const int32_t ewol::compositing::Area::m_vboIdCoordText(1); +const int32_t ewol::compositing::Area::m_vboIdColor(2); +#define NB_VBO (3) + +ewol::compositing::Area::Area(const ivec2& _size) : + m_position(0.0, 0.0, 0.0), + m_color(etk::color::white), + m_GLprogram(null), + m_GLPosition(-1), + m_GLMatrix(-1), + m_GLColor(-1), + m_GLtexture(-1), + m_GLtexID(-1), + m_resource(null) { + m_resource = ewol::resource::Texture::create(); + m_resource->setImageSize(_size); + m_resource->flush(); + // Create the VBO: + m_VBO = gale::resource::VirtualBufferObject::create(NB_VBO); + if (m_VBO == null) { + EWOL_ERROR("can not instanciate VBO ..."); + return; + } + // TO facilitate some debugs we add a name of the VBO: + m_VBO->setName("[VBO] of ewol::compositing::Area"); + loadProgram(); +} + +ewol::compositing::Area::~Area() { + +} + +void ewol::compositing::Area::loadProgram() { + // get the shader resource : + m_GLPosition = 0; + m_GLprogram = gale::resource::Program::create(etk::String("DATA:///textured3D.prog?lib=ewol")); + if (m_GLprogram != null) { + m_GLPosition = m_GLprogram->getAttribute("EW_coord3d"); + m_GLColor = m_GLprogram->getAttribute("EW_color"); + m_GLtexture = m_GLprogram->getAttribute("EW_texture2d"); + m_GLMatrix = m_GLprogram->getUniform("EW_MatrixTransformation"); + m_GLtexID = m_GLprogram->getUniform("EW_texID"); + } +} + +void ewol::compositing::Area::draw(bool _disableDepthTest) { + if (m_VBO->bufferSize(m_vboIdCoord) <= 0) { + //EWOL_WARNING("Nothink to draw..."); + return; + } + if (m_resource == null) { + // this is a normale case ... the user can choice to have no image ... + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + // set Matrix : translation/positionMatrix + mat4 tmpMatrix = gale::openGL::getMatrix()*m_matrixApply; + m_GLprogram->use(); + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // TextureID + m_GLprogram->setTexture0(m_GLtexID, m_resource->getRendererId()); + // position: + m_GLprogram->sendAttributePointer(m_GLPosition, m_VBO, m_vboIdCoord); + // Texture: + m_GLprogram->sendAttributePointer(m_GLtexture, m_VBO, m_vboIdColor); + // color: + m_GLprogram->sendAttributePointer(m_GLColor, m_VBO, m_vboIdCoordText); + // Request the draw od the elements : + gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, m_VBO->bufferSize(m_vboIdCoord)); + m_GLprogram->unUse(); +} + +void ewol::compositing::Area::clear() { + // call upper class + ewol::Compositing::clear(); + // reset all VBOs: + m_VBO->clear(); + // reset temporal variables : + m_position = vec3(0.0, 0.0, 0.0); +} + +void ewol::compositing::Area::print(const ivec2& _size) { + vec3 point(0,0,0); + vec2 tex(0,1); + point.setX(m_position.x()); + point.setY(m_position.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdCoordText, tex); + + tex.setValue(1,1); + point.setX(m_position.x() + _size.x()); + point.setY(m_position.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdCoordText, tex); + + tex.setValue(1,0); + point.setX(m_position.x() + _size.x()); + point.setY(m_position.y() + _size.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdCoordText, tex); + + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdCoordText, tex); + + tex.setValue(0,0); + point.setX(m_position.x()); + point.setY(m_position.y() + _size.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdCoordText, tex); + + tex.setValue(0,1); + point.setX(m_position.x()); + point.setY(m_position.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdCoordText, tex); + + m_VBO->flush(); +} + + diff --git a/src/org/atriasoft/ewol/compositing/Area.java b/src/org/atriasoft/ewol/compositing/Area.java new file mode 100644 index 0000000..d953b32 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Area.java @@ -0,0 +1,101 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace compositing { + class Area : public ewol::Compositing { + private: + vec3 m_position; //!< The current position to draw + etk::Color m_color; //!< The text foreground color + private: + ememory::SharedPtr m_GLprogram; //!< pointer on the opengl display program + int32_t m_GLPosition; //!< openGL id on the element (vertex buffer) + int32_t m_GLMatrix; //!< openGL id on the element (transformation matrix) + int32_t m_GLColor; //!< openGL id on the element (color buffer) + int32_t m_GLtexture; //!< openGL id on the element (Texture position) + int32_t m_GLtexID; //!< openGL id on the element (texture ID) + private: + ememory::SharedPtr m_resource; //!< texture resources + protected: + static const int32_t m_vboIdCoord; + static const int32_t m_vboIdCoordText; + static const int32_t m_vboIdColor; + ememory::SharedPtr m_VBO; + private: + /** + * @brief load the openGL program and get all the ID needed + */ + void loadProgram(); + public: + /** + * @brief generic constructor + * @param[in] _size Basic size of the area. + */ + Area(const ivec2& _size); + /** + * @brief generic destructor + */ + virtual ~Area(); + public: + /** + * @brief draw All the refistered text in the current element on openGL + */ + void draw(bool _disableDepthTest=true); + /** + * @brief clear alll the registered element in the current element + */ + void clear(); + /** + * @brief get the current display position (sometime needed in the gui control) + * @return the current position. + */ + const vec3& getPos() { + return m_position; + }; + /** + * @brief set position for the next text writen + * @param[in] _pos Position of the text (in 3D) + */ + void setPos(const vec3& _pos) { + m_position = _pos; + }; + inline void setPos(const vec2& _pos) { + setPos(vec3(_pos.x(),_pos.y(),0)); + }; + /** + * @brief set relative position for the next text writen + * @param[in] _pos ofset apply of the text (in 3D) + */ + void setRelPos(const vec3& _pos) { + m_position += _pos; + }; + inline void setRelPos(const vec2& _pos) { + setRelPos(vec3(_pos.x(),_pos.y(),0)); + }; + /** + * @brief add a compleate of the image to display with the requested size + * @param[in] _size size of the output image + */ + void print(const ivec2& _size); + + egami::Image& get() { + return m_resource->get(); + }; + void flush() { + m_resource->flush(); + }; + }; + }; +}; diff --git a/src/org/atriasoft/ewol/compositing/Compositing.cpp b/src/org/atriasoft/ewol/compositing/Compositing.cpp new file mode 100644 index 0000000..ff4462b --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Compositing.cpp @@ -0,0 +1,47 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +#include +#include +#include +ETK_DECLARE_TYPE(ewol::Compositing); + +ewol::Compositing::Compositing() { + // nothing to do +} + + +void ewol::Compositing::resetMatrix() { + m_matrixApply.identity(); +} + + +void ewol::Compositing::translate(const vec3& _vect) { + m_matrixApply *= etk::matTranslate(_vect); +} + + +void ewol::Compositing::rotate(const vec3& _vect, float _angle) { + m_matrixApply *= etk::matRotate(_vect, _angle); +} + + +void ewol::Compositing::scale(const vec3& _vect) { + m_matrixApply *= etk::matScale(_vect); +} + + +void ewol::Compositing::clear() { + m_matrixApply.identity(); +} + + +void ewol::Compositing::setMatrix(const mat4& _mat) { + m_matrixApply = _mat; +} diff --git a/src/org/atriasoft/ewol/compositing/Compositing.java b/src/org/atriasoft/ewol/compositing/Compositing.java new file mode 100644 index 0000000..7cea545 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Compositing.java @@ -0,0 +1,58 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include + +namespace ewol { + class Compositing { + protected: + mat4 m_matrixApply; + public: + /** + * @brief generic constructor + */ + Compositing(); + /** + * @brief Generic destructor + */ + virtual ~Compositing() = default; + /** + * @brief Virtal pure function that request the draw of all openGl elements + */ + virtual void draw(bool _disableDepthTest = true) = 0; + /** + * @brief clear alll tre registered element in the current element + */ + virtual void clear(); + /** + * @brief reset to the eye matrix the openGL mouving system + */ + virtual void resetMatrix(); + /** + * @brief translate the current display of this element + * @param[in] _vect The translation vector to apply at the transformation matrix + */ + virtual void translate(const vec3& _vect); + /** + * @brief rotate the curent display of this element + * @param[in] _vect The rotation vector to apply at the transformation matrix + */ + virtual void rotate(const vec3& _vect, float _angle); + /** + * @brief scale the current diaplsy of this element + * @param[in] _vect The scaling vector to apply at the transformation matrix + */ + virtual void scale(const vec3& _vect); + /** + * @brief set the transformation matrix + * @param[in] _mat The new matrix. + */ + virtual void setMatrix(const mat4& _mat); + }; +}; diff --git a/src/org/atriasoft/ewol/compositing/Drawing.cpp b/src/org/atriasoft/ewol/compositing/Drawing.cpp new file mode 100644 index 0000000..6f9d386 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Drawing.cpp @@ -0,0 +1,558 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::compositing::Drawing); + +// VBO table property: +const int32_t ewol::compositing::Drawing::m_vboIdCoord(0); +const int32_t ewol::compositing::Drawing::m_vboIdColor(1); +#define NB_VBO (2) + +#if 0 + +static void generatePolyGone(etk::Vector & input, etk::Vector & output ) +{ + if (input.size()<3) { + return; + } + // TODO : Regenerate a linear poligone generation + for (int32_t iii=1; iii " << output.size() ); +} + +static void SutherlandHodgman(etk::Vector & input, etk::Vector & output, float sx, float sy, float ex, float ey) +{ + // with Sutherland-Hodgman-Algorithm + if (input.size() <0) { + return; + } + //int32_t sizeInit=input.size(); + // last element : + vec2 destPoint; + vec2 lastElement = input[input.size()-1]; + bool inside = true; + if (lastElement.x < sx) { + inside = false; + } + //EWOL_DEBUG("generate an crop : "); + for(int32_t iii=0; iii OUT "); + //new point intersection ... + //y=aaax+bbb + float aaa = (lastElement.y-input[iii].y) / (lastElement.x-input[iii].x); + float bbb = lastElement.y - (aaa*lastElement.x); + destPoint.y = aaa*sx + bbb; + destPoint.x = sx; + output.pushBack(destPoint); + } else { + //EWOL_DEBUG("element OUT == > OUT "); + } + inside = false; + } else { + if(true == inside) { + //EWOL_DEBUG("element IN == > IN "); + output.pushBack(input[iii]); + } else { + //EWOL_DEBUG("element OUT == > IN "); + //new point intersection ... + //y=aaax+bbb + float aaa = (lastElement.y-input[iii].y) / (lastElement.x-input[iii].x); + float bbb = lastElement.y - (aaa*lastElement.x); + destPoint.y = aaa*sx + bbb; + destPoint.x = sx; + output.pushBack(destPoint); + output.pushBack(input[iii]); + } + inside = true; + } + // update the last point position : + lastElement.x = input[iii].x; + lastElement.y = input[iii].y; + } + + //EWOL_DEBUG("generate an crop on element : " << sizeInit << " == > " << output.size() << "intermediate (1)"); + input = output; + output.clear(); + lastElement = input[input.size()-1]; + inside = true; + if (lastElement.y < sy) { + inside = false; + } + for(int32_t iii=0; iii OUT "); + //new point intersection ... + //x=aaay+bbb + float aaa = (lastElement.x-input[iii].x) / (lastElement.y-input[iii].y); + float bbb = lastElement.x - (aaa*lastElement.y); + destPoint.y = sy; + destPoint.x = sy*aaa + bbb; + output.pushBack(destPoint); + } else { + //EWOL_DEBUG("element OUT == > OUT "); + } + inside = false; + } else { + if(true == inside) { + //EWOL_DEBUG("element IN == > IN "); + output.pushBack(input[iii]); + } else { + //EWOL_DEBUG("element OUT == > IN "); + //new point intersection ... + //y=aaax+bbb + float aaa = (lastElement.x-input[iii].x) / (lastElement.y-input[iii].y); + float bbb = lastElement.x - (aaa*lastElement.y); + destPoint.y = sy; + destPoint.x = sy*aaa + bbb; + output.pushBack(destPoint); + output.pushBack(input[iii]); + } + inside = true; + } + // update the last point position : + lastElement.x = input[iii].x; + lastElement.y = input[iii].y; + } + + input = output; + output.clear(); + lastElement = input[input.size()-1]; + inside = true; + if (lastElement.x > ex) { + inside = false; + } + //EWOL_DEBUG("generate an crop : "); + for(int32_t iii=0; iii ex) { + if(true == inside) { + //EWOL_DEBUG("element IN == > OUT "); + //new point intersection ... + //y=aaax+bbb + float aaa = (lastElement.y-input[iii].y) / (lastElement.x-input[iii].x); + float bbb = lastElement.y - (aaa*lastElement.x); + destPoint.y = aaa*ex + bbb; + destPoint.x = ex; + output.pushBack(destPoint); + } else { + //EWOL_DEBUG("element OUT == > OUT "); + } + inside = false; + } else { + if(true == inside) { + //EWOL_DEBUG("element IN == > IN "); + output.pushBack(input[iii]); + } else { + //EWOL_DEBUG("element OUT == > IN "); + //new point intersection ... + //y=aaax+bbb + float aaa = (lastElement.y-input[iii].y) / (lastElement.x-input[iii].x); + float bbb = lastElement.y - (aaa*lastElement.x); + destPoint.y = aaa*ex + bbb; + destPoint.x = ex; + output.pushBack(destPoint); + output.pushBack(input[iii]); + } + inside = true; + } + // update the last point position : + lastElement.x = input[iii].x; + lastElement.y = input[iii].y; + } + + input = output; + output.clear(); + lastElement = input[input.size()-1]; + inside = true; + if (lastElement.y > ey) { + inside = false; + } + for(int32_t iii=0; iii ey) { + if(true == inside) { + //EWOL_DEBUG("element IN == > OUT "); + //new point intersection ... + //x=aaay+bbb + float aaa = (lastElement.x-input[iii].x) / (lastElement.y-input[iii].y); + float bbb = lastElement.x - (aaa*lastElement.y); + destPoint.y = ey; + destPoint.x = ey*aaa + bbb; + output.pushBack(destPoint); + } else { + //EWOL_DEBUG("element OUT == > OUT "); + } + inside = false; + } else { + if(true == inside) { + //EWOL_DEBUG("element IN == > IN "); + output.pushBack(input[iii]); + } else { + //EWOL_DEBUG("element OUT == > IN "); + //new point intersection ... + //y=aaax+bbb + float aaa = (lastElement.x-input[iii].x) / (lastElement.y-input[iii].y); + float bbb = lastElement.x - (aaa*lastElement.y); + destPoint.y = ey; + destPoint.x = ey*aaa + bbb; + output.pushBack(destPoint); + output.pushBack(input[iii]); + } + inside = true; + } + // update the last point position : + lastElement.x = input[iii].x; + lastElement.y = input[iii].y; + } + + + //EWOL_DEBUG("generate an crop on element : " << sizeInit << " == > " << output.size() ); +} +#endif + +ewol::compositing::Drawing::Drawing() : + m_position(0.0, 0.0, 0.0), + m_clippingPosStart(0.0, 0.0, 0.0), + m_clippingPosStop(0.0, 0.0, 0.0), + m_clippingEnable(false), + m_color(etk::color::black), + m_colorBg(etk::color::none), + m_GLprogram(null), + m_GLPosition(-1), + m_GLMatrix(-1), + m_GLMatrixPosition(-1), + m_GLColor(-1), + m_thickness(0.0), + m_triElement(0) { + loadProgram(); + for (int32_t iii=0; iii<3; iii++) { + m_triangle[iii] = m_position; + m_tricolor[iii] = m_color; + } + // Create the VBO: + m_VBO = gale::resource::VirtualBufferObject::create(NB_VBO); + if (m_VBO == null) { + EWOL_ERROR("can not instanciate VBO ..."); + return; + } + // TO facilitate some debugs we add a name of the VBO: + m_VBO->setName("[VBO] of ewol::compositing::Area"); +} + +ewol::compositing::Drawing::~Drawing() { + unLoadProgram(); +} + +void ewol::compositing::Drawing::generateTriangle() { + m_triElement = 0; + + m_VBO->pushOnBuffer(m_vboIdCoord, m_triangle[0]); + m_VBO->pushOnBuffer(m_vboIdColor, m_tricolor[0]); + m_VBO->pushOnBuffer(m_vboIdCoord, m_triangle[1]); + m_VBO->pushOnBuffer(m_vboIdColor, m_tricolor[1]); + m_VBO->pushOnBuffer(m_vboIdCoord, m_triangle[2]); + m_VBO->pushOnBuffer(m_vboIdColor, m_tricolor[2]); +} + +void ewol::compositing::Drawing::internalSetColor(const etk::Color<>& _color) { + if (m_triElement < 1) { + m_tricolor[0] = _color; + } + if (m_triElement < 2) { + m_tricolor[1] = _color; + } + if (m_triElement < 3) { + m_tricolor[2] = _color; + } +} + +void ewol::compositing::Drawing::setPoint(const vec3& _point) { + m_triangle[m_triElement] = _point; + m_triElement++; + if (m_triElement >= 3) { + generateTriangle(); + } + m_VBO->flush(); +} + +void ewol::compositing::Drawing::resetCount() { + m_triElement = 0; +} + +void ewol::compositing::Drawing::unLoadProgram() { + m_GLprogram.reset(); +} + +void ewol::compositing::Drawing::loadProgram() { + // remove previous loading ... in case + unLoadProgram(); + // oad the new ... + m_GLprogram = gale::resource::Program::create("DATA:///color3.prog?lib=ewol"); + // get the shader resource : + if (m_GLprogram != null) { + m_GLPosition = m_GLprogram->getAttribute("EW_coord3d"); + m_GLColor = m_GLprogram->getAttribute("EW_color"); + m_GLMatrix = m_GLprogram->getUniform("EW_MatrixTransformation"); + m_GLMatrixPosition = m_GLprogram->getUniform("EW_MatrixPosition"); + } +} + +void ewol::compositing::Drawing::draw(bool _disableDepthTest) { + if (m_VBO->bufferSize(m_vboIdCoord) <= 0) { + // TODO : set it back ... + //EWOL_WARNING("Nothink to draw..."); + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + // set Matrix : translation/positionMatrix + mat4 tmpMatrix = gale::openGL::getMatrix()*m_matrixApply; + m_GLprogram->use(); + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + mat4 tmpMatrix2; + m_GLprogram->uniformMatrix(m_GLMatrixPosition, tmpMatrix2); + // position: + m_GLprogram->sendAttributePointer(m_GLPosition, m_VBO, m_vboIdCoord); + // color: + m_GLprogram->sendAttributePointer(m_GLColor, m_VBO, m_vboIdColor); + // Request the draw od the elements : + gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, m_VBO->bufferSize(m_vboIdCoord)); + m_GLprogram->unUse(); +} + +void ewol::compositing::Drawing::clear() { + // call upper class + ewol::Compositing::clear(); + // reset Buffer : + m_VBO->clear(); + // reset temporal variables : + m_position = vec3(0.0, 0.0, 0.0); + + m_clippingPosStart = vec3(0.0, 0.0, 0.0); + m_clippingPosStop = vec3(0.0, 0.0, 0.0); + m_clippingEnable = false; + + m_color = etk::color::black; + m_colorBg = etk::color::none; + + for (int32_t iii=0; iii<3; iii++) { + m_triangle[iii] = m_position; + m_tricolor[iii] = m_color; + } +} + +void ewol::compositing::Drawing::setClipping(const vec3& _pos, const vec3& _posEnd) { + // note the internal system all time request to have a bounding all time in the same order + if (_pos.x() <= _posEnd.x()) { + m_clippingPosStart.setX(_pos.x()); + m_clippingPosStop.setX(_posEnd.x()); + } else { + m_clippingPosStart.setX(_posEnd.x()); + m_clippingPosStop.setX(_pos.x()); + } + if (_pos.y() <= _posEnd.y()) { + m_clippingPosStart.setY(_pos.y()); + m_clippingPosStop.setY(_posEnd.y()); + } else { + m_clippingPosStart.setY(_posEnd.y()); + m_clippingPosStop.setY(_pos.y()); + } + if (_pos.z() <= _posEnd.z()) { + m_clippingPosStart.setZ(_pos.z()); + m_clippingPosStop.setZ(_posEnd.z()); + } else { + m_clippingPosStart.setZ(_posEnd.z()); + m_clippingPosStop.setZ(_pos.z()); + } + m_clippingEnable = true; +} + +void ewol::compositing::Drawing::setThickness(float _thickness) { + m_thickness = _thickness; + // thickness must be positive + if (m_thickness < 0) { + m_thickness *= -1; + } +} + +void ewol::compositing::Drawing::addVertex() { + internalSetColor(m_color); + setPoint(m_position); +} + +void ewol::compositing::Drawing::lineTo(const vec3& _dest) { + resetCount(); + internalSetColor(m_color); + //EWOL_VERBOSE("DrawLine : " << m_position << " to " << _dest); + if (m_position.x() == _dest.x() && m_position.y() == _dest.y() && m_position.z() == _dest.z()) { + //EWOL_WARNING("Try to draw a line width 0"); + return; + } + //teta = tan-1(oposer/adjacent) + float teta = 0; + if (m_position.x() <= _dest.x()) { + teta = atan((_dest.y()-m_position.y())/(_dest.x()-m_position.x())); + } else { + teta = M_PI + atan((_dest.y()-m_position.y())/(_dest.x()-m_position.x())); + } + if (teta < 0) { + teta += 2*M_PI; + } else if (teta > 2*M_PI) { + teta -= 2*M_PI; + } + //EWOL_DEBUG("teta = " << (teta*180/(M_PI)) << " deg." ); + float offsety = sin(teta-M_PI/2) * (m_thickness/2); + float offsetx = cos(teta-M_PI/2) * (m_thickness/2); + setPoint(vec3(m_position.x() - offsetx, m_position.y() - offsety, m_position.z()) ); + setPoint(vec3(m_position.x() + offsetx, m_position.y() + offsety, m_position.z()) ); + setPoint(vec3(_dest.x() + offsetx, _dest.y() + offsety, m_position.z()) ); + + setPoint(vec3(_dest.x() + offsetx, _dest.y() + offsety, _dest.z()) ); + setPoint(vec3(_dest.x() - offsetx, _dest.y() - offsety, _dest.z()) ); + setPoint(vec3(m_position.x() - offsetx, m_position.y() - offsety, _dest.z()) ); + // update the system position : + m_position = _dest; +} + +void ewol::compositing::Drawing::rectangle(const vec3& _dest) { + resetCount(); + internalSetColor(m_color); + /* Bitmap position + * xA xB + * yC *------* + * | | + * | | + * yD *------* + */ + float dxA = m_position.x(); + float dxB = _dest.x(); + if (dxA > dxB) { + // inverse order : + float tmp = dxA; + dxA = dxB; + dxB = tmp; + } + float dyC = m_position.y(); + float dyD = _dest.y(); + if (dyC > dyD) { + // inverse order : + float tmp = dyC; + dyC = dyD; + dyD = tmp; + } + if (true == m_clippingEnable) { + if (dxA < m_clippingPosStart.x()) { + dxA = m_clippingPosStart.x(); + } + if (dxB > m_clippingPosStop.x()) { + dxB = m_clippingPosStop.x(); + } + if (dyC < m_clippingPosStart.y()) { + dyC = m_clippingPosStart.y(); + } + if (dyD > m_clippingPosStop.y()) { + dyD = m_clippingPosStop.y(); + } + } + if( dyC >= dyD + || dxA >= dxB) { + return; + } + setPoint(vec3(dxA, dyD, 0) ); + setPoint(vec3(dxA, dyC, 0) ); + setPoint(vec3(dxB, dyC, 0) ); + + setPoint(vec3(dxB, dyC, 0) ); + setPoint(vec3(dxB, dyD, 0) ); + setPoint(vec3(dxA, dyD, 0) ); +} + +void ewol::compositing::Drawing::cube(const vec3& _dest) { + +} + +void ewol::compositing::Drawing::circle(float _radius, float _angleStart, float _angleStop) { + resetCount(); + + if (_radius<0) { + _radius *= -1; + } + _angleStop = _angleStop-_angleStart; + + + int32_t nbOcurence = _radius; + if (nbOcurence < 10) + { + nbOcurence = 10; + } + + // display background : + if (m_colorBg.a()!=0) { + internalSetColor(m_colorBg); + for (int32_t iii=0; iii + +#include +#include +#include + + +namespace ewol { + namespace compositing { + class Drawing : public ewol::Compositing { + private: + vec3 m_position; //!< The current position to draw + vec3 m_clippingPosStart; //!< Clipping start position + vec3 m_clippingPosStop; //!< Clipping stop position + bool m_clippingEnable; //!< true if the clipping must be activated + private: + etk::Color<> m_color; //!< The text foreground color + etk::Color<> m_colorBg; //!< The text background color + private: + ememory::SharedPtr m_GLprogram; //!< pointer on the opengl display program + int32_t m_GLPosition; //!< openGL id on the element (vertex buffer) + int32_t m_GLMatrix; //!< openGL id on the element (transformation matrix) + int32_t m_GLMatrixPosition; //!< position matrix + int32_t m_GLColor; //!< openGL id on the element (color buffer) + protected: + static const int32_t m_vboIdCoord; + static const int32_t m_vboIdColor; + ememory::SharedPtr m_VBO; + public: + /** + * @brief Basic constructor + */ + Drawing(); + /** + * @brief Basic destructor + */ + virtual ~Drawing(); + private: + /** + * @brief load the openGL program and get all the ID needed + */ + void loadProgram(); + /** + * @brief Un-Load the openGL program and get all the ID needed + */ + void unLoadProgram(); + float m_thickness; //!< when drawing line and other things + int32_t m_triElement; //!< special counter of the single dot generated + vec3 m_triangle[3]; //!< Register every system with a combinaison of tiangle + etk::Color m_tricolor[3]; //!< Register every the associated color foreground + // internal API for the generation abstraction of triangles + /** + * @brief Lunch the generation of triangle + */ + void generateTriangle(); + /** + * @brief in case of some error the count can be reset + */ + void resetCount(); + /** + * @brief set the Color of the current triangle drawing + * @param[in] _color Color to current dots generated + */ + void internalSetColor(const etk::Color<>& _color); + /** + * @brief internal add of the specific point + * @param[in] _point The requeste dpoint to add + */ + void setPoint(const vec3& point); + + public: + /** + * @brief draw All the refistered text in the current element on openGL + */ + void draw(bool _disableDepthTest=true); + /** + * @brief clear alll tre registered element in the current element + */ + void clear(); + /** + * @brief get the current display position (sometime needed in the gui control) + * @return the current position. + */ + const vec3& getPos() { + return m_position; + }; + /** + * @brief set position for the next text writen + * @param[in] _pos Position of the text (in 3D) + */ + void setPos(const vec3& _pos) { + m_position = _pos; + }; + inline void setPos(const vec2& _pos) { + setPos(vec3(_pos.x(), _pos.y(), 0)); + }; + /** + * @brief set relative position for the next text writen + * @param[in] _pos ofset apply of the text (in 3D) + */ + void setRelPos(const vec3& _pos) { + m_position += _pos; + }; + inline void setRelPos(const vec2& _pos) { + setRelPos(vec3(_pos.x(), _pos.y(), 0)); + }; + /** + * @brief set the Color of the current foreground font + * @param[in] _color Color to set on foreground (for next print) + */ + void setColor(const etk::Color<>& _color) { + m_color = _color; + }; + /** + * @brief Get the foreground color of the font. + * @return Foreground color. + */ + const etk::Color<>& getColor() { + return m_color; + }; + /** + * @brief set the background color of the font (for selected Text (not the global BG)) + * @param[in] _color Color to set on background (for next print) + */ + void setColorBg(const etk::Color<>& _color) { + m_colorBg = _color; + }; + /** + * @brief Get the background color of the font. + * @return Background color. + */ + const etk::Color<>& getColorBg() { + return m_colorBg; + }; + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in]_ pos Start position of the clipping + * @param[in] _width Width size of the clipping + */ + void setClippingWidth(const vec3& _pos, const vec3& _width) { + setClipping(_pos, _pos+_width); + }; + inline void setClippingWidth(const vec2& _pos, const vec2& _width) { + setClippingWidth(vec3(_pos.x(),_pos.y(),-1), vec3(_width.x(),_width.y(), 2)); + }; + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in] _pos Start position of the clipping + * @param[in] _posEnd End position of the clipping + */ + void setClipping(const vec3& _pos, const vec3& _posEnd); + inline void setClipping(const vec2& _pos, const vec2& _posEnd) { + setClipping(vec3(_pos.x(),_pos.y(),-1), vec3(_posEnd.x(),_posEnd.y(), 1)); + }; + /** + * @brief enable/Disable the clipping (without lose the current clipping position) + * @brief _newMode The new status of the clipping + */ + void setClippingMode(bool _newMode) { + m_clippingEnable = _newMode; + }; + /** + * @brief Specify the line thickness for the next elements + * @param[in] _thickness The thickness disired for the next print + */ + void setThickness(float _thickness); + /** + * @brief add a point reference at the current position (this is a vertex reference at the current position + */ + void addVertex(); + /** + * @brief draw a line to a specific position + * @param[in] _dest Position of the end of the line. + */ + void lineTo(const vec3& _dest); + inline void lineTo(const vec2& _dest) { + lineTo(vec3(_dest.x(), _dest.y(), 0)); + }; + /** + * @brief Relative drawing a line (spacial vector) + * @param[in] _vect Vector of the curent line. + */ + void lineRel(const vec3& _vect) { + lineTo(m_position+_vect); + }; + inline void lineRel(const vec2& _vect) { + lineRel(vec3(_vect.x(), _vect.y(), 0)); + }; + /** + * @brief draw a 2D rectangle to the position requested. + * @param[in] _dest Position the the end of the rectangle + */ + void rectangle(const vec3& _dest); + inline void rectangle(const vec2& _dest) { + rectangle(vec3(_dest.x(), _dest.y(), 0)); + }; + /** + * @brief draw a 2D rectangle to the requested size. + * @param[in] _size size of the rectangle + */ + void rectangleWidth(const vec3& _size) { + rectangle(m_position+_size); + }; + inline void rectangleWidth(const vec2& _size) { + rectangleWidth(vec3(_size.x(), _size.y(), 0)); + }; + /** + * @brief draw a 3D rectangle to the position requested. + * @param[in] _dest Position the the end of the rectangle + */ + void cube(const vec3& _dest); + /** + * @brief draw a 2D circle with the specify rafdius parameter. + * @param[in] _radius Distence to the dorder + * @param[in] _angleStart start angle of this circle ([0..2PI] otherwithe == > disable) + * @param[in] _angleStop stop angle of this circle ([0..2PI] otherwithe == > disable) + */ + void circle(float _radius, float _angleStart = 0, float _angleStop = 2*M_PI); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/compositing/Image.cpp b/src/org/atriasoft/ewol/compositing/Image.cpp new file mode 100644 index 0000000..76e8f67 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Image.cpp @@ -0,0 +1,364 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +ETK_DECLARE_TYPE(ewol::compositing::Image); + +const int32_t ewol::compositing::Image::sizeAuto(0); + +// VBO table property: +const int32_t ewol::compositing::Image::m_vboIdCoord(0); +const int32_t ewol::compositing::Image::m_vboIdCoordTex(1); +const int32_t ewol::compositing::Image::m_vboIdColor(2); +#define NB_VBO (3) + +ewol::compositing::Image::Image(const etk::Uri& _imageName, + bool _df, + int32_t _size) : + m_filename(_imageName), + m_requestSize(2,2), + m_position(0.0, 0.0, 0.0), + m_clippingPosStart(0.0, 0.0, 0.0), + m_clippingPosStop(0.0, 0.0, 0.0), + m_clippingEnable(false), + m_color(etk::color::white), + m_angle(0.0), + m_GLprogram(null), + m_GLPosition(-1), + m_GLMatrix(-1), + m_GLColor(-1), + m_GLtexture(-1), + m_GLtexID(-1), + m_distanceFieldMode(_df), + m_resource(null), + m_resourceDF(null) { + // Create the VBO: + m_VBO = gale::resource::VirtualBufferObject::create(NB_VBO); + if (m_VBO == null) { + EWOL_ERROR("can not instanciate VBO ..."); + return; + } + // TO facilitate some debugs we add a name of the VBO: + m_VBO->setName("[VBO] of ewol::compositing::Image"); + setSource(_imageName, _size); + loadProgram(); +} + +ewol::compositing::Image::~Image() { + +} + +void ewol::compositing::Image::loadProgram() { + // get the shader resource: + m_GLPosition = 0; + m_GLprogram.reset(); + if (m_distanceFieldMode == true) { + m_GLprogram = gale::resource::Program::create("DATA:///texturedDF.prog?lib=ewol"); + } else { + m_GLprogram = gale::resource::Program::create("DATA:///textured3D.prog?lib=ewol"); + } + if (m_GLprogram != null) { + m_GLPosition = m_GLprogram->getAttribute("EW_coord3d"); + m_GLColor = m_GLprogram->getAttribute("EW_color"); + m_GLtexture = m_GLprogram->getAttribute("EW_texture2d"); + m_GLMatrix = m_GLprogram->getUniform("EW_MatrixTransformation"); + m_GLtexID = m_GLprogram->getUniform("EW_texID"); + } +} + +void ewol::compositing::Image::draw(bool _disableDepthTest) { + if (m_VBO->bufferSize(m_vboIdCoord) <= 0) { + //EWOL_WARNING("Nothink to draw..."); + return; + } + if ( m_resource == null + && m_resourceDF == null + && m_resourceImage == null) { + // this is a normale case ... the user can choice to have no image ... + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + //EWOL_WARNING("Display image : " << m_VBO->bufferSize(m_vboIdCoord)); + if (_disableDepthTest == true) { + gale::openGL::disable(gale::openGL::flag_depthTest); + } else { + gale::openGL::enable(gale::openGL::flag_depthTest); + } + // set Matrix : translation/positionMatrix + mat4 tmpMatrix = gale::openGL::getMatrix()*m_matrixApply; + m_GLprogram->use(); + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // TextureID + if (m_resourceImage != null) { + m_GLprogram->setTexture0(m_GLtexID, m_resourceImage->getRendererId()); + } else if (m_resource != null) { + if (m_distanceFieldMode == true) { + EWOL_ERROR("FONT type error Request distance field and display normal ..."); + } + m_GLprogram->setTexture0(m_GLtexID, m_resource->getRendererId()); + } else { + if (m_distanceFieldMode == false) { + EWOL_ERROR("FONT type error Request normal and display distance field ..."); + } + m_GLprogram->setTexture0(m_GLtexID, m_resourceDF->getRendererId()); + } + // position: + m_GLprogram->sendAttributePointer(m_GLPosition, m_VBO, m_vboIdCoord); + // Texture: + m_GLprogram->sendAttributePointer(m_GLtexture, m_VBO, m_vboIdCoordTex); + // color: + m_GLprogram->sendAttributePointer(m_GLColor, m_VBO, m_vboIdColor); + // Request the draw of the elements: + gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, m_VBO->bufferSize(m_vboIdCoord)); + m_GLprogram->unUse(); +} + +void ewol::compositing::Image::clear() { + // call upper class + ewol::Compositing::clear(); + // reset Buffer : + m_VBO->clear(); + // reset temporal variables : + m_position = vec3(0.0, 0.0, 0.0); + m_clippingPosStart = vec3(0.0, 0.0, 0.0); + m_clippingPosStop = vec3(0.0, 0.0, 0.0); + m_clippingEnable = false; + m_color = etk::color::white; + m_angle = 0.0; +} + +void ewol::compositing::Image::setClipping(const vec3& _pos, vec3 _posEnd) { + // note the internal system all time request to have a bounding all time in the same order + if (_pos.x() <= _posEnd.x()) { + m_clippingPosStart.setX(_pos.x()); + m_clippingPosStop.setX(_posEnd.x()); + } else { + m_clippingPosStart.setX(_posEnd.x()); + m_clippingPosStop.setX(_pos.x()); + } + if (_pos.y() <= _posEnd.y()) { + m_clippingPosStart.setY(_pos.y()); + m_clippingPosStop.setY(_posEnd.y()); + } else { + m_clippingPosStart.setY(_posEnd.y()); + m_clippingPosStop.setY(_pos.y()); + } + if (_pos.z() <= _posEnd.z()) { + m_clippingPosStart.setZ(_pos.z()); + m_clippingPosStop.setZ(_posEnd.z()); + } else { + m_clippingPosStart.setZ(_posEnd.z()); + m_clippingPosStop.setZ(_pos.z()); + } + m_clippingEnable = true; +} + +void ewol::compositing::Image::setAngle(float _angle) { + m_angle = _angle; +} + +void ewol::compositing::Image::print(const vec2& _size) { + printPart(_size, vec2(0,0), vec2(1.0,1.0)); +} + +void ewol::compositing::Image::printPart(const vec2& _size, + vec2 _sourcePosStart, + vec2 _sourcePosStop) { + if (m_resource == null) { + return; + } + vec2 openGLSize = vec2(m_resource->getOpenGlSize().x(), m_resource->getOpenGlSize().y()); + vec2 usefullSize = m_resource->getUsableSize(); + vec2 ratio = usefullSize/openGLSize; + _sourcePosStart *= ratio; + _sourcePosStop *= ratio; + EWOL_VERBOSE(" openGLSize=" << openGLSize << " usableSize=" << usefullSize << " start=" << _sourcePosStart << " stop=" << _sourcePosStop); + + //EWOL_ERROR("Debug image " << m_filename << " ==> " << m_position << " " << _size << " " << _sourcePosStart << " " << _sourcePosStop); + if (m_angle == 0.0f) { + vec3 point = m_position; + vec2 tex(_sourcePosStart.x(),_sourcePosStop.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + tex.setValue(_sourcePosStop.x(),_sourcePosStop.y()); + point.setX(m_position.x() + _size.x()); + point.setY(m_position.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + tex.setValue(_sourcePosStop.x(),_sourcePosStart.y()); + point.setX(m_position.x() + _size.x()); + point.setY(m_position.y() + _size.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + tex.setValue(_sourcePosStart.x(),_sourcePosStart.y()); + point.setX(m_position.x()); + point.setY(m_position.y() + _size.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + tex.setValue(_sourcePosStart.x(),_sourcePosStop.y()); + point.setX(m_position.x()); + point.setY(m_position.y()); + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->flush(); + return; + } + vec3 center = m_position + vec3(_size.x(),_size.y(),0)/2.0f; + vec3 limitedSize(_size.x()*0.5f, _size.y()*0.5f, 0.0f); + + vec3 point(0,0,0); + vec2 tex(_sourcePosStart.x(),_sourcePosStop.y()); + + point.setValue(-limitedSize.x(), -limitedSize.y(), 0); + point = point.rotate(vec3(0,0,1), m_angle) + center; + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + tex.setValue(_sourcePosStop.x(),_sourcePosStop.y()); + point.setValue(limitedSize.x(), -limitedSize.y(), 0); + point = point.rotate(vec3(0,0,1), m_angle) + center; + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + tex.setValue(_sourcePosStop.x(),_sourcePosStart.y()); + point.setValue(limitedSize.x(), limitedSize.y(), 0); + point = point.rotate(vec3(0,0,1), m_angle) + center; + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + tex.setValue(_sourcePosStart.x(),_sourcePosStart.y()); + point.setValue(-limitedSize.x(), limitedSize.y(), 0); + point = point.rotate(vec3(0,0,1), m_angle) + center; + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + tex.setValue(_sourcePosStart.x(),_sourcePosStop.y()); + point.setValue(-limitedSize.x(), -limitedSize.y(), 0); + point = point.rotate(vec3(0,0,1), m_angle) + center; + m_VBO->pushOnBuffer(m_vboIdCoord, point); + m_VBO->pushOnBuffer(m_vboIdCoordTex, tex); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + + m_VBO->flush(); +} + +void ewol::compositing::Image::setSource(const etk::Uri& _uri, const vec2& _size) { + clear(); + if ( m_filename == _uri + && m_requestSize == _size) { + // Nothing to do ... + return; + } + ememory::SharedPtr resource = m_resource; + ememory::SharedPtr resourceDF = m_resourceDF; + ememory::SharedPtr resourceTex = m_resourceImage; + m_filename = _uri; + m_requestSize = _size; + m_resource.reset(); + m_resourceDF.reset(); + m_resourceImage.reset(); + ivec2 tmpSize(_size.x(),_size.y()); + // note that no image can be loaded... + if (_uri.isEmpty() == false) { + // link to new one + if (m_distanceFieldMode == false) { + m_resource = ewol::resource::TextureFile::create(m_filename, tmpSize); + if (m_resource == null) { + EWOL_ERROR("Can not get Image resource"); + } + } else { + m_resourceDF = ewol::resource::ImageDF::create(m_filename, tmpSize); + if (m_resourceDF == null) { + EWOL_ERROR("Can not get Image resource DF"); + } + } + } + if ( m_resource == null + && m_resourceDF == null + && m_resourceImage == null) { + if (resource != null) { + EWOL_WARNING("Retrive previous resource"); + m_resource = resource; + } + if (resourceDF != null) { + EWOL_WARNING("Retrive previous resource (DF)"); + m_resourceDF = resourceDF; + } + if (resourceTex != null) { + EWOL_WARNING("Retrive previous resource (image)"); + m_resourceImage = resourceTex; + } + } +} +void ewol::compositing::Image::setSource(egami::Image _image) { + clear(); + m_filename = "direct image BUFFER"; + m_requestSize = _image.getSize(); + m_resourceImage = ewol::resource::Texture::create(); + m_resourceImage->set(etk::move(_image)); +} + +bool ewol::compositing::Image::hasSources() { + return m_resource != null + || m_resourceDF != null; +} + + +vec2 ewol::compositing::Image::getRealSize() { + if ( m_resource == null + && m_resourceDF == null + && m_resourceImage == null) { + return vec2(0,0); + } + if (m_resource != null) { + return m_resource->getRealSize(); + } + if (m_resourceDF != null) { + return m_resourceDF->getRealSize(); + } + if (m_resourceImage != null) { + return m_resourceImage->getUsableSize(); + } + return vec2(0,0); +} + + + +void ewol::compositing::Image::setDistanceFieldMode(bool _mode) { + if (m_distanceFieldMode == _mode) { + return; + } + m_distanceFieldMode = _mode; + // Force reload input + setSource(m_filename, m_requestSize); + loadProgram(); +} diff --git a/src/org/atriasoft/ewol/compositing/Image.java b/src/org/atriasoft/ewol/compositing/Image.java new file mode 100644 index 0000000..9725a15 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Image.java @@ -0,0 +1,193 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace ewol { + namespace compositing { + class Image : public ewol::Compositing { + public: + static const int32_t sizeAuto; + private: + etk::Uri m_filename; + ivec2 m_requestSize; + vec3 m_position; //!< The current position to draw + vec3 m_clippingPosStart; //!< Clipping start position + vec3 m_clippingPosStop; //!< Clipping stop position + bool m_clippingEnable; //!< true if the clipping must be activated + private: + etk::Color m_color; //!< The text foreground color + float m_angle; //!< Angle to set at the axes + private: + ememory::SharedPtr m_GLprogram; //!< pointer on the opengl display program + int32_t m_GLPosition; //!< openGL id on the element (vertex buffer) + int32_t m_GLMatrix; //!< openGL id on the element (transformation matrix) + int32_t m_GLColor; //!< openGL id on the element (color buffer) + int32_t m_GLtexture; //!< openGL id on the element (Texture position) + int32_t m_GLtexID; //!< openGL id on the element (texture ID) + private: + bool m_distanceFieldMode; //!< select distance field mode + ememory::SharedPtr m_resource; //!< texture resources + ememory::SharedPtr m_resourceImage; //!< texture resources + ememory::SharedPtr m_resourceDF; //!< texture resources + static const int32_t m_vboIdCoord; + static const int32_t m_vboIdCoordTex; + static const int32_t m_vboIdColor; + ememory::SharedPtr m_VBO; + private: + /** + * @brief load the openGL program and get all the ID needed + */ + void loadProgram(); + public: + /** + * @brief generic constructor + * @param[in] _uri URI of the file that might be loaded + * @param[in] _df enable distance field mode + * @param[in] _size for the image when Verctorial image loading is requested + */ + Image(const etk::Uri& _uri="", + bool _df=false, + int32_t _size=ewol::compositing::Image::sizeAuto); + /** + * @brief generic destructor + */ + virtual ~Image(); + public: + /** + * @brief draw All the refistered text in the current element on openGL + * @param[in] _disableDepthTest disable the Depth test for display + */ + void draw(bool _disableDepthTest=true); + /** + * @brief clear alll tre registered element in the current element + */ + void clear(); + /** + * @brief get the current display position (sometime needed in the gui control) + * @return the current position. + */ + const vec3& getPos() { + return m_position; + }; + /** + * @brief set position for the next text writen + * @param[in] _pos Position of the text (in 3D) + */ + void setPos(const vec3& _pos) { + m_position = _pos; + }; + inline void setPos(const vec2& _pos) { + setPos(vec3(_pos.x(),_pos.y(),0)); + }; + /** + * @brief set relative position for the next text writen + * @param[in] _pos ofset apply of the text (in 3D) + */ + void setRelPos(const vec3& _pos) { + m_position += _pos; + }; + inline void setRelPos(const vec2& _pos) { + setRelPos(vec3(_pos.x(),_pos.y(),0)); + }; + /** + * @brief set the Color of the current foreground font + * @param[in] _color Color to set on foreground (for next print) + */ + void setColor(const etk::Color<>& _color) { + m_color = _color; + }; + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in] _pos Start position of the clipping + * @param[in] _width Width size of the clipping + */ + void setClippingWidth(const vec3& _pos, vec3 _width) { + setClipping(_pos, _pos+_width); + }; + inline void setClippingWidth(const vec2& _pos, const vec2& _width) { + setClippingWidth(vec3(_pos.x(),_pos.y(),0), vec3(_width.x(),_width.y(),0)); + }; + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in] _pos Start position of the clipping + * @param[in] _posEnd End position of the clipping + */ + void setClipping(const vec3& _pos, vec3 _posEnd); + inline void setClipping(const vec2& _pos, const vec2& _posEnd) { + setClipping(vec3(_pos.x(),_pos.y(),0), vec3(_posEnd.x(),_posEnd.y(),0)); + }; + /** + * @brief enable/Disable the clipping (without lose the current clipping position) + * @brief _newMode The new status of the clipping + */ + void setClippingMode(bool _newMode) { + m_clippingEnable = _newMode; + }; + /** + * @brief set a unique rotation of this element (not set in the rotate Generic system) + * @param[in] _angle Angle to set in radiant. + */ + void setAngle(float _angleRad); + /** + * @brief add a compleate of the image to display with the requested size + * @param[in] _size size of the output image + */ + void print(const ivec2& _size) { + print(vec2(_size.x(),_size.y())); + }; + void print(const vec2& _size); + /** + * @brief add a part of the image to display with the requested size + * @param[in] _size size of the output image + * @param[in] _sourcePosStart Start position in the image [0..1] (can be bigger but this repeate the image). + * @param[in] _sourcePosStop Stop position in the image [0..1] (can be bigger but this repeate the image). + */ + void printPart(const vec2& _size, + vec2 _sourcePosStart, + vec2 _sourcePosStop); + /** + * @brief change the image Source == > can not be done to display 2 images at the same time ... + * @param[in] _uri New file of the Image + * @param[in] _size for the image when Verctorial image loading is requested + */ + void setSource(const etk::Uri& _uri, int32_t _size=32) { + setSource(_uri, vec2(_size,_size)); + }; + void setSource(const etk::Uri& _uri, const vec2& _size); + void setSource(egami::Image _image); + /** + * @brief Sometimes the user declare an image but not allocate the ressources all the time, this is to know it .. + * @return the validity od the resources. + */ + bool hasSources(); + /** + * @brief get the source image registered size in the file (<0 when multiple size image) + * @return tre image registered size + */ + vec2 getRealSize(); + public: + /** + * @brief Set render mode of the image + * @param[in] _mode Activation of distance field mode + */ + void setDistanceFieldMode(bool _mode); + /** + * @brief Get the render methode. + * @return The render mode of the image. + */ + bool getDistanceFieldMode() const { + return m_distanceFieldMode; + } + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/compositing/Shaper.cpp b/src/org/atriasoft/ewol/compositing/Shaper.cpp new file mode 100644 index 0000000..cf96f8b --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Shaper.cpp @@ -0,0 +1,693 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::compositing::Shaper); + +// VBO table property: +const int32_t ewol::compositing::Shaper::m_vboIdCoord(0); +const int32_t ewol::compositing::Shaper::m_vboIdPos(1); +#define NB_VBO (2) + +ewol::compositing::Shaper::Shaper(const etk::Uri& _uri) : + m_uri(_uri), + m_config(null), + m_confIdMode(-1), + m_confIdDisplayOutside(-1), + m_confIdChangeTime(-1), + m_confProgramFile(-1), + m_confColorFile(-1), + m_confImageFile(-1), + m_GLprogram(null), + m_GLPosition(-1), + m_GLMatrix(-1), + m_GLStateActivate(-1), + m_GLStateOld(-1), + m_GLStateNew(-1), + m_GLStateTransition(-1), + m_resourceTexture(null), + m_nextStatusRequested(-1), + m_propertyOrigin(0,0), + m_propertySize(0,0), + m_propertyInsidePosition(0,0), + m_propertyInsideSize(0,0), + m_stateActivate(0), + m_stateOld(0), + m_stateNew(0), + m_stateTransition(1.0), + m_nbVertexToDisplay(0) { + for (size_t iii=0; iiisetName("[VBO] of ewol::compositing::Shaper"); + loadProgram(); +} + +ewol::compositing::Shaper::~Shaper() { + unLoadProgram(); +} + +void ewol::compositing::Shaper::unLoadProgram() { + m_GLprogram.reset(); + m_resourceTexture.reset(); + m_config.reset(); + m_colorProperty.reset(); + for (size_t iii=0; iiiclear(); + m_confIdMode = -1; + m_confIdDisplayOutside = -1; + m_nbVertexToDisplay = 0; + m_confIdChangeTime = -1; + m_confProgramFile = -1; + m_confImageFile = -1; + m_listAssiciatedId.clear(); +} + +void ewol::compositing::Shaper::loadProgram() { + if (m_uri.isEmpty() == true) { + EWOL_DEBUG("no Shaper set for loading resources ..."); + return; + } + m_config = ewol::resource::ConfigFile::create(m_uri.get()); + if (m_config != null) { + m_confIdMode = m_config->request("mode"); + m_confIdDisplayOutside = m_config->request("display-outside"); + m_confIdPaddingOut[shaperPosLeft] = m_config->request("padding-out-left"); + m_confIdPaddingOut[shaperPosRight] = m_config->request("padding-out-right"); + m_confIdPaddingOut[shaperPosTop] = m_config->request("padding-out-top"); + m_confIdPaddingOut[shaperPosButtom] = m_config->request("padding-out-buttom"); + m_confIdBorder[shaperPosLeft] = m_config->request("border-left"); + m_confIdBorder[shaperPosRight] = m_config->request("border-right"); + m_confIdBorder[shaperPosTop] = m_config->request("border-top"); + m_confIdBorder[shaperPosButtom] = m_config->request("border-buttom"); + m_confIdPaddingIn[shaperPosLeft] = m_config->request("padding-in-left"); + m_confIdPaddingIn[shaperPosRight] = m_config->request("padding-in-right"); + m_confIdPaddingIn[shaperPosTop] = m_config->request("padding-in-top"); + m_confIdPaddingIn[shaperPosButtom] = m_config->request("padding-in-buttom"); + m_confIdChangeTime = m_config->request("change-time"); + m_confProgramFile = m_config->request("program"); + m_confImageFile = m_config->request("image"); + m_confColorFile = m_config->request("color"); + } + etk::String basicShaderFile = m_config->getString(m_confProgramFile); + if (basicShaderFile != "") { + etk::String tmpFilename(basicShaderFile); + if (tmpFilename.find(':') == etk::String::npos) { + // get the relative position of the current file ... + etk::Uri tmpUri = m_uri; + tmpUri.setPath(m_uri.getPath().getParent() / basicShaderFile); + tmpFilename = tmpUri.get(); + EWOL_DEBUG("Shaper try load shader : '" << tmpFilename << "' with base : '" << basicShaderFile << "'"); + } else { + EWOL_DEBUG("Shaper try load shader : '" << tmpFilename << "'"); + } + // get the shader resource : + m_GLPosition = 0; + m_GLprogram = gale::resource::Program::create(tmpFilename); + if (m_GLprogram != null) { + m_GLPosition = m_GLprogram->getAttribute("EW_coord2d"); + m_GLMatrix = m_GLprogram->getUniform("EW_MatrixTransformation"); + // Widget property == > for the Vertex shader + m_GLPropertyPos = m_GLprogram->getAttribute("EW_widgetPropertyPos"); + // status property == > for the fragment shader + m_GLStateActivate = m_GLprogram->getUniform("EW_status.activate"); + m_GLStateOld = m_GLprogram->getUniform("EW_status.stateOld"); + m_GLStateNew = m_GLprogram->getUniform("EW_status.stateNew"); + m_GLStateTransition = m_GLprogram->getUniform("EW_status.transition"); + // for the texture ID : + m_GLtexID = m_GLprogram->getUniform("EW_texID"); + } + etk::String basicImageFile = m_config->getString(m_confImageFile); + if (basicImageFile != "") { + etk::String tmpFilename(basicImageFile); + if (tmpFilename.find(':') == etk::String::npos) { + // get the relative position of the current file ... + etk::Uri tmpUri = m_uri; + tmpUri.setPath(m_uri.getPath().getParent() / basicImageFile); + tmpFilename = tmpUri.get(); + EWOL_DEBUG("Shaper try load shaper image : '" << tmpFilename << "' with base : '" << basicImageFile << "'"); + } else { + EWOL_DEBUG("Shaper try load shaper image : '" << tmpFilename << "'"); + } + ivec2 size(64,64); + m_resourceTexture = ewol::resource::TextureFile::create(tmpFilename, size); + } + } + etk::String basicColorFile = m_config->getString(m_confColorFile); + if (basicColorFile != "") { + etk::String tmpFilename(basicColorFile); + if (tmpFilename.find(':') == etk::String::npos) { + // get the relative position of the current file ... + etk::Uri tmpUri = m_uri; + tmpUri.setPath(m_uri.getPath().getParent() / basicColorFile); + tmpFilename = tmpUri.get(); + EWOL_DEBUG("Shaper try load colorFile : '" << tmpFilename << "' with base : '" << basicColorFile << "'"); + } else { + EWOL_DEBUG("Shaper try load colorFile : '" << tmpFilename << "'"); + } + m_colorProperty = ewol::resource::ColorFile::create(tmpFilename); + if ( m_GLprogram != null + && m_colorProperty != null) { + etk::Vector listColor = m_colorProperty->getColors(); + for (auto tmpColor : listColor) { + int32_t glId = m_GLprogram->getUniform(tmpColor); + int32_t colorID = m_colorProperty->request(tmpColor); + m_listAssiciatedId.pushBack(ivec2(glId, colorID)); + } + } + } +} + +void ewol::compositing::Shaper::draw(bool _disableDepthTest) { + if (m_config == null) { + // this is a normale case ... the user can choice to have no config basic file ... + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + if (m_VBO->bufferSize(m_vboIdCoord) <= 0) { + return; + } + //glScalef(m_scaling.x, m_scaling.y, 1.0); + m_GLprogram->use(); + // set Matrix : translation/positionMatrix + mat4 tmpMatrix = gale::openGL::getMatrix(); + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // position: + m_GLprogram->sendAttributePointer(m_GLPosition, m_VBO, m_vboIdCoord); + // property + m_GLprogram->sendAttributePointer(m_GLPropertyPos, m_VBO, m_vboIdPos); + // all entry parameters : + m_GLprogram->uniform1i(m_GLStateActivate, m_stateActivate); + m_GLprogram->uniform1i(m_GLStateOld, m_stateOld); + m_GLprogram->uniform1i(m_GLStateNew, m_stateNew); + m_GLprogram->uniform1f(m_GLStateTransition, m_stateTransition); + for (auto element : m_listAssiciatedId) { + m_GLprogram->uniform(element.x(), m_colorProperty->get(element.y())); + } + if (m_resourceTexture != null) { + // TextureID + m_GLprogram->setTexture0(m_GLtexID, m_resourceTexture->getRendererId()); + } + // Request the draw of the elements : + //gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, SHAPER_NB_MAX_VERTEX); + gale::openGL::drawArrays(gale::openGL::renderMode::triangleStrip, 0, m_nbVertexToDisplay); + m_GLprogram->unUse(); +} + +void ewol::compositing::Shaper::clear() { + // nothing to do ... + m_propertySize = vec2(0,0); + m_propertyOrigin = vec2(0,0); + m_propertyInsidePosition = vec2(0,0); + m_propertyInsideSize = vec2(0,0); + m_VBO->clear(); +} + +bool ewol::compositing::Shaper::setState(int32_t _newState) { + if (m_stateActivate == _newState) { + return false; + } + m_stateActivate = _newState; + return true; +} + +bool ewol::compositing::Shaper::changeStatusIn(int32_t _newStatusId) { + if (_newStatusId != m_stateNew) { + m_nextStatusRequested = _newStatusId; + return true; + } + if( m_nextStatusRequested != -1 + || m_stateNew != m_stateOld) { + return true; + } + return false; +} + +bool ewol::compositing::Shaper::periodicCall(const ewol::event::Time& _event) { + EWOL_VERBOSE("call=" << _event << "state transition=" << m_stateTransition << " speedTime=" << m_config->getNumber(m_confIdChangeTime)); + // start : + if (m_stateTransition >= 1.0) { + m_stateOld = m_stateNew; + if( m_nextStatusRequested != -1 + && m_nextStatusRequested != m_stateOld) { + m_stateNew = m_nextStatusRequested; + m_nextStatusRequested = -1; + m_stateTransition = 0.0; + EWOL_VERBOSE(" ##### START ##### "); + } else { + m_nextStatusRequested = -1; + // disable periodic call ... + return false; + } + } + if (m_stateTransition<1.0) { + // check if no new state requested: + if (m_nextStatusRequested != -1 && m_stateTransition<0.5) { + // invert sources with destination + int32_t tmppp = m_stateOld; + m_stateOld = m_stateNew; + m_stateNew = tmppp; + m_stateTransition = 1.0 - m_stateTransition; + if (m_nextStatusRequested == m_stateNew) { + m_nextStatusRequested = -1; + } + } + float timeRelativity = 0.0f; + if (m_config != null) { + timeRelativity = m_config->getNumber(m_confIdChangeTime) / 1000.0; + } + m_stateTransition += _event.getDeltaCall() / timeRelativity; + //m_stateTransition += _event.getDeltaCall(); + m_stateTransition = etk::avg(0.0f, m_stateTransition, 1.0f); + EWOL_VERBOSE("relative=" << timeRelativity << " Transition : " << m_stateTransition); + } + return true; +} + +//Create Line: +void ewol::compositing::Shaper::addVertexLine(float _yTop, + float _yButtom, + float _x1, + float _x2, + float _x3, + float _x4, + float _x5, + float _x6, + float _x7, + float _x8, + float _yValTop, + float _yValButtom, + const float* _table, + bool _displayOutside) { + if (m_nbVertexToDisplay != 0) { + // change line ... + m_VBO->pushOnBuffer(m_vboIdCoord, + m_VBO->getOnBufferVec2(m_vboIdCoord, m_nbVertexToDisplay-1)); + m_VBO->pushOnBuffer(m_vboIdPos, + m_VBO->getOnBufferVec2(m_vboIdPos, m_nbVertexToDisplay-1)); + + m_nbVertexToDisplay++; + if (_displayOutside == true) { + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x1, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[0],_yValButtom)); + m_nbVertexToDisplay++; + } else { + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x2, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[1],_yValButtom)); + m_nbVertexToDisplay++; + } + } + + if (_displayOutside == true) { + // A + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x1, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[0],_yValButtom)); + m_nbVertexToDisplay++; + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x1, _yTop)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[0],_yValTop)); + m_nbVertexToDisplay++; + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x2, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[1],_yValButtom)); + m_nbVertexToDisplay++; + // B + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x2, _yTop)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[1],_yValTop)); + m_nbVertexToDisplay++; + + // C + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x3, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[2],_yValButtom)); + m_nbVertexToDisplay++; + } else { + // C + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x2, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[1],_yValButtom)); + m_nbVertexToDisplay++; + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x2, _yTop)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[1],_yValTop)); + m_nbVertexToDisplay++; + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x3, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[2],_yValButtom)); + m_nbVertexToDisplay++; + } + // D + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x3, _yTop)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[2],_yValTop)); + m_nbVertexToDisplay++; + + // E + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x4, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[3],_yValButtom)); + m_nbVertexToDisplay++; + // F + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x4, _yTop)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[3],_yValTop)); + m_nbVertexToDisplay++; + + // G + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x5, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[4],_yValButtom)); + m_nbVertexToDisplay++; + // H + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x5, _yTop)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[4],_yValTop)); + m_nbVertexToDisplay++; + + // I + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x6, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[5],_yValButtom)); + m_nbVertexToDisplay++; + // J + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x6, _yTop)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[5],_yValTop)); + m_nbVertexToDisplay++; + + // K + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x7, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[6],_yValButtom)); + m_nbVertexToDisplay++; + // L + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x7, _yTop)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[6],_yValTop)); + m_nbVertexToDisplay++; + + if (_displayOutside == true) { + // M + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x8, _yButtom)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[7],_yValButtom)); + m_nbVertexToDisplay++; + // N + m_VBO->pushOnBuffer(m_vboIdCoord, vec2(_x8, _yTop)); + m_VBO->pushOnBuffer(m_vboIdPos, vec2(_table[7],_yValTop)); + m_nbVertexToDisplay++; + } +} +const float modeDisplay[][8] = { + /* !! 0 !! + * / ******* + * / ****** / + * ****** / + */ + { 0.0f, 0.0f, 0.5f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f }, + /* !! 1 !! + * ****** \ + * \ ****** \ + * \ ******* + */ + { 1.0f, 1.0f, 0.5f, 0.5f, 0.5f, 0.5f, 0.0f, 0.0f }, + /* !! 2 !! + * / ****** \ + * ****** / \ ******* + */ + { 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f }, + /* !! 3 !! + * ****** \ / ******* + * \ ****** / + */ + { 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f }, + /* !! 4 !! + * / ******* + * / ****** / + * ****** / + */ + { -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f }, + /* !! 5 !! + * ****** \ + * \ ****** \ + * \ ******* + */ + { 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, -1.0f }, + /* !! 6 !! + * / ****** \ + * ****** / \ ******* + */ + { -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f }, + /* !! 7 !! + * ****** \ / ******* + * \ ****** / + */ + { 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f } +}; + +void ewol::compositing::Shaper::setShape(const vec2& _origin, const vec2& _size, const vec2& _insidePos, const vec2& _insideSize) { + m_VBO->clear(); + ewol::Padding borderTmp = getBorder(); + ewol::Padding paddingIn = getPaddingIn(); + ewol::Padding paddingOut = getPaddingOut(); + ewol::Padding padding = paddingIn + borderTmp + paddingOut; + ewol::Padding enveloppe(_origin.x(), + _origin.y() + _size.y(), + _origin.x() + _size.x(), + _origin.y()); + #if 0 + ewol::Padding inside(_insidePos.x(), + _insidePos.y() + _insideSize.y(), + _insidePos.x() + _insideSize.x(), + _insidePos.y()); + ewol::Padding insideBorder(inside.xLeft() - paddingIn.xLeft(), + inside.yTop() + paddingIn.yTop(), + inside.xRight() + paddingIn.xRight(), + inside.yButtom() - paddingIn.yButtom()); + ewol::Padding border(insideBorder.xLeft() - borderTmp.xLeft(), + insideBorder.yTop() + borderTmp.yTop(), + insideBorder.xRight() + borderTmp.xRight(), + insideBorder.yButtom() - borderTmp.yButtom()); + #else + ewol::Padding border(_insidePos.x() - padding.xLeft() + paddingOut.xLeft(), + _insidePos.y() + _insideSize.y() + padding.yTop() - paddingOut.yTop(), + _insidePos.x() + _insideSize.x() + padding.xRight() - paddingOut.xRight(), + _insidePos.y() - padding.yButtom() + paddingOut.yButtom()); + ewol::Padding insideBorder(border.xLeft() + borderTmp.xLeft(), + border.yTop() - borderTmp.yTop(), + border.xRight() - borderTmp.xRight(), + border.yButtom() + borderTmp.yButtom()); + ewol::Padding inside(insideBorder.xLeft() + etk::max(0.0f, paddingIn.xLeft()), + insideBorder.yTop() - etk::max(0.0f, paddingIn.yTop()), + insideBorder.xRight() - etk::max(0.0f, paddingIn.xRight()), + insideBorder.yButtom() + etk::max(0.0f, paddingIn.yButtom())); + + #endif + /* + EWOL_ERROR(" enveloppe = " << enveloppe); + EWOL_ERROR(" border = " << border); + EWOL_ERROR(" inside = " << inside); + */ + int32_t mode = 0; + bool displayOutside = false; + if (m_config != null) { + mode = m_config->getNumber(m_confIdMode); + displayOutside = m_config->getBoolean(m_confIdDisplayOutside); + } + m_nbVertexToDisplay = 0; + if (displayOutside == true) { + addVertexLine(enveloppe.yTop(), border.yTop(), + enveloppe.xLeft(), + border.xLeft(), + insideBorder.xLeft(), + inside.xLeft(), + inside.xRight(), + insideBorder.xRight(), + border.xRight(), + enveloppe.xRight(), + modeDisplay[mode][7], modeDisplay[mode][6], + modeDisplay[mode], + displayOutside); + } + addVertexLine(border.yTop(), insideBorder.yTop(), + enveloppe.xLeft(), + border.xLeft(), + insideBorder.xLeft(), + inside.xLeft(), + inside.xRight(), + insideBorder.xRight(), + border.xRight(), + enveloppe.xRight(), + modeDisplay[mode][6], modeDisplay[mode][5], + modeDisplay[mode], + displayOutside); + addVertexLine(insideBorder.yTop(), inside.yTop(), + enveloppe.xLeft(), + border.xLeft(), + insideBorder.xLeft(), + inside.xLeft(), + inside.xRight(), + insideBorder.xRight(), + border.xRight(), + enveloppe.xRight(), + modeDisplay[mode][5], modeDisplay[mode][4], + modeDisplay[mode], + displayOutside); + addVertexLine(inside.yTop(), inside.yButtom(), + enveloppe.xLeft(), + border.xLeft(), + insideBorder.xLeft(), + inside.xLeft(), + inside.xRight(), + insideBorder.xRight(), + border.xRight(), + enveloppe.xRight(), + modeDisplay[mode][4], modeDisplay[mode][3], + modeDisplay[mode], + displayOutside); + addVertexLine(inside.yButtom(), insideBorder.yButtom(), + enveloppe.xLeft(), + border.xLeft(), + insideBorder.xLeft(), + inside.xLeft(), + inside.xRight(), + insideBorder.xRight(), + border.xRight(), + enveloppe.xRight(), + modeDisplay[mode][3], modeDisplay[mode][2], + modeDisplay[mode], + displayOutside); + addVertexLine(insideBorder.yButtom(), border.yButtom(), + enveloppe.xLeft(), + border.xLeft(), + insideBorder.xLeft(), + inside.xLeft(), + inside.xRight(), + insideBorder.xRight(), + border.xRight(), + enveloppe.xRight(), + modeDisplay[mode][2], modeDisplay[mode][1], + modeDisplay[mode], + displayOutside); + if (displayOutside == true) { + addVertexLine(border.yButtom(), enveloppe.yButtom(), + enveloppe.xLeft(), + border.xLeft(), + insideBorder.xLeft(), + inside.xLeft(), + inside.xRight(), + insideBorder.xRight(), + border.xRight(), + enveloppe.xRight(), + modeDisplay[mode][1], modeDisplay[mode][0], + modeDisplay[mode], + displayOutside); + } + m_VBO->flush(); +} + +ewol::Padding ewol::compositing::Shaper::getPadding() { + return getPaddingOut() + getBorder() + getPaddingIn(); +} + +ewol::Padding ewol::compositing::Shaper::getPaddingIn() { + ewol::Padding padding(0,0,0,0); + if (m_config != null) { + padding.setValue(m_config->getNumber(m_confIdPaddingIn[shaperPosLeft]), + m_config->getNumber(m_confIdPaddingIn[shaperPosTop]), + m_config->getNumber(m_confIdPaddingIn[shaperPosRight]), + m_config->getNumber(m_confIdPaddingIn[shaperPosButtom])); + } + return padding; +} + +ewol::Padding ewol::compositing::Shaper::getPaddingOut() { + ewol::Padding padding(0,0,0,0); + if (m_config != null) { + padding.setValue(m_config->getNumber(m_confIdPaddingOut[shaperPosLeft]), + m_config->getNumber(m_confIdPaddingOut[shaperPosTop]), + m_config->getNumber(m_confIdPaddingOut[shaperPosRight]), + m_config->getNumber(m_confIdPaddingOut[shaperPosButtom])); + } + return padding; +} + +ewol::Padding ewol::compositing::Shaper::getBorder() { + ewol::Padding padding(0,0,0,0); + if (m_config != null) { + padding.setValue(m_config->getNumber(m_confIdBorder[shaperPosLeft]), + m_config->getNumber(m_confIdBorder[shaperPosTop]), + m_config->getNumber(m_confIdBorder[shaperPosRight]), + m_config->getNumber(m_confIdBorder[shaperPosButtom])); + } + return padding; +} + +void ewol::compositing::Shaper::setSource(const etk::Uri& _uri) { + clear(); + unLoadProgram(); + m_uri = _uri; + loadProgram(); +} + +bool ewol::compositing::Shaper::hasSources() { + return m_GLprogram != null; +} + + +const etk::Color& ewol::compositing::Shaper::getColor(int32_t _id) { + static const etk::Color errorValue(0,0,0,0); + if (m_colorProperty == null) { + EWOL_WARNING("null of m_colorProperty ==> return #0000 for id " << _id); + return errorValue; + } + return m_colorProperty->get(_id); +} + +int32_t ewol::compositing::Shaper::requestColor(const etk::String& _name) { + if (m_colorProperty == null) { + EWOL_WARNING("null of m_colorProperty ==> return -1 for name " << _name); + return -1; + } + return m_colorProperty->request(_name); +} + +int32_t ewol::compositing::Shaper::requestConfig(const etk::String& _name) { + if (m_config == null) { + EWOL_WARNING("null of m_config ==> return -1 for name " << _name); + return -1; + } + return m_config->request(_name); +} + +double ewol::compositing::Shaper::getConfigNumber(int32_t _id) { + if ( _id == -1 + || m_config == null) { + EWOL_WARNING("null of m_config ==> return 0.0 for id " << _id); + return 0.0; + } + return m_config->getNumber(_id); +} + + +namespace etk { + template<> etk::String toString(const ewol::compositing::Shaper& _obj) { + return _obj.getSource().get(); + } + template<> etk::UString toUString(const ewol::compositing::Shaper& _obj) { + return etk::toUString(etk::toString(_obj)); + } + template<> bool from_string(ewol::compositing::Shaper& _variableRet, const etk::String& _value) { + _variableRet.setSource(_value); + return true; + } + template<> bool from_string(ewol::compositing::Shaper& _variableRet, const etk::UString& _value) { + return from_string(_variableRet, etk::toString(_value)); + } +}; \ No newline at end of file diff --git a/src/org/atriasoft/ewol/compositing/Shaper.java b/src/org/atriasoft/ewol/compositing/Shaper.java new file mode 100644 index 0000000..db86d64 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Shaper.java @@ -0,0 +1,296 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace compositing { + enum renderMode { + renderSingleSquare, //!< basic historic render mode + renderBorder, //!< Render 4 squares for coiner, and renctangle for border, a big rentangle for background and 8 rectangle for the outside part + renderOneBorder, + }; + #define SHAPER_NB_MAX_QUAD (5*5) + #define SHAPER_NB_MAX_TRIANGLE (SHAPER_NB_MAX_QUAD*2) + #define SHAPER_NB_MAX_VERTEX (SHAPER_NB_MAX_TRIANGLE*3) + enum shaperPos { + shaperPosLeft, + shaperPosRight, + shaperPosTop, + shaperPosButtom, + shaperPosCount, + }; + /** + * @brief the Shaper system is a basic theme configuration for every widget, it corespond at a background display described by a pool of files + */ + // TODO : load image + // TODO : Abstaraction between states (call by name and the system greate IDs + class Shaper : public ewol::Compositing { + private: + etk::Uri m_uri; //!< Name of the configuration of the shaper. + // External theme config: + ememory::SharedPtr m_config; //!< pointer on the config file resources + int32_t m_confIdPaddingOut[shaperPosCount]; //!< Padding out property : X-left X-right Y-top Y-buttom + int32_t m_confIdBorder[shaperPosCount]; //!< border property : X-left X-right Y-top Y-buttom + int32_t m_confIdPaddingIn[shaperPosCount]; //!< Padding in property : X-left X-right Y-top Y-buttom + int32_t m_confIdMode; //!< Display mode + int32_t m_confIdDisplayOutside; //!< Display outside of the shape... + int32_t m_confIdChangeTime; //!< ConfigFile padding transition time property + int32_t m_confProgramFile; //!< ConfigFile opengGl program Name + int32_t m_confColorFile; //!< ConfigFile opengGl color file Name + int32_t m_confImageFile; //!< ConfigFile opengGl program Name + // openGL shaders programs: + ememory::SharedPtr m_GLprogram; //!< pointer on the opengl display program + int32_t m_GLPosition; //!< openGL id on the element (vertex buffer) + int32_t m_GLMatrix; //!< openGL id on the element (transformation matrix) + int32_t m_GLPropertyPos; //!< openGL id on the element (simple ratio position in the widget : ____/-----\_____ on vec2(X,Y)) + int32_t m_GLStateActivate; //!< openGL id on the element (activate state displayed) + int32_t m_GLStateOld; //!< openGL id on the element (old state displayed) + int32_t m_GLStateNew; //!< openGL id on the element (new state displayed) + int32_t m_GLStateTransition; //!< openGL id on the element (transition ofset [0.0..1.0] ) + int32_t m_GLtexID; //!< openGL id on the element (texture image) + // For the Image : + ememory::SharedPtr m_resourceTexture; //!< texture resources (for the image) + // internal needed data : + int32_t m_nextStatusRequested; //!< when status is changing, this represent the next step of it + vec2 m_propertyOrigin; //!< widget origin + vec2 m_propertySize; //!< widget size + vec2 m_propertyInsidePosition; //!< internal subwidget position + vec2 m_propertyInsideSize; //!< internal subwidget size + int32_t m_stateActivate; //!< Activate state of the element + int32_t m_stateOld; //!< previous state + int32_t m_stateNew; //!< destination state + float m_stateTransition; //!< working state between 2 states + int32_t m_nbVertexToDisplay; + // color management theme: + ememory::SharedPtr m_colorProperty; //!< input resource for color management + etk::Vector m_listAssiciatedId; //!< Corellation ID between ColorProperty (Y) and OpenGL Program (X) + protected: + static const int32_t m_vboIdCoord; + static const int32_t m_vboIdPos; + ememory::SharedPtr m_VBO; + private: + /** + * @brief load the openGL program and get all the ID needed + */ + void loadProgram(); + /** + * @brief Un-Load the openGL program and get all the ID needed + */ + void unLoadProgram(); + public: + /** + * @brief generic constructor + * @param[in] _uri URI of the file that might be loaded + */ + Shaper(const etk::Uri& _uri=""); + /** + * @brief generic destructor + */ + virtual ~Shaper(); + public: + /** + * @brief draw All the refistered text in the current element on openGL + */ + void draw(bool _disableDepthTest=true); + /** + * @brief clear alll tre registered element in the current element + */ + void clear(); + /** + * @brief Change the current state + * @param[in] _newState Current state of the configuration + * @return true Need redraw. + * @return false No need redraw. + */ + bool setState(int32_t _newState); + /** + * @brief change the current status in an other + * @param[in] _newStatusId the next new status requested + * @return true The widget must call this fuction periodicly (and redraw itself) + * @return false No need to request the periodic call. + */ + bool changeStatusIn(int32_t _newStatusId); + /** + * @brief get the current displayed status of the shaper + * @return The Status Id + */ + int32_t getCurrentDisplayedStatus() { + return m_stateNew; + }; + /** + * @brief get the next displayed status of the shaper + * @return The next status Id (-1 if no status in next) + */ + int32_t getNextDisplayedStatus() { + return m_nextStatusRequested; + }; + /** + * @brief get the current trasion status + * @return value of the transition status (0.0f when no activity) + */ + float getTransitionStatus() { + return m_stateTransition; + }; + /** + * @brief Same as the widfget periodic call (this is for change display) + * @param[in] _event The current time of the call. + * @return true The widget must call this fuction periodicly (and redraw itself) + * @return false No need to request the periodic call. + */ + bool periodicCall(const ewol::event::Time& _event); + /** + * @brief get the padding declared by the user in the config file + * @return the padding property + */ + ewol::Padding getPadding(); + ewol::Padding getPaddingIn(); + ewol::Padding getPaddingOut(); + /** + * @brief get the padding declared by the user in the config file + * @return the padding property + */ + ewol::Padding getBorder(); + /** + * @brief change the shaper Source + * @param[in] _uri New file of the shaper + */ + void setSource(const etk::Uri& _uri); + /** + * @brief get the shaper file Source + * @return the shapper file name + */ + const etk::Uri& getSource() const { + return m_uri; + }; + /** + * @brief Sometimes the user declare an image but not allocate the ressources all the time, this is to know it .. + * @return the validity od the resources. + */ + bool hasSources(); + public: + /** + * @brief set the shape property: + * + * ******************************************************************************** + * * _size * + * * * + * * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * + * * * + * * | | * + * * *************************************************** * + * * | * * | * + * * * * * + * * | * * - - - - - - - - - - - - - - - - - - * * | * + * * * _insideSize * * + * * | * | | * | * + * * * * * + * * | * | | * | * + * * * * * + * * | * | | * | * + * * * * * + * * | * | | * | * + * * * * * + * * | * | | * | * + * * * * * + * * | * | | * | * + * * * _insidePos * * + * * | * * - - - - - - - - - - - - - - - - - - * * | * + * * * * * + * * | *************************************************** | * + * * * + * * | | * + * * * + * * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * * + * * * + * * * + * ******************************************************************************** + * _origin + * + * + * @param[in] _origin Origin of the display + * @param[in] _size Size of the display + * @param[in] _insidePos Positin of the internal data + * @param[in] _insideSize Size of the internal data + */ + void setShape(const vec2& _origin, const vec2& _size, const vec2& _insidePos, const vec2& _insideSize); + // @previous + void setShape(const vec2& _origin, const vec2& _size) { + ewol::Padding tmp = getPadding(); + setShape(_origin, _size, _origin+vec2(tmp.xLeft(), tmp.yButtom()), _size - vec2(tmp.x(), tmp.y())); + } + public: + /** + * @brief Get an ID on the color instance element + * @param[in] _name Name of the element requested + * @return The Id of the color + */ + int32_t requestColor(const etk::String& _name); + /** + * @brief Get The color associated at an ID. + * @param[in] _id Id of the color + * @return the reference on the color + */ + const etk::Color& getColor(int32_t _id); + public: + /** + * @brief Get an ID on the configuration instance element + * @param[in] _name Name of the element requested + * @return The Id of the element + */ + int32_t requestConfig(const etk::String& _name); + /** + * @brief Get The number associated at an ID. + * @param[in] _id Id of the parameter + * @return the requested number. + */ + double getConfigNumber(int32_t _id); + public: + /** + * @brief Set activate state of the element + * @param[in] _status New activate status + */ + void setActivateState(int32_t _status) { + m_stateActivate = _status; + } + private: + void addVertexLine(float _yTop, + float _yButtom, + float _x1, + float _x2, + float _x3, + float _x4, + float _x5, + float _x6, + float _x7, + float _x8, + float _yValTop, + float _yValButtom, + const float* _table, + bool _displayOutside); + public: + /* **************************************************** + * == operator + *****************************************************/ + bool operator== (const Shaper& _obj) const { + return _obj.m_uri == m_uri; + } + bool operator!= (const Shaper& _obj) const { + return _obj.m_uri != m_uri; + } + }; + } +} + + diff --git a/src/org/atriasoft/ewol/compositing/Sprite.cpp b/src/org/atriasoft/ewol/compositing/Sprite.cpp new file mode 100644 index 0000000..16a5b97 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Sprite.cpp @@ -0,0 +1,39 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::compositing::Sprite); + +ewol::compositing::Sprite::Sprite(const etk::String& _imageName, const ivec2& _nbSprite, int32_t _size) : + ewol::compositing::Image(_imageName, false, _size), + m_nbSprite(_nbSprite), + m_unitarySpriteSize(0,0) { + /* + vec2 imageSize = getRealSize(); + m_unitarySpriteSize.setValue(imageSize.x()/(float)m_nbSprite.x(), + imageSize.y()/(float)m_nbSprite.y()); + */ + m_unitarySpriteSize.setValue(1.0/(float)m_nbSprite.x(), + 1.0/(float)m_nbSprite.y()); +} + + +void ewol::compositing::Sprite::printSprite(const ivec2& _spriteID, const vec3& _size) { + if( _spriteID.x()<0 + || _spriteID.y()<0 + || _spriteID.x() >= m_nbSprite.x() + || _spriteID.y() >= m_nbSprite.y()) { + return; + } + printPart(vec2(_size.x(),_size.y()), + vec2((float)(_spriteID.x() )*m_unitarySpriteSize.x(), (float)(_spriteID.y() )*m_unitarySpriteSize.y()), + vec2((float)(_spriteID.x()+1)*m_unitarySpriteSize.x(), (float)(_spriteID.y()+1)*m_unitarySpriteSize.y())); +} + + diff --git a/src/org/atriasoft/ewol/compositing/Sprite.java b/src/org/atriasoft/ewol/compositing/Sprite.java new file mode 100644 index 0000000..d2b5231 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Sprite.java @@ -0,0 +1,29 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ewol { + namespace compositing { + class Sprite : public ewol::compositing::Image { + protected: + ivec2 m_nbSprite; //!< number of sprite in vertical and horizontal + vec2 m_unitarySpriteSize; //!< size of a unique sprite + public: + Sprite(const etk::String& _imageName, + const ivec2& _nbSprite, + int32_t _size=ewol::compositing::Image::sizeAuto); + virtual ~Sprite() {}; + void printSprite(const ivec2& _spriteID, const vec2& _size) { + printSprite(_spriteID, vec3(_size.x(), _size.y(),0)); + }; + void printSprite(const ivec2& _spriteID, const vec3& _size); + }; + } +} + diff --git a/src/org/atriasoft/ewol/compositing/Text.cpp b/src/org/atriasoft/ewol/compositing/Text.cpp new file mode 100644 index 0000000..0b912e5 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Text.cpp @@ -0,0 +1,372 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::compositing::Text); + +ewol::compositing::Text::Text(const etk::String& _fontName, int32_t _fontSize) : + m_font(null) { + setFont(_fontName, _fontSize); +} + +ewol::compositing::Text::~Text() { + +} + +void ewol::compositing::Text::drawMT(const mat4& _transformationMatrix, bool _enableDepthTest) { + + // draw BG in any case: + m_vectorialDraw.draw(); + + if ( m_VBO->bufferSize(m_vboIdCoord) <= 0 + || m_font == null) { + // TODO : set it back ... + //EWOL_WARNING("Nothink to draw..."); + return; + } + if (m_font == null) { + EWOL_WARNING("no font..."); + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + if (_enableDepthTest == true) { + gale::openGL::enable(gale::openGL::flag_depthTest); + } + // set Matrix : translation/positionMatrix + mat4 projMatrix = gale::openGL::getMatrix(); + mat4 camMatrix = gale::openGL::getCameraMatrix(); + mat4 tmpMatrix = projMatrix * camMatrix * _transformationMatrix; + m_GLprogram->use(); + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // Texture: + m_GLprogram->setTexture0(m_GLtexID, m_font->getRendererId()); + m_GLprogram->uniform1i(m_GLtextWidth, m_font->getOpenGlSize().x()); + m_GLprogram->uniform1i(m_GLtextHeight, m_font->getOpenGlSize().x()); + // position: + m_GLprogram->sendAttributePointer(m_GLPosition, m_VBO, m_vboIdCoord); + // Texture: + m_GLprogram->sendAttributePointer(m_GLtexture, m_VBO, m_vboIdCoordText); + // color: + m_GLprogram->sendAttributePointer(m_GLColor, m_VBO, m_vboIdColor); + // Request the draw od the elements: + gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, m_VBO->bufferSize(m_vboIdCoord)); + m_GLprogram->unUse(); + if (_enableDepthTest == true) { + gale::openGL::disable(gale::openGL::flag_depthTest); + } +} + +void ewol::compositing::Text::drawD(bool _disableDepthTest) { + // draw BG in any case: + m_vectorialDraw.draw(_disableDepthTest); + + if ( m_VBO->bufferSize(m_vboIdCoord) <= 0 + || m_font == null) { + //EWOL_WARNING("Nothink to draw..."); + return; + } + if (m_font == null) { + EWOL_WARNING("no font..."); + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + // set Matrix : translation/positionMatrix + mat4 tmpMatrix = gale::openGL::getMatrix()*m_matrixApply; + m_GLprogram->use(); + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // Texture : + m_GLprogram->setTexture0(m_GLtexID, m_font->getRendererId()); + m_GLprogram->uniform1i(m_GLtextWidth, m_font->getOpenGlSize().x()); + m_GLprogram->uniform1i(m_GLtextHeight, m_font->getOpenGlSize().x()); + // position: + m_GLprogram->sendAttributePointer(m_GLPosition, m_VBO, m_vboIdCoord); + // Texture: + m_GLprogram->sendAttributePointer(m_GLtexture, m_VBO, m_vboIdCoordText); + // color: + m_GLprogram->sendAttributePointer(m_GLColor, m_VBO, m_vboIdColor); + // Request the draw od the elements : + gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, m_VBO->bufferSize(m_vboIdCoord)); + m_GLprogram->unUse(); +} + +float ewol::compositing::Text::getSize() { + if (m_font == null) { + EWOL_WARNING("no font..."); + return 1.0f; + } + return m_font->getFontSize(); +} +float ewol::compositing::Text::getHeight() { + if (m_font == null) { + EWOL_WARNING("no font..."); + return 10.0f; + } + return m_font->getHeight(m_mode); +} +ewol::GlyphProperty * ewol::compositing::Text::getGlyphPointer(char32_t _charcode) { + if (m_font == null) { + EWOL_WARNING("no font..."); + return null; + } + return m_font->getGlyphPointer(_charcode, m_mode); +} + +void ewol::compositing::Text::setFontSize(int32_t _fontSize) { + // get old size + etk::String fontName = ""; + if (m_font != null) { + fontName = m_font->getName(); + // Remove the :XX for the size ... + size_t pos = fontName.rfind(':'); + fontName.erase(pos, fontName.size()-pos); + } + setFont(fontName, _fontSize); +} + +void ewol::compositing::Text::setFontName(const etk::String& _fontName) { + // get old size + int32_t fontSize = -1; + if (m_font != null) { + fontSize = m_font->getFontSize(); + } + setFont(_fontName, fontSize); +} + +void ewol::compositing::Text::setFont(etk::String _fontName, int32_t _fontSize) { + clear(); + // remove old one + ememory::SharedPtr previousFont = m_font; + if (_fontSize <= 0) { + _fontSize = ewol::getContext().getFontDefault().getSize(); + } + if (_fontName == "") { + _fontName = ewol::getContext().getFontDefault().getName(); + } + _fontName += ":"; + _fontName += etk::toString(_fontSize); + EWOL_VERBOSE("plop : " << _fontName << " size=" << _fontSize << " result :" << _fontName); + // link to new one + m_font = ewol::resource::TexturedFont::create(_fontName); + if (m_font == null) { + EWOL_ERROR("Can not get font resource"); + m_font = previousFont; + } +} + +void ewol::compositing::Text::setFontMode(enum ewol::font::mode _mode) { + if (m_font != null) { + m_mode = m_font->getWrappingMode(_mode); + } +} + +void ewol::compositing::Text::printChar(const char32_t& _charcode) { + // get a pointer on the glyph property : + ewol::GlyphProperty* myGlyph = getGlyphPointer(_charcode); + if (null == myGlyph) { + EWOL_ERROR(" font does not really existed ..."); + return; + } + int32_t fontSize = getSize(); + int32_t fontHeigh = getHeight(); + + // get the kerning ofset : + float kerningOffset = 0; + if (m_kerning == true) { + kerningOffset = myGlyph->kerningGet(m_previousCharcode); + if (kerningOffset != 0) { + //EWOL_DEBUG("Kerning between : '" << m_previousCharcode << "'&'" << myGlyph->m_UVal << "' value : " << kerningOffset); + } + } + // 0x01 == 0x20 == ' '; + if (_charcode != 0x01) { + /* Bitmap position + * xA xB + * yC *------* + * | | + * | | + * yD *------* + */ + float dxA = m_position.x() + myGlyph->m_bearing.x() + kerningOffset; + float dxB = dxA + myGlyph->m_sizeTexture.x(); + float dyC = m_position.y() + myGlyph->m_bearing.y() + fontHeigh - fontSize; + float dyD = dyC - myGlyph->m_sizeTexture.y(); + + float tuA = myGlyph->m_texturePosStart.x(); + float tuB = tuA + myGlyph->m_texturePosSize.x(); + float tvC = myGlyph->m_texturePosStart.y(); + float tvD = tvC + myGlyph->m_texturePosSize.y(); + + + // Clipping and drawing area + if( m_clippingEnable == true + && ( dxB < m_clippingPosStart.x() + || dxA > m_clippingPosStop.x() + || dyC < m_clippingPosStart.y() + || dyD > m_clippingPosStop.y() ) ) { + // Nothing to diplay ... + } else { + if (m_clippingEnable == true) { + // generata positions... + float TexSizeX = tuB - tuA; + if (dxA < m_clippingPosStart.x()) { + // clip display + float drawSize = m_clippingPosStart.x() - dxA; + // update element start display + dxA = m_clippingPosStart.x(); + float addElement = TexSizeX * drawSize / (float)myGlyph->m_sizeTexture.x(); + // update texture start X Pos + tuA += addElement; + } + if (dxB > m_clippingPosStop.x()) { + // clip display + float drawSize = dxB - m_clippingPosStop.x(); + // update element start display + dxB = m_clippingPosStop.x(); + float addElement = TexSizeX * drawSize / (float)myGlyph->m_sizeTexture.x(); + // update texture start X Pos + tuB -= addElement; + } + float TexSizeY = tvC - tvD; + if (dyC > m_clippingPosStop.y()) { + // clip display + float drawSize = dyC - m_clippingPosStop.y(); + // update element start display + dyC = m_clippingPosStop.y(); + float addElement = TexSizeY * drawSize / (float)myGlyph->m_sizeTexture.y(); + // update texture start X Pos + tvC -= addElement; + } + if (dyD < m_clippingPosStart.y()) { + // clip display + float drawSize = m_clippingPosStart.y() - dyD; + // update element start display + dyD = m_clippingPosStart.y(); + float addElement = TexSizeY * drawSize / (float)myGlyph->m_sizeTexture.y(); + // update texture start X Pos + tvD += addElement; + } + } + if( dxB <= dxA + || dyD >= dyC) { + // nothing to do ... + } else { + /* Bitmap position + * 0------1 + * | | + * | | + * 3------2 + */ + if (m_needDisplay == true) { + vec3 bitmapDrawPos[4]; + bitmapDrawPos[0].setValue((int32_t)dxA, (int32_t)dyC, 0); + bitmapDrawPos[1].setValue((int32_t)dxB, (int32_t)dyC, 0); + bitmapDrawPos[2].setValue((int32_t)dxB, (int32_t)dyD, 0); + bitmapDrawPos[3].setValue((int32_t)dxA, (int32_t)dyD, 0); + /* texture Position : + * 0------1 + * | | + * | | + * 3------2 + */ + vec2 texturePos[4]; + texturePos[0].setValue(tuA+m_mode, tvC); + texturePos[1].setValue(tuB+m_mode, tvC); + texturePos[2].setValue(tuB+m_mode, tvD); + texturePos[3].setValue(tuA+m_mode, tvD); + + // NOTE : Android does not support the Quads elements ... + /* Step 1 : + * ******** + * ****** + * **** + * ** + * + */ + // set texture coordonates : + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[0]); + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[1]); + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[2]); + // set display positions : + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[0]); + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[1]); + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[2]); + // set the color + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + /* Step 2 : + * + * ** + * **** + * ****** + * ******** + */ + // set texture coordonates : + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[0]); + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[2]); + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[3]); + // set display positions : + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[0]); + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[2]); + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[3]); + // set the color + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + } + } + } + } + // move the position : + //EWOL_DEBUG(" 5 pos=" << m_position << " advance=" << myGlyph->m_advance.x() << " kerningOffset=" << kerningOffset); + m_position.setX(m_position.x() + myGlyph->m_advance.x() + kerningOffset); + //EWOL_DEBUG(" 6 print '" << charcode << "' : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + // Register the previous character + m_previousCharcode = _charcode; + m_VBO->flush(); + return; +} + + +vec3 ewol::compositing::Text::calculateSizeChar(const char32_t& _charcode) { + // get a pointer on the glyph property : + ewol::GlyphProperty * myGlyph = getGlyphPointer(_charcode); + int32_t fontHeigh = getHeight(); + if (myGlyph == null) { + if (m_font == null) { + EWOL_WARNING("no Glyph... in no font"); + } else { + EWOL_WARNING("no Glyph... in font : " << m_font->getName()); + } + return vec3((float)(0.2), + (float)(fontHeigh), + (float)(0.0)); + } + // get the kerning ofset : + float kerningOffset = 0.0; + if (m_kerning == true) { + kerningOffset = myGlyph->kerningGet(m_previousCharcode); + } + + vec3 outputSize((float)(myGlyph->m_advance.x() + kerningOffset), + (float)(fontHeigh), + (float)(0.0)); + // Register the previous character + m_previousCharcode = _charcode; + return outputSize; +} + diff --git a/src/org/atriasoft/ewol/compositing/Text.java b/src/org/atriasoft/ewol/compositing/Text.java new file mode 100644 index 0000000..8e9d3ac --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/Text.java @@ -0,0 +1,56 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace ewol { + namespace compositing { + class Text : public ewol::compositing::TextBase { + protected: + ememory::SharedPtr m_font; //!< Font resources + public: + /** + * @brief generic constructor + * @param[in] _fontName Name of the font that might be loaded + * @param[in] _fontSize size of the font that might be loaded + */ + Text(const etk::String& _fontName="", int32_t _fontSize=-1); + /** + * @brief generic destructor + */ + virtual ~Text(); + public: + virtual void drawD(bool _disableDepthTest); + virtual void drawMT(const mat4& _transformationMatrix, bool _enableDepthTest); + protected: + float m_size; + public: + virtual float getHeight(); + virtual float getSize(); + virtual ewol::GlyphProperty * getGlyphPointer(char32_t _charcode); + + public: + virtual void setFontSize(int32_t _fontSize); + virtual void setFontName(const etk::String& _fontName); + virtual void setFont(etk::String _fontName, int32_t _fontSize); + virtual void setFontMode(enum ewol::font::mode _mode); + virtual void printChar(const char32_t& _charcode); + virtual vec3 calculateSizeChar(const char32_t& _charcode); + }; + } +} + diff --git a/src/org/atriasoft/ewol/compositing/TextBase.cpp b/src/org/atriasoft/ewol/compositing/TextBase.cpp new file mode 100644 index 0000000..1869c9e --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/TextBase.cpp @@ -0,0 +1,1116 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::compositing::TextBase); + +const int32_t ewol::compositing::TextBase::m_vboIdCoord(0); +const int32_t ewol::compositing::TextBase::m_vboIdCoordText(1); +const int32_t ewol::compositing::TextBase::m_vboIdColor(2); +const int32_t ewol::compositing::TextBase::m_vboIdGlyphLevel(3); +#define NB_VBO (4) + +ewol::compositing::TextBase::TextBase(const etk::String& _shaderName, bool _loadProgram) : + m_position(0.0, 0.0, 0.0), + m_clippingPosStart(0.0, 0.0, 0.0), + m_clippingPosStop(0.0, 0.0, 0.0), + m_clippingEnable(false), + m_defaultColorFg(etk::color::black), + m_defaultColorBg(etk::color::none), + m_color(etk::color::black), + m_colorBg(etk::color::none), + m_colorCursor(etk::color::black), + m_colorSelection(etk::color::olive), + m_mode(ewol::font::Regular), + m_kerning(true), + m_previousCharcode(0), + m_startTextpos(0), + m_stopTextPos(0), + m_alignement(alignDisable), + m_GLprogram(null), + m_GLPosition(-1), + m_GLMatrix(-1), + m_GLColor(-1), + m_GLtexture(-1), + m_GLtexID(-1), + m_selectionStartPos(-100), + m_cursorPos(-100) { + if (_loadProgram == true) { + loadProgram(_shaderName); + } + // Create the VBO: + m_VBO = gale::resource::VirtualBufferObject::create(NB_VBO); + if (m_VBO == null) { + EWOL_ERROR("can not instanciate VBO ..."); + return; + } + // TO facilitate some debugs we add a name of the VBO: + m_VBO->setName("[VBO] of ewol::compositing::TextBase"); +} + + +ewol::compositing::TextBase::~TextBase() { + +} + +void ewol::compositing::TextBase::loadProgram(const etk::String& _shaderName) { + // get the shader resource: + m_GLPosition = 0; + ememory::SharedPtr old = m_GLprogram; + m_GLprogram = gale::resource::Program::create(_shaderName); + if (m_GLprogram != null) { + m_GLPosition = m_GLprogram->getAttribute("EW_coord3d"); + m_GLColor = m_GLprogram->getAttribute("EW_color"); + m_GLtexture = m_GLprogram->getAttribute("EW_texture2d"); + m_GLMatrix = m_GLprogram->getUniform("EW_MatrixTransformation"); + m_GLtexID = m_GLprogram->getUniform("EW_texID"); + m_GLtextWidth = m_GLprogram->getUniform("EW_texWidth"); + m_GLtextHeight = m_GLprogram->getUniform("EW_texHeight"); + } else { + EWOL_ERROR("Can not load the program => create previous one..."); + m_GLprogram = old; + old = null; + } +} + +void ewol::compositing::TextBase::translate(const vec3& _vect) { + ewol::Compositing::translate(_vect); + m_vectorialDraw.translate(_vect); +} + +void ewol::compositing::TextBase::rotate(const vec3& _vect, float _angle) { + ewol::Compositing::rotate(_vect, _angle); + m_vectorialDraw.rotate(_vect, _angle); +} + +void ewol::compositing::TextBase::scale(const vec3& _vect) { + ewol::Compositing::scale(_vect); + m_vectorialDraw.scale(_vect); +} + +void ewol::compositing::TextBase::clear() { + // call upper class + ewol::Compositing::clear(); + // remove sub draw system + m_vectorialDraw.clear(); + // reset Buffer: + m_VBO->clear(); + // reset temporal variables: + reset(); +} + +void ewol::compositing::TextBase::reset() { + m_position = vec3(0,0,0); + m_clippingPosStart = vec3(0,0,0); + m_clippingPosStop = vec3(0,0,0); + m_sizeDisplayStart = m_position; + m_sizeDisplayStop = m_position; + m_nbCharDisplayed = 0; + m_clippingEnable = false; + m_color = m_defaultColorFg; + m_colorBg = m_defaultColorBg; + m_mode = ewol::font::Regular; + m_previousCharcode = 0; + m_startTextpos = 0; + m_stopTextPos = 0; + m_alignement = alignDisable; + m_htmlCurrrentLine = U""; + m_selectionStartPos = -100; + m_cursorPos = -100; + m_htmlDecoration.clear(); + m_needDisplay = true; + m_nbCharDisplayed = 0; +} + +void ewol::compositing::TextBase::setPos(const vec3& _pos) { + // check min max for display area + if (m_nbCharDisplayed != 0) { + EWOL_VERBOSE("update size 1 " << m_sizeDisplayStart << " " << m_sizeDisplayStop); + m_sizeDisplayStop.setX(etk::max(m_position.x(), m_sizeDisplayStop.x())); + m_sizeDisplayStop.setY(etk::max(m_position.y(), m_sizeDisplayStop.y())); + m_sizeDisplayStart.setX(etk::min(m_position.x(), m_sizeDisplayStart.x())); + m_sizeDisplayStart.setY(etk::min(m_position.y(), m_sizeDisplayStart.y())); + EWOL_VERBOSE("update size 2 " << m_sizeDisplayStart << " " << m_sizeDisplayStop); + } + // update position + m_position = _pos; + m_previousCharcode = 0; + m_vectorialDraw.setPos(m_position); + // update min max of the display area: + if (m_nbCharDisplayed == 0) { + m_sizeDisplayStart = m_position; + m_sizeDisplayStop = m_position; + m_sizeDisplayStop.setY( m_sizeDisplayStop.y()+ getHeight()); + EWOL_VERBOSE("update size 0 " << m_sizeDisplayStart << " " << m_sizeDisplayStop); + } else { + EWOL_VERBOSE("update size 3 " << m_sizeDisplayStart << " " << m_sizeDisplayStop); + m_sizeDisplayStop.setX(etk::max(m_position.x(), m_sizeDisplayStop.x())); + m_sizeDisplayStop.setY(etk::max(m_position.y(), m_sizeDisplayStop.y())); + m_sizeDisplayStart.setX(etk::min(m_position.x(), m_sizeDisplayStart.x())); + m_sizeDisplayStart.setY(etk::min(m_position.y(), m_sizeDisplayStart.y())); + EWOL_VERBOSE("update size 4 " << m_sizeDisplayStart << " " << m_sizeDisplayStop); + } +} + +void ewol::compositing::TextBase::setRelPos(const vec3& _pos) { + m_position += _pos; + m_previousCharcode = 0; + m_vectorialDraw.setPos(m_position); +} + +void ewol::compositing::TextBase::setColorBg(const etk::Color<>& _color) { + m_colorBg = _color; + m_vectorialDraw.setColor(_color); +} + +void ewol::compositing::TextBase::setClipping(const vec3& _pos, const vec3& _posEnd) { + // note the internal system all time request to have a bounding all time in the same order + if (_pos.x() <= _posEnd.x()) { + m_clippingPosStart.setX(_pos.x()); + m_clippingPosStop.setX(_posEnd.x()); + } else { + m_clippingPosStart.setX(_posEnd.x()); + m_clippingPosStop.setX(_pos.x()); + } + if (_pos.y() <= _posEnd.y()) { + m_clippingPosStart.setY(_pos.y()); + m_clippingPosStop.setY(_posEnd.y()); + } else { + m_clippingPosStart.setY(_posEnd.y()); + m_clippingPosStop.setY(_pos.y()); + } + if (_pos.z() <= _posEnd.z()) { + m_clippingPosStart.setZ(_pos.z()); + m_clippingPosStop.setZ(_posEnd.z()); + } else { + m_clippingPosStart.setZ(_posEnd.z()); + m_clippingPosStop.setZ(_pos.z()); + } + m_clippingEnable = true; + //m_vectorialDraw.setClipping(m_clippingPosStart, m_clippingPosStop); +} + +void ewol::compositing::TextBase::setClippingMode(bool _newMode) { + m_clippingEnable = _newMode; + //m_vectorialDraw.setClippingMode(m_clippingEnable); +} + +void ewol::compositing::TextBase::setFontBold(bool _status) { + if (_status == true) { + // enable + if (m_mode == ewol::font::Regular) { + setFontMode(ewol::font::Bold); + } else if (m_mode == ewol::font::Italic) { + setFontMode(ewol::font::BoldItalic); + } + } else { + // disable + if (m_mode == ewol::font::Bold) { + setFontMode(ewol::font::Regular); + } else if (m_mode == ewol::font::BoldItalic) { + setFontMode(ewol::font::Italic); + } + } +} + +void ewol::compositing::TextBase::setFontItalic(bool _status) { + if (_status == true) { + // enable + if (m_mode == ewol::font::Regular) { + setFontMode(ewol::font::Italic); + } else if (m_mode == ewol::font::Bold) { + setFontMode(ewol::font::BoldItalic); + } + } else { + // disable + if (m_mode == ewol::font::Italic) { + setFontMode(ewol::font::Regular); + } else if (m_mode == ewol::font::BoldItalic) { + setFontMode(ewol::font::Bold); + } + } +} + +void ewol::compositing::TextBase::setKerningMode(bool _newMode) { + m_kerning = _newMode; +} + +void ewol::compositing::TextBase::print(const etk::UString& _text) { + etk::Vector decorationEmpty; + print(_text, decorationEmpty); +} + +void ewol::compositing::TextBase::print(const etk::String& _text) { + etk::Vector decorationEmpty; + print(_text, decorationEmpty); +} + + +void ewol::compositing::TextBase::parseHtmlNode(const exml::Element& _element) { + // get the static real pointer + if (_element.exist() == false) { + EWOL_ERROR( "Error Input node does not existed ..."); + return; + } + for(auto it : _element.nodes) { + if (it.isComment() == true) { + // nothing to do ... + continue; + } else if (it.isText() == true) { + htmlAddData(etk::toUString(it.getValue())); + EWOL_VERBOSE("XML add : " << it.getValue()); + continue; + } else if (it.isElement() == false) { + EWOL_ERROR("(l "<< it.getPos() << ") node not suported type : " << it.getType() << " val='"<< it.getValue() << "'" ); + continue; + } + exml::Element elem = it.toElement(); + if (elem.exist() == false) { + EWOL_ERROR("Cast error ..."); + continue; + } + if(etk::compare_no_case(elem.getValue(), "br") == true) { + htmlFlush(); + EWOL_VERBOSE("XML flush & newLine"); + forceLineReturn(); + } else if (etk::compare_no_case(elem.getValue(), "font") == true) { + EWOL_VERBOSE("XML Font ..."); + TextDecoration tmpDeco = m_htmlDecoTmp; + etk::String colorValue = elem.attributes["color"]; + if (colorValue.size() != 0) { + m_htmlDecoTmp.m_colorFg = colorValue; + } + colorValue = elem.attributes["colorBg"]; + if (colorValue.size() != 0) { + m_htmlDecoTmp.m_colorBg = colorValue; + } + parseHtmlNode(elem); + m_htmlDecoTmp = tmpDeco; + } else if( etk::compare_no_case(elem.getValue(), "b") == true + || etk::compare_no_case(elem.getValue(), "bold") == true) { + EWOL_VERBOSE("XML bold ..."); + TextDecoration tmpDeco = m_htmlDecoTmp; + if (m_htmlDecoTmp.m_mode == ewol::font::Regular) { + m_htmlDecoTmp.m_mode = ewol::font::Bold; + } else if (m_htmlDecoTmp.m_mode == ewol::font::Italic) { + m_htmlDecoTmp.m_mode = ewol::font::BoldItalic; + } + parseHtmlNode(elem); + m_htmlDecoTmp = tmpDeco; + } else if( etk::compare_no_case(elem.getValue(), "i") == true + || etk::compare_no_case(elem.getValue(), "italic") == true) { + EWOL_VERBOSE("XML italic ..."); + TextDecoration tmpDeco = m_htmlDecoTmp; + if (m_htmlDecoTmp.m_mode == ewol::font::Regular) { + m_htmlDecoTmp.m_mode = ewol::font::Italic; + } else if (m_htmlDecoTmp.m_mode == ewol::font::Bold) { + m_htmlDecoTmp.m_mode = ewol::font::BoldItalic; + } + parseHtmlNode(elem); + m_htmlDecoTmp = tmpDeco; + } else if( etk::compare_no_case(elem.getValue(), "u") == true + || etk::compare_no_case(elem.getValue(), "underline") == true) { + EWOL_VERBOSE("XML underline ..."); + parseHtmlNode(elem); + } else if( etk::compare_no_case(elem.getValue(), "p") == true + || etk::compare_no_case(elem.getValue(), "paragraph") == true) { + EWOL_VERBOSE("XML paragraph ..."); + htmlFlush(); + m_alignement = alignLeft; + forceLineReturn(); + parseHtmlNode(elem); + forceLineReturn(); + } else if (etk::compare_no_case(elem.getValue(), "center") == true) { + EWOL_VERBOSE("XML center ..."); + htmlFlush(); + m_alignement = alignCenter; + parseHtmlNode(elem); + } else if (etk::compare_no_case(elem.getValue(), "left") == true) { + EWOL_VERBOSE("XML left ..."); + htmlFlush(); + m_alignement = alignLeft; + parseHtmlNode(elem); + } else if (etk::compare_no_case(elem.getValue(), "right") == true) { + EWOL_VERBOSE("XML right ..."); + htmlFlush(); + m_alignement = alignRight; + parseHtmlNode(elem); + } else if (etk::compare_no_case(elem.getValue(), "justify") == true) { + EWOL_VERBOSE("XML justify ..."); + htmlFlush(); + m_alignement = alignJustify; + parseHtmlNode(elem); + } else { + EWOL_ERROR("(l "<< elem.getPos() << ") node not suported type: " << elem.getType() << " val='"<< elem.getValue() << "'" ); + } + } +} + +void ewol::compositing::TextBase::printDecorated(const etk::String& _text) { + etk::String tmpData("\n\n"); + tmpData += _text; + tmpData += "\n\n\n"; + //EWOL_DEBUG("plop : " << tmpData); + printHTML(tmpData); +} + +void ewol::compositing::TextBase::printDecorated(const etk::UString& _text) { + etk::UString tmpData(U"\n\n"); + tmpData += _text; + tmpData += U"\n\n\n"; + //EWOL_DEBUG("plop : " << tmpData); + printHTML(tmpData); +} + +void ewol::compositing::TextBase::printHTML(const etk::String& _text) { + exml::Document doc; + + // reset parameter : + m_htmlDecoTmp.m_colorBg = m_defaultColorBg; + m_htmlDecoTmp.m_colorFg = m_defaultColorFg; + m_htmlDecoTmp.m_mode = ewol::font::Regular; + + if (doc.parse(_text) == false) { + EWOL_ERROR( "can not load XML: PARSING error: Decorated text "); + return; + } + + exml::Element root = doc.nodes["html"]; + if (root.exist() == false) { + EWOL_ERROR( "can not load XML: main node not find: 'html'"); + doc.display(); + return; + } + exml::Element bodyNode = root.nodes["body"]; + if (root.exist() == false) { + EWOL_ERROR( "can not load XML: main node not find: 'body'"); + return; + } + parseHtmlNode(bodyNode); + htmlFlush(); +} + +void ewol::compositing::TextBase::printHTML(const etk::UString& _text) { + exml::Document doc; + + // reset parameter : + m_htmlDecoTmp.m_colorBg = m_defaultColorBg; + m_htmlDecoTmp.m_colorFg = m_defaultColorFg; + m_htmlDecoTmp.m_mode = ewol::font::Regular; + // TODO : Create an instance of xml parser to manage etk::UString... + if (doc.parse(etk::toString(_text)) == false) { + EWOL_ERROR( "can not load XML: PARSING error: Decorated text "); + return; + } + + exml::Element root = doc.nodes["html"]; + if (root.exist() == false) { + EWOL_ERROR( "can not load XML: main node not find: 'html'"); + doc.display(); + return; + } + exml::Element bodyNode = root.nodes["body"]; + if (root.exist() == false) { + EWOL_ERROR( "can not load XML: main node not find: 'body'"); + return; + } + parseHtmlNode(bodyNode); + htmlFlush(); +} + +void ewol::compositing::TextBase::print(const etk::String& _text, const etk::Vector& _decoration) { + etk::Color<> tmpFg(m_color); + etk::Color<> tmpBg(m_colorBg); + if (m_alignement == alignDisable) { + //EWOL_DEBUG(" 1 print in not alligned mode : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + // display the cursor if needed (if it is at the start position...) + if (m_needDisplay == true) { + if (0 == m_cursorPos) { + m_vectorialDraw.setPos(m_position); + setColorBg(m_colorCursor); + printCursor(false); + } + } + // note this is faster when nothing is requested ... + for(size_t iii=0; iii<_text.size(); iii++) { + // check if ve have decoration + if (iii<_decoration.size()) { + tmpFg = _decoration[iii].m_colorFg; + tmpBg = _decoration[iii].m_colorBg; + setFontMode(_decoration[iii].m_mode); + } + // if real display : ( not display is for size calculation) + if (m_needDisplay == true) { + if( ( m_selectionStartPos-1 < (int64_t)iii + && (int64_t)iii <= m_cursorPos-1) + || ( m_selectionStartPos-1 >= (int64_t)iii + && (int64_t)iii > m_cursorPos-1) ) { + setColor( 0x000000FF); + setColorBg(m_colorSelection); + } else { + setColor( tmpFg); + setColorBg(tmpBg); + } + } + if( m_needDisplay == true + && m_colorBg.a() != 0) { + vec3 pos = m_position; + m_vectorialDraw.setPos(pos); + printChar(_text[iii]); + float fontHeigh = getHeight(); + m_vectorialDraw.rectangleWidth(vec3(m_position.x()-pos.x(),fontHeigh,0.0f) ); + m_nbCharDisplayed++; + } else { + printChar(_text[iii]); + m_nbCharDisplayed++; + } + // display the cursor if needed (if it is at the other position...) + if (m_needDisplay == true) { + if ((int64_t)iii == m_cursorPos-1) { + m_vectorialDraw.setPos(m_position); + setColorBg(m_colorCursor); + printCursor(false); + } + } + } + //EWOL_DEBUG(" 2 print in not alligned mode : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + } else { + //EWOL_DEBUG(" 3 print in not alligned mode : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + // special start case at the right of the endpoint : + if (m_stopTextPos < m_position.x()) { + forceLineReturn(); + } + float basicSpaceWidth = calculateSize(char32_t(' ')).x(); + int32_t currentId = 0; + int32_t stop; + int32_t space; + int32_t freeSpace; + while (currentId < (int64_t)_text.size()) { + bool needNoJustify = extrapolateLastId(_text, currentId, stop, space, freeSpace); + float interpolation = basicSpaceWidth; + switch (m_alignement) { + case alignJustify: + if (needNoJustify == false) { + interpolation += (float)freeSpace / (float)(space-1); + } + break; + case alignDisable: // must not came from here ... + case alignLeft: + // nothing to do ... + break; + case alignRight: + if (m_needDisplay == true) { + // Move the first char at the right : + setPos(vec3(m_position.x() + freeSpace, + m_position.y(), + m_position.z()) ); + } + break; + case alignCenter: + if (m_needDisplay == true) { + // Move the first char at the right : + setPos(vec3(m_position.x() + freeSpace/2, + m_position.y(), + m_position.z()) ); + } + break; + } + // display all the elements + if( m_needDisplay == true + && m_cursorPos == 0) { + m_vectorialDraw.setPos(m_position); + setColorBg(m_colorCursor); + printCursor(false); + } + for(size_t iii=currentId; (int64_t)iii= (int64_t)iii + && (int64_t)iii > m_cursorPos-1) ) { + setColor( 0x000000FF); + setColorBg(m_colorSelection); + } else { + setColor( tmpFg); + setColorBg(tmpBg); + } + } + // special for the justify mode + if ((char32_t)_text[iii] == u32char::Space) { + //EWOL_DEBUG(" generateString : \" \""); + if( m_needDisplay == true + && m_colorBg.a() != 0) { + m_vectorialDraw.setPos(m_position); + } + // Must generate a dynamic space : + setPos(vec3(m_position.x() + interpolation, + m_position.y(), + m_position.z()) ); + if( m_needDisplay == true + && m_colorBg.a() != 0) { + m_vectorialDraw.rectangleWidth(vec3(interpolation,fontHeigh,0.0f) ); + } + } else { + //EWOL_DEBUG(" generateString : \"" << (char)text[iii] << "\""); + if( m_needDisplay == true + && m_colorBg.a() != 0) { + vec3 pos = m_position; + m_vectorialDraw.setPos(pos); + printChar(_text[iii]); + m_vectorialDraw.rectangleWidth(vec3(m_position.x()-pos.x(),fontHeigh,0.0f) ); + m_nbCharDisplayed++; + } else { + printChar(_text[iii]); + m_nbCharDisplayed++; + } + } + if (m_needDisplay == true) { + if ((int64_t)iii == m_cursorPos-1) { + m_vectorialDraw.setPos(m_position); + setColorBg(m_colorCursor); + printCursor(false); + } + } + } + if (currentId == stop) { + currentId++; + } else if((char32_t)_text[stop] == u32char::Space) { + currentId = stop+1; + // reset position : + setPos(vec3(m_startTextpos, + (float)(m_position.y() - getHeight()), + m_position.z()) ); + m_nbCharDisplayed++; + } else if((char32_t)_text[stop] == u32char::Return) { + currentId = stop+1; + // reset position : + setPos(vec3(m_startTextpos, + (float)(m_position.y() - getHeight()), + m_position.z()) ); + m_nbCharDisplayed++; + } else { + currentId = stop; + } + } + //EWOL_DEBUG(" 4 print in not alligned mode : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + } +} + +void ewol::compositing::TextBase::print(const etk::UString& _text, const etk::Vector& _decoration) { + etk::Color<> tmpFg(m_color); + etk::Color<> tmpBg(m_colorBg); + if (m_alignement == alignDisable) { + //EWOL_DEBUG(" 1 print in not alligned mode : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + // display the cursor if needed (if it is at the start position...) + if (m_needDisplay == true) { + if (0 == m_cursorPos) { + m_vectorialDraw.setPos(m_position); + setColorBg(m_colorCursor); + printCursor(false); + } + } + // note this is faster when nothing is requested ... + for(size_t iii=0; iii<_text.size(); iii++) { + // check if ve have decoration + if (iii<_decoration.size()) { + tmpFg = _decoration[iii].m_colorFg; + tmpBg = _decoration[iii].m_colorBg; + setFontMode(_decoration[iii].m_mode); + } + // if real display : ( not display is for size calculation) + if (m_needDisplay == true) { + if( ( m_selectionStartPos-1<(int64_t)iii + && (int64_t)iii <= m_cursorPos-1) + || ( m_selectionStartPos-1 >= (int64_t)iii + && (int64_t)iii > m_cursorPos-1) ) { + setColor( 0x000000FF); + setColorBg(m_colorSelection); + } else { + setColor( tmpFg); + setColorBg(tmpBg); + } + } + if( m_needDisplay == true + && m_colorBg.a() != 0) { + vec3 pos = m_position; + m_vectorialDraw.setPos(pos); + printChar(_text[iii]); + float fontHeigh = getHeight(); + m_vectorialDraw.rectangleWidth(vec3(m_position.x()-pos.x(),fontHeigh,0.0f) ); + m_nbCharDisplayed++; + } else { + printChar(_text[iii]); + m_nbCharDisplayed++; + } + // display the cursor if needed (if it is at the other position...) + if (m_needDisplay == true) { + if ((int64_t)iii == m_cursorPos-1) { + m_vectorialDraw.setPos(m_position); + setColorBg(m_colorCursor); + printCursor(false); + } + } + } + //EWOL_DEBUG(" 2 print in not alligned mode : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + } else { + //EWOL_DEBUG(" 3 print in not alligned mode : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + // special start case at the right of the endpoint : + if (m_stopTextPos < m_position.x()) { + forceLineReturn(); + } + float basicSpaceWidth = calculateSize(char32_t(' ')).x(); + int32_t currentId = 0; + int32_t stop; + int32_t space; + int32_t freeSpace; + while (currentId < (int64_t)_text.size()) { + bool needNoJustify = extrapolateLastId(_text, currentId, stop, space, freeSpace); + float interpolation = basicSpaceWidth; + switch (m_alignement) { + case alignJustify: + if (needNoJustify == false) { + interpolation += (float)freeSpace / (float)(space-1); + } + break; + case alignDisable: // must not came from here ... + case alignLeft: + // nothing to do ... + break; + case alignRight: + if (m_needDisplay == true) { + // Move the first char at the right : + setPos(vec3(m_position.x() + freeSpace, + m_position.y(), + m_position.z()) ); + } + break; + case alignCenter: + if (m_needDisplay == true) { + // Move the first char at the right : + setPos(vec3(m_position.x() + freeSpace/2, + m_position.y(), + m_position.z()) ); + } + break; + } + // display all the elements + if( m_needDisplay == true + && m_cursorPos == 0) { + m_vectorialDraw.setPos(m_position); + setColorBg(m_colorCursor); + printCursor(false); + } + for(size_t iii=currentId; (int64_t)iii= (int64_t)iii + && (int64_t)iii > m_cursorPos-1) ) { + setColor( 0x000000FF); + setColorBg(m_colorSelection); + } else { + setColor( tmpFg); + setColorBg(tmpBg); + } + } + // special for the justify mode + if ((char32_t)_text[iii] == u32char::Space) { + //EWOL_DEBUG(" generateString : \" \""); + if( m_needDisplay == true + && m_colorBg.a() != 0) { + m_vectorialDraw.setPos(m_position); + } + // Must generate a dynamic space : + setPos(vec3(m_position.x() + interpolation, + m_position.y(), + m_position.z()) ); + if( m_needDisplay == true + && m_colorBg.a() != 0) { + m_vectorialDraw.rectangleWidth(vec3(interpolation,fontHeigh,0.0f) ); + } + } else { + //EWOL_DEBUG(" generateString : \"" << (char)text[iii] << "\""); + if( m_needDisplay == true + && m_colorBg.a() != 0) { + vec3 pos = m_position; + m_vectorialDraw.setPos(pos); + printChar(_text[iii]); + m_vectorialDraw.rectangleWidth(vec3(m_position.x()-pos.x(),fontHeigh,0.0f) ); + m_nbCharDisplayed++; + } else { + printChar(_text[iii]); + m_nbCharDisplayed++; + } + } + if (m_needDisplay == true) { + if ((int64_t)iii == m_cursorPos-1) { + m_vectorialDraw.setPos(m_position); + setColorBg(m_colorCursor); + printCursor(false); + } + } + } + if (currentId == stop) { + currentId++; + } else if(_text[stop] == u32char::Space) { + currentId = stop+1; + // reset position : + setPos(vec3(m_startTextpos, + (float)(m_position.y() - getHeight()), + m_position.z()) ); + m_nbCharDisplayed++; + } else if(_text[stop] == u32char::Return) { + currentId = stop+1; + // reset position : + setPos(vec3(m_startTextpos, + (float)(m_position.y() - getHeight()), + m_position.z()) ); + m_nbCharDisplayed++; + } else { + currentId = stop; + } + } + //EWOL_DEBUG(" 4 print in not alligned mode : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + } +} + + + + +void ewol::compositing::TextBase::forceLineReturn() { + // reset position : + setPos(vec3(m_startTextpos, m_position.y() - getHeight(), 0) ); +} + +void ewol::compositing::TextBase::setTextAlignement(float _startTextpos, float _stopTextPos, enum ewol::compositing::aligneMode _alignement) { + m_startTextpos = _startTextpos; + m_stopTextPos = _stopTextPos+1; + m_alignement = _alignement; + if (m_startTextpos >= m_stopTextPos) { + // TODO: understand why this flush ... + EWOL_VERBOSE("Request allignement with Borne position error : " << _startTextpos << " => " << _stopTextPos); + } +} + +enum ewol::compositing::aligneMode ewol::compositing::TextBase::getAlignement() { + return m_alignement; +} + +void ewol::compositing::TextBase::disableAlignement() { + m_alignement = alignDisable; +} + +vec3 ewol::compositing::TextBase::calculateSizeHTML(const etk::String& _text) { + // remove intermediate result + reset(); + //EWOL_DEBUG(" 0 size for=\n" << text); + // disable display system + m_needDisplay = false; + + setPos(vec3(0,0,0) ); + // same as print without the end display ... + printHTML(_text); + //EWOL_DEBUG(" 1 Start pos=" << m_sizeDisplayStart); + //EWOL_DEBUG(" 1 Stop pos=" << m_sizeDisplayStop); + + // get the last elements + m_sizeDisplayStop.setValue(etk::max(m_position.x(), m_sizeDisplayStop.x()) , + etk::max(m_position.y(), m_sizeDisplayStop.y()) , + 0); + m_sizeDisplayStart.setValue(etk::min(m_position.x(), m_sizeDisplayStart.x()) , + etk::min(m_position.y(), m_sizeDisplayStart.y()) , + 0); + + //EWOL_DEBUG(" 2 Start pos=" << m_sizeDisplayStart); + //EWOL_DEBUG(" 2 Stop pos=" << m_sizeDisplayStop); + // set back the display system + m_needDisplay = true; + + return vec3( m_sizeDisplayStop.x()-m_sizeDisplayStart.x(), + m_sizeDisplayStop.y()-m_sizeDisplayStart.y(), + m_sizeDisplayStop.z()-m_sizeDisplayStart.z()); +} + +vec3 ewol::compositing::TextBase::calculateSizeHTML(const etk::UString& _text) { + // remove intermediate result + reset(); + //EWOL_DEBUG(" 0 size for=\n" << text); + // disable display system + m_needDisplay = false; + + setPos(vec3(0,0,0) ); + // same as print without the end display ... + printHTML(_text); + //EWOL_DEBUG(" 1 Start pos=" << m_sizeDisplayStart); + //EWOL_DEBUG(" 1 Stop pos=" << m_sizeDisplayStop); + + // get the last elements + m_sizeDisplayStop.setValue(etk::max(m_position.x(), m_sizeDisplayStop.x()) , + etk::max(m_position.y(), m_sizeDisplayStop.y()) , + 0); + m_sizeDisplayStart.setValue(etk::min(m_position.x(), m_sizeDisplayStart.x()) , + etk::min(m_position.y(), m_sizeDisplayStart.y()) , + 0); + + //EWOL_DEBUG(" 2 Start pos=" << m_sizeDisplayStart); + //EWOL_DEBUG(" 2 Stop pos=" << m_sizeDisplayStop); + // set back the display system + m_needDisplay = true; + + return vec3( m_sizeDisplayStop.x()-m_sizeDisplayStart.x(), + m_sizeDisplayStop.y()-m_sizeDisplayStart.y(), + m_sizeDisplayStop.z()-m_sizeDisplayStart.z()); +} + +vec3 ewol::compositing::TextBase::calculateSizeDecorated(const etk::String& _text) { + if (_text.size() == 0) { + return vec3(0,0,0); + } + etk::String tmpData("\n"); + tmpData+=_text; + tmpData+="\n\n"; + vec3 tmpVal = calculateSizeHTML(tmpData); + return tmpVal; +} + +vec3 ewol::compositing::TextBase::calculateSizeDecorated(const etk::UString& _text) { + if (_text.size() == 0) { + return vec3(0,0,0); + } + etk::UString tmpData(U"\n"); + tmpData += _text; + tmpData += U"\n\n"; + vec3 tmpVal = calculateSizeHTML(tmpData); + return tmpVal; +} + +vec3 ewol::compositing::TextBase::calculateSize(const etk::String& _text) { + vec3 outputSize(0, 0, 0); + for(auto element : _text) { + vec3 tmpp = calculateSize(element); + if (outputSize.y() == 0) { + outputSize.setY(tmpp.y()); + } + outputSize.setX( outputSize.x() + tmpp.x()); + } + return outputSize; +} + +vec3 ewol::compositing::TextBase::calculateSize(const etk::UString& _text) { + vec3 outputSize(0, 0, 0); + for(auto element : _text) { + vec3 tmpp = calculateSize(element); + if (outputSize.y() == 0) { + outputSize.setY(tmpp.y()); + } + outputSize.setX( outputSize.x() + tmpp.x()); + } + return outputSize; +} + +void ewol::compositing::TextBase::printCursor(bool _isInsertMode, float _cursorSize) { + int32_t fontHeigh = getHeight(); + if (true == _isInsertMode) { + m_vectorialDraw.rectangleWidth(vec3(_cursorSize, fontHeigh, 0) ); + } else { + m_vectorialDraw.setThickness(2); + m_vectorialDraw.lineRel( vec3(0, fontHeigh, 0) ); + m_vectorialDraw.setThickness(0); + } +} + +bool ewol::compositing::TextBase::extrapolateLastId(const etk::String& _text, + const int32_t _start, + int32_t& _stop, + int32_t& _space, + int32_t& _freeSpace) { + // store previous : + char32_t storePrevious = m_previousCharcode; + + _stop = _text.size(); + _space = 0; + + int32_t lastSpacePosition = _start; + int32_t lastSpacefreeSize = 0; + + float endPos = m_position.x(); + bool endOfLine = false; + + float stopPosition = m_stopTextPos; + if( m_needDisplay == false + || m_stopTextPos == m_startTextpos) { + stopPosition = m_startTextpos + 3999999999.0; + } + + for (size_t iii=_start; iii<_text.size(); iii++) { + vec3 tmpSize = calculateSize(_text[iii]); + // check oveflow : + if (endPos + tmpSize.x() > stopPosition) { + _stop = iii; + break; + } + // save number of space : + if ((char32_t)_text[iii] == u32char::Space) { + _space++; + lastSpacePosition = iii; + lastSpacefreeSize = stopPosition - endPos; + } else if ((char32_t)_text[iii] == u32char::Return) { + _stop = iii; + endOfLine = true; + break; + } + // update local size : + endPos += tmpSize.x(); + } + _freeSpace = stopPosition - endPos; + // retore previous : + m_previousCharcode = storePrevious; + // need to align left or right ... + if(_stop == (int64_t)_text.size()) { + return true; + } else { + if (endOfLine) { + return true; + } else { + if (_space == 0) { + return true; + } + _stop = lastSpacePosition; + _freeSpace = lastSpacefreeSize; + return false; + } + } +} + +bool ewol::compositing::TextBase::extrapolateLastId(const etk::UString& _text, + const int32_t _start, + int32_t& _stop, + int32_t& _space, + int32_t& _freeSpace) { + // store previous : + char32_t storePrevious = m_previousCharcode; + + _stop = _text.size(); + _space = 0; + + int32_t lastSpacePosition = _start; + int32_t lastSpacefreeSize = 0; + + float endPos = m_position.x(); + bool endOfLine = false; + + float stopPosition = m_stopTextPos; + if( m_needDisplay == false + || m_stopTextPos == m_startTextpos) { + stopPosition = m_startTextpos + 3999999999.0; + } + + for (size_t iii=_start; iii<_text.size(); iii++) { + vec3 tmpSize = calculateSize(_text[iii]); + // check oveflow : + if (endPos + tmpSize.x() > stopPosition) { + _stop = iii; + break; + } + // save number of space : + if (_text[iii] == u32char::Space) { + _space++; + lastSpacePosition = iii; + lastSpacefreeSize = stopPosition - endPos; + } else if (_text[iii] == u32char::Return) { + _stop = iii; + endOfLine = true; + break; + } + // update local size : + endPos += tmpSize.x(); + } + _freeSpace = stopPosition - endPos; + // retore previous : + m_previousCharcode = storePrevious; + // need to align left or right ... + if(_stop == (int64_t)_text.size()) { + return true; + } else { + if (endOfLine) { + return true; + } else { + if (_space == 0) { + return true; + } + _stop = lastSpacePosition; + _freeSpace = lastSpacefreeSize; + return false; + } + } +} + +void ewol::compositing::TextBase::htmlAddData(const etk::UString& _data) { + if( m_htmlCurrrentLine.size()>0 + && m_htmlCurrrentLine[m_htmlCurrrentLine.size()-1] != ' ') { + m_htmlCurrrentLine += U" "; + if(m_htmlDecoration.size()>0) { + TextDecoration tmp = m_htmlDecoration[m_htmlDecoration.size()-1]; + m_htmlDecoration.pushBack(tmp); + } else { + m_htmlDecoration.pushBack(m_htmlDecoTmp); + } + } + m_htmlCurrrentLine += _data; + for(size_t iii=0; iii<_data.size() ; iii++) { + m_htmlDecoration.pushBack(m_htmlDecoTmp); + } +} + +void ewol::compositing::TextBase::htmlFlush() { + if (m_htmlCurrrentLine.size()>0) { + print(m_htmlCurrrentLine, m_htmlDecoration); + } + m_htmlCurrrentLine = U""; + m_htmlDecoration.clear(); +} + +void ewol::compositing::TextBase::disableCursor() { + m_selectionStartPos = -100; + m_cursorPos = -100; +} + +void ewol::compositing::TextBase::setCursorPos(int32_t _cursorPos) { + m_selectionStartPos = _cursorPos; + m_cursorPos = _cursorPos; +} + +void ewol::compositing::TextBase::setCursorSelection(int32_t _cursorPos, int32_t _selectionStartPos) { + m_selectionStartPos = _selectionStartPos; + m_cursorPos = _cursorPos; +} + +void ewol::compositing::TextBase::setSelectionColor(const etk::Color<>& _color) { + m_colorSelection = _color; +} + +void ewol::compositing::TextBase::setCursorColor(const etk::Color<>& _color) { + m_colorCursor = _color; +} diff --git a/src/org/atriasoft/ewol/compositing/TextBase.java b/src/org/atriasoft/ewol/compositing/TextBase.java new file mode 100644 index 0000000..fa37b31 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/TextBase.java @@ -0,0 +1,478 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace compositing { + /** + * @brief This class represent the specific display for every char in the string ... + * @not_in_doc + */ + class TextDecoration { + public: + etk::Color m_colorBg; //!< display background color + etk::Color m_colorFg; //!< display foreground color + enum ewol::font::mode m_mode; //!< display mode Regular/Bold/Italic/BoldItalic + TextDecoration() { + m_colorBg = etk::color::blue; + m_colorBg = etk::color::green; + m_mode = ewol::font::Regular; + } + }; + + enum aligneMode { + alignDisable, + alignRight, + alignLeft, + alignCenter, + alignJustify + }; + + class TextBase : public ewol::Compositing { + protected: + ewol::compositing::Drawing m_vectorialDraw; //!< This is used to draw background selection and other things ... + public: + virtual ewol::compositing::Drawing& getDrawing() { + return m_vectorialDraw; + }; + protected: + int32_t m_nbCharDisplayed; //!< prevent some error in calculation size. + vec3 m_sizeDisplayStart; //!< The start windows of the display. + vec3 m_sizeDisplayStop; //!< The end windows of the display. + bool m_needDisplay; //!< This just need the display and not the size rendering. + vec3 m_position; //!< The current position to draw + vec3 m_clippingPosStart; //!< Clipping start position + vec3 m_clippingPosStop; //!< Clipping stop position + bool m_clippingEnable; //!< true if the clipping must be activated + protected: + etk::Color m_defaultColorFg; //!< The text foreground color + etk::Color m_defaultColorBg; //!< The text background color + protected: + etk::Color m_color; //!< The text foreground color + etk::Color m_colorBg; //!< The text background color + etk::Color m_colorCursor; //!< The text cursor color + etk::Color m_colorSelection; //!< The text Selection color + protected: + enum ewol::font::mode m_mode; //!< font display property : Regular/Bold/Italic/BoldItalic + bool m_kerning; //!< Kerning enable or disable on the next elements displayed + char32_t m_previousCharcode; //!< we remember the previous charcode to perform the kerning. @ref Kerning + protected: + float m_startTextpos; //!< start position of the Alignement (when \n the text return at this position) + float m_stopTextPos; //!< end of the alignement (when a string is too hight it cut at the word previously this virtual line and the center is perform with this one) + enum aligneMode m_alignement; //!< Current Alignement mode (justify/left/right ...) + protected: + ememory::SharedPtr m_GLprogram; //!< pointer on the opengl display program + int32_t m_GLPosition; //!< openGL id on the element (vertex buffer) + int32_t m_GLMatrix; //!< openGL id on the element (transformation matrix) + int32_t m_GLColor; //!< openGL id on the element (color buffer) + int32_t m_GLtexture; //!< openGL id on the element (Texture position) + int32_t m_GLtexID; //!< openGL id on the element (texture ID) + int32_t m_GLtextWidth; //!< openGL Id on the texture width + int32_t m_GLtextHeight; //!< openGL Id on the texture height + protected: + int32_t m_selectionStartPos; //!< start position of the Selection (if == m_cursorPos ==> no selection) + int32_t m_cursorPos; //!< Cursor position (default no cursor == > -100) + protected: // Text + static const int32_t m_vboIdCoord; + static const int32_t m_vboIdCoordText; + static const int32_t m_vboIdColor; + static const int32_t m_vboIdGlyphLevel; + ememory::SharedPtr m_VBO; + public: + /** + * @brief load the openGL program and get all the ID needed + */ + virtual void loadProgram(const etk::String& _shaderName); + public: + /** + * @brief generic constructor + */ + TextBase(const etk::String& _shaderName = "DATA:///text.prog?lib=ewol", bool _loadProgram = true); + /** + * @brief generic destructor + */ + virtual ~TextBase(); + public: // Derived function + void translate(const vec3& _vect); + void rotate(const vec3& _vect, float _angle); + void scale(const vec3& _vect); + public: + /** + * @brief draw All the refistered text in the current element on openGL + */ + void draw(bool _disableDepthTest=true) { + drawD(_disableDepthTest); + } + //! @previous + void draw(const mat4& _transformationMatrix, bool _enableDepthTest=false) { + drawMT(_transformationMatrix, _enableDepthTest); + } + /** + * @brief draw All the refistered text in the current element on openGL + */ + virtual void drawD(bool _disableDepthTest) = 0; + //! @previous + virtual void drawMT(const mat4& _transformationMatrix, bool _enableDepthTest) = 0; + /** + * @brief clear all the registered element in the current element + */ + virtual void clear(); + /** + * @brief clear all the intermediate result detween 2 prints + */ + virtual void reset(); + /** + * @brief get the current display position (sometime needed in the gui control) + * @return the current position. + */ + const vec3& getPos() { + return m_position; + }; + /** + * @brief set position for the next text writen + * @param[in] _pos Position of the text (in 3D) + */ + void setPos(const vec3& _pos); + //! @previous + inline void setPos(const vec2& _pos) { + setPos(vec3(_pos.x(),_pos.y(),0)); + }; + /** + * @brief set relative position for the next text writen + * @param[in] _pos ofset apply of the text (in 3D) + */ + void setRelPos(const vec3& _pos); + //! @previous + inline void setRelPos(const vec2& _pos) { + setRelPos(vec3(_pos.x(),_pos.y(),0)); + }; + /** + * @brief set the default background color of the font (when reset, set this value ...) + * @param[in] _color Color to set on background + */ + void setDefaultColorBg(const etk::Color<>& _color) { + m_defaultColorBg = _color; + } + /** + * @brief set the default Foreground color of the font (when reset, set this value ...) + * @param[in] _color Color to set on foreground + */ + void setDefaultColorFg(const etk::Color<>& _color) { + m_defaultColorFg = _color; + } + /** + * @brief set the Color of the current foreground font + * @param[in] _color Color to set on foreground (for next print) + */ + void setColor(const etk::Color<>& _color) { + m_color = _color; + }; + /** + * @brief set the background color of the font (for selected Text (not the global BG)) + * @param[in] _color Color to set on background (for next print) + */ + void setColorBg(const etk::Color<>& _color); + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in] _pos Start position of the clipping + * @param[in] _width Width size of the clipping + */ + void setClippingWidth(const vec3& _pos, const vec3& _width) { + setClipping(_pos, _pos+_width); + } + //! @previous + void setClippingWidth(const vec2& _pos, const vec2& _width) { + setClipping(_pos, _pos+_width); + }; + /** + * @brief Request a clipping area for the text (next draw only) + * @param[in] _pos Start position of the clipping + * @param[in] _posEnd End position of the clipping + */ + void setClipping(const vec3& _pos, const vec3& _posEnd); + //! @previous + void setClipping(const vec2& _pos, const vec2& _posEnd) { + setClipping(vec3(_pos.x(),_pos.y(),-1), vec3(_posEnd.x(),_posEnd.y(),1) ); + }; + /** + * @brief enable/Disable the clipping (without lose the current clipping position) + * @brief _newMode The new status of the clipping + */ + // TODO : Rename setClippingActivity + void setClippingMode(bool _newMode); + /** + * @brief Specify the font size (this reset the internal element of the current text (system requirement) + * @param[in] _fontSize New font size + */ + virtual void setFontSize(int32_t _fontSize) = 0; + /** + * @brief Specify the font name (this reset the internal element of the current text (system requirement) + * @param[in] _fontName Current name of the selected font + */ + virtual void setFontName(const etk::String& _fontName) = 0; + /** + * @brief Specify the font property (this reset the internal element of the current text (system requirement) + * @param[in] fontName Current name of the selected font + * @param[in] fontSize New font size + */ + virtual void setFont(etk::String _fontName, int32_t _fontSize) = 0; + /** + * @brief Specify the font mode for the next @ref print + * @param[in] mode The font mode requested + */ + virtual void setFontMode(enum ewol::font::mode _mode) = 0; + /** + * @brief get the current font mode + * @return The font mode applied + */ + enum ewol::font::mode getFontMode() { + return m_mode; + }; + virtual float getHeight() = 0; + virtual float getSize() = 0; + virtual ewol::GlyphProperty * getGlyphPointer(char32_t _charcode) = 0; + /** + * @brief enable or disable the bold mode + * @param[in] _status The new status for this display property + */ + void setFontBold(bool _status); + /** + * @brief enable or disable the italic mode + * @param[in] _status The new status for this display property + */ + void setFontItalic(bool _status); + /** + * @brief set the activation of the Kerning for the display (if it existed) + * @param[in] _newMode enable/Diasable the kerning on this font. + */ + void setKerningMode(bool _newMode); + /** + * @brief display a compleat string in the current element. + * @param[in] _text The string to display. + */ + void print(const etk::String& _text); + //! @previous + void print(const etk::UString& _text); + /** + * @brief display a compleat string in the current element with the generic decoration specification. (basic html data) + * + * [code style=xml] + *
+ *


+ *
+ * text exemple in bold other text bold part boldItalic part an other thext + * colored text bold color text bold italic text normal color text the end of the string
+ * an an other thext + *
+ *


+ * + * plop 1 + * + *


+ * + * plop 2 + * + *


+ * + * Un exemple de text + * + * [/code] + * + * @note This is parsed with tiny xml, then be carfull that the XML is correct, and all balises are closed ... otherwite the display can not be done + * @param[in] _text The string to display. + * @TODO : implementation not done .... + */ + void printDecorated(const etk::String& _text); + //! @previous + void printDecorated(const etk::UString& _text); + /** + * @brief display a compleat string in the current element with the generic decoration specification. (basic html data) + * + * [code style=xml] + * + * + *
+ *


+ *
+ * text exemple in bold other text bold part boldItalic part an other thext + * colored text bold color text bold italic text normal color text the end of the string
+ * an an other thext + *
+ *


+ * + * plop 1 + * + *


+ * + * plop 2 + * + *


+ * + * Un exemple de text + * + * + * + * [/code] + * + * @note This is parsed with tiny xml, then be carfull that the XML is correct, and all balises are closed ... otherwite the display can not be done + * @param[in] _text The string to display. + * @TODO : implementation not done .... + */ + void printHTML(const etk::String& _text); + //! @previous + void printHTML(const etk::UString& _text); + /** + * @brief display a compleat string in the current element whith specific decorations (advence mode). + * @param[in] _text The string to display. + * @param[in] _decoration The text decoration for the text that might be display (if the vector is smaller, the last parameter is get) + */ + void print(const etk::String& _text, const etk::Vector& _decoration); + //! @previous + void print(const etk::UString& _text, const etk::Vector& _decoration); + /** + * @brief display the current char in the current element (note that the kerning is availlable if the position is not changed) + * @param[in] _charcode Char that might be dispalyed + */ + virtual void printChar(const char32_t& _charcode) = 0; + /** + * @brief This generate the line return == > it return to the alignement position start and at the correct line position ==> it might be use to not know the line height + */ + void forceLineReturn(); + protected: + /** + * @brief This parse a tinyXML node (void pointer to permit to hide tiny XML in include). + * @param[in] _element the exml element. + */ + void parseHtmlNode(const exml::Element& _element); + public: + /** + * @brief This generate the possibility to generate the big text property + * @param[in] _startTextpos The x text start position of the display. + * @param[in] _stopTextPos The x text stop position of the display. + * @param[in] _alignement mode of alignement for the Text. + * @note The text align in center change of line every display done (even if it was just a char) + */ + void setTextAlignement(float _startTextpos, float _stopTextPos, enum ewol::compositing::aligneMode _alignement=ewol::compositing::alignDisable); + /** + * @brief disable the alignement system + */ + void disableAlignement(); + /** + * @brief get the current alignement property + * @return the curent alignement type + */ + enum ewol::compositing::aligneMode getAlignement(); + /** + * @brief calculate a theoric text size + * @param[in] _text The string to calculate dimention. + * @return The theoric size used. + */ + vec3 calculateSizeHTML(const etk::String& _text); + //! @previous + vec3 calculateSizeHTML(const etk::UString& _text); + /** + * @brief calculate a theoric text size + * @param[in] _text The string to calculate dimention. + * @return The theoric size used. + */ + vec3 calculateSizeDecorated(const etk::String& _text); + //! @previous + vec3 calculateSizeDecorated(const etk::UString& _text); + /** + * @brief calculate a theoric text size + * @param[in] _text The string to calculate dimention. + * @return The theoric size used. + */ + vec3 calculateSize(const etk::String& _text); + //! @previous + vec3 calculateSize(const etk::UString& _text); + /** + * @brief calculate a theoric charcode size + * @param[in] _charcode The Unicode value to calculate dimention. + * @return The theoric size used. + */ + inline vec3 calculateSize(const char32_t& _charcode) { + return calculateSizeChar(_charcode); + }; + protected: + //! @previous + virtual vec3 calculateSizeChar(const char32_t& _charcode) = 0; + public: + /** + * @brief draw a cursor at the specify position + * @param[in] _isInsertMode True if the insert mode is activated + * @param[in] _cursorSize The sizae of the cursor that might be set when insert mode is set [default 20] + */ + void printCursor(bool _isInsertMode, float _cursorSize = 20.0f); + protected: + /** + * @brief calculate the element number that is the first out the alignement range + * (start at the specify ID, and use start pos with current one) + * @param[in] _text The string that might be parsed. + * @param[in] _start The first elemnt that might be used to calculate. + * @param[out] _stop The last Id availlable in the current string. + * @param[out] _space Number of space in the string. + * @param[out] _freespace This represent the number of pixel present in the right white space. + * @return true if the rifht has free space that can be use for jystify. + * @return false if we find '\n' + */ + bool extrapolateLastId(const etk::String& _text, const int32_t _start, int32_t& _stop, int32_t& _space, int32_t& _freeSpace); + //! @previous + bool extrapolateLastId(const etk::UString& _text, const int32_t _start, int32_t& _stop, int32_t& _space, int32_t& _freeSpace); + protected: + // this section is reserved for HTML parsing and display: + etk::UString m_htmlCurrrentLine; //!< current line for HTML display + etk::Vector m_htmlDecoration; //!< current decoration for the HTML display + TextDecoration m_htmlDecoTmp; //!< current decoration + /** + * @brief add a line with the current m_htmlDecoTmp decoration + * @param[in] _data The cuurent data to add. + */ + void htmlAddData(const etk::UString& _data); + /** + * @brief draw the current line + */ + void htmlFlush(); + public: + /** + * @brief remove the cursor display + */ + void disableCursor(); + /** + * @brief set a cursor at a specific position: + * @param[in] _cursorPos id of the cursor position + */ + void setCursorPos(int32_t _cursorPos); + /** + * @brief set a cursor at a specific position with his associated selection: + * @param[in] _cursorPos id of the cursor position + * @param[in] _selectionStartPos id of the starting of the selection + */ + void setCursorSelection(int32_t _cursorPos, int32_t _selectionStartPos); + /** + * @brief change the selection color + * @param[in] _color New color for the Selection + */ + void setSelectionColor(const etk::Color<>& _color); + /** + * @brief change the cursor color + * @param[in] _color New color for the Selection + */ + void setCursorColor(const etk::Color<>& _color); + }; + } +} + + diff --git a/src/org/atriasoft/ewol/compositing/TextDF.cpp b/src/org/atriasoft/ewol/compositing/TextDF.cpp new file mode 100644 index 0000000..41430ac --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/TextDF.cpp @@ -0,0 +1,407 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::compositing::TextDF); + +ewol::compositing::TextDF::TextDF(const etk::String& _fontName, int32_t _fontSize) : + ewol::compositing::TextBase("", false), + m_fontDF(null), + m_GLglyphLevel(-1), + m_size(12.0) { + setFont(_fontName, _fontSize); + loadProgram("DATA:///fontDistanceField/font1.prog?lib=ewol"); +} + +ewol::compositing::TextDF::~TextDF() { + +} + +void ewol::compositing::TextDF::updateSizeToRender(const vec2& _size) { + float minSize = etk::min(_size.x(), _size.y()); + if (m_fontDF != null) { + setFontSize(m_fontDF->getSize(minSize)); + } +} + +void ewol::compositing::TextDF::drawMT(const mat4& _transformationMatrix, bool _enableDepthTest) { + // draw BG in any case: + m_vectorialDraw.draw(); + if ( m_VBO->bufferSize(m_vboIdCoord) <= 0 + || m_fontDF == null) { + //EWOL_WARNING("Nothink to draw..."); + return; + } + if (m_fontDF == null) { + EWOL_WARNING("no font..."); + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + if (_enableDepthTest == true) { + gale::openGL::enable(gale::openGL::flag_depthTest); + } + // set Matrix: translation/positionMatrix + mat4 projMatrix = gale::openGL::getMatrix(); + mat4 camMatrix = gale::openGL::getCameraMatrix(); + mat4 tmpMatrix = projMatrix * camMatrix * _transformationMatrix; + m_GLprogram->use(); + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // Texture: + m_GLprogram->setTexture0(m_GLtexID, m_fontDF->getRendererId()); + m_GLprogram->uniform1i(m_GLtextWidth, m_fontDF->getOpenGlSize().x()); + m_GLprogram->uniform1i(m_GLtextHeight, m_fontDF->getOpenGlSize().x()); + m_GLprogram->sendAttributePointer(m_GLPosition, m_VBO, m_vboIdCoord); + m_GLprogram->sendAttributePointer(m_GLtexture, m_VBO, m_vboIdCoordText); + m_GLprogram->sendAttributePointer(m_GLColor, m_VBO, m_vboIdColor); + m_GLprogram->sendAttributePointer(m_GLglyphLevel, m_VBO, m_vboIdGlyphLevel); + // Request the draw od the elements: + gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, m_VBO->bufferSize(m_vboIdCoord)); + m_GLprogram->unUse(); + if (_enableDepthTest == true) { + gale::openGL::disable(gale::openGL::flag_depthTest); + } +} + + +void ewol::compositing::TextDF::drawD(bool _disableDepthTest) { + // draw BG in any case: + m_vectorialDraw.draw(); + + if ( m_VBO->bufferSize(m_vboIdCoord) <= 0 + || m_fontDF == null) { + // TODO : Set it back + //EWOL_WARNING("Nothink to draw..."); + return; + } + if (m_fontDF == null) { + EWOL_WARNING("no font..."); + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + // set Matrix: translation/positionMatrix + mat4 tmpMatrix = gale::openGL::getMatrix()*m_matrixApply; + m_GLprogram->use(); + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // Texture: + m_GLprogram->setTexture0(m_GLtexID, m_fontDF->getRendererId()); + m_GLprogram->uniform1i(m_GLtextWidth, m_fontDF->getOpenGlSize().x()); + m_GLprogram->uniform1i(m_GLtextHeight, m_fontDF->getOpenGlSize().x()); + m_GLprogram->sendAttributePointer(m_GLPosition, m_VBO, m_vboIdCoord); + m_GLprogram->sendAttributePointer(m_GLtexture, m_VBO, m_vboIdCoordText); + m_GLprogram->sendAttributePointer(m_GLColor, m_VBO, m_vboIdColor); + m_GLprogram->sendAttributePointer(m_GLglyphLevel, m_VBO, m_vboIdGlyphLevel); + // Request the draw od the elements: + gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, m_VBO->bufferSize(m_vboIdCoord)); + m_GLprogram->unUse(); +} + +void ewol::compositing::TextDF::loadProgram(const etk::String& _shaderName) { + ewol::compositing::TextBase::loadProgram(_shaderName); + if (m_GLprogram != null) { + m_GLglyphLevel = m_GLprogram->getAttribute("EW_glyphLevel"); + } +} + + +float ewol::compositing::TextDF::getHeight() { + if (m_fontDF == null) { + EWOL_WARNING("no font..."); + return 1; + } + return m_fontDF->getHeight(m_size); +} + +ewol::GlyphProperty * ewol::compositing::TextDF::getGlyphPointer(char32_t _charcode) { + if (m_fontDF == null) { + EWOL_WARNING("no font..."); + return null; + } + return m_fontDF->getGlyphPointer(_charcode); +} + +void ewol::compositing::TextDF::setFontSize(int32_t _fontSize) { + clear(); + EWOL_VERBOSE("Set font Size: " << _fontSize); + if (_fontSize <= 1) { + m_size = ewol::getContext().getFontDefault().getSize(); + } else { + m_size = _fontSize; + } +} + +void ewol::compositing::TextDF::setFontName(const etk::String& _fontName) { + clear(); + // remove old one + ememory::SharedPtr previousFont = m_fontDF; + etk::String fontName; + if (_fontName == "") { + fontName = ewol::getContext().getFontDefault().getName(); + } else { + fontName = _fontName; + } + EWOL_VERBOSE("Set font name: '" << fontName << "'"); + // link to new one + m_fontDF = ewol::resource::DistanceFieldFont::create(fontName); + if (m_fontDF == null) { + EWOL_ERROR("Can not get find resource"); + m_fontDF = previousFont; + } +} + +void ewol::compositing::TextDF::setFont(etk::String _fontName, int32_t _fontSize) { + setFontSize(_fontSize); + setFontName(_fontName); +} + +void ewol::compositing::TextDF::setFontMode(enum ewol::font::mode _mode) { + m_mode = _mode; +} + +//#define ANGLE_OF_ITALIC (tan(0.4)) +#define ANGLE_OF_ITALIC (0.00698143f) + + +void ewol::compositing::TextDF::printChar(const char32_t& _charcode) { + // get a pointer on the glyph property : + ewol::GlyphProperty* myGlyph = getGlyphPointer(_charcode); + if (null == myGlyph) { + EWOL_ERROR(" font does not really existed ..."); + return; + } + float fontSize = getSize(); + float fontHeigh = getHeight(); + + float factorDisplay = m_fontDF->getDisplayRatio(fontSize); + + // get the kerning ofset : + float kerningOffset = 0; + if (true == m_kerning) { + kerningOffset = myGlyph->kerningGet(m_previousCharcode); + if (kerningOffset != 0) { + //EWOL_DEBUG("Kerning between : '" << m_previousCharcode << "'&'" << myGlyph->m_UVal << "' value : " << kerningOffset); + } + } + // 0x01 == 0x20 == ' '; + if ( _charcode != 0x01 + && _charcode != 0x20) { + float glyphLevel = 0.5f; + if ( m_mode == ewol::font::BoldItalic + || m_mode == ewol::font::Bold) { + glyphLevel = 0.41f; + } + float italicMove = 0.0f; + if ( m_mode == ewol::font::BoldItalic + || m_mode == ewol::font::Italic) { + // This is a simple version of Italic mode, in theory we need to move the up and the down... + italicMove = (float)myGlyph->m_sizeTexture.y() * factorDisplay * ANGLE_OF_ITALIC; + // TODO : pb on the clipper... + } + + /* Bitmap position + * xA xB + * yC *------* + * | | + * | | + * yD *------* + */ + #if 0 + float dxA = m_position.x() + (myGlyph->m_bearing.x() + kerningOffset) * factorDisplay; + float dxB = dxA + myGlyph->m_sizeTexture.x() * factorDisplay; + float dyC = m_position.y() + (myGlyph->m_bearing.y() + fontHeigh - fontSize) * factorDisplay; + float dyD = dyC - myGlyph->m_sizeTexture.y() * factorDisplay; + #else + //EWOL_DEBUG(" plop : fontHeigh" << fontHeigh << " fontSize=" << fontSize); + float dxA = m_position.x() + ((float)myGlyph->m_bearing.x() + kerningOffset - (float)m_fontDF->getPixelBorderSize()*0.5f) * factorDisplay; + float dxB = dxA + ((float)myGlyph->m_sizeTexture.x() + (float)m_fontDF->getPixelBorderSize()) * factorDisplay; + float dyC = m_position.y() + (fontHeigh - fontSize + ((float)myGlyph->m_bearing.y() + (float)m_fontDF->getPixelBorderSize()*0.5f) * factorDisplay); + float dyD = dyC - ((float)myGlyph->m_sizeTexture.y() + (float)m_fontDF->getPixelBorderSize()) * factorDisplay; + #endif + + float tuA = myGlyph->m_texturePosStart.x(); + float tuB = tuA + myGlyph->m_texturePosSize.x(); + float tvC = myGlyph->m_texturePosStart.y(); + float tvD = tvC + myGlyph->m_texturePosSize.y(); + /* + vec3 drawingPos = m_vectorialDraw.getPos(); + etk::Color<> backColor = m_vectorialDraw.getColor(); + + m_vectorialDraw.setPos(vec2(dxA, dyC)); + + m_vectorialDraw.setColor(etk::Color<>(0.0,1.0,0.0,1.0)); + m_vectorialDraw.rectangle(vec2(dxB, dyD)); + + m_vectorialDraw.setPos(drawingPos); + m_vectorialDraw.setColor(backColor); + */ + // Clipping and drawing area + if( m_clippingEnable == true + && ( dxB < m_clippingPosStart.x() + || dxA > m_clippingPosStop.x() + || dyC < m_clippingPosStart.y() + || dyD > m_clippingPosStop.y() ) ) { + // Nothing to diplay ... + } else { + if (m_clippingEnable == true) { + // generata positions... + float TexSizeX = tuB - tuA; + if (dxA < m_clippingPosStart.x()) { + // clip display + float drawSize = m_clippingPosStart.x() - dxA; + // update element start display + dxA = m_clippingPosStart.x(); + float addElement = TexSizeX * drawSize / ((float)myGlyph->m_sizeTexture.x() * factorDisplay); + // update texture start X Pos + tuA += addElement; + } + if (dxB > m_clippingPosStop.x()) { + // clip display + float drawSize = dxB - m_clippingPosStop.x(); + // update element start display + dxB = m_clippingPosStop.x(); + float addElement = TexSizeX * drawSize / ((float)myGlyph->m_sizeTexture.x() * factorDisplay); + // update texture start X Pos + tuB -= addElement; + } + float TexSizeY = tvC - tvD; + if (dyC > m_clippingPosStop.y()) { + // clip display + float drawSize = dyC - m_clippingPosStop.y(); + // update element start display + dyC = m_clippingPosStop.y(); + float addElement = TexSizeY * drawSize / ((float)myGlyph->m_sizeTexture.y() * factorDisplay); + // update texture start X Pos + tvC -= addElement; + } + if (dyD < m_clippingPosStart.y()) { + // clip display + float drawSize = m_clippingPosStart.y() - dyD; + // update element start display + dyD = m_clippingPosStart.y(); + float addElement = TexSizeY * drawSize / ((float)myGlyph->m_sizeTexture.y() * factorDisplay); + // update texture start X Pos + tvD += addElement; + } + } + if( dxB <= dxA + || dyD >= dyC) { + // nothing to do ... + } else { + /* Bitmap position + * 0------1 + * | | + * | | + * 3------2 + */ + if (m_needDisplay == true) { + vec3 bitmapDrawPos[4]; + bitmapDrawPos[0].setValue(dxA+italicMove, dyC, 0); + bitmapDrawPos[1].setValue(dxB+italicMove, dyC, 0); + bitmapDrawPos[2].setValue(dxB, dyD, 0); + bitmapDrawPos[3].setValue(dxA, dyD, 0); + /* texture Position : + * 0------1 + * | | + * | | + * 3------2 + */ + vec2 texturePos[4]; + texturePos[0].setValue(tuA+m_mode, tvC); + texturePos[1].setValue(tuB+m_mode, tvC); + texturePos[2].setValue(tuB+m_mode, tvD); + texturePos[3].setValue(tuA+m_mode, tvD); + + // NOTE : Android does not support the Quads elements ... + /* Step 1 : + * ******** + * ****** + * **** + * ** + * + */ + // set texture coordonates : + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[0]); + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[1]); + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[2]); + // set display positions : + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[0]); + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[1]); + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[2]); + // set the color + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + // set the bliph level + m_VBO->pushOnBuffer(m_vboIdGlyphLevel, glyphLevel); + m_VBO->pushOnBuffer(m_vboIdGlyphLevel, glyphLevel); + m_VBO->pushOnBuffer(m_vboIdGlyphLevel, glyphLevel); + /* Step 2 : + * + * ** + * **** + * ****** + * ******** + */ + // set texture coordonates : + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[0]); + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[2]); + m_VBO->pushOnBuffer(m_vboIdCoordText, texturePos[3]); + // set display positions : + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[0]); + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[2]); + m_VBO->pushOnBuffer(m_vboIdCoord, bitmapDrawPos[3]); + // set the color + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + m_VBO->pushOnBuffer(m_vboIdColor, m_color); + // set the bliph level + m_VBO->pushOnBuffer(m_vboIdGlyphLevel, glyphLevel); + m_VBO->pushOnBuffer(m_vboIdGlyphLevel, glyphLevel); + m_VBO->pushOnBuffer(m_vboIdGlyphLevel, glyphLevel); + } + } + } + } + // move the position : + //EWOL_DEBUG(" 5 pos=" << m_position << " advance=" << myGlyph->m_advance.x() << " kerningOffset=" << kerningOffset); + m_position.setX(m_position.x() + (myGlyph->m_advance.x() + kerningOffset) * factorDisplay); + //EWOL_DEBUG(" 6 print '" << charcode << "' : start=" << m_sizeDisplayStart << " stop=" << m_sizeDisplayStop << " pos=" << m_position); + // Register the previous character + m_previousCharcode = _charcode; + m_VBO->flush(); + return; +} + + +vec3 ewol::compositing::TextDF::calculateSizeChar(const char32_t& _charcode) { + // get a pointer on the glyph property : + ewol::GlyphProperty * myGlyph = getGlyphPointer(_charcode); + int32_t fontHeigh = getHeight(); + + // get the kerning ofset : + float kerningOffset = 0.0; + if (true == m_kerning) { + kerningOffset = myGlyph->kerningGet(m_previousCharcode); + } + + vec3 outputSize((float)(myGlyph->m_advance.x() + kerningOffset)*m_fontDF->getDisplayRatio(getSize()), + (float)(fontHeigh), + (float)(0.0)); + // Register the previous character + m_previousCharcode = _charcode; + return outputSize; +} + + diff --git a/src/org/atriasoft/ewol/compositing/TextDF.java b/src/org/atriasoft/ewol/compositing/TextDF.java new file mode 100644 index 0000000..6bc6ba7 --- /dev/null +++ b/src/org/atriasoft/ewol/compositing/TextDF.java @@ -0,0 +1,70 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace compositing { + class TextDF : public ewol::compositing::TextBase { + protected: + ememory::SharedPtr m_fontDF; //!< Font resources + protected: + int32_t m_GLglyphLevel; //!< openGL Id on the glyph level display + public: + /** + * @brief generic constructor + * @param[in] _fontName Name of the font that might be loaded + * @param[in] _fontSize size of the font that might be loaded + */ + TextDF(const etk::String& _fontName="", int32_t _fontSize=-1); + /** + * @brief generic destructor + */ + virtual ~TextDF(); + public: + /** + * @brief Calculate size to be at the best size for a render in this special size. + * @note special for Distance field mode. + * @param[in] _size request dimention. + */ + void updateSizeToRender(const vec2& _size); + public: + virtual void drawD(bool _disableDepthTest); + virtual void drawMT(const mat4& _transformationMatrix, bool _enableDepthTest); + protected: + float m_size; + public: + virtual float getHeight(); + virtual float getSize() { + return m_size; + } + virtual void setSize(float _size) { + m_size = _size; + } + virtual ewol::GlyphProperty * getGlyphPointer(char32_t _charcode); + + public: + virtual void loadProgram(const etk::String& _shaderName); + virtual void setFontSize(int32_t _fontSize); + virtual void setFontName(const etk::String& _fontName); + virtual void setFont(etk::String _fontName, int32_t _fontSize); + virtual void setFontMode(enum ewol::font::mode _mode); + virtual void printChar(const char32_t& _charcode); + virtual vec3 calculateSizeChar(const char32_t& _charcode); + }; + } +} + + diff --git a/src/org/atriasoft/ewol/context/Application.cpp b/src/org/atriasoft/ewol/context/Application.cpp new file mode 100644 index 0000000..cbc08b3 --- /dev/null +++ b/src/org/atriasoft/ewol/context/Application.cpp @@ -0,0 +1,49 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::context::Application); + +ewol::context::Application::Application() { + +} + +ewol::context::Application::~Application() { + +} + +void ewol::context::Application::onCreate(ewol::Context& _context) { + +} + +void ewol::context::Application::onStart(ewol::Context& _context) { + +} + +void ewol::context::Application::onResume(ewol::Context& _context) { + +} + +void ewol::context::Application::onPause(ewol::Context& _context) { + +} + +void ewol::context::Application::onStop(ewol::Context& _context) { + +} + +void ewol::context::Application::onDestroy(ewol::Context& _context) { + +} + +void ewol::context::Application::onKillDemand(ewol::Context& _context) { + _context.exit(0); +} + diff --git a/src/org/atriasoft/ewol/context/Application.java b/src/org/atriasoft/ewol/context/Application.java new file mode 100644 index 0000000..0dacf17 --- /dev/null +++ b/src/org/atriasoft/ewol/context/Application.java @@ -0,0 +1,54 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#pragma once + +namespace ewol { + class Context; + namespace context { + class Application { + public: + Application(); + virtual ~Application(); + public: + /** + * @brief The application is created. + * @param[in] _context Current ewol context. + */ + virtual void onCreate(ewol::Context& _context); + /** + * @brief The application is started. + * @param[in] _context Current ewol context. + */ + virtual void onStart(ewol::Context& _context); + /** + * @brief The application is resumed (now visible). + * @param[in] _context Current ewol context. + */ + virtual void onResume(ewol::Context& _context); + /** + * @brief The application is Hide / not visible. + * @param[in] _context Current ewol context. + */ + virtual void onPause(ewol::Context& _context); + /** + * @brief The application is stopped. + * @param[in] _context Current ewol context. + */ + virtual void onStop(ewol::Context& _context); + /** + * @brief The application is removed (call destructor just adter it.). + * @param[in] _context Current ewol context. + */ + virtual void onDestroy(ewol::Context& _context); + /** + * @brief The user request application removing. + * @param[in] _context Current ewol context. + */ + virtual void onKillDemand(ewol::Context& _context); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/context/ConfigFont.cpp b/src/org/atriasoft/ewol/context/ConfigFont.cpp new file mode 100644 index 0000000..886a4ab --- /dev/null +++ b/src/org/atriasoft/ewol/context/ConfigFont.cpp @@ -0,0 +1,43 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +ETK_DECLARE_TYPE(ewol::context::ConfigFont); + +ewol::context::ConfigFont::ConfigFont() : + m_folder("DATA:///fonts?lib=ewol"), + m_name("Arial;Helvetica"), + m_size(10), + m_useExternal(false) { + #ifdef __TARGET_OS__Android + m_name = "Roboto;DroidSans"; + #endif + ewol::resource::freeTypeInit(); +} + +ewol::context::ConfigFont::~ConfigFont() { + // UnInit FreeTypes + ewol::resource::freeTypeUnInit(); +} + +void ewol::context::ConfigFont::set(const etk::String& _fontName, int32_t _size) { + m_name = _fontName; + m_size = _size; + EWOL_DEBUG("Set default Font : '" << m_name << "' size=" << m_size); +} + +void ewol::context::ConfigFont::setSize(int32_t _size) { + m_size = _size; + EWOL_DEBUG("Set default Font : '" << m_name << "' size=" << m_size << " (change size only)"); +} + +void ewol::context::ConfigFont::setName(const etk::String& _fontName) { + m_name = _fontName; + EWOL_DEBUG("Set default Font : '" << m_name << "' size=" << m_size << " (change name only)"); +} + diff --git a/src/org/atriasoft/ewol/context/ConfigFont.java b/src/org/atriasoft/ewol/context/ConfigFont.java new file mode 100644 index 0000000..837d696 --- /dev/null +++ b/src/org/atriasoft/ewol/context/ConfigFont.java @@ -0,0 +1,92 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ewol { + namespace context { + class ConfigFont { + public: + /** + * Constructor / destructor + */ + ConfigFont(); + virtual ~ConfigFont(); + private: + etk::Uri m_folder; + public: + /** + * @brief Specify the default font folder for the Ewol search system (only needed when embended font) + * @param[in] _folder basic folder of the font (ex: DATA:fonts) + */ + void setFolder(const etk::Uri& _folder) { + m_folder = _folder; + }; + /** + * @brief get the default font folder. + * @return The default font folder. + */ + const etk::Uri& getFolder() { + return m_folder; + }; + private: + etk::String m_name; + int32_t m_size; + public: + /** + * @brief set the defaut font for all the widgets and basics display. + * @param[in] _fontName The font name requested (not case sensitive) ex "Arial" or multiple separate by ';' ex : "Arial;Helvetica". + * @param[in] _size The default size of the font default=10. + */ + void set(const etk::String& _fontName, int32_t _size); + /** + * @brief get the current default font name + * @raturn a reference on the font name string + */ + const etk::String& getName() { + return m_name; + }; + /** + * @brief Set the current default font name + * @param[in] _fontName The font name requested (not case sensitive) ex "Arial" or multiple separate by ';' ex : "Arial;Helvetica". + */ + void setName(const etk::String& _fontName); + /** + * @brief get the default font size. + * @return the font size. + */ + int32_t getSize() { + return m_size; + }; + /** + * @brief Set the default font size. + * @param[in] _size new font size. + */ + void setSize(int32_t _size); + private: + bool m_useExternal; + public: + /** + * @brief set use of internal/external Font + * @param[in] _val true to enable search of internal data. + */ + void setUseExternal(bool _val) { + m_useExternal=_val; + }; + /** + * @brief get the use of internal/external Font + * @return true to enable search of internal data. + */ + bool getUseExternal() { + return m_useExternal; + }; + }; + }; +}; + + diff --git a/src/org/atriasoft/ewol/context/Context.cpp b/src/org/atriasoft/ewol/context/Context.cpp new file mode 100644 index 0000000..c25c10a --- /dev/null +++ b/src/org/atriasoft/ewol/context/Context.cpp @@ -0,0 +1,382 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +ETK_DECLARE_TYPE(ewol::Context); + +static ewol::Context* l_curentInterface=null; +ewol::Context& ewol::getContext() { + gale::Context& context = gale::getContext(); + ememory::SharedPtr appl = context.getApplication(); + if (appl == null) { + EWOL_CRITICAL("[CRITICAL] try acces at an empty GALE application (can not get Context)"); + // ??? + } + return *(ememory::staticPointerCast(appl)); +} + + +void ewol::Context::setInitImage(const etk::Uri& _fileName) { + //m_initDisplayImageName = _fileName; +} + + + +void ewol::Context::inputEventTransfertWidget(ewol::WidgetShared _source, + ewol::WidgetShared _destination) { + m_input.transfertEvent(_source, _destination); +} + + +void ewol::Context::inputEventGrabPointer(ewol::WidgetShared _widget) { + m_input.grabPointer(_widget); +} + +void ewol::Context::inputEventUnGrabPointer() { + m_input.unGrabPointer(); +} + + +void ewol::Context::onCreate(gale::Context& _context) { + EWOL_INFO(" == > Ewol system create (BEGIN)"); + // Add basic ewol translation: + etranslate::addPath("ewol", "DATA:///translate/ewol/?lib=ewol"); + etranslate::autoDetectLanguage(); + // By default we set 2 themes (1 color and 1 shape ...) : + etk::theme::setNameDefault("GUI", "shape/square/"); + etk::theme::setNameDefault("COLOR", "color/black/"); + // parse for help: + for(int32_t iii = 0; iii < _context.getCmd().size() ; ++iii) { + if ( _context.getCmd().get(iii) == "-h" + || _context.getCmd().get(iii) == "--help") { + EWOL_PRINT("ewol - help : "); + EWOL_PRINT(" " << etk::getApplicationName() << " [options]"); + EWOL_PRINT(" -h/--help: Display this help"); + EWOL_PRINT(" example:"); + EWOL_PRINT(" " << etk::getApplicationName() << " --help"); + // this is a global help system does not remove it + continue; + } else { + continue; + } + _context.getCmd().remove(iii); + --iii; + } + + EWOL_INFO("EWOL v:" << ewol::getVersion()); + // force a recalculation + /* + requestUpdateSize(); + #if defined(__EWOL_ANDROID_ORIENTATION_LANDSCAPE__) + forceOrientation(ewol::screenLandscape); + #elif defined(__EWOL_ANDROID_ORIENTATION_PORTRAIT__) + forceOrientation(ewol::screenPortrait); + #else + forceOrientation(ewol::screenAuto); + #endif + */ + ememory::SharedPtr appl = m_application; + if (appl == null) { + EWOL_ERROR(" == > Create without application"); + return; + } + appl->onCreate(*this); + EWOL_INFO(" == > Ewol system create (END)"); +} + +void ewol::Context::onStart(gale::Context& _context) { + EWOL_INFO(" == > Ewol system start (BEGIN)"); + ememory::SharedPtr appl = m_application; + if (appl == null) { + // TODO : Request exit of the application .... with error ... + return; + } + appl->onStart(*this); + EWOL_INFO(" == > Ewol system start (END)"); +} + +void ewol::Context::onResume(gale::Context& _context) { + EWOL_INFO(" == > Ewol system resume (BEGIN)"); + ememory::SharedPtr appl = m_application; + if (appl == null) { + return; + } + appl->onResume(*this); + EWOL_INFO(" == > Ewol system resume (END)"); +} + +void ewol::Context::onRegenerateDisplay(gale::Context& _context) { + //EWOL_INFO("REGENERATE_DISPLAY"); + // check if the user selected a windows + ewol::widget::WindowsShared window = m_windowsCurrent; + if (window == null) { + EWOL_DEBUG("No windows ..."); + return; + } + // Redraw all needed elements + window->onRegenerateDisplay(); + if (m_widgetManager.isDrawingNeeded() == true) { + markDrawingIsNeeded(); + } + //markDrawingIsNeeded(); +} + +void ewol::Context::onDraw(gale::Context& _context) { + //EWOL_INFO("DRAW"); + // clean internal data... + m_objectManager.cleanInternalRemoved(); + // real draw... + ewol::widget::WindowsShared window = m_windowsCurrent; + if (window == null) { + return; + } + window->sysDraw(); +} + +void ewol::Context::onPause(gale::Context& _context) { + EWOL_INFO(" == > Ewol system pause (BEGIN)"); + ememory::SharedPtr appl = m_application; + if (appl == null) { + return; + } + appl->onPause(*this); + EWOL_INFO(" == > Ewol system pause (END)"); +} + +void ewol::Context::onStop(gale::Context& _context) { + EWOL_INFO(" == > Ewol system stop (BEGIN)"); + ememory::SharedPtr appl = m_application; + if (appl == null) { + return; + } + appl->onStop(*this); + EWOL_INFO(" == > Ewol system stop (END)"); +} + +void ewol::Context::onDestroy(gale::Context& _context) { + EWOL_INFO(" == > Ewol system destroy (BEGIN)"); + // Remove current windows + m_windowsCurrent.reset(); + // clean all widget and sub widget with their resources: + m_objectManager.cleanInternalRemoved(); + ememory::SharedPtr appl = m_application; + if (appl != null) { + // call application to uninit + appl->onDestroy(*this); + m_application.reset(); + } + // internal clean elements + m_objectManager.cleanInternalRemoved(); + EWOL_INFO("List of all widget of this context must be equal at 0 ==> otherwise some remove is missing"); + m_objectManager.displayListObject(); + // now All must be removed !!! + m_objectManager.unInit(); + EWOL_INFO(" == > Ewol system destroy (END)"); +} + +void ewol::Context::onKillDemand(gale::Context& _context) { + EWOL_INFO(" == > User demand a destroy (BEGIN)"); + ememory::SharedPtr appl = m_application; + if (appl == null) { + exit(0); + return; + } + appl->onKillDemand(*this); + EWOL_INFO(" == > User demand a destroy (END)"); +} + +void ewol::Context::onPointer(enum gale::key::type _type, + int32_t _pointerID, + const vec2& _pos, + gale::key::status _state) { + switch (_state) { + case gale::key::status::move: + //EWOL_DEBUG("Receive MSG : THREAD_INPUT_MOTION"); + m_input.motion(_type, _pointerID, _pos); + break; + case gale::key::status::down: + case gale::key::status::downRepeate: + //EWOL_DEBUG("Receive MSG : THREAD_INPUT_STATE"); + m_input.state(_type, _pointerID, true, _pos); + break; + case gale::key::status::up: + //EWOL_DEBUG("Receive MSG : THREAD_INPUT_STATE"); + m_input.state(_type, _pointerID, false, _pos); + break; + default: + EWOL_DEBUG("Unknow state : " << _state); + break; + } +} +void ewol::Context::onKeyboard(const gale::key::Special& _special, + enum gale::key::keyboard _type, + char32_t _value, + gale::key::status _state) { + EWOL_VERBOSE("event {" << _special << "} " << _type << " " << _value << " " << _state); + // store the keyboard special key status for mouse event... + m_input.setLastKeyboardSpecial(_special); + if (m_windowsCurrent == null) { + // No windows ... + return; + } + bool repeate = (_state == gale::key::status::downRepeate); + bool isDown = (_state == gale::key::status::downRepeate) + || (_state == gale::key::status::down); + if (m_windowsCurrent->onEventShortCut(_special, + _value, + _type, + isDown) == true) { + // Keep a shortcut ... + return; + } + // get the current focused Widget : + ewol::WidgetShared tmpWidget = m_widgetManager.focusGet(); + if (tmpWidget == null) { + // no Widget ... + return; + } + // check if the widget allow repeating key events. + //EWOL_INFO("repeating test :" << repeate << " widget=" << tmpWidget->getKeyboardRepeate() << " state=" << isDown); + if( repeate == false + || ( repeate == true + && tmpWidget->getKeyboardRepeat() == true) ) { + // check Widget shortcut + if (tmpWidget->onEventShortCut(_special, + _value, + _type, + isDown) == false) { + // generate the direct event ... + if (_type == gale::key::keyboard::character) { + ewol::event::EntrySystem tmpEntryEvent(gale::key::keyboard::character, + gale::key::status::up, + _special, + _value); + if(isDown == true) { + tmpEntryEvent.m_event.setStatus(gale::key::status::down); + } + tmpWidget->systemEventEntry(tmpEntryEvent); + } else { // THREAD_KEYBORAD_MOVE + ewol::event::EntrySystem tmpEntryEvent(_type, + gale::key::status::up, + _special, + 0); + if(isDown == true) { + tmpEntryEvent.m_event.setStatus(gale::key::status::down); + } + tmpWidget->systemEventEntry(tmpEntryEvent); + } + } else { + EWOL_DEBUG("remove Repeate key ..."); + } + } +} + +/* +void ewol::Context::processEvents() { + case eSystemMessage::msgResize: + //EWOL_DEBUG("Receive MSG : THREAD_RESIZE"); + m_windowsSize = data->dimention; + ewol::Dimension::setPixelWindowsSize(m_windowsSize); + forceRedrawAll(); + break; +*/ + +void ewol::Context::onClipboardEvent(enum gale::context::clipBoard::clipboardListe _clipboardId) { + ewol::WidgetShared tmpWidget = m_widgetManager.focusGet(); + if (tmpWidget != null) { + tmpWidget->onEventClipboard(_clipboardId); + } +} + + +ewol::Context::Context(ewol::context::Application* _application) : + //m_application(ememory::makeShared(_application)), + m_application(_application), + m_objectManager(*this), + m_input(*this), + m_windowsCurrent(null), + m_initStepId(0) { + if (m_application == null) { + EWOL_CRITICAL("Can not start context with no Application ==> rtfm ..."); + } +} + +ewol::Context::~Context() { + // nothing to do ... +} + +void ewol::Context::requestUpdateSize() { + gale::Context& context = gale::getContext(); + context.requestUpdateSize(); +} + +void ewol::Context::onPeriod(const echrono::Clock& _time) { + m_objectManager.timeCall(_time); +} + +void ewol::Context::resetIOEvent() { + m_input.newLayerSet(); +} + +void ewol::Context::setWindows(const ewol::widget::WindowsShared& _windows) { + EWOL_INFO("set New windows"); + // remove current focus : + m_widgetManager.focusSetDefault(null); + m_widgetManager.focusRelease(); + // set the new pointer as windows system + m_windowsCurrent = _windows; + // set the new default focus: + m_widgetManager.focusSetDefault(_windows); + // display the title of the Windows: + if (m_windowsCurrent != null) { + setTitle(m_windowsCurrent->propertyTitle.get()); + } + // request all the widget redrawing + forceRedrawAll(); +} + +ewol::widget::WindowsShared ewol::Context::getWindows() { + return m_windowsCurrent; +}; +void ewol::Context::onResize(const ivec2& _size) { + EWOL_VERBOSE("Resize: " << _size); + forceRedrawAll(); +} + +void ewol::Context::forceRedrawAll() { + if (m_windowsCurrent == null) { + return; + } + ivec2 size = getSize(); + m_windowsCurrent->setSize(vec2(size.x(), size.y())); + m_windowsCurrent->onChangeSize(); +} + diff --git a/src/org/atriasoft/ewol/context/Context.java b/src/org/atriasoft/ewol/context/Context.java new file mode 100644 index 0000000..8adf8ea --- /dev/null +++ b/src/org/atriasoft/ewol/context/Context.java @@ -0,0 +1,159 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + // Here we hereted from the gale application to be agnostic of the OW where we work ... + class Context : public gale::Application { + private: + ememory::SharedPtr m_application; //!< Application handle + public: + ememory::SharedPtr getApplication() { + return m_application; + } + public: + gale::context::CommandLine& getCmd() { + return gale::getContext().getCmd(); + }; + private: + ewol::context::ConfigFont m_configFont; //!< global font configuration + public: + ewol::context::ConfigFont& getFontDefault() { + return m_configFont; + }; + private: + ewol::object::Manager m_objectManager; //!< Object Manager main instance + public: + ewol::object::Manager& getEObjectManager() { + return m_objectManager; + }; + private: + ewol::widget::Manager m_widgetManager; //!< global widget manager + public: + ewol::widget::Manager& getWidgetManager() { + return m_widgetManager; + }; + public: + gale::resource::Manager& getResourcesManager() { + return gale::getContext().getResourcesManager(); + }; + public: + Context(ewol::context::Application* _application); + virtual ~Context(); + private: + ewol::context::InputManager m_input; + public: // herited function: + void onCreate(gale::Context& _context) override; + void onStart(gale::Context& _context) override; + void onResume(gale::Context& _context) override; + void onRegenerateDisplay(gale::Context& _context) override; + void onDraw(gale::Context& _context) override; + void onPause(gale::Context& _context) override; + void onStop(gale::Context& _context) override; + void onDestroy(gale::Context& _context) override; + void onKillDemand(gale::Context& _context) override; + void onPointer(enum gale::key::type _type, + int32_t _pointerID, + const vec2& _pos, + gale::key::status _state) override; + void onKeyboard(const gale::key::Special& _special, + enum gale::key::keyboard _type, + char32_t _value, + gale::key::status _state) override; + void onClipboardEvent(enum gale::context::clipBoard::clipboardListe _clipboardId) override; + public: + /** + * @brief reset event management for the IO like Input ou Mouse or keyborad + */ + void resetIOEvent(); + private: + ewol::widget::WindowsShared m_windowsCurrent; //!< curent displayed windows + public: + /** + * @brief set the current windows to display : + * @param _windows Windows that might be displayed + */ + void setWindows(const ewol::widget::WindowsShared& _windows); + /** + * @brief get the current windows that is displayed + * @return the current handle on the windows (can be null) + */ + ewol::widget::WindowsShared getWindows(); + + /** + * @brief Redraw all the windows + */ + void forceRedrawAll(); + + /** + * @brief This is to transfert the event from one widget to another one + * @param source the widget where the event came from + * @param destination the widget where the event mitgh be generated now + */ + void inputEventTransfertWidget(ewol::WidgetShared _source, ewol::WidgetShared _destination); + /** + * @brief This fonction lock the pointer properties to move in relative instead of absolute + * @param[in] widget The widget that lock the pointer events + */ + void inputEventGrabPointer(ewol::WidgetShared _widget); + /** + * @brief This fonction un-lock the pointer properties to move in relative instead of absolute + */ + void inputEventUnGrabPointer(); + void onResize(const ivec2& _size) override; + public: + /** + * @brief This is the only one things the User might done in his main(); + * @note : must be implemented in all system OPS implementation + * @note To answare you before you ask the question, this is really simple: + * Due to the fect that the current system is multiple-platform, you "main" + * Does not exist in the android platform, then ewol call other start + * and stop function, to permit to have only one code + * @note The main can not be in the ewol, due to the fact thet is an librairy + * @param[in] _argc Standard argc + * @param[in] _argv Standard argv + * @return normal error int for the application error management + */ + static int main(int _argc, const char *_argv[]); + private: + size_t m_initStepId; + size_t m_initTotalStep; + public: + /** + * @brief Special for init (main) set the start image when loading data + * @param[in] _fileName Name of the image to load + */ + void setInitImage(const etk::Uri& _fileName); + public: + /** + * @brief Request a display after call a resize + */ + void requestUpdateSize(); + void onPeriod(const echrono::Clock& _time) override; + }; + /** + * @brief From everyware in the program, we can get the context inteface. + * @return current reference on the instance. + */ + Context& getContext(); +}; + diff --git a/src/org/atriasoft/ewol/context/InputManager.cpp b/src/org/atriasoft/ewol/context/InputManager.cpp new file mode 100644 index 0000000..0e57cd8 --- /dev/null +++ b/src/org/atriasoft/ewol/context/InputManager.cpp @@ -0,0 +1,502 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::context::InputManager); + +#define EVENT_DEBUG EWOL_VERBOSE +//#define EVENT_DEBUG EWOL_DEBUG + +void ewol::context::InputManager::calculateLimit() { + m_eventInputLimit.sepatateTime = echrono::Duration(echrono::milliseconds(300)); + m_eventInputLimit.DpiOffset = m_dpi*100; + m_eventMouseLimit.sepatateTime = echrono::Duration(echrono::milliseconds(300)); + m_eventMouseLimit.DpiOffset = float(m_dpi)*0.1f; +} + +void ewol::context::InputManager::setDpi(int32_t newDPI) { + m_dpi = newDPI; + // recalculate the DPI system ... + calculateLimit(); +} + +bool ewol::context::InputManager::localEventInput(enum gale::key::type _type, + ewol::WidgetShared _destWidget, + int32_t _IdInput, + enum gale::key::status _status, + vec2 _pos) { + if (_destWidget != null) { + if ( _type == gale::key::type::mouse + || _type == gale::key::type::finger) { + // create the system Event : + ewol::event::InputSystem tmpEventSystem(_type, _status, _IdInput, _pos, _destWidget, 0, m_specialKey); // TODO : set the real ID ... + // generate the event : + return _destWidget->systemEventInput(tmpEventSystem); + } else { + return false; + } + } + return false; +} + +void ewol::context::InputManager::abortElement(InputPoperty *_eventTable, + int32_t _idInput, + enum gale::key::type _type) { + if (_eventTable == null) { + return; + } + if (_eventTable[_idInput].isUsed == true) { + localEventInput(_type, + _eventTable[_idInput].curentWidgetEvent.lock(), + _eventTable[_idInput].destinationInputId, + gale::key::status::abort, + _eventTable[_idInput].posEvent); + } +} + +void ewol::context::InputManager::cleanElement(InputPoperty *_eventTable, + int32_t _idInput) { + if (_eventTable == null) { + return; + } + //EWOL_INFO("CleanElement[" << idInput << "] = @" << (int64_t)eventTable); + _eventTable[_idInput].isUsed = false; + _eventTable[_idInput].destinationInputId = 0; + _eventTable[_idInput].lastTimeEvent.reset(); + _eventTable[_idInput].curentWidgetEvent.reset(); + _eventTable[_idInput].origin.setValue(0,0); + _eventTable[_idInput].size.setValue(99999999,99999999); + _eventTable[_idInput].downStart.setValue(0,0); + _eventTable[_idInput].isDown = false; + _eventTable[_idInput].isInside = false; + _eventTable[_idInput].nbClickEvent = 0; + _eventTable[_idInput].posEvent.setValue(0,0); +} + +void ewol::context::InputManager::transfertEvent(ewol::WidgetShared _source, ewol::WidgetShared _destination) { + if( _source == null + || _destination == null) { + // prevent errors ... + return; + } + for(int32_t iii=0; iii" << m_eventInputSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_ABORT] " << m_eventInputSaved[iii].posEvent); + localEventInput(gale::key::type::finger, tmpWidget, m_eventInputSaved[iii].destinationInputId, gale::key::status::abort, m_eventInputSaved[iii].posEvent); + // set the new widget ... + m_eventInputSaved[iii].curentWidgetEvent = _destination; + // inform the widget that he receive the event property now... + EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventInputSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_TRANSFERT] " << m_eventInputSaved[iii].posEvent); + localEventInput(gale::key::type::finger, _destination, m_eventInputSaved[iii].destinationInputId, gale::key::status::transfert, m_eventInputSaved[iii].posEvent); + } + tmpWidget = m_eventMouseSaved[iii].curentWidgetEvent.lock(); + if (tmpWidget == _source) { + // inform the widget that it does not receive the event now + EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventMouseSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_ABORT] " << m_eventMouseSaved[iii].posEvent); + localEventInput(gale::key::type::mouse, tmpWidget, m_eventMouseSaved[iii].destinationInputId, gale::key::status::abort, m_eventMouseSaved[iii].posEvent); + // set the new widget ... + m_eventMouseSaved[iii].curentWidgetEvent = _destination; + // inform the widget that he receive the event property now... + EVENT_DEBUG("GUI : Input ID=" << iii << " == >" << m_eventMouseSaved[iii].destinationInputId << " [EVENT_INPUT_TYPE_TRANSFERT] " << m_eventMouseSaved[iii].posEvent); + localEventInput(gale::key::type::mouse, _destination, m_eventMouseSaved[iii].destinationInputId, gale::key::status::transfert, m_eventMouseSaved[iii].posEvent); + } + } +} + +void ewol::context::InputManager::grabPointer(ewol::WidgetShared _widget) { + if(_widget == null) { + return; + } + m_grabWidget = _widget; + /* TODO : + m_context.grabPointerEvents(true, _widget->getOrigin() + + ivec2(_widget->getSize().x()/2.0f, + _widget->getSize().y()/2.0f) ); + */ +} + +void ewol::context::InputManager::unGrabPointer() { + m_grabWidget.reset(); + // TODO: m_context.grabPointerEvents(false, vec2(0,0)); +} + +void ewol::context::InputManager::newLayerSet() { + for(int32_t iii=0; iii the it was finger event ... +void ewol::context::InputManager::motion(enum gale::key::type _type, + int _pointerID, + vec2 _pos) { + EVENT_DEBUG("motion event : " << _type << " " << _pointerID << " " << _pos); + if (MAX_MANAGE_INPUT <= _pointerID) { + // reject pointer == > out of IDs... + return; + } + InputPoperty *eventTable = null; + if (_type == gale::key::type::mouse) { + eventTable = m_eventMouseSaved; + } else if (_type == gale::key::type::finger) { + eventTable = m_eventInputSaved; + } else { + EWOL_ERROR("Unknown type of event"); + return; + } + if( _pointerID > MAX_MANAGE_INPUT + || _pointerID < 0) { + // not manage input + return; + } + ewol::widget::WindowsShared tmpWindows = m_context.getWindows(); + // special case for the mouse event 0 that represent the hover event of the system : + if ( _type == gale::key::type::mouse + && _pointerID == 0) { + // this event is all time on the good widget ... and manage the enter and leave ... + // NOTE : the "layer widget" force us to get the widget at the specific position all the time : + ewol::WidgetShared tmpWidget; + if (m_grabWidget.lock() != null) { + // grab all events ... + tmpWidget = m_grabWidget.lock(); + } else { + if (tmpWindows != null) { + tmpWidget = tmpWindows->getWidgetAtPos(_pos); + } + } + if( tmpWidget != eventTable[_pointerID].curentWidgetEvent.lock() + || ( eventTable[_pointerID].isInside == true + && ( eventTable[_pointerID].origin.x() > _pos.x() + || eventTable[_pointerID].origin.y() > _pos.y() + || (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) < _pos.x() + || (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) < _pos.y()) ) ) { + eventTable[_pointerID].isInside = false; + EVENT_DEBUG("GUI : Input ID=" << _pointerID << " == >" << eventTable[_pointerID].destinationInputId << " [LEAVE] " << _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, + eventTable[_pointerID].curentWidgetEvent.lock(), + eventTable[_pointerID].destinationInputId, + gale::key::status::leave, + _pos); + } + if (eventTable[_pointerID].isInside == false) { + // set the element inside ... + eventTable[_pointerID].isInside = true; + // get destination widget : + eventTable[_pointerID].curentWidgetEvent = tmpWidget; + if (tmpWidget == null) { + eventTable[_pointerID].isInside = false; + } else { + eventTable[_pointerID].origin = tmpWidget->getOrigin(); + eventTable[_pointerID].size = tmpWidget->getSize(); + } + eventTable[_pointerID].destinationInputId = 0; + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [ENTER] " << _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, + tmpWidget, + eventTable[_pointerID].destinationInputId, + gale::key::status::enter, + _pos); + } + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [MOVE] " << _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, + tmpWidget, + eventTable[_pointerID].destinationInputId, + gale::key::status::move, + _pos); + } else if (eventTable[_pointerID].isUsed == true) { + if (eventTable[_pointerID].isInside == true) { + if( eventTable[_pointerID].origin.x() > _pos.x() + || eventTable[_pointerID].origin.y() > _pos.y() + || (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) < _pos.x() + || (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) < _pos.y()) { + eventTable[_pointerID].isInside = false; + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [LEAVE] " << _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, + eventTable[_pointerID].curentWidgetEvent.lock(), + eventTable[_pointerID].destinationInputId, + gale::key::status::leave, + _pos); + } + } else { + if( ( eventTable[_pointerID].origin.x() <= _pos.x() + && (eventTable[_pointerID].origin.x() + eventTable[_pointerID].size.x()) >= _pos.x() ) + && ( eventTable[_pointerID].origin.y() <= _pos.y() + && (eventTable[_pointerID].origin.y() + eventTable[_pointerID].size.y()) >= _pos.y() ) ) { + eventTable[_pointerID].isInside = true; + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [ENTER] " << _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, + eventTable[_pointerID].curentWidgetEvent.lock(), + eventTable[_pointerID].destinationInputId, + gale::key::status::enter, + _pos); + } + } + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [MOVE] " << _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, + eventTable[_pointerID].curentWidgetEvent.lock(), + eventTable[_pointerID].destinationInputId, + gale::key::status::move, + _pos); + } +} + +void ewol::context::InputManager::state(enum gale::key::type _type, + int _pointerID, + bool _isDown, + vec2 _pos) { + if (_pointerID >= MAX_MANAGE_INPUT) { + // reject pointer == > out of IDs... + return; + } + EVENT_DEBUG("event pointerId=" << _pointerID); + // convert position in open-GL coordonates ... + InputPoperty *eventTable = null; + InputLimit localLimit; + if (_type == gale::key::type::mouse) { + eventTable = m_eventMouseSaved; + localLimit = m_eventMouseLimit; + } else if (_type == gale::key::type::finger) { + eventTable = m_eventInputSaved; + localLimit = m_eventInputLimit; + } else { + EWOL_ERROR("Unknown type of event"); + return; + } + if( _pointerID > MAX_MANAGE_INPUT + || _pointerID <= 0) { + // not manage input + return; + } + // get the curent time ... + echrono::Clock currentTime = echrono::Clock::now(); + ewol::widget::WindowsShared tmpWindows = m_context.getWindows(); + + if (_isDown == true) { + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [DOWN] " << _pos); + if(eventTable[_pointerID].isUsed == true) { + // we have an event previously ... check delay between click and offset position + if (currentTime - eventTable[_pointerID].lastTimeEvent > localLimit.sepatateTime) { + cleanElement(eventTable, _pointerID); + } else if( etk::abs(eventTable[_pointerID].downStart.x() - _pos.x()) >= localLimit.DpiOffset + || etk::abs(eventTable[_pointerID].downStart.y() - _pos.y()) >= localLimit.DpiOffset ){ + cleanElement(eventTable, _pointerID); + } + } + if(eventTable[_pointerID].isUsed == true) { + // save start time + eventTable[_pointerID].lastTimeEvent = currentTime; + // generate DOWN Event + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [DOWN] " << _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, + eventTable[_pointerID].curentWidgetEvent.lock(), + eventTable[_pointerID].destinationInputId, + gale::key::status::down, + _pos); + } else { + // Mark it used : + eventTable[_pointerID].isUsed = true; + // Save current position : + eventTable[_pointerID].downStart = _pos; + // save start time + eventTable[_pointerID].lastTimeEvent = currentTime; + // set the element inside ... + eventTable[_pointerID].isInside = true; + ewol::WidgetShared tmpWidget = m_grabWidget.lock(); + // get destination widget : + if(tmpWindows != null) { + if ( tmpWidget != null + && _type == gale::key::type::mouse) { + eventTable[_pointerID].curentWidgetEvent = tmpWidget; + } else { + tmpWidget = tmpWindows->getWidgetAtPos(_pos); + eventTable[_pointerID].curentWidgetEvent = tmpWidget; + if (tmpWidget != null) { + EVENT_DEBUG("Get widget at pos=" << _pos << " type: " << tmpWidget->getObjectType()); + } else { + EVENT_DEBUG("Get widget at pos=" << _pos << " NO WIDGET"); + } + } + } else { + eventTable[_pointerID].curentWidgetEvent.reset(); + } + tmpWidget = eventTable[_pointerID].curentWidgetEvent.lock(); + if (tmpWidget != null) { + eventTable[_pointerID].origin = tmpWidget->getOrigin(); + eventTable[_pointerID].size = tmpWidget->getSize(); + eventTable[_pointerID].destinationInputId = localGetDestinationId(_type, tmpWidget, _pointerID); + } else { + eventTable[_pointerID].destinationInputId = -1; + } + // generate DOWN Event + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [DOWN] " << _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, + tmpWidget, + eventTable[_pointerID].destinationInputId, + gale::key::status::down, + _pos); + } + } else { + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [UP] " << _pos); + ewol::WidgetShared tmpWidget = eventTable[_pointerID].curentWidgetEvent.lock(); + if(eventTable[_pointerID].isUsed == false) { + // bad case ... ??? + EWOL_DEBUG("Up event without previous down ... "); + // Mark it un-used : + eventTable[_pointerID].isUsed = false; + // revove the widget ... + eventTable[_pointerID].curentWidgetEvent.reset(); + } else if (tmpWidget == null) { + // The widget has been removed: + EVENT_DEBUG(" Object Removed ..."); + // Mark it un-used : + eventTable[_pointerID].isUsed = false; + // revove the widget ... + eventTable[_pointerID].curentWidgetEvent.reset(); + } else { + // generate UP Event + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [UP] " << _pos); + eventTable[_pointerID].posEvent = _pos; + // send up event after the single event to prevent multiple widget getting elements + localEventInput(_type, + tmpWidget, + _pointerID, + gale::key::status::up, + _pos); + // generate event (single) + if( etk::abs(eventTable[_pointerID].downStart.x() - _pos.x()) < localLimit.DpiOffset + && etk::abs(eventTable[_pointerID].downStart.y() - _pos.y()) < localLimit.DpiOffset ){ + // Save current position : + eventTable[_pointerID].downStart = _pos; + // save start time + eventTable[_pointerID].lastTimeEvent = currentTime; + int32_t nbClickMax = 0; + if(tmpWidget != null) { + nbClickMax = tmpWidget->getMouseLimit(); + if (nbClickMax>5) { + nbClickMax = 5; + } + } + // in grab mode the single to quinte event are not generated .... + if( ( m_grabWidget.lock() == null + || _type != gale::key::type::mouse ) + && eventTable[_pointerID].nbClickEvent < nbClickMax) { + // generate event SINGLE : + eventTable[_pointerID].nbClickEvent++; + EVENT_DEBUG("GUI : Input ID=" << _pointerID + << " == >" << eventTable[_pointerID].destinationInputId + << " [" << eventTable[_pointerID].nbClickEvent << "] " << _pos); + eventTable[_pointerID].posEvent = _pos; + localEventInput(_type, + tmpWidget, + eventTable[_pointerID].destinationInputId, + (enum gale::key::status)(uint32_t(gale::key::status::pressSingle) + eventTable[_pointerID].nbClickEvent-1), + _pos); + if( eventTable[_pointerID].nbClickEvent >= nbClickMax) { + eventTable[_pointerID].nbClickEvent = 0; + } + } else { + eventTable[_pointerID].nbClickEvent = 0; + } + } + // send up event after the single event to prevent multiple widget getting elements + localEventInput(_type, + tmpWidget, + _pointerID, + gale::key::status::upAfter, + _pos); + // specific for tuch event + if (_type == gale::key::type::finger) { + cleanElement(eventTable, _pointerID); + } + } + } +} + + diff --git a/src/org/atriasoft/ewol/context/InputManager.java b/src/org/atriasoft/ewol/context/InputManager.java new file mode 100644 index 0000000..1445d0f --- /dev/null +++ b/src/org/atriasoft/ewol/context/InputManager.java @@ -0,0 +1,120 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once +#include + +#define MAX_MANAGE_INPUT (15) + +namespace ewol { + namespace context { + /** + * @brief internal structure + * @not_in_doc + */ + class InputPoperty { + public: + bool isUsed; + int32_t destinationInputId; + echrono::Clock lastTimeEvent; + ewol::WidgetWeak curentWidgetEvent; + vec2 origin; + vec2 size; + vec2 downStart; + vec2 posEvent; + bool isDown; + bool isInside; + int32_t nbClickEvent; // 0 .. 1 .. 2 .. 3 + }; + + /** + * @brief internal structure + * @not_in_doc + */ + class InputLimit { + public: + echrono::Duration sepatateTime; + int32_t DpiOffset; + }; + class Context; + class InputManager{ + // special grab pointer mode : + private: + ewol::WidgetWeak m_grabWidget; //!< widget that grab the curent pointer. + private: + int32_t m_dpi; + InputLimit m_eventInputLimit; + InputLimit m_eventMouseLimit; + void calculateLimit(); + InputPoperty m_eventInputSaved[MAX_MANAGE_INPUT]; + InputPoperty m_eventMouseSaved[MAX_MANAGE_INPUT]; + void abortElement(InputPoperty* _eventTable, int32_t _idInput, enum gale::key::type _type); + void cleanElement(InputPoperty* _eventTable, int32_t _idInput); + /** + * @brief generate the event on the destinated widget. + * @param[in] _type Type of the event that might be sended. + * @param[in] _destWidget Pointer on the requested widget that element might be sended + * @param[in] _IdInput Id of the event (PC : [0..9] and touch : [1..9]) + * @param[in] _typeEvent type of the eventg generated + * @param[in] _pos position of the event + * @return true if event has been greped + */ + bool localEventInput(enum gale::key::type _type, + ewol::WidgetShared _destWidget, + int32_t _IdInput, + enum gale::key::status _typeEvent, + vec2 _pos); + /** + * @brief convert the system event id in the correct EWOL id depending of the system management mode + * This function find the next input id unused on the specifiic widget + * == > on PC, the ID does not change (GUI is not the same) + * @param[in] _type Type of the kay event. + * @param[in] _destWidget Pointer of the widget destination + * @param[in] _realInputId system Id + * @return the ewol input id + */ + int32_t localGetDestinationId(enum gale::key::type _type, + ewol::WidgetShared _destWidget, + int32_t _realInputId); + private: + ewol::Context& m_context; + public: + InputManager(ewol::Context& _context); + ~InputManager(); + void setDpi(int32_t _newDPI); + + // note if id<0 == > the it was finger event ... + void motion(enum gale::key::type _type, int _pointerID, vec2 _pos ); + void state(enum gale::key::type _type, int _pointerID, bool _isDown, vec2 _pos); + public: + /** + * @brief a new layer on the windows is set == > might remove all the property of the current element ... + */ + void newLayerSet(); + /** + * @brief This is to transfert the event from one widget to another one + * @param _source the widget where the event came from + * @param _destination the widget where the event mitgh be generated now + */ + void transfertEvent(ewol::WidgetShared _source, ewol::WidgetShared _destination); + /** + * @brief This fonction lock the pointer properties to move in relative instead of absolute + * @param[in] _widget The widget that lock the pointer events + */ + void grabPointer(ewol::WidgetShared _widget); + /** + * @brief This fonction un-lock the pointer properties to move in relative instead of absolute + */ + void unGrabPointer(); + private: + gale::key::Special m_specialKey; + public: + void setLastKeyboardSpecial(const gale::key::Special& _specialKey) { + m_specialKey = _specialKey; + } + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/debug.cpp b/src/org/atriasoft/ewol/debug.cpp new file mode 100644 index 0000000..643e481 --- /dev/null +++ b/src/org/atriasoft/ewol/debug.cpp @@ -0,0 +1,12 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +int32_t ewol::getLogId() { + static int32_t g_val = elog::registerInstance("ewol"); + return g_val; +} diff --git a/src/org/atriasoft/ewol/event/Entry.cpp b/src/org/atriasoft/ewol/event/Entry.cpp new file mode 100644 index 0000000..912e1a8 --- /dev/null +++ b/src/org/atriasoft/ewol/event/Entry.cpp @@ -0,0 +1,25 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +ETK_DECLARE_TYPE(ewol::event::Entry); + +etk::Stream& ewol::event::operator <<(etk::Stream& _os, const ewol::event::Entry& _obj) { + _os << "{type=" << _obj.getType(); + _os << " status=" << _obj.getStatus(); + if (_obj.getType() == gale::key::keyboard::character) { + _os << " char=" << _obj.getChar(); + } + _os << "}"; + return _os; +} + +etk::Stream& ewol::event::operator <<(etk::Stream& _os, const ewol::event::EntrySystem& _obj) { + _os << _obj.m_event; + return _os; +} diff --git a/src/org/atriasoft/ewol/event/Entry.java b/src/org/atriasoft/ewol/event/Entry.java new file mode 100644 index 0000000..427e060 --- /dev/null +++ b/src/org/atriasoft/ewol/event/Entry.java @@ -0,0 +1,70 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ewol { + namespace event { + class Entry { + private: + enum gale::key::keyboard m_type; //!< type of hardware event + enum gale::key::status m_status; //!< status of hardware event + gale::key::Special m_specialKey; //!< input key status (prevent change in time..) + char32_t m_unicodeData; //!< Unicode data (in some case) + public: + Entry(enum gale::key::keyboard _type, + enum gale::key::status _status, + gale::key::Special _specialKey, + char32_t _char) : + m_type(_type), + m_status(_status), + m_specialKey(_specialKey), + m_unicodeData(_char) { + + }; + void setType(enum gale::key::keyboard _type) { + m_type = _type; + }; + inline const enum gale::key::keyboard& getType() const { + return m_type; + }; + void setStatus(enum gale::key::status _status) { + m_status = _status; + }; + inline const enum gale::key::status& getStatus() const { + return m_status; + }; + void setSpecialKey(const gale::key::Special& _specialKey) { + m_specialKey = _specialKey; + }; + inline const gale::key::Special& getSpecialKey() const { + return m_specialKey; + }; + void setChar(char32_t _char) { + m_unicodeData = _char; + }; + inline const char32_t& getChar() const { + return m_unicodeData; + }; + }; + etk::Stream& operator <<(etk::Stream& _os, const ewol::event::Entry& _obj); + + class EntrySystem { + public: + EntrySystem(enum gale::key::keyboard _type, + enum gale::key::status _status, + gale::key::Special _specialKey, + char32_t _char) : + m_event(_type, _status, _specialKey, _char) { + + }; + ewol::event::Entry m_event; + }; + etk::Stream& operator <<(etk::Stream& _os, const ewol::event::EntrySystem& _obj); + }; +}; diff --git a/src/org/atriasoft/ewol/event/Input.cpp b/src/org/atriasoft/ewol/event/Input.cpp new file mode 100644 index 0000000..a846a3f --- /dev/null +++ b/src/org/atriasoft/ewol/event/Input.cpp @@ -0,0 +1,24 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +ETK_DECLARE_TYPE(ewol::event::Input); + +etk::Stream& ewol::event::operator <<(etk::Stream& _os, const ewol::event::Input& _obj) { + _os << "{type=" << _obj.getType(); + _os << " status=" << _obj.getStatus(); + _os << " id=" << etk::toString(_obj.getId()); + _os << " pos=" << _obj.getPos(); + _os << "}"; + return _os; +} + +etk::Stream& ewol::event::operator <<(etk::Stream& _os, const ewol::event::InputSystem& _obj) { + _os << _obj.m_event; + return _os; +} diff --git a/src/org/atriasoft/ewol/event/Input.java b/src/org/atriasoft/ewol/event/Input.java new file mode 100644 index 0000000..05e6557 --- /dev/null +++ b/src/org/atriasoft/ewol/event/Input.java @@ -0,0 +1,104 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include + +namespace ewol { + namespace event { + class Input { + private: + enum gale::key::type m_type; + enum gale::key::status m_status; + uint8_t m_inputId; + vec2 m_pos; + gale::key::Special m_specialKey; //!< input key status (prevent change in time..) + public: + Input(enum gale::key::type _type, + enum gale::key::status _status, + uint8_t _id, + const vec2& _pos, + gale::key::Special _specialKey): + m_type(_type), + m_status(_status), + m_inputId(_id), + m_pos(_pos), + m_specialKey(_specialKey) { + + }; + void setType(enum gale::key::type _type) { + m_type = _type; + }; + inline const enum gale::key::type& getType() const { + return m_type; + }; + void setStatus(enum gale::key::status _status) { + m_status = _status; + }; + inline const enum gale::key::status& getStatus() const { + return m_status; + }; + void setId(uint8_t _id) { + m_inputId = _id; + }; + inline const uint8_t& getId() const { + return m_inputId; + }; + void setPos(const vec2& _pos) { + m_pos = _pos; + }; + inline const vec2& getPos() const { + return m_pos; + }; + void setSpecialKey(const gale::key::Special& _specialKey) { + m_specialKey = _specialKey; + }; + inline const gale::key::Special& getSpecialKey() const { + return m_specialKey; + }; + /** + * @brief Reset the input property of the curent event. + */ + void reset() const { + // TODO : Call the entry element ant rest it ... + } + }; + etk::Stream& operator <<(etk::Stream& _os, const ewol::event::Input& _obj); + + class InputSystem { + public: + InputSystem(enum gale::key::type _type, + enum gale::key::status _status, + uint8_t _id, + const vec2& _pos, + ewol::WidgetShared _dest, + int32_t _realIdEvent, + gale::key::Special _specialKey) : + m_event(_type, _status, _id, _pos, _specialKey), + m_dest(_dest), + m_realIdEvent(_realIdEvent) { }; + ewol::event::Input m_event; + private: + ewol::WidgetShared m_dest; + int32_t m_realIdEvent; + public: + void setDestWidget(ewol::WidgetShared _dest) { + m_dest = _dest; + }; + inline ewol::WidgetShared getDestWidget() const { + return m_dest; + }; + void setRealId(int32_t _realIdEvent) { + m_realIdEvent = _realIdEvent; + }; + inline int32_t getRealId() const { + return m_realIdEvent; + }; + }; + etk::Stream& operator <<(etk::Stream& _os, const ewol::event::InputSystem& _obj); + }; +}; + diff --git a/src/org/atriasoft/ewol/event/Time.cpp b/src/org/atriasoft/ewol/event/Time.cpp new file mode 100644 index 0000000..a843bf4 --- /dev/null +++ b/src/org/atriasoft/ewol/event/Time.cpp @@ -0,0 +1,35 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +ETK_DECLARE_TYPE(ewol::event::Time); + +etk::Stream& ewol::event::operator <<(etk::Stream& _os, const ewol::event::Time& _obj) { + _os << "{time=" << _obj.getTime(); + _os << " uptime=" << _obj.getApplUpTime(); + _os << " delta=" << _obj.getDelta(); + _os << " deltaCall=" << _obj.getDeltaCall(); + _os << "}"; + return _os; +} + +namespace etk { + template<> etk::String toString(ewol::event::Time const& _obj) { + etk::String out; + out = "{[ewol::event::Time]time=" + etk::toString(_obj.getTime()); + out += ";uptime=" + etk::toString(_obj.getApplUpTime()); + out += ";delta=" + etk::toString(_obj.getDelta()); + out += ";deltaCall=" + etk::toString(_obj.getDeltaCall()); + out += "}"; + return out; + } +} + +// declare for signal event +#include +ESIGNAL_DECLARE_SIGNAL(ewol::event::Time); + diff --git a/src/org/atriasoft/ewol/event/Time.java b/src/org/atriasoft/ewol/event/Time.java new file mode 100644 index 0000000..de66d18 --- /dev/null +++ b/src/org/atriasoft/ewol/event/Time.java @@ -0,0 +1,69 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include + +namespace ewol { + namespace event { + class Time { + private: + echrono::Clock m_timeSystem; //!< Current system time (micro-second) + echrono::Clock m_timeUpAppl; //!< Current application wake up-time (micro-second) + echrono::Duration m_timeDelta; //!< Time from the last cycle call of the system (main appl tick) (second) + echrono::Duration m_timeDeltaCall; //!< Time from the last call (when we can manage periodic call with specifying periode) (second) + public: + Time(const echrono::Clock& _timeSystem, + const echrono::Clock& _timeUpAppl, + const echrono::Duration& _timeDelta, + const echrono::Duration& _timeDeltaCall) : + m_timeSystem(_timeSystem), + m_timeUpAppl(_timeUpAppl), + m_timeDelta(_timeDelta), + m_timeDeltaCall(_timeDeltaCall){ + + }; + public: + void setTime(const echrono::Clock& _timeSystem) { + m_timeSystem = _timeSystem; + }; + inline const echrono::Clock& getTime() const { + return m_timeSystem; + }; + void setApplWakeUpTime(const echrono::Clock& _timeUpAppl) { + m_timeUpAppl = _timeUpAppl; + }; + inline const echrono::Clock& getApplWakeUpTime() const { + return m_timeUpAppl; + }; + inline echrono::Duration getApplUpTime() const { + return m_timeSystem-m_timeUpAppl; + }; + void setDelta(const echrono::Duration& _timeDelta) { + m_timeDelta = _timeDelta; + }; + inline const echrono::Duration& getDeltaDuration() const { + return m_timeDelta; + }; + inline float getDelta() const { + return m_timeDelta.toSeconds(); + }; + void setDeltaCall(const echrono::Duration& _timeDeltaCall) { + m_timeDeltaCall = _timeDeltaCall; + }; + inline const echrono::Duration& getDeltaCallDuration() const { + return m_timeDeltaCall; + }; + inline float getDeltaCall() const { + return m_timeDeltaCall.toSeconds(); + }; + }; + etk::Stream& operator <<(etk::Stream& _os, const ewol::event::Time& _obj); + } +} + diff --git a/src/org/atriasoft/ewol/ewol.cpp b/src/org/atriasoft/ewol/ewol.cpp new file mode 100644 index 0000000..079b52a --- /dev/null +++ b/src/org/atriasoft/ewol/ewol.cpp @@ -0,0 +1,32 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include + +#include +#include + +#ifndef EWOL_VERSION +#define EWOL_VERSION "0.0.0" +#endif + +etk::String ewol::getVersion() { + return EWOL_VERSION; +} + + +int32_t ewol::run(ewol::context::Application* _application, + int32_t _argc, + const char* _argv[]) { + etranslate::init(_argc, _argv); + return gale::run(ETK_NEW(ewol::Context, _application), _argc, _argv); +} + + diff --git a/src/org/atriasoft/ewol/ewol.java b/src/org/atriasoft/ewol/ewol.java new file mode 100644 index 0000000..1e5ba30 --- /dev/null +++ b/src/org/atriasoft/ewol/ewol.java @@ -0,0 +1,30 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ewol { + /** + * @brief This is the only one things the User might done in his main(); + * @note To answare you before you ask the question, this is really simple: + * Due to the fect that the current system is multiple-platform, you "main" + * Does not exist in the android platform, then ewol call other start + * and stop function, to permit to have only one code + * @note The main can not be in the ewol, due to the fact thet is an librairy + * @param[in] _application just created instance of the applicationo + * @param[in] _argc Standard argc + * @param[in] _argv Standard argv + * @return normal error int for the application error management + */ + int32_t run(ewol::context::Application* _application, int32_t _argc = 0, const char* _argv[] = null); + /** + * @brief get EWOL version + * @return The string that describe ewol version + */ + etk::String getVersion(); +}; diff --git a/src/org/atriasoft/ewol/gravity.cpp b/src/org/atriasoft/ewol/gravity.cpp new file mode 100644 index 0000000..537aea1 --- /dev/null +++ b/src/org/atriasoft/ewol/gravity.cpp @@ -0,0 +1,86 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +#include +ETK_DECLARE_TYPE(enum ewol::gravity); + +etk::String ewol::gravityToString(const enum ewol::gravity _obj) { + switch(_obj) { + case ewol::gravity_center: + return "center"; + case ewol::gravity_topLeft: + return "top-left"; + case ewol::gravity_top: + return "top"; + case ewol::gravity_topRight: + return "top-right"; + case ewol::gravity_right: + return "right"; + case ewol::gravity_buttomRight: + return "buttom-right"; + case ewol::gravity_buttom: + return "buttom"; + case ewol::gravity_buttomLeft: + return "buttom-left"; + case ewol::gravity_left: + return "left"; + } + return "unknow"; +} + +enum ewol::gravity ewol::stringToGravity(const etk::String& _obj) { + if (_obj == "center") { + return ewol::gravity_center; + } else if (_obj == "top-left") { + return ewol::gravity_topLeft; + } else if (_obj == "top") { + return ewol::gravity_top; + } else if (_obj == "top-right") { + return ewol::gravity_topRight; + } else if (_obj == "right") { + return ewol::gravity_right; + } else if (_obj == "buttom-right") { + return ewol::gravity_buttomRight; + } else if (_obj == "buttom") { + return ewol::gravity_buttom; + } else if (_obj == "buttom-left") { + return ewol::gravity_buttomLeft; + } else if (_obj == "left") { + return ewol::gravity_left; + } + return ewol::gravity_center; +} +vec2 ewol::gravityGenerateDelta(const enum ewol::gravity _gravity, const vec2& _deltas) { + vec2 out(0.0f,0.0f); + if (_deltas.x() > 0.0001f) { + if ((uint32_t(_gravity) & uint32_t(ewol::gravity_left)) != 0) { + // nothing to do + } else if ((uint32_t(_gravity) & uint32_t(ewol::gravity_right)) != 0) { + out = vec2(int32_t(_deltas.x()), 0.0f); + } else { + out = vec2(int32_t(_deltas.x()*0.5f), 0.0f); + } + } + if (_deltas.y() > 0.0001f) { + if ((uint32_t(_gravity) & uint32_t(ewol::gravity_buttom)) != 0) { + // nothing to do + } else if ((uint32_t(_gravity) & uint32_t(ewol::gravity_top)) != 0) { + out += vec2(0.0f, int32_t(_deltas.y())); + } else { + out += vec2(0.0f, int32_t(_deltas.y()*0.5f)); + } + } + return out; +} + +etk::Stream& ewol::operator <<(etk::Stream& _os, const enum ewol::gravity _obj) { + _os << ewol::gravityToString(_obj); + return _os; +} + diff --git a/src/org/atriasoft/ewol/gravity.java b/src/org/atriasoft/ewol/gravity.java new file mode 100644 index 0000000..e1cec79 --- /dev/null +++ b/src/org/atriasoft/ewol/gravity.java @@ -0,0 +1,31 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ewol { + /** + * @brief Gravity of the widget property + * @not_in_doc + */ + enum gravity { + gravity_center = 0x00, //!< gravity is in center + gravity_top = 0x01, //!< gravity is in top + gravity_buttom = 0x02, //!< gravity is in buttom + gravity_right = 0x04, //!< gravity is in right + gravity_left = 0x08, //!< gravity is in left + gravity_topRight = gravity_top|gravity_right, //!< gravity is in top-right + gravity_topLeft = gravity_top|gravity_left, //!< gravity is in top-left + gravity_buttomRight = gravity_buttom|gravity_right, //!< gravity is in buttom-right + gravity_buttomLeft = gravity_buttom|gravity_left, //!< gravity is in buttom-left + }; + etk::Stream& operator <<(etk::Stream& _os, const enum ewol::gravity _obj); + etk::String gravityToString(const enum ewol::gravity _obj); + enum ewol::gravity stringToGravity(const etk::String& _obj); + vec2 gravityGenerateDelta(const enum ewol::gravity _gravity, const vec2& _deltas); +} diff --git a/src/org/atriasoft/ewol/internal/Log.java b/src/org/atriasoft/ewol/internal/Log.java new file mode 100644 index 0000000..46f2fa1 --- /dev/null +++ b/src/org/atriasoft/ewol/internal/Log.java @@ -0,0 +1,68 @@ +package org.atriasoft.ewol.internal; + +import io.scenarium.logger.LogLevel; +import io.scenarium.logger.Logger; + +class Log { + private static final String LIB_NAME = "ewol"; + private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME); + private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL); + private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR); + private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING); + private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO); + private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG); + private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE); + private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO); + private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT); + + public static void critical(final String data) { + if (PRINT_CRITICAL) { + Logger.critical(LIB_NAME_DRAW, data); + } + } + + public static void debug(final String data) { + if (PRINT_DEBUG) { + Logger.debug(LIB_NAME_DRAW, data); + } + } + + public static void error(final String data) { + if (PRINT_ERROR) { + Logger.error(LIB_NAME_DRAW, data); + } + } + + public static void info(final String data) { + if (PRINT_INFO) { + Logger.info(LIB_NAME_DRAW, data); + } + } + + public static void print(final String data) { + if (PRINT_PRINT) { + Logger.print(LIB_NAME_DRAW, data); + } + } + + public static void todo(final String data) { + if (PRINT_TODO) { + Logger.todo(LIB_NAME_DRAW, data); + } + } + + public static void verbose(final String data) { + if (PRINT_VERBOSE) { + Logger.verbose(LIB_NAME_DRAW, data); + } + } + + public static void warning(final String data) { + if (PRINT_WARNING) { + Logger.warning(LIB_NAME_DRAW, data); + } + } + + private Log() {} + +} diff --git a/src/org/atriasoft/ewol/object/Manager.cpp b/src/org/atriasoft/ewol/object/Manager.cpp new file mode 100644 index 0000000..bc6dadd --- /dev/null +++ b/src/org/atriasoft/ewol/object/Manager.cpp @@ -0,0 +1,161 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::object::Manager); + +ewol::object::Manager::Manager(ewol::Context& _context) : + m_context(_context), + periodicCall(this, "periodic", "Call every time system render"), + m_applWakeUpTime(0), + m_lastPeriodicCallTime(0) { + EWOL_DEBUG(" == > init Object-Manager"); + periodicCall.setPeriodic(true); + // set the basic time properties : + m_applWakeUpTime = echrono::Clock::now(); + m_lastPeriodicCallTime = m_applWakeUpTime; +} + +ewol::object::Manager::~Manager() { + ethread::RecursiveLock lock(m_mutex); + m_workerList.clear(); + bool hasError = false; + if (m_eObjectList.size()!=0) { + EWOL_ERROR("Must not have anymore eObject !!!"); + hasError = true; + } + if (hasError == true) { + EWOL_ERROR("Check if the function UnInit has been called !!!"); + } + displayListObject(); +} + +void ewol::object::Manager::displayListObject() { + ethread::RecursiveLock lock(m_mutex); + EWOL_INFO("List loaded object : "); + for (auto &it : m_eObjectList) { + ewol::ObjectShared element = it.lock(); + if (element != null) { + EWOL_INFO(" [" << element->getId() << "] ref=" << element.useCount()-1 << " name='" << element->propertyName.get() << "' type=" << element->getObjectType()); + } + } +} + +void ewol::object::Manager::unInit() { + ethread::RecursiveLock lock(m_mutex); + EWOL_DEBUG(" == > Un-Init Object-Manager"); + if (m_workerList.size() > 0) { + EWOL_DEBUG(" == > Remove all workers"); + m_workerList.clear(); + } + for (auto &it : m_eObjectList) { + ewol::ObjectShared element = it.lock(); + if (element != null) { + //it->removeObject(); + } + } + if (m_eObjectList.size() != 0) { + EWOL_ERROR("Have " << m_eObjectList.size() << " active Object"); + } + m_eObjectList.clear(); +} + +void ewol::object::Manager::add(const ewol::ObjectShared& _object) { + ethread::RecursiveLock lock(m_mutex); + if (_object == null) { + EWOL_ERROR("try to add an inexistant Object in manager"); + } + m_eObjectList.pushBack(_object); +} + +int32_t ewol::object::Manager::getNumberObject() { + ethread::RecursiveLock lock(m_mutex); + return m_eObjectList.size(); +} + +// clean all Object that request an autoRemove ... +void ewol::object::Manager::cleanInternalRemoved() { + ethread::RecursiveLock lock(m_mutex); + size_t nbObject = m_eObjectList.size(); + EWOL_VERBOSE("Clean Object List (if needed) : " << m_eObjectList.size() << " elements"); + auto it(m_eObjectList.begin()); + while (it != m_eObjectList.end()) { + if (it->expired() == true) { + it = m_eObjectList.erase(it); + } else { + ++it; + } + } + if (m_eObjectList.size() != nbObject) { + EWOL_VERBOSE(" remove " << nbObject - m_eObjectList.size() << " deprecated objects"); + } +} + +ewol::ObjectShared ewol::object::Manager::get(const etk::String& _name) { + ethread::RecursiveLock lock(m_mutex); + if (_name == "") { + return null; + } + for (auto &it : m_eObjectList) { + ewol::ObjectShared element = it.lock(); + if ( element != null + && element->propertyName.get() == _name) { + return element; + } + } + return null; +} + + +ewol::ObjectShared ewol::object::Manager::getObjectNamed(const etk::String& _name) { + ethread::RecursiveLock lock(m_mutex); + return ewol::object::Manager::get(_name); +} + + +void ewol::object::Manager::workerAdd(const ewol::ObjectShared& _worker) { + ethread::RecursiveLock lock(m_mutex); + m_workerList.pushBack(_worker); +} + +void ewol::object::Manager::workerRemove(const ewol::ObjectShared& _worker) { + ethread::RecursiveLock lock(m_mutex); + auto it(m_workerList.begin()); + while (it != m_workerList.end()) { + if (*it == _worker) { + it = m_workerList.erase(it); + } else { + ++it; + } + } +} + +void ewol::object::Manager::timeCall(const echrono::Clock& _localTime) { + ethread::RecursiveLock lock(m_mutex); + echrono::Clock previousTime = m_lastPeriodicCallTime; + m_lastPeriodicCallTime = _localTime; + if (periodicCall.size() <= 0) { + return; + } + echrono::Duration deltaTime = _localTime - previousTime; + ewol::event::Time myTime(_localTime, m_applWakeUpTime, deltaTime, deltaTime); + periodicCall.emit(myTime); +} + +void ewol::object::Manager::timeCallResume(const echrono::Clock& _localTime) { + ethread::RecursiveLock lock(m_mutex); + m_lastPeriodicCallTime = _localTime; +} + +bool ewol::object::Manager::timeCallHave() { + ethread::RecursiveLock lock(m_mutex); + return periodicCall.size() > 0; +} diff --git a/src/org/atriasoft/ewol/object/Manager.java b/src/org/atriasoft/ewol/object/Manager.java new file mode 100644 index 0000000..14c755f --- /dev/null +++ b/src/org/atriasoft/ewol/object/Manager.java @@ -0,0 +1,105 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + class Context; + namespace object { + class Manager : public esignal::Interface { + protected: + ethread::MutexRecursive m_mutex; + private: + etk::Vector m_eObjectList; // all widget allocated == > all time increment ... never removed ... + Context& m_context; + public: + Manager(Context& _context); + virtual ~Manager(); + /** + * @brief remove all resources (un-init) out of the destructor (due to the system implementation) + */ + void unInit(); + /** + * @brief Get the number of loaded object in the system + * @return number of Object + */ + int32_t getNumberObject(); + /** + * @brief Display all object Open. + */ + void displayListObject(); + private: + //! @not_in_doc + friend class ewol::Object; + /** + * @brief Internal API that used only with Object toi reference itself in the manager. + * @note The manager remove the object when the refecence Low down 1 (last keeper) + * @param[in] _object Reference shared pointer on the object + */ + void add(const ewol::ObjectShared& _object); + public: + /** + * @brief clean the weak pointer list (remove weak_ptr that is remoed) + */ + void cleanInternalRemoved(); + /** + * @brief Retrive an Object with his name + * @param[in] _name Name of the Object + * @return Pointer on the finded Object. + */ + ewol::ObjectShared get(const etk::String& _name); + public: + /** + * @brief retrive an object with his name + * @param[in] _name Name of the object + * @return the requested object or null + */ + ewol::ObjectShared getObjectNamed(const etk::String& _name); + private: + etk::Vector m_workerList; + public: + /** + * @brief Add a worker on the system list. + * @param[in] _worker Worker to add in the list. + */ + void workerAdd(const ewol::ObjectShared& _worker); + /** + * @brief Remove a worker on the system list. + * @param[in] _worker Worker to add in the list. + */ + void workerRemove(const ewol::ObjectShared& _worker); + public: + esignal::Signal periodicCall; + private: + echrono::Clock m_applWakeUpTime; //!< Time of the application initialize + echrono::Clock m_lastPeriodicCallTime; //!< last call time ... + public: // ewol system internal : + /** + * @brief Call every time we can with the current time + * @param[in] _localTime Current system Time. + */ + void timeCall(const echrono::Clock& _localTime); + /** + * @brief If the application is suspended The Ewol Object manager does not know it, just call this to update delta call + * @param[in] _localTime Current system Time. + */ + void timeCallResume(const echrono::Clock& _localTime); + /** + * @breif check if the Interface have some user that request a periodic call + * @return true, have some periodic event... + */ + bool timeCallHave(); + + }; + }; +}; diff --git a/src/org/atriasoft/ewol/object/Object.cpp b/src/org/atriasoft/ewol/object/Object.cpp new file mode 100644 index 0000000..442a1c8 --- /dev/null +++ b/src/org/atriasoft/ewol/object/Object.cpp @@ -0,0 +1,186 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::Object); + +size_t ewol::Object::m_valUID = 0; + +void ewol::Object::autoDestroy() { + if (m_objectHasBeenInit == false) { + EWOL_WARNING("try to auto destroy inside a constructor"); + return; + } + EWOL_VERBOSE("Destroy object: [" << getId() << "] type:" << getObjectType()); + ewol::ObjectShared parent = m_parent.lock(); + // TODO : set a signal to do this ... + if (parent != null) { + EWOL_VERBOSE("Destroy object: Call parrent"); + parent->requestDestroyFromChild(sharedFromThis()); + } + //if no parent ==> noting to do ... + m_destroy = true; +} + +bool ewol::Object::objectHasBeenCorectlyInit() { + return m_objectHasBeenInit; +} + +void ewol::Object::requestDestroyFromChild(const ewol::ObjectShared& _child) { + EWOL_INFO("requestDestroyFromChild(...) is called when an object reference as a parent have a child that request quto-destroy ..."); + EWOL_CRITICAL("Call From Child with no effects ==> must implement : requestDestroyFromChild(...)"); +} + +void ewol::Object::destroy() { + autoDestroy(); +} + +bool ewol::Object::isDestroyed() const { + return m_destroy; +} + +void ewol::Object::setParent(const ewol::ObjectShared& _newParent) { + // TODO : Implement change of parent ... + m_parent = _newParent; +} + +void ewol::Object::removeParent() { + m_parent.reset(); +} + +ewol::Object::Object() : + propertyName(this, "name", "", "Object name, might be a unique reference in all the program"), + m_objectHasBeenInit(false), + m_destroy(false), + m_static(false), + m_isResource(false) { + // note this is nearly atomic ... (but it is enough) + m_uniqueId = m_valUID++; + EWOL_DEBUG("new Object : [" << m_uniqueId << "]"); +} + +ewol::Object::~Object() { + EWOL_DEBUG("delete Object : [" << m_uniqueId << "] : " << getTypeDescription()); + m_uniqueId = -1; +} + + +void ewol::Object::init() { + getObjectManager().add(sharedFromThis()); + //parameterDisplay(); + m_objectHasBeenInit = true; +} + +const char * const ewol::Object::getObjectType() const { + if (m_listType.size() == 0) { + return "ewol::Object"; + } + return m_listType.back(); +} + +void ewol::Object::addObjectType(const char* _type) { + if (_type == null) { + EWOL_ERROR(" try to add a type with no value..."); + return; + } + m_listType.pushBack(_type); +} +etk::String ewol::Object::getTypeDescription() const { + etk::String ret("ewol::Object"); + for(auto element : m_listType) { + ret += "|"; + ret += element; + } + return ret; +} + +bool ewol::Object::isTypeCompatible(const etk::String& _type) const { + if (_type == "ewol::Object") { + return true; + } + for(auto element : m_listType) { + if (_type == element) { + return true; + } + } + return false; +} + +bool ewol::Object::loadXMLAttributes(const exml::Element& _node) { + if (_node.exist() == false) { + return false; + } + bool errorOccured = false; + + for(const auto it : _node.attributes) { + auto pair = it.getPair(); + if (pair.first == "") { + continue; + } + if (properties.set(pair.first, pair.second) == false) { + errorOccured = true; + } + } + return errorOccured; +} + +bool ewol::Object::loadXML(const exml::Element& _node) { + return true; //loadXMLAttributes(_node); +} + +bool ewol::Object::storeXML(exml::Element& _node) const { + if (_node.exist() == false) { + return false; + } + bool errorOccured = true; + for (auto &it : properties.getAll(true)) { + _node.attributes.set(it.first, it.second); + } + return errorOccured; +} + +bool ewol::Object::propertySetOnWidgetNamed(const etk::String& _objectName, const etk::String& _config, const etk::String& _value) { + ewol::ObjectShared object = getObjectManager().get(_objectName); + if (object == null) { + return false; + } + return object->properties.set(_config, _value); +} + +ewol::object::Manager& ewol::Object::getObjectManager() { + ewol::object::Manager& tmp = ewol::getContext().getEObjectManager(); + return tmp; +} + +ewol::Context& ewol::Object::getContext() { + return ewol::getContext(); +} + +ewol::ObjectShared ewol::Object::getObjectNamed(const etk::String& _objectName) { + return getObjectManager().getObjectNamed(_objectName); +} + +ewol::ObjectShared ewol::Object::getSubObjectNamed(const etk::String& _objectName) { + EWOL_VERBOSE("check if name : " << _objectName << " ?= " << propertyName.get()); + if (_objectName == propertyName.get()) { + return sharedFromThis(); + } + return null; +} + + +bool ewol::propertySetOnObjectNamed(const etk::String& _objectName, const etk::String& _config, const etk::String& _value) { + ewol::ObjectShared object = ewol::getContext().getEObjectManager().get(_objectName); + if (object == null) { + return false; + } + return object->properties.set(_config, _value); +} + diff --git a/src/org/atriasoft/ewol/object/Object.java b/src/org/atriasoft/ewol/object/Object.java new file mode 100644 index 0000000..7c41a1e --- /dev/null +++ b/src/org/atriasoft/ewol/object/Object.java @@ -0,0 +1,339 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace ewol { + // some class need to define element befor other ... + class Object; + namespace object { + class Manager; + } + class Context; +} + +template static void baseInit(const ememory::SharedPtr& _object) { + // end of recurtion + return; +} + +template static void baseInit(const ememory::SharedPtr& _object, const etk::String& _name, const TYPE_VAL& _val, TYPE&& ... _all ) { + eproperty::Property* prop(null); + eproperty::PropertyType* propType(null); + if (_object == null) { + EWOL_ERROR("EMPTY pointer"); + return; + } + prop = _object->properties.getRaw(_name); + if (prop == null) { + EWOL_ERROR("property does not exit ... '" << _name << "'"); + goto exit_on_error; + } + propType = dynamic_cast*>(prop); + if (propType == null) { + EWOL_ERROR("property does not cast in requested type ... '" << _name << "' require type : " << /*typeid(_val).name()*/ "?TODO?" << "' instead of '" << prop->getType() << "'"); + goto exit_on_error; + } + propType->setDirectCheck(_val); +exit_on_error: + baseInit(_object, etk::forward(_all)... ); + return; +} + +#define UN_DECLARE_FACTORY(className) \ + template static ememory::SharedPtr create(const EWOL_FACTORY_CREATE_TYPE& ... _all) = delete; + +#define DECLARE_FACTORY(className) \ + template static ememory::SharedPtr create(const EWOL_FACTORY_CREATE_TYPE& ... _all) { \ + ememory::SharedPtr object(ETK_NEW(className)); \ + if (object == null) { \ + EWOL_ERROR("Factory error"); \ + return null; \ + } \ + baseInit(object, _all... ); \ + object->init(); \ + if (object->objectHasBeenCorectlyInit() == false) { \ + EWOL_CRITICAL("Object Is not correctly init : " << #className ); \ + } \ + return object; \ + } \ + static ememory::SharedPtr createXml(const exml::Element& _node) { \ + ememory::SharedPtr object(ETK_NEW(className)); \ + if (object == null) { \ + EWOL_ERROR("Factory error"); \ + return null; \ + } \ + object->loadXMLAttributes(_node); \ + object->init(); \ + if (object->objectHasBeenCorectlyInit() == false) { \ + EWOL_CRITICAL("Object Is not correctly init : " << #className ); \ + } \ + return object; \ + } + +#define DECLARE_SINGLE_FACTORY(className, uniqueName) \ + template static ememory::SharedPtr create(const EWOL_FACTORY_CREATE_TYPE& ... _all) { \ + ememory::SharedPtr object; \ + ememory::SharedPtr object2 = getObjectNamed(uniqueName); \ + if (object2 != null) { \ + object = ememory::dynamicPointerCast(object2); \ + if (object == null) { \ + EWOL_CRITICAL("Request object element: '" << uniqueName << "' With the wrong type (dynamic cast error)"); \ + return null; \ + } \ + } \ + if (object != null) { \ + return object; \ + } \ + object = ememory::SharedPtr(ETK_NEW(className)); \ + if (object == null) { \ + EWOL_ERROR("Factory error"); \ + return null; \ + } \ + baseInit(object, "name", etk::String(uniqueName), _all... ); \ + object->init(); \ + if (object->objectHasBeenCorectlyInit() == false) { \ + EWOL_CRITICAL("Object Is not correctly init : " << #className ); \ + } \ + return object; \ + } + +namespace ewol { + using ObjectShared = ememory::SharedPtr; + using ObjectWeak = ememory::WeakPtr; + /** + * @brief Basic message classes for ewol system + * this class mermit at every Object to communicate between them. + */ + class Object : public ememory::EnableSharedFromThis, + public eproperty::Interface, + public esignal::Interface { + public: // Event list + + public: // propertie list + eproperty::Value propertyName; //!< name of the element ... + private: + static size_t m_valUID; //!< Static used for the unique ID definition + private: + bool m_objectHasBeenInit; //!< Know if the init function has bben called + public: + /** + * @brief Destructor + */ + virtual ~Object(); + protected: + /** + * @brief Constructor. + */ + Object(); + virtual void init(); + public: + /** + * @brief Factory + */ + DECLARE_FACTORY(Object); + bool objectHasBeenCorectlyInit(); + protected: + ewol::ObjectWeak m_parent; //!< Reference on the current parrent. + bool m_destroy; //!< Flag to know if the object is requesting has destroy. + protected: + /** + * @brief Auto-destroy the object + */ + virtual void autoDestroy(); + public: + /** + * @brief Destroy the current object + */ + virtual void destroy(); + /** + * @brief Check if the current objetc his destroy (in removing) + * @return true The object is removed + * @return false The object is not removed + */ + bool isDestroyed() const; + protected: + /** + * @brief Called by a whild that want to remove pointer of itself from the current list of his parrent + * @param[in] _child Object of the child that want to remove itself + */ + virtual void requestDestroyFromChild(const ewol::ObjectShared& _child); + public: + /** + * @brief Set the Object has new parrent. + * @param[in] _newParent Object that requesting the parenting + */ + virtual void setParent(const ewol::ObjectShared& _newParent); + /** + * @brief Remove the current parenting. + */ + virtual void removeParent(); + private: + etk::Vector m_listType; + public: + /** + * @brief get the current Object type of the Object + * @return the last type name of the element + */ + const char * const getObjectType() const; + /** + * @brief Get the herarchie of the Object type. + * @return descriptive string. + */ + etk::String getTypeDescription() const; + /** + * @brief check if the element herited from a specific type + * @param[in] _type Type to check. + * @return true if the element is compatible. + */ + bool isTypeCompatible(const etk::String& _type) const; + protected: + /** + * @brief Add a type of the list of Object. + * @param[in] _type new type to add. + */ + void addObjectType(const char* _type); + protected: + bool m_static; //!< set this variable at true if this element must not be auto destroy (exemple : use static object) + public: + /** + * @brief get the static status of the Object == > mark at true if the user set the object mark as static allocated element ==> not auto remove element + * @return true if it might not be removed == > usefull for conficuration class + */ + bool getStatic(){ + return m_static; + }; + private: + int32_t m_uniqueId; //!< Object UniqueID == > TODO : Check if it use is needed + public: + /** + * @brief get the UniqueId of the Object + * @return the requested ID + */ + int32_t getId(){ + return m_uniqueId; + }; + public: + // TODO : Rework the position on this function ... This is a convignent function ... + bool propertySetOnWidgetNamed(const etk::String& _objectName, const etk::String& _config, const etk::String& _value); + public: + /** + * @brief load attribute properties with an XML node. + * @param[in] _node Reference on the XML node. + * @return true : All has been done corectly. + * @return false : An error occured. + */ + bool loadXMLAttributes(const exml::Element& _node); + /** + * @brief load properties with an XML node. + * @param[in] _node Reference on the XML node. + * @return true : All has been done corectly. + * @return false : An error occured. + */ + virtual bool loadXML(const exml::Element& _node); + /** + * @brief store properties in this XML node. + * @param[in,out] _node Reference on the XML node. + * @return true : All has been done corectly. + * @return false : An error occured. + */ + virtual bool storeXML(exml::Element& _node) const; + public: + /** + * @breif get the current Object manager. + * @return the requested object manager. + */ + static ewol::object::Manager& getObjectManager(); + /** + * @brief get the curent the system inteface. + * @return current reference on the instance. + */ + static ewol::Context& getContext(); + private: + bool m_isResource; //!< enable this when you want to declare this element is auto-remove + public: + /** + * @brief Declare this element as a resource (or singleton) this mean the element will + * not be auto Remove at the end of the programm. It just notify that it is not removed. + * @param[in] _val Value of the type of the element. + */ + void setStatusResource(bool _val) { + m_isResource = _val; + } + /** + * @brief Get the resource status of the element. + * @return the resource status. + */ + bool getStatusResource() const { + return m_isResource; + } + /** + * @brief Retrive an object with his name (in the global list) + * @param[in] _name Name of the object + * @return the requested object or null + */ + static ewol::ObjectShared getObjectNamed(const etk::String& _objectName); + /** + * @brief Retrive an object with his name (in the global list) + * @param[in] _name Name of the object + * @return the requested object or null + */ + virtual ewol::ObjectShared getSubObjectNamed(const etk::String& _objectName); + protected: + // TODO : Create a template ... + /** + * @brief link on an signal in the subwiget with his name + */ + #define subBind(_type, _name, _event, _shared_ptr, _func, ...) do {\ + ememory::SharedPtr<_type> myObject = ememory::dynamicPointerCast<_type>(getSubObjectNamed(_name)); \ + if (myObject != null) { \ + myObject->_event.connect(_shared_ptr, _func, ##__VA_ARGS__); \ + } else { \ + EWOL_ERROR("object named='" << _name << "' not exit or can not be cast in : " << #_type); \ + } \ + } while (false) + }; + bool propertySetOnObjectNamed(const etk::String& _objectName, const etk::String& _config, const etk::String& _value); +}; + +/** + * @brief link on an signal in the global object list with his name + */ +#define globalBind(_type, _name, _event, _obj, _func, ...) do {\ + ememory::SharedPtr<_type> myObject = ememory::dynamicPointerCast<_type>(ewol::getContext().getEObjectManager().getObjectNamed(_name)); \ + if (myObject != null) { \ + myObject->_event.connect(_obj, _func, ##__VA_ARGS__); \ + } else { \ + EWOL_ERROR("object named='" << _name << "' not exit or can not be cast in : " << #_type); \ + } \ +} while (false) + +/** + * @brief link on an signal in the subWidget of an object with his name + */ +#define externSubBind(_object, _type, _name, _event, _obj, _func, ...) do {\ + ememory::SharedPtr<_type> myObject = ememory::dynamicPointerCast<_type>(_object->getObjectNamed(_name)); \ + if (myObject != null) { \ + myObject->_event.connect(_obj, _func, ##__VA_ARGS__); \ + } else { \ + EWOL_ERROR("object named='" << _name << "' not exit or can not be cast in : " << #_type); \ + } \ +} while (false) + diff --git a/src/org/atriasoft/ewol/object/Worker.cpp b/src/org/atriasoft/ewol/object/Worker.cpp new file mode 100644 index 0000000..6a148cb --- /dev/null +++ b/src/org/atriasoft/ewol/object/Worker.cpp @@ -0,0 +1,29 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::object::Worker); + +ewol::object::Worker::Worker() { + addObjectType("ewol::Worker"); +} + +void ewol::object::Worker::init() { + ewol::Object::init(); + getObjectManager().workerAdd(sharedFromThis()); +} + +ewol::object::Worker::~Worker() { + // nothing to do ... +} + +void ewol::object::Worker::destroy() { + ewol::Object::destroy(); + getObjectManager().workerRemove(sharedFromThis()); +} diff --git a/src/org/atriasoft/ewol/object/Worker.java b/src/org/atriasoft/ewol/object/Worker.java new file mode 100644 index 0000000..ca0fd0f --- /dev/null +++ b/src/org/atriasoft/ewol/object/Worker.java @@ -0,0 +1,39 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ewol { + namespace object { + class Worker; + using WorkerShared = ememory::SharedPtr; + using WorkerWeak = ememory::WeakPtr; + /** + * @brief A worker might not been possesed by someone, then the system might keep a pointer on it. + */ + class Worker : public ewol::Object { + protected: + /** + * @brief Constructor. + */ + Worker(); + void init() override; + public: + /** + * @brief Factory + */ + DECLARE_FACTORY(Worker); + /** + * @brief Destructor + */ + virtual ~Worker(); + public: + void destroy() override; + }; + } +} diff --git a/src/org/atriasoft/ewol/resource/ColorFile.cpp b/src/org/atriasoft/ewol/resource/ColorFile.cpp new file mode 100644 index 0000000..cbd5afd --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ColorFile.cpp @@ -0,0 +1,86 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::resource::ColorFile); + +ewol::resource::ColorFile::ColorFile() : + gale::Resource(), + // Set the list unodered + m_list(0, false), + m_errorColor(etk::color::orange) { + addResourceType("ewol::ColorFile"); +} + +void ewol::resource::ColorFile::init(const etk::Uri& _uri) { + ethread::RecursiveLock lock(m_mutex); + gale::Resource::init(_uri.get()); + EWOL_DEBUG("CF : load \"" << _uri << "\""); + reload(); + EWOL_DEBUG("List of all color : " << m_list.getKeys()); +} + +ewol::resource::ColorFile::~ColorFile() { + // remove all element + m_list.clear(); +} + + +void ewol::resource::ColorFile::reload() { + ethread::RecursiveLock lock(m_mutex); + // remove all previous set of value : + for (size_t iii = 0; iii < m_list.size() ; ++iii) { + m_list.getValue(iii) = m_errorColor; + } + // open and read all json elements: + ejson::Document doc; + if (doc.load(etk::Uri(m_name)) == false) { + EWOL_ERROR("Can not load file : '" << m_name << "'"); + return; + } + ejson::Array baseArray = doc["color"].toArray(); + if (baseArray.exist() == false) { + EWOL_ERROR("Can not get basic array : 'color' in file:" << m_name); + doc.display(); + return; + } + bool findError = false; + for (const auto it : baseArray) { + ejson::Object tmpObj = it.toObject(); + if (tmpObj.exist() == false) { + EWOL_ERROR(" can not get object in 'color' : " << it); + findError = true; + continue; + } + etk::String name = tmpObj["name"].toString().get(); + etk::String color = tmpObj["color"].toString().get(m_errorColor.getHexString()); + EWOL_DEBUG("find new color : '" << name << "' color='" << color << "'"); + if (name.size() == 0) { + EWOL_ERROR("Drop an empty name"); + findError = true; + continue; + } + m_list.add(name, etk::Color(color)); + } + if (findError == true) { + EWOL_ERROR("pb in parsing file:" << m_name); + doc.display(); + } +} + + +int32_t ewol::resource::ColorFile::request(const etk::String& _paramName) { + ethread::RecursiveLock lock(m_mutex); + // check if the parameters existed : + if (m_list.exist(_paramName) == false) { + m_list.add(_paramName, m_errorColor); + } + return m_list.getId(_paramName); +} diff --git a/src/org/atriasoft/ewol/resource/ColorFile.java b/src/org/atriasoft/ewol/resource/ColorFile.java new file mode 100644 index 0000000..f8c2367 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ColorFile.java @@ -0,0 +1,73 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace ewol { + namespace resource { + /** + * @brief ColorFile is a Resource designed to be specific with the theme (for example black, or white or orange ...) + */ + class ColorFile : public gale::Resource { + private: + etk::Map > m_list; //!< List of all color in the file + etk::Color m_errorColor; //!< Error returned color + protected: + /** + * @brief Constructor of the color property file + * @param[in] _uri Name of the file needed + */ + ColorFile(); + void init(const etk::Uri& _uri); + public: + DECLARE_RESOURCE_URI_FACTORY(ColorFile); + /** + * @brief Simple Destructor of this class (nothing specific ...) + */ + virtual ~ColorFile(); + public: + /** + * @brief Set the error color. + * @param[in] _errorColor Color that might be set when not finding a color + */ + void setErrorColor(const etk::Color& _errorColor) { + m_errorColor = _errorColor; + } + /** + * @brief Request the presence of a specific color. + * @param[in] _paramName Name of the color. + * @return A unique ID of the color (or -1 if an error occured). + */ + int32_t request(const etk::String& _paramName); + /** + * @brief Get the associated color of the ID. + * @param[in] _Id Id of the color. + * @return The requested color. + */ + const etk::Color& get(int32_t _id) const { + if (_id < 0) { + return m_errorColor; + } + return m_list.getValue(_id); + }; + /** + * @brief Get All color name + * @return list of all color existing + */ + etk::Vector getColors() const { + return m_list.getKeys(); + } + public: // herited function: + void reload(); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/resource/Colored3DObject.cpp b/src/org/atriasoft/ewol/resource/Colored3DObject.cpp new file mode 100644 index 0000000..692147a --- /dev/null +++ b/src/org/atriasoft/ewol/resource/Colored3DObject.cpp @@ -0,0 +1,527 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#ifndef __TARGET_OS__Web + +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::resource::Colored3DObject); + +ewol::resource::Colored3DObject::Colored3DObject() : + m_GLprogram(null) { + addResourceType("ewol::Colored3DObject"); +} + +void ewol::resource::Colored3DObject::init() { + gale::Resource::init(); + // get the shader resource : + m_GLPosition = 0; + m_GLprogram = gale::resource::Program::create("DATA:///simple3D.prog?lib=ewol"); + if (m_GLprogram != null) { + m_GLPosition = m_GLprogram->getAttribute("EW_coord3d"); + m_GLColor = m_GLprogram->getUniform("EW_color"); + m_GLMatrix = m_GLprogram->getUniform("EW_MatrixTransformation"); + } +} + +ewol::resource::Colored3DObject::~Colored3DObject() { + +} + + +void ewol::resource::Colored3DObject::draw(const etk::Vector& _vertices, + const etk::Color& _color, + bool _updateDepthBuffer, + bool _depthtest) { + if (_vertices.size() <= 0) { + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + if (true == _depthtest) { + gale::openGL::enable(gale::openGL::flag_depthTest); + if (false == _updateDepthBuffer) { + glDepthMask(GL_FALSE); + } + } + //EWOL_DEBUG(" display " << m_coord.size() << " elements" ); + m_GLprogram->use(); + // set Matrix: translation/positionMatrix + mat4 projMatrix = gale::openGL::getMatrix(); + mat4 camMatrix = gale::openGL::getCameraMatrix(); + mat4 tmpMatrix = projMatrix * camMatrix; + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // position : + m_GLprogram->sendAttribute(m_GLPosition, 3/*x,y,z,unused*/, &_vertices[0], 4*sizeof(float)); + // color : + m_GLprogram->uniform4fv(m_GLColor, 1/*r,g,b,a*/, (float*)&_color); + // Request the draw od the elements: + gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, _vertices.size()); + m_GLprogram->unUse(); + // Request the draw od the elements: + //glDrawArrays(GL_LINES, 0, vertices.size()); + //m_GLprogram->UnUse(); + if (true == _depthtest) { + if (false == _updateDepthBuffer) { + glDepthMask(GL_TRUE); + } + gale::openGL::disable(gale::openGL::flag_depthTest); + } +} + +void ewol::resource::Colored3DObject::draw(const etk::Vector& _vertices, + const etk::Color& _color, + mat4& _transformationMatrix, + bool _updateDepthBuffer, + bool _depthtest) { + if (_vertices.size() <= 0) { + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + if (true == _depthtest) { + gale::openGL::enable(gale::openGL::flag_depthTest); + if (false == _updateDepthBuffer) { + glDepthMask(GL_FALSE); + } + } + //EWOL_DEBUG(" display " << m_coord.size() << " elements" ); + m_GLprogram->use(); + // set Matrix: translation/positionMatrix + mat4 projMatrix = gale::openGL::getMatrix(); + mat4 camMatrix = gale::openGL::getCameraMatrix(); + mat4 tmpMatrix = projMatrix * camMatrix * _transformationMatrix; + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // position : + m_GLprogram->sendAttribute(m_GLPosition, 3/*x,y,z*/, &_vertices[0], 4*sizeof(float)); + // color : + m_GLprogram->uniform4fv(m_GLColor, 1/*r,g,b,a*/, (float*)&_color); + // Request the draw od the elements: + gale::openGL::drawArrays(gale::openGL::renderMode::triangle, 0, _vertices.size()); + m_GLprogram->unUse(); + if (true == _depthtest) { + if (false == _updateDepthBuffer) { + glDepthMask(GL_TRUE); + } + gale::openGL::disable(gale::openGL::flag_depthTest); + } +} + +void ewol::resource::Colored3DObject::drawLine(etk::Vector& _vertices, + const etk::Color& _color, + mat4& _transformationMatrix, + bool _updateDepthBuffer, + bool _depthtest) { + if (_vertices.size() <= 0) { + return; + } + if (m_GLprogram == null) { + EWOL_ERROR("No shader ..."); + return; + } + if (true == _depthtest) { + gale::openGL::enable(gale::openGL::flag_depthTest); + if (false == _updateDepthBuffer) { + glDepthMask(GL_FALSE); + } + } + //EWOL_DEBUG(" display " << m_coord.size() << " elements" ); + m_GLprogram->use(); + // set Matrix: translation/positionMatrix + mat4 projMatrix = gale::openGL::getMatrix(); + mat4 camMatrix = gale::openGL::getCameraMatrix(); + mat4 tmpMatrix = projMatrix * camMatrix * _transformationMatrix; + m_GLprogram->uniformMatrix(m_GLMatrix, tmpMatrix); + // position : + m_GLprogram->sendAttribute(m_GLPosition, 3/*x,y,z*/, &_vertices[0], 4*sizeof(float)); + // color : + m_GLprogram->uniform4fv(m_GLColor, 1/*r,g,b,a*/, (float*)&_color); + // Request the draw od the elements: + gale::openGL::drawArrays(gale::openGL::renderMode::line, 0, _vertices.size()); + m_GLprogram->unUse(); + if (true == _depthtest) { + if (false == _updateDepthBuffer) { + glDepthMask(GL_TRUE); + } + gale::openGL::disable(gale::openGL::flag_depthTest); + } +} + + +void ewol::resource::Colored3DObject::drawCubeLine(const vec3& _min, + const vec3& _max, + const etk::Color& _color, + mat4& _transformationMatrix, + bool _updateDepthBuffer, + bool _depthtest) { + etk::Vector vertices; + vertices.pushBack(vec3(_min.x(), _min.y(),_min.z())); + vertices.pushBack(vec3(_max.x(), _min.y(),_min.z())); + + vertices.pushBack(vec3(_max.x(), _min.y(),_min.z())); + vertices.pushBack(vec3(_max.x(), _min.y(),_max.z())); + + vertices.pushBack(vec3(_max.x(), _min.y(),_max.z())); + vertices.pushBack(vec3(_min.x(), _min.y(),_max.z())); + + vertices.pushBack(vec3(_min.x(), _min.y(),_max.z())); + vertices.pushBack(vec3(_min.x(), _min.y(),_min.z())); + + + vertices.pushBack(vec3(_min.x(), _max.y(),_min.z())); + vertices.pushBack(vec3(_max.x(), _max.y(),_min.z())); + + vertices.pushBack(vec3(_max.x(), _max.y(),_min.z())); + vertices.pushBack(vec3(_max.x(), _max.y(),_max.z())); + + vertices.pushBack(vec3(_max.x(), _max.y(),_max.z())); + vertices.pushBack(vec3(_min.x(), _max.y(),_max.z())); + + vertices.pushBack(vec3(_min.x(), _max.y(),_max.z())); + vertices.pushBack(vec3(_min.x(), _max.y(),_min.z())); + + + vertices.pushBack(vec3(_min.x(), _min.y(),_min.z())); + vertices.pushBack(vec3(_min.x(), _max.y(),_min.z())); + + vertices.pushBack(vec3(_max.x(), _min.y(),_min.z())); + vertices.pushBack(vec3(_max.x(), _max.y(),_min.z())); + + vertices.pushBack(vec3(_max.x(), _min.y(),_max.z())); + vertices.pushBack(vec3(_max.x(), _max.y(),_max.z())); + + vertices.pushBack(vec3(_min.x(), _min.y(),_max.z())); + vertices.pushBack(vec3(_min.x(), _max.y(),_max.z())); + + drawLine(vertices, _color, _transformationMatrix, _updateDepthBuffer, _depthtest); +} + +void ewol::resource::Colored3DObject::drawSquare(const vec3& _size, + mat4& _transformationMatrix, + const etk::Color& _tmpColor) { + etk::Vector tmpVertices; + static int indices[36] = { 0,1,2, 3,2,1, 4,0,6, + 6,0,2, 5,1,4, 4,1,0, + 7,3,1, 7,1,5, 5,4,7, + 7,4,6, 7,2,3, 7,6,2}; + vec3 vertices[8]={ vec3(_size[0],_size[1],_size[2]), + vec3(-_size[0],_size[1],_size[2]), + vec3(_size[0],-_size[1],_size[2]), + vec3(-_size[0],-_size[1],_size[2]), + vec3(_size[0],_size[1],-_size[2]), + vec3(-_size[0],_size[1],-_size[2]), + vec3(_size[0],-_size[1],-_size[2]), + vec3(-_size[0],-_size[1],-_size[2])}; + tmpVertices.clear(); + for (int32_t iii=0 ; iii<36 ; iii+=3) { + // normal calculation : + //btVector3 normal = (vertices[indices[iii+2]]-vertices[indices[iii]]).cross(vertices[indices[iii+1]]-vertices[indices[iii]]); + //normal.normalize (); + tmpVertices.pushBack(vertices[indices[iii]]); + tmpVertices.pushBack(vertices[indices[iii+1]]); + tmpVertices.pushBack(vertices[indices[iii+2]]); + } + draw(tmpVertices, _tmpColor, _transformationMatrix); +} + +void ewol::resource::Colored3DObject::drawSphere(float _radius, + int _lats, + int _longs, + mat4& _transformationMatrix, + const etk::Color& _tmpColor) { + etk::Vector tmpVertices; + for(int32_t iii=0; iii<=_lats; ++iii) { + float lat0 = M_PI * (-0.5f + float(iii - 1) / _lats); + float z0 = _radius*sin(lat0); + float zr0 = _radius*cos(lat0); + + float lat1 = M_PI * (-0.5f + float(iii) / _lats); + float z1 = _radius*sin(lat1); + float zr1 = _radius*cos(lat1); + + for(int32_t jjj=0; jjj<_longs; ++jjj) { + float lng = 2.0f * M_PI * float(jjj - 1) / _longs; + float x = cos(lng); + float y = sin(lng); + vec3 v1 = vec3(x * zr1, y * zr1, z1); + vec3 v4 = vec3(x * zr0, y * zr0, z0); + + lng = 2 * M_PI * float(jjj) / _longs; + x = cos(lng); + y = sin(lng); + vec3 v2 = vec3(x * zr1, y * zr1, z1); + vec3 v3 = vec3(x * zr0, y * zr0, z0); + + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v2); + tmpVertices.pushBack(v3); + + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v3); + tmpVertices.pushBack(v4); + } + } + draw(tmpVertices, _tmpColor, _transformationMatrix); +} +void ewol::resource::Colored3DObject::drawCylinder(float _radius, + float _size, + int _lats, + int _longs, + mat4& _transformationMatrix, + const etk::Color& _tmpColor) { + etk::Vector tmpVertices; + // center to border (TOP) + + // center to border (TOP) + for(int32_t jjj=0; jjj<_longs; ++jjj) { + float lng = 2.0f * M_PI * float(jjj - 1) / _longs; + + float z = _size*0.5f; + vec3 v1 = vec3(0.0f, 0.0f, z); + + float x = cos(lng)*_radius; + float y = sin(lng)*_radius; + vec3 v2 = vec3(x, y, z); + + lng = 2.0f * M_PI * float(jjj) / _longs; + x = cos(lng)*_radius; + y = sin(lng)*_radius; + vec3 v3 = vec3(x, y, z); + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v3); + tmpVertices.pushBack(v2); + } + // Cylinder + for(int32_t jjj=0; jjj<_longs; ++jjj) { + float lng = 2.0f * M_PI * float(jjj - 1) / _longs; + + float z = _size*0.5f; + + float x = cos(lng)*_radius; + float y = sin(lng)*_radius; + vec3 v2 = vec3(x, y, z); + vec3 v2b = vec3(x, y, -z); + + lng = 2.0f * M_PI * float(jjj) / _longs; + x = cos(lng)*_radius; + y = sin(lng)*_radius; + vec3 v3 = vec3(x, y, z); + vec3 v3b = vec3(x, y, -z); + + tmpVertices.pushBack(v2); + tmpVertices.pushBack(v3); + tmpVertices.pushBack(v3b); + + tmpVertices.pushBack(v2); + tmpVertices.pushBack(v3b); + tmpVertices.pushBack(v2b); + } + // center to border (BUTTOM) + for(int32_t jjj=0; jjj<_longs; ++jjj) { + float lng = 2.0f * M_PI * float(jjj - 1) / _longs; + + float z = _size*-0.5f; + vec3 v1 = vec3(0.0f, 0.0f, z); + + float x = cos(lng)*_radius; + float y = sin(lng)*_radius; + vec3 v2 = vec3(x, y, z); + + lng = 2.0f * M_PI * float(jjj) / _longs; + x = cos(lng)*_radius; + y = sin(lng)*_radius; + vec3 v3 = vec3(x, y, z); + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v2); + tmpVertices.pushBack(v3); + } + draw(tmpVertices, _tmpColor, _transformationMatrix); +} +void ewol::resource::Colored3DObject::drawCapsule(float _radius, + float _size, + int _lats, + int _longs, + mat4& _transformationMatrix, + const etk::Color& _tmpColor) { + etk::Vector tmpVertices; + _lats = int32_t(_lats / 2)*2; + + // center to border (TOP) + float offset = _size*0.5f; + for(int32_t iii=_lats/2+1; iii<=_lats; ++iii) { + float lat0 = M_PI * (-0.5f + float(iii - 1) / _lats); + float z0 = _radius*sin(lat0); + float zr0 = _radius*cos(lat0); + + float lat1 = M_PI * (-0.5f + float(iii) / _lats); + float z1 = _radius*sin(lat1); + float zr1 = _radius*cos(lat1); + + for(int32_t jjj=0; jjj<_longs; ++jjj) { + float lng = 2.0f * M_PI * float(jjj - 1) / _longs; + float x = cos(lng); + float y = sin(lng); + vec3 v1 = vec3(x * zr1, y * zr1, z1+offset); + vec3 v4 = vec3(x * zr0, y * zr0, z0+offset); + + lng = 2 * M_PI * float(jjj) / _longs; + x = cos(lng); + y = sin(lng); + vec3 v2 = vec3(x * zr1, y * zr1, z1+offset); + vec3 v3 = vec3(x * zr0, y * zr0, z0+offset); + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v2); + tmpVertices.pushBack(v3); + + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v3); + tmpVertices.pushBack(v4); + } + } + // Cylinder + for(int32_t jjj=0; jjj<_longs; ++jjj) { + float lng = 2.0f * M_PI * float(jjj - 1) / _longs; + + float z = _size*0.5f; + + float x = cos(lng)*_radius; + float y = sin(lng)*_radius; + vec3 v2 = vec3(x, y, z); + vec3 v2b = vec3(x, y, -z); + + lng = 2.0f * M_PI * float(jjj) / _longs; + x = cos(lng)*_radius; + y = sin(lng)*_radius; + vec3 v3 = vec3(x, y, z); + vec3 v3b = vec3(x, y, -z); + + tmpVertices.pushBack(v2); + tmpVertices.pushBack(v3); + tmpVertices.pushBack(v3b); + + tmpVertices.pushBack(v2); + tmpVertices.pushBack(v3b); + tmpVertices.pushBack(v2b); + } + // center to border (BUTTOM) + offset = -_size*0.5f; + for(int32_t iii=0; iii<=_lats/2; ++iii) { + float lat0 = M_PI * (-0.5f + float(iii - 1) / _lats); + float z0 = _radius*sin(lat0); + float zr0 = _radius*cos(lat0); + + float lat1 = M_PI * (-0.5f + float(iii) / _lats); + float z1 = _radius*sin(lat1); + float zr1 = _radius*cos(lat1); + + for(int32_t jjj=0; jjj<_longs; ++jjj) { + float lng = 2.0f * M_PI * float(jjj - 1) / _longs; + float x = cos(lng); + float y = sin(lng); + vec3 v1 = vec3(x * zr1, y * zr1, z1+offset); + vec3 v4 = vec3(x * zr0, y * zr0, z0+offset); + + lng = 2 * M_PI * float(jjj) / _longs; + x = cos(lng); + y = sin(lng); + vec3 v2 = vec3(x * zr1, y * zr1, z1+offset); + vec3 v3 = vec3(x * zr0, y * zr0, z0+offset); + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v2); + tmpVertices.pushBack(v3); + + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v3); + tmpVertices.pushBack(v4); + } + } + draw(tmpVertices, _tmpColor, _transformationMatrix); +} + +void ewol::resource::Colored3DObject::drawCone(float _radius, + float _size, + int _lats, + int _longs, + mat4& _transformationMatrix, + const etk::Color& _tmpColor) { + etk::Vector tmpVertices; + // center to border (TOP) + for(int32_t jjj=0; jjj<_longs; ++jjj) { + float lng = 2.0f * M_PI * float(jjj - 1) / _longs; + vec3 v1 = vec3(0.0f, 0.0f, -_size/2); + + float x = cos(lng)*_radius; + float y = sin(lng)*_radius; + vec3 v2 = vec3(x, y, _size/2); + + lng = 2.0f * M_PI * float(jjj) / _longs; + x = cos(lng)*_radius; + y = sin(lng)*_radius; + vec3 v3 = vec3(x, y, _size/2); + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v3); + tmpVertices.pushBack(v2); + } + // center to border (BUTTOM) + for(int32_t jjj=0; jjj<_longs; ++jjj) { + float lng = 2.0f * M_PI * float(jjj - 1) / _longs; + + vec3 v1 = vec3(0.0f, 0.0f, _size/2); + + float x = cos(lng)*_radius; + float y = sin(lng)*_radius; + vec3 v2 = vec3(x, y, _size/2); + + lng = 2.0f * M_PI * float(jjj) / _longs; + x = cos(lng)*_radius; + y = sin(lng)*_radius; + vec3 v3 = vec3(x, y, _size/2); + tmpVertices.pushBack(v1); + tmpVertices.pushBack(v2); + tmpVertices.pushBack(v3); + } + draw(tmpVertices, _tmpColor, _transformationMatrix); +} + +void ewol::resource::Colored3DObject::drawTriangles(const etk::Vector& _vertex, + const etk::Vector& _indice, + mat4& _transformationMatrix, + const etk::Color& _tmpColor, + const vec3& _offset) { + etk::Vector tmpVertices; + for (size_t iii=0; iii<_indice.size()/3; ++iii) { + tmpVertices.pushBack(_vertex[_indice[iii*3 + 0]]+_offset); + tmpVertices.pushBack(_vertex[_indice[iii*3 + 1]]+_offset); + tmpVertices.pushBack(_vertex[_indice[iii*3 + 2]]+_offset); + //EWOL_INFO(" indices " << _indice[iii*3 + 0] << " " << _indice[iii*3 + 1] << " " << _indice[iii*3 + 2]); + //EWOL_INFO(" triangle " << _vertex[_indice[iii*3 + 0]] << " " << _vertex[_indice[iii*3 + 1]] << " " << _vertex[_indice[iii*3 + 2]]); + } + //EWOL_INFO("display " << tmpVertices.size() << " vertices form " << _indice.size()); + draw(tmpVertices, _tmpColor, _transformationMatrix); +} + +namespace etk { + template<> etk::String toString(ewol::resource::Colored3DObject const&) { + return "!!ewol::resource::Colored3DObject!ERROR!CAN_NOT_BE_CONVERT!!"; + } +} +#include + +// declare for signal event +ESIGNAL_DECLARE_SIGNAL(ewol::resource::Colored3DObject); +ESIGNAL_DECLARE_SIGNAL(ememory::SharedPtr); + +#endif + diff --git a/src/org/atriasoft/ewol/resource/Colored3DObject.java b/src/org/atriasoft/ewol/resource/Colored3DObject.java new file mode 100644 index 0000000..c9a6c42 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/Colored3DObject.java @@ -0,0 +1,89 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#ifndef __TARGET_OS__Web + +#include +#include +#include +#include + +namespace ewol { + namespace resource { + /** + * @brief simple display of Colored3DObject ==> for DEBUG only Not availlable on ALL platform (like webGL) + */ + class Colored3DObject : public gale::Resource { + protected: + ememory::SharedPtr m_GLprogram; + int32_t m_GLPosition; + int32_t m_GLMatrix; + int32_t m_GLColor; + protected: + Colored3DObject(); + void init(); + public: + DECLARE_RESOURCE_FACTORY(Colored3DObject); + virtual ~Colored3DObject(); + public: + virtual void draw(const etk::Vector& _vertices, + const etk::Color& _color, + bool _updateDepthBuffer=true, + bool _depthtest=true); + virtual void draw(const etk::Vector& _vertices, + const etk::Color& _color, + mat4& _transformationMatrix, + bool _updateDepthBuffer=true, + bool _depthtest=true); + virtual void drawLine(etk::Vector& _vertices, + const etk::Color& _color, + mat4& _transformationMatrix, + bool _updateDepthBuffer=true, + bool _depthtest=true); + virtual void drawCubeLine(const vec3& _min, + const vec3& _max, + const etk::Color& _color, + mat4& _transformationMatrix, + bool _updateDepthBuffer=true, + bool _depthtest=true); + public: + void drawSquare(const vec3& _size, + mat4& _transformationMatrix, + const etk::Color& _tmpColor); + void drawSphere(float _radius, + int _lats, + int _longs, + mat4& _transformationMatrix, + const etk::Color& _tmpColor); + void drawCylinder(float _radius, + float _size, + int _lats, + int _longs, + mat4& _transformationMatrix, + const etk::Color& _tmpColor); + void drawCapsule(float _radius, + float _size, + int _lats, + int _longs, + mat4& _transformationMatrix, + const etk::Color& _tmpColor); + void drawCone(float _radius, + float _size, + int _lats, + int _longs, + mat4& _transformationMatrix, + const etk::Color& _tmpColor); + void drawTriangles(const etk::Vector& _vertex, + const etk::Vector& _indice, + mat4& _transformationMatrix, + const etk::Color& _tmpColor, + const vec3& _offset=vec3(0,0,0.1)); + }; + }; +}; + +#endif diff --git a/src/org/atriasoft/ewol/resource/ConfigFile.cpp b/src/org/atriasoft/ewol/resource/ConfigFile.cpp new file mode 100644 index 0000000..ceb5b75 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ConfigFile.cpp @@ -0,0 +1,92 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::resource::ConfigFile); + +ewol::resource::ConfigFile::ConfigFile() : + gale::Resource(), + // set map unorderred + m_list(0, false) { + addResourceType("ewol::ConfigFile"); +} + +void ewol::resource::ConfigFile::init(const etk::Uri& _uri) { + ethread::RecursiveLock lock(m_mutex); + gale::Resource::init(_uri.get()); + EWOL_DEBUG("SFP : load \"" << _uri << "\""); + reload(); +} + + +ewol::resource::ConfigFile::~ConfigFile() { + m_list.clear(); +} + +void ewol::resource::ConfigFile::reload() { + ethread::RecursiveLock lock(m_mutex); + // reset all parameters + for (size_t iii=0; iii +#include +#include +#include +#include + +namespace ewol { + namespace resource { + class ConfigFile : public gale::Resource { + private: + ejson::Document m_doc; + etk::Map m_list; + protected: + ConfigFile(); + void init(const etk::Uri& _filename); + public: + virtual ~ConfigFile(); + DECLARE_RESOURCE_URI_FACTORY(ConfigFile); + public: + void reload(); + + int32_t request(const etk::String& _paramName); + + double getNumber(int32_t _id); + etk::String getString(int32_t _id); + bool getBoolean(int32_t _id); + public: + /** + * @brief keep the resource pointer. + * @note Never free this pointer by your own... + * @param[in] _filename Name of the configuration file. + * @return pointer on the resource or null if an error occured. + */ + static ememory::SharedPtr keep(const etk::String& _filename); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/resource/DistanceFieldFont.cpp b/src/org/atriasoft/ewol/resource/DistanceFieldFont.cpp new file mode 100644 index 0000000..fd126f1 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/DistanceFieldFont.cpp @@ -0,0 +1,470 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#define SIZE_GENERATION (30) + +#include +ETK_DECLARE_TYPE(ewol::resource::DistanceFieldFont); + +ewol::resource::DistanceFieldFont::DistanceFieldFont() : + ewol::resource::Texture(), + m_borderSize(10), + m_textureBorderSize(0,0) { + addResourceType("ewol::resource::DistanceFieldFont"); + m_font = null; + m_lastGlyphPos.setValue(1,1); + m_lastRawHeigh = 0; + m_sizeRatio = 1.0f; +} + +/** + * @brief Get all the Path contain in the specidy path: + * @param[in] _path Generic path to parse ... + * @return The list of path found + * @example[start] + * auto out = explodeMultiplePath("DATA:///font?lib=ewol"); + * // out contain: {"DATA:///font", "DATA:///font?lib=ewol"} + * @example[stop] + */ +static etk::Vector explodeMultiplePath(const etk::Uri& _uri) { + etk::Vector out; + out.pushBack(_uri); + if (_uri.getQuery().exist("lib") == true) { + etk::Uri tmp = _uri; + tmp.getQuery().erase("lib"); + out.pushBack(tmp); + } + return out; +} + +void ewol::resource::DistanceFieldFont::init(const etk::String& _fontName) { + ethread::RecursiveLock lock(m_mutex); + ewol::resource::Texture::init(_fontName); + etk::String localName = _fontName; + etk::Vector folderList; + if (ewol::getContext().getFontDefault().getUseExternal() == true) { + #if defined(__TARGET_OS__Android) + folderList.pushBack(etk::Path("/system/fonts")); + #elif defined(__TARGET_OS__Linux) + folderList.pushBack(etk::Path("/usr/share/fonts")); + #endif + } + etk::Uri applicationBaseFont = ewol::getContext().getFontDefault().getFolder(); + for (auto &it : explodeMultiplePath(applicationBaseFont)) { + folderList.pushBack(it); + } + for (size_t folderID = 0; folderID < folderList.size() ; folderID++) { + etk::Vector output = etk::uri::listRecursive(folderList[folderID]); + + etk::Vector split = etk::split(localName, ';'); + EWOL_INFO("try to find font named : " << split << " in: " << output); + //EWOL_CRITICAL("parse string : " << split); + bool hasFindAFont = false; + for (size_t jjj=0; jjjgetHeight(SIZE_GENERATION)); + // TODO : basic font use 512 is better ... == > maybe estimate it with the dpi ??? + setImageSize(ivec2(512,32)); + // now we can acces directly on the image + m_data.clear(etk::Color<>(0x00000000)); + // add error glyph + addGlyph(0); + // by default we set only the first AINSI char availlable + for (int32_t iii=0x20; iii<0x7F; iii++) { + addGlyph(iii); + } + flush(); + if (true) { + EWOL_ERROR("Save in cache the loaded data ..... "); + egami::store(m_data, "CACHE:///fileFont.bmp"); // ==> for debug test only ... + egami::store(m_data, "CACHE:///fileFont.png"); + } + exportOnFile(); +} + +ewol::resource::DistanceFieldFont::~DistanceFieldFont() { + +} + + +float ewol::resource::DistanceFieldFont::getDisplayRatio(float _size) { + ethread::RecursiveLock lock(m_mutex); + return _size / (float)SIZE_GENERATION; +} + + +void ewol::resource::DistanceFieldFont::generateDistanceField(const egami::ImageMono& _input, egami::Image& _output) { + EWOL_INFO("Generate Distance field font [START]"); + EWOL_INFO(" _input.getSize()=" << _input.getSize()); + ethread::RecursiveLock lock(m_mutex); + int32_t size = _input.getSize().x() * _input.getSize().y(); + etk::Vector xdist; + etk::Vector ydist; + etk::Vector gx; + etk::Vector gy; + etk::Vector data; + etk::Vector outside; + etk::Vector inside; + xdist.resize(size, 0); + ydist.resize(size, 0); + gx.resize(size, 0.0); + gy.resize(size, 0.0); + data.resize(size, 0.0); + outside.resize(size, 0.0); + inside.resize(size, 0.0); + EWOL_INFO(" size=" << size); + // Convert img into double (data) + double img_min = 255, img_max = -255; + for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) { + for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) { + int32_t iii = yyy * _input.getSize().x() + xxx; + double v = _input.get(ivec2(xxx, yyy)); + data[iii] = v; + if (v > img_max) { + img_max = v; + } + if (v < img_min) { + img_min = v; + } + } + } + // Rescale image levels between 0 and 1 + for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) { + for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) { + int32_t iii = yyy * _input.getSize().x() + xxx; + data[iii] = (_input.get(ivec2(xxx, yyy))-img_min)/img_max; + } + } + // Compute outside = edtaa3(bitmap); % Transform background (0's) + computegradient(&data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]); + edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().x(), _input.getSize().y(), &xdist[0], &ydist[0], &outside[0]); + for(size_t iii = 0; iii < outside.size(); ++iii) { + if( outside[iii] < 0 ) { + outside[iii] = 0.0; + } + } + // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's) + for(size_t iii = 0; iii < gx.size(); ++iii) { + gx[iii] = 0; + } + for(size_t iii = 0; iii < gy.size(); ++iii) { + gy[iii] = 0; + } + for(size_t iii = 0; iii < data.size(); ++iii) { + data[iii] = 1 - data[iii]; + } + computegradient( &data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]); + edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().x(), _input.getSize().y(), &xdist[0], &ydist[0], &inside[0]); + for(size_t iii = 0; iii < inside.size(); ++iii) { + if( inside[iii] < 0 ) { + inside[iii] = 0.0; + } + } + EWOL_INFO(" _output=" << _output); + _output.resize(_input.getSize(), etk::Color<>(0)); + _output.clear(etk::Color<>(0)); + for (int32_t xxx = 0; xxx < _output.getSize().x(); ++xxx) { + for (int32_t yyy = 0; yyy < _output.getSize().y(); ++yyy) { + int32_t iii = yyy * _output.getSize().x() + xxx; + outside[iii] -= inside[iii]; + outside[iii] = 128+outside[iii]*16; + if( outside[iii] < 0 ) { + outside[iii] = 0; + } + if( outside[iii] > 255 ) { + outside[iii] = 255; + } + uint8_t val = 255 - (unsigned char) outside[iii]; + // TODO : Remove multiple size of the map ... + _output.set(ivec2(xxx, yyy), etk::Color<>((int32_t)val,(int32_t)val,(int32_t)val,255)); + } + } + EWOL_INFO(" _output=" << _output); +} + +bool ewol::resource::DistanceFieldFont::addGlyph(const char32_t& _val) { + ethread::RecursiveLock lock(m_mutex); + bool hasChange = false; + if (m_font == null) { + return false; + } + // add the curent "char" + GlyphProperty tmpchar; + tmpchar.m_UVal = _val; + egami::ImageMono imageGlyphRaw; + egami::Image imageGlyphDistanceField(ivec2(32,32), egami::colorType::RGBA8); + EWOL_DEBUG("Generate Glyph : " << _val); + + if (m_font->getGlyphProperty(SIZE_GENERATION, tmpchar) == true) { + //EWOL_DEBUG("load char: '" << _val << "'=" << _val); + hasChange = true; + // change line if needed ... + if (m_lastGlyphPos.x() + tmpchar.m_sizeTexture.x()+m_borderSize*2.0 > m_data.getSize().x()) { + m_lastGlyphPos.setX(1); + m_lastGlyphPos += ivec2(0, m_lastRawHeigh); + m_lastRawHeigh = 0; + } + while(m_lastGlyphPos.y()+tmpchar.m_sizeTexture.y()+m_borderSize*2.0 > m_data.getSize().y()) { + ivec2 size = m_data.getSize(); + size.setY(size.y()*2); + EWOL_VERBOSE("resize " << m_data.getSize() << " => " << size); + m_data.resize(size, etk::Color<>(0)); + // change the coordonate on the element in the texture + for (size_t jjj = 0; jjj < m_listElement.size(); ++jjj) { + m_listElement[jjj].m_texturePosStart *= vec2(1.0f, 0.5f); + m_listElement[jjj].m_texturePosSize *= vec2(1.0f, 0.5f); + } + } + m_textureBorderSize = vec2(m_borderSize/(float)m_data.getSize().x(), + m_borderSize/(float)m_data.getSize().y() ); + // draw the glyph + m_font->drawGlyph(imageGlyphRaw, SIZE_GENERATION, tmpchar, m_borderSize); + + generateDistanceField(imageGlyphRaw, imageGlyphDistanceField); + + if (_val == 100) { + EWOL_DEBUG("print char: " << _val << " size=" << imageGlyphDistanceField.getSize()); + for (int32_t yyy = 0; yyy < imageGlyphDistanceField.getSize().y(); ++yyy) { + for (int32_t xxx = 0; xxx < imageGlyphDistanceField.getSize().x(); ++xxx) { + EWOL_PRINT((int)(imageGlyphDistanceField.get(ivec2(xxx, yyy)).r()) << " "); + } + } + } + + m_data.insert(m_lastGlyphPos, imageGlyphDistanceField); + + // set image position + tmpchar.m_texturePosStart.setValue( ((float)m_lastGlyphPos.x()+(m_borderSize*0.5f)) / (float)m_data.getSize().x(), + ((float)m_lastGlyphPos.y()+(m_borderSize*0.5f)) / (float)m_data.getSize().y() ); + tmpchar.m_texturePosSize.setValue( ((float)imageGlyphRaw.getSize().x()-m_borderSize) / (float)m_data.getSize().x(), + ((float)imageGlyphRaw.getSize().y()-m_borderSize) / (float)m_data.getSize().y() ); + + // update the maximum of the line hight : + if (m_lastRawHeigh < imageGlyphRaw.getSize().y()) { + // note : +1 is for the overlapping of the glyph (Part 2) + m_lastRawHeigh = imageGlyphRaw.getSize().y()+1; + } + // note : +1 is for the overlapping of the glyph (Part 3) + // update the Bitmap position drawing : + m_lastGlyphPos += ivec2(imageGlyphRaw.getSize().x()+1, 0); + } else { + EWOL_WARNING("Did not find char : '" << _val << "'=" << _val); + tmpchar.setNotExist(); + } + m_listElement.pushBack(tmpchar); + //m_font[iii]->display(); + // generate the kerning for all the characters : + if (tmpchar.exist() == true) { + // TODO : set the kerning back ... + //m_font[iii]->generateKerning(m_size, m_listElement[iii]); + } + if (hasChange == true) { + flush(); + //EWOL_ERROR("Save in cache the loaded data ..... "); + //egami::store(m_data, "CACHE:///fileFont.bmp"); // ==> for debug test only ... + //egami::store(m_data, "CACHE:///fileFont.png"); + } + return hasChange; +} + +int32_t ewol::resource::DistanceFieldFont::getIndex(char32_t _charcode) { + ethread::RecursiveLock lock(m_mutex); + if (_charcode < 0x20) { + return 0; + } else if (_charcode < 0x80) { + return _charcode - 0x1F; + } else { + for (size_t iii=0x80-0x20; iii < m_listElement.size(); iii++) { + //EWOL_DEBUG("search : '" << charcode << "' =?= '" << (m_listElement[displayMode])[iii].m_UVal << "'"); + if (_charcode == (m_listElement)[iii].m_UVal) { + //EWOL_DEBUG("search : '" << charcode << "'"); + if ((m_listElement)[iii].exist()) { + //EWOL_DEBUG("return " << iii); + return iii; + } else { + return 0; + } + } + } + } + if (addGlyph(_charcode) == true) { + // TODO : This does not work due to the fact that the update of open GL is not done in the context main cycle !!! + ewol::getContext().forceRedrawAll(); + } + return 0; +} + +ewol::GlyphProperty* ewol::resource::DistanceFieldFont::getGlyphPointer(const char32_t& _charcode) { + ethread::RecursiveLock lock(m_mutex); + EWOL_VERBOSE("getGlyphPointer : " << uint32_t(_charcode)); + int32_t index = getIndex(_charcode); + if( index < 0 + || (size_t)index >= m_listElement.size() ) { + EWOL_ERROR(" Try to get glyph index inexistant ... == > return the index 0 ... id=" << index); + if (m_listElement.size() > 0) { + return &((m_listElement)[0]); + } + return null; + } + //EWOL_ERROR(" index=" << index); + //EWOL_ERROR(" m_UVal=" << m_listElement[_displayMode][index].m_UVal); + //EWOL_ERROR(" m_glyphIndex=" << m_listElement[_displayMode][index].m_glyphIndex); + //EWOL_ERROR(" m_advance=" << m_listElement[_displayMode][index].m_advance); + //EWOL_ERROR(" m_bearing=" << m_listElement[_displayMode][index].m_bearing); + return &((m_listElement)[index]); +} + +void ewol::resource::DistanceFieldFont::exportOnFile() { + ethread::RecursiveLock lock(m_mutex); + EWOL_DEBUG("EXPORT: DistanceFieldFont : file : '" << m_fileName << ".json'"); + ejson::Document doc; + ejson::Array tmpList; + for (size_t iii=0; iii +#include +#include + +namespace ewol { + namespace resource { + class DistanceFieldFont : public ewol::resource::Texture { + private: + etk::Uri m_fileName; + float m_sizeRatio; + // specific element to have the the know if the specify element is known... + // == > otherwise I can just generate italic ... + // == > Bold is a little more complicated (maybe with the bordersize) + ememory::SharedPtr m_font; + public: + etk::Vector m_listElement; + private: + // for the texture generation : + ivec2 m_lastGlyphPos; + int32_t m_lastRawHeigh; + protected: + DistanceFieldFont(); + void init(const etk::String& _fontName); + public: + DECLARE_RESOURCE_NAMED_FACTORY(DistanceFieldFont); + virtual ~DistanceFieldFont(); + public: + float getDisplayRatio(float _size); + /** + * @brief get the display height of this font + * @param[in] _size Request font size + * @return Dimention of the font need between 2 lines + */ + float getHeight(float _size) { + return ((float)m_font->getHeight(_size)); + }; + /** + * @brief get the font size with a specific display size + * @param[in] _fontHeight Request font height + * @return Dimention of the font for this compleate line size. + */ + float getSize(float _fontHeight) { + return m_font->getSizeWithHeight(_fontHeight); + } + /** + * @brief get the ID of a unicode charcode + * @param[in] _charcode The unicodeValue + * @return The ID in the table (if it does not exist : return 0) + */ + int32_t getIndex(char32_t _charcode); + /** + * @brief get the pointer on the coresponding glyph + * @param[in] _charcode The unicodeValue + * @return The pointer on the glyph == > never null + */ + ewol::GlyphProperty* getGlyphPointer(const char32_t& _charcode); + public: + /** + * @brief keep the resource pointer. + * @note Never free this pointer by your own... + * @param[in] _filename Name of the texture font. + * @return pointer on the resource or null if an error occured. + */ + static ememory::SharedPtr keep(const etk::String& _filename); + private: + /** + * @brief add a glyph in a texture font. + * @param[in] _val Char value to add. + * @return true if the image size have change, false otherwise + */ + bool addGlyph(const char32_t& _val); + + void generateDistanceField(const egami::ImageMono& _input, egami::Image& _output); + private: + float m_borderSize; //!< number of pixel added on the border of a glyph + vec2 m_textureBorderSize; //!< Transformed the border size in the texture dimention + public: + float getPixelBorderSize() { + return m_borderSize; + } + const vec2& getTextureBorderSize() { + return m_textureBorderSize; + } + public: + void exportOnFile(); + bool importFromFile(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/resource/FontFreeType.cpp b/src/org/atriasoft/ewol/resource/FontFreeType.cpp new file mode 100644 index 0000000..d74dd09 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/FontFreeType.cpp @@ -0,0 +1,384 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + + +#include + +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::resource::FontFreeType); + +// free Font hnadle of librairies ... entry for acces ... +static int32_t l_countLoaded=0; +static FT_Library library; + +void ewol::resource::freeTypeInit() { + EWOL_DEBUG(" == > init Font-Manager"); + l_countLoaded++; + if (l_countLoaded>1) { + // already loaded ... + return; + } + int32_t error = FT_Init_FreeType( &library ); + if(0 != error) { + EWOL_CRITICAL(" when loading FreeType Librairy ..."); + } +} + +void ewol::resource::freeTypeUnInit() { + EWOL_DEBUG(" == > Un-Init Font-Manager"); + l_countLoaded--; + if (l_countLoaded>0) { + // already needed ... + return; + } + int32_t error = FT_Done_FreeType( library ); + library = null; + if(0 != error) { + EWOL_CRITICAL(" when Un-loading FreeType Librairy ..."); + } +} + +ewol::resource::FontFreeType::FontFreeType() { + addResourceType("ewol::FontFreeType"); + m_init = false; + m_FileSize = 0; +} + +void ewol::resource::FontFreeType::init(const etk::Uri& _uri) { + ethread::RecursiveLock lock(m_mutex); + ewol::resource::FontBase::init(_uri); + auto fileIO = etk::uri::get(_uri); + if (fileIO == null) { + EWOL_ERROR("File Does not exist : " << _uri); + return; + } + if (fileIO->open(etk::io::OpenMode::Read) == false) { + EWOL_ERROR("Can not open the file : " << _uri); + return; + } + m_FileBuffer = fileIO->readAll(); + // close the file: + fileIO->close(); + // load Face ... + int32_t error = FT_New_Memory_Face(library, &m_FileBuffer[0], m_FileBuffer.size(), 0, &m_fftFace ); + if( FT_Err_Unknown_File_Format == error) { + EWOL_ERROR("... the font file could be opened and read, but it appears ... that its font format is unsupported"); + } else if (0 != error) { + EWOL_ERROR("... another error code means that the font file could not ... be opened or read, or simply that it is broken..."); + } else { + // all OK + EWOL_DEBUG("load font : \"" << _uri << "\" glyph count = " << (int)m_fftFace->num_glyphs); + m_init = true; + //display(); + } +} + +ewol::resource::FontFreeType::~FontFreeType() { + ethread::RecursiveLock lock(m_mutex); + // clean the tmp memory + m_FileBuffer.clear(); + // must be deleted fftFace + FT_Done_Face(m_fftFace); +} + +vec2 ewol::resource::FontFreeType::getSize(int32_t _fontSize, const etk::String& _unicodeString) { + ethread::RecursiveLock lock(m_mutex); + if (m_init == false) { + return vec2(0,0); + } + // TODO : ... + vec2 outputSize(0,0); + return outputSize; +} + +int32_t ewol::resource::FontFreeType::getHeight(int32_t _fontSize) { + ethread::RecursiveLock lock(m_mutex); + return _fontSize*1.43f; // this is a really "magic" number ... +} +float ewol::resource::FontFreeType::getSizeWithHeight(float _fontHeight) { + ethread::RecursiveLock lock(m_mutex); + return _fontHeight*0.6993f; // this is a really "magic" number ... +} + +bool ewol::resource::FontFreeType::getGlyphProperty(int32_t _fontSize, ewol::GlyphProperty& _property) { + ethread::RecursiveLock lock(m_mutex); + if(false == m_init) { + return false; + } + // 300dpi (hight quality) 96 dpi (normal quality) + int32_t fontQuality = 96; + // Select size ... + // note tha <<6 == *64 corespond with the 1/64th of points calculation of freetype + int32_t error = FT_Set_Char_Size(m_fftFace, _fontSize<<6, _fontSize<<6, fontQuality, fontQuality); + if (0!=error ) { + EWOL_ERROR("FT_Set_Char_Size == > error in settings ..."); + return false; + } + // a small shortcut + FT_GlyphSlot slot = m_fftFace->glyph; + // retrieve glyph index from character code + int32_t glyph_index = FT_Get_Char_Index(m_fftFace, _property.m_UVal); + // load glyph image into the slot (erase previous one) + error = FT_Load_Glyph(m_fftFace, // handle to face object + glyph_index, // glyph index + FT_LOAD_DEFAULT ); + if (0!=error ) { + EWOL_ERROR("FT_Load_Glyph specify Glyph"); + return false; + } + // convert to an anti-aliased bitmap + error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL ); + if (0!=error) { + EWOL_ERROR("FT_Render_Glyph"); + return false; + } + // set properties : + _property.m_glyphIndex = glyph_index; + _property.m_sizeTexture.setValue(slot->bitmap.width, slot->bitmap.rows); + _property.m_bearing.setValue( slot->metrics.horiBearingX>>6 , slot->metrics.horiBearingY>>6 ); + _property.m_advance.setValue( slot->metrics.horiAdvance>>6 , slot->metrics.vertAdvance>>6 ); + + return true; +} + +bool ewol::resource::FontFreeType::drawGlyph(egami::Image& _imageOut, + int32_t _fontSize, + ivec2 _glyphPosition, + ewol::GlyphProperty& _property, + int8_t _posInImage) { + ethread::RecursiveLock lock(m_mutex); + if(m_init == false) { + return false; + } + // 300dpi (hight quality) 96 dpi (normal quality) + int32_t fontQuality = 96; + // Select size ... + // note tha <<6 == *64 corespond with the 1/64th of points calculation of freetype + int32_t error = FT_Set_Char_Size(m_fftFace, _fontSize<<6, _fontSize<<6, fontQuality, fontQuality); + if (0!=error ) { + EWOL_ERROR("FT_Set_Char_Size == > error in settings ..."); + return false; + } + // a small shortcut + FT_GlyphSlot slot = m_fftFace->glyph; + // load glyph image into the slot (erase previous one) + error = FT_Load_Glyph(m_fftFace, // handle to face object + _property.m_glyphIndex, // glyph index + FT_LOAD_DEFAULT ); + if (0!=error ) { + EWOL_ERROR("FT_Load_Glyph specify Glyph"); + return false; + } + // convert to an anti-aliased bitmap + error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL ); + if (0!=error) { + EWOL_ERROR("FT_Render_Glyph"); + return false; + } + // draw it on the output Image : + etk::Color<> tlpppp(0xFF, 0xFF, 0xFF, 0x00); + for(size_t jjj=0; jjj < slot->bitmap.rows;jjj++) { + for(size_t iii=0; iii < slot->bitmap.width; iii++){ + tlpppp = _imageOut.get(ivec2(_glyphPosition.x()+iii, _glyphPosition.y()+jjj)); + uint8_t valueColor = slot->bitmap.buffer[iii + slot->bitmap.width*jjj]; + // set only alpha : + switch(_posInImage) { + default: + case 0: + tlpppp.setA(valueColor); + break; + case 1: + tlpppp.setR(valueColor); + break; + case 2: + tlpppp.setG(valueColor); + break; + case 3: + tlpppp.setB(valueColor); + break; + } + // real set of color + _imageOut.set(ivec2(_glyphPosition.x()+iii, _glyphPosition.y()+jjj), tlpppp ); + } + } + return true; +} + +bool ewol::resource::FontFreeType::drawGlyph(egami::ImageMono& _imageOut, + int32_t _fontSize, + ewol::GlyphProperty& _property, + int32_t _borderSize) { + ethread::RecursiveLock lock(m_mutex); + if(false == m_init) { + return false; + } + // 300dpi (hight quality) 96 dpi (normal quality) + int32_t fontQuality = 96; + // Select size ... + // note tha <<6 == *64 corespond with the 1/64th of points calculation of freetype + int32_t error = FT_Set_Char_Size(m_fftFace, _fontSize<<6, _fontSize<<6, fontQuality, fontQuality); + if (0!=error ) { + EWOL_ERROR("FT_Set_Char_Size == > error in settings ..."); + return false; + } + // a small shortcut + FT_GlyphSlot slot = m_fftFace->glyph; + // load glyph image into the slot (erase previous one) + error = FT_Load_Glyph(m_fftFace, // handle to face object + _property.m_glyphIndex, // glyph index + FT_LOAD_DEFAULT ); + if (0!=error ) { + EWOL_ERROR("FT_Load_Glyph specify Glyph"); + return false; + } + // convert to an anti-aliased bitmap + error = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL ); // TODO : set FT_RENDER_MODE_MONO ==> 1 bit value ==> faster generation ... + if (0!=error) { + EWOL_ERROR("FT_Render_Glyph"); + return false; + } + // resize output image : + _imageOut.resize(ivec2(slot->bitmap.width+2*_borderSize, slot->bitmap.rows+2*_borderSize), 0); + + for(size_t jjj=0; jjj < slot->bitmap.rows;jjj++) { + for(size_t iii=0; iii < slot->bitmap.width; iii++){ + uint8_t valueColor = slot->bitmap.buffer[iii + slot->bitmap.width*jjj]; + // real set of color + _imageOut.set(ivec2(_borderSize+iii, _borderSize+jjj), valueColor ); + } + } + return true; +} + + +void ewol::resource::FontFreeType::generateKerning(int32_t fontSize, etk::Vector& listGlyph) { + ethread::RecursiveLock lock(m_mutex); + if(m_init == false) { + return; + } + if ((FT_FACE_FLAG_KERNING & m_fftFace->face_flags) == 0) { + EWOL_INFO("No kerning generation (disable) in the font"); + } + // 300dpi (hight quality) 96 dpi (normal quality) + int32_t fontQuality = 96; + // Select size ... + // note tha <<6 == *64 corespond with the 1/64th of points calculation of freetype + int32_t error = FT_Set_Char_Size(m_fftFace, fontSize<<6, fontSize<<6, fontQuality, fontQuality); + if (0!=error ) { + EWOL_ERROR("FT_Set_Char_Size == > error in settings ..."); + return; + } + // For all the kerning element we get the kerning value : + for(size_t iii=0; iii " << (kerning.x/64.0f)); + } + } + } +} + + +void ewol::resource::FontFreeType::display() { + ethread::RecursiveLock lock(m_mutex); + if(m_init == false) { + return; + } + EWOL_INFO(" number of glyph = " << (int)m_fftFace->num_glyphs); + if ((FT_FACE_FLAG_SCALABLE & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_SCALABLE (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_SCALABLE (disable)"); + } + if ((FT_FACE_FLAG_FIXED_SIZES & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_FIXED_SIZES (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_FIXED_SIZES (disable)"); + } + if ((FT_FACE_FLAG_FIXED_WIDTH & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_FIXED_WIDTH (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_FIXED_WIDTH (disable)"); + } + if ((FT_FACE_FLAG_SFNT & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_SFNT (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_SFNT (disable)"); + } + if ((FT_FACE_FLAG_HORIZONTAL & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_HORIZONTAL (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_HORIZONTAL (disable)"); + } + if ((FT_FACE_FLAG_VERTICAL & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_VERTICAL (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_VERTICAL (disable)"); + } + if ((FT_FACE_FLAG_KERNING & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_KERNING (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_KERNING (disable)"); + } + /* Deprecated flag + if ((FT_FACE_FLAG_FAST_GLYPHS & face->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_FAST_GLYPHS (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_FAST_GLYPHS (disable)"); + } + */ + if ((FT_FACE_FLAG_MULTIPLE_MASTERS & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_MULTIPLE_MASTERS (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_MULTIPLE_MASTERS (disable)"); + } + if ((FT_FACE_FLAG_GLYPH_NAMES & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_GLYPH_NAMES (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_GLYPH_NAMES (disable)"); + } + if ((FT_FACE_FLAG_EXTERNAL_STREAM & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_EXTERNAL_STREAM (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_EXTERNAL_STREAM (disable)"); + } + if ((FT_FACE_FLAG_HINTER & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_HINTER (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_HINTER (disable)"); + } + if ((FT_FACE_FLAG_CID_KEYED & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_CID_KEYED (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_CID_KEYED (disable)"); + } + /* + if ((FT_FACE_FLAG_TRICKY & m_fftFace->face_flags) != 0) { + EWOL_INFO(" flags = FT_FACE_FLAG_TRICKY (enable)"); + } else { + EWOL_DEBUG(" flags = FT_FACE_FLAG_TRICKY (disable)"); + } + */ + EWOL_INFO(" unit per EM = " << m_fftFace->units_per_EM); + EWOL_INFO(" num of fixed sizes = " << m_fftFace->num_fixed_sizes); + //EWOL_INFO(" Availlable sizes = " << (int)m_fftFace->available_sizes); + + //EWOL_INFO(" Current size = " << (int)m_fftFace->size); +} diff --git a/src/org/atriasoft/ewol/resource/FontFreeType.java b/src/org/atriasoft/ewol/resource/FontFreeType.java new file mode 100644 index 0000000..3bede00 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/FontFreeType.java @@ -0,0 +1,61 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include + +extern "C" { + #include +} +#include FT_FREETYPE_H + +namespace ewol { + namespace resource { + // show : http://www.freetype.org/freetype2/docs/tutorial/step2.html + class FontFreeType : public ewol::resource::FontBase { + private: + etk::Vector m_FileBuffer; + int32_t m_FileSize; + FT_Face m_fftFace; + bool m_init; + void display(); + protected: + FontFreeType(); + void init(const etk::Uri& _uri); + public: + DECLARE_RESOURCE_URI_FACTORY(FontFreeType); + virtual ~FontFreeType(); + public: + + bool getGlyphProperty(int32_t _fontSize, + ewol::GlyphProperty& _property); + + bool drawGlyph(egami::Image& _imageOut, + int32_t _fontSize, + ivec2 _glyphPosition, + ewol::GlyphProperty& _property, + int8_t _posInImage); + + bool drawGlyph(egami::ImageMono& _imageOut, + int32_t _fontSize, + ewol::GlyphProperty& _property, + int32_t _borderSize = 0); + + vec2 getSize(int32_t _fontSize, const etk::String& _unicodeString); + + int32_t getHeight(int32_t _fontSize); + float getSizeWithHeight(float _fontHeight); + + void generateKerning(int32_t _fontSize, etk::Vector& _listGlyph); + }; + void freeTypeInit(); + void freeTypeUnInit(); + }; +}; + diff --git a/src/org/atriasoft/ewol/resource/ImageDF.cpp b/src/org/atriasoft/ewol/resource/ImageDF.cpp new file mode 100644 index 0000000..86e75b6 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ImageDF.cpp @@ -0,0 +1,225 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::resource::ImageDF); + +ewol::resource::ImageDF::ImageDF() { + addResourceType("ewol::resource::ImageDF"); +} + + +void ewol::resource::ImageDF::init() { + ethread::RecursiveLock lock(m_mutex); + ewol::resource::Texture::init(); +} + +void ewol::resource::ImageDF::init(etk::String _genName, const etk::Uri& _uri, const ivec2& _size) { + ethread::RecursiveLock lock(m_mutex); + ewol::resource::Texture::init(_genName); + EWOL_DEBUG("create a new resource::Image : _genName=" << _genName << " _uri=" << _uri << " size=" << _size); + m_data = egami::load(_uri, _size); + if (m_data.exist() == false) { + EWOL_ERROR("ERROR when loading the image : " << _uri); + } + ivec2 tmp = m_data.getSize(); + m_realImageSize = vec2(tmp.x(), tmp.y()); + // distance field Generation + // TODO : if it is not a .edf ==> generate dynamicly ... + /* + egami::ImageMono input; + input.resize(tmp); + for (size_t yyy = 0; yyy < tmp.y(); ++yyy) { + for (size_t xxx = 0; xxx < tmp.x(); ++xxx) { + input.set(ivec2(xxx, yyy), m_data.get(ivec2(xxx, yyy)).a() ); + } + } + generateDistanceField(input, m_data); + */ + flush(); +} + + +void ewol::resource::ImageDF::generateDistanceField(const egami::ImageMono& _input, egami::Image& _output) { + ethread::RecursiveLock lock(m_mutex); + int32_t size = _input.getSize().x() * _input.getSize().y(); + etk::Vector xdist; + etk::Vector ydist; + etk::Vector gx; + etk::Vector gy; + etk::Vector data; + etk::Vector outside; + etk::Vector inside; + xdist.resize(size, 0); + ydist.resize(size, 0); + gx.resize(size, 0.0); + gy.resize(size, 0.0); + data.resize(size, 0.0); + outside.resize(size, 0.0); + inside.resize(size, 0.0); + // Convert img into double (data) + double img_min = 255, img_max = -255; + for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) { + for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) { + int32_t iii = yyy * _input.getSize().x() + xxx; + double v = _input.get(ivec2(xxx, yyy)); + data[iii] = v; + if (v > img_max) { + img_max = v; + } + if (v < img_min) { + img_min = v; + } + } + } + // Rescale image levels between 0 and 1 + for (int32_t yyy = 0; yyy < _input.getSize().y(); ++yyy) { + for (int32_t xxx = 0; xxx < _input.getSize().x(); ++xxx) { + int32_t iii = yyy * _input.getSize().x() + xxx; + data[iii] = (_input.get(ivec2(xxx, yyy))-img_min)/img_max; + } + } + + // Compute outside = edtaa3(bitmap); % Transform background (0's) + computegradient(&data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]); + edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().x(), _input.getSize().y(), &xdist[0], &ydist[0], &outside[0]); + for(size_t iii = 0; iii < outside.size(); ++iii) { + if( outside[iii] < 0 ) { + outside[iii] = 0.0; + } + } + + // Compute inside = edtaa3(1-bitmap); % Transform foreground (1's) + for(size_t iii = 0; iii < gx.size(); ++iii) { + gx[iii] = 0; + } + for(size_t iii = 0; iii < gy.size(); ++iii) { + gy[iii] = 0; + } + for(size_t iii = 0; iii < data.size(); ++iii) { + data[iii] = 1 - data[iii]; + } + computegradient( &data[0], _input.getSize().x(), _input.getSize().y(), &gx[0], &gy[0]); + edtaa3(&data[0], &gx[0], &gy[0], _input.getSize().x(), _input.getSize().y(), &xdist[0], &ydist[0], &inside[0]); + for(size_t iii = 0; iii < inside.size(); ++iii) { + if( inside[iii] < 0 ) { + inside[iii] = 0.0; + } + } + + _output.resize(_input.getSize(), etk::Color<>(0)); + _output.clear(etk::Color<>(0)); + for (int32_t xxx = 0; xxx < _output.getSize().x(); ++xxx) { + for (int32_t yyy = 0; yyy < _output.getSize().y(); ++yyy) { + int32_t iii = yyy * _output.getSize().x() + xxx; + outside[iii] -= inside[iii]; + outside[iii] = 128+outside[iii]*16; + if( outside[iii] < 0 ) { + outside[iii] = 0; + } + if( outside[iii] > 255 ) { + outside[iii] = 255; + } + uint8_t val = 255 - (unsigned char) outside[iii]; + // TODO : Remove multiple size of the map ... + _output.set(ivec2(xxx, yyy), etk::Color<>((int32_t)val,(int32_t)val,(int32_t)val,255)); + } + } +} + + +#ifdef __TARGET_OS__Android +/** + * @brief get the next power 2 if the input + * @param[in] _value Value that we want the next power of 2 + * @return result value + */ +static int32_t nextP2(int32_t _value) { + int32_t val=1; + for (int32_t iii=1; iii<31; iii++) { + if (_value <= val) { + return val; + } + val *=2; + } + EWOL_CRITICAL("impossible CASE.... request P2 of " << _value); + return val; +} +#endif + + + +ememory::SharedPtr ewol::resource::ImageDF::create(const etk::Uri& _uri, ivec2 _size) { + EWOL_VERBOSE("KEEP: TextureFile: '" << _uri << "' size=" << _size); + if (_uri.isEmpty() == true) { + ememory::SharedPtr object(ETK_NEW(ewol::resource::ImageDF)); + if (object == null) { + EWOL_ERROR("allocation error of a resource : ??TEX??"); + return null; + } + object->init(); + getManager().localAdd(object); + return object; + } + if (_size.x() == 0) { + _size.setX(-1); + //EWOL_ERROR("Error Request the image size.x() =0 ???"); + } + if (_size.y() == 0) { + _size.setY(-1); + //EWOL_ERROR("Error Request the image size.y() =0 ???"); + } + etk::Uri tmpFilename = _uri; + if (etk::toLower(_uri.getPath().getExtention()) != "svg") { + _size = ivec2(-1,-1); + } + #ifdef __TARGET_OS__MacOs + EWOL_ERROR("TODO : remove this strange hack"); + _size = ivec2(64,64); + #endif + if ( _size.x() > 0 + && _size.y() > 0) { + EWOL_VERBOSE(" == > specific size : " << _size); + #ifdef __TARGET_OS__Android + _size.setValue(nextP2(_size.x()), nextP2(_size.y())); + #endif + tmpFilename.getQuery().set("x", etk::toString(_size.x())); + tmpFilename.getQuery().set("y", etk::toString(_size.y())); + } + + EWOL_VERBOSE("KEEP: TextureFile: '" << tmpFilename << "' new size=" << _size); + ememory::SharedPtr object = null; + ememory::SharedPtr object2 = getManager().localKeep("DF__" + tmpFilename.getString()); + if (object2 != null) { + object = ememory::dynamicPointerCast(object2); + if (object == null) { + EWOL_CRITICAL("Request resource file : '" << tmpFilename << "' With the wrong type (dynamic cast error)"); + return null; + } + } + if (object != null) { + return object; + } + EWOL_INFO("CREATE: ImageDF: '" << tmpFilename << "' size=" << _size); + // need to crate a new one ... + object = ememory::SharedPtr(ETK_NEW(ewol::resource::ImageDF)); + if (object == null) { + EWOL_ERROR("allocation error of a resource : " << _uri); + return null; + } + object->init("DF__" + tmpFilename.getString(), _uri, _size); + getManager().localAdd(object); + return object; +} + diff --git a/src/org/atriasoft/ewol/resource/ImageDF.java b/src/org/atriasoft/ewol/resource/ImageDF.java new file mode 100644 index 0000000..4c4b9fc --- /dev/null +++ b/src/org/atriasoft/ewol/resource/ImageDF.java @@ -0,0 +1,47 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include + +namespace ewol { + namespace resource { + class ImageDF : public ewol::resource::Texture { + protected: + vec2 m_realImageSize; + protected: + ImageDF(); + void init(); + void init(etk::String _genName, const etk::Uri& _uri, const ivec2& _size); + public: + virtual ~ImageDF() { }; + protected: + /** + * @brief Generate distance field of this Image input. + * @param[in] _input Input image to change in distance field mode. + * @param[out] _output New image generate with this image _input. + */ + void generateDistanceField(const egami::ImageMono& _input, egami::Image& _output); + public: + const vec2& getRealSize() { + return m_realImageSize; + }; + public: + /** + * @brief keep the resource pointer. + * @note Never free this pointer by your own... + * @param[in] _filename Name of the image file. + * @param[in] _requested size of the image (usefull when loading .svg to automatic rescale) + * @return pointer on the resource or null if an error occured. + */ + static ememory::SharedPtr create(const etk::Uri& _uri, ivec2 _size=ivec2(-1,-1)); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/resource/Texture.cpp b/src/org/atriasoft/ewol/resource/Texture.cpp new file mode 100644 index 0000000..0320e19 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/Texture.cpp @@ -0,0 +1,319 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::resource::Texture); + +/** + * @brief get the next power 2 if the input + * @param[in] value Value that we want the next power of 2 + * @return result value + */ +static int32_t nextP2(int32_t _value) { + int32_t val=1; + for (int32_t iii=1; iii<31; iii++) { + if (_value <= val) { + return val; + } + val *=2; + } + EWOL_CRITICAL("impossible CASE...."); + return val; +} + +void ewol::resource::Texture::init(const etk::String& _filename) { + gale::Resource::init(_filename); +} +void ewol::resource::Texture::init() { + gale::Resource::init(); +} + +ewol::resource::Texture::Texture() : + m_texId(0), + #ifdef EWOL_USE_FBO + m_texPboId(0), + #endif + m_data(ivec2(32,32),egami::colorType::RGBA8), + m_realImageSize(1,1), + m_lastSize(1,1), + m_loaded(false), + m_lastTypeObject(0), + m_lastSizeObject(0), + m_repeat(false), + m_filter(ewol::resource::TextureFilter::linear) { + addResourceType("ewol::compositing::Texture"); +} + +ewol::resource::Texture::~Texture() { + removeContext(); +} + + +void ewol::resource::Texture::setRepeat(bool _value) { + m_repeat = _value; +} + +void ewol::resource::Texture::setFilterMode(enum ewol::resource::TextureFilter _filter) { + m_filter = _filter; +} + +#include + +bool ewol::resource::Texture::updateContext() { + EWOL_VERBOSE("updateContext [START]"); + if (false) { + echrono::Steady tic = echrono::Steady::now(); + gale::openGL::flush(); + echrono::Steady toc = echrono::Steady::now(); + EWOL_VERBOSE(" updateContext [FLUSH] ==> " << (toc - tic)); + } + ethread::RecursiveLock lock(m_mutex, true); + echrono::Steady tic = echrono::Steady::now(); + if (lock.tryLock() == false) { + //Lock error ==> try later ... + return false; + } + int32_t typeObject = GL_RGBA; + int32_t sizeObject = GL_UNSIGNED_BYTE; + int32_t sizeByte = 1; + switch (m_data.getType()) { + case egami::colorType::RGBA8: + typeObject = GL_RGBA; + sizeObject = GL_UNSIGNED_BYTE; + sizeByte = 4; + break; + case egami::colorType::RGB8: + typeObject = GL_RGB; + sizeObject = GL_UNSIGNED_BYTE; + sizeByte = 3; + break; + case egami::colorType::RGBAf: + typeObject = GL_RGBA; + sizeObject = GL_FLOAT; + sizeByte = 16; + break; + case egami::colorType::RGBf: + typeObject = GL_RGBA; + sizeObject = GL_FLOAT; + sizeByte = 12; + break; + case egami::colorType::unsignedInt16: + case egami::colorType::unsignedInt32: + case egami::colorType::float32: + case egami::colorType::float64: + EWOL_ERROR("Not manage the type " << m_data.getType() << " for texture"); + break; + } + if (m_loaded == true) { + if ( m_lastTypeObject != typeObject + || m_lastSizeObject != sizeObject + || m_lastSize != m_data.getSize()) { + EWOL_WARNING("TEXTURE: Rm [" << getId() << "] texId=" << m_texId); + glDeleteTextures(1, &m_texId); + m_loaded = false; + } + } + if (m_loaded == false) { + // Request a new texture at openGl : + glGenTextures(1, &m_texId); + + #ifdef EWOL_USE_FBO + EWOL_ERROR("CREATE PBO"); + glGenBuffers(1, &m_texPboId); + EWOL_ERROR("CREATE PBO 1"); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_texPboId); + EWOL_ERROR("CREATE PBO 2"); + glBufferData(GL_PIXEL_UNPACK_BUFFER, m_data.getGPUSize().x()*m_data.getGPUSize().y()*sizeByte, 0, GL_STREAM_DRAW); + EWOL_ERROR("CREATE PBO 3"); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + EWOL_ERROR("CREATE PBO 4 (done)"); + #endif + m_lastSize = m_data.getSize(); + m_lastTypeObject = typeObject; + m_lastSizeObject = sizeObject; + EWOL_DEBUG("TEXTURE: add [" << getId() << "]=" << m_data.getSize() << "=>" << m_data.getGPUSize() << " OGl_Id=" << m_texId << " type=" << m_data.getType()); + } else { + EWOL_DEBUG("TEXTURE: update [" << getId() << "]=" << m_data.getSize() << "=>" << m_data.getGPUSize() << " OGl_Id=" << m_texId << " type=" << m_data.getType()); + } + // in all case we set the texture properties : + // TODO : check error ??? + glBindTexture(GL_TEXTURE_2D, m_texId); + if (m_loaded == false) { + if (m_repeat == false) { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); + } else { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + } + if (m_filter == ewol::resource::TextureFilter::linear) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + } + //glPixelStorei(GL_UNPACK_ALIGNMENT,1); + echrono::Steady toc1 = echrono::Steady::now(); + EWOL_VERBOSE(" BIND ==> " << (toc1 - tic)); + //egami::store(m_data, etk::String("~/texture_") + etk::toString(getId()) + ".bmp"); + #if defined(__TARGET_OS__Android) \ + || defined(__TARGET_OS__IOs) + // On some embended target, the texture size must be square of 2: + if (m_loaded == false) { + // 1: Create the square 2 texture: + int32_t bufferSize = m_data.getGPUSize().x() * m_data.getGPUSize().y() * 8; + static etk::Vector tmpData; + if (tmpData.size() < bufferSize) { + tmpData.resize(bufferSize, 0.0f); + } + EWOL_DEBUG(" CREATE texture ==> " << m_data.getGPUSize()); + // 2 create a new empty texture: + #ifdef EWOL_USE_FBO + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_texPboId); + void* pBuff = ::glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, m_data.getGPUSize().x() * m_data.getGPUSize().y() * sizeByte, GL_MAP_WRITE_BIT); + memcpy(pBuff, &tmpData[0], m_data.getGPUSize().x()*m_data.getGPUSize().y()*sizeByte); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + glTexImage2D(GL_TEXTURE_2D, // Target + 0, // Level + typeObject, // Format internal + m_data.getGPUSize().x(), + m_data.getGPUSize().y(), + 0, // Border + typeObject, // format + sizeObject, // type + (void*)0 ); + #else + glTexImage2D(GL_TEXTURE_2D, // Target + 0, // Level + typeObject, // Format internal + m_data.getGPUSize().x(), + m_data.getGPUSize().y(), + 0, // Border + typeObject, // format + sizeObject, // type + &tmpData[0] ); + #endif + } + #ifdef EWOL_USE_FBO + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_texPboId); + void* pBuff = ::glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, m_data.getGPUSize().x() * m_data.getGPUSize().y() * sizeByte, GL_MAP_WRITE_BIT); + memcpy(pBuff, m_data.getTextureDataPointer(), m_data.getWidth()*m_data.getHeight()*sizeByte); + glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + //3 Flush all time the data: + glTexSubImage2D(GL_TEXTURE_2D, // Target + 0, // Level + 0, // x offset + 0, // y offset + m_data.getWidth(), + m_data.getHeight(), + typeObject, // format + sizeObject, // type + (void *)0 ); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + #else + //3 Flush all time the data: + echrono::Steady tic1 = echrono::Steady::now(); + glTexSubImage2D(GL_TEXTURE_2D, // Target + 0, // Level + 0, // x offset + 0, // y offset + m_data.getWidth(), + m_data.getHeight(), + typeObject, // format + sizeObject, // type + (void*)((char*)m_data.getTextureDataPointer()) ); + echrono::Steady toc2 = echrono::Steady::now(); + EWOL_INFO(" updateContext [STOP] ==> " << (toc2 - tic1)); + #endif + #else + // This is the normal case ==> set the image and after set just the update of the data + if (m_loaded == false) { + glTexImage2D(GL_TEXTURE_2D, // Target + 0, // Level + typeObject, // Format internal + m_data.getWidth(), + m_data.getHeight(), + 0, // Border + typeObject, // format + sizeObject, // type + m_data.getTextureDataPointer() ); + } else { + glTexSubImage2D(GL_TEXTURE_2D, // Target + 0, // Level + 0, // x offset + 0, // y offset + m_data.getWidth(), + m_data.getHeight(), + typeObject, // format + sizeObject, // type + m_data.getTextureDataPointer() ); + } + #endif + // now the data is loaded + m_loaded = true; + echrono::Steady toc = echrono::Steady::now(); + //EWOL_ERROR(" updateContext [STOP] ==> " << (toc - toc1)); + return true; +} + +void ewol::resource::Texture::removeContext() { + ethread::RecursiveLock lock(m_mutex); + if (m_loaded == true) { + // Request remove texture ... + EWOL_DEBUG("TEXTURE: Rm [" << getId() << "] texId=" << m_texId); + // TODO: Check if we are in the correct thread + glDeleteTextures(1, &m_texId); + m_loaded = false; + } +} + +void ewol::resource::Texture::removeContextToLate() { + ethread::RecursiveLock lock(m_mutex); + m_loaded = false; + m_texId=0; +} + +void ewol::resource::Texture::flush() { + ethread::RecursiveLock lock(m_mutex); + // request to the manager to be call at the next update ... + EWOL_VERBOSE("Request UPDATE of Element"); + getManager().update(ememory::dynamicPointerCast(sharedFromThis())); +} + +void ewol::resource::Texture::setImageSize(ivec2 _newSize) { + ethread::RecursiveLock lock(m_mutex); + _newSize.setValue( nextP2(_newSize.x()), nextP2(_newSize.y()) ); + m_data.resize(_newSize); +} + +void ewol::resource::Texture::set(egami::Image _image) { + EWOL_DEBUG("Set a new image in a texture:"); + ethread::RecursiveLock lock(m_mutex); + if (_image.exist() == false) { + EWOL_ERROR("ERROR when loading the image : [raw data]"); + return; + } + EWOL_DEBUG(" size=" << _image.getSize()); + etk::swap(m_data, _image); + ivec2 tmp = m_data.getSize(); + m_realImageSize = vec2(tmp.x(), tmp.y()); + vec2 compatibilityHWSize = vec2(nextP2(tmp.x()), nextP2(tmp.y())); + if (m_realImageSize != compatibilityHWSize) { + EWOL_VERBOSE("RESIZE Image for HArwareCompatibility:" << m_realImageSize << " => " << compatibilityHWSize); + m_data.resize(ivec2(compatibilityHWSize.x(),compatibilityHWSize.y())); + } + flush(); +} diff --git a/src/org/atriasoft/ewol/resource/Texture.java b/src/org/atriasoft/ewol/resource/Texture.java new file mode 100644 index 0000000..e7ba8ff --- /dev/null +++ b/src/org/atriasoft/ewol/resource/Texture.java @@ -0,0 +1,91 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include + +//#define EWOL_USE_FBO 1 + +namespace ewol { + namespace resource { + enum class TextureFilter { + nearest, + linear + }; + class Texture : public gale::Resource { + protected: + uint32_t m_texId; //!< openGl textureID. + #ifdef EWOL_USE_FBO + uint32_t m_texPboId; //!< openGl textureID. + #endif + // openGl Context propoerties : + egami::Image m_data; + //! Last loaded size in the system openGL + vec2 m_lastSize; + //! some image are not square == > we need to sqared it to prevent some openGl api error the the displayable size is not all the time 0.0 -> 1.0 + vec2 m_realImageSize; + // internal state of the openGl system : + bool m_loaded; + int32_t m_lastTypeObject; + int32_t m_lastSizeObject; + protected: + bool m_repeat; //!< repeate mode of the image (repeat the image if out of range [0..1] + public: + /** + * @brief Set the repeate mode of the images if UV range is out of [0..1] + * @param[in] _value Value of the new repeate mode + */ + void setRepeat(bool _value); + protected: + enum ewol::resource::TextureFilter m_filter; //!< Filter apply at the image when rendering it + public: + /** + * @brief Set the Filter mode to apply at the image when display with a scale (not 1:1 ratio) + * @param[in] _value Value of the new filter mode + */ + void setFilterMode(enum ewol::resource::TextureFilter _filter); + // Public API: + protected: + void init(const etk::String& _filename); + void init(); + Texture(); + public: + DECLARE_RESOURCE_FACTORY(Texture); + virtual ~Texture(); + public: + // You must set the size here, because it will be set in multiple of pow(2) + void setImageSize(ivec2 _newSize); + // Get the reference on this image to draw nomething on it ... + inline egami::Image& get() { + return m_data; + }; + /** + * @brief Set the image in the texture system + * @note It will reize in square2 if needed by the system. + * @param[in] _image Image to set. (use @code set(etk::move(xxx)); @endcode ) + */ + void set(egami::Image _image); + // Flush the data to send it at the openGl system + void flush(); + bool updateContext(); + void removeContext(); + void removeContextToLate(); + const ivec2& getOpenGlSize() const { + return m_data.getSize(); + }; + const vec2& getUsableSize() const { + return m_realImageSize; + }; + uint32_t getRendererId() const { + return m_texId; + }; + }; + } +} + diff --git a/src/org/atriasoft/ewol/resource/TextureFile.cpp b/src/org/atriasoft/ewol/resource/TextureFile.cpp new file mode 100644 index 0000000..f37acf8 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/TextureFile.cpp @@ -0,0 +1,119 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::resource::TextureFile); + +const ivec2 ewol::resource::TextureFile::sizeAuto(-1,-1); +const ivec2 ewol::resource::TextureFile::sizeDefault(0,0); + +/** + * @brief get the next power 2 if the input + * @param[in] _value Value that we want the next power of 2 + * @return result value + */ +static int32_t nextP2(int32_t _value) { + int32_t val=1; + for (int32_t iii=1; iii<31; iii++) { + if (_value <= val) { + return val; + } + val *=2; + } + EWOL_CRITICAL("impossible CASE.... request P2 of " << _value); + return val; +} + + +ewol::resource::TextureFile::TextureFile() { + addResourceType("ewol::resource::Image"); + +} + +void ewol::resource::TextureFile::init() { + ethread::RecursiveLock lock(m_mutex); + ewol::resource::Texture::init(); +} + +void ewol::resource::TextureFile::init(etk::String _genName, const etk::Uri& _uri, const ivec2& _size) { + ethread::RecursiveLock lock(m_mutex); + ewol::resource::Texture::init(_genName); + EWOL_DEBUG("create a new resource::Image : _genName=" << _genName << " _uri=" << _uri << " size=" << _size); + egami::Image tmp = egami::load(_uri, _size); + set(etk::move(tmp)); + //m_lastSize = m_realImageSize; + #ifdef GENERATE_DISTANCE_FIELD_MODE + //egami::generateDistanceFieldFile(_uri, etk::String(_uri, 0, _uri.size()-4) + ".bmp"); + egami::generateDistanceFieldFile(_uri, etk::String(_uri, 0, _uri.size()-4) + ".edf"); + #endif +} + +ememory::SharedPtr ewol::resource::TextureFile::create(const etk::Uri& _uri, ivec2 _size, ivec2 _sizeRegister) { + EWOL_VERBOSE("KEEP: TextureFile: '" << _uri << "' size=" << _size << " sizeRegister=" << _sizeRegister); + if (_uri.isEmpty() == true) { + ememory::SharedPtr object(ETK_NEW(ewol::resource::TextureFile)); + if (object == null) { + EWOL_ERROR("allocation error of a resource : ??TEX??"); + return null; + } + object->init(); + getManager().localAdd(object); + return object; + } + if (_size.x() == 0) { + _size.setX(-1); + //EWOL_ERROR("Error Request the image size.x() =0 ???"); + } + if (_size.y() == 0) { + _size.setY(-1); + //EWOL_ERROR("Error Request the image size.y() =0 ???"); + } + etk::Uri tmpFilename = _uri; + if (etk::toLower(_uri.getPath().getExtention()) != "svg") { + _size = ewol::resource::TextureFile::sizeAuto; + } + if (_size.x()>0 && _size.y()>0) { + EWOL_VERBOSE(" == > specific size : " << _size); + _size.setValue(nextP2(_size.x()), nextP2(_size.y())); + if (_sizeRegister != ewol::resource::TextureFile::sizeAuto) { + if (_sizeRegister != ewol::resource::TextureFile::sizeDefault) { + tmpFilename.getQuery().set("x", etk::toString(_size.x())); + tmpFilename.getQuery().set("y", etk::toString(_size.y())); + } + } + } + + EWOL_VERBOSE("KEEP: TextureFile: '" << tmpFilename << "' new size=" << _size); + ememory::SharedPtr object = null; + ememory::SharedPtr object2 = getManager().localKeep(tmpFilename.getString()); + if (object2 != null) { + object = ememory::dynamicPointerCast(object2); + if (object == null) { + EWOL_CRITICAL("Request resource file : '" << tmpFilename << "' With the wrong type (dynamic cast error)"); + return null; + } + } + if (object != null) { + return object; + } + EWOL_DEBUG("CREATE: TextureFile: '" << tmpFilename << "' size=" << _size); + // need to crate a new one ... + object = ememory::SharedPtr(ETK_NEW(ewol::resource::TextureFile)); + if (object == null) { + EWOL_ERROR("allocation error of a resource : " << _uri); + return null; + } + object->init(tmpFilename.getString(), _uri, _size); + getManager().localAdd(object); + return object; +} diff --git a/src/org/atriasoft/ewol/resource/TextureFile.java b/src/org/atriasoft/ewol/resource/TextureFile.java new file mode 100644 index 0000000..8dc61a0 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/TextureFile.java @@ -0,0 +1,47 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +// TODO : Change tis file name ... +#pragma once + +#include +#include +#include +#include + + + +namespace ewol { + namespace resource { + class TextureFile : public ewol::resource::Texture { + public: + static const ivec2 sizeAuto; + static const ivec2 sizeDefault; + protected: + TextureFile(); + void init(); + void init(etk::String _genName, const etk::Uri& _uri, const ivec2& _size); + public: + virtual ~TextureFile() { }; + public: + const vec2& getRealSize() { + return m_realImageSize; + }; + public: + /** + * @brief keep the resource pointer. + * @note Never free this pointer by your own... + * @param[in] _filename Name of the image file. + * @param[in] _requested size of the image (usefull when loading .svg to automatic rescale) + * @param[in] _sizeRegister size register in named (When you preaload the images the size write here will be ) + * @return pointer on the resource or null if an error occured. + */ + static ememory::SharedPtr create(const etk::Uri& _filename, + ivec2 _size=ewol::resource::TextureFile::sizeAuto, + ivec2 _sizeRegister=ewol::resource::TextureFile::sizeAuto); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/resource/TexturedFont.cpp b/src/org/atriasoft/ewol/resource/TexturedFont.cpp new file mode 100644 index 0000000..75fae1e --- /dev/null +++ b/src/org/atriasoft/ewol/resource/TexturedFont.cpp @@ -0,0 +1,369 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::font::mode); +ETK_DECLARE_TYPE(ewol::resource::TexturedFont); + +etk::Stream& ewol::operator <<(etk::Stream& _os, enum ewol::font::mode _obj) { + switch(_obj) { + default : + _os << "error"; + break; + case ewol::font::Regular: + _os << "Regular"; + break; + case ewol::font::Italic: + _os << "Italic"; + break; + case ewol::font::Bold: + _os << "Bold"; + break; + case ewol::font::BoldItalic: + _os << "BoldItalic"; + break; + } + return _os; +} + +ewol::resource::TexturedFont::TexturedFont(): + m_size(10) { + addResourceType("ewol::resource::TexturedFont"); +} + +/** + * @brief Get all the Path contain in the specidy path: + * @param[in] _path Generic path to parse ... + * @return The list of path found + * @example[start] + * auto out = explodeMultiplePath("DATA:///font?lib=ewol"); + * // out contain: {"DATA:///font", "DATA:///font?lib=ewol"} + * @example[stop] + */ +static etk::Vector explodeMultiplePath(const etk::Uri& _uri) { + etk::Vector out; + out.pushBack(_uri); + if (_uri.getQuery().exist("lib") == true) { + etk::Uri tmp = _uri; + tmp.getQuery().erase("lib"); + out.pushBack(tmp); + } + return out; +} + +void ewol::resource::TexturedFont::init(const etk::String& _fontName) { + ethread::RecursiveLock lock(m_mutex); + ewol::resource::Texture::init(_fontName); + EWOL_DEBUG("Load font : '" << _fontName << "'" ); + + m_font[0] = null; + m_font[1] = null; + m_font[2] = null; + m_font[3] = null; + + m_modeWraping[0] = ewol::font::Regular; + m_modeWraping[1] = ewol::font::Regular; + m_modeWraping[2] = ewol::font::Regular; + m_modeWraping[3] = ewol::font::Regular; + + m_lastGlyphPos[0].setValue(1,1); + m_lastGlyphPos[1].setValue(1,1); + m_lastGlyphPos[2].setValue(1,1); + m_lastGlyphPos[3].setValue(1,1); + + m_lastRawHeigh[0] = 0; + m_lastRawHeigh[1] = 0; + m_lastRawHeigh[2] = 0; + m_lastRawHeigh[3] = 0; + + int32_t tmpSize = 0; + // extarct name and size : + const char * tmpData = _fontName.c_str(); + const char * tmpPos = strchr(tmpData, ':'); + + if (tmpPos == null) { + m_size = 1; + EWOL_CRITICAL("Can not parse the font name: '" << _fontName << "' ??? ':' " ); + return; + } else { + if (sscanf(tmpPos+1, "%d", &tmpSize)!=1) { + m_size = 1; + EWOL_CRITICAL("Can not parse the font name: '" << _fontName << "' == > size ???"); + return; + } + } + etk::String localName(_fontName, 0, (tmpPos - tmpData)); + if (tmpSize>400) { + EWOL_ERROR("Font size too big ==> limit at 400 when exxeed ==> error: " << tmpSize << "==>30"); + tmpSize = 30; + } + m_size = tmpSize; + + etk::Vector folderList; + if (ewol::getContext().getFontDefault().getUseExternal() == true) { + #if defined(__TARGET_OS__Android) + folderList.pushBack(etk::Path("/system/fonts")); + #elif defined(__TARGET_OS__Linux) + folderList.pushBack(etk::Path("/usr/share/fonts")); + #endif + } + etk::Uri applicationBaseFont = ewol::getContext().getFontDefault().getFolder(); + for (auto &it : explodeMultiplePath(applicationBaseFont)) { + folderList.pushBack(it); + } + for (size_t folderID = 0; folderID < folderList.size() ; folderID++) { + etk::Vector output = etk::uri::listRecursive(folderList[folderID]); + + etk::Vector split = etk::split(localName, ';'); + EWOL_DEBUG("try to find font named : " << split << " in: " << output); + //EWOL_CRITICAL("parse string : " << split); + bool hasFindAFont = false; + for (size_t jjj=0; jjj= 0; iii--) { + if (m_fileName[iii].isEmpty() == false) { + refMode = (enum ewol::font::mode)iii; + } + } + EWOL_DEBUG(" set reference mode : " << refMode); + // generate the wrapping on the preventing error + for(int32_t iii=3; iii >= 0; iii--) { + if (m_fileName[iii].isEmpty() == false) { + m_modeWraping[iii] = (enum ewol::font::mode)iii; + } else { + m_modeWraping[iii] = refMode; + } + } + + for (int32_t iiiFontId=0; iiiFontId<4 ; iiiFontId++) { + if (m_fileName[iiiFontId].isEmpty() == true) { + EWOL_DEBUG("can not load FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" == > size=" << m_size ); + m_font[iiiFontId] = null; + continue; + } + EWOL_DEBUG("Load FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" == > size=" << m_size); + m_font[iiiFontId] = ewol::resource::FontFreeType::create(m_fileName[iiiFontId]); + if (m_font[iiiFontId] == null) { + EWOL_DEBUG("error in loading FONT [" << iiiFontId << "] name : \"" << m_fileName[iiiFontId] << "\" == > size=" << m_size ); + } + } + for (int32_t iiiFontId=0; iiiFontId<4 ; iiiFontId++) { + // set the bassic charset: + m_listElement[iiiFontId].clear(); + if (m_font[iiiFontId] == null) { + continue; + } + m_height[iiiFontId] = m_font[iiiFontId]->getHeight(m_size); + // TODO : basic font use 512 is better ... == > maybe estimate it with the dpi ??? + setImageSize(ivec2(256,32)); + // now we can acces directly on the image + m_data.clear(etk::Color<>(0x00000000)); + } + // add error glyph + addGlyph(0); + // by default we set only the first AINSI char availlable + for (int32_t iii=0x20; iii<0x7F; iii++) { + EWOL_VERBOSE("Add clyph :" << iii); + addGlyph(iii); + } + flush(); + EWOL_DEBUG("Wrapping properties : "); + EWOL_DEBUG(" " << ewol::font::Regular << " == >" << getWrappingMode(ewol::font::Regular)); + EWOL_DEBUG(" " << ewol::font::Italic << " == >" << getWrappingMode(ewol::font::Italic)); + EWOL_DEBUG(" " << ewol::font::Bold << " == >" << getWrappingMode(ewol::font::Bold)); + EWOL_DEBUG(" " << ewol::font::BoldItalic << " == >" << getWrappingMode(ewol::font::BoldItalic)); +} + +ewol::resource::TexturedFont::~TexturedFont() { + +} + +bool ewol::resource::TexturedFont::addGlyph(const char32_t& _val) { + ethread::RecursiveLock lock(m_mutex); + bool hasChange = false; + // for each font : + for (int32_t iii=0; iii<4 ; iii++) { + if (m_font[iii] == null) { + continue; + } + // add the curent "char" + GlyphProperty tmpchar; + tmpchar.m_UVal = _val; + + if (m_font[iii]->getGlyphProperty(m_size, tmpchar) == true) { + //EWOL_DEBUG("load char : '" << _val << "'=" << _val.get()); + hasChange = true; + // change line if needed ... + if (m_lastGlyphPos[iii].x()+tmpchar.m_sizeTexture.x()+3 > m_data.getSize().x()) { + m_lastGlyphPos[iii].setX(1); + m_lastGlyphPos[iii] += ivec2(0, m_lastRawHeigh[iii]); + m_lastRawHeigh[iii] = 0; + } + while(m_lastGlyphPos[iii].y()+tmpchar.m_sizeTexture.y()+3 > m_data.getSize().y()) { + ivec2 size = m_data.getSize(); + size.setY(size.y()*2); + m_data.resize(size, etk::Color<>(0)); + // note : need to rework all the lyer due to the fact that the texture is used by the faur type... + for (size_t kkk=0; kkk<4 ; kkk++) { + // change the coordonate on the element in the texture + for (size_t jjj=0 ; jjjdrawGlyph(m_data, m_size, m_lastGlyphPos[iii], tmpchar, iii); + // set video position + tmpchar.m_texturePosStart.setValue( (float)m_lastGlyphPos[iii].x() / (float)m_data.getSize().x(), + (float)m_lastGlyphPos[iii].y() / (float)m_data.getSize().y() ); + tmpchar.m_texturePosSize.setValue( (float)tmpchar.m_sizeTexture.x() / (float)m_data.getSize().x(), + (float)tmpchar.m_sizeTexture.y() / (float)m_data.getSize().y() ); + + // update the maximum of the line hight : + if (m_lastRawHeigh[iii] for debug test only ... + } + return hasChange; +} + +int32_t ewol::resource::TexturedFont::getIndex(char32_t _charcode, const enum ewol::font::mode _displayMode) { + ethread::RecursiveLock lock(m_mutex); + if (_charcode < 0x20) { + return 0; + } else if (_charcode < 0x80) { + return _charcode - 0x1F; + } else { + for (size_t iii=0x80-0x20; iii < m_listElement[_displayMode].size(); iii++) { + //EWOL_DEBUG("search : '" << charcode << "' =?= '" << (m_listElement[displayMode])[iii].m_UVal << "'"); + if (_charcode == (m_listElement[_displayMode])[iii].m_UVal) { + //EWOL_DEBUG("search : '" << charcode << "'"); + if ((m_listElement[_displayMode])[iii].exist()) { + //EWOL_DEBUG("return " << iii); + return iii; + } else { + return 0; + } + } + } + } + if (addGlyph(_charcode) == true) { + // TODO : This does not work due to the fact that the update of open GL is not done in the context main cycle !!! + ewol::getContext().forceRedrawAll(); + } + return 0; +} + +ewol::GlyphProperty* ewol::resource::TexturedFont::getGlyphPointer(const char32_t& _charcode, const enum ewol::font::mode _displayMode) { + ethread::RecursiveLock lock(m_mutex); + //EWOL_DEBUG("Get glyph property for mode: " << _displayMode << " == > wrapping index : " << m_modeWraping[_displayMode]); + int32_t index = getIndex(_charcode, _displayMode); + if( index < 0 + || (size_t)index >= m_listElement[_displayMode].size() ) { + EWOL_ERROR(" Try to get glyph index inexistant ... == > return the index 0 ... id=" << index); + if (m_listElement[_displayMode].size() > 0) { + return &((m_listElement[_displayMode])[0]); + } + return &m_emptyGlyph; + } + //EWOL_ERROR(" index=" << index); + //EWOL_ERROR(" m_UVal=" << m_listElement[_displayMode][index].m_UVal); + //EWOL_ERROR(" m_glyphIndex=" << m_listElement[_displayMode][index].m_glyphIndex); + //EWOL_ERROR(" m_advance=" << m_listElement[_displayMode][index].m_advance); + //EWOL_ERROR(" m_bearing=" << m_listElement[_displayMode][index].m_bearing); + return &((m_listElement[_displayMode])[index]); +} + diff --git a/src/org/atriasoft/ewol/resource/TexturedFont.java b/src/org/atriasoft/ewol/resource/TexturedFont.java new file mode 100644 index 0000000..0874cb2 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/TexturedFont.java @@ -0,0 +1,98 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include + +namespace ewol { + namespace font { + /** + * @not_in_doc + */ + enum mode { + Regular=0, + Italic, + Bold, + BoldItalic, + }; + } + etk::Stream& operator <<(etk::Stream& _os, enum ewol::font::mode _obj); + + namespace resource { + class TexturedFont : public ewol::resource::Texture { + private: + etk::Uri m_fileName[4]; + int32_t m_size; + int32_t m_height[4]; + // specific element to have the the know if the specify element is known... + // == > otherwise I can just generate italic ... + // == > Bold is a little more complicated (maybe with the bordersize) + ememory::SharedPtr m_font[4]; + enum ewol::font::mode m_modeWraping[4]; //!< This is a wrapping mode to prevent the fact that no font is define for a specific mode + public: + GlyphProperty m_emptyGlyph; + etk::Vector m_listElement[4]; + private: + // for the texture generation : + ivec2 m_lastGlyphPos[4]; + int32_t m_lastRawHeigh[4]; + protected: + TexturedFont(); + void init(const etk::String& _fontName); + public: + DECLARE_RESOURCE_NAMED_FACTORY(TexturedFont); + virtual ~TexturedFont(); + public: + /** + * @brief get the display height of this font + * @param[in] _displayMode Mode to display the currrent font + * @return Dimention of the font need between 2 lines + */ + int32_t getHeight(const enum ewol::font::mode _displayMode = ewol::font::Regular) { + return m_height[_displayMode]; + }; + /** + * @brief get the font height (user friendly) + * @return Dimention of the font the user requested + */ + int32_t getFontSize() { + return m_size; + }; + /** + * @brief get the ID of a unicode charcode + * @param[in] _charcode The unicodeValue + * @param[in] _displayMode Mode to display the currrent font + * @return The ID in the table (if it does not exist : return 0) + */ + int32_t getIndex(char32_t _charcode, const enum ewol::font::mode _displayMode); + /** + * @brief get the pointer on the coresponding glyph + * @param[in] _charcode The unicodeValue + * @param[in] _displayMode Mode to display the currrent font + * @return The pointer on the glyph == > never null + */ + ewol::GlyphProperty* getGlyphPointer(const char32_t& _charcode, const enum ewol::font::mode _displayMode); + /** + * @brief The wrapping mode is used to prevent the non existance of a specific mode. + * For exemple when a blod mode does not exist, this resend a regular mode. + * @param[in] _source The requested mode. + * @return the best mode we have in stock. + */ + enum ewol::font::mode getWrappingMode(const enum ewol::font::mode _source) { + return m_modeWraping[_source]; + }; + private: + /** + * @brief add a glyph in a texture font. + * @param[in] _val Char value to add. + * @return true if the image size have change, false otherwise + */ + bool addGlyph(const char32_t& _val); + }; + } +} + diff --git a/src/org/atriasoft/ewol/resource/font/FontBase.java b/src/org/atriasoft/ewol/resource/font/FontBase.java new file mode 100644 index 0000000..e4595d5 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/font/FontBase.java @@ -0,0 +1,55 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + + +namespace ewol { + namespace resource { + class FontBase : public gale::Resource { + public: + FontBase() { + addResourceType("ewol::FontFreeType"); + } + void init(const etk::Uri& _uri) { + gale::Resource::init(_uri); + }; + + virtual ~FontBase() { }; + + virtual bool getGlyphProperty(int32_t _fontSize, + ewol::GlyphProperty& _property) = 0; + + virtual bool drawGlyph(egami::Image& _imageOut, + int32_t _fontSize, + ivec2 _glyphPosition, + ewol::GlyphProperty& _property, + int8_t _posInImage) = 0; + + virtual bool drawGlyph(egami::ImageMono& _imageOut, + int32_t _fontSize, + ewol::GlyphProperty& _property, + int32_t _borderSize = 0) = 0; + + virtual vec2 getSize(int32_t _fontSize, const etk::String& _unicodeString) = 0; + virtual float getSizeWithHeight(float _fontHeight) = 0; + + virtual int32_t getHeight(int32_t _fontSize) = 0; + + virtual void generateKerning(int32_t _fontSize, etk::Vector& _listGlyph) { }; + + virtual void display() {}; + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/resource/font/GlyphProperty.java b/src/org/atriasoft/ewol/resource/font/GlyphProperty.java new file mode 100644 index 0000000..39a7876 --- /dev/null +++ b/src/org/atriasoft/ewol/resource/font/GlyphProperty.java @@ -0,0 +1,103 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include + +namespace ewol { + /* + | | | | + | | | | + | | | | + Y | | | | + ^ |------------| |------------| + | + m_advance.y:/-> | + | | + | | + m_sizeTex.x/-> | | |------------| |------------| + | | | | | | | + | | | | | | | + | | | | | | | + | | | | | | | + | | | | A | | G | + | | | | | | | + | | | | | | | + | | | | | | | + | | | | | | | + \-> | | |------------| |------------| + /--> | | + \--> \-> | + m_bearing.y | + |____*________________________*____________>> X + + + <------------------------> : m_advance.x + + <------------> : m_sizeTexture.x + + <---> : m_bearing.x + + */ + /** + * @not_in_doc + */ + class GlyphProperty { + public: + char32_t m_UVal; //!< Unicode value + public: + bool m_exist; + public: + int32_t m_glyphIndex; //!< Glyph index in the system + ivec2 m_sizeTexture; //!< size of the element to display + ivec2 m_bearing; //!< offset to display the data (can be negatif id the texture sise is bigger than the theoric places in the string) + ivec2 m_advance; //!< space use in the display for this specific char + vec2 m_texturePosStart; //!< Texture normalized position (START) + vec2 m_texturePosSize; //!< Texture normalized position (SIZE) + private: + etk::Vector m_kerning; //!< kerning values of link of all elements + public: + GlyphProperty() : + m_UVal(0), + m_exist(true), + m_glyphIndex(0), + m_sizeTexture(10,10), + m_bearing(2,2), + m_advance(10,10), + m_texturePosStart(0,0), + m_texturePosSize(0,0) { + + }; + float kerningGet(const char32_t _charcode) { + for(size_t iii=0; iii +#include +#include +#include +#include +#include +#include +#include + +void ewol::tools::message::create(enum ewol::tools::message::type _type, const etk::String& _message) { + ewol::widget::StdPopUpShared tmpPopUp = widget::StdPopUp::create(); + if (tmpPopUp == null) { + EWOL_ERROR("Can not create a simple pop-up"); + return; + } + switch(_type) { + case ewol::tools::message::type::info: + tmpPopUp->propertyTitle.set("_T{Info}"); + break; + case ewol::tools::message::type::warning: + tmpPopUp->propertyTitle.set("_T{Warning}"); + break; + case ewol::tools::message::type::error: + tmpPopUp->propertyTitle.set("_T{Error}"); + break; + case ewol::tools::message::type::critical: + tmpPopUp->propertyTitle.set("_T{Critical}"); + break; + } + tmpPopUp->propertyComment.set(_message); + tmpPopUp->addButton("_T{close}", true); + tmpPopUp->propertyCloseOutEvent.set(true); + // get windows: + ewol::Context& context = ewol::getContext(); + ewol::widget::WindowsShared windows = context.getWindows(); + if (windows == null) { + EWOL_ERROR("can not get the current windows ... ==> can not display message : " << _message); + return; + } + windows->popUpWidgetPush(tmpPopUp); +} + +void ewol::tools::message::displayInfo(const etk::String& _message) { + ewol::tools::message::create(ewol::tools::message::type::info, _message); +} + +void ewol::tools::message::displayWarning(const etk::String& _message) { + ewol::tools::message::create(ewol::tools::message::type::warning, _message); +} + +void ewol::tools::message::displayError(const etk::String& _message) { + ewol::tools::message::create(ewol::tools::message::type::error, _message); +} + +void ewol::tools::message::displayCritical(const etk::String& _message) { + ewol::tools::message::create(ewol::tools::message::type::critical, _message); +} + + diff --git a/src/org/atriasoft/ewol/tools/message.java b/src/org/atriasoft/ewol/tools/message.java new file mode 100644 index 0000000..f0be75d --- /dev/null +++ b/src/org/atriasoft/ewol/tools/message.java @@ -0,0 +1,52 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace ewol { + namespace tools { + namespace message { + enum class type { + info, //!< information message pop-up + warning, //!< warning message pop-up + error, //!< Error message pop-up + critical //!< Critical message pop-up + }; + /** + * @brief Create a simple pop-up message on the screen for application error. + * @param[in] _type Type of the error. + * @param[in] _message message to display (decorated text) + */ + void create(enum ewol::tools::message::type _type, const etk::String& _message); + /** + * @brief Create a simple information message + * @param[in] _message message to display (decorated text) + */ + void displayInfo(const etk::String& _message); + /** + * @brief Create a simple warning message + * @param[in] _message message to display (decorated text) + */ + void displayWarning(const etk::String& _message); + /** + * @brief Create a simple error message + * @param[in] _message message to display (decorated text) + */ + void displayError(const etk::String& _message); + /** + * @brief Create a simple critical message + * @param[in] _message message to display (decorated text) + */ + void displayCritical(const etk::String& _message); + } + } +} + diff --git a/src/org/atriasoft/ewol/widget/Button.cpp b/src/org/atriasoft/ewol/widget/Button.cpp new file mode 100644 index 0000000..0a8a51d --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Button.cpp @@ -0,0 +1,288 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Button); +ETK_DECLARE_TYPE(ewol::widget::Button::buttonLock); +// DEFINE for the shader display system: +const static int32_t STATUS_UP(0); +const static int32_t STATUS_HOVER(2); +const static int32_t STATUS_PRESSED(1); +const static int32_t STATUS_DOWN(3); + +ewol::widget::Button::Button() : + signalPressed(this, "pressed", "Button is pressed"), + signalDown(this, "down", "Button is DOWN"), + signalUp(this, "up", "Button is UP"), + signalEnter(this, "enter", "The cursor enter inside the button"), + signalLeave(this, "leave", "the cursor leave the button"), + signalValue(this, "value", "button value change"), + propertyShape(this, "shape", etk::Uri("THEME_GUI:///Button.json?lib=ewol"), "The display name for config file", &ewol::widget::Button::onChangePropertyShape), + propertyValue(this, "value", false, "Value of the Button", &ewol::widget::Button::onChangePropertyValue), + propertyLock(this, "lock", lockNone, "Lock the button in a special state to permit changing state only by the coder", &ewol::widget::Button::onChangePropertyLock), + propertyToggleMode(this, "toggle", false, "The Button can toogle", &ewol::widget::Button::onChangePropertyToggleMode), + propertyEnableSingle(this, "enable-single", false, "If one element set in the Button ==> display only set", &ewol::widget::Button::onChangePropertyEnableSingle), + m_mouseHover(false), + m_buttonPressed(false), + m_selectableAreaPos(0,0), + m_selectableAreaSize(0,0) { + addObjectType("ewol::widget::Button"); + + // set property list: + propertyLock.add(lockNone, "none"); + propertyLock.add(lockWhenPressed, "pressed"); + propertyLock.add(lockWhenReleased, "released"); + propertyLock.add(lockAccess, "access"); + + propertyCanFocus.setDirectCheck(true); + + // shaper satatus update: + CheckStatus(); + // Limit event at 1: + setMouseLimit(1); +} + +void ewol::widget::Button::init() { + ewol::widget::Container2::init(); + propertyShape.notifyChange(); +} + +ewol::widget::Button::~Button() { + +} + +void ewol::widget::Button::onChangeSize() { + ewol::Padding padding = m_shaper.getPadding(); + ewol::Padding ret = onChangeSizePadded(padding); + //EWOL_DEBUG(" configuring : origin=" << origin << " size=" << subElementSize << ""); + m_selectableAreaPos = vec2(ret.xLeft(), ret.yButtom()); + m_selectableAreaSize = m_size - (m_selectableAreaPos + vec2(ret.xRight(), ret.yTop())); +} + + +void ewol::widget::Button::calculateMinMaxSize() { + ewol::Padding padding = m_shaper.getPadding(); + calculateMinMaxSizePadded(padding); +} + +void ewol::widget::Button::onDraw() { + // draw the shaaper (if needed indeed) + m_shaper.draw(); +} + +void ewol::widget::Button::onRegenerateDisplay() { + ewol::widget::Container2::onRegenerateDisplay(); + if (needRedraw() == false) { + return; + } + ewol::Padding padding = m_shaper.getPadding(); + m_shaper.setShape(vec2(0,0), + m_size, + vec2ClipInt32(m_selectableAreaPos+vec2(padding.xLeft(),padding.yButtom()) ), + vec2ClipInt32(m_selectableAreaSize-vec2(padding.x(),padding.y()) ) ); + //EWOL_ERROR("pos=" << m_origin << " size=" << m_size); +} + +bool ewol::widget::Button::onEventInput(const ewol::event::Input& _event) { + EWOL_VERBOSE("Event on BT : " << _event); + // disable event in the lock access mode : + if(ewol::widget::Button::lockAccess == *propertyLock) { + return false; + } + if( _event.getStatus() == gale::key::status::leave + || _event.getStatus() == gale::key::status::abort) { + m_mouseHover = false; + m_buttonPressed = false; + } else { + vec2 relativePos = relativePosition(_event.getPos()); + // prevent error from ouside the button + if( relativePos.x() < m_selectableAreaPos.x() + || relativePos.y() < m_selectableAreaPos.y() + || relativePos.x() > m_selectableAreaPos.x() + m_selectableAreaSize.x() + || relativePos.y() > m_selectableAreaPos.y() + m_selectableAreaSize.y() ) { + m_mouseHover = false; + m_buttonPressed = false; + } else { + m_mouseHover = true; + } + } + EWOL_VERBOSE("Event on BT ... mouse hover : " << m_mouseHover); + if (m_mouseHover == true) { + if (_event.getId() == 1) { + if(_event.getStatus() == gale::key::status::down) { + EWOL_VERBOSE(*propertyName << " : Generate event : " << signalDown); + signalDown.emit(); + m_buttonPressed = true; + markToRedraw(); + } + if(_event.getStatus() == gale::key::status::up) { + EWOL_VERBOSE(*propertyName << " : Generate event : " << signalUp); + signalUp.emit(); + m_buttonPressed = false; + markToRedraw(); + } + if(_event.getStatus() == gale::key::status::pressSingle) { + if ( ( *propertyValue == true + && *propertyLock == ewol::widget::Button::lockWhenPressed) + || ( *propertyValue == false + && *propertyLock == ewol::widget::Button::lockWhenReleased) ) { + // nothing to do : Lock mode ... + // user might set himself the new correct value with @ref setValue(xxx) + } else { + // inverse value : + propertyValue.set((*propertyValue)?false:true); + EWOL_VERBOSE(*propertyName << " : Generate event : " << signalPressed); + signalPressed.emit(); + EWOL_VERBOSE(*propertyName << " : Generate event : " << signalValue << " val=" << *propertyValue ); + signalValue.emit(*propertyValue); + if( *propertyToggleMode == false + && *propertyValue == true) { + propertyValue.set(false); + EWOL_VERBOSE(*propertyName << " : Generate event : " << signalValue << " val=" << *propertyValue); + signalValue.emit(*propertyValue); + } + } + markToRedraw(); + } + } + } + CheckStatus(); + return m_mouseHover; +} + + +bool ewol::widget::Button::onEventEntry(const ewol::event::Entry& _event) { + //EWOL_DEBUG("BT PRESSED : \"" << UTF8_data << "\" size=" << strlen(UTF8_data)); + if( _event.getType() == gale::key::keyboard::character + && _event.getStatus() == gale::key::status::down + && _event.getChar() == '\r') { + signalEnter.emit(); + return true; + } + return false; +} + +void ewol::widget::Button::onLostFocus() { + m_buttonPressed = false; + EWOL_VERBOSE(propertyName.get() << " : Remove Focus ..."); + CheckStatus(); +} + +void ewol::widget::Button::CheckStatus() { + if (m_buttonPressed == true) { + changeStatusIn(STATUS_PRESSED); + return; + } + if (m_mouseHover == true) { + changeStatusIn(STATUS_HOVER); + return; + } + if (*propertyValue == true) { + changeStatusIn(STATUS_DOWN); + } + changeStatusIn(STATUS_UP); +} + +void ewol::widget::Button::changeStatusIn(int32_t _newStatusId) { + if (m_shaper.changeStatusIn(_newStatusId) == true) { + m_PCH = getObjectManager().periodicCall.connect(this, &ewol::widget::Button::periodicCall); + markToRedraw(); + } +} + + +void ewol::widget::Button::periodicCall(const ewol::event::Time& _event) { + if (m_shaper.periodicCall(_event) == false) { + m_PCH.disconnect(); + } + markToRedraw(); +} + +void ewol::widget::Button::onChangePropertyShape() { + m_shaper.setSource(*propertyShape); + markToRedraw(); +} +void ewol::widget::Button::onChangePropertyValue() { + if (*propertyToggleMode == true) { + if (*propertyValue == false) { + m_idWidgetDisplayed = 0; + } else { + m_idWidgetDisplayed = 1; + } + } + if (*propertyEnableSingle == true) { + if ( m_idWidgetDisplayed == 0 + && m_subWidget[0] == null + && m_subWidget[1] != null) { + m_idWidgetDisplayed = 1; + } else if ( m_idWidgetDisplayed == 1 + && m_subWidget[1] == null + && m_subWidget[0] != null) { + m_idWidgetDisplayed = 0; + } + } + CheckStatus(); + markToRedraw(); +} + +void ewol::widget::Button::onChangePropertyLock() { + if(ewol::widget::Button::lockAccess == *propertyLock) { + m_buttonPressed = false; + m_mouseHover = false; + } + CheckStatus(); + markToRedraw(); +} + +void ewol::widget::Button::onChangePropertyToggleMode() { + if (*propertyValue == true) { + propertyValue.setDirect(false); + // TODO : change display and send event ... + } + if (*propertyToggleMode == false) { + m_idWidgetDisplayed = 0; + } else { + if (*propertyValue == false) { + m_idWidgetDisplayed = 0; + } else { + m_idWidgetDisplayed = 1; + } + } + if (*propertyEnableSingle == true) { + if ( m_idWidgetDisplayed == 0 + && m_subWidget[0] == null + && m_subWidget[1] != null) { + m_idWidgetDisplayed = 1; + } else if ( m_idWidgetDisplayed == 1 + && m_subWidget[1] == null + && m_subWidget[0] != null) { + m_idWidgetDisplayed = 0; + } + } + CheckStatus(); + markToRedraw(); +} + +void ewol::widget::Button::onChangePropertyEnableSingle() { + if (*propertyEnableSingle == true) { + if ( m_idWidgetDisplayed == 0 + && m_subWidget[0] == null + && m_subWidget[1] != null) { + m_idWidgetDisplayed = 1; + } else if ( m_idWidgetDisplayed == 1 + && m_subWidget[1] == null + && m_subWidget[0] != null) { + m_idWidgetDisplayed = 0; + } else if ( m_subWidget[0] == null + && m_subWidget[1] == null) { + m_idWidgetDisplayed = 0; + } + } +} diff --git a/src/org/atriasoft/ewol/widget/Button.java b/src/org/atriasoft/ewol/widget/Button.java new file mode 100644 index 0000000..55c168c --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Button.java @@ -0,0 +1,107 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + + + +namespace ewol { + namespace widget { + class Button; + using ButtonShared = ememory::SharedPtr; + using ButtonWeak = ememory::WeakPtr; + /** + * @brief a composed button is a button with an inside composed with the specify XML element + * ==> this permit to generate standard element simple + */ + class Button : public ewol::widget::Container2 { + public: + enum buttonLock{ + lockNone, //!< normal status of the button + lockWhenPressed, //!< When the state is set in pressed, the status stay in this one + lockWhenReleased, //!< When the state is set in not pressed, the status stay in this one + lockAccess, //!< all event are trashed == > acctivity of the button is disable + }; + public: // Event list + esignal::Signal<> signalPressed; + esignal::Signal<> signalDown; + esignal::Signal<> signalUp; + esignal::Signal<> signalEnter; + esignal::Signal<> signalLeave; + esignal::Signal signalValue; + public: // propertie list + eproperty::Value propertyShape; //!< shaper name property + eproperty::Value propertyValue; //!< Current state of the button. + eproperty::List propertyLock; //!< Current lock state of the button. + eproperty::Value propertyToggleMode; //!< The button is able to toggle. + eproperty::Value propertyEnableSingle; //!< When a single subwidget is set display all time it. + private: + ewol::compositing::Shaper m_shaper; //!< Compositing theme. + protected: + /** + * @brief Constructor + * @param[in] _shaperName Shaper file properties + */ + Button(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(Button, "Button"); + /** + * @brief Destructor + */ + virtual ~Button(); + private: + bool m_mouseHover; //!< Flag to know where the mouse is (inside the displayed widget (if not fill)). + bool m_buttonPressed; //!< Flag to know if the button is curently pressed. + // hover area : + vec2 m_selectableAreaPos; //!< Start position of the events + vec2 m_selectableAreaSize; //!< size of the event positions + private: + /** + * @brief internal system to change the property of the current status + * @param[in] _newStatusId new state + */ + void changeStatusIn(int32_t _newStatusId); + /** + * @brief update the status with the internal satte of the button ... + */ + void CheckStatus(); + protected: // Derived function + virtual void onDraw() override; + public: + void calculateMinMaxSize() override; + void onChangeSize() override; + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + bool onEventEntry(const ewol::event::Entry& _event) override; + void onDetectPresenceToggleWidget() override { + propertyToggleMode.set(true); + } + protected: + esignal::Connection m_PCH; //!< Periodic Call Handle to remove it when needed + /** + * @brief Periodic call to update grapgic display + * @param[in] _event Time generic event + */ + void periodicCall(const ewol::event::Time& _event); + void onLostFocus() override; + protected: + virtual void onChangePropertyShape(); + virtual void onChangePropertyValue(); + virtual void onChangePropertyLock(); + virtual void onChangePropertyToggleMode(); + virtual void onChangePropertyEnableSingle(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/ButtonColor.cpp b/src/org/atriasoft/ewol/widget/ButtonColor.cpp new file mode 100644 index 0000000..e60077d --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ButtonColor.cpp @@ -0,0 +1,228 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::ButtonColor); + +// DEFINE for the shader display system : +#define STATUS_UP (0) +#define STATUS_HOVER (2) +#define STATUS_PRESSED (1) +#define STATUS_DOWN (3) + +ewol::widget::ButtonColor::ButtonColor() : + signalChange(this, "change", "Button color change value"), + propertyValue(this, "color", etk::color::black, "Current color", &ewol::widget::ButtonColor::onChangePropertyValue), + propertyShape(this, "shape", etk::Uri("THEME_GUI:///Button.json?lib=ewol"), "shape of the widget", &ewol::widget::ButtonColor::onChangePropertyShape), + m_widgetContextMenu(null) { + addObjectType("ewol::widget::ButtonColor"); + changeStatusIn(STATUS_UP); + // Limit event at 1: + setMouseLimit(1); + propertyCanFocus.setDirectCheck(true); +} + +void ewol::widget::ButtonColor::init() { + ewol::Widget::init(); + propertyShape.notifyChange(); + propertyValue.notifyChange(); +} + +ewol::widget::ButtonColor::~ButtonColor() { + +} + +void ewol::widget::ButtonColor::calculateMinMaxSize() { + ewol::Padding padding = m_shaper.getPadding(); + etk::String label = propertyValue.getString(); + vec3 minSize = m_text.calculateSize(label); + m_minSize.setX(padding.x()*2 + minSize.x() + 7); + m_minSize.setY(padding.y()*2 + minSize.y() ); + markToRedraw(); +} + + + +void ewol::widget::ButtonColor::onDraw() { + m_shaper.draw(); + m_text.draw(); +} + + +void ewol::widget::ButtonColor::onRegenerateDisplay() { + if (needRedraw() == false) { + return; + } + EWOL_DEBUG("redraw"); + m_text.clear(); + m_shaper.clear(); + + ewol::Padding padding = m_shaper.getPadding(); + + etk::String label = propertyValue.getString(); + + ivec2 localSize = m_minSize; + + vec3 tmpOrigin((m_size.x() - m_minSize.x()) / 2.0, + (m_size.y() - m_minSize.y()) / 2.0, + 0); + // no change for the text orogin : + vec3 tmpTextOrigin((m_size.x() - m_minSize.x()) / 2.0, + (m_size.y() - m_minSize.y()) / 2.0, + 0); + + if (propertyFill->x() == true) { + localSize.setX(m_size.x()); + tmpOrigin.setX(0); + tmpTextOrigin.setX(0); + } + if (propertyFill->y() == true) { + localSize.setY(m_size.y()); + } + tmpOrigin += vec3(padding.xLeft(), padding.yButtom(), 0); + tmpTextOrigin += vec3(padding.xLeft(), padding.yButtom(), 0); + localSize -= ivec2(padding.x(), padding.y()); + + // clean the element + m_text.reset(); + if( propertyValue.get().r() < 100 + || propertyValue.get().g() < 100 + || propertyValue.get().b() < 100) { + m_text.setColor(etk::color::white); + } else { + m_text.setColor(etk::color::black); + } + m_text.setPos(tmpTextOrigin); + m_text.setColorBg(propertyValue.get()); + m_text.setTextAlignement(tmpTextOrigin.x(), tmpTextOrigin.x()+localSize.x(), ewol::compositing::alignCenter); + m_text.print(label); + + + if (propertyFill->y() == true) { + tmpOrigin.setY(padding.yButtom()); + } + + // selection area : + m_selectableAreaPos = vec2(tmpOrigin.x()-padding.xLeft(), tmpOrigin.y()-padding.yButtom()); + m_selectableAreaSize = localSize + vec2(padding.x(),padding.y()); + vec3 tmpp = m_text.calculateSize(label); + m_shaper.setShape(m_selectableAreaPos, + m_selectableAreaSize, + vec2(tmpTextOrigin.x(), tmpTextOrigin.y()), + vec2(tmpp.x(), tmpp.y())); +} + + +bool ewol::widget::ButtonColor::onEventInput(const ewol::event::Input& _event) { + bool previousHoverState = m_mouseHover; + if(gale::key::status::leave == _event.getStatus()) { + m_mouseHover = false; + m_buttonPressed = false; + } else { + vec2 relativePos = relativePosition(_event.getPos()); + // prevent error from ouside the button + if( relativePos.x() < m_selectableAreaPos.x() + || relativePos.y() < m_selectableAreaPos.y() + || relativePos.x() > m_selectableAreaPos.x() + m_selectableAreaSize.x() + || relativePos.y() > m_selectableAreaPos.y() + m_selectableAreaSize.y() ) { + m_mouseHover = false; + m_buttonPressed = false; + } else { + m_mouseHover = true; + } + } + bool previousPressed = m_buttonPressed; + //EWOL_DEBUG("Event on BT ... mouse position : " << m_mouseHover); + if (true == m_mouseHover) { + if (1 == _event.getId()) { + if(gale::key::status::down == _event.getStatus()) { + m_buttonPressed = true; + markToRedraw(); + } + if(gale::key::status::up == _event.getStatus()) { + m_buttonPressed = false; + markToRedraw(); + } + if(gale::key::status::pressSingle == _event.getStatus()) { + m_buttonPressed = false; + m_mouseHover = false; + // create a context menu : + m_widgetContextMenu = ewol::widget::ContextMenu::create(); + if (m_widgetContextMenu == null) { + EWOL_ERROR("Allocation Error"); + return true; + } + vec2 tmpPos = m_origin + m_selectableAreaPos + m_selectableAreaSize; + tmpPos.setX( tmpPos.x() - m_minSize.x()/2.0); + m_widgetContextMenu->setPositionMark(ewol::widget::ContextMenu::markButtom, tmpPos ); + + ewol::widget::ColorChooserShared myColorChooser = widget::ColorChooser::create(); + myColorChooser->propertyValue.set(propertyValue.get()); + // set it in the pop-up-system : + m_widgetContextMenu->setSubWidget(myColorChooser); + myColorChooser->signalChange.connect(sharedFromThis(), &ewol::widget::ButtonColor::onCallbackColorChange); + ewol::widget::WindowsShared currentWindows = getWindows(); + if (currentWindows == null) { + EWOL_ERROR("Can not get the curent Windows..."); + m_widgetContextMenu.reset(); + } else { + currentWindows->popUpWidgetPush(m_widgetContextMenu); + } + markToRedraw(); + } + } + } + if( m_mouseHover != previousHoverState + || m_buttonPressed != previousPressed) { + if (m_buttonPressed == true) { + changeStatusIn(STATUS_PRESSED); + } else { + if (m_mouseHover == true) { + changeStatusIn(STATUS_HOVER); + } else { + changeStatusIn(STATUS_UP); + } + } + } + return m_mouseHover; +} + +void ewol::widget::ButtonColor::onCallbackColorChange(const etk::Color<>& _color) { + propertyValue.set(_color); +} + +void ewol::widget::ButtonColor::changeStatusIn(int32_t _newStatusId) { + if (m_shaper.changeStatusIn(_newStatusId) == true) { + m_PCH = getObjectManager().periodicCall.connect(this, &ewol::widget::ButtonColor::periodicCall); + markToRedraw(); + } +} + +void ewol::widget::ButtonColor::periodicCall(const ewol::event::Time& _event) { + if (m_shaper.periodicCall(_event) == false) { + m_PCH.disconnect(); + } + markToRedraw(); +} + +void ewol::widget::ButtonColor::onChangePropertyValue() { + signalChange.emit(propertyValue); +} + +void ewol::widget::ButtonColor::onChangePropertyShape() { + m_shaper.setSource(propertyShape.get()); + markToRedraw(); +} + diff --git a/src/org/atriasoft/ewol/widget/ButtonColor.java b/src/org/atriasoft/ewol/widget/ButtonColor.java new file mode 100644 index 0000000..0719794 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ButtonColor.java @@ -0,0 +1,78 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class ButtonColor; + using ButtonColorShared = ememory::SharedPtr; + using ButtonColorWeak = ememory::WeakPtr; + class ButtonColor : public ewol::Widget { + public: // signals + esignal::Signal> signalChange; + public: // properties + eproperty::Value> propertyValue; //!< Current color. + eproperty::Value propertyShape; //!< Current color. + private: + ewol::compositing::Shaper m_shaper; //!< Compositing theme. + ewol::compositing::Text m_text; //!< Compositing Test display. + ewol::widget::ContextMenuShared m_widgetContextMenu; //!< Specific context menu. + bool m_mouseHover; //!< Flag to know where the mouse is (inside the displayed widget (if not fill)). + bool m_buttonPressed; //!< Flag to know if the button is curently pressed. + // hover area : + vec2 m_selectableAreaPos; //!< Start position of the events + vec2 m_selectableAreaSize; //!< size of the event positions + protected: + /** + * @brief Main constructor. + * @param[in] _baseColor basic displayed color. + * @param[in] _shaperName The new shaper filename. + */ + ButtonColor(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(ButtonColor, "ButtonColor"); + /** + * @brief Main destructor. + */ + virtual ~ButtonColor(); + protected: + void onDraw() override; + public: + void calculateMinMaxSize() override; + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + private: + /** + * @brief internal system to change the property of the current status + * @param[in] _newStatusId new state + */ + void changeStatusIn(int32_t _newStatusId); + esignal::Connection m_PCH; //!< Periodic call handle to remove it when needed + /** + * @brief Periodic call to update grapgic display + * @param[in] _event Time generic event + */ + void periodicCall(const ewol::event::Time& _event); + // Callback function: + void onCallbackColorChange(const etk::Color<>& _color); + protected: + virtual void onChangePropertyValue(); + virtual void onChangePropertyShape(); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/CheckBox.cpp b/src/org/atriasoft/ewol/widget/CheckBox.cpp new file mode 100644 index 0000000..6596481 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/CheckBox.cpp @@ -0,0 +1,216 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::CheckBox); + +// DEFINE for the shader display system : +#define STATUS_UP (0) +#define STATUS_HOVER (2) +#define STATUS_PRESSED (1) +#define STATUS_SELECTED (2) + +ewol::widget::CheckBox::CheckBox() : + signalPressed(this, "pressed", "CheckBox is pressed"), + signalDown(this, "down", "CheckBox is DOWN"), + signalUp(this, "up", "CheckBox is UP"), + signalEnter(this, "enter", "The cursor enter inside the CheckBox"), + signalValue(this, "value", "CheckBox value change"), + propertyValue(this, "value", + false, + "Basic value of the widget", + &ewol::widget::CheckBox::onChangePropertyValue), + propertyShape(this, "shape", + etk::Uri("THEME_GUI:///CheckBox.json?lib=ewol"), + "The display name for config file", + &ewol::widget::CheckBox::onChangePropertyShape), + m_mouseHover(false), + m_buttonPressed(false), + m_selectableAreaPos(0,0), + m_selectableAreaSize(0,0), + m_shaperIdSize(-1), + m_shaperIdSizeInsize(-1) { + addObjectType("ewol::widget::CheckBox"); + // shaper satatus update: + CheckStatus(); + propertyCanFocus.setDirectCheck(true); + // Limit event at 1: + setMouseLimit(1); +} + + +void ewol::widget::CheckBox::init() { + ewol::widget::Container2::init(); + propertyShape.notifyChange(); +} + +ewol::widget::CheckBox::~CheckBox() { + +} + +void ewol::widget::CheckBox::onChangeSize() { + ewol::Padding padding = m_shaper.getPadding(); + float boxSize = m_shaper.getConfigNumber(m_shaperIdSize); + padding.setXLeft(padding.xLeft()*2.0f + boxSize); + ewol::Padding ret = onChangeSizePadded(padding); + EWOL_DEBUG(" configuring : padding=" << padding << " boxSize=" << boxSize << ""); + m_selectableAreaPos = vec2(ret.xLeft()/*-boxSize*/, ret.yButtom()); + m_selectableAreaSize = m_size - (m_selectableAreaPos + vec2(ret.xRight(), ret.yTop())); +} + +void ewol::widget::CheckBox::calculateMinMaxSize() { + ewol::Padding padding = m_shaper.getPadding(); + float boxSize = m_shaper.getConfigNumber(m_shaperIdSize); + padding.setXLeft(padding.xLeft()*2.0f + boxSize); + calculateMinMaxSizePadded(padding); + if (m_minSize.y() < padding.y()+boxSize) { + m_minSize.setY(padding.y()+boxSize); + } +} + +void ewol::widget::CheckBox::onDraw() { + // draw the shaaper (if needed indeed) + m_shaper.draw(); +} + +void ewol::widget::CheckBox::onRegenerateDisplay() { + ewol::widget::Container2::onRegenerateDisplay(); + if (needRedraw() == false) { + return; + } + ewol::Padding padding = m_shaper.getPadding(); + float boxSize = m_shaper.getConfigNumber(m_shaperIdSize); + float boxInside = m_shaper.getConfigNumber(m_shaperIdSizeInsize); + m_shaper.clear(); + EWOL_DEBUG(" configuring : boxSize=" << boxSize << " boxInside=" << boxInside << ""); + vec2 origin(m_selectableAreaPos + vec2(0, (m_selectableAreaSize.y() - (boxSize+padding.y()))*0.5f)); + vec2 size = vec2(boxSize+padding.x(), boxSize+padding.y()); + + vec2 origin2 = m_selectableAreaPos + vec2((boxSize-boxInside)*0.5f, (m_selectableAreaSize.y() - (boxInside+padding.y()))*0.5f); + vec2 size2 = vec2(boxInside+padding.x(), boxInside+padding.y()); + m_shaper.setShape(vec2ClipInt32(origin), + vec2ClipInt32(size), + vec2ClipInt32(origin2+vec2(padding.xLeft(),padding.yButtom()) ), + vec2ClipInt32(size2-vec2(padding.x(),padding.y()) )); +} + +bool ewol::widget::CheckBox::onEventInput(const ewol::event::Input& _event) { + EWOL_VERBOSE("Event on BT : " << _event); + + bool previousHoverState = m_mouseHover; + if( gale::key::status::leave == _event.getStatus() + || gale::key::status::abort == _event.getStatus()) { + m_mouseHover = false; + m_buttonPressed = false; + } else { + vec2 relativePos = relativePosition(_event.getPos()); + // prevent error from ouside the button + if( relativePos.x() < m_selectableAreaPos.x() + || relativePos.y() < m_selectableAreaPos.y() + || relativePos.x() > m_selectableAreaPos.x() + m_selectableAreaSize.x() + || relativePos.y() > m_selectableAreaPos.y() + m_selectableAreaSize.y() ) { + m_mouseHover = false; + m_buttonPressed = false; + } else { + m_mouseHover = true; + } + } + bool previousPressed = m_buttonPressed; + EWOL_VERBOSE("Event on BT ... mouse hover : " << m_mouseHover); + if (m_mouseHover == true) { + if (_event.getId() == 1) { + if(gale::key::status::down == _event.getStatus()) { + EWOL_VERBOSE(*propertyName << " : Generate event : " << signalDown); + signalDown.emit(); + m_buttonPressed = true; + markToRedraw(); + } + if(gale::key::status::up == _event.getStatus()) { + EWOL_VERBOSE(*propertyName << " : Generate event : " << signalUp); + signalUp.emit(); + m_buttonPressed = false; + markToRedraw(); + } + if(gale::key::status::pressSingle == _event.getStatus()) { + // inverse value : + propertyValue.set((*propertyValue)?false:true); + EWOL_VERBOSE(*propertyName << " : Generate event : " << signalPressed); + signalPressed.emit(); + EWOL_VERBOSE(*propertyName << " : Generate event : " << signalValue << " val=" << propertyValue ); + signalValue.emit(*propertyValue); + markToRedraw(); + } + } + } + if( m_mouseHover != previousHoverState + || m_buttonPressed != previousPressed) { + CheckStatus(); + } + return m_mouseHover; +} + + +bool ewol::widget::CheckBox::onEventEntry(const ewol::event::Entry& _event) { + //EWOL_DEBUG("BT PRESSED : \"" << UTF8_data << "\" size=" << strlen(UTF8_data)); + if( _event.getType() == gale::key::keyboard::character + && _event.getStatus() == gale::key::status::down + && _event.getChar() == '\r') { + signalEnter.emit(); + return true; + } + return false; +} + +void ewol::widget::CheckBox::CheckStatus() { + if (m_shaper.setState(*propertyValue==true?1:0) == true) { + markToRedraw(); + } + if (m_buttonPressed == true) { + changeStatusIn(STATUS_PRESSED); + return; + } + if (m_mouseHover == true) { + changeStatusIn(STATUS_HOVER); + return; + } + changeStatusIn(STATUS_UP); +} + +void ewol::widget::CheckBox::changeStatusIn(int32_t _newStatusId) { + if (m_shaper.changeStatusIn(_newStatusId) == true) { + m_PCH = getObjectManager().periodicCall.connect(this, &ewol::widget::CheckBox::periodicCall); + markToRedraw(); + } +} + + +void ewol::widget::CheckBox::periodicCall(const ewol::event::Time& _event) { + if (m_shaper.periodicCall(_event) == false) { + m_PCH.disconnect(); + } + markToRedraw(); +} + +void ewol::widget::CheckBox::onChangePropertyShape() { + m_shaper.setSource(*propertyShape); + m_shaperIdSize = m_shaper.requestConfig("box-size"); + m_shaperIdSizeInsize = m_shaper.requestConfig("box-inside"); + markToRedraw(); +} + +void ewol::widget::CheckBox::onChangePropertyValue() { + if (*propertyValue == false) { + m_idWidgetDisplayed = convertId(0); + } else { + m_idWidgetDisplayed = convertId(1); + } + CheckStatus(); + markToRedraw(); + m_shaper.setActivateState(*propertyValue==true?1:0); +} diff --git a/src/org/atriasoft/ewol/widget/CheckBox.java b/src/org/atriasoft/ewol/widget/CheckBox.java new file mode 100644 index 0000000..b5059b3 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/CheckBox.java @@ -0,0 +1,85 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + + +namespace ewol { + namespace widget { + class CheckBox; + using CheckBoxShared = ememory::SharedPtr; + using CheckBoxWeak = ememory::WeakPtr; + class CheckBox : public ewol::widget::Container2 { + public: // Event list + esignal::Signal<> signalPressed; + esignal::Signal<> signalDown; + esignal::Signal<> signalUp; + esignal::Signal<> signalEnter; + esignal::Signal signalValue; + public: // propertie list + eproperty::Value propertyValue; //!< Current state of the checkbox. + eproperty::Value propertyShape; //!< shape of the widget + private: + ewol::compositing::Shaper m_shaper; //!< Compositing theme. + bool m_mouseHover; //!< Flag to know where the mouse is (inside the displayed widget (if not fill)). + bool m_buttonPressed; //!< Flag to know if the button is curently pressed. + // hover area : + vec2 m_selectableAreaPos; //!< Start position of the events + vec2 m_selectableAreaSize; //!< size of the event positions + // shaper ids: + int32_t m_shaperIdSize; + int32_t m_shaperIdSizeInsize; + protected: + /** + * @brief Main checkbox constructor + * @param[in] _shaperName Shaper file properties + */ + CheckBox(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(CheckBox, "CheckBox"); + /** + * @brief main destructor. + */ + virtual ~CheckBox(); + protected: + /** + * @brief internal system to change the property of the current status + * @param[in] _newStatusId new state + */ + void changeStatusIn(int32_t _newStatusId); + /** + * @brief update the status with the internal satte of the button ... + */ + void CheckStatus(); + protected: + void onDraw() override; + public: + void calculateMinMaxSize() override; + void onChangeSize() override; + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + bool onEventEntry(const ewol::event::Entry& _event) override; + protected: + esignal::Connection m_PCH; //!< Periodic call handle to remove it when needed + /** + * @brief Periodic call to update grapgic display + * @param[in] _event Time generic event + */ + void periodicCall(const ewol::event::Time& _event); + protected: + virtual void onChangePropertyShape(); + virtual void onChangePropertyValue(); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/ColorBar.cpp b/src/org/atriasoft/ewol/widget/ColorBar.cpp new file mode 100644 index 0000000..f66dc33 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ColorBar.cpp @@ -0,0 +1,223 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +#include + +#include +#include +ETK_DECLARE_TYPE(ewol::widget::ColorBar); + +ewol::widget::ColorBar::ColorBar() : + signalChange(this, "change", "Color value change"), + propertyValue(this, "color", + etk::color::black, + "Current color", + &ewol::widget::ColorBar::onChangePropertyValue) { + addObjectType("ewol::widget::ColorBar"); + m_currentUserPos.setValue(0,0); + propertyCanFocus.setDirectCheck(true); + setMouseLimit(1); +} + +ewol::widget::ColorBar::~ColorBar() { + +} + + +void ewol::widget::ColorBar::calculateMinMaxSize() { + m_minSize.setValue(160, 80); + markToRedraw(); +} + +static etk::Color<> s_listColorWhite(0xFF, 0xFF, 0xFF, 0xFF); +static etk::Color<> s_listColorBlack(0x00, 0x00, 0x00, 0xFF); +#define NB_BAND_COLOR (6) +static etk::Color<> s_listColor[NB_BAND_COLOR+1] = { + etk::Color<>(0xFF, 0x00, 0x00, 0xFF), + etk::Color<>(0xFF, 0xFF, 0x00, 0xFF), + etk::Color<>(0x00, 0xFF, 0x00, 0xFF), + etk::Color<>(0x00, 0xFF, 0xFF, 0xFF), + etk::Color<>(0x00, 0x00, 0xFF, 0xFF), + etk::Color<>(0xFF, 0x00, 0xFF, 0xFF), + etk::Color<>(0xFF, 0x00, 0x00, 0xFF)}; + + +void ewol::widget::ColorBar::onChangePropertyValue() { + propertyValue.getDirect().setA(0xFF); + // estimate the cursor position: + EWOL_TODO("Later when really needed ..."); +} + +void ewol::widget::ColorBar::onDraw() { + m_draw.draw(); +} + + +void ewol::widget::ColorBar::onRegenerateDisplay() { + if (needRedraw() == true) { + return; + } + // clean the object list ... + m_draw.clear(); + + int32_t tmpSizeX = m_minSize.x(); + int32_t tmpSizeY = m_minSize.y(); + int32_t tmpOriginX = (m_size.x() - m_minSize.x()) / 2; + int32_t tmpOriginY = (m_size.y() - m_minSize.y()) / 2; + + if (propertyFill->x() == true) { + tmpSizeX = m_size.x(); + tmpOriginX = 0; + } + if (propertyFill->y() == true) { + tmpSizeY = m_size.y(); + tmpOriginY = 0; + } + + for(int32_t iii=0; iii 0.5) { + m_draw.setColor(etk::color::white); + } else { + m_draw.setColor(etk::color::black); + } + m_draw.setPos(vec3(m_currentUserPos.x()*m_size.x(), m_currentUserPos.y()*m_size.y(), 0) ); + m_draw.setThickness(1); + m_draw.circle(3.0); +} + + +bool ewol::widget::ColorBar::onEventInput(const ewol::event::Input& _event) { + vec2 relativePos = relativePosition(_event.getPos()); + //EWOL_DEBUG("Event on BT ..."); + if (1 == _event.getId()) { + relativePos.setValue( etk::avg(0.0f, m_size.x(),relativePos.x()), + etk::avg(0.0f, m_size.y(),relativePos.y()) ); + if( gale::key::status::pressSingle == _event.getStatus() + || gale::key::status::move == _event.getStatus()) { + // nothing to do ... + m_currentUserPos.setValue( relativePos.x()/m_size.x(), + relativePos.y()/m_size.y() ); + markToRedraw(); + // == > try to estimate color + EWOL_VERBOSE("event on (" << relativePos.x() << "," << relativePos.y() << ")"); + int32_t bandID = (int32_t)(relativePos.x()/(m_size.x()/6)); + float localPos = relativePos.x() - (m_size.x()/6) * bandID; + float poroportionnalPos = localPos/(m_size.x()/6); + EWOL_VERBOSE("bandId=" << bandID << " relative pos=" << localPos); + etk::Color<> estimateColor = etk::color::white; + if (s_listColor[bandID].r() == s_listColor[bandID+1].r()) { + estimateColor.setR(s_listColor[bandID].r()); + } else if (s_listColor[bandID].r() < s_listColor[bandID+1].r()) { + estimateColor.setR(s_listColor[bandID].r() + (s_listColor[bandID+1].r()-s_listColor[bandID].r())*poroportionnalPos); + } else { + estimateColor.setR(s_listColor[bandID+1].r() + (s_listColor[bandID].r()-s_listColor[bandID+1].r())*(1-poroportionnalPos)); + } + if (s_listColor[bandID].g() == s_listColor[bandID+1].g()) { + estimateColor.setG(s_listColor[bandID].g()); + } else if (s_listColor[bandID].g() < s_listColor[bandID+1].g()) { + estimateColor.setG(s_listColor[bandID].g() + (s_listColor[bandID+1].g()-s_listColor[bandID].g())*poroportionnalPos); + } else { + estimateColor.setG(s_listColor[bandID+1].g() + (s_listColor[bandID].g()-s_listColor[bandID+1].g())*(1-poroportionnalPos)); + } + if (s_listColor[bandID].b() == s_listColor[bandID+1].b()) { + estimateColor.setB(s_listColor[bandID].b()); + } else if (s_listColor[bandID].b() < s_listColor[bandID+1].b()) { + estimateColor.setB(s_listColor[bandID].b() + (s_listColor[bandID+1].b()-s_listColor[bandID].b())*poroportionnalPos); + } else { + estimateColor.setB(s_listColor[bandID+1].b() + (s_listColor[bandID].b()-s_listColor[bandID+1].b())*(1-poroportionnalPos)); + } + // step 2 generate the white and black ... + if (m_currentUserPos.y() == 0.5) { + // nothing to do ... just get the current color ... + } else if (m_currentUserPos.y() < 0.5) { + float poroportionnalWhite = (0.5-m_currentUserPos.y())*2.0; + estimateColor.setR(estimateColor.r() + (0xFF-estimateColor.r())*poroportionnalWhite); + estimateColor.setG(estimateColor.g() + (0xFF-estimateColor.g())*poroportionnalWhite); + estimateColor.setB(estimateColor.b() + (0xFF-estimateColor.b())*poroportionnalWhite); + } else { + float poroportionnalBlack = (m_currentUserPos.y()-0.5)*2.0; + estimateColor.setR(estimateColor.r() - estimateColor.r()*poroportionnalBlack); + estimateColor.setG(estimateColor.g() - estimateColor.g()*poroportionnalBlack); + estimateColor.setB(estimateColor.b() - estimateColor.b()*poroportionnalBlack); + } + if(*propertyValue != estimateColor) { + propertyValue.set(estimateColor); + signalChange.emit(*propertyValue); + } + return true; + } + } + return false; +} + diff --git a/src/org/atriasoft/ewol/widget/ColorBar.java b/src/org/atriasoft/ewol/widget/ColorBar.java new file mode 100644 index 0000000..b086e6c --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ColorBar.java @@ -0,0 +1,44 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + + +namespace ewol { + namespace widget { + class ColorBar; + using ColorBarShared = ememory::SharedPtr; + using ColorBarWeak = ememory::WeakPtr; + class ColorBar : public ewol::Widget { + public: // signals + esignal::Signal> signalChange; + public: + eproperty::Value> propertyValue; + protected: + ColorBar(); + public: + DECLARE_WIDGET_FACTORY(ColorBar, "ColorBar"); + virtual ~ColorBar(); + private: + ewol::compositing::Drawing m_draw; //!< Compositing drawing element + vec2 m_currentUserPos; + protected: + void onDraw() override; + public: + void calculateMinMaxSize() override; + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + protected: + virtual void onChangePropertyValue(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/Composer.cpp b/src/org/atriasoft/ewol/widget/Composer.cpp new file mode 100644 index 0000000..c76ed0b --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Composer.cpp @@ -0,0 +1,162 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Composer); + +ewol::widget::Composer::Composer() : + propertyRemoveIfUnderRemove(this, "remove-if-under-remove", true, "Demand the remove iof the widget if the subObject demand a remove"), + propertySubFile(this, "sub-file", "", "compose with a subXML file", &ewol::widget::Composer::onChangePropertySubFile) { + addObjectType("ewol::widget::Composer"); + // nothing to do ... +} + +ewol::WidgetShared ewol::widget::composerGenerateFile(const etk::Uri& _uri, uint64_t _id) { + etk::String tmpData; + if (etk::uri::readAll(_uri, tmpData) == false) { + EWOL_ERROR("Can not read the file: " << _uri); + return null; + } + return ewol::widget::composerGenerateString(tmpData, _id); +} + +ewol::WidgetShared ewol::widget::composerGenerateString(const etk::String& _data, uint64_t _id) { + ewol::widget::Manager& widgetManager = ewol::getContext().getWidgetManager(); + if (_data == "") { + return null; + } + exml::Document doc; + etk::String tmpData = _data; + // replace all elements: + if (_id != 0) { + tmpData.replace("{ID}", etk::toString(_id)); + } + if (doc.parse(tmpData) == false) { + EWOL_ERROR(" can not load file XML string..."); + return null; + } + exml::Element root = doc.toElement(); + if (root.nodes.size() == 0) { + EWOL_ERROR(" (l ?) No node in the XML file/string."); + return null; + } + if (root.nodes.size() > 1) { + EWOL_WARNING(" (l ?) More than 1 node in the XML file/string. (JUST parse the first)"); + } + exml::Element pNode = root.nodes[0].toElement(); + if (pNode.exist() == false) { + EWOL_ERROR(" (l ?) No node in the XML file/string. {2}"); + return null; + } + etk::String widgetName = pNode.getValue(); + if (widgetManager.exist(widgetName) == false) { + EWOL_ERROR("(l " << pNode.getPos() << ") Unknown basic node='" << widgetName << "' not in : [" << widgetManager.list() << "]" ); + return null; + } + EWOL_DEBUG("try to create subwidget : '" << widgetName << "'"); + ewol::WidgetShared tmpWidget = widgetManager.create(widgetName); + if (tmpWidget == null) { + EWOL_ERROR ("(l " << pNode.getPos() << ") Can not create the widget : '" << widgetName << "'"); + return null; + } + if (tmpWidget->loadXML(pNode) == false) { + EWOL_ERROR ("(l " << pNode.getPos() << ") can not load widget properties : '" << widgetName << "'"); + } + return tmpWidget; +} + +ewol::widget::Composer::~Composer() { + +} + +bool ewol::widget::Composer::loadFromFile(const etk::Uri& _uri, uint64_t _id) { + etk::String tmpData; + if (etk::uri::readAll(_uri, tmpData) == false) { + EWOL_ERROR("Can not read the file: " << _uri); + return false; + } + return loadFromString(tmpData, _id); +} + +bool ewol::widget::Composer::loadFromString(const etk::String& _composerXmlString, uint64_t _id) { + exml::Document doc; + etk::String tmpData = _composerXmlString; + // replace all elements: + if (_id != 0) { + tmpData.replace("{ID}", etk::toString(_id)); + } + if (doc.parse(tmpData) == false) { + EWOL_ERROR(" can not load file XML string..."); + return false; + } + exml::Element root = doc.nodes["composer"]; + if (root.exist() == false) { + // Maybe a multiple node XML for internal config: + root = doc.toElement(); + if (root.exist() == false) { + EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} (l ?) main node not find: 'composer' ..."); + return false; + } + if (root.nodes.size() == 0) { + EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} (l ?) no node in the Container XML element."); + return false; + } + } + // call upper class to parse his elements ... + ewol::widget::Container::loadXML(root); + if (m_subWidget == null) { + EWOL_WARNING("Load data from composer and have no under Widget after loading"); + if (_composerXmlString.size() != 0) { + EWOL_ERROR("Error Loading XML data : " << _composerXmlString); + return false; + } + } + requestUpdateSize(); + return true; +} + +void ewol::widget::Composer::requestDestroyFromChild(const ewol::ObjectShared& _child) { + ewol::widget::Container::requestDestroyFromChild(_child); + if (*propertyRemoveIfUnderRemove == true) { + EWOL_DEBUG("Child widget remove ==> auto-remove"); + autoDestroy(); + } +} + +void ewol::widget::Composer::onChangePropertySubFile() { + EWOL_INFO("Load compositing form external file : " << propertySubFile); + if (*propertySubFile == "") { + // remove all elements: + subWidgetRemove(); + return; + } + if (loadFromFile(*propertySubFile, getId()) == false) { + EWOL_ERROR("Can not load Player GUI from file ... " << propertySubFile); + return; + } +} + +bool ewol::widget::Composer::loadXML(const exml::Element& _node) { + //EWOL_VERBOSE("[" << getId() << "] t=" << getObjectType() << " Load XML (start)"); + if (_node.exist() == false) { + return false; + } + // parse generic properties: + ewol::Widget::loadXML(_node); + // parse all the elements: + if (_node.nodes.size() != 0) { + EWOL_ERROR("a composer Node Can not have Sub-element in XML ==> must be done in an external file and load it with attribute: 'sub-file'"); + } + //drawWidgetTree(); + //EWOL_VERBOSE("[" << getId() << "] t=" << getObjectType() << " Load XML (stop)"); + return true; +} \ No newline at end of file diff --git a/src/org/atriasoft/ewol/widget/Composer.java b/src/org/atriasoft/ewol/widget/Composer.java new file mode 100644 index 0000000..7f46063 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Composer.java @@ -0,0 +1,63 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Composer; + using ComposerShared = ememory::SharedPtr; + using ComposerWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + * @brief the composer widget is a widget that create a link on a string.file to parse the data and generate some widget tree + */ + class Composer : public ewol::widget::Container { + public: + eproperty::Value propertyRemoveIfUnderRemove; //!< Remove the composer if sub element request a remove + eproperty::Value propertySubFile; //!< If loading a sub-file, we must do it here ==> permit to configure it in the xml and not have wrong display + protected: + /** + * @brief Constructor + */ + Composer(); + public: + DECLARE_WIDGET_FACTORY(Composer, "Composer"); + /** + * @brief Destructor + */ + virtual ~Composer(); + /** + * @brief load a composition with a file + * @param[in] _uri Name of the file + * @param[in] _id Unique ID that is used in replacing the balise "{ID}" inside the File (do nothing if == 0) + * @return true == > all done OK + * @return false == > some error occured + */ + bool loadFromFile(const etk::Uri& _uri, uint64_t _id=0); + /** + * @brief load a composition with a file + * @param[in] _composerXmlString xml to parse directly + * @param[in] _id Unique ID that is used in replacing the balise "{ID}" inside the String (do nothing if == 0) + * @return true == > all done OK + * @return false == > some error occured + */ + bool loadFromString(const etk::String& _composerXmlString, uint64_t _id=0); + private: + void requestDestroyFromChild(const ewol::ObjectShared& _child) override; + public: + bool loadXML(const exml::Element& _node) override; + protected: + virtual void onChangePropertySubFile(); + }; + ewol::WidgetShared composerGenerateString(const etk::String& _data = "", uint64_t _id=0); + ewol::WidgetShared composerGenerateFile(const etk::Uri& _uri = "", uint64_t _id=0); + }; +}; diff --git a/src/org/atriasoft/ewol/widget/Container.cpp b/src/org/atriasoft/ewol/widget/Container.cpp new file mode 100644 index 0000000..35c2705 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Container.cpp @@ -0,0 +1,215 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::Container); + +ewol::widget::Container::Container() { + addObjectType("ewol::widget::Container"); + // nothing to do ... +} + +ewol::widget::Container::~Container() { + subWidgetRemove(); +} + +ewol::WidgetShared ewol::widget::Container::getSubWidget() { + return m_subWidget; +} + +void ewol::widget::Container::setSubWidget(ewol::WidgetShared _newWidget) { + if (_newWidget == null) { + return; + } + subWidgetRemove(); + m_subWidget = _newWidget; + if (m_subWidget != null) { + m_subWidget->setParent(sharedFromThis()); + } + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::Container::subWidgetReplace(const ewol::WidgetShared& _oldWidget, + const ewol::WidgetShared& _newWidget) { + if (m_subWidget != _oldWidget) { + EWOL_WARNING("Request replace with a wrong old widget"); + return; + } + m_subWidget->removeParent(); + m_subWidget.reset(); + m_subWidget = _newWidget; + if (m_subWidget != null) { + m_subWidget->setParent(sharedFromThis()); + } + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::Container::subWidgetRemove() { + if (m_subWidget != null) { + m_subWidget->removeParent(); + m_subWidget.reset(); + markToRedraw(); + requestUpdateSize(); + } +} + +void ewol::widget::Container::subWidgetUnLink() { + if (m_subWidget != null) { + m_subWidget->removeParent(); + } + m_subWidget.reset(); +} + +ewol::ObjectShared ewol::widget::Container::getSubObjectNamed(const etk::String& _objectName) { + ewol::ObjectShared tmpObject = ewol::Widget::getSubObjectNamed(_objectName); + if (tmpObject != null) { + return tmpObject; + } + if (m_subWidget != null) { + return m_subWidget->getSubObjectNamed(_objectName); + } + return null; +} + +void ewol::widget::Container::systemDraw(const ewol::DrawProperty& _displayProp) { + if (propertyHide.get() == true){ + // widget is hidden ... + return; + } + ewol::Widget::systemDraw(_displayProp); + if (m_subWidget != null) { + ewol::DrawProperty prop = _displayProp; + prop.limit(m_origin, m_size); + //EWOL_INFO("Draw : [" << propertyName << "] t=" << getObjectType() << " o=" << m_origin << " s=" << m_size); + m_subWidget->systemDraw(prop); + } else { + EWOL_INFO("[" << getId() << "] ++++++ : [null]"); + } +} + +void ewol::widget::Container::onChangeSize() { + ewol::Widget::onChangeSize(); + if (*propertyHide == true) { + return; + } + if (m_subWidget == null) { + return; + } + vec2 origin = m_origin+m_offset; + vec2 minSize = m_subWidget->getCalculateMinSize(); + bvec2 expand = m_subWidget->propertyExpand.get(); + origin += ewol::gravityGenerateDelta(propertyGravity.get(), minSize - m_size); + m_subWidget->setOrigin(origin); + m_subWidget->setSize(m_size); + m_subWidget->onChangeSize(); +} + +void ewol::widget::Container::calculateMinMaxSize() { + // call main class + ewol::Widget::calculateMinMaxSize(); + // call sub classes + if (m_subWidget != null) { + m_subWidget->calculateMinMaxSize(); + vec2 min = m_subWidget->getCalculateMinSize(); + m_minSize.setMax(min); + } + //EWOL_ERROR("[" << getId() << "] Result min size : " << m_minSize); +} + +void ewol::widget::Container::onRegenerateDisplay() { + if (m_subWidget != null) { + m_subWidget->onRegenerateDisplay(); + } +} + +ewol::WidgetShared ewol::widget::Container::getWidgetAtPos(const vec2& _pos) { + if (propertyHide.get() == false) { + if (m_subWidget != null) { + return m_subWidget->getWidgetAtPos(_pos); + } + } + return null; +}; + +bool ewol::widget::Container::loadXML(const exml::Element& _node) { + if (_node.exist() == false) { + return false; + } + // parse generic properties: + ewol::Widget::loadXML(_node); + // remove previous element: + subWidgetRemove(); + // parse all the elements: + for (const auto it : _node.nodes) { + exml::Element pNode = it.toElement(); + if (pNode.exist() == false) { + // trash here all that is not element + continue; + } + etk::String widgetName = pNode.getValue(); + EWOL_VERBOSE("[" << getId() << "] t=" << getObjectType() << " Load node name : '" << widgetName << "'"); + if (getWidgetManager().exist(widgetName) == false) { + EWOL_ERROR("(l " << pNode.getPos() << ") Unknown basic node='" << widgetName << "' not in : [" << getWidgetManager().list() << "]" ); + continue; + } + if (getSubWidget() != null) { + EWOL_ERROR("(l " << pNode.getPos() << ") Can only have one subWidget ??? node='" << widgetName << "'" ); + continue; + } + EWOL_DEBUG("try to create subwidget : '" << widgetName << "'"); + ewol::WidgetShared tmpWidget = getWidgetManager().create(widgetName, pNode); + if (tmpWidget == null) { + EWOL_ERROR ("(l " << pNode.getPos() << ") Can not create the widget : '" << widgetName << "'"); + continue; + } + // add widget : + setSubWidget(tmpWidget); + if (tmpWidget->loadXML(pNode) == false) { + EWOL_ERROR ("(l " << pNode.getPos() << ") can not load widget properties : '" << widgetName << "'"); + return false; + } + } + if ( _node.nodes.size() != 0 + && m_subWidget == null) { + EWOL_WARNING("Load container with no data inside"); + } + return true; +} + +void ewol::widget::Container::setOffset(const vec2& _newVal) { + if (m_offset != _newVal) { + ewol::Widget::setOffset(_newVal); + // recalculate the new sise and position of sub widget ... + onChangeSize(); + } +} + +void ewol::widget::Container::requestDestroyFromChild(const ewol::ObjectShared& _child) { + if (m_subWidget != _child) { + return; + } + if (m_subWidget == null) { + return; + } + m_subWidget->removeParent(); + m_subWidget.reset(); + markToRedraw(); +} + +void ewol::widget::Container::drawWidgetTree(int32_t _level) { + ewol::Widget::drawWidgetTree(_level); + _level++; + if (m_subWidget != null) { + m_subWidget->drawWidgetTree(_level); + } +} diff --git a/src/org/atriasoft/ewol/widget/Container.java b/src/org/atriasoft/ewol/widget/Container.java new file mode 100644 index 0000000..12aae48 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Container.java @@ -0,0 +1,73 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include + +namespace ewol { + namespace widget { + class Container; + using ContainerShared = ememory::SharedPtr; + using ContainerWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + * @brief the Cotainer widget is a widget that have an only one subWidget + */ + class Container : public ewol::Widget { + protected: + ewol::WidgetShared m_subWidget; + protected: + /** + * @brief Constructor + */ + Container(); + public: + /** + * @brief Destructor + */ + virtual ~Container(); + public: + /** + * @brief get the main node widget + * @return the requested pointer on the node + */ + ewol::WidgetShared getSubWidget(); + /** + * @brief set the subWidget node widget. + * @param[in] _newWidget The widget to add. + */ + void setSubWidget(ewol::WidgetShared _newWidget); + /** + * @brief Replace a old subwidget with a new one. + * @param[in] _oldWidget The widget to replace. + * @param[in] _newWidget The widget to set. + */ + virtual void subWidgetReplace(const ewol::WidgetShared& _oldWidget, + const ewol::WidgetShared& _newWidget); + /** + * @brief remove the subWidget node (async). + */ + void subWidgetRemove(); + /** + * @brief Unlink the subwidget Node. + */ + void subWidgetUnLink(); + public: + void systemDraw(const ewol::DrawProperty& _displayProp) override; + void onRegenerateDisplay() override; + void onChangeSize() override; + void calculateMinMaxSize() override; + ewol::WidgetShared getWidgetAtPos(const vec2& _pos) override; + ewol::ObjectShared getSubObjectNamed(const etk::String& _objectName) override; + bool loadXML(const exml::Element& _node) override; + void setOffset(const vec2& _newVal) override; + void requestDestroyFromChild(const ewol::ObjectShared& _child) override; + void drawWidgetTree(int32_t _level=0) override; + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/Container2.cpp b/src/org/atriasoft/ewol/widget/Container2.cpp new file mode 100644 index 0000000..1c7e629 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Container2.cpp @@ -0,0 +1,261 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::Container2); + +ewol::widget::Container2::Container2() : + m_idWidgetDisplayed(0) { + addObjectType("ewol::widget::Container2"); +} + +ewol::widget::Container2::~Container2() { + subWidgetRemove(); + subWidgetRemoveToggle(); +} + +void ewol::widget::Container2::setSubWidget(ewol::WidgetShared _newWidget, int32_t _idWidget) { + subWidgetRemove(_idWidget); + m_subWidget[_idWidget] = _newWidget; + if (m_subWidget[_idWidget] != null) { + EWOL_VERBOSE("Add widget : " << _idWidget); + m_subWidget[_idWidget]->setParent(sharedFromThis()); + } + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::Container2::subWidgetReplace(const ewol::WidgetShared& _oldWidget, + const ewol::WidgetShared& _newWidget) { + bool haveChange = false; + for (size_t iii=0; iii<2; ++iii) { + if (m_subWidget[iii] != _oldWidget) { + continue; + } + m_subWidget[iii]->removeParent(); + m_subWidget[iii].reset(); + m_subWidget[iii] = _newWidget; + if (m_subWidget[iii] != null) { + m_subWidget[iii]->setParent(sharedFromThis()); + } + haveChange = true; + } + if (haveChange == false) { + EWOL_WARNING("Request replace with a wrong old widget"); + return; + } + markToRedraw(); + requestUpdateSize(); +} + + +void ewol::widget::Container2::subWidgetRemove(int32_t _idWidget) { + if (m_subWidget[_idWidget] != null) { + EWOL_VERBOSE("Remove widget : " << _idWidget); + m_subWidget[_idWidget]->removeParent(); + m_subWidget[_idWidget].reset(); + markToRedraw(); + requestUpdateSize(); + } +} + +void ewol::widget::Container2::subWidgetUnLink(int32_t _idWidget) { + if (m_subWidget[_idWidget] != null) { + m_subWidget[_idWidget]->removeParent(); + EWOL_VERBOSE("Unlink widget : " << _idWidget); + } + m_subWidget[_idWidget].reset(); +} + +ewol::ObjectShared ewol::widget::Container2::getSubObjectNamed(const etk::String& _widgetName) { + ewol::ObjectShared tmpObject = ewol::Widget::getSubObjectNamed(_widgetName); + if (tmpObject != null) { + return tmpObject; + } + if (m_subWidget[0] != null) { + tmpObject = m_subWidget[0]->getSubObjectNamed(_widgetName); + if (tmpObject != null) { + return tmpObject; + } + } + if (m_subWidget[1] != null) { + return m_subWidget[1]->getSubObjectNamed(_widgetName); + } + return null; +} + +void ewol::widget::Container2::systemDraw(const ewol::DrawProperty& _displayProp) { + if (propertyHide.get() == true){ + // widget is hidden ... + return; + } + ewol::Widget::systemDraw(_displayProp); + if (m_subWidget[m_idWidgetDisplayed] != null) { + //EWOL_INFO("Draw : [" << propertyName << "] t=" << getObjectType() << " o=" << m_origin << " s=" << m_size); + m_subWidget[m_idWidgetDisplayed]->systemDraw(_displayProp); + } +} + +ewol::Padding ewol::widget::Container2::onChangeSizePadded(const ewol::Padding& _padding) { + ewol::Widget::onChangeSize(); + vec2 localAvaillable = m_size - vec2(_padding.x(), _padding.y()); + // Checkin the filling properties == > for the subElements: + vec2 subElementSize = m_minSize; + if (propertyFill->x() == true) { + subElementSize.setX(m_size.x()); + } + if (propertyFill->y() == true) { + subElementSize.setY(m_size.y()); + } + vec2 delta = ewol::gravityGenerateDelta(propertyGravity, m_size - subElementSize); + vec2 origin = delta + vec2(_padding.xLeft(), _padding.yButtom()); + subElementSize -= vec2(_padding.x(), _padding.y()); + for (size_t iii = 0; iii < 2; ++iii) { + if (m_subWidget[iii] != null) { + vec2 origin2 = origin+m_offset; + vec2 minSize = m_subWidget[iii]->getCalculateMinSize(); + //bvec2 expand = m_subWidget[iii]->propertyExpand.get(); + origin2 += ewol::gravityGenerateDelta(propertyGravity, minSize - localAvaillable); + m_subWidget[iii]->setOrigin(m_origin + origin); + m_subWidget[iii]->setSize(subElementSize); + m_subWidget[iii]->onChangeSize(); + } + } + vec2 selectableAreaPos = origin-vec2(_padding.xLeft(), _padding.yButtom()); + vec2 selectableAreaEndPos = m_size - (selectableAreaPos + subElementSize + vec2(_padding.x(), _padding.y())); + markToRedraw(); + return ewol::Padding(selectableAreaPos.x(), + selectableAreaEndPos.y(), + selectableAreaEndPos.x(), + selectableAreaPos.y()); +} + +void ewol::widget::Container2::calculateMinMaxSizePadded(const ewol::Padding& _padding) { + // call main class + m_minSize = vec2(0,0); + // call sub classes + for (size_t iii = 0; iii < 2; ++iii) { + if (m_subWidget[iii] != null) { + m_subWidget[iii]->calculateMinMaxSize(); + vec2 min = m_subWidget[iii]->getCalculateMinSize(); + m_minSize.setMax(min); + } + } + // add padding : + m_minSize += vec2(_padding.x(), _padding.y()); + // verify the min max of the min size ... + checkMinSize(); + markToRedraw(); +} + +void ewol::widget::Container2::onRegenerateDisplay() { + if (m_subWidget[m_idWidgetDisplayed] != null) { + m_subWidget[m_idWidgetDisplayed]->onRegenerateDisplay(); + } +} +/* +ewol::WidgetShared ewol::widget::Container2::getWidgetAtPos(const vec2& _pos) { + if (isHide() == false) { + if (m_subWidget[m_idWidgetDisplayed] != null) { + return m_subWidget[m_idWidgetDisplayed]->getWidgetAtPos(_pos); + } + } + return null; +} +*/ + +bool ewol::widget::Container2::loadXML(const exml::Element& _node) { + if (_node.exist() == false) { + return false; + } + // parse generic properties : + ewol::Widget::loadXML(_node); + // remove previous element : + subWidgetRemove(); + EWOL_VERBOSE("Create en element 2 ... with nodes.size()=" << _node.nodes.size()); + // parse all the elements: + for(const auto it : _node.nodes) { + EWOL_VERBOSE(" node: " << it); + exml::Element pNode = it.toElement(); + if (pNode.exist() == false) { + // trash here all that is not element + continue; + } + etk::String widgetName = pNode.getValue(); + if (getWidgetManager().exist(widgetName) == false) { + EWOL_ERROR("(l " << pNode.getPos() << ") Unknown basic node='" << widgetName << "' not in: [" << getWidgetManager().list() << "]" ); + continue; + } + bool toogleMode=false; + if (getSubWidget() != null) { + toogleMode=true; + if (getSubWidgetToggle() != null) { + EWOL_ERROR("(l " << pNode.getPos() << ") Can only have one subWidget ??? node='" << widgetName << "'" ); + continue; + } + } + EWOL_DEBUG("try to create subwidget : '" << widgetName << "'"); + ewol::WidgetShared tmpWidget = getWidgetManager().create(widgetName, pNode); + if (tmpWidget == null) { + EWOL_ERROR ("(l " << pNode.getPos() << ") Can not create the widget: '" << widgetName << "'"); + continue; + } + // add widget : + if (toogleMode == false) { + setSubWidget(tmpWidget); + } else { + setSubWidgetToggle(tmpWidget); + } + if (tmpWidget->loadXML(pNode) == false) { + EWOL_ERROR ("(l "<removeParent(); + m_subWidget[0].reset(); + markToRedraw(); + } + if (m_subWidget[1] == _child) { + if (m_subWidget[1] == null) { + return; + } + m_subWidget[1]->removeParent(); + m_subWidget[1].reset(); + markToRedraw(); + } +} + +void ewol::widget::Container2::drawWidgetTree(int32_t _level) { + ewol::Widget::drawWidgetTree(_level); + _level++; + if (m_subWidget[0] != null) { + m_subWidget[0]->drawWidgetTree(_level); + } + if (m_subWidget[1] != null) { + m_subWidget[1]->drawWidgetTree(_level); + } +} diff --git a/src/org/atriasoft/ewol/widget/Container2.java b/src/org/atriasoft/ewol/widget/Container2.java new file mode 100644 index 0000000..93ad51a --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Container2.java @@ -0,0 +1,174 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Container2; + using Container2Shared = ememory::SharedPtr; + using Container2Weak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + * @brief the Cotainer widget is a widget that have an only one subWidget + */ + class Container2 : public ewol::Widget { + protected: + ewol::WidgetShared m_subWidget[2]; //!< 2 subwidget possible + int32_t m_idWidgetDisplayed; //!< current widget displayed + protected: + /** + * @brief Constructor + * @param[in] _subElement Widget to set on the normal position + * @param[in] _subElementToggle Widget to set on the toggle position + */ + Container2(); + public: + /** + * @brief Destructor + */ + virtual ~Container2(); + private: + /** + * @brief Specify the current widget + * @param[in] _subWidget Widget to add normal + * @param[in] _idWidget Id of the widget to set + */ + void setSubWidget(ewol::WidgetShared _subWidget, int32_t _idWidget); + public: + /** + * @brief Specify the current widget + * @param[in] _subWidget Widget to add normal + */ + void setSubWidget(ewol::WidgetShared _subWidget) { + setSubWidget(_subWidget, 0); + } + /** + * @brief Specify the current toggle widget + * @param[in] _subWidget Widget to add Toggle + */ + void setSubWidgetToggle(ewol::WidgetShared _subWidget) { + setSubWidget(_subWidget, 1); + } + private: + /** + * @brief get the current displayed composition + * @param[in] _idWidget Id of the widget to set + * @return The base widget + */ + ewol::WidgetShared getSubWidget(int32_t _idWidget) const { + return m_subWidget[_idWidget]; + }; + public: + /** + * @brief get the current displayed composition + * @return The base widget + */ + ewol::WidgetShared getSubWidget() const { + return getSubWidget(0); + }; + /** + * @brief get the current displayed composition + * @return The toggle widget + */ + ewol::WidgetShared getSubWidgetToggle() const { + return getSubWidget(1); + }; + private: + /** + * @brief remove the subWidget node (async). + * @param[in] _idWidget Id of the widget to set + */ + void subWidgetRemove(int32_t _idWidget); + public: + /** + * @brief remove the subWidget node (async). + */ + void subWidgetRemove() { + subWidgetRemove(0); + } + /** + * @brief remove the subWidget Toggle node (async). + */ + void subWidgetRemoveToggle() { + subWidgetRemove(1); + } + private: + /** + * @brief Unlink the subwidget Node. + * @param[in] _idWidget Id of the widget to set + */ + void subWidgetUnLink(int32_t _idWidget); + public: + /** + * @brief Unlink the subwidget Node. + */ + void subWidgetUnLink() { + subWidgetUnLink(0); + } + /** + * @brief Unlink the subwidget Toggle Node. + */ + void subWidgetUnLinkToggle() { + subWidgetUnLink(1); + } + protected: + /** + * @brief Parent set the possible diplay size of the current widget whith his own possibilities + * By default this save the widget available size in the widget size + * @param[in] _padding Padding of the widget. + * @note : INTERNAL EWOL SYSTEM + */ + virtual ewol::Padding onChangeSizePadded(const ewol::Padding& _padding = ewol::Padding(0,0,0,0)); + /** + * @brief calculate the minimum and maximum size (need to estimate expend properties of the widget) + * @param[in] _padding Padding of the widget. + * @note : INTERNAL EWOL SYSTEM + */ + virtual void calculateMinMaxSizePadded(const ewol::Padding& _padding = ewol::Padding(0,0,0,0)); + /** + * @brief Called when parsing a XML and detect the presence of a second Widget + */ + virtual void onDetectPresenceToggleWidget() {} + /** + * @brief convert ID of the widget if not existed + * @param[in] _id Id of the widget to display. + * @return the id of the widget displayable + */ + int32_t convertId(int32_t _id) { + if (m_subWidget[_id] == null) { + return (_id+1)%2; + } + return _id; + } + /** + * @brief Replace a old subwidget with a new one. + * @param[in] _oldWidget The widget to replace. + * @param[in] _newWidget The widget to set. + */ + virtual void subWidgetReplace(const ewol::WidgetShared& _oldWidget, + const ewol::WidgetShared& _newWidget); + public: + void systemDraw(const ewol::DrawProperty& _displayProp) override; + void onRegenerateDisplay() override; + void onChangeSize() override { + onChangeSizePadded(); + } + void calculateMinMaxSize() override { + calculateMinMaxSizePadded(); + } + ewol::ObjectShared getSubObjectNamed(const etk::String& _objectName) override; + bool loadXML(const exml::Element& _node) override; + void setOffset(const vec2& _newVal) override; + void requestDestroyFromChild(const ewol::ObjectShared& _child) override; + void drawWidgetTree(int32_t _level=0) override; + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/ContainerN.cpp b/src/org/atriasoft/ewol/widget/ContainerN.cpp new file mode 100644 index 0000000..deaa7e0 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ContainerN.cpp @@ -0,0 +1,342 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::ContainerN); + +ewol::widget::ContainerN::ContainerN() : + propertyLockExpand(this, "lock", + vec2(false,false), + "Lock the subwidget expand", + &ewol::widget::ContainerN::onChangePropertyLockExpand), + m_subExpend(false,false) { + addObjectType("ewol::widget::ContainerN"); + // nothing to do ... +} + +ewol::widget::ContainerN::~ContainerN() { + subWidgetRemoveAll(); +} + + +bvec2 ewol::widget::ContainerN::canExpand() { + bvec2 res = propertyExpand.get(); + if (propertyLockExpand->x() == false) { + if (m_subExpend.x() == true) { + res.setX(true); + } + } + if (propertyLockExpand->y() == false) { + if (m_subExpend.y() == true) { + res.setY(true); + } + } + //EWOL_DEBUG("Expend check : user=" << m_userExpand << " lock=" << propertyLockExpand << " sub=" << m_subExpend << " res=" << res); + return res; +} + +void ewol::widget::ContainerN::onChangePropertyLockExpand() { + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::ContainerN::subWidgetReplace(ewol::WidgetShared _oldWidget, + ewol::WidgetShared _newWidget) { + bool haveChange = false; + for (auto &it : m_subWidget) { + if (it != _oldWidget) { + continue; + } + it->removeParent(); + it.reset(); + if (_newWidget != null) { + _newWidget->setParent(sharedFromThis()); + } + it = _newWidget; + haveChange = true; + } + if (haveChange == false) { + EWOL_WARNING("Request replace with a wrong old widget"); + return; + } + markToRedraw(); + requestUpdateSize(); +} + +int32_t ewol::widget::ContainerN::subWidgetAdd(ewol::WidgetShared _newWidget) { + if (_newWidget == null) { + EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} Try to add An empty Widget ... "); + return -1; + } + _newWidget->setParent(sharedFromThis()); + m_subWidget.pushBack(_newWidget); + markToRedraw(); + requestUpdateSize(); + // added at the last eelement : + return _newWidget->getId(); +} + +int32_t ewol::widget::ContainerN::subWidgetAddStart(ewol::WidgetShared _newWidget) { + if (_newWidget == null) { + EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} Try to add start An empty Widget ... "); + return -1; + } + if (_newWidget != null) { + _newWidget->setParent(sharedFromThis()); + } + m_subWidget.insert(m_subWidget.begin(), _newWidget); + markToRedraw(); + requestUpdateSize(); + return _newWidget->getId(); +} + +void ewol::widget::ContainerN::subWidgetRemove(ewol::WidgetShared _newWidget) { + if (_newWidget == null) { + return; + } + size_t errorControl = m_subWidget.size(); + + auto it(m_subWidget.begin()); + while (it != m_subWidget.end()) { + if (_newWidget == *it) { + (*it)->removeParent(); + m_subWidget.erase(it); + it = m_subWidget.begin(); + markToRedraw(); + requestUpdateSize(); + } else { + ++it; + } + } +} + +void ewol::widget::ContainerN::subWidgetUnLink(ewol::WidgetShared _newWidget) { + if (_newWidget == null) { + return; + } + auto it(m_subWidget.begin()); + while (it != m_subWidget.end()) { + if (_newWidget == *it) { + (*it)->removeParent(); + (*it).reset(); + m_subWidget.erase(it); + it = m_subWidget.begin(); + markToRedraw(); + requestUpdateSize(); + } else { + ++it; + } + } +} + +void ewol::widget::ContainerN::subWidgetRemoveAll() { + for(auto &it : m_subWidget) { + if (it != null) { + it->removeParent(); + } + it.reset(); + } + m_subWidget.clear(); +} + +void ewol::widget::ContainerN::subWidgetRemoveAllDelayed() { + subWidgetRemoveAll(); +} + +ewol::ObjectShared ewol::widget::ContainerN::getSubObjectNamed(const etk::String& _objectName) { + ewol::ObjectShared tmpObject = ewol::Widget::getSubObjectNamed(_objectName); + if (tmpObject != null) { + return tmpObject; + } + for (auto &it : m_subWidget) { + if (it != null) { + tmpObject = it->getSubObjectNamed(_objectName); + if (tmpObject != null) { + return tmpObject; + } + } + } + return null; +} + +void ewol::widget::ContainerN::systemDraw(const ewol::DrawProperty& _displayProp) { + if (*propertyHide == true){ + // widget is hidden ... + return; + } + // local widget draw + ewol::Widget::systemDraw(_displayProp); + // subwidget draw + ewol::DrawProperty prop = _displayProp; + prop.limit(m_origin, m_size); + for (int64_t iii = m_subWidget.size()-1; iii>=0; --iii) { + if (m_subWidget[iii] != null) { + //EWOL_INFO(" ***** : [" << (*it)->propertyName << "] t=" << (*it)->getObjectType() << " o=" << (*it)->m_origin << " s=" << (*it)->m_size); + m_subWidget[iii]->systemDraw(prop); + } + } +} + +void ewol::widget::ContainerN::onChangeSize() { + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + it->setOrigin(m_origin+m_offset); + it->setSize(m_size); + it->onChangeSize(); + } +} + +void ewol::widget::ContainerN::calculateMinMaxSize() { + m_subExpend.setValue(false, false); + m_minSize.setValue(0,0); + m_maxSize.setValue(ULTIMATE_MAX_SIZE,ULTIMATE_MAX_SIZE); + //EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} set min size : " << m_minSize); + for (auto &it : m_subWidget) { + if (it != null) { + it->calculateMinMaxSize(); + bvec2 subExpendProp = it->canExpand(); + if (true == subExpendProp.x()) { + m_subExpend.setX(true); + } + if (true == subExpendProp.y()) { + m_subExpend.setY(true); + } + vec2 tmpSize = it->getCalculateMinSize(); + m_minSize.setValue( etk::max(tmpSize.x(), m_minSize.x()), + etk::max(tmpSize.y(), m_minSize.y()) ); + } + } + //EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} Result min size : " << m_minSize); +} + +void ewol::widget::ContainerN::onRegenerateDisplay() { + for (auto &it : m_subWidget) { + if (it != null) { + it->onRegenerateDisplay(); + } + } +} + +ewol::WidgetShared ewol::widget::ContainerN::getWidgetAtPos(const vec2& _pos) { + if (*propertyHide == true) { + return null; + } + // for all element in the sizer ... + for (auto &it : m_subWidget) { + if (it != null) { + vec2 tmpSize = it->getSize(); + vec2 tmpOrigin = it->getOrigin(); + if( (tmpOrigin.x() <= _pos.x() && tmpOrigin.x() + tmpSize.x() >= _pos.x()) + && (tmpOrigin.y() <= _pos.y() && tmpOrigin.y() + tmpSize.y() >= _pos.y()) ) + { + ewol::WidgetShared tmpWidget = it->getWidgetAtPos(_pos); + if (tmpWidget != null) { + return tmpWidget; + } + // stop searching + break; + } + } + } + return null; +}; + +bool ewol::widget::ContainerN::loadXML(const exml::Element& _node) { + if (_node.exist() == false) { + return false; + } + // parse generic properties : + ewol::Widget::loadXML(_node); + // remove previous element : + subWidgetRemoveAll(); + + etk::String tmpAttributeValue = _node.attributes["lock"]; + if (tmpAttributeValue.size()!=0) { + propertyLockExpand.set(tmpAttributeValue); + } + bool invertAdding=false; + tmpAttributeValue = _node.attributes["addmode"]; + if(etk::compare_no_case(tmpAttributeValue, "invert")) { + invertAdding=true; + } + // parse all the elements : + for (const auto nodeIt : _node.nodes) { + const exml::Element pNode = nodeIt.toElement(); + if (pNode.exist() == false) { + // trash here all that is not element + continue; + } + etk::String widgetName = pNode.getValue(); + EWOL_VERBOSE(" t=" << getObjectType() << " Load node name : '" << widgetName << "'"); + if (getWidgetManager().exist(widgetName) == false) { + EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} (l " << pNode.getPos() << ") Unknown basic node='" << widgetName << "' not in : [" << getWidgetManager().list() << "]" ); + continue; + } + EWOL_DEBUG("[" << getId() << "] {" << getObjectType() << "} load new element : '" << widgetName << "'"); + ewol::WidgetShared subWidget = getWidgetManager().create(widgetName, pNode); + if (subWidget == null) { + EWOL_ERROR ("[" << getId() << "] {" << getObjectType() << "} (l " << pNode.getPos() << ") Can not create the widget : '" << widgetName << "'"); + continue; + } + // add sub element : + if (invertAdding == false) { + subWidgetAdd(subWidget); + } else { + subWidgetAddStart(subWidget); + } + if (subWidget->loadXML(pNode) == false) { + EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} (l " << pNode.getPos() << ") can not load widget properties : '" << widgetName << "'"); + return false; + } + } + return true; +} + + +void ewol::widget::ContainerN::setOffset(const vec2& _newVal) { + if (m_offset != _newVal) { + ewol::Widget::setOffset(_newVal); + // recalculate the new sise and position of sub widget ... + onChangeSize(); + } +} + +void ewol::widget::ContainerN::requestDestroyFromChild(const ewol::ObjectShared& _child) { + auto it = m_subWidget.begin(); + while (it != m_subWidget.end()) { + if (*it == _child) { + if (*it == null) { + m_subWidget.erase(it); + it = m_subWidget.begin(); + continue; + } + (*it)->removeParent(); + (*it).reset(); + m_subWidget.erase(it); + it = m_subWidget.begin(); + markToRedraw(); + continue; + } + ++it; + } +} + +void ewol::widget::ContainerN::drawWidgetTree(int32_t _level) { + ewol::Widget::drawWidgetTree(_level); + _level++; + for (auto &it: m_subWidget) { + if (it != null) { + it->drawWidgetTree(_level); + } + } +} diff --git a/src/org/atriasoft/ewol/widget/ContainerN.java b/src/org/atriasoft/ewol/widget/ContainerN.java new file mode 100644 index 0000000..b62e089 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ContainerN.java @@ -0,0 +1,105 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include + +namespace ewol { + namespace widget { + class ContainerN; + using ContainerNShared = ememory::SharedPtr; + using ContainerNWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + * @brief the Cotainer widget is a widget that have an only one subWidget + */ + class ContainerN : public ewol::Widget { + public: // properties: + eproperty::Value propertyLockExpand; //!< Lock the expend of the sub widget to this one == > this permit to limit bigger subWidget + protected: + etk::Vector m_subWidget; + protected: + /** + * @brief Constructor + */ + ContainerN(); + public: + /** + * @brief Destructor + */ + virtual ~ContainerN(); + protected: + bvec2 m_subExpend; //!< reference of the sub element expention requested. + // herited function + virtual bvec2 canExpand() override; + public: + /** + * @brief remove all sub element from the widget. + */ + virtual void subWidgetRemoveAll(); + /** + * @brief remove all sub element from the widget (delayed to prevent remove in the callbback). + */ + virtual void subWidgetRemoveAllDelayed(); + /** + * @brief Replace a old subwidget with a new one. + * @param[in] _oldWidget The widget to replace. + * @param[in] _newWidget The widget to set. + */ + virtual void subWidgetReplace(ewol::WidgetShared _oldWidget, + ewol::WidgetShared _newWidget); + /** + * @brief add at end position a Widget (note : This system use an inverted phylisophie (button to top, and left to right) + * @param[in] _newWidget the element pointer + * @return the ID of the set element + */ + virtual int32_t subWidgetAdd(ewol::WidgetShared _newWidget); + //! @previous + inline int32_t subWidgetAddBack(ewol::WidgetShared _newWidget) { + return subWidgetAdd(_newWidget); + }; + //! @previous + inline int32_t subWidgetAddEnd(ewol::WidgetShared _newWidget) { + return subWidgetAdd(_newWidget); + }; + /** + * @brief add at start position a Widget (note : This system use an inverted phylisophie (button to top, and left to right) + * @param[in] _newWidget the element pointer + * @return the ID of the set element + */ + virtual int32_t subWidgetAddStart(ewol::WidgetShared _newWidget); + //! @previous + inline int32_t subWidgetAddFront(ewol::WidgetShared _newWidget) { + return subWidgetAddStart(_newWidget); + }; + /** + * @brief remove definitly a widget from the system and this layer. + * @param[in] _newWidget the element pointer. + */ + virtual void subWidgetRemove(ewol::WidgetShared _newWidget); + /** + * @brief Just unlick the specify widget, this function does not remove it from the system (if you can, do nt use it ...) + * @param[in] _newWidget the element pointer. + */ + virtual void subWidgetUnLink(ewol::WidgetShared _newWidget); + public: + void systemDraw(const ewol::DrawProperty& _displayProp) override; + void onRegenerateDisplay() override; + void onChangeSize() override; + void calculateMinMaxSize() override; + ewol::WidgetShared getWidgetAtPos(const vec2& _pos) override; + ewol::ObjectShared getSubObjectNamed(const etk::String& _objectName) override; + bool loadXML(const exml::Element& _node) override; + void setOffset(const vec2& _newVal) override; + void requestDestroyFromChild(const ewol::ObjectShared& _child) override; + void drawWidgetTree(int32_t _level=0) override; + protected: + virtual void onChangePropertyLockExpand(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/ContextMenu.cpp b/src/org/atriasoft/ewol/widget/ContextMenu.cpp new file mode 100644 index 0000000..57e4ea4 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ContextMenu.cpp @@ -0,0 +1,267 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::ContextMenu); +ETK_DECLARE_TYPE(enum ewol::widget::ContextMenu::markPosition); + +ewol::widget::ContextMenu::ContextMenu(): + propertyShape(this, "shape", + etk::Uri("THEME_GUI:///ContextMenu.json?lib=ewol"), + "the display name for config file", + &ewol::widget::ContextMenu::onChangePropertyShape), + propertyArrowPos(this, "arrow-position", + vec2(0,0), + "Position of the arrow in the pop-up", + &ewol::widget::ContextMenu::onChangePropertyArrowPos), + propertyArrawBorder(this, "arrow-mode", + markTop, + "position of the arrow", + &ewol::widget::ContextMenu::onChangePropertyArrawBorder) { + addObjectType("ewol::widget::ContextMenu"); + propertyArrawBorder.add(markTop, "top"); + propertyArrawBorder.add(markRight, "right"); + propertyArrawBorder.add(markButtom, "buttom"); + propertyArrawBorder.add(markLeft, "left"); + propertyArrawBorder.add(markNone, "none"); + + + m_offset = 20; + + + m_colorBorder = etk::color::black; + m_colorBorder.setA(0x7F); + + setMouseLimit(1); +} + +void ewol::widget::ContextMenu::init() { + ewol::widget::Container::init(); + propertyShape.notifyChange(); +} + +ewol::widget::ContextMenu::~ContextMenu() { + +} + +void ewol::widget::ContextMenu::onChangeSize() { + markToRedraw(); + // pop-up fill all the display : + ewol::Padding padding = m_shaper.getPadding(); + EWOL_VERBOSE("our origin=" << m_origin << " size=" << m_size); + if (m_subWidget == null) { + return; + } + vec2 subWidgetSize(0,0); + vec2 subWidgetOrigin(0,0); + subWidgetSize = m_subWidget->getCalculateMinSize(); + if (m_subWidget->canExpand().x() == true) { + subWidgetSize.setX(m_size.x()); + } + if (m_subWidget->canExpand().y() == true) { + subWidgetSize.setY(m_size.y()); + } + int32_t minWidth = 100; + int32_t maxWidth = 300; + subWidgetSize.setX((int32_t)etk::max(minWidth, (int32_t)subWidgetSize.x())); + subWidgetSize.setX((int32_t)etk::min(maxWidth, (int32_t)subWidgetSize.x())); + subWidgetSize.setY((int32_t)subWidgetSize.y()); + + // set config to the Sub-widget + switch (propertyArrawBorder.get()) { + case markTop: + subWidgetOrigin.setX((int32_t)(propertyArrowPos->x() - subWidgetSize.x()/2)); + subWidgetOrigin.setY((int32_t)(propertyArrowPos->y() - m_offset - subWidgetSize.y())); + break; + case markButtom: + subWidgetOrigin.setX((int32_t)(propertyArrowPos->x() - subWidgetSize.x()/2)); + subWidgetOrigin.setY((int32_t)(propertyArrowPos->y() + m_offset)); + break; + case markRight: + case markLeft: + default: + subWidgetOrigin.setX((int32_t)(m_size.x() - m_origin.x() - subWidgetSize.x())/2 + m_origin.x()); + subWidgetOrigin.setY((int32_t)(m_size.y() - m_origin.y() - subWidgetSize.y())/2 + m_origin.y()); + break; + } + // set the widget position at the border of the screen + subWidgetOrigin.setX( (int32_t)( etk::max(0, (int32_t)(subWidgetOrigin.x()-padding.x())) + + padding.x()) ); + subWidgetOrigin.setY( (int32_t)( etk::max(0, (int32_t)(subWidgetOrigin.y()-padding.y())) + + padding.y()) ); + switch (propertyArrawBorder.get()) { + default: + case markTop: + case markButtom: + if (propertyArrowPos->x() <= m_offset ) { + subWidgetOrigin.setX(propertyArrowPos->x()+padding.xLeft()); + } + break; + case markRight: + case markLeft: + if (propertyArrowPos->y() <= m_offset ) { + subWidgetOrigin.setY(propertyArrowPos->y()+padding.yButtom()); + } + break; + } + EWOL_VERBOSE(" == > sub origin=" << subWidgetOrigin << " size=" << subWidgetSize); + m_subWidget->setOrigin(subWidgetOrigin); + m_subWidget->setSize(subWidgetSize); + m_subWidget->onChangeSize(); +} + + +void ewol::widget::ContextMenu::calculateMinMaxSize() { + // call main class to calculate the min size... + ewol::widget::Container::calculateMinMaxSize(); + // add padding of the display + ewol::Padding padding = m_shaper.getPadding(); + m_minSize += vec2(padding.x(), padding.y()); + //EWOL_DEBUG("CalculateMinSize=>>" << m_minSize); + markToRedraw(); +} + + +void ewol::widget::ContextMenu::onDraw() { + m_compositing.draw(); + m_shaper.draw(); +} + + +void ewol::widget::ContextMenu::onRegenerateDisplay() { + // call upper class : + ewol::widget::Container::onRegenerateDisplay(); + if (needRedraw() == false) { + return; + } + m_compositing.clear(); + m_shaper.clear(); + ewol::Padding padding = m_shaper.getPadding(); + + if (m_subWidget == null) { + return; + } + vec2 tmpSize = m_subWidget->getSize(); + vec2 tmpOrigin = m_subWidget->getOrigin(); + + // display border ... + m_compositing.setColor(m_colorBorder); + switch (propertyArrawBorder) { + case markTop: + m_compositing.setPos(vec3(propertyArrowPos->x(), propertyArrowPos->y(), 0.0f) ); + m_compositing.addVertex(); + if (propertyArrowPos->x() <= tmpOrigin.x() ) { + float laking = m_offset - padding.yTop(); + m_compositing.setPos(vec3(propertyArrowPos->x()+laking, propertyArrowPos->y()-laking, 0.0f) ); + m_compositing.addVertex(); + m_compositing.setPos(vec3(propertyArrowPos->x(), propertyArrowPos->y()-laking, 0.0f) ); + m_compositing.addVertex(); + } else { + float laking = m_offset - padding.yTop(); + m_compositing.setPos(vec3(propertyArrowPos->x()+laking, propertyArrowPos->y()-laking, 0.0f) ); + m_compositing.addVertex(); + m_compositing.setPos(vec3(propertyArrowPos->x()-laking, propertyArrowPos->y()-laking, 0.0f) ); + m_compositing.addVertex(); + } + break; + case markButtom: + m_compositing.setPos(vec3(propertyArrowPos->x(), propertyArrowPos->y(), 0) ); + m_compositing.addVertex(); + if (propertyArrowPos->x() <= tmpOrigin.x() ) { + int32_t laking = m_offset - padding.yTop(); + m_compositing.setPos(vec3(propertyArrowPos->x()+laking, propertyArrowPos->y()+laking, 0.0f) ); + m_compositing.addVertex(); + m_compositing.setPos(vec3(propertyArrowPos->x(), propertyArrowPos->y()+laking, 0.0f) ); + m_compositing.addVertex(); + } else { + int32_t laking = m_offset - padding.yTop(); + m_compositing.setPos(vec3(propertyArrowPos->x()+laking, propertyArrowPos->y()+laking, 0.0f) ); + m_compositing.addVertex(); + m_compositing.setPos(vec3(propertyArrowPos->x()-laking, propertyArrowPos->y()+laking, 0.0f) ); + m_compositing.addVertex(); + } + break; + default: + case markRight: + case markLeft: + EWOL_TODO("later"); + break; + } + + vec2 shaperOrigin = tmpOrigin-vec2(padding.xLeft(), padding.yButtom()); + vec2 shaperSize = tmpSize+vec2(padding.x(), padding.y()); + m_shaper.setShape(vec2ClipInt32(shaperOrigin), + vec2ClipInt32(shaperSize)); +} + +bool ewol::widget::ContextMenu::onEventInput(const ewol::event::Input& _event) { + if (_event.getId() > 0) { + if (ewol::widget::Container::getWidgetAtPos(_event.getPos()) != null) { + return false; + } + if( _event.getStatus() == gale::key::status::down + || _event.getStatus() == gale::key::status::move + || _event.getStatus() == gale::key::status::pressSingle + || _event.getStatus() == gale::key::status::up + || _event.getStatus() == gale::key::status::enter + || _event.getStatus() == gale::key::status::leave ) { + // Auto-remove ... + autoDestroy(); + return true; + } + } + return false; +} + +ewol::WidgetShared ewol::widget::ContextMenu::getWidgetAtPos(const vec2& _pos) { + ewol::WidgetShared val = ewol::widget::Container::getWidgetAtPos(_pos); + if (val != null) { + return val; + } + return ememory::dynamicPointerCast(sharedFromThis()); +} + +void ewol::widget::ContextMenu::onChangePropertyArrowPos() { + markToRedraw(); +} + +void ewol::widget::ContextMenu::onChangePropertyArrawBorder() { + markToRedraw(); +} + +void ewol::widget::ContextMenu::onChangePropertyShape() { + m_shaper.setSource(propertyShape.get()); + markToRedraw(); +} + + +void ewol::widget::ContextMenu::setPositionMarkAuto(const vec2& _origin, const vec2& _size) { + ewol::widget::WindowsShared windows = getWindows(); + vec2 globalSize = windows->getSize(); + // TODO : Support left and right + float upperSize = globalSize.y() - (_origin.y() + _size.y()); + float underSize = _origin.y(); + if (underSize >= upperSize) { + vec2 pos = _origin + _size - vec2(_size.x()*0.5f, 0.0f); + setPositionMark(ewol::widget::ContextMenu::markButtom, pos); + } else { + vec2 pos = _origin + vec2(_size.x()*0.5f, 0.0f); + setPositionMark(ewol::widget::ContextMenu::markTop, pos); + } +} +void ewol::widget::ContextMenu::setPositionMark(enum markPosition _position, const vec2& _arrowPos) { + propertyArrawBorder.set(_position); + propertyArrowPos.set(_arrowPos); +} + diff --git a/src/org/atriasoft/ewol/widget/ContextMenu.java b/src/org/atriasoft/ewol/widget/ContextMenu.java new file mode 100644 index 0000000..9dc1537 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ContextMenu.java @@ -0,0 +1,70 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class ContextMenu; + using ContextMenuShared = ememory::SharedPtr; + using ContextMenuWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class ContextMenu : public ewol::widget::Container { + public: + enum markPosition { + markTop, + markRight, + markButtom, + markLeft, + markNone + }; + public: // properties + eproperty::Value propertyShape; //!< shape of the widget. + eproperty::Value propertyArrowPos; + eproperty::List propertyArrawBorder; + protected: + ContextMenu(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(ContextMenu, "ContextMenu"); + virtual ~ContextMenu(); + private: + ewol::compositing::Shaper m_shaper; //!< Compositing theme. + + // TODO : Use shaper for the arraw ... + ewol::compositing::Drawing m_compositing; + etk::Color<> m_colorBorder; // use shaper ID + + + float m_offset; + public: + void setPositionMarkAuto(const vec2& _origin, const vec2& _size); + void setPositionMark(enum markPosition _position, const vec2& _arrowPos); + protected: + void onDraw() override; + public: + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + void onChangeSize() override; + void calculateMinMaxSize() override; + ewol::WidgetShared getWidgetAtPos(const vec2& _pos) override; + protected: + virtual void onChangePropertyArrowPos(); + virtual void onChangePropertyArrawBorder(); + virtual void onChangePropertyShape(); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/Entry.cpp b/src/org/atriasoft/ewol/widget/Entry.cpp new file mode 100644 index 0000000..c47eb11 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Entry.cpp @@ -0,0 +1,612 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Entry); + +// DEFINE for the shader display system : +#define STATUS_NORMAL (0) +#define STATUS_HOVER (1) +#define STATUS_SELECTED (2) + +ewol::widget::Entry::Entry() : + signalClick(this, "click", "the user Click on the Entry box"), + signalEnter(this, "enter", "The cursor enter inside the button"), + signalModify(this, "modify", "Entry box value change"), + propertyPassword(this, "password", + false, + "Not display content in password mode", + &ewol::widget::Entry::onChangePropertyPassword), + propertyShape(this, "shape", + etk::Uri("THEME_GUI:///Entry.json?lib=ewol"), + "Shaper to display the background", + &ewol::widget::Entry::onChangePropertyShaper), + propertyValue(this, "value", + "", + "Value display in the entry (decorated text)", + &ewol::widget::Entry::onChangePropertyValue), + propertyMaxCharacter(this, "max", + 0x7FFFFFFF, 0, 0x7FFFFFFF, + "Maximum char that can be set on the Entry", + &ewol::widget::Entry::onChangePropertyMaxCharacter), + propertyRegex(this, "regex", + ".*", + "Control what it is write with a regular expression", + &ewol::widget::Entry::onChangePropertyRegex), + propertyTextWhenNothing(this, "empty-text", + "", + "Text when nothing is written", + &ewol::widget::Entry::onChangePropertyTextWhenNothing), + m_needUpdateTextPos(true), + m_displayStartPosition(0), + m_displayCursor(false), + m_displayCursorPos(0), + m_displayCursorPosSelection(0) { + addObjectType("ewol::widget::Entry"); + propertyCanFocus.setDirectCheck(true); +} + +void ewol::widget::Entry::init() { + ewol::Widget::init(); + propertyShape.notifyChange(); + + m_regex.compile(propertyRegex.get()); + if (m_regex.getStatus() == false) { + EWOL_ERROR("can not parse regex for : " << propertyRegex); + } + markToRedraw(); + + shortCutAdd("ctrl+w", "clean"); + shortCutAdd("ctrl+x", "cut"); + shortCutAdd("ctrl+c", "copy"); + shortCutAdd("ctrl+v", "paste"); + shortCutAdd("ctrl+a", "select:all"); + shortCutAdd("ctrl+shift+a", "select:none"); + signalShortcut.connect(sharedFromThis(), &ewol::widget::Entry::onCallbackShortCut); +} + + +ewol::widget::Entry::~Entry() { + +} + +void ewol::widget::Entry::onCallbackShortCut(const etk::String& _value) { + if (_value == "clean") { + onCallbackEntryClean(); + } else if (_value == "cut") { + onCallbackCut(); + } else if (_value == "copy") { + onCallbackCopy(); + } else if (_value == "paste") { + EWOL_WARNING("Request past ..."); + onCallbackPaste(); + } else if (_value == "select:all") { + onCallbackSelect(true); + } else if (_value == "select:none") { + onCallbackSelect(false); + } else { + EWOL_WARNING("Unknow event from ShortCut : " << _value); + } +} + +void ewol::widget::Entry::calculateMinMaxSize() { + // call main class + ewol::Widget::calculateMinMaxSize(); + // get generic padding + ewol::Padding padding = m_shaper.getPadding(); + int32_t minHeight = m_text.calculateSize(char32_t('A')).y(); + vec2 minimumSizeBase(20, minHeight); + // add padding : + minimumSizeBase += vec2(padding.x(), padding.y()); + m_minSize.setMax(minimumSizeBase); + // verify the min max of the min size ... + checkMinSize(); +} + + +void ewol::widget::Entry::onDraw() { + m_shaper.draw(); + m_text.draw(); +} + + +void ewol::widget::Entry::onRegenerateDisplay() { + if (needRedraw() == true) { + m_shaper.clear(); + m_text.clear(); + if (m_colorIdTextFg >= 0) { + m_text.setDefaultColorFg(m_shaper.getColor(m_colorIdTextFg)); + m_text.setDefaultColorBg(m_shaper.getColor(m_colorIdTextBg)); + m_text.setCursorColor(m_shaper.getColor(m_colorIdCursor)); + m_text.setSelectionColor(m_shaper.getColor(m_colorIdSelection)); + } + updateTextPosition(); + ewol::Padding padding = m_shaper.getPadding(); + + vec2 tmpSizeShaper = m_minSize; + if (propertyFill->x() == true) { + tmpSizeShaper.setX(m_size.x()); + } + if (propertyFill->y() == true) { + tmpSizeShaper.setY(m_size.y()); + } + + vec2 tmpOriginShaper = (m_size - tmpSizeShaper) / 2.0f; + vec2 tmpSizeText = tmpSizeShaper - vec2(padding.x(), padding.y()); + vec2 tmpOriginText = (m_size - tmpSizeText) / 2.0f; + // sometimes, the user define an height bigger than the real size needed == > in this case we need to center the text in the shaper ... + int32_t minHeight = m_text.calculateSize(char32_t('A')).y(); + if (tmpSizeText.y() > minHeight) { + tmpOriginText += vec2(0,(tmpSizeText.y()-minHeight)/2.0f); + } + // fix all the position in the int32_t class: + tmpSizeShaper = vec2ClipInt32(tmpSizeShaper); + tmpOriginShaper = vec2ClipInt32(tmpOriginShaper); + tmpSizeText = vec2ClipInt32(tmpSizeText); + tmpOriginText = vec2ClipInt32(tmpOriginText); + + m_text.reset(); + m_text.setClippingWidth(tmpOriginText, tmpSizeText); + m_text.setPos(tmpOriginText+vec2(m_displayStartPosition,0)); + if (m_displayCursorPosSelection != m_displayCursorPos) { + m_text.setCursorSelection(m_displayCursorPos, m_displayCursorPosSelection); + } else { + m_text.setCursorPos(m_displayCursorPos); + } + etk::UString valueToDisplay = etk::toUString(*propertyValue); + if (*propertyPassword == true) { + for (auto &it: valueToDisplay) { + it = '*'; + } + } + + if (valueToDisplay.size() != 0) { + m_text.print(valueToDisplay); + } else { + if (propertyTextWhenNothing->size() != 0) { + m_text.printDecorated(propertyTextWhenNothing); + } + } + m_text.setClippingMode(false); + + m_shaper.setShape(tmpOriginShaper, tmpSizeShaper, tmpOriginText, tmpSizeText); + } +} + + +void ewol::widget::Entry::updateCursorPosition(const vec2& _pos, bool _selection) { + ewol::Padding padding = m_shaper.getPadding(); + + vec2 relPos = relativePosition(_pos); + relPos.setX(relPos.x()-m_displayStartPosition - padding.xLeft()); + // try to find the new cursor position : + etk::String tmpDisplay = etk::String(propertyValue, 0, m_displayStartPosition); + int32_t displayHidenSize = m_text.calculateSize(tmpDisplay).x(); + //EWOL_DEBUG("hidenSize : " << displayHidenSize); + int32_t newCursorPosition = -1; + int32_t tmpTextOriginX = padding.xLeft(); + for (size_t iii=0; iiisize(); iii++) { + tmpDisplay = etk::String(propertyValue, 0, iii); + int32_t tmpWidth = m_text.calculateSize(tmpDisplay).x() - displayHidenSize; + if (tmpWidth >= relPos.x()-tmpTextOriginX) { + newCursorPosition = iii; + break; + } + } + if (newCursorPosition == -1) { + newCursorPosition = propertyValue->size(); + } + if (_selection == false) { + m_displayCursorPos = newCursorPosition; + m_displayCursorPosSelection = m_displayCursorPos; + markToRedraw(); + } else { + if (m_displayCursorPos == m_displayCursorPosSelection) { + m_displayCursorPosSelection = m_displayCursorPos; + } + m_displayCursorPos = newCursorPosition; + markToRedraw(); + } + markToUpdateTextPosition(); +} + + +void ewol::widget::Entry::removeSelected() { + if (m_displayCursorPosSelection == m_displayCursorPos) { + // nothing to cut ... + return; + } + int32_t pos1 = m_displayCursorPosSelection; + int32_t pos2 = m_displayCursorPos; + if(m_displayCursorPosSelection>m_displayCursorPos) { + pos2 = m_displayCursorPosSelection; + pos1 = m_displayCursorPos; + } + // remove data ... + m_displayCursorPos = pos1; + m_displayCursorPosSelection = pos1; + propertyValue.getDirect().erase(pos1, pos2-pos1); + markToRedraw(); +} + + +void ewol::widget::Entry::copySelectionToClipBoard(enum gale::context::clipBoard::clipboardListe _clipboardID) { + if (m_displayCursorPosSelection == m_displayCursorPos) { + // nothing to cut ... + return; + } + int32_t pos1 = m_displayCursorPosSelection; + int32_t pos2 = m_displayCursorPos; + if(m_displayCursorPosSelection>m_displayCursorPos) { + pos2 = m_displayCursorPosSelection; + pos1 = m_displayCursorPos; + } + // Copy + etk::String tmpData = etk::String(propertyValue, pos1, pos2); + gale::context::clipBoard::set(_clipboardID, tmpData); +} + + +bool ewol::widget::Entry::onEventInput(const ewol::event::Input& _event) { + EWOL_WARNING("Event on Input ... " << _event); + if (_event.getId() == 1) { + if (gale::key::status::pressSingle == _event.getStatus()) { + keepFocus(); + signalClick.emit(); + //nothing to do ... + return true; + } else if (gale::key::status::pressDouble == _event.getStatus()) { + keepFocus(); + // select word + m_displayCursorPosSelection = m_displayCursorPos-1; + // search forward + for (size_t iii=m_displayCursorPos; iii <= propertyValue->size(); iii++) { + if(iii == propertyValue->size()) { + m_displayCursorPos = iii; + break; + } + if(!( ( propertyValue.get()[iii] >= 'a' + && propertyValue.get()[iii] <= 'z') + || ( propertyValue.get()[iii] >= 'A' + && propertyValue.get()[iii] <= 'Z') + || ( propertyValue.get()[iii] >= '0' + && propertyValue.get()[iii] <= '9') + || propertyValue.get()[iii] == '_' + || propertyValue.get()[iii] == '-' + ) ) { + m_displayCursorPos = iii; + break; + } + } + // search backward + for (int64_t iii=m_displayCursorPosSelection; iii >= -1; iii--) { + if(iii == -1) { + m_displayCursorPosSelection = 0; + break; + } + if(!( ( propertyValue.get()[iii] >= 'a' + && propertyValue.get()[iii] <= 'z') + || ( propertyValue.get()[iii] >= 'A' + && propertyValue.get()[iii] <= 'Z') + || ( propertyValue.get()[iii] >= '0' + && propertyValue.get()[iii] <= '9') + || propertyValue.get()[iii] == '_' + || propertyValue.get()[iii] == '-' + ) ) { + m_displayCursorPosSelection = iii+1; + break; + } + } + // Copy to clipboard Middle ... + copySelectionToClipBoard(gale::context::clipBoard::clipboardSelection); + markToRedraw(); + } else if (gale::key::status::pressTriple == _event.getStatus()) { + keepFocus(); + m_displayCursorPosSelection = 0; + m_displayCursorPos = propertyValue->size(); + } else if (gale::key::status::down == _event.getStatus()) { + keepFocus(); + updateCursorPosition(_event.getPos()); + markToRedraw(); + } else if (gale::key::status::move == _event.getStatus()) { + keepFocus(); + updateCursorPosition(_event.getPos(), true); + markToRedraw(); + } else if (gale::key::status::up == _event.getStatus()) { + keepFocus(); + updateCursorPosition(_event.getPos(), true); + // Copy to clipboard Middle ... + copySelectionToClipBoard(gale::context::clipBoard::clipboardSelection); + markToRedraw(); + } + } + else if( gale::key::type::mouse == _event.getType() + && _event.getId() == 2) { + if( _event.getStatus() == gale::key::status::down + || _event.getStatus() == gale::key::status::move + || _event.getStatus() == gale::key::status::up) { + keepFocus(); + // updatethe cursor position : + updateCursorPosition(_event.getPos()); + } + // Paste current selection only when up button + if (_event.getStatus() == gale::key::status::up) { + keepFocus(); + // middle button => past data... + gale::context::clipBoard::request(gale::context::clipBoard::clipboardSelection); + } + } + return false; +} + + +bool ewol::widget::Entry::onEventEntry(const ewol::event::Entry& _event) { + EWOL_WARNING("Event on Entry ... " << _event); + if (_event.getType() == gale::key::keyboard::character) { + if(_event.getStatus() == gale::key::status::down) { + // remove curent selected data ... + removeSelected(); + if( _event.getChar() == '\n' + || _event.getChar() == '\r') { + signalEnter.emit(propertyValue); + return true; + } else if (_event.getChar() == 0x7F) { + // SUPPR : + if (propertyValue->size() > 0 && m_displayCursorPos < (int64_t)propertyValue->size()) { + propertyValue.getDirect().erase(m_displayCursorPos, 1); + m_displayCursorPos = etk::max(m_displayCursorPos, 0); + m_displayCursorPosSelection = m_displayCursorPos; + } + } else if (_event.getChar() == 0x08) { + // DEL : + if (propertyValue->size() > 0 && m_displayCursorPos != 0) { + propertyValue.getDirect().erase(m_displayCursorPos-1, 1); + m_displayCursorPos--; + m_displayCursorPos = etk::max(m_displayCursorPos, 0); + m_displayCursorPosSelection = m_displayCursorPos; + } + } else if(_event.getChar() >= 20) { + EWOL_ERROR("get data: '" << _event.getChar() << "' = '" << u32char::convertToUtf8(_event.getChar()) << "'"); + if ((int64_t)propertyValue->size() > propertyMaxCharacter) { + EWOL_INFO("Reject data for entry : '" << _event.getChar() << "'"); + } else { + etk::String newData = propertyValue; + etk::String inputData = u32char::convertToUtf8(_event.getChar()); + newData.insert(newData.begin()+m_displayCursorPos, inputData); + setInternalValue(newData); + if (propertyValue.get() == newData) { + m_displayCursorPos += inputData.size(); + m_displayCursorPosSelection = m_displayCursorPos; + } + } + } + signalModify.emit(propertyValue); + markToRedraw(); + return true; + } + return false; + } else { + if(_event.getStatus() == gale::key::status::down) { + switch (_event.getType()) { + case gale::key::keyboard::left: + m_displayCursorPos--; + break; + case gale::key::keyboard::right: + m_displayCursorPos++; + break; + case gale::key::keyboard::start: + m_displayCursorPos = 0; + break; + case gale::key::keyboard::end: + m_displayCursorPos = propertyValue->size(); + break; + default: + return false; + } + m_displayCursorPos = etk::avg(0, m_displayCursorPos, (int32_t)propertyValue->size()); + m_displayCursorPosSelection = m_displayCursorPos; + markToRedraw(); + return true; + } + } + return false; +} + +void ewol::widget::Entry::setInternalValue(const etk::String& _newData) { + etk::String previous = propertyValue; + // check the RegExp : + if (_newData.size()>0) { + /* + if (m_regex.parse(_newData, 0, _newData.size()) == false) { + EWOL_INFO("The input data does not match with the regExp '" << _newData << "' Regex='" << propertyRegex << "'" ); + return; + } + if (m_regex.start() != 0) { + EWOL_INFO("The input data does not match with the regExp '" << _newData << "' Regex='" << propertyRegex << "' (start position error)" ); + return; + } + if (m_regex.stop() != _newData.size()) { + EWOL_INFO("The input data does not match with the regExp '" << _newData << "' Regex='" << propertyRegex << "' (stop position error)" ); + return; + } + */ + } + propertyValue.setDirect(_newData); + markToRedraw(); +} + +void ewol::widget::Entry::onEventClipboard(enum gale::context::clipBoard::clipboardListe _clipboardID) { + // remove curent selected data ... + removeSelected(); + // get current selection / Copy : + etk::String tmpData = get(_clipboardID); + // add it on the current display : + if (tmpData.size() != 0) { + etk::String newData = propertyValue; + newData.insert(m_displayCursorPos, &tmpData[0]); + setInternalValue(newData); + if (propertyValue.get() == newData) { + if (propertyValue->size() == tmpData.size()) { + m_displayCursorPos = tmpData.size(); + } else { + m_displayCursorPos += tmpData.size(); + } + m_displayCursorPosSelection = m_displayCursorPos; + markToRedraw(); + } + } + signalModify.emit(propertyValue); +} + +void ewol::widget::Entry::onCallbackEntryClean() { + propertyValue.setDirect(""); + m_displayStartPosition = 0; + m_displayCursorPos = 0; + m_displayCursorPosSelection = m_displayCursorPos; + markToRedraw(); +} + +void ewol::widget::Entry::onCallbackCut() { + copySelectionToClipBoard(gale::context::clipBoard::clipboardStd); + removeSelected(); + signalModify.emit(propertyValue); +} + +void ewol::widget::Entry::onCallbackCopy() { + copySelectionToClipBoard(gale::context::clipBoard::clipboardStd); +} + +void ewol::widget::Entry::onCallbackPaste() { + gale::context::clipBoard::request(gale::context::clipBoard::clipboardStd); +} + +void ewol::widget::Entry::onCallbackSelect(bool _all) { + if(_all == true) { + m_displayCursorPosSelection = 0; + m_displayCursorPos = propertyValue->size(); + } else { + m_displayCursorPosSelection = m_displayCursorPos; + } + markToRedraw(); +} + +void ewol::widget::Entry::markToUpdateTextPosition() { + m_needUpdateTextPos = true; +} + +void ewol::widget::Entry::updateTextPosition() { + if (m_needUpdateTextPos == false) { + return; + } + ewol::Padding padding = m_shaper.getPadding(); + + int32_t tmpSizeX = m_minSize.x(); + if (propertyFill->x() == true) { + tmpSizeX = m_size.x(); + } + int32_t tmpUserSize = tmpSizeX - padding.x(); + int32_t totalWidth = m_text.calculateSize(propertyValue).x(); + // Check if the data inside the display can be contain in the entry box + if (totalWidth < tmpUserSize) { + // all can be display : + m_displayStartPosition = 0; + } else { + // all can not be set : + etk::String tmpDisplay = etk::String(propertyValue, 0, m_displayCursorPos); + int32_t pixelCursorPos = m_text.calculateSize(tmpDisplay).x(); + // check if the Cussor is visible at 10px nearest the border : + int32_t tmp1 = pixelCursorPos+m_displayStartPosition; + EWOL_DEBUG("cursorPos=" << pixelCursorPos << "px maxSize=" << tmpUserSize << "px tmp1=" << tmp1); + if (tmp1<10) { + // set the cursor on le left + m_displayStartPosition = etk::min(-pixelCursorPos+10, 0); + } else if (tmp1>tmpUserSize-10) { + // set the cursor of the Right + m_displayStartPosition = etk::min(-pixelCursorPos + tmpUserSize - 10, 0); + } + // else : the cursor is inside the display + //m_displayStartPosition = -totalWidth + tmpUserSize; + } +} + +void ewol::widget::Entry::onGetFocus() { + m_displayCursor = true; + changeStatusIn(STATUS_SELECTED); + showKeyboard(); + markToRedraw(); +} + +void ewol::widget::Entry::onLostFocus() { + m_displayCursor = false; + changeStatusIn(STATUS_NORMAL); + hideKeyboard(); + markToRedraw(); +} + +void ewol::widget::Entry::changeStatusIn(int32_t _newStatusId) { + if (m_shaper.changeStatusIn(_newStatusId) == true) { + m_PCH = getObjectManager().periodicCall.connect(this, &ewol::widget::Entry::periodicCall); + markToRedraw(); + } +} + +void ewol::widget::Entry::periodicCall(const ewol::event::Time& _event) { + if (m_shaper.periodicCall(_event) == false) { + m_PCH.disconnect(); + } + markToRedraw(); +} + +void ewol::widget::Entry::onChangePropertyPassword() { + markToRedraw(); +} + +void ewol::widget::Entry::onChangePropertyShaper() { + m_shaper.setSource(propertyShape.get()); + m_colorIdTextFg = m_shaper.requestColor("text-foreground"); + m_colorIdTextBg = m_shaper.requestColor("text-background"); + m_colorIdCursor = m_shaper.requestColor("text-cursor"); + m_colorIdSelection = m_shaper.requestColor("text-selection"); +} + +void ewol::widget::Entry::onChangePropertyValue() { + etk::String newData = propertyValue.get(); + if ((int64_t)newData.size() > propertyMaxCharacter) { + newData = etk::String(newData, 0, propertyMaxCharacter); + EWOL_DEBUG("Limit entry set of data... " << etk::String(newData, propertyMaxCharacter)); + } + // set the value with the check of the RegExp ... + setInternalValue(newData); + if (newData == propertyValue.get()) { + m_displayCursorPos = propertyValue->size(); + m_displayCursorPosSelection = m_displayCursorPos; + EWOL_VERBOSE("Set : '" << newData << "'"); + } + markToRedraw(); +} + +void ewol::widget::Entry::onChangePropertyMaxCharacter() { + // TODO : check nomber of char in the data +} + +void ewol::widget::Entry::onChangePropertyRegex() { + m_regex.compile(propertyRegex.get()); + if (m_regex.getStatus() == false) { + EWOL_ERROR("can not parse regex for : " << propertyRegex); + } + markToRedraw(); +} + +void ewol::widget::Entry::onChangePropertyTextWhenNothing() { + markToRedraw(); +} + diff --git a/src/org/atriasoft/ewol/widget/Entry.java b/src/org/atriasoft/ewol/widget/Entry.java new file mode 100644 index 0000000..66eb62f --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Entry.java @@ -0,0 +1,141 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Entry; + using EntryShared = ememory::SharedPtr; + using EntryWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + * @brief Entry box display : + * + * ~~~~~~~~~~~~~~~~~~~~~~ + * ---------------------------------------------- + * | Editable Text | + * ---------------------------------------------- + * ~~~~~~~~~~~~~~~~~~~~~~ + */ + class Entry : public ewol::Widget { + public: // Event list + esignal::Signal<> signalClick; //!< bang on click the entry box + esignal::Signal signalEnter; //!< Enter key is pressed + esignal::Signal signalModify; //!< data change + public: // propertie list + eproperty::Value propertyPassword; //!< Disable display of the content of the entry + eproperty::Value propertyShape; + eproperty::Value propertyValue; //!< string that must be displayed + eproperty::Range propertyMaxCharacter; //!< number max of xharacter in the list + eproperty::Value propertyRegex; //!< regular expression value + eproperty::Value propertyTextWhenNothing; //!< Text to display when nothing in in the entry (decorated text...) + private: + ewol::compositing::Shaper m_shaper; + int32_t m_colorIdTextFg; //!< color property of the text foreground + int32_t m_colorIdTextBg; //!< color property of the text background + int32_t m_colorIdCursor; //!< color property of the text cursor + int32_t m_colorIdSelection; //!< color property of the text selection + ewol::compositing::Text m_text; //!< text display m_text + protected: + /** + * @brief Contuctor + * @param[in] _newData The USting that might be set in the Entry box (no event generation!!) + */ + Entry(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(Entry, "Entry"); + /** + * @brief Destuctor + */ + virtual ~Entry(); + protected: + /** + * @brief internal check the value with RegExp checking + * @param[in] _newData The new string to display + */ + void setInternalValue(const etk::String& _newData); + private: + etk::RegEx m_regex; //!< regular expression to check content + private: + bool m_needUpdateTextPos; //!< text position can have change + int32_t m_displayStartPosition; //!< ofset in pixel of the display of the UString + bool m_displayCursor; //!< Cursor must be display only when the widget has the focus + int32_t m_displayCursorPos; //!< Cursor position in number of Char + int32_t m_displayCursorPosSelection; //!< Selection position end (can be befor or after cursor and == m_displayCursorPos chan no selection availlable + protected: + /** + * @brief informe the system thet the text change and the start position change + */ + virtual void markToUpdateTextPosition(); + /** + * @brief update the display position start == > depending of the position of the Cursor and the size of the Data inside + * @change m_displayStartPosition < == updated + */ + virtual void updateTextPosition(); + /** + * @brief change the cursor position with the curent position requested on the display + * @param[in] _pos Absolute position of the event + * @note The display is automaticly requested when change apear. + */ + virtual void updateCursorPosition(const vec2& _pos, bool _Selection=false); + public: + /** + * @brief Copy the selected data on the specify clipboard + * @param[in] _clipboardID Selected clipboard + */ + virtual void copySelectionToClipBoard(enum gale::context::clipBoard::clipboardListe _clipboardID); + /** + * @brief remove the selected area + * @note This request a regeneration of the display + */ + virtual void removeSelected(); + public: + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + bool onEventEntry(const ewol::event::Entry& _event) override; + void onEventClipboard(enum gale::context::clipBoard::clipboardListe _clipboardID) override; + void calculateMinMaxSize() override; + protected: + void onDraw() override; + void onGetFocus() override; + void onLostFocus() override; + virtual void changeStatusIn(int32_t _newStatusId); + protected: + esignal::Connection m_PCH; //!< Periodic call handle to remove it when needed + /** + * @brief Periodic call to update grapgic display + * @param[in] _event Time generic event + */ + void periodicCall(const ewol::event::Time& _event); + private: // callback functions + void onCallbackShortCut(const etk::String& _value); + void onCallbackEntryClean(); + void onCallbackCut(); + void onCallbackCopy(); + void onCallbackPaste(); + void onCallbackSelect(bool _all); + protected: + virtual void onChangePropertyPassword(); + virtual void onChangePropertyShaper(); + virtual void onChangePropertyValue(); + virtual void onChangePropertyMaxCharacter(); + virtual void onChangePropertyRegex(); + virtual void onChangePropertyTextWhenNothing(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/Gird.cpp b/src/org/atriasoft/ewol/widget/Gird.cpp new file mode 100644 index 0000000..503662b --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Gird.cpp @@ -0,0 +1,330 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::Gird); + +ewol::widget::Gird::Gird() : + m_sizeRow(0), + m_tmpWidget(null), + m_gavityButtom(true), + m_borderSize(0,0) { + addObjectType("ewol::widget::Gird"); + requestUpdateSize(); +} + +ewol::widget::Gird::~Gird() { + EWOL_DEBUG("[" << getId() << "]={" << getObjectType() << "} Gird : destroy"); + subWidgetRemoveAll(); +} + +void ewol::widget::Gird::setBorderSize(const ivec2& _newBorderSize) { + m_borderSize = _newBorderSize; + if (m_borderSize.x() < 0) { + EWOL_ERROR("Try to set a border size <0 on x : " << m_borderSize.x() << " == > restore to 0"); + m_borderSize.setX(0); + } + if (m_borderSize.y() < 0) { + EWOL_ERROR("Try to set a border size <0 on y : " << m_borderSize.y() << " == > restore to 0"); + m_borderSize.setY(0); + } + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::Gird::onChangeSize() { + //EWOL_DEBUG("Update size"); + m_size -= m_borderSize*2; + + for (size_t iii=0; iiigetPixel(); + m_maxSize = propertyMaxSize->getPixel(); + m_uniformSizeRow = 0; + m_minSize += m_borderSize*2; + int32_t lastLineID = 0; + for (size_t iii=0; iii lastLineID) { + // change of line : + lastLineID = m_subWidget[iii].row; + } + if (m_subWidget[iii].widget != null) { + m_subWidget[iii].widget->calculateMinMaxSize(); + vec2 tmpSize = m_subWidget[iii].widget->getCalculateMinSize(); + EWOL_DEBUG(" [" << iii << "] subWidgetMinSize=" << tmpSize); + // for all we get the max size : + m_uniformSizeRow = etk::max((int32_t)tmpSize.y(), m_uniformSizeRow); + // for the colomn size : We set the autamatic value in negative : + if (m_sizeCol[m_subWidget[iii].col] <= 0) { + m_sizeCol[m_subWidget[iii].col] = etk::min(m_sizeCol[m_subWidget[iii].col], (int32_t)-tmpSize.x() ); + } + } + } + + if (m_sizeRow > 0) { + m_uniformSizeRow = m_sizeRow; + } + int32_t tmpSizeWidth = 0; + for (size_t iii=0; iii it is not the case ==> the herited class must call the \"OnObjectRemove\" function..."); + } + } else { + EWOL_WARNING("[" << getId() << "] Must not have null pointer on the subWidget list ..."); + m_subWidget.erase(m_subWidget.begin()+iii); + } + errorControl = m_subWidget.size(); + } + } + // just add the col size: + m_sizeCol.erase(m_sizeCol.end()); + } else { + // just add the col size: + for (int32_t iii=m_sizeCol.size()-1; iii<_colNumber-1 ; iii++) { + m_sizeCol.pushBack(0); + } + } +} + +void ewol::widget::Gird::setColSize(int32_t _colId, int32_t _size) { + if ((int64_t)m_sizeCol.size() > _colId) { + m_sizeCol[_colId] = _size; + } else { + EWOL_ERROR("Can not set the Colomn size : " << _colId+1 + << " at " << _size << "px we have " + << m_sizeCol.size() << " colomn"); + } +} + +void ewol::widget::Gird::setRowSize(int32_t _size) { + m_sizeRow = _size; +} + +int32_t ewol::widget::Gird::getColSize(int32_t _colId) { + if ((int64_t)m_sizeCol.size() > _colId) { + if (m_sizeCol[_colId] <= 0) { + return 0; + } + return m_sizeCol[_colId]; + } + EWOL_ERROR("Can not get the Colomn size : " << _colId+1 << " we have "<< m_sizeCol.size() << " colomn"); + return 0; +} + +int32_t ewol::widget::Gird::getRowSize() { + return m_sizeRow; +} + +void ewol::widget::Gird::subWidgetRemoveAll() { + size_t errorControl = m_subWidget.size(); + m_subWidget.clear(); +} + + +void ewol::widget::Gird::subWidgetAdd(int32_t _colId, int32_t _rowId, ewol::WidgetShared _newWidget) { + if (_newWidget == null) { + return; + } + GirdProperties prop; + prop.row = _rowId; + prop.col = _colId; + prop.widget = _newWidget; + + // need to find the correct position : + for (size_t iii=0; iii prop.row) { + // find a new position; + m_subWidget.insert(m_subWidget.begin()+iii, prop); + return; + } else { + if (m_subWidget[iii].col < prop.col) { + continue; + } else if (m_subWidget[iii].col > prop.col) { + // find a new position; + m_subWidget.insert(m_subWidget.begin()+iii, prop); + return; + } else { + // The element already exist == > replace it ... + m_tmpWidget = m_subWidget[iii].widget; + m_subWidget[iii].widget = _newWidget; + if (m_tmpWidget != null) { + m_tmpWidget.reset(); + if (m_tmpWidget != null) { + EWOL_CRITICAL("[" << getId() << "] Error while replacing a widget ... == > never call when free"); + m_tmpWidget = null; + } + } + } + } + } + // not find == > just adding it ... + m_subWidget.pushBack(prop); +} + +void ewol::widget::Gird::subWidgetRemove(ewol::WidgetShared _newWidget) { + for (size_t iii=0; iiisystemDraw(_displayProp); + } + } +} + +void ewol::widget::Gird::onRegenerateDisplay() { + for (auto &it : m_subWidget) { + if (it.widget != null) { + it.widget->onRegenerateDisplay(); + } + } +} + +ewol::WidgetShared ewol::widget::Gird::getWidgetAtPos(const vec2& _pos) { + if (*propertyHide == true) { + return null; + } + // for all element in the sizer ... + for (auto &it : m_subWidget) { + if (it.widget == null) { + continue; + } + vec2 tmpSize = it.widget->getSize(); + vec2 tmpOrigin = it.widget->getOrigin(); + if( (tmpOrigin.x() <= _pos.x() && tmpOrigin.x() + tmpSize.x() >= _pos.x()) + && (tmpOrigin.y() <= _pos.y() && tmpOrigin.y() + tmpSize.y() >= _pos.y()) ) { + ewol::WidgetShared tmpWidget = it.widget->getWidgetAtPos(_pos); + if (tmpWidget != null) { + return tmpWidget; + } + // stop searching + break; + } + } + return null; +} + diff --git a/src/org/atriasoft/ewol/widget/Gird.java b/src/org/atriasoft/ewol/widget/Gird.java new file mode 100644 index 0000000..aa07daf --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Gird.java @@ -0,0 +1,146 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Gird; + using GirdShared = ememory::SharedPtr; + using GirdWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Gird :public ewol::Widget { + private: + class GirdProperties { + public: + ewol::WidgetShared widget; + int32_t row; + int32_t col; + }; + int32_t m_sizeRow; //!< size of all lines (row) (if set (otherwise 0)) == > we have a only one size ==> multiple size will have no use ... + int32_t m_uniformSizeRow; + etk::Vector m_sizeCol; //!< size of all colomn (if set (otherwise 0)) + etk::Vector m_subWidget; //!< all sub widget are contained in this element + ewol::WidgetShared m_tmpWidget; //!< use when replace a widget ... + bool m_gavityButtom; + protected: + /** + * @brief Constructor + */ + Gird(); + public: + DECLARE_WIDGET_FACTORY(Gird, "Gird"); + /** + * @brief Desstructor + */ + virtual ~Gird(); + /** + * @brief set the number of colomn + * @param[in] colNumber Nuber of colomn + */ + void setColNumber(int32_t _colNumber); + /** + * @brief change a size view of a colomn. + * @param[in] colId Id of the colomn [0..x]. + * @param[in] size size of the colomn. + */ + void setColSize(int32_t _colId, int32_t _size); + /** + * @brief change a size view of a line. + * @param[in] size size of the line. + */ + void setRowSize(int32_t _size); + /** + * @brief get the size view of a colomn. + * @param[in] colId Id of the colomn [0..x]. + * @return The size of the colomn. + */ + int32_t getColSize(int32_t _colId); + /** + * @brief get the size view of the lines. + * @return The size of the lines. + */ + int32_t getRowSize(); + /** + * @brief set the gravity of the widget on the Button (index 0 is on buttom) + */ + void setGravityButtom() { + m_gavityButtom = true; + markToRedraw(); + } + /** + * @brief set the gravity of the widget on the Top (index 0 is on top) + */ + void setGravityTop() { + m_gavityButtom = false; + markToRedraw(); + } + public: + /** + * @brief remove all sub element from the widget. + */ + virtual void subWidgetRemoveAll(); + /** + * @brief add at end position a Widget (note : This system use an inverted phylisophie (button to top, and left to right) + * @param[in] _colId Id of the colomn [0..x]. + * @param[in] _rowId Id of the row [0..y]. + * @param[in] _newWidget the element pointer + */ + virtual void subWidgetAdd(int32_t _colId, int32_t _rowId, ewol::WidgetShared _newWidget); + /** + * @brief remove definitly a widget from the system and this Gird. + * @param[in] _newWidget the element pointer. + */ + virtual void subWidgetRemove(ewol::WidgetShared _newWidget); + /** + * @brief remove definitly a widget from the system and this Gird. + * @param[in] _colId Id of the colomn [0..x]. + * @param[in] _rowId Id of the row [0..y]. + */ + virtual void subWidgetRemove(int32_t _colId, int32_t _rowId); + /** + * @brief Just unlick the specify widget, this function does not remove it from the system (if you can, do nt use it ...). + * @param[in] _newWidget the element pointer. + */ + virtual void subWidgetUnLink(ewol::WidgetShared _newWidget); + /** + * @brief Just unlick the specify widget, this function does not remove it from the system (if you can, do nt use it ...). + * @param[in] _colId Id of the colomn [0..x]. + * @param[in] _rowId Id of the row [0..y]. + */ + virtual void subWidgetUnLink(int32_t _colId, int32_t _rowId); + private: + // TODO : property + ivec2 m_borderSize; //!< Border size needed for all the display + public: + /** + * @brief set the current border size of the current element: + * @param[in] _newBorderSize The border size to set (0 if not used) + */ + void setBorderSize(const ivec2& _newBorderSize); + /** + * @brief get the current border size of the current element: + * @return the border size (0 if not used) + */ + const ivec2& getBorderSize() { + return m_borderSize; + }; + public: + virtual void systemDraw(const ewol::DrawProperty& _displayProp) override; + virtual void onRegenerateDisplay() override; + virtual ewol::WidgetShared getWidgetAtPos(const vec2& pos) override; + virtual void onChangeSize() override; + virtual void calculateMinMaxSize() override; + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/Image.cpp b/src/org/atriasoft/ewol/widget/Image.cpp new file mode 100644 index 0000000..00f4e3b --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Image.cpp @@ -0,0 +1,239 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::Image); + +ewol::widget::Image::Image() : + signalPressed(this, "pressed", "Image is pressed"), + propertySource(this, "src", "", "Image source path", &ewol::widget::Image::onChangePropertySource), + propertyBorder(this, "border", vec2(0,0), "Border of the image", &ewol::widget::Image::onChangePropertyGlobalSize), + propertyImageSize(this, "size", vec2(0,0), "Basic display size of the image", &ewol::widget::Image::onChangePropertyGlobalSize), + propertyKeepRatio(this, "ratio", true, "Keep ratio of the image", &ewol::widget::Image::onChangePropertyGlobalSize), + propertyPosStart(this, "part-start", vec2(0.0f, 0.0f), vec2(0.0f, 0.0f), vec2(1.0f, 1.0f), "Start display position in the image", &ewol::widget::Image::onChangePropertyGlobalSize), + propertyPosStop(this, "part-stop", vec2(1.0f, 1.0f), vec2(0.0f, 0.0f), vec2(1.0f, 1.0f), "Start display position in the image", &ewol::widget::Image::onChangePropertyGlobalSize), + propertyDistanceFieldMode(this, "distance-field", false, "Distance field mode", &ewol::widget::Image::onChangePropertyDistanceFieldMode), + propertySmooth(this, "smooth", true, "Smooth display of the image", &ewol::widget::Image::onChangePropertySmooth), + propertyUseThemeColor(this, "use-theme-color", false, "use the theme color to display images", &ewol::widget::Image::onChangePropertyUseThemeColor), + m_colorProperty(null), + m_colorId(-1) { + addObjectType("ewol::widget::Image"); + m_imageRenderSize = vec2(0,0); + m_colorProperty = ewol::resource::ColorFile::create(etk::Uri("THEME_COLOR:///Image.json?lib=ewol")); + if (m_colorProperty != null) { + m_colorId = m_colorProperty->request("foreground"); + } +} +ewol::widget::Image::~Image() { + +} + +void ewol::widget::Image::init() { + ewol::Widget::init(); + if (*propertySource != "") { + onChangePropertySource(); + } +} + +void ewol::widget::Image::set(const etk::Uri& _uri, const gale::Dimension& _border) { + EWOL_VERBOSE("Set Image : " << _uri << " border=" << _border); + propertyBorder.set(_border); + propertySource.set(_uri); +} + +void ewol::widget::Image::setCustumSource(const egami::Image& _image) { + // TODO : Better interfacing of all element internal ==> this is a temporary prototype + m_compositing.setSource(_image); + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::Image::onDraw() { + m_compositing.draw(); +} + +void ewol::widget::Image::onRegenerateDisplay() { + if (needRedraw() == false) { + return; + } + // remove data of the previous composition : + m_compositing.clear(); + if ( *propertyUseThemeColor == true + && m_colorProperty != null) { + m_compositing.setColor(m_colorProperty->get(m_colorId)); + } + // Calculate the new position and size: + vec2 imageBoder = propertyBorder->getPixel(); + vec2 origin = imageBoder; + imageBoder *= 2.0f; + vec2 imageRealSize = m_imageRenderSize - imageBoder; + vec2 imageRealSizeMax = m_size - imageBoder; + + vec2 ratioSizeDisplayRequested = *propertyPosStop - *propertyPosStart; + //imageRealSizeMax *= ratioSizeDisplayRequested; + + vec2 delta = ewol::gravityGenerateDelta(*propertyGravity, m_size-m_imageRenderSize); + if (propertyFill->x() == true) { + imageRealSize.setX(imageRealSizeMax.x()); + delta.setX(0.0); + } + if (propertyFill->y() == true) { + imageRealSize.setY(imageRealSizeMax.y()); + delta.setY(0.0); + } + origin += delta; + + if (*propertyKeepRatio == true) { + vec2 tmpSize = m_compositing.getRealSize(); + //float ratio = tmpSize.x() / tmpSize.y(); + float ratio = (tmpSize.x()*ratioSizeDisplayRequested.x()) / (tmpSize.y() * ratioSizeDisplayRequested.y()); + //float ratioCurrent = (imageRealSize.x()*ratioSizeDisplayRequested.x()) / (imageRealSize.y() * ratioSizeDisplayRequested.y()); + float ratioCurrent = imageRealSize.x() / imageRealSize.y(); + if (ratio == ratioCurrent) { + // nothing to do ... + } else if (ratio < ratioCurrent) { + float oldX = imageRealSize.x(); + imageRealSize.setX(imageRealSize.y()*ratio); + origin += vec2((oldX - imageRealSize.x()) * 0.5f, 0); + } else { + float oldY = imageRealSize.y(); + imageRealSize.setY(imageRealSize.x()/ratio); + origin += vec2(0, (oldY - imageRealSize.y()) * 0.5f); + } + } + + // set the somposition properties : + if (*propertySmooth == true) { + m_compositing.setPos(origin); + } else { + m_compositing.setPos(ivec2(origin)); + } + m_compositing.printPart(imageRealSize, *propertyPosStart, *propertyPosStop); + EWOL_DEBUG("Paint Image at : " << origin << " size=" << imageRealSize); + EWOL_DEBUG("Paint Image :" << *propertySource << " realsize=" << m_compositing.getRealSize() << " origin=" << origin << " size=" << imageRealSize); + EWOL_DEBUG(" start=" << *propertyPosStart << " stop=" << *propertyPosStop); +} + +void ewol::widget::Image::calculateMinMaxSize() { + EWOL_DEBUG("calculate min size: border=" << propertyBorder << " size=" << propertyImageSize << " min-size=" << propertyMinSize); + vec2 imageBoder = propertyBorder->getPixel()*2.0f; + vec2 imageSize = propertyImageSize->getPixel(); + vec2 size = propertyMinSize->getPixel(); + EWOL_DEBUG(" ==> border=" << imageBoder << " size=" << imageSize << " min-size=" << size); + if (imageSize != vec2(0,0)) { + m_minSize = imageBoder+imageSize; + m_maxSize = m_minSize; + } else { + vec2 imageSizeReal = m_compositing.getRealSize(); + EWOL_VERBOSE(" Real Size = " << imageSizeReal); + vec2 min1 = imageBoder+propertyMinSize->getPixel(); + m_minSize = imageBoder+imageSizeReal; + EWOL_VERBOSE(" set max : " << m_minSize << " min1=" << min1); + m_minSize.setMax(min1); + EWOL_VERBOSE(" result : " << m_minSize); + m_maxSize = imageBoder+propertyMaxSize->getPixel(); + m_minSize.setMin(m_maxSize); + } + m_imageRenderSize = m_minSize; + m_minSize.setMax(size); + m_maxSize.setMax(m_minSize); + EWOL_DEBUG("set widget min=" << m_minSize << " max=" << m_maxSize << " with real Image size=" << m_imageRenderSize << " img size=" << imageSize << " " << propertyImageSize); + markToRedraw(); +} + + +bool ewol::widget::Image::onEventInput(const ewol::event::Input& _event) { + //EWOL_DEBUG("Event on BT ..."); + if (_event.getId() == 1) { + if(gale::key::status::pressSingle == _event.getStatus()) { + signalPressed.emit(); + return true; + } + } + return false; +} + +bool ewol::widget::Image::loadXML(const exml::Element& _node) { + if (_node.exist() == false) { + return false; + } + ewol::Widget::loadXML(_node); + // get internal data : + + etk::String tmpAttributeValue = _node.attributes["ratio"]; + if (tmpAttributeValue.size() != 0) { + if (etk::compare_no_case(tmpAttributeValue, "true") == true) { + propertyKeepRatio.setDirect(true); + } else if (tmpAttributeValue == "1") { + propertyKeepRatio.setDirect(true); + } else { + propertyKeepRatio.setDirect(false); + } + } + tmpAttributeValue = _node.attributes["size"]; + if (tmpAttributeValue.size() != 0) { + //EWOL_CRITICAL(" Parse SIZE : " << tmpAttributeValue); + propertyImageSize.setDirect(tmpAttributeValue); + //EWOL_CRITICAL(" == > " << propertyImageSize); + } + tmpAttributeValue = _node.attributes["border"]; + if (tmpAttributeValue.size() != 0) { + propertyBorder.setDirect(tmpAttributeValue); + } + tmpAttributeValue = _node.attributes["smooth"]; + if (tmpAttributeValue.size() != 0) { + propertySmooth.setDirect(etk::string_to_bool(tmpAttributeValue)); + } + //EWOL_DEBUG("Load label:" << node->ToElement()->getText()); + if (_node.nodes.size() != 0) { + propertySource.set(_node.getText()); + } else { + tmpAttributeValue = _node.attributes["src"]; + if (tmpAttributeValue.size() != 0) { + propertySource.set(tmpAttributeValue); + } + } + return true; +} + +void ewol::widget::Image::onChangePropertySource() { + markToRedraw(); + requestUpdateSize(); + EWOL_VERBOSE("Set sources : " << *propertySource << " size=" << *propertyImageSize); + m_compositing.setSource(*propertySource, propertyImageSize->getPixel()); +} + +void ewol::widget::Image::onChangePropertyImageSize() { + markToRedraw(); + requestUpdateSize(); + EWOL_VERBOSE("Set sources : " << *propertySource << " size=" << *propertyImageSize); + m_compositing.setSource(*propertySource, propertyImageSize->getPixel()); +} + +void ewol::widget::Image::onChangePropertyGlobalSize() { + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::Image::onChangePropertySmooth() { + markToRedraw(); +} + +void ewol::widget::Image::onChangePropertyDistanceFieldMode() { + m_compositing.setDistanceFieldMode(*propertyDistanceFieldMode); + markToRedraw(); +} + +void ewol::widget::Image::onChangePropertyUseThemeColor() { + markToRedraw(); +} + diff --git a/src/org/atriasoft/ewol/widget/Image.java b/src/org/atriasoft/ewol/widget/Image.java new file mode 100644 index 0000000..e0920c9 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Image.java @@ -0,0 +1,82 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Image; + using ImageShared = ememory::SharedPtr; + using ImageWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Image :public ewol::Widget { + public: // signals + esignal::Signal<> signalPressed; + public: // properties + eproperty::Value propertySource; //!< file name of the image. + eproperty::Value propertyBorder; //!< border to add at the image. + eproperty::Value propertyImageSize; //!< border to add at the image. + eproperty::Value propertyKeepRatio; //!< keep the image ratio between width and hight + eproperty::Range propertyPosStart; //!< position in the image to start the sisplay (when we want not to display all the image) + eproperty::Range propertyPosStop; //!< position in the image to start the sisplay (when we want not to display all the image) + eproperty::Value propertyDistanceFieldMode; //!< to have a parameter + eproperty::Value propertySmooth; //!< display is done in the pixed approximation if false + eproperty::Value propertyUseThemeColor; //!< Use the themo color management ("THEME_COLOR:///Image.json?lib=ewol") default false + protected: + ewol::compositing::Image m_compositing; //!< compositing element of the image. + ememory::SharedPtr m_colorProperty; //!< theme color property + int32_t m_colorId; //!< Color of the image. + public: + /** + * @brief + */ + Image(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(Image, "Image"); + /** + * @brief + */ + virtual ~Image(); + /** + * @brief set All the configuration of the current image + * @param[in] _uri URI of the new image + * @param[in] _border New border size to set + */ + void set(const etk::Uri& _uri, const gale::Dimension& _border); + /** + * @brief Set an image with direct elements + * @param[in] _image Image to set in the display + */ + void setCustumSource(const egami::Image& _image); + protected: + vec2 m_imageRenderSize; //!< size of the image when we render it + protected: + void onDraw() override; + public: + void calculateMinMaxSize() override; + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + bool loadXML(const exml::Element& _node) override; + protected: + virtual void onChangePropertySource(); + virtual void onChangePropertyImageSize(); + virtual void onChangePropertyGlobalSize(); + virtual void onChangePropertySmooth(); + virtual void onChangePropertyDistanceFieldMode(); + virtual void onChangePropertyUseThemeColor(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/Joystick.cpp b/src/org/atriasoft/ewol/widget/Joystick.cpp new file mode 100644 index 0000000..d93b2f0 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Joystick.cpp @@ -0,0 +1,190 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Joystick); + +static bool l_displayBackground(true); +static etk::String l_background(""); +static etk::String l_foreground(""); +static float l_ratio(1.0/7.0); + +ewol::widget::Joystick::Joystick() : + signalEnable(this, "enable", ""), + signalDisable(this, "disable", ""), + signalMove(this, "move", "") { + addObjectType("ewol::widget::Joystick"); + // by default the joy does not lock when free out + m_lock = false; + m_displayMode = modeNormal; + + m_colorFg = etk::color::blue; + + m_colorBg = etk::color::black; + m_colorBg.setA(0x3F); + + m_displayPos.setValue(0,0); + m_distance = 0.0; + m_angle = -0.1; + + // set the generic parameters: + m_displayBackground = l_displayBackground; + m_background = l_background; + m_foreground = l_foreground; + m_ratio = l_ratio; + propertyCanFocus.setDirectCheck(true); +} + +ewol::widget::Joystick::~Joystick() { + +} + +void ewol::widget::Joystick::onRegenerateDisplay() { + if (needRedraw() == true) { + // clean the object list ... + + /* + ewol::OObject2DColored * tmpOObjects = null; + ewol::OObject2DTextured * tmpOOtexBg = null; + ewol::OObject2DTextured * tmpOOtexFg = null; + // set background + if (true == m_displayBackground) { + if (m_background == "") { + tmpOObjects = ne w ewol::OObject2DColored; + tmpOObjects->setColor(m_colorBg); + tmpOObjects->Disc( m_size.x/2, m_size.y/2, m_size.x/2-1); + } else { + tmpOOtexBg = n ew ewol::OObject2DTextured(m_background, m_size.x, m_size.y); + tmpOOtexBg->rectangle(0, 0, m_size.x, m_size.y); + } + } + // set cursor point + float sizeElement = m_size.x*m_ratio; + if (m_foreground == "") { + if (null == tmpOObjects) { + tmpOObjects = ne w ewol::OObject2DColored; + } + tmpOObjects->setColor(m_colorFg); + tmpOObjects->Disc( ((m_displayPos.x+1.0)/2.0)*(m_size.x-2*sizeElement) + sizeElement, + ((m_displayPos.y+1.0)/2.0)*(m_size.y-2*sizeElement) + sizeElement, sizeElement); + } else { + tmpOOtexFg = ne w ewol::OObject2DTextured(m_foreground,sizeElement*2, sizeElement*2); + tmpOOtexFg->rectangle(((m_displayPos.x+1.0)/2.0)*(m_size.x-2*sizeElement), + ((m_displayPos.y+1.0)/2.0)*(m_size.y-2*sizeElement), sizeElement*2, sizeElement*2); + } + // add all needed objects ... + if (null != tmpOObjects) { + addOObject(tmpOObjects); + } + if (null != tmpOOtexBg) { + addOObject(tmpOOtexBg); + } + if (null != tmpOOtexFg) { + addOObject(tmpOOtexFg); + } + */ + } +} + +/* +Sine Function: sin(teta) = Opposite / Hypotenuse +Cosine Function: cos(teta) = Adjacent / Hypotenuse +Tangent Function: tan(teta) = Opposite / Adjacent +*/ +bool ewol::widget::Joystick::onEventInput(const ewol::event::Input& _event) { +/* + if (1 == IdInput) { + if( gale::key::status::down == typeEvent + || gale::key::status::move == typeEvent) { + // get local relative position + vec2 relativePos = relativePosition(pos); + float sizeElement = m_size.x*m_ratio; + // calculate the position of the cursor... + m_displayPos.x = (relativePos.x-sizeElement)/(m_size.x-sizeElement*2)*2.0 - 1.0; + m_displayPos.y = (relativePos.y-sizeElement)/(m_size.y-sizeElement*2)*2.0 - 1.0; + + // distance : + m_distance = m_displayPos.y*m_displayPos.y + m_displayPos.x * m_displayPos.x; + m_distance = sqrt(m_distance); + // angle : + m_angle = atan(m_displayPos.y/m_displayPos.x); + if (m_displayPos.x < 0) { + m_angle += M_PI; + } + + // clip if needed ... + if (m_distance > 1.0) { + m_distance = 1.0; + // regenerate n ew display position : + m_displayPos.x = cos(m_angle)*m_distance; + m_displayPos.y = sin(m_angle)*m_distance; + } + markToRedraw(); + if(gale::key::status::down == typeEvent) { + signalEnable.emit(); + } else { + etk::String tmp = etk::String("distance=") + etk::String(m_distance) + etk::String("angle=") + etk::String(m_angle+M_PI/2); + signalMove.emit(m_angle+M_PI/2); + } + //teta += M_PI/2; + //EWOL_DEBUG("TETA = " << (m_angle*180/M_PI) << " deg distance = " << m_distance); + return true; + } else if( gale::key::status::up == typeEvent) { + if( true == m_lock + && m_distance == 1) { + // nothing to do ... + } else { + m_displayPos.x = 0.0; + m_displayPos.y = 0.0; + m_angle = -0.1; + m_distance = 0; + } + markToRedraw(); + signalDisable.emit(); + return true; + } + return false; + } + */ + return false; +} + + +void ewol::widget::Joystick::ratio(float _newRatio) { + if (_newRatio > 1) { + _newRatio = 1; + } + m_ratio = _newRatio; + EWOL_INFO("Set default Joystick ratio at " << m_ratio); +} + + +void ewol::widget::Joystick::background(etk::String _imageNameInData, bool _display) { + // TODO : check if it existed + m_background = _imageNameInData; + m_displayBackground = _display; + EWOL_INFO("Set default Joystick background at " << m_background << " display it=" << m_displayBackground); +} + + +void ewol::widget::Joystick::foreground(etk::String imageNameInData) { + // TODO : check if it existed + m_foreground = imageNameInData; + EWOL_INFO("Set default Joystick Foreground at " << m_foreground); +} + + +void ewol::widget::Joystick::getProperty(float& distance, float& angle) { + distance = m_distance; + angle = m_angle+M_PI/2; +} + + diff --git a/src/org/atriasoft/ewol/widget/Joystick.java b/src/org/atriasoft/ewol/widget/Joystick.java new file mode 100644 index 0000000..bba67c5 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Joystick.java @@ -0,0 +1,90 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +// TODO : Rework ==> use property and shaper ... + +namespace ewol { + namespace widget { + class Joystick; + using JoystickShared = ememory::SharedPtr; + using JoystickWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Joystick :public ewol::Widget { + public: + // Event list of properties + esignal::Signal<> signalEnable; + esignal::Signal<> signalDisable; + esignal::Signal signalMove; + public: + enum joystickMode { + modeNormal, + modeArrow, + }; + private: + etk::Color<> m_colorFg; //!< Forground color + etk::Color<> m_colorBg; //!< Background color + vec2 m_displayPos; //!< direction of the cursor ... + float m_distance; //!< dintance from the center + float m_angle; //!< angle of the arraw (if < 0 : No arraw...) 0 is the TOP ... + bool m_lock; //!< flag to mark the lock when the cursor is free when we are outside the circle + enum joystickMode m_displayMode; //!< Type of fonctionnal mode of the joystick + private: + // generic property of the joystick: + bool m_displayBackground; + etk::String m_background; + etk::String m_foreground; + float m_ratio; + protected: + Joystick(); + public: + DECLARE_WIDGET_FACTORY(Joystick, "Joystick"); + virtual ~Joystick(); + public: + void setLockMode(bool _lockWhenOut) { + m_lock = _lockWhenOut; + }; + void setDisplayMode(enum joystickMode _newMode) { + m_displayMode = _newMode; + }; + /** + * @brief set the ratio of the widget joystick + * @param[in] _newRatio the new ratio that might be set + */ + void ratio(float _newRatio); + /** + * @brief set the Background of the widget joystick + * @param[in] _imageNameInData the new rbackground that might be set + * @param[in] _display + */ + void background(etk::String _imageNameInData, bool _display=true); + /** + * @brief set the Foreground of the widget joystick + * @param[in] _imageNameInData the new Foreground that might be set + */ + void foreground(etk::String _imageNameInData); + /** + * @brief get the property of the joystick + * @param[out] _distance distance to the center + * @param[out] _angle angle of the joy + */ + void getProperty(float& _distance, float& _angle); + + public: + virtual void onRegenerateDisplay() override; + virtual bool onEventInput(const ewol::event::Input& _event) override; + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/Label.cpp b/src/org/atriasoft/ewol/widget/Label.cpp new file mode 100644 index 0000000..f068bb4 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Label.cpp @@ -0,0 +1,175 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Label); + +// TODO : Remove the label name in the constructor ... +ewol::widget::Label::Label() : + signalPressed(this, "pressed", ""), + propertyAutoTranslate(this, "auto-translate", + true, + "Translate the String with the marker _{T:xxxxxx}", + &ewol::widget::Label::onChangePropertyAutoTranslate), + propertyValue(this, "value", + "", + "displayed value string", + &ewol::widget::Label::onChangePropertyValue), + propertyFontSize(this, "font-size", + 0, + "default font size (0=> system default)", + &ewol::widget::Label::onChangePropertyFontSize), + m_value(U""), + m_colorProperty(null), + m_colorDefaultFgText(-1), + m_colorDefaultBgText(-1){ + addObjectType("ewol::widget::Label"); + m_colorProperty = ewol::resource::ColorFile::create(etk::Uri("THEME_COLOR:///Label.json?lib=ewol")); + if (m_colorProperty != null) { + m_colorDefaultFgText = m_colorProperty->request("foreground"); + m_colorDefaultBgText = m_colorProperty->request("background"); + } + setMouseLimit(1); + propertyCanFocus.setDirectCheck(false); +} + +ewol::widget::Label::~Label() { + +} + +void ewol::widget::Label::init() { + ewol::Widget::init(); + // Force update the value of internal display + onChangePropertyValue(); +} + + +void ewol::widget::Label::calculateMinMaxSize() { + vec2 tmpMax = propertyMaxSize->getPixel(); + vec2 tmpMin = propertyMinSize->getPixel(); + //EWOL_DEBUG("[" << getId() << "] {" << getObjectType() << "} tmpMax : " << tmpMax); + if (tmpMax.x() <= 999999) { + m_text.setTextAlignement(0, tmpMax.x()-4, ewol::compositing::alignLeft); + //EWOL_DEBUG("[" << getId() << "] {" << getObjectType() << "} forcez Alignement "); + } + vec3 minSize = m_text.calculateSizeDecorated(m_value); + //EWOL_DEBUG("[" << getId() << "] {" << getObjectType() << "} minSize : " << minSize); + + m_minSize.setX(etk::avg(tmpMin.x(), 4 + minSize.x(), tmpMax.x())); + m_minSize.setY(etk::avg(tmpMin.y(), 4 + minSize.y(), tmpMax.y())); + EWOL_VERBOSE("[" << getId() << "] {" << getObjectType() << "} Result min size : " << tmpMin << " < " << m_minSize << " < " << tmpMax); +} + +void ewol::widget::Label::onDraw() { + m_text.draw(); +} + +void ewol::widget::Label::onRegenerateDisplay() { + if (needRedraw() == false) { + return; + } + m_text.clear(); + int32_t paddingSize = 2; + + vec2 tmpMax = propertyMaxSize->getPixel(); + // to know the size of one line : + vec3 minSize = m_text.calculateSize(char32_t('A')); + + //minSize.setX(etk::max(minSize.x(), m_minSize.x())); + //minSize.setY(etk::max(minSize.y(), m_minSize.y())); + if (tmpMax.x() <= 999999) { + m_text.setTextAlignement(0, tmpMax.x()-2*paddingSize, ewol::compositing::alignLeft); + } + vec3 curentTextSize = m_text.calculateSizeDecorated(m_value); + + ivec2 localSize = m_minSize; + + // no change for the text orogin : + vec3 tmpTextOrigin((m_size.x() - m_minSize.x()) / 2.0, + (m_size.y() - m_minSize.y()) / 2.0, + 0); + + if (propertyFill->x() == true) { + localSize.setX(m_size.x()); + tmpTextOrigin.setX(0); + } + if (propertyFill->y() == true) { + localSize.setY(m_size.y()); + tmpTextOrigin.setY(m_size.y() - 2*paddingSize - curentTextSize.y()); + } + tmpTextOrigin += vec3(paddingSize, paddingSize, 0); + localSize -= vec2(2*paddingSize,2*paddingSize); + + tmpTextOrigin.setY( tmpTextOrigin.y() + (m_minSize.y()-2*paddingSize) - minSize.y()); + + vec2 textPos(tmpTextOrigin.x(), tmpTextOrigin.y()); + + vec3 drawClippingPos(paddingSize, paddingSize, -0.5); + vec3 drawClippingSize((m_size.x() - paddingSize), + (m_size.y() - paddingSize), + 1); + + // clean the element + m_text.reset(); + if (propertyFontSize.get() != 0) { + m_text.setFontSize(propertyFontSize.get()); + } + if (m_colorProperty != null) { + m_text.setDefaultColorFg(m_colorProperty->get(m_colorDefaultFgText)); + m_text.setDefaultColorBg(m_colorProperty->get(m_colorDefaultBgText)); + } + m_text.setPos(tmpTextOrigin); + EWOL_VERBOSE("[" << getId() << "] {" << m_value << "} display at pos : " << tmpTextOrigin); + m_text.setTextAlignement(tmpTextOrigin.x(), tmpTextOrigin.x()+localSize.x(), ewol::compositing::alignLeft); + m_text.setClipping(drawClippingPos, drawClippingSize); + m_text.printDecorated(m_value); +} + +bool ewol::widget::Label::onEventInput(const ewol::event::Input& _event) { + //EWOL_DEBUG("Event on Label ..."); + if (_event.getId() == 1) { + if (gale::key::status::pressSingle == _event.getStatus()) { + // nothing to do ... + signalPressed.emit(); + return true; + } + } + return false; +} + +bool ewol::widget::Label::loadXML(const exml::Element& _node) { + if (_node.exist() == false) { + return false; + } + ewol::Widget::loadXML(_node); + // get internal data : + EWOL_DEBUG("Load label:" << _node.getText()); + propertyValue.set(_node.getText()); + return true; +} + +void ewol::widget::Label::onChangePropertyValue() { + if (*propertyAutoTranslate == true) { + m_value = etk::toUString(etranslate::get(*propertyValue)); + } else { + m_value = etk::toUString(*propertyValue); + } + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::Label::onChangePropertyFontSize() { + onChangePropertyValue(); +} + +void ewol::widget::Label::onChangePropertyAutoTranslate() { + onChangePropertyValue(); +} diff --git a/src/org/atriasoft/ewol/widget/Label.java b/src/org/atriasoft/ewol/widget/Label.java new file mode 100644 index 0000000..e1a2505 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Label.java @@ -0,0 +1,64 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Label; + using LabelShared = ememory::SharedPtr; + using LabelWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Label : public ewol::Widget { + public: // signals + esignal::Signal<> signalPressed; + public: // properties + eproperty::Value propertyAutoTranslate; //!< if at true the data is translate automaticaly translate. + eproperty::Value propertyValue; //!< decorated text to display. + eproperty::Value propertyFontSize; //!< default size of the font. + private: + ewol::compositing::Text m_text; //!< Compositing text element. + etk::UString m_value; + ememory::SharedPtr m_colorProperty; //!< theme color property + int32_t m_colorDefaultFgText; //!< Default color of the text + int32_t m_colorDefaultBgText; //!< Default Background color of the text + protected: + /** + * @brief Constructor + * @param[in] _newLabel The displayed decorated text. + */ + Label(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(Label, "Label"); + /** + * @brief destructor + */ + virtual ~Label(); + protected: + void onDraw() override; + public: + void calculateMinMaxSize() override; + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + bool loadXML(const exml::Element& _node) override; + protected: + virtual void onChangePropertyValue(); + virtual void onChangePropertyAutoTranslate(); + virtual void onChangePropertyFontSize(); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/Layer.cpp b/src/org/atriasoft/ewol/widget/Layer.cpp new file mode 100644 index 0000000..d9a1cc9 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Layer.cpp @@ -0,0 +1,43 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::Layer); + +ewol::widget::Layer::Layer() { + addObjectType("ewol::widget::Layer"); +} + +ewol::widget::Layer::~Layer() { + EWOL_DEBUG("[" << getId() << "] Layer : destroy"); +} + +ewol::WidgetShared ewol::widget::Layer::getWidgetAtPos(const vec2& _pos) { + if (*propertyHide == true) { + return null; + } + // for all element in the sizer ... + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + vec2 tmpSize = it->getSize(); + vec2 tmpOrigin = it->getOrigin(); + if( (tmpOrigin.x() <= _pos.x() && tmpOrigin.x() + tmpSize.x() >= _pos.x()) + && (tmpOrigin.y() <= _pos.y() && tmpOrigin.y() + tmpSize.y() >= _pos.y()) ) { + ewol::WidgetShared tmpWidget = it->getWidgetAtPos(_pos); + if (tmpWidget != null) { + return tmpWidget; + } + // parse the next layer ... + } + } + return null; +}; + diff --git a/src/org/atriasoft/ewol/widget/Layer.java b/src/org/atriasoft/ewol/widget/Layer.java new file mode 100644 index 0000000..c5faf91 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Layer.java @@ -0,0 +1,38 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Layer; + using LayerShared = ememory::SharedPtr; + using LayerWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Layer : public ewol::widget::ContainerN { + protected: + /** + * @brief Constructor + */ + Layer(); + public: + DECLARE_WIDGET_FACTORY(Layer, "Layer"); + /** + * @brief Desstructor + */ + virtual ~Layer(); + public: + ewol::WidgetShared getWidgetAtPos(const vec2& _pos) override; + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/List.cpp b/src/org/atriasoft/ewol/widget/List.cpp new file mode 100644 index 0000000..c4dff93 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/List.cpp @@ -0,0 +1,332 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::List); + +ewol::widget::List::List() { + addObjectType("ewol::widget::List"); + m_paddingSizeX = 2; + #ifdef __TARGET_OS__Android + m_paddingSizeY = 10; + #else + m_paddingSizeY = 2; + #endif + m_nbVisibleRaw = 0; + propertyCanFocus.setDirectCheck(true); + m_limitScrolling = vec2(1, 0.5); +} + + +void ewol::widget::List::init() { + ewol::widget::WidgetScrolled::init(); + addComposeElemnent("drawing", ememory::makeShared()); + addComposeElemnent("text", ememory::makeShared()); +} + + +ewol::widget::List::~List() { +} + +void ewol::widget::List::addComposeElemnent(const etk::String& _name, const ememory::SharedPtr& _element) { + m_compositingElements.set(_name, _element); + m_listOObject.pushBack(_element); +} + +void ewol::widget::List::clearComposeElemnent() { + for (auto &it: m_compositingElements) { + it.second->clear(); + } +} + +void ewol::widget::List::removeComposeElemnent() { + m_compositingElements.clear(); +} + +ememory::SharedPtr ewol::widget::List::getComposeElemnent(const etk::String& _name) { + return m_compositingElements[_name]; +} +/* +void ewol::widget::List::setRawVisible(int32_t _id) { + EWOL_DEBUG("Set Raw visible : " << _id); + if (_id<0) { + return; + } + if (_id == m_displayStartRaw) { + // nothing to do ... + return; + } + if (_id < m_displayStartRaw) { + m_displayStartRaw = _id-2; + } else { + if (m_displayStartRaw + m_nbVisibleRaw < _id) { + m_displayStartRaw = _id - m_nbVisibleRaw + 2; + } + } + ivec2 matrixSize = getMatrixSize(); + if (m_displayStartRaw > matrixSize.y()) { + m_displayStartRaw = matrixSize.y()-2; + } + if (m_displayStartRaw<0) { + m_displayStartRaw = 0; + } + EWOL_DEBUG("Set start raw : " << m_displayStartRaw); + markToRedraw(); +} +*/ + +void ewol::widget::List::calculateMinMaxSize() { + /*int32_t fontId = getDefaultFontId(); + int32_t minWidth = ewol::getWidth(fontId, m_label); + int32_t minHeight = ewol::getHeight(fontId); + m_minSize.x = 3+minWidth; + m_minSize.y = 3+minHeight; + */ + m_minSize.setValue(200, 150); +} + +void ewol::widget::List::onDraw() { + for (size_t iii=0; iiidraw(); + } + } + WidgetScrolled::onDraw(); +} + +void ewol::widget::List::onRegenerateDisplay() { + if (needRedraw() == true) { + // clean the object list ... + clearComposeElemnent(); + // ------------------------------------------------------- + // -- Calculate the size of each element + // ------------------------------------------------------- + ivec2 matrixSize = getMatrixSize(); + m_listSizeX.clear(); + m_listSizeX.resize(matrixSize.x(), 0); + m_listSizeY.clear(); + m_listSizeY.resize(matrixSize.y(), 0); + for (int_t yyy=0; yyy m_listSizeX[xxx]) { + m_listSizeX[xxx] = elementSize.x(); + } + if (elementSize.y() > m_listSizeY[yyy]) { + m_listSizeY[yyy] = elementSize.y(); + } + } + } + // ------------------------------------------------------- + // -- Fill property applyence + // ------------------------------------------------------- + if (propertyFill->x() == true) { + int32_t fullSize = 0; + for (auto &size: m_listSizeX) { + fullSize += size; + } + if (fullSize < m_size.x() ) { + // need to expand all elements: + int32_t residualAdd = (m_size.x() - fullSize) / matrixSize.x(); + if (residualAdd != 0) { + for (auto &size: m_listSizeX) { + size += residualAdd; + } + } + } + } + /* + if (propertyFill->y() == true) { + int32_t fullSize = 0; + for (auto &size: m_listSizeY) { + fullSize += size; + } + if (fullSize < m_size.y() ) { + // need to expand all elements: + int32_t residualAdd = (m_size.y() - fullSize) / matrixSize.y(); + if (residualAdd != 0) { + for (auto &size: m_listSizeY) { + size += residualAdd; + } + } + } + } + */ + // ------------------------------------------------------- + // -- Calculate the start position size of each element + // ------------------------------------------------------- + etk::Vector listStartPosX; + etk::Vector listStartPosY; + int32_t lastPositionX = 0; + for (auto &size: m_listSizeX) { + listStartPosX.pushBack(lastPositionX); + lastPositionX += size; + } + int32_t lastPositionY = 0; + for (auto &size: m_listSizeY) { + lastPositionY += size; + listStartPosY.pushBack(lastPositionY); + } + // ------------------------------------------------------- + // -- Update the scroolBar + // ------------------------------------------------------- + m_maxSize = ivec2(lastPositionX, lastPositionY); + // ------------------------------------------------------- + // -- Clean the background + // ------------------------------------------------------- + drawBackground(); + // ------------------------------------------------------- + // -- Draw each element + // ------------------------------------------------------- + for (int_t yyy=0; yyy element out of range ==> nothing to display + break; + } + if (startYposition > m_size.y()) { + // ==> element out of range ==> nothing to display + continue; + } + for (int_t xxx=0; xxx element out of range ==> nothing to display + continue; + } + if (startXposition > m_size.x()) { + // ==> element out of range ==> nothing to display + break; + } + drawElement(ivec2(xxx, yyy), + vec2(startXposition, startYposition), + vec2(m_listSizeX[xxx], m_listSizeY[yyy])); + } + } + // ------------------------------------------------------- + // -- Draw Scrooling widget + // ------------------------------------------------------- + WidgetScrolled::onRegenerateDisplay(); + } +} + +ivec2 ewol::widget::List::getMatrixSize() const { + return ivec2(1,0); +} + +vec2 ewol::widget::List::calculateElementSize(const ivec2& _pos) { + auto tmpText = ememory::staticPointerCast(getComposeElemnent("text")); + etk::String myTextToWrite = getData(ListRole::Text, _pos).getSafeString(); + vec3 textSize = tmpText->calculateSize(myTextToWrite); + ivec2 count = getMatrixSize(); + return vec2(textSize.x(), + textSize.y() + m_paddingSizeY*3 + ); +} + +void ewol::widget::List::drawBackground() { + auto BGOObjects = ememory::staticPointerCast(getComposeElemnent("drawing")); + if (BGOObjects != null) { + etk::Color<> basicBG = getBasicBG(); + BGOObjects->setColor(basicBG); + BGOObjects->setPos(vec3(0, 0, 0) ); + BGOObjects->rectangleWidth(m_size); + } +} + +void ewol::widget::List::drawElement(const ivec2& _pos, const vec2& _start, const vec2& _size) { + etk::String myTextToWrite = getData(ListRole::Text, _pos).getSafeString(); + etk::Color<> fg = getData(ListRole::FgColor, _pos).getSafeColor(); + auto backgroundVariant = getData(ListRole::BgColor, _pos); + if (backgroundVariant.isColor() == true) { + etk::Color<> bg = backgroundVariant.getColor(); + auto BGOObjects = ememory::staticPointerCast(getComposeElemnent("drawing")); + if (BGOObjects != null) { + BGOObjects->setColor(bg); + BGOObjects->setPos(vec3(_start.x(), _start.y(), 0) ); + BGOObjects->rectangleWidth(_size); + } + } + if (myTextToWrite != "") { + auto tmpText = ememory::staticPointerCast(getComposeElemnent("text")); + if (tmpText != null) { + int32_t displayPositionY = _start.y() + m_paddingSizeY; + tmpText->setColor(fg); + tmpText->setPos(vec3(_start.x() + m_paddingSizeX, displayPositionY, 0) ); + tmpText->print(myTextToWrite);; + } + } +} + +bool ewol::widget::List::onEventInput(const ewol::event::Input& _event) { + vec2 relativePos = relativePosition(_event.getPos()); + if (WidgetScrolled::onEventInput(_event) == true) { + keepFocus(); + // nothing to do ... done on upper widet ... + return true; + } + if (m_listSizeY.size() == 0) { + return false; + } + relativePos = vec2(relativePos.x(),m_size.y() - relativePos.y()) + m_originScrooled; + // Find the colomn and the row + ivec2 pos{0,0}; + float_t offsetY = 0; + for (size_t iii=0; iii= previous ) { + pos.setY(iii); + offsetY = previous; + break; + } + if ( iii == m_listSizeY.size()-2 + && relativePos.y() >= offsetY ) { + pos.setY(iii+1); + break; + } + } + float_t offsetX = 0; + for (size_t iii=0; iii= previous ) { + pos.setX(iii); + offsetX = previous; + break; + } + if ( iii == m_listSizeX.size()-2 + && relativePos.x() >= offsetX ) { + pos.setX(iii+1); + break; + } + } + vec2 posInternalMouse = relativePos - vec2(offsetX, offsetY); + bool isUsed = onItemEvent(_event, pos, posInternalMouse); + if (isUsed == true) { + // TODO : this generate bugs ... I did not understand why .. + //ewol::WidgetSharedManager::focusKeep(this); + } + return isUsed; +} + +void ewol::widget::List::onGetFocus() { + EWOL_DEBUG("Ewol::List get focus"); +} + +void ewol::widget::List::onLostFocus() { + EWOL_DEBUG("Ewol::List Lost focus"); +} diff --git a/src/org/atriasoft/ewol/widget/List.java b/src/org/atriasoft/ewol/widget/List.java new file mode 100644 index 0000000..ec398c8 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/List.java @@ -0,0 +1,130 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class List; + using ListShared = ememory::SharedPtr; + using ListWeak = ememory::WeakPtr; + + enum ListRole { + Text = 11234, // string + IsSelected, // bool + IsExpand, // bool + Icon, // string + ChildCount, // uint_t + HaveChild, // bool + ParentId, // uint_t + BgColor, // color + FgColor, // color + DistanceToRoot, // uint_t + // Every other role must be set here: + EndOfEwolRole + }; + + /** + * @ingroup ewolWidgetGroup + */ + class List : public ewol::widget::WidgetScrolled { + protected: + List(); + void init() override; + public: + virtual ~List(); + void calculateMinMaxSize() override; + // drawing capabilities .... + protected: + etk::Vector> m_listOObject; //!< generic element to display... + etk::Vector m_listSizeX; //!< size of every colomns + etk::Vector m_listSizeY; //!< size of every rows + protected: + etk::Map> m_compositingElements; + void addComposeElemnent(const etk::String& _name, const ememory::SharedPtr& _element); + void clearComposeElemnent(); + void removeComposeElemnent(); + ememory::SharedPtr getComposeElemnent(const etk::String& _name); + public: + void clearOObjectList(); + // list properties ... + protected: + int32_t m_paddingSizeX; + int32_t m_paddingSizeY; + int32_t m_displayStartRaw; //!< Current starting diaplayed raw + int32_t m_displayCurrentNbLine; //!< Number of line in the display + int32_t m_nbVisibleRaw; // set the number of visible raw (calculate don display) + protected: + // function call to display the list : + virtual etk::Color<> getBasicBG() { + return etk::Color<>(0xFF, 0xFF, 0xFF, 0xFF); + } + + /** + * @brief Get the number of colomn and row availlable in the list + * @return Number of colomn and row + */ + virtual ivec2 getMatrixSize() const; + + virtual fluorine::Variant getData(int32_t _role, const ivec2& _pos) { + switch (_role) { + case ListRole::Text: + return ""; + case ListRole::FgColor: + return etk::Color<>(0x00, 0x00, 0x00, 0xFF); + case ListRole::BgColor: + if (_pos.y() % 2 == 0) { + return etk::Color<>(0xFF, 0xFF, 0xFF, 0xFF); + } + return etk::Color<>(0x7F, 0x7F, 0x7F, 0xFF); + } + return fluorine::Variant(); + }; + /** + * @brief Calculate an element size to extimate the render size. + * @note Does not generate the with the same size. + * @param[in] _pos Position of colomn and Raw of the element. + * @return The estimate size of the element. + */ + virtual vec2 calculateElementSize(const ivec2& _pos); + /** + * @brief Draw an element in the specific size and position. + * @param[in] _pos Position of colomn and Raw of the element. + * @param[in] _start Start display position. + * @param[in] _size Render raw size + * @return The estimate size of the element. + */ + virtual void drawElement(const ivec2& _pos, const vec2& _start, const vec2& _size); + /** + * @brief Draw the background + */ + virtual void drawBackground(); + + virtual bool onItemEvent(const ewol::event::Input& _event, const ivec2& _pos, const vec2& _mousePosition) { + return false; + } + /** + * @brief set a raw visible in the main display + * @param[in] _id Id of the raw that might be visible. + */ + //void setRawVisible(int32_t _id); + protected: + void onGetFocus() override; + void onLostFocus() override; + void onDraw() override; + public: + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/ListFileSystem.cpp b/src/org/atriasoft/ewol/widget/ListFileSystem.cpp new file mode 100644 index 0000000..d8df3b2 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ListFileSystem.cpp @@ -0,0 +1,256 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::ListFileSystem); + +ewol::widget::ListFileSystem::ListFileSystem() : + signalFileSelect(this, "file-select", ""), + signalFileValidate(this, "file-validate", ""), + signalFolderSelect(this, "folder-select", ""), + signalFolderValidate(this, "folder-validate", ""), + propertyPath(this, "path", + etk::Path("/"), + "Path to display", + &ewol::widget::ListFileSystem::onChangePropertyPath), + propertyFile(this, "select", + etk::Path(), + "selection af a specific file", + &ewol::widget::ListFileSystem::onChangePropertyFile), + propertyShowFile(this, "show-file", + true, + "display files", + &ewol::widget::ListFileSystem::onChangePropertyShowFile), + propertyShowFolder(this, "show-folder", + true, + "display folders", + &ewol::widget::ListFileSystem::onChangePropertyShowFolder), + propertyShowHidden(this, "show-hidden", + true, + "Show the hidden element (file, folder, ...)", + &ewol::widget::ListFileSystem::onChangePropertyShowHidden), + propertyFilter(this, "filter", + "", + "regex to filter files ...", + &ewol::widget::ListFileSystem::onChangePropertyFilter), + m_selectedLine(-1) { + addObjectType("ewol::widget::ListFileSystem"); + #if defined(__TARGET_OS__Windows) + propertyPath.setDirectCheck("c:/"); + #endif + m_colorProperty = ewol::resource::ColorFile::create("THEME_COLOR:///ListFileSystem.json?lib=ewol"); + if (m_colorProperty != null) { + m_colorIdText = m_colorProperty->request("text"); + m_colorIdBackground1 = m_colorProperty->request("background1"); + m_colorIdBackground2 = m_colorProperty->request("background2"); + m_colorIdBackgroundSelected = m_colorProperty->request("selected"); + } + setMouseLimit(2); +} + +ewol::widget::ListFileSystem::~ListFileSystem() { + clearList(); +} + +void ewol::widget::ListFileSystem::clearList() { + m_list.clear(); +} + +etk::Color<> ewol::widget::ListFileSystem::getBasicBG() { + return m_colorProperty->get(m_colorIdBackground1); +} + +static bool localSort(const etk::Path& _left, const etk::Path& _right) { + return _left.getString().toUpper() <= _right.getString().toUpper(); +} + +void ewol::widget::ListFileSystem::regenerateView() { + clearList(); + m_selectedLine = -1; + m_list.clear(); + m_originScrooled.setValue(0,0); + uint32_t flags = 0; + if (*propertyShowHidden == true) { + flags |= etk::path::LIST_HIDDEN; + } + if (*propertyShowFolder == true) { + flags |= etk::path::LIST_FOLDER; + } + if (*propertyShowFile == true) { + flags |= etk::path::LIST_FILE; + } + m_list = etk::path::list(*propertyPath, flags); + EWOL_ERROR("Lsit of element: " << m_list.size() ); + // Sort the list: + etk::algorithm::quickSort(m_list, localSort); + // request a redraw ... + markToRedraw(); +} + +etk::Path ewol::widget::ListFileSystem::getSelect() const { + etk::String tmpVal = ""; + if (m_selectedLine >= 0) { + tmpVal = m_list[m_selectedLine].getFileName(); + } + return tmpVal; +} + +// select the specific file +void ewol::widget::ListFileSystem::setSelect(const etk::Path& _data) { + // remove selected line + m_selectedLine = -1; + // search the coresponding file : + for (size_t iii=0; iii= 0 + && _pos.y()-offset < (int32_t)m_list.size()) { + EWOL_VERBOSE("get filename for : '" << m_list[_pos.y()-offset] << ":'" << m_list[_pos.y()-offset].getFileName() << "'"); + return m_list[_pos.y()-offset].getFileName(); + } + } + return "<<>>"; + case ListRole::FgColor: + return m_colorProperty->get(m_colorIdText); + case ListRole::BgColor: + if (m_selectedLine == _pos.y()) { + return m_colorProperty->get(m_colorIdBackgroundSelected); + } + if (_pos.y() % 2) { + return m_colorProperty->get(m_colorIdBackground1); + } + return m_colorProperty->get(m_colorIdBackground2); + } + return fluorine::Variant(); +} + +bool ewol::widget::ListFileSystem::onItemEvent(const ewol::event::Input& _event, + const ivec2& _pos, + const vec2& _mousePosition) { + int32_t offset = 0; + if (*propertyShowFolder == true) { + if (*propertyPath == "/") { + offset = 1; + } else { + offset = 2; + } + } + if ( _event.getStatus() == gale::key::status::pressSingle + || _event.getStatus() == gale::key::status::pressDouble) { + EWOL_VERBOSE("Event on List : IdInput=" << _event.getId() << " _pos=" << _pos ); + if (1 == _event.getId()) { + if (_pos.y() > (int32_t)m_list.size()+offset ) { + m_selectedLine = -1; + } else { + m_selectedLine = _pos.y(); + } + if( *propertyShowFolder == true + && m_selectedLine == 0) { + // "." folder + if (_event.getStatus() == gale::key::status::pressSingle) { + signalFolderSelect.emit(*propertyPath); + } else { + signalFolderValidate.emit(*propertyPath); + } + } else if ( *propertyShowFolder == true + && m_selectedLine == 1) { + // ".." folder + if (_event.getStatus() == gale::key::status::pressSingle) { + signalFolderSelect.emit(propertyPath->getParent()); + } else { + signalFolderValidate.emit(propertyPath->getParent()); + } + } else if( m_selectedLine-offset >= 0 + && m_selectedLine-offset < (int32_t)m_list.size() ) { + // generate event extern: + if(etk::path::isDirectory(m_list[m_selectedLine-offset])) { + if (_event.getStatus() == gale::key::status::pressSingle) { + signalFolderSelect.emit(m_list[m_selectedLine-offset]); + } else { + signalFolderValidate.emit(m_list[m_selectedLine-offset]); + } + } else { + if (_event.getStatus() == gale::key::status::pressSingle) { + signalFileSelect.emit(m_list[m_selectedLine-offset]); + } else { + signalFileValidate.emit(m_list[m_selectedLine-offset]); + } + } + } + // need to regenerate the display of the list : + markToRedraw(); + return true; + } + } + return false; +} + +void ewol::widget::ListFileSystem::onChangePropertyPath() { + EWOL_WARNING("Change Path: " << *propertyPath << " selected File=" << *propertyFile);; + regenerateView(); +} + +void ewol::widget::ListFileSystem::onChangePropertyFile() { + setSelect(propertyFile); +} + +void ewol::widget::ListFileSystem::onChangePropertyShowFile() { + regenerateView(); +} + +void ewol::widget::ListFileSystem::onChangePropertyShowFolder() { + regenerateView(); +} + +void ewol::widget::ListFileSystem::onChangePropertyShowHidden() { + regenerateView(); +} + +void ewol::widget::ListFileSystem::onChangePropertyFilter() { + regenerateView(); +} + diff --git a/src/org/atriasoft/ewol/widget/ListFileSystem.java b/src/org/atriasoft/ewol/widget/ListFileSystem.java new file mode 100644 index 0000000..430e279 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ListFileSystem.java @@ -0,0 +1,83 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include + +namespace ewol { + namespace widget { + class ListFileSystem; + using ListFileSystemShared = ememory::SharedPtr; + using ListFileSystemWeak = ememory::WeakPtr; + /** + * @brief Generic display folder class. This widget display the content of a single folder : + */ + class ListFileSystem : public ewol::widget::List { + public: // signals + esignal::Signal signalFileSelect; //!< @event "file-select" Generated when a file is selected. + esignal::Signal signalFileValidate; //!< @event "file-validate" Generate when the user validate (return) or double click on the element + esignal::Signal signalFolderSelect; + esignal::Signal signalFolderValidate; + public: // properties + eproperty::Value propertyPath; //!< Current folder that display point on. + eproperty::Value propertyFile; //!< current selected file + eproperty::Value propertyShowFile; //!< Show files elements + eproperty::Value propertyShowFolder; //!< Display the folders elements + eproperty::Value propertyShowHidden; //!< Display hidden elements + eproperty::Value propertyFilter; //!< Regular expression to filter the view (for temporary file:".*(~|.bck|.pyc)\e") + protected: + ListFileSystem(); + public: + DECLARE_WIDGET_FACTORY(ListFileSystem, "ListFileSystem"); + virtual ~ListFileSystem(); + protected: + ememory::SharedPtr m_colorProperty; //!< theme color property. + int32_t m_colorIdText; //!< Color of the text. + int32_t m_colorIdBackground1; //!< Color of the Background. + int32_t m_colorIdBackground2; //!< Color of the Background 2. + int32_t m_colorIdBackgroundSelected; //!< Color of line selected. + protected: + etk::Color<> getBasicBG() override; + ivec2 getMatrixSize() const override; + fluorine::Variant getData(int32_t _role, const ivec2& _pos) override; + bool onItemEvent(const ewol::event::Input& _event, const ivec2& _pos, const vec2& _mousePosition) override; + protected: + etk::Vector m_list; //!< List of all element in the path. (they are filtered) + /** + * @brief Clean the list of element. + */ + void clearList(); + /** + * @brief Regenerate the content of the view. this is actually not automation on the system update. + */ + virtual void regenerateView(); + protected: + int32_t m_selectedLine; //!< Current Line ID that is selected + public: + /** + * @brief Select a specific file in the path + * @param[in] _data File to selested. + */ + virtual void setSelect(const etk::Path& _data); + /** + * @brief Get the current selected file/folder/... in the list + * @return the String of the element selected. + */ + etk::Path getSelect() const ; + protected: + virtual void onChangePropertyPath(); + virtual void onChangePropertyFile(); + virtual void onChangePropertyShowFile(); + virtual void onChangePropertyShowFolder(); + virtual void onChangePropertyShowHidden(); + virtual void onChangePropertyFilter(); + }; + }; +}; + + diff --git a/src/org/atriasoft/ewol/widget/Manager.cpp b/src/org/atriasoft/ewol/widget/Manager.cpp new file mode 100644 index 0000000..9bb0271 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Manager.cpp @@ -0,0 +1,249 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::Manager); + +ewol::widget::Manager::Manager() : + m_creatorList(0, false), + m_creatorListXml(0, false), + m_haveRedraw(true) { + EWOL_DEBUG(" == > init Widget-Manager"); + + ewol::widget::Button::createManagerWidget(*this); + ewol::widget::ButtonColor::createManagerWidget(*this); + ewol::widget::Spacer::createManagerWidget(*this); + ewol::widget::Slider::createManagerWidget(*this); + ewol::widget::Sizer::createManagerWidget(*this); + ewol::widget::ProgressBar::createManagerWidget(*this); + ewol::widget::Layer::createManagerWidget(*this); + ewol::widget::Label::createManagerWidget(*this); + ewol::widget::Image::createManagerWidget(*this); + ewol::widget::Gird::createManagerWidget(*this); + ewol::widget::Entry::createManagerWidget(*this); + ewol::widget::Menu::createManagerWidget(*this); + ewol::widget::CheckBox::createManagerWidget(*this); + ewol::widget::Scroll::createManagerWidget(*this); + ewol::widget::ContextMenu::createManagerWidget(*this); + ewol::widget::PopUp::createManagerWidget(*this); + ewol::widget::WSlider::createManagerWidget(*this); + ewol::widget::ListFileSystem::createManagerWidget(*this); + ewol::widget::Composer::createManagerWidget(*this); + ewol::widget::Select::createManagerWidget(*this); + ewol::widget::Spin::createManagerWidget(*this); +} + +ewol::widget::Manager::~Manager() { + EWOL_DEBUG(" == > Un-Init Widget-Manager"); + EWOL_INFO("Realease all FOCUS"); + focusSetDefault(null); + focusRelease(); + + m_creatorList.clear(); +} + +/* ************************************************************************* + * focus Area : + * *************************************************************************/ + +void ewol::widget::Manager::focusKeep(ewol::WidgetShared _newWidget) { + if (_newWidget == null) { + // nothing to do ... + return; + } + EWOL_DEBUG("focusKeep=" << _newWidget->getId() ); + //elog::displayBacktrace(); + auto focusWidgetCurrent = m_focusWidgetCurrent.lock(); + if (_newWidget == focusWidgetCurrent) { + // nothing to do ... + return; + } + if (focusWidgetCurrent != null) { + EWOL_DEBUG("Rm focus on WidgetID=" << focusWidgetCurrent->getId() ); + focusWidgetCurrent->rmFocus(); + focusWidgetCurrent.reset(); + } + if (_newWidget->propertyCanFocus.get() == false) { + EWOL_DEBUG("Widget can not have focus, id=" << _newWidget->getId() ); + return; + } + m_focusWidgetCurrent = _newWidget; + if (_newWidget != null) { + EWOL_DEBUG("Set focus on WidgetID=" << _newWidget->getId() ); + _newWidget->setFocus(); + } +} + +void ewol::widget::Manager::focusSetDefault(ewol::WidgetShared _newWidget) { + if( _newWidget != null + && _newWidget->propertyCanFocus.get() == false) { + EWOL_VERBOSE("Widget can not have focus, id=" << _newWidget->getId() ); + return; + } + ewol::WidgetShared focusWidgetDefault = m_focusWidgetDefault.lock(); + ewol::WidgetShared focusWidgetCurrent = m_focusWidgetCurrent.lock(); + if (focusWidgetDefault == focusWidgetCurrent) { + if (focusWidgetCurrent != null) { + EWOL_DEBUG("Rm focus on WidgetID=" << focusWidgetCurrent->getId() ); + focusWidgetCurrent->rmFocus(); + } + m_focusWidgetCurrent = _newWidget; + if (_newWidget != null) { + EWOL_DEBUG("Set focus on WidgetID=" << _newWidget->getId() ); + _newWidget->setFocus(); + } + } + m_focusWidgetDefault = _newWidget; +} + +void ewol::widget::Manager::focusRelease() { + ewol::WidgetShared focusWidgetDefault = m_focusWidgetDefault.lock(); + ewol::WidgetShared focusWidgetCurrent = m_focusWidgetCurrent.lock(); + if (focusWidgetDefault == focusWidgetCurrent) { + // nothink to do ... + return; + } + if (focusWidgetCurrent != null) { + EWOL_DEBUG("Rm focus on WidgetID=" << focusWidgetCurrent->getId() ); + focusWidgetCurrent->rmFocus(); + } + m_focusWidgetCurrent = m_focusWidgetDefault; + focusWidgetCurrent = m_focusWidgetCurrent.lock(); + if (focusWidgetCurrent != null) { + EWOL_DEBUG("Set focus on WidgetID=" << focusWidgetCurrent->getId() ); + focusWidgetCurrent->setFocus(); + } +} + +ewol::WidgetShared ewol::widget::Manager::focusGet() { + return m_focusWidgetCurrent.lock(); +} + +void ewol::widget::Manager::setCallbackonRedrawNeeded(const etk::Function& _func) { + m_funcRedrawNeeded = _func; +} + +void ewol::widget::Manager::markDrawingIsNeeded() { + if (m_haveRedraw == true) { + return; + } + m_haveRedraw = true; + if (m_funcRedrawNeeded != null) { + m_funcRedrawNeeded(); + } +} + +bool ewol::widget::Manager::isDrawingNeeded() { + bool tmp = m_haveRedraw; + m_haveRedraw = false; + return tmp; +} + +// element that generate the list of elements +void ewol::widget::Manager::addWidgetCreator(const etk::String& _name, + ewol::widget::Manager::widgetCreatorFunction _pointer, + ewol::widget::Manager::widgetCreatorFunctionXml _pointerXml) { + if ( _pointer == null + || _pointerXml == null) { + return; + } + //Keep name in lower case : + etk::String nameLower = etk::toLower(_name); + bool find = false; + { + auto it = m_creatorList.find(nameLower); + if (it != m_creatorList.end()) { + EWOL_WARNING("Replace Creator of a specify widget : " << nameLower); + it->second = _pointer; + find = true; + } + } + { + auto it = m_creatorListXml.find(nameLower); + if (it != m_creatorListXml.end()) { + EWOL_WARNING("Replace CreatorXml of a specify widget : " << nameLower); + it->second = _pointerXml; + find = true; + } + } + if (find == true) { + return; + } + EWOL_INFO("Add Creator of a specify widget : " << nameLower); + m_creatorList.set(nameLower, _pointer); + m_creatorListXml.set(nameLower, _pointerXml); +} + +ewol::WidgetShared ewol::widget::Manager::create(const etk::String& _name) { + etk::String nameLower = etk::toLower(_name); + auto it = m_creatorList.find(nameLower); + if (it != m_creatorList.end()) { + if (it->second != null) { + return it->second(); + } + } + EWOL_WARNING("try to create an UnExistant widget : " << nameLower); + return null; +} + +ewol::WidgetShared ewol::widget::Manager::create(const etk::String& _name, const exml::Element& _node) { + etk::String nameLower = etk::toLower(_name); + auto it = m_creatorListXml.find(nameLower); + if (it != m_creatorListXml.end()) { + if (it->second != null) { + return it->second(_node); + } + } + EWOL_WARNING("try to create an UnExistant widget : " << nameLower); + return null; +} + +bool ewol::widget::Manager::exist(const etk::String& _name) { + etk::String nameLower = etk::toLower(_name); + auto it = m_creatorList.find(nameLower); + if (it == m_creatorList.end()) { + return false; + } + return true; +} + +etk::String ewol::widget::Manager::list() { + etk::String tmpVal; + for (auto &it : m_creatorList) { + if (tmpVal.size() != 0) { + tmpVal += ","; + } + tmpVal += it.first; + } + return tmpVal; +} + diff --git a/src/org/atriasoft/ewol/widget/Manager.java b/src/org/atriasoft/ewol/widget/Manager.java new file mode 100644 index 0000000..a726e47 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Manager.java @@ -0,0 +1,115 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Manager { + public: + Manager(); + virtual ~Manager(); + // --------------------------------------------- + // -- Focus area + // --------------------------------------------- + private: + ewol::WidgetWeak m_focusWidgetDefault; //!< default focus when no current focus is set + ewol::WidgetWeak m_focusWidgetCurrent; //!< Currect focus selected + public: + /** + * @brief Request a focus on a specify widget. + * @param[in] _newWidget Widget that might get the focus. + */ + void focusKeep(ewol::WidgetShared _newWidget); + /** + * @brief Set the default focus when none selected. + * @param[in] _newWidget Widget that might get the focus (when nothing else). + */ + void focusSetDefault(ewol::WidgetShared _newWidget); + /** + * @brief Release the current focus (back on default if possible). + */ + void focusRelease(); + /** + * @brief Get the current Focused widget. + * @return The pointer on the current focused element. + */ + ewol::WidgetShared focusGet(); + // --------------------------------------------- + // -- Factory area + // --------------------------------------------- + public: + using widgetCreatorFunction = etk::Function; //!< funtion factory basic definition + using widgetCreatorFunctionXml = etk::Function; //!< funtion factory basic definition + private: + etk::Map m_creatorList; //!< List of factory of a widget + etk::Map m_creatorListXml; //!< List of factory of a widget + public: + /** + * @brief add a factory of a specific widget. + * @param[in] _name Name of the widget that is associated of the factory. + * @param[in] _factory Function pointer to create the widget + * @param[in] _factoryXml Function pointer to create the widget with XML node for parsing of XML + */ + void addWidgetCreator(const etk::String& _name, widgetCreatorFunction _factory, widgetCreatorFunctionXml _factoryXml); + /** + * @brief Create a widget with his name. + * @param[in] _name Name of the widget to create. + * @return The widget created (null if it does not exist). + */ + ewol::WidgetShared create(const etk::String& _name); + /** + * @brief Create a widget with his name. + * @param[in] _name Name of the widget to create. + * @param[in] _node Reference on the XML node. + * @return The widget created (null if it does not exist). + */ + ewol::WidgetShared create(const etk::String& _name, const exml::Element& _node); + /** + * @brief Check if an Widget exist + * @param[in] _name Name of the widget to check. + * @return true The Widget exist. + * @return false The Widget Does NOT exist. + */ + bool exist(const etk::String& _name); + /** + * @brief Get the list of all Widget that can be created. + * @return Separate with ',' string list. + */ + etk::String list(); + // --------------------------------------------- + // -- Something change area (TODO: maybe set it in the windows) + // --------------------------------------------- + private: + bool m_haveRedraw; //!< something request a redraw + private: + etk::Function m_funcRedrawNeeded; + public: + /** + * @brief Mark the display to redraw + */ + void markDrawingIsNeeded(); + /** + * @brief Check if a redraw has been requested (set the local value back at false) + * @return true if something to be redraw + */ + bool isDrawingNeeded(); + private: + + /** + * @brief Set a callback when we need redraw the display (need by MacOs) + * @param[in] _func function to call + */ + void setCallbackonRedrawNeeded(const etk::Function& _func); + + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/Menu.cpp b/src/org/atriasoft/ewol/widget/Menu.cpp new file mode 100644 index 0000000..e878f7b --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Menu.cpp @@ -0,0 +1,330 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Menu); + +ewol::widget::Menu::Menu() : + signalSelect(this, "select", "") { + addObjectType("ewol::widget::Menu"); + m_staticId = 666; + propertyLockExpand.setDirect(bvec2(true,true)); +} + +ewol::widget::Menu::~Menu() { + clear(); +} + +void ewol::widget::Menu::subWidgetRemoveAll() { + clear(); + ewol::widget::Sizer::subWidgetRemoveAll(); +} + +int32_t ewol::widget::Menu::subWidgetAdd(ewol::WidgetShared _newWidget) { + EWOL_ERROR("Not availlable"); + return -1; +} + +void ewol::widget::Menu::subWidgetRemove(ewol::WidgetShared _newWidget) { + EWOL_ERROR("Not availlable"); +} + +void ewol::widget::Menu::subWidgetUnLink(ewol::WidgetShared _newWidget) { + EWOL_ERROR("Not availlable"); +} + +void ewol::widget::Menu::clear() { + m_listElement.clear(); +} + +int32_t ewol::widget::Menu::addTitle(const etk::String& _label, + const etk::String& _image, + const etk::String& _message) { + return add(-1, _label, _image, _message); +} + +static const char* eventButtonPressed = "menu-local-pressed"; + +int32_t ewol::widget::Menu::get(const etk::String& _label) { + for (auto &it : m_listElement) { + if (it.m_label == _label) { + return it.m_localId; + } + } + return -1; +} + +int32_t ewol::widget::Menu::add(int32_t _parent, + const etk::String& _label, + const etk::String& _image, + const etk::String& _message) { + // try to find one already created: + int32_t previous = get(_label); + if (previous != -1) { + return previous; + } + ewol::widget::MenuElement tmpObject; + tmpObject.m_localId = m_staticId++; + tmpObject.m_parentId = _parent; + tmpObject.m_label = _label; + tmpObject.m_image = _image; + tmpObject.m_message = _message; + if (tmpObject.m_parentId == -1) { + ewol::widget::ButtonShared myButton = ewol::widget::Button::create(); + if (myButton == null) { + EWOL_ERROR("Allocation button error"); + return tmpObject.m_localId; + } + if (tmpObject.m_image.size()!=0) { + etk::String composeString ="\n"; + if (etk::end_with(tmpObject.m_image, ".edf") == true) { + composeString+=" \n"; + } else { + composeString+=" \n"; + } + composeString+=" \n"; + composeString+="\n"; + myButton->setSubWidget(ewol::widget::composerGenerateString(composeString)); + } else { + ewol::widget::LabelShared label = ewol::widget::Label::create(); + label->propertyValue.set("" + tmpObject.m_label + ""); + myButton->setSubWidget(label); + } + // add it in the widget list + ewol::widget::Sizer::subWidgetAdd(myButton); + // keep the specific event ... + myButton->signalPressed.connect(sharedFromThis(), &ewol::widget::Menu::onButtonPressed, ewol::widget::ButtonWeak(myButton)); + tmpObject.m_widgetPointer = myButton; + } + m_listElement.pushBack(tmpObject); + return tmpObject.m_localId; +} + +void ewol::widget::Menu::remove(int32_t _id) { + EWOL_TODO("NOT remove..."); +} + + +int32_t ewol::widget::Menu::addSpacer(int32_t _parent) { + ewol::widget::MenuElement tmpObject; + tmpObject.m_localId = m_staticId++; + tmpObject.m_parentId = _parent; + tmpObject.m_label = ""; + tmpObject.m_image = ""; + tmpObject.m_message = ""; + if (tmpObject.m_parentId == -1) { + ewol::widget::SpacerShared mySpacer = ewol::widget::Spacer::create(); + if (mySpacer == null) { + EWOL_ERROR("Allocation spacer error"); + return tmpObject.m_localId; + } + mySpacer->propertyExpand.set(bvec2(true,true)); + mySpacer->propertyFill.set(bvec2(true,true)); + mySpacer->propertyMinSize.set(gale::Dimension(vec2(2,0), gale::distance::pixel)); + mySpacer->propertyMaxSize.set(gale::Dimension(vec2(2,10000), gale::distance::pixel)); + mySpacer->propertyColor.set(etk::Color<>(0,0,0,0xFF)); + // add it in the widget list + ewol::widget::Sizer::subWidgetAdd(mySpacer); + } + m_listElement.pushBack(tmpObject); + return tmpObject.m_localId; +} + +void ewol::widget::Menu::onButtonPressed(ewol::widget::ButtonWeak _button) { + ewol::widget::ButtonShared caller = _button.lock(); + if (caller == null) { + return; + } + for (auto &it : m_listElement) { + if (caller != it.m_widgetPointer.lock()) { + continue; + } + // 2 posible case (have a message or have a child ... + if (it.m_message.size() > 0) { + EWOL_DEBUG("Menu == > generate Event"); + // Send a multicast event ... + signalSelect.emit(it.m_message); + ewol::widget::ContextMenuShared tmpContext = m_widgetContextMenu.lock(); + if (tmpContext != null) { + EWOL_DEBUG("Mark the menu to remove ..."); + tmpContext->destroy(); + } + return; + } + EWOL_DEBUG("Menu == > load Sub Menu"); + bool findChild = false; + for (auto &it2 : m_listElement) { + if (it.m_localId == it2.m_parentId) { + findChild = true; + break; + } + } + if (false == findChild) { + EWOL_WARNING("Event on menu element with no child an no event... label=" << it.m_label); + return; + } + // create a context menu: + ewol::widget::ContextMenuShared tmpContext = ewol::widget::ContextMenu::create(); + m_widgetContextMenu = tmpContext; + if (tmpContext == null) { + EWOL_ERROR("Allocation Error"); + return; + } + // get the button widget: + vec2 newPosition; + ewol::WidgetShared eventFromWidget = ememory::dynamicPointerCast(caller); + if (eventFromWidget != null) { + vec2 tmpOri = eventFromWidget->getOrigin(); + vec2 tmpSize = eventFromWidget->getSize(); + // calculate the correct position + newPosition.setValue(tmpOri.x() + tmpSize.x()/2, + tmpOri.y() ); + } + tmpContext->setPositionMark(ewol::widget::ContextMenu::markTop, newPosition); + ewol::widget::SizerShared mySizer; + ewol::widget::ButtonShared myButton; + mySizer = ewol::widget::Sizer::create(); + if (mySizer != null) { + mySizer->propertyMode.set(widget::Sizer::modeVert); + mySizer->propertyLockExpand.set(vec2(true,true)); + mySizer->propertyFill.set(vec2(true,true)); + // set it in the pop-up-system: + tmpContext->setSubWidget(mySizer); + bool menuHaveImage = false; + for (auto &it2 : m_listElement) { + if (it.m_localId != it2.m_parentId) { + continue; + } + if (it2.m_image.size()!=0) { + menuHaveImage = true; + break; + } + } + for (int64_t iii=m_listElement.size()-1; iii>=0; --iii) { + if (it.m_localId != m_listElement[iii].m_parentId) { + continue; + } + if (m_listElement[iii].m_message == "" && m_listElement[iii].m_label == "") { + ewol::widget::SpacerShared mySpacer = ewol::widget::Spacer::create(); + if (mySpacer == null) { + EWOL_ERROR("Allocation spacer error"); + continue; + } + mySpacer->propertyExpand.set(bvec2(true,true)); + mySpacer->propertyFill.set(bvec2(true,true)); + mySpacer->propertyMinSize.set(gale::Dimension(vec2(0,2), gale::distance::pixel)); + mySpacer->propertyMaxSize.set(gale::Dimension(vec2(10000,2), gale::distance::pixel)); + mySpacer->propertyColor.set(etk::Color<>(0,0,0,0xFF)); + // add it in the widget list + mySizer->subWidgetAdd(mySpacer); + } else { + myButton = ewol::widget::Button::create(); + if (myButton == null) { + EWOL_ERROR("Allocation Error"); + continue; + } + myButton->propertyExpand.set(bvec2(true,true)); + myButton->propertyFill.set(bvec2(true,true)); + // set callback + myButton->signalPressed.connect(sharedFromThis(), &ewol::widget::Menu::onButtonPressed, ewol::widget::ButtonWeak(myButton)); + // add it in the widget list + mySizer->subWidgetAdd(myButton); + if (m_listElement[iii].m_image.size() != 0) { + etk::String composeString; + composeString+= " \n"; + if (etk::end_with(m_listElement[iii].m_image, ".edf") == true) { + composeString+=" \n"; + } else { + composeString+=" \n"; + } + composeString+=" \n"; + composeString+=" \n"; + myButton->setSubWidget(ewol::widget::composerGenerateString(composeString)); + } else { + if (menuHaveImage == true) { + myButton->setSubWidget(ewol::widget::composerGenerateString( + etk::String() + + " \n" + " \n" + " \n" + " \n") + ); + } else { + ewol::widget::LabelShared tmpLabel = widget::Label::create(); + if (tmpLabel != null) { + tmpLabel->propertyValue.set(etk::String("") + m_listElement[iii].m_label + "\n"); + tmpLabel->propertyExpand.set(bvec2(true,false)); + tmpLabel->propertyFill.set(bvec2(true,true)); + myButton->setSubWidget(tmpLabel); + } + } + } + m_listElement[iii].m_widgetPointer = myButton; + } + } + } + ewol::widget::WindowsShared currentWindows = getWindows(); + if (currentWindows == null) { + EWOL_ERROR("Can not get the curent Windows..."); + } else { + currentWindows->popUpWidgetPush(tmpContext); + } + return; + } +} + +bool ewol::widget::Menu::loadXML(const exml::Element& _node) { + if (_node.exist() == false) { + return false; + } + // parse generic properties: + ewol::Widget::loadXML(_node); + // parse all the elements : + for (const auto nodeIt : _node.nodes) { + const exml::Element pNode = nodeIt.toElement(); + if (pNode.exist() == false) { + // trash here all that is not element + continue; + } + etk::String widgetName = pNode.getValue(); + EWOL_INFO("Get node : " << pNode); + if (widgetName == "elem") { + // + int32_t idMenu = addTitle(pNode.attributes["title"], pNode.attributes["image"], pNode.attributes["event"]); + for (const auto nodeIt2 : pNode.nodes) { + + const exml::Element pNode2 = nodeIt2.toElement(); + if (pNode2.exist() == false) { + // trash here all that is not element + continue; + } + etk::String widgetName2 = pNode2.getValue(); + if (widgetName2 == "elem") { + // + add(idMenu, pNode2.attributes["title"], pNode2.attributes["image"], pNode2.attributes["event"]); + } else if (widgetName2 == "separator") { + addSpacer(idMenu); + } else { + EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} (l " << pNode2.getPos() << ") Unknown basic node='" << widgetName2 << "' not in : [elem,separator]" ); + } + } + } else if (widgetName == "separator") { + addSpacer(); + } else { + EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} (l " << pNode.getPos() << ") Unknown basic node='" << widgetName << "' not in : [elem,separator]" ); + } + } + return true; +} diff --git a/src/org/atriasoft/ewol/widget/Menu.hpp b/src/org/atriasoft/ewol/widget/Menu.hpp new file mode 100644 index 0000000..c5e10a2 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Menu.hpp @@ -0,0 +1,63 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class MenuElement { + public : + MenuElement() { }; + int32_t m_localId; + int32_t m_parentId; + ewol::WidgetWeak m_widgetPointer; + etk::String m_label; + etk::String m_image; + etk::String m_message; + }; + class Menu; + using MenuShared = ememory::SharedPtr; + using MenuWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Menu :public ewol::widget::Sizer { + public: + esignal::Signal signalSelect; // event on a menu button or ... + protected: + Menu(); + public: + DECLARE_WIDGET_FACTORY(Menu, "Menu"); + virtual ~Menu(); + private: + void subWidgetRemoveAll() override; + int32_t subWidgetAdd(ewol::WidgetShared _newWidget) override; + void subWidgetRemove(ewol::WidgetShared _newWidget) override; + void subWidgetUnLink(ewol::WidgetShared _newWidget) override; + bool loadXML(const exml::Element& _node) override; + private: + etk::Vector m_listElement; + int32_t m_staticId; // unique ID for every element of the menu ... + ewol::widget::ContextMenuWeak m_widgetContextMenu; + int32_t get(const etk::String& _label); + public: + void clear(); + int32_t addTitle(const etk::String& _label, const etk::String& _image="", const etk::String& _message = ""); + int32_t add(int32_t _parent, const etk::String& _label, const etk::String& _image="", const etk::String& _message = ""); + int32_t addSpacer(int32_t _parent=-1); + void remove(int32_t _id); + private: + void onButtonPressed(ewol::widget::ButtonWeak _button); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/Panned.cpp b/src/org/atriasoft/ewol/widget/Panned.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/org/atriasoft/ewol/widget/Panned.java b/src/org/atriasoft/ewol/widget/Panned.java new file mode 100644 index 0000000..e69de29 diff --git a/src/org/atriasoft/ewol/widget/PopUp.cpp b/src/org/atriasoft/ewol/widget/PopUp.cpp new file mode 100644 index 0000000..73d6a0f --- /dev/null +++ b/src/org/atriasoft/ewol/widget/PopUp.cpp @@ -0,0 +1,179 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::PopUp); + +static const char* annimationIncrease = "increase"; + +ewol::widget::PopUp::PopUp() : + propertyShape(this, "shaper", + etk::Uri("THEME_GUI:///PopUp.json?lib=ewol"), + "The shaper properties", + &ewol::widget::PopUp::onChangePropertyShape), + propertyLockExpand(this, "lock", + bvec2(true,true), + "Lock expand contamination", + &ewol::widget::PopUp::onChangePropertyLockExpand), + propertyCloseOutEvent(this, "out-click-remove", + false, + "Remove the widget if the use click outside") { + addObjectType("ewol::widget::PopUp"); + +} + +void ewol::widget::PopUp::init() { + ewol::widget::Container::init(); + propertyFill.set(bvec2(false,false)); + propertyShape.notifyChange(); + propertyMinSize.set(gale::Dimension(vec2(80,80),gale::distance::pourcent)); + propertyExpand.set(bvec2(false, false)); +} +ewol::widget::PopUp::~PopUp() { + +} + +void ewol::widget::PopUp::onChangeSize() { + markToRedraw(); + if (m_subWidget == null) { + return; + } + ewol::Padding padding = m_shaper.getPadding(); + vec2 subWidgetSize = m_subWidget->getCalculateMinSize(); + if (m_subWidget->canExpand().x() == true) { + if (propertyLockExpand->x() == true) { + subWidgetSize.setX(m_minSize.x()); + } else { + subWidgetSize.setX(m_size.x()-padding.xLeft()); + } + } + if (m_subWidget->canExpand().y() == true) { + if (propertyLockExpand->y() == true) { + subWidgetSize.setY(m_minSize.y()); + } else { + subWidgetSize.setY(m_size.y()-padding.yButtom()); + } + } + // limit the size of the element : + //subWidgetSize.setMin(m_minSize); + // posiition at a int32_t pos : + subWidgetSize = vec2ClipInt32(subWidgetSize); + + // set config to the Sub-widget + vec2 subWidgetOrigin = m_origin + (m_size-subWidgetSize)/2.0f; + subWidgetOrigin = vec2ClipInt32(subWidgetOrigin); + + m_subWidget->setOrigin(subWidgetOrigin); + m_subWidget->setSize(subWidgetSize); + m_subWidget->onChangeSize(); +} + +void ewol::widget::PopUp::systemDraw(const ewol::DrawProperty& _displayProp) { + if (*propertyHide == true){ + // widget is hidden ... + return; + } + ewol::Widget::systemDraw(_displayProp); + if (m_subWidget == null) { + return; + } + if( m_shaper.getNextDisplayedStatus() == -1 + && m_shaper.getTransitionStatus() >= 1.0) { + ewol::DrawProperty prop = _displayProp; + prop.limit(m_origin, m_size); + m_subWidget->systemDraw(prop); + } +} + +void ewol::widget::PopUp::onDraw() { + m_shaper.draw(); +} + +void ewol::widget::PopUp::onRegenerateDisplay() { + if (needRedraw() == true) { + m_shaper.clear(); + ewol::Padding padding = m_shaper.getPadding(); + vec2 tmpSize(0,0); + bvec2 expand = canExpand(); + bvec2 fill = canFill(); + if (fill.x() == true) { + tmpSize.setX(m_size.x()-padding.x()); + } + if (fill.y() == true) { + tmpSize.setY(m_size.y()-padding.y()); + } + if (m_subWidget != null) { + vec2 tmpSize = m_subWidget->getSize(); + } + tmpSize.setMax(m_minSize); + vec2 tmpOrigin = (m_size-tmpSize)/2.0f; + m_shaper.setShape(vec2(0,0), + vec2ClipInt32(m_size), + vec2ClipInt32(tmpOrigin-vec2(padding.xLeft(), padding.yButtom())), + vec2ClipInt32(tmpSize + vec2(padding.x(), padding.y()))); + } + // SUBwIDGET GENERATION ... + if (m_subWidget != null) { + m_subWidget->onRegenerateDisplay(); + } +} + +ewol::WidgetShared ewol::widget::PopUp::getWidgetAtPos(const vec2& _pos) { + ewol::WidgetShared val = ewol::widget::Container::getWidgetAtPos(_pos); + if (val != null) { + return val; + } + return ememory::dynamicPointerCast(sharedFromThis()); +} + +void ewol::widget::PopUp::onChangePropertyShape() { + m_shaper.setSource(*propertyShape); + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::PopUp::onChangePropertyLockExpand() { + markToRedraw(); + requestUpdateSize(); +} + +bool ewol::widget::PopUp::onEventInput(const ewol::event::Input& _event) { + if (_event.getId() == 0) { + return false; + } + if (_event.getStatus() == gale::key::status::move) { + return false; + } + if (*propertyCloseOutEvent == true) { + return false; + } + ewol::Padding padding = m_shaper.getPadding(); + vec2 tmpSize(0,0); + if (m_subWidget != null) { + vec2 tmpSize = m_subWidget->getSize(); + } + tmpSize.setMax(m_minSize); + vec2 tmpOrigin = (m_size-tmpSize)/2.0f; + + tmpOrigin -= vec2(padding.xLeft(), padding.yButtom()); + tmpSize += vec2(padding.x(), padding.y()); + vec2 pos = relativePosition(_event.getPos()); + if( pos.x() < tmpOrigin.x() + || pos.y() < tmpOrigin.y() + || pos.x() > tmpOrigin.x()+tmpSize.x() + || pos.y() > tmpOrigin.y()+tmpSize.y() ) { + autoDestroy(); + return true; + } + return false; +} + diff --git a/src/org/atriasoft/ewol/widget/PopUp.java b/src/org/atriasoft/ewol/widget/PopUp.java new file mode 100644 index 0000000..3d784c9 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/PopUp.java @@ -0,0 +1,58 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class PopUp; + using PopUpShared = ememory::SharedPtr; + using PopUpWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class PopUp : public ewol::widget::Container { + public: // properties + eproperty::Value propertyShape; //!< Compositing theme. + eproperty::Value propertyLockExpand; //!< Lock the expend of the sub widget to this one == > this permit to limit bigger subWidget + eproperty::Value propertyCloseOutEvent; //!< ratio progression of a sliding + protected: + /** + * @brief Constructor + * @param[in] _shaperName Shaper file properties + */ + PopUp(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(PopUp, "PopUp"); + /** + * @brief Destructor + */ + virtual ~PopUp(); + protected: + ewol::compositing::Shaper m_shaper; //!< Compositing theme. + protected: + void onDraw() override; + public: + void systemDraw(const ewol::DrawProperty& _displayProp) override; + void onRegenerateDisplay() override; + void onChangeSize() override; + bool onEventInput(const ewol::event::Input& _event) override; + ewol::WidgetShared getWidgetAtPos(const vec2& _pos) override; + protected: + virtual void onChangePropertyShape(); + virtual void onChangePropertyLockExpand(); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/ProgressBar.cpp b/src/org/atriasoft/ewol/widget/ProgressBar.cpp new file mode 100644 index 0000000..29ca3fe --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ProgressBar.cpp @@ -0,0 +1,97 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::ProgressBar); + +const int32_t dotRadius = 6; + +ewol::widget::ProgressBar::ProgressBar() : + propertyValue(this, "value", + 0.0f, 0.0f, 1.0f, + "Value of the progress bar", + &ewol::widget::ProgressBar::onChangePropertyValue), + propertyTextColorFg(this, "color-bg", + etk::color::black, + "Background color", + &ewol::widget::ProgressBar::onChangePropertyTextColorFg), + propertyTextColorBgOn(this, "color-on", + etk::Color<>(0x00, 0xFF, 0x00, 0xFF), + "Color of the true value", + &ewol::widget::ProgressBar::onChangePropertyTextColorBgOn), + propertyTextColorBgOff(this, "color-off", + etk::color::none, + "Color of the false value", + &ewol::widget::ProgressBar::onChangePropertyTextColorBgOff) { + addObjectType("ewol::widget::ProgressBar"); +} + +void ewol::widget::ProgressBar::init() { + ewol::Widget::init(); + propertyCanFocus.set(true); +} + +ewol::widget::ProgressBar::~ProgressBar() { + +} + +void ewol::widget::ProgressBar::calculateMinMaxSize() { + vec2 tmpMin = propertyMinSize->getPixel(); + m_minSize.setValue( etk::max(tmpMin.x(), 40.0f), + etk::max(tmpMin.y(), dotRadius*2.0f) ); + markToRedraw(); +} + +void ewol::widget::ProgressBar::onDraw() { + m_draw.draw(); +} + +void ewol::widget::ProgressBar::onRegenerateDisplay() { + if (needRedraw() == false) { + return; + } + // clean the object list ... + m_draw.clear(); + + m_draw.setColor(propertyTextColorFg); + + int32_t tmpSizeX = m_size.x() - 10; + int32_t tmpSizeY = m_size.y() - 10; + int32_t tmpOriginX = 5; + int32_t tmpOriginY = 5; + m_draw.setColor(propertyTextColorBgOn); + m_draw.setPos(vec3(tmpOriginX, tmpOriginY, 0) ); + m_draw.rectangleWidth(vec3(tmpSizeX*propertyValue, tmpSizeY, 0) ); + m_draw.setColor(propertyTextColorBgOff); + m_draw.setPos(vec3(tmpOriginX+tmpSizeX*propertyValue, tmpOriginY, 0) ); + m_draw.rectangleWidth(vec3(tmpSizeX*(1.0-propertyValue), tmpSizeY, 0) ); + + // TODO : Create a better progress Bar ... + //m_draw.setColor(propertyTextColorFg); + //m_draw.rectangleBorder( tmpOriginX, tmpOriginY, tmpSizeX, tmpSizeY, 1); +} + +void ewol::widget::ProgressBar::onChangePropertyValue() { + markToRedraw(); +} + +void ewol::widget::ProgressBar::onChangePropertyTextColorFg() { + markToRedraw(); +} + +void ewol::widget::ProgressBar::onChangePropertyTextColorBgOn() { + markToRedraw(); +} + +void ewol::widget::ProgressBar::onChangePropertyTextColorBgOff() { + markToRedraw(); +} + + diff --git a/src/org/atriasoft/ewol/widget/ProgressBar.java b/src/org/atriasoft/ewol/widget/ProgressBar.java new file mode 100644 index 0000000..7b709ea --- /dev/null +++ b/src/org/atriasoft/ewol/widget/ProgressBar.java @@ -0,0 +1,50 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class ProgressBar; + using ProgressBarShared = ememory::SharedPtr; + using ProgressBarWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class ProgressBar : public ewol::Widget { + public: // properties + eproperty::Range propertyValue; //!< % used + eproperty::Value> propertyTextColorFg; //!< forder bar color + eproperty::Value> propertyTextColorBgOn; //!< bar color enable + eproperty::Value> propertyTextColorBgOff; //!< bar color disable + protected: + ProgressBar(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(ProgressBar, "ProgressBar"); + virtual ~ProgressBar(); + private: + ewol::compositing::Drawing m_draw; // basic drawing element + protected: + void onDraw() override; + public: + void onRegenerateDisplay() override; + void calculateMinMaxSize() override; + protected: + virtual void onChangePropertyValue(); + virtual void onChangePropertyTextColorFg(); + virtual void onChangePropertyTextColorBgOn(); + virtual void onChangePropertyTextColorBgOff(); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/Scroll.cpp b/src/org/atriasoft/ewol/widget/Scroll.cpp new file mode 100644 index 0000000..7fb6758 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Scroll.cpp @@ -0,0 +1,444 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Scroll); + +ewol::widget::Scroll::Scroll() : + propertyLimit(this, "limit", + vec2(0.15,0.5), vec2(0.0,0.0), vec2(1.0,1.0), + "Limit the scroll maximum position [0..1]% represent the free space in the scoll when arrive at the end", + &ewol::widget::Scroll::onChangePropertyLimit), + propertyShapeVert(this, "shape-vert", + etk::Uri("THEME_GUI:///WidgetScrolled.json?lib=ewol"), + "shape for the vertical display", + &ewol::widget::Scroll::onChangePropertyShapeVert), + propertyShapeHori(this, "shape-hori", + etk::Uri("THEME_GUI:///WidgetScrolled.json?lib=ewol"), + "shape for the horizonal display", + &ewol::widget::Scroll::onChangePropertyShapeHori), + propertyHover(this, "hover", + true, + "the display bar are hover the subWidget"), + m_pixelScrolling(20), + m_highSpeedStartPos(0,0), + m_highSpeedMode(speedModeDisable), + m_highSpeedButton(-1), + m_highSpeedType(gale::key::type::unknow) { + addObjectType("ewol::widget::Scroll"); + // Remove gravity property: (only keep top/buttom) + propertyGravity.remove("center"); + propertyGravity.remove("top-left"); + //propertyGravity.remove("top"); + propertyGravity.remove("top-right"); + propertyGravity.remove("right"); + propertyGravity.remove("buttom-right"); + //propertyGravity.remove("buttom"); + propertyGravity.remove("buttom-left"); + propertyGravity.remove("left"); +} + +void ewol::widget::Scroll::init() { + ewol::widget::Container::init(); + propertyShapeVert.notifyChange(); + propertyShapeHori.notifyChange(); +} + + +ewol::widget::Scroll::~Scroll() { + +} +// TODO : create a config for this ... +#define SCROLL_BAR_SPACE (15) + +// note: The widget will expand has possible and will control itself the display property +void ewol::widget::Scroll::onChangeSize() { + // Note: No call of container ==> normal case ... + ewol::Widget::onChangeSize(); + if (*propertyHide == true) { + return; + } + if (m_subWidget == null) { + return; + } + // remove the bar if hover + vec2 basicSize = m_size; + if (*propertyHover == false) { + basicSize -= vec2(SCROLL_BAR_SPACE,SCROLL_BAR_SPACE); + } + + + vec2 origin = m_origin+m_offset; + vec2 minSize = m_subWidget->getCalculateMinSize(); + bvec2 expand = m_subWidget->propertyExpand.get(); + //The gravity is not set on the sub element ==> special use of the widget + //origin += ewol::gravityGenerateDelta(propertyGravity.get(), minSize - m_size); + if ( expand.x() == true + && minSize.x() < basicSize.x()) { + minSize.setX(basicSize.x()); + } + if ( expand.y() == true + && minSize.y() < basicSize.y()) { + minSize.setY(basicSize.y()); + } + m_subWidget->setSize(minSize); + if (*propertyGravity == ewol::gravity_top) { + origin += vec2(0.0f, basicSize.y()-minSize.y()); + if (*propertyHover == false) { + origin += vec2(0,SCROLL_BAR_SPACE); + } + } else if (*propertyGravity == ewol::gravity_buttom) { + // nothing to do ... origin += + } else { + EWOL_ERROR(" Not manage other gravity ..."); + } + m_subWidget->setOrigin(origin); + m_subWidget->onChangeSize(); +} + +void ewol::widget::Scroll::calculateMinMaxSize() { + // Note: No call of container ==> normal case ... + ewol::Widget::calculateMinMaxSize(); + // call sub classes + if (m_subWidget != null) { + m_subWidget->calculateMinMaxSize(); + } +} + +void ewol::widget::Scroll::systemDraw(const ewol::DrawProperty& _displayProp) { + if (*propertyHide == true) { + return; + } + if (m_subWidget != null) { + ewol::DrawProperty prop = _displayProp; + prop.limit(m_origin, m_size); + m_subWidget->systemDraw(prop); + } + ewol::Widget::systemDraw(_displayProp); +} + +void ewol::widget::Scroll::onDraw() { + m_shaperH.draw(); + m_shaperV.draw(); + /* + ewol::compositing::Drawing draw; + draw.setPos(vec2(10,10)); + draw.setColor(etk::color::orange); + draw.rectangleWidth(vec2(25,25)); + draw.setPos(m_size - vec2(35,35)); + draw.setColor(etk::color::green); + draw.rectangleWidth(vec2(25,25)); + draw.draw(); + */ +} + +void ewol::widget::Scroll::onRegenerateDisplay() { + if (*propertyHide == true) { + return; + } + // call upper class + ewol::widget::Container::onRegenerateDisplay(); + if (needRedraw() == false) { + return; + } + // clear all previous display + m_shaperH.clear(); + m_shaperV.clear(); + ewol::Padding paddingVert = m_shaperV.getPadding(); + ewol::Padding paddingHori = m_shaperH.getPadding(); + vec2 scrollOffset(0,0); + vec2 scrollSize(0,0); + if (m_subWidget != null) { + scrollOffset = m_subWidget->getOffset(); + scrollSize = m_subWidget->getSize(); + } + if( m_size.y() < scrollSize.y() + || scrollOffset.y() != 0) { + float lenScrollBar = m_size.y()*m_size.y() / scrollSize.y(); + lenScrollBar = etk::avg(10.0f, lenScrollBar, m_size.y()); + float originScrollBar = scrollOffset.y() / (scrollSize.y()-m_size.y()*propertyLimit->y()); + originScrollBar = etk::avg(0.0f, originScrollBar, 1.0f); + originScrollBar *= (m_size.y()-lenScrollBar); + m_shaperV.setShape(vec2(m_size.x() - paddingVert.x(), 0), + vec2(paddingVert.x(), m_size.y()), + vec2(m_size.x() - paddingVert.xRight(), m_size.y() - originScrollBar - lenScrollBar), + vec2(0, lenScrollBar)); + } + if( m_size.x() < scrollSize.x() + || scrollOffset.x() != 0) { + float lenScrollBar = (m_size.x()-paddingHori.xLeft())*(m_size.x()-paddingVert.x()) / scrollSize.x(); + lenScrollBar = etk::avg(10.0f, lenScrollBar, (m_size.x()-paddingVert.x())); + float originScrollBar = scrollOffset.x() / (scrollSize.x()-m_size.x()*propertyLimit->x()); + originScrollBar = etk::avg(0.0f, originScrollBar, 1.0f); + originScrollBar *= (m_size.x()-paddingHori.xRight()-lenScrollBar); + m_shaperH.setShape(vec2(0, 0), + vec2(m_size.x()-paddingVert.x(), paddingHori.y()), + vec2(originScrollBar, paddingHori.yButtom()), + vec2(lenScrollBar, 0)); + } +} + +bool ewol::widget::Scroll::onEventInput(const ewol::event::Input& _event) { + //ewol::event::Input _event = event; + //_event.setType(gale::key::type::finger); + vec2 relativePos = relativePosition(_event.getPos()); + vec2 scrollOffset(0,0); + vec2 scrollSize(0,0); + if (m_subWidget != null) { + scrollOffset = m_subWidget->getOffset(); + scrollSize = m_subWidget->getSize(); + } + EWOL_VERBOSE("Get Event on scroll : " << _event); + relativePos.setY(m_size.y() - relativePos.y()); + if( _event.getType() == gale::key::type::mouse + && ( m_highSpeedType == gale::key::type::unknow + || m_highSpeedType == gale::key::type::mouse) ) { + if( _event.getId() == 1 + && _event.getStatus() == gale::key::status::down) { + // check if selected the scrolling position whth the scrolling bar ... + if (relativePos.x() >= (m_size.x()-SCROLL_BAR_SPACE)) { + if( m_size.y() < scrollSize.y() + || scrollOffset.y() != 0) { + m_highSpeedMode = speedModeEnableVertical; + m_highSpeedType = gale::key::type::mouse; + m_highSpeedStartPos.setX(relativePos.x()); + m_highSpeedStartPos.setY(scrollOffset.y() / scrollSize.y() * (m_size.y()-SCROLL_BAR_SPACE*2)); + m_highSpeedButton = 1; + // force direct scrolling in this case + scrollOffset.setY((int32_t)(scrollSize.y() * (relativePos.y()-SCROLL_BAR_SPACE) / (m_size.y()-SCROLL_BAR_SPACE*2))); + scrollOffset.setY(etk::avg(0.0f, scrollOffset.y(), (scrollSize.y() - m_size.y()*propertyLimit->y()))); + markToRedraw(); + if (m_subWidget != null) { + m_subWidget->setOffset(scrollOffset); + } + return true; + } + } else if (relativePos.y() >= (m_size.y()-SCROLL_BAR_SPACE)) { + if( m_size.x() < scrollSize.x() + || scrollOffset.x()!=0) { + m_highSpeedMode = speedModeEnableHorizontal; + m_highSpeedType = gale::key::type::mouse; + m_highSpeedStartPos.setX(scrollOffset.x() / scrollSize.x() * (m_size.x()-SCROLL_BAR_SPACE*2)); + m_highSpeedStartPos.setY(relativePos.y()); + m_highSpeedButton = 1; + // force direct scrolling in this case + scrollOffset.setX((int32_t)(scrollSize.x() * (relativePos.x()-SCROLL_BAR_SPACE) / (m_size.x()-SCROLL_BAR_SPACE*2))); + scrollOffset.setY(etk::avg(0.0f, scrollOffset.x(), (scrollSize.x() - m_size.x()*propertyLimit->x()))); + markToRedraw(); + if (m_subWidget != null) { + m_subWidget->setOffset(scrollOffset); + } + return true; + } + } + return false; + } else if( _event.getId() == 4 + && _event.getStatus() == gale::key::status::up) { + EWOL_VERBOSE(" mode UP " << m_size.y() << "<" << scrollSize.y()); + if(m_size.y() < scrollSize.y()) { + scrollOffset.setY(scrollOffset.y()-m_pixelScrolling); + scrollOffset.setY(etk::avg(0.0f, scrollOffset.y(), (scrollSize.y() - m_size.y()*propertyLimit->y()))); + markToRedraw(); + if (m_subWidget != null) { + m_subWidget->setOffset(scrollOffset); + } + return true; + } + } else if( _event.getId() == 5 + && _event.getStatus() == gale::key::status::up) { + EWOL_VERBOSE(" mode DOWN " << m_size.y() << "<" << scrollSize.y()); + if(m_size.y() < scrollSize.y()) { + scrollOffset.setY(scrollOffset.y()+m_pixelScrolling); + scrollOffset.setY(etk::avg(0.0f, scrollOffset.y(), (scrollSize.y() - m_size.y()*propertyLimit->y()))); + markToRedraw(); + if (m_subWidget != null) { + m_subWidget->setOffset(scrollOffset); + } + return true; + } + }else if (_event.getId() == 2) { + if (_event.getStatus() == gale::key::status::down) { + m_highSpeedMode = speedModeInit; + m_highSpeedType = gale::key::type::mouse; + m_highSpeedStartPos.setValue(relativePos.x(), relativePos.y()); + m_highSpeedButton = 2; + // not really use... == > just keep some informations + return false; + } + } else if( m_highSpeedMode != speedModeDisable + && _event.getStatus() == gale::key::status::leave) { + m_highSpeedMode = speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + markToRedraw(); + return true; + } + if ( _event.getId() == m_highSpeedButton + && m_highSpeedMode != speedModeDisable) { + if (_event.getStatus() == gale::key::status::up) { + if (m_highSpeedMode == speedModeInit) { + // TODO : generate back the down event ... + m_highSpeedMode = speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + return false; + } else { + m_highSpeedMode = speedModeGrepEndEvent; + markToRedraw(); + return true; + } + } else if (m_highSpeedMode == speedModeGrepEndEvent) { + if (_event.getStatus() == gale::key::status::pressSingle) { + m_highSpeedMode = speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + m_highSpeedButton = -1; + markToRedraw(); + } + return true; + } else if( m_highSpeedMode == speedModeInit + && _event.getStatus() == gale::key::status::move) { + // wait that the cursor move more than 10 px to enable it : + if( etk::abs(relativePos.x() - m_highSpeedStartPos.x()) > 10 + || etk::abs(relativePos.y() - m_highSpeedStartPos.y()) > 10 ) { + // the scrooling can start : + // select the direction : + if (relativePos.x() == m_highSpeedStartPos.x()) { + m_highSpeedMode = speedModeEnableVertical; + } else if (relativePos.y() == m_highSpeedStartPos.y()) { + m_highSpeedMode = speedModeEnableHorizontal; + } else { + float coef = (relativePos.y() - m_highSpeedStartPos.y()) / (relativePos.x() - m_highSpeedStartPos.x()); + if (etk::abs(coef) <= 1 ) { + m_highSpeedMode = speedModeEnableHorizontal; + } else { + m_highSpeedMode = speedModeEnableVertical; + } + } + if (m_highSpeedMode == speedModeEnableHorizontal) { + m_highSpeedStartPos.setX(scrollOffset.x() / scrollSize.x() * (m_size.x()-SCROLL_BAR_SPACE*2)); + } else { + m_highSpeedStartPos.setY(scrollOffset.y() / scrollSize.y() * (m_size.y()-SCROLL_BAR_SPACE*2)); + } + markToRedraw(); + } + scrollOffset.setY(etk::avg(0.0f, scrollOffset.y(), (scrollSize.y() - m_size.y()*propertyLimit->y()))); + if (m_subWidget != null) { + m_subWidget->setOffset(scrollOffset); + } + return true; + } + if( m_highSpeedMode == speedModeEnableHorizontal + && _event.getStatus() == gale::key::status::move) { + scrollOffset.setX((int32_t)(scrollSize.x() * (relativePos.x()-SCROLL_BAR_SPACE) / (m_size.x()-SCROLL_BAR_SPACE*2))); + scrollOffset.setX(etk::avg(0.0f, scrollOffset.x(), (scrollSize.x() - m_size.x()*propertyLimit->x() ))); + markToRedraw(); + if (m_subWidget != null) { + m_subWidget->setOffset(scrollOffset); + } + return true; + } + if( m_highSpeedMode == speedModeEnableVertical + && _event.getStatus() == gale::key::status::move) { + scrollOffset.setY((int32_t)(scrollSize.y() * (relativePos.y()-SCROLL_BAR_SPACE) / (m_size.y()-SCROLL_BAR_SPACE*2))); + scrollOffset.setY(etk::avg(0.0f, scrollOffset.y(), (scrollSize.y() - m_size.y()*propertyLimit->x()))); + markToRedraw(); + if (m_subWidget != null) { + m_subWidget->setOffset(scrollOffset); + } + return true; + } + } + } else if( gale::key::type::finger == _event.getType() + && ( gale::key::type::unknow == m_highSpeedType + || gale::key::type::finger == m_highSpeedType ) ) { + if (1 == _event.getId()) { + EWOL_VERBOSE("event: " << _event); + if (gale::key::status::down == _event.getStatus()) { + m_highSpeedMode = speedModeInit; + m_highSpeedType = gale::key::type::finger; + m_highSpeedStartPos.setValue(relativePos.x(), relativePos.y()); + EWOL_VERBOSE("SCROOL == > INIT pos=" << m_highSpeedStartPos << " && curent scrollOffset=" << scrollOffset); + return true; + } else if (gale::key::status::upAfter == _event.getStatus()) { + m_highSpeedMode = speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + EWOL_VERBOSE("SCROOL == > DISABLE"); + markToRedraw(); + return true; + } else if ( m_highSpeedMode == speedModeInit + && gale::key::status::move == _event.getStatus()) { + // wait that the cursor move more than 10 px to enable it : + if( etk::abs(relativePos.x() - m_highSpeedStartPos.x()) > 10 + || etk::abs(relativePos.y() - m_highSpeedStartPos.y()) > 10 ) { + // the scrooling can start : + // select the direction : + m_highSpeedMode = speedModeEnableFinger; + EWOL_VERBOSE("SCROOL == > ENABLE"); + markToRedraw(); + } + return true; + } + if ( m_highSpeedMode == speedModeEnableFinger + && gale::key::status::move == _event.getStatus()) { + EWOL_VERBOSE("SCROOL == > INIT scrollOffset=" << scrollOffset.y() << " relativePos=" << relativePos.y() << " m_highSpeedStartPos=" << m_highSpeedStartPos.y()); + //scrollOffset.x = (int32_t)(scrollSize.x * x / m_size.x); + if (propertyLimit->x() != 0.0f) { + scrollOffset.setX(scrollOffset.x() + (relativePos.x() - m_highSpeedStartPos.x())); + scrollOffset.setX(etk::avg(0.0f, scrollOffset.x(), (scrollSize.x() - m_size.x()*propertyLimit->x()))); + } + if (propertyLimit->y() != 0.0f) { + scrollOffset.setY(scrollOffset.y() - (relativePos.y() - m_highSpeedStartPos.y())); + scrollOffset.setY(etk::avg(0.0f, scrollOffset.y(), (scrollSize.y() - m_size.y()*propertyLimit->y()))); + } + // update current position: + m_highSpeedStartPos = relativePos; + EWOL_VERBOSE("SCROOL == > MOVE " << scrollOffset); + markToRedraw(); + if (m_subWidget != null) { + m_subWidget->setOffset(scrollOffset); + } + return true; + } + if (m_highSpeedMode == speedModeEnableFinger) { + return true; + } + } else if ( m_highSpeedMode != speedModeDisable + && gale::key::status::leave == _event.getStatus()) { + m_highSpeedMode = speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + EWOL_VERBOSE("SCROOL == > DISABLE"); + markToRedraw(); + return true; + } + } + return false; +} + +ewol::WidgetShared ewol::widget::Scroll::getWidgetAtPos(const vec2& _pos) { + ewol::WidgetShared tmpWidget = ewol::widget::Container::getWidgetAtPos(_pos); + if (tmpWidget != null) { + return tmpWidget; + } + return ememory::dynamicPointerCast(sharedFromThis());; +} + +void ewol::widget::Scroll::onChangePropertyLimit() { + markToRedraw(); +} + +void ewol::widget::Scroll::onChangePropertyShapeVert() { + m_shaperV.setSource(propertyShapeVert); + markToRedraw(); +} + +void ewol::widget::Scroll::onChangePropertyShapeHori() { + m_shaperH.setSource(propertyShapeHori); + markToRedraw(); +} + diff --git a/src/org/atriasoft/ewol/widget/Scroll.java b/src/org/atriasoft/ewol/widget/Scroll.java new file mode 100644 index 0000000..e7959d0 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Scroll.java @@ -0,0 +1,66 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Scroll; + using ScrollShared = ememory::SharedPtr; + using ScrollWeak = ememory::WeakPtr; + class Scroll : public ewol::widget::Container { + public: // properties + eproperty::Range propertyLimit; //!< Set the limitation of the ratio in the sreen + eproperty::Value propertyShapeVert; //!< Vertical shaper name + eproperty::Value propertyShapeHori; //!< Horizontal shaper name + eproperty::Value propertyHover; //!< Horizontal shaper name + public: + enum highSpeedMode { + speedModeDisable, + speedModeInit, + speedModeEnableFinger, // Specific for touchpad + speedModeEnableHorizontal, // Specific for mouse + speedModeEnableVertical, // Specific for mouse + speedModeGrepEndEvent + }; + private: + ewol::compositing::Shaper m_shaperH; //!< Compositing theme Horizontal. + ewol::compositing::Shaper m_shaperV; //!< Compositing theme Vertical. + private: + float m_pixelScrolling; + vec2 m_highSpeedStartPos; + enum highSpeedMode m_highSpeedMode; + int32_t m_highSpeedButton; + enum gale::key::type m_highSpeedType; + protected: + Scroll(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(Scroll, "Scroll"); + virtual ~Scroll(); + public: + void onChangeSize() override; + void calculateMinMaxSize() override; + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + void systemDraw(const ewol::DrawProperty& _displayProp) override; + ewol::WidgetShared getWidgetAtPos(const vec2& _pos) override; + protected: + void onDraw() override; + protected: + virtual void onChangePropertyLimit(); + virtual void onChangePropertyShapeVert(); + virtual void onChangePropertyShapeHori(); + }; + } +} + diff --git a/src/org/atriasoft/ewol/widget/Select.cpp b/src/org/atriasoft/ewol/widget/Select.cpp new file mode 100644 index 0000000..4a849ce --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Select.cpp @@ -0,0 +1,205 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#include +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::Select); + +ewol::widget::Select::Element::Element(int32_t _value, etk::String _name, bool _selected): + m_value(_value), + m_name(_name), + m_selected(_selected) { + +} + +ewol::widget::Select::Select() : + signalValue(this, "value", "Select value change"), + propertyValue(this, "value", + -1, + "Value of the Select", + &ewol::widget::Select::onChangePropertyValue) { + addObjectType("ewol::widget::Select"); + // override the basic parameter: + propertyShape.setDirectCheck(etk::Uri("THEME_GUI:///Select.json?lib=ewol")); + propertySpinMode.setDirect(ewol::widget::spinPosition_noneRight); + propertySpinMode.changeDefault(ewol::widget::spinPosition_noneRight); + propertySpinMode.rename("none-none", "none"); + propertySpinMode.rename("none-right", "right"); + propertySpinMode.rename("left-none", "left"); + propertySpinMode.remove("left-right"); + propertySpinMode.remove("left-left"); + propertySpinMode.remove("right-right"); +} + +ewol::widget::Select::~Select() { + +} + +void ewol::widget::Select::onChangePropertyValue() { + markToRedraw(); + if (m_widgetEntry == null) { + EWOL_ERROR("Can not acces at entry ..."); + return; + } + for (auto &it : m_listElement) { + if (it.m_value == propertyValue.get()) { + if (it.m_selected == false) { + it.m_selected = true; + m_widgetEntry->propertyValue.set(it.m_name); + signalValue.emit(propertyValue.get()); + } + } else { + it.m_selected = false; + } + } +} + +void ewol::widget::Select::optionSelectDefault() { + if (m_widgetEntry == null) { + EWOL_ERROR("Can not acces at entry ..."); + return; + } + for (auto &it : m_listElement) { + if (it.m_selected == true) { + return; + } + } + if (m_listElement.size() == 0) { + m_widgetEntry->propertyValue.set(""); + } + m_widgetEntry->propertyValue.set(m_listElement[0].m_name); +} + +void ewol::widget::Select::optionRemove(int32_t _value) { + for (auto it=m_listElement.begin(); it != m_listElement.end(); ++it) { + if (_value == it->m_value) { + EWOL_DEBUG("remove element: " << _value); + m_listElement.erase(it); + break; + } + } + optionSelectDefault(); +} + +void ewol::widget::Select::optionClear() { + m_listElement.clear(); + optionSelectDefault(); +} + +void ewol::widget::Select::optionAdd(int32_t _value, etk::String _data) { + for (auto &it : m_listElement) { + if (_value == it.m_value) { + EWOL_DEBUG("replace element: " << _value << " with: '" << _data << "'"); + it.m_name = _data; + } + } + m_listElement.pushBack(ewol::widget::Select::Element(_value, _data, false)); +} + +bool ewol::widget::Select::loadXML(const exml::Element& _node) { + if (_node.exist() == false) { + return false; + } + // parse generic properties: + ewol::widget::SpinBase::loadXML(_node); + // remove previous element: + //subWidgetRemove(); + // parse all the elements: + for(const auto it : _node.nodes) { + exml::Element pNode = it.toElement(); + if (pNode.exist() == false) { + // trash here all that is not element + continue; + } + if (pNode.getValue() != "option") { + EWOL_ERROR("(l " << pNode.getPos() << ") Unknown basic node='" << pNode.getValue() << "' not in : [option]" ); + continue; + } + etk::String valId = pNode.attributes["id"]; + etk::String valIsSelected = pNode.attributes["select"]; + etk::String valText = pNode.getText(); + int32_t id = etk::string_to_int32_t(valId); + bool select = etk::string_to_bool(valIsSelected); + optionAdd(id, valText); + if (select == true) { + propertyValue.set(id); + } + EWOL_WARNING("Add option : id='" << valId << "' select='" << valIsSelected << "' text='" << valText << "'"); + } + return true; +} + +void ewol::widget::Select::updateGui() { + ewol::widget::SpinBase::updateGui(); + + if ( m_widgetEntry != null + && m_connectionEntry.isConnected() == false) { + + } + if ( m_widgetButtonUp != null + && m_connectionButton.isConnected() == false) { + m_connectionButton = m_widgetButtonUp->signalPressed.connect(this, &ewol::widget::Select::onCallbackOpenMenu); + } + +} + +void ewol::widget::Select::onCallbackLabelPressed(int32_t _value) { + EWOL_VERBOSE("User select:" << _value); + propertyValue.set(_value); +} + +void ewol::widget::Select::onCallbackOpenMenu() { + // create a context menu: + ewol::widget::ContextMenuShared tmpContext = ewol::widget::ContextMenu::create(); + if (tmpContext == null) { + EWOL_ERROR("Allocation Error"); + return; + } + // auto-select mark position: + tmpContext->setPositionMarkAuto(m_origin, m_size); + ewol::widget::SizerShared mySizer; + mySizer = ewol::widget::Sizer::create(); + if (mySizer == null) { + EWOL_ERROR("Allocation Error or sizer"); + return; + } + mySizer->propertyMode.set(widget::Sizer::modeVert); + mySizer->propertyLockExpand.set(vec2(true,true)); + mySizer->propertyFill.set(vec2(true,true)); + // set it in the pop-up-system: + tmpContext->setSubWidget(mySizer); + for (auto &it : m_listElement) { + ewol::widget::LabelShared myLabel = ewol::widget::Label::create(); + if (myLabel == null) { + EWOL_ERROR("Allocation Error"); + continue; + } + if (it.m_selected == true) { + myLabel->propertyValue.set(etk::String("") + it.m_name + ""); + } else { + myLabel->propertyValue.set(it.m_name); + } + myLabel->propertyExpand.set(bvec2(true,true)); + myLabel->propertyFill.set(bvec2(true,true)); + // set callback + myLabel->signalPressed.connect(sharedFromThis(), &ewol::widget::Select::onCallbackLabelPressed, it.m_value); + myLabel->signalPressed.connect(tmpContext, &ewol::widget::ContextMenu::destroy); + // add it in the widget list + mySizer->subWidgetAddStart(myLabel); + } + ewol::widget::WindowsShared currentWindows = getWindows(); + if (currentWindows == null) { + EWOL_ERROR("Can not get the curent Windows..."); + } else { + currentWindows->popUpWidgetPush(tmpContext); + } +} + diff --git a/src/org/atriasoft/ewol/widget/Select.java b/src/org/atriasoft/ewol/widget/Select.java new file mode 100644 index 0000000..9f56f50 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Select.java @@ -0,0 +1,68 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include + +namespace ewol { + namespace widget { + class Select; + using SelectShared = ememory::SharedPtr; + using SelectWeak = ememory::WeakPtr; + /** + * @brief a composed Select is a Select with an inside composed with the specify XML element + * ==> this permit to generate standard element simple + */ + class Select : public ewol::widget::SpinBase { + public: // signals + esignal::Signal signalValue; + public: // properties + eproperty::Value propertyValue; //!< Current state of the Select. + protected: + /** + * @brief Constructor + * @param[in] _shaperName Shaper file properties + */ + Select(); + public: + DECLARE_WIDGET_FACTORY(Select, "Select"); + /** + * @brief Destructor + */ + virtual ~Select(); + protected: + class Element { + public: + int32_t m_value; + etk::String m_name; + bool m_selected; + public: + // TODO: Remove this: due to the fact my etk::Vector is not full implemented + Element() {} + Element(int32_t _value, etk::String _name, bool _selected=false); + }; + etk::Vector m_listElement; + public: + void optionSelectDefault(); + void optionRemove(int32_t _value); + void optionClear(); + void optionAdd(int32_t _value, etk::String _name); + protected: + bool loadXML(const exml::Element& _node) override; + void updateGui() override; + protected: + void onCallbackOpenMenu(); + void onCallbackLabelPressed(int32_t _value); + protected: + esignal::Connection m_connectionEntry; + esignal::Connection m_connectionButton; + protected: + virtual void onChangePropertyValue(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/Sizer.cpp b/src/org/atriasoft/ewol/widget/Sizer.cpp new file mode 100644 index 0000000..d41a460 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Sizer.cpp @@ -0,0 +1,300 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Sizer); +ETK_DECLARE_TYPE(enum ewol::widget::Sizer::animation); +ETK_DECLARE_TYPE(enum ewol::widget::Sizer::displayMode); +ewol::widget::Sizer::Sizer() : + propertyMode(this, "mode", + modeHori, + "The display mode", + &ewol::widget::Sizer::onChangePropertyMode), + propertyBorderSize(this, "border", + vec2(0,0), + "The sizer border size", + &ewol::widget::Sizer::onChangePropertyBorderSize), + propertyAnimation(this, "annimation", + animationNone, + "sizer annimation"), + propertyAnimationTime(this, "annimation-time", + 0, + "time of the anniation") { + addObjectType("ewol::widget::Sizer"); + propertyMode.add(modeHori, "hori"); + propertyMode.add(modeVert, "vert"); + propertyAnimation.add(animationNone, "none"); + propertyAnimation.add(animationTop, "top"); + propertyAnimation.add(animationbuttom, "buttom"); + propertyAnimation.add(animationLeft, "left"); + propertyAnimation.add(animationRight, "right"); +} + +ewol::widget::Sizer::~Sizer() { + //EWOL_DEBUG("[" << getId() << "]={" << getObjectType() << "} sizer : destroy (mode=" << (propertyMode == ewol::widget::Sizer::modeVert?"Vert":"Hori") << ")"); +} + + +void ewol::widget::Sizer::onChangeSize() { + ewol::Widget::onChangeSize(); + vec2 tmpBorderSize = propertyBorderSize->getPixel(); + EWOL_VERBOSE("[" << getId() << "] update size : " << m_size << " nbElement : " << m_subWidget.size() << " borderSize=" << tmpBorderSize << " from border=" << propertyBorderSize); + vec2 localWidgetSize = m_size - tmpBorderSize*2.0f; + // -1- calculate min-size and expand requested: + vec2 minSize(0.0f, 0.0f); + ivec2 nbWidgetExpand(0,0); + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + vec2 tmpSize = it->getCalculateMinSize(); + if (*propertyMode == ewol::widget::Sizer::modeVert) { + minSize = vec2(etk::max(minSize.x(), tmpSize.x()), + minSize.y() + tmpSize.y()); + } else { + minSize = vec2(minSize.x() + tmpSize.x(), + etk::max(minSize.y(), tmpSize.y())); + } + bvec2 expand = it->canExpand(); + nbWidgetExpand += ivec2(expand.x()==true?1:0, + expand.y()==true?1:0); + } + // -2- Calculate the size to add at every elements... + float deltaExpandSize = 0.0f; + if (nbWidgetExpand != ivec2(0,0)) { + if (*propertyMode == ewol::widget::Sizer::modeVert) { + deltaExpandSize = (localWidgetSize.y() - minSize.y()) / float(nbWidgetExpand.y()); + } else { + deltaExpandSize = (localWidgetSize.x() - minSize.x()) / float(nbWidgetExpand.x()); + } + if (deltaExpandSize<0.0) { + deltaExpandSize=0; + } + } + // -3- Configure all at the min size ... + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + it->setSize(it->getCalculateMinSize()); + } + // -4- For each element we apply the minmax range and update if needed + while (deltaExpandSize > 0.0001f) { + float residualNext = 0.0f; + // get the number of element that need to devide... + int32_t countCalculation = nbWidgetExpand.x(); + if (*propertyMode == ewol::widget::Sizer::modeVert) { + countCalculation = nbWidgetExpand.y(); + } + // -4.1- Update every subWidget size + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + vec2 tmpSizeMin = it->getSize(); + vec2 tmpSizeMax = it->getCalculateMaxSize(); + // Now update his size his size in X and the curent sizer size in Y: + if (*propertyMode == ewol::widget::Sizer::modeVert) { + if (it->canExpand().y() == true) { + float sizeExpand = tmpSizeMin.y() + deltaExpandSize; + if (sizeExpand > tmpSizeMax.y()) { + residualNext += (sizeExpand - tmpSizeMax.y()); + sizeExpand = tmpSizeMax.y(); + countCalculation--; + } + tmpSizeMin.setY(sizeExpand); + } + it->setSize(tmpSizeMin); + } else { + if (it->canExpand().x() == true) { + float sizeExpand = tmpSizeMin.x() + deltaExpandSize; + if (sizeExpand > tmpSizeMax.x()) { + residualNext += (sizeExpand - tmpSizeMax.x()); + sizeExpand = tmpSizeMax.x(); + countCalculation--; + } + tmpSizeMin.setX(sizeExpand); + } + it->setSize(tmpSizeMin); + } + } + // Reset size add ... + deltaExpandSize = 0.0f; + if (residualNext < 0.0001f) { + break; + } + if (countCalculation <= 0) { + break; + } + if (*propertyMode == ewol::widget::Sizer::modeVert) { + deltaExpandSize = residualNext / float(countCalculation); + } else { + deltaExpandSize = residualNext / float(countCalculation); + } + if (deltaExpandSize < 0.0f) { + deltaExpandSize = 0.0f; + break; + } + } + // -5- Update the expand in the second size if vert ==> X and if hori ==> Y + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + // Now update his size his size in X and the curent sizer size in Y: + if (*propertyMode == ewol::widget::Sizer::modeVert) { + if (it->canExpand().x() == false) { + continue; + } + vec2 tmpSizeMin = it->getSize(); + tmpSizeMin.setX(etk::avg(tmpSizeMin.x(), localWidgetSize.x(), it->getCalculateMaxSize().x())); + it->setSize(tmpSizeMin); + } else { + if (it->canExpand().y() == false) { + continue; + } + vec2 tmpSizeMin = it->getSize(); + tmpSizeMin.setY(etk::avg(tmpSizeMin.y(), localWidgetSize.y(), it->getCalculateMaxSize().y())); + it->setSize(tmpSizeMin); + } + } + // -6- Force size at the entire number: + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + it->setSize(vec2ClipInt32(it->getSize())); + } + // -7- get under Size + vec2 underSize(0,0); + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + vec2 size = it->getSize(); + if (*propertyMode == ewol::widget::Sizer::modeVert) { + underSize += vec2(0.0f, size.y()); + underSize.setX(etk::max(underSize.x(), size.x())); + } else { + underSize += vec2(size.x(), 0.0f); + underSize.setY(etk::max(underSize.y(), size.y())); + } + } + vec2 deltas = localWidgetSize - underSize; + + // -8- Calculate the local origin, depending of the gravity: + vec2 tmpOrigin = m_origin + tmpBorderSize + ewol::gravityGenerateDelta(propertyGravity, deltas); + // -9- Set sub widget origin: + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + vec2 origin; + vec2 size = it->getSize(); + if (*propertyMode == ewol::widget::Sizer::modeVert) { + origin = vec2ClipInt32(tmpOrigin+m_offset + ewol::gravityGenerateDelta(propertyGravity, vec2(underSize.x()-size.x(),0.0f))); + } else { + origin = vec2ClipInt32(tmpOrigin+m_offset + ewol::gravityGenerateDelta(propertyGravity, vec2(0.0f, underSize.y()-size.y()))); + } + it->setOrigin(origin); + if (*propertyMode == ewol::widget::Sizer::modeVert) { + tmpOrigin.setY(tmpOrigin.y() + size.y()); + } else { + tmpOrigin.setX(tmpOrigin.x() + size.x()); + } + } + // -10- Update all subSize at every element: + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + it->onChangeSize(); + } + markToRedraw(); +} + +void ewol::widget::Sizer::calculateMinMaxSize() { + EWOL_VERBOSE("[" << getId() << "] update minimum size"); + m_subExpend.setValue(false, false); + m_minSize = propertyMinSize->getPixel(); + vec2 tmpBorderSize = propertyBorderSize->getPixel(); + EWOL_VERBOSE("[" << getId() << "] {" << getObjectType() << "} set min size : " << m_minSize); + for (auto &it : m_subWidget) { + if (it == null) { + continue; + } + it->calculateMinMaxSize(); + if (it->canExpand().x() == true) { + m_subExpend.setX(true); + } + if (it->canExpand().y() == true) { + m_subExpend.setY(true); + } + vec2 tmpSize = it->getCalculateMinSize(); + EWOL_VERBOSE("[" << getId() << "] NewMinSize=" << tmpSize); + EWOL_VERBOSE("[" << getId() << "] {" << getObjectType() << "} Get minSize="<< tmpSize); + if (*propertyMode == ewol::widget::Sizer::modeVert) { + m_minSize.setY(m_minSize.y() + tmpSize.y()); + if (tmpSize.x()>m_minSize.x()) { + m_minSize.setX(tmpSize.x()); + } + } else { + m_minSize.setX(m_minSize.x() + tmpSize.x()); + if (tmpSize.y()>m_minSize.y()) { + m_minSize.setY(tmpSize.y()); + } + } + } + m_minSize += tmpBorderSize*2; + //EWOL_ERROR("[" << getId() << "] {" << getObjectType() << "} Result min size : " << m_minSize); +} + +int32_t ewol::widget::Sizer::subWidgetAdd(ewol::WidgetShared _newWidget) { + if (*propertyAnimation == animationNone) { + return ewol::widget::ContainerN::subWidgetAdd(_newWidget); + } + // TODO : ... + return ewol::widget::ContainerN::subWidgetAdd(_newWidget); +} + +int32_t ewol::widget::Sizer::subWidgetAddStart(ewol::WidgetShared _newWidget) { + if (*propertyAnimation == animationNone) { + return ewol::widget::ContainerN::subWidgetAddStart(_newWidget); + } + // TODO : ... + return ewol::widget::ContainerN::subWidgetAddStart(_newWidget); +} + +void ewol::widget::Sizer::subWidgetRemove(ewol::WidgetShared _newWidget) { + if (*propertyAnimation == animationNone) { + ewol::widget::ContainerN::subWidgetRemove(_newWidget); + return; + } + // TODO : ... + ewol::widget::ContainerN::subWidgetRemove(_newWidget); +} + +void ewol::widget::Sizer::subWidgetUnLink(ewol::WidgetShared _newWidget) { + if (*propertyAnimation == animationNone) { + ewol::widget::ContainerN::subWidgetUnLink(_newWidget); + return; + } + // TODO : ... + ewol::widget::ContainerN::subWidgetUnLink(_newWidget); +} + +void ewol::widget::Sizer::onChangePropertyMode() { + markToRedraw(); + requestUpdateSize(); +} + +void ewol::widget::Sizer::onChangePropertyBorderSize() { + markToRedraw(); + requestUpdateSize(); +} diff --git a/src/org/atriasoft/ewol/widget/Sizer.java b/src/org/atriasoft/ewol/widget/Sizer.java new file mode 100644 index 0000000..8edaa27 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Sizer.java @@ -0,0 +1,68 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Sizer; + using SizerShared = ememory::SharedPtr; + using SizerWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Sizer : public ewol::widget::ContainerN { + public: + enum displayMode { + modeVert, //!< Vertical mode + modeHori, //!< Horizontal mode + }; + enum animation { + animationNone, //!< No annimation + animationTop, //!< element came from the top + animationbuttom, //!< element came from the buttom + animationLeft, //!< element came from the Left + animationRight //!< element came from the right + //animationZoom //!< element came from zooming + }; + public: // properties: + eproperty::List propertyMode; //!< Methode to display the widget list (vert/hory ...) + eproperty::Value propertyBorderSize; //!< Border size needed for all the display + eproperty::List propertyAnimation; //!< Methode add and remove element (animation) + eproperty::Value propertyAnimationTime; //!< Time in second to generate animation + protected: + /** + * @brief Constructor + * @param[in] _mode The mode to display the elements + */ + Sizer(); + public: + DECLARE_WIDGET_FACTORY(Sizer, "Sizer"); + /** + * @brief Destructor + */ + virtual ~Sizer(); + public: + void onChangeSize() override; + void calculateMinMaxSize() override; + // overwrite the set fuction to start annimations ... + int32_t subWidgetAdd(ewol::WidgetShared _newWidget) override; + int32_t subWidgetAddStart(ewol::WidgetShared _newWidget) override; + void subWidgetRemove(ewol::WidgetShared _newWidget) override; + void subWidgetUnLink(ewol::WidgetShared _newWidget) override; + protected: + virtual void onChangePropertyMode(); + virtual void onChangePropertyBorderSize(); + }; + } +} + diff --git a/src/org/atriasoft/ewol/widget/Slider.cpp b/src/org/atriasoft/ewol/widget/Slider.cpp new file mode 100644 index 0000000..07f5c2a --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Slider.cpp @@ -0,0 +1,134 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Slider); + +const int32_t dotRadius = 6; + +ewol::widget::Slider::Slider() : + signalChange(this, "change", ""), + propertyValue(this, "value", + 0.0f, + "Value of the Slider", + &ewol::widget::Slider::onChangePropertyValue), + propertyMinimum(this, "min", + 0.0f, + "Minium value", + &ewol::widget::Slider::onChangePropertyMinimum), + propertyMaximum(this, "max", + 10.0f, + "Maximum value", + &ewol::widget::Slider::onChangePropertyMaximum), + propertyStep(this, "step", + 1.0f, + "Step size", + &ewol::widget::Slider::onChangePropertyStep) { + addObjectType("ewol::widget::Slider"); + + m_textColorFg = etk::color::black; + + m_textColorBg = etk::color::black; + m_textColorBg.setA(0x3F); + + propertyCanFocus.setDirectCheck(true); + // Limit event at 1: + setMouseLimit(1); +} + +ewol::widget::Slider::~Slider() { + +} + +void ewol::widget::Slider::calculateMinMaxSize() { + vec2 minTmp = propertyMinSize->getPixel(); + m_minSize.setValue(etk::max(minTmp.x(), 40.0f), + etk::max(minTmp.y(), dotRadius*2.0f) ); + markToRedraw(); +} + +void ewol::widget::Slider::onDraw() { + m_draw.draw(); +} + +void ewol::widget::Slider::onRegenerateDisplay() { + if (needRedraw() == false) { + return; + } + // clean the object list ... + m_draw.clear(); + m_draw.setColor(m_textColorFg); + // draw a line : + m_draw.setThickness(1); + m_draw.setPos(vec3(dotRadius, m_size.y()/2, 0) ); + m_draw.lineTo(vec3(m_size.x()-dotRadius, m_size.y()/2, 0) ); + m_draw.setThickness(0); + + etk::Color<> borderDot = m_textColorFg; + borderDot.setA(borderDot.a()/2); + m_draw.setPos(vec3(4+((propertyValue-propertyMinimum)/(propertyMaximum-propertyMinimum))*(m_size.x()-2*dotRadius), m_size.y()/2, 0) ); + m_draw.setColorBg(borderDot); + m_draw.circle(dotRadius); + m_draw.setColorBg(m_textColorFg); + m_draw.circle(dotRadius/1.6); +} + +bool ewol::widget::Slider::onEventInput(const ewol::event::Input& _event) { + vec2 relativePos = relativePosition(_event.getPos()); + //EWOL_DEBUG("Event on Slider ..." << _event); + if (1 == _event.getId()) { + if( gale::key::status::pressSingle == _event.getStatus() + || gale::key::status::move == _event.getStatus()) { + // get the new position : + EWOL_VERBOSE("Event on Slider (" << relativePos.x() << "," << relativePos.y() << ")"); + float oldValue = *propertyValue; + updateValue(*propertyMinimum + (float)(relativePos.x() - dotRadius) / (m_size.x()-2*dotRadius) * (*propertyMaximum-*propertyMinimum)); + if (oldValue != *propertyValue) { + EWOL_VERBOSE(" new value : " << *propertyValue << " in [" << *propertyMinimum << ".." << *propertyMaximum << "]"); + signalChange.emit(*propertyValue); + } + return true; + } + } + return false; +} + +void ewol::widget::Slider::updateValue(float _newValue) { + _newValue = etk::max(etk::min(_newValue, *propertyMaximum), *propertyMinimum); + if (*propertyStep == 0.0f) { + propertyValue.setDirect(_newValue); + } else { + float basicVal = (int64_t)(_newValue / *propertyStep); + propertyValue.setDirect(basicVal * *propertyStep); + } + markToRedraw(); +} + + +void ewol::widget::Slider::onChangePropertyValue() { + updateValue(*propertyValue); + return; +} + +void ewol::widget::Slider::onChangePropertyMinimum() { + updateValue(*propertyValue); + return; +} + +void ewol::widget::Slider::onChangePropertyMaximum() { + updateValue(*propertyValue); + return; +} + +void ewol::widget::Slider::onChangePropertyStep() { + updateValue(*propertyValue); + return; +} + + diff --git a/src/org/atriasoft/ewol/widget/Slider.java b/src/org/atriasoft/ewol/widget/Slider.java new file mode 100644 index 0000000..3ef1874 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Slider.java @@ -0,0 +1,60 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Slider; + using SliderShared = ememory::SharedPtr; + using SliderWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Slider : public ewol::Widget { + public: // signals + esignal::Signal signalChange; + public: + //eproperty::Value propertyShape; //!< name of the shape used + eproperty::Value propertyValue; //!< current value of the Slider + eproperty::Value propertyMinimum; //!< minimum value of the slider + eproperty::Value propertyMaximum; //!< maximum value of the slider + eproperty::Value propertyStep; //!< step of every iteration of the slider (increment/precision) + protected: + Slider(); + public: + DECLARE_WIDGET_FACTORY(Slider, "Slider"); + virtual ~Slider(); + public: + // TODO : Rewoek the color in the theme ... + void setColor(etk::Color<> _newColor) { + m_textColorFg = _newColor; + }; + protected: + ewol::compositing::Drawing m_draw; //!< drawing tool. + etk::Color<> m_textColorFg; //!< Text color + etk::Color<> m_textColorBg; //!< Background color + void updateValue(float _newValue); + public: // Derived function + void onDraw() override; + void calculateMinMaxSize() override; + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + protected: + virtual void onChangePropertyValue(); + virtual void onChangePropertyMinimum(); + virtual void onChangePropertyMaximum(); + virtual void onChangePropertyStep(); + }; + } +} + diff --git a/src/org/atriasoft/ewol/widget/Spacer.cpp b/src/org/atriasoft/ewol/widget/Spacer.cpp new file mode 100644 index 0000000..1e6143b --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Spacer.cpp @@ -0,0 +1,50 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Spacer); + +ewol::widget::Spacer::Spacer() : + propertyColor(this, "color", + etk::color::none, + "background of the spacer", + &ewol::widget::Spacer::onChangePropertyColor) { + addObjectType("ewol::widget::Spacer"); + propertyMinSize.setDirectCheck(gale::Dimension(vec2(10,10))); + propertyCanFocus.setDirectCheck(true); +} + +ewol::widget::Spacer::~Spacer() { + +} + +void ewol::widget::Spacer::onDraw() { + m_draw.draw(); +} + +#define BORDER_SIZE_TMP (4) +void ewol::widget::Spacer::onRegenerateDisplay() { + if (false == needRedraw()) { + return; + } + m_draw.clear(); + + if (propertyColor->a() == 0) { + return; + } + m_draw.setColor(propertyColor); + m_draw.setPos(vec3(0, 0, 0) ); + m_draw.rectangleWidth(vec3(m_size.x(), m_size.y(),0) ); +} + +void ewol::widget::Spacer::onChangePropertyColor() { + markToRedraw(); +} + diff --git a/src/org/atriasoft/ewol/widget/Spacer.java b/src/org/atriasoft/ewol/widget/Spacer.java new file mode 100644 index 0000000..9c6cbc7 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Spacer.java @@ -0,0 +1,50 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Spacer; + using SpacerShared = ememory::SharedPtr; + using SpacerWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Spacer : public ewol::Widget { + public: // properties: + eproperty::Value> propertyColor; //!< Background color + protected: + /** + * @brief Main constructer + */ + Spacer(); + public: + DECLARE_WIDGET_FACTORY(Spacer, "Spacer"); + /** + * @brief Main destructer + */ + virtual ~Spacer(); + private: + ewol::compositing::Drawing m_draw; //!< Compositing drawing element + public: + ewol::WidgetShared getWidgetAtPos(const vec2& _pos) override { + return null; + }; + void onRegenerateDisplay() override; + void onDraw() override; + protected: + virtual void onChangePropertyColor(); + }; + } +} + diff --git a/src/org/atriasoft/ewol/widget/Spin.cpp b/src/org/atriasoft/ewol/widget/Spin.cpp new file mode 100644 index 0000000..a0abde2 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Spin.cpp @@ -0,0 +1,106 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#include +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Spin); + +ewol::widget::Spin::Spin() : + signalValue(this, "value", + "Spin value change"), + signalValueDouble(this, "valueDouble", + "Spin value change value in 'double'"), + propertyValue(this, "value", + 0, + "Value of the Spin", + &ewol::widget::Spin::onChangePropertyValue), + propertyMin(this, "min", + -9999999999, + "Minimum value of the spin", + &ewol::widget::Spin::onChangePropertyMin), + propertyMax(this, "max", + 9999999999, + "Maximum value of the spin", + &ewol::widget::Spin::onChangePropertyMax), + propertyIncrement(this, "increment", + 1, + "Increment value at each button event or keybord event", + &ewol::widget::Spin::onChangePropertyIncrement), + propertyMantis(this, "mantis", + 0, + "fix-point mantis", + &ewol::widget::Spin::onChangePropertyMantis) { + addObjectType("ewol::widget::Spin"); + propertyShape.setDirectCheck(etk::Uri("THEME_GUI:///Spin.json?lib=ewol")); +} + +ewol::widget::Spin::~Spin() { + +} + +void ewol::widget::Spin::onChangePropertyValue() { + markToRedraw(); + if (m_widgetEntry == null) { + EWOL_ERROR("Can not acces at entry ..."); + return; + } + checkValue(*propertyValue); +} + +void ewol::widget::Spin::onChangePropertyMin() { + checkValue(*propertyValue); +} + +void ewol::widget::Spin::onChangePropertyMax() { + checkValue(*propertyValue); +} + +void ewol::widget::Spin::onChangePropertyIncrement() { + +} + +void ewol::widget::Spin::onChangePropertyMantis() { + +} + +void ewol::widget::Spin::updateGui() { + EWOL_WARNING("updateGui [START]"); + ewol::widget::SpinBase::updateGui(); + + if ( m_widgetEntry != null + && m_connectionEntry.isConnected() == false) { + + } + if ( m_widgetButtonUp != null + && m_connectionButtonUp.isConnected() == false) { + m_connectionButtonUp = m_widgetButtonUp->signalPressed.connect(this, &ewol::widget::Spin::onCallbackUp); + } + if ( m_widgetButtonDown != null + && m_connectionButtonDown.isConnected() == false) { + m_connectionButtonDown = m_widgetButtonDown->signalPressed.connect(this, &ewol::widget::Spin::onCallbackDown); + } + EWOL_WARNING("updateGui [STOP]"); +} + +void ewol::widget::Spin::checkValue(int64_t _value) { + _value = etk::avg(propertyMin.get(), _value, propertyMax.get()); + propertyValue.setDirect(_value); + m_widgetEntry->propertyValue.set(etk::toString(_value)); +} + +void ewol::widget::Spin::onCallbackUp() { + int64_t value = propertyValue.get() + propertyIncrement.get(); + checkValue(value); +} + +void ewol::widget::Spin::onCallbackDown() { + int64_t value = propertyValue.get() - propertyIncrement.get(); + checkValue(value); +} diff --git a/src/org/atriasoft/ewol/widget/Spin.java b/src/org/atriasoft/ewol/widget/Spin.java new file mode 100644 index 0000000..5fbe49e --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Spin.java @@ -0,0 +1,63 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include + +namespace ewol { + namespace widget { + class Spin; + using SpinShared = ememory::SharedPtr; + using SpinWeak = ememory::WeakPtr; + /** + * @brief a composed Spin is a Spin with an inside composed with the specify XML element + * ==> this permit to generate standard element simple + */ + class Spin : public ewol::widget::SpinBase { + public: + // Event list of properties + esignal::Signal signalValue; + esignal::Signal signalValueDouble; + public: + eproperty::Value propertyValue; //!< Current value of the Spin. + eproperty::Value propertyMin; //!< Minimum value + eproperty::Value propertyMax; //!< Maximum value + eproperty::Value propertyIncrement; //!< Increment value + eproperty::Value propertyMantis; //!< number of value under '.' value + protected: + /** + * @brief Constructor + * @param[in] _mode mode to display the spin + * @param[in] _shaperName Shaper file properties + */ + Spin(); + public: + DECLARE_WIDGET_FACTORY(Spin, "Spin"); + /** + * @brief Destructor + */ + virtual ~Spin(); + protected: + virtual void checkValue(int64_t _value); + virtual void updateGui(); + protected: + void onCallbackUp(); + void onCallbackDown(); + protected: + esignal::Connection m_connectionEntry; + esignal::Connection m_connectionButtonUp; + esignal::Connection m_connectionButtonDown; + protected: + virtual void onChangePropertyValue(); + virtual void onChangePropertyMin(); + virtual void onChangePropertyMax(); + virtual void onChangePropertyIncrement(); + virtual void onChangePropertyMantis(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/TreeView.cpp b/src/org/atriasoft/ewol/widget/TreeView.cpp new file mode 100644 index 0000000..0e9aee8 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/TreeView.cpp @@ -0,0 +1,186 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::TreeView); + +ewol::widget::TreeView::TreeView(): + ewol::widget::List(), + propertyOffsetTreeView(this, "offsetTreeView", + 15, + "Offset indentation for each node", + &ewol::widget::TreeView::onChangePropertyOffsetTreeView), + propertyIconTreeViewSize(this, "iconTreeViewSize", + 20, + "Size of the icon for treeView", + &ewol::widget::TreeView::onChangePropertyOffsetTreeView), + propertyTextIsDecorated(this, "textIsDecorated", + true, + "Text is draw as decorated mode", + &ewol::widget::TreeView::onChangePropertyTextDecorated) { + addObjectType("ewol::widget::TreeView"); +} + +void ewol::widget::TreeView::init() { + ewol::widget::List::init(); + propertyFill.set(bvec2(true,false)); + addComposeElemnent("image_ChevronRight", ememory::makeShared("THEME_GUI:///ChevronRight.svg?lib=ewol")); + addComposeElemnent("image_ChevronMore", ememory::makeShared("THEME_GUI:///ChevronMore.svg?lib=ewol")); +} + +ewol::widget::TreeView::~TreeView() { + +} + +vec2 ewol::widget::TreeView::calculateElementSize(const ivec2& _pos) { + auto tmpText = ememory::staticPointerCast(getComposeElemnent("text")); + etk::String myTextToWrite = getData(ListRole::Text, _pos).getSafeString(); + float_t treeOffset = 0; + if (_pos.x() == 0) { + treeOffset += getData(ListRole::DistanceToRoot, _pos).getSafeNumber() * propertyOffsetTreeView.get(); + #if 0 + bool haveChild = getData(ListRole::HaveChild, _pos).getSafeBoolean(); + if (haveChild == true) { + treeOffset += propertyOffsetTreeView.get(); + } + #else + treeOffset += propertyOffsetTreeView.get(); + #endif + } + etk::String iconName; + float_t iconSize = 0; + if (_pos.x() == 0) { + iconName = getData(ListRole::Icon, _pos).getSafeString(); + if (iconName != "") { + iconSize += propertyIconTreeViewSize.get(); + } + } + vec3 textSize; + if (propertyTextIsDecorated.get() == true) { + textSize = tmpText->calculateSizeDecorated(myTextToWrite); + } else { + textSize = tmpText->calculateSize(myTextToWrite); + } + ivec2 count = getMatrixSize(); + return vec2(textSize.x() + treeOffset + iconSize, + etk::max(textSize.y(), iconSize) + m_paddingSizeY*2 + ); +} + +void ewol::widget::TreeView::drawElement(const ivec2& _pos, const vec2& _start, const vec2& _size) { + vec2 posStart = _start; + etk::String iconName; + etk::Color<> fg = getData(ListRole::FgColor, _pos).getSafeColor(); + if (_pos.x() == 0) { + auto value = getData(ListRole::DistanceToRoot, _pos); + if (value.isNumber() == true) { + posStart.setX(posStart.x() + value.getSafeNumber() * propertyOffsetTreeView.get()); + } + iconName = getData(ListRole::Icon, _pos).getSafeString(); + bool haveChild = getData(ListRole::HaveChild, _pos).getSafeBoolean(); + if (haveChild == true) { + ememory::SharedPtr tmpImage = null; + if ( getData(ListRole::IsExpand, _pos).getSafeBoolean() == false) { + tmpImage = ememory::staticPointerCast(getComposeElemnent("image_ChevronRight")); + } else { + tmpImage = ememory::staticPointerCast(getComposeElemnent("image_ChevronMore")); + } + if (tmpImage != null) { + tmpImage->setColor(fg); + tmpImage->setPos(posStart); + tmpImage->print(vec2(propertyIconTreeViewSize.get(), propertyIconTreeViewSize.get())); + } + } + // move right + posStart.setX(posStart.x() + propertyIconTreeViewSize.get()); + } + + etk::String myTextToWrite = getData(ListRole::Text, _pos).getSafeString(); + auto backgroundVariant = getData(ListRole::BgColor, _pos); + if (backgroundVariant.isColor() == true) { + etk::Color<> bg = backgroundVariant.getColor(); + auto BGOObjects = ememory::staticPointerCast(getComposeElemnent("drawing")); + if (BGOObjects != null) { + BGOObjects->setColor(bg); + BGOObjects->setPos(_start); + BGOObjects->rectangleWidth(_size); + } + } + posStart += vec2(m_paddingSizeX, m_paddingSizeY); + if (iconName != "") { + auto tmpImage = ememory::staticPointerCast(getComposeElemnent(iconName)); + if (tmpImage != null) { + tmpImage->setColor(fg); + tmpImage->setPos(posStart); + tmpImage->print(vec2(propertyIconTreeViewSize.get(), propertyIconTreeViewSize.get())); + } else { + EWOL_ERROR("can not get : " << iconName ); + } + // move right + posStart.setX(posStart.x() + propertyIconTreeViewSize.get()); + } + if (myTextToWrite != "") { + auto tmpText = ememory::staticPointerCast(getComposeElemnent("text")); + if (tmpText != null) { + tmpText->setColor(fg); + tmpText->setPos(posStart); + if (propertyTextIsDecorated.get() == true) { + tmpText->printDecorated(myTextToWrite); + } else { + tmpText->print(myTextToWrite); + } + } + } +} + +void ewol::widget::TreeView::onChangePropertyTextDecorated() { + markToRedraw(); +} + +void ewol::widget::TreeView::onChangePropertyOffsetTreeView() { + markToRedraw(); +} + +bool ewol::widget::TreeView::onItemEvent(const ewol::event::Input& _event, const ivec2& _pos, const vec2& _mousePosition) { + if (_event.getStatus() != gale::key::status::pressSingle) { + return false; + } + if (_event.getId() != 1) { + return false; + } + if (_pos.x() != 0) { + return false; + } + //EWOL_INFO("event: " << _event); + vec2 posStart = vec2(0,0); + bool haveChild = getData(ListRole::HaveChild, _pos).getSafeBoolean(); + if (haveChild == false) { + return false; + } + auto value = getData(ListRole::DistanceToRoot, _pos); + if (value.isNumber() == true) { + posStart.setX(posStart.x() + value.getSafeNumber() * propertyOffsetTreeView.get()); + } + // Inverse the display of Y + EWOL_VERBOSE("check: " << vec2(_mousePosition.x(), m_listSizeY[_pos.y()] - _mousePosition.y()) + << " in " << posStart + << " -> " << (posStart+vec2(propertyIconTreeViewSize.get(),propertyIconTreeViewSize.get()))); + if ( _mousePosition.x() >= posStart.x() + && _mousePosition.x() <= posStart.x()+propertyIconTreeViewSize.get() + && m_listSizeY[_pos.y()] - _mousePosition.y() >= posStart.y() + && m_listSizeY[_pos.y()] - _mousePosition.y() <= propertyIconTreeViewSize.get() ) { + onItemExpandEvent(_pos); + return true; + } + return false; +} \ No newline at end of file diff --git a/src/org/atriasoft/ewol/widget/TreeView.java b/src/org/atriasoft/ewol/widget/TreeView.java new file mode 100644 index 0000000..d6872f6 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/TreeView.java @@ -0,0 +1,60 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class TreeView; + using TreeViewShared = ememory::SharedPtr; + using TreeViewWeak = ememory::WeakPtr; + + /** + * @ingroup ewolWidgetGroup + */ + class TreeView : public ewol::widget::List { + public: // signals + public: // properties + eproperty::Value propertyOffsetTreeView; //!< indentation betwwen every new element. + eproperty::Value propertyIconTreeViewSize; //!< Size of the icon. + eproperty::Value propertyTextIsDecorated; //!< Size of the icon. + protected: + TreeView(); + void init() override; + public: + virtual ~TreeView(); + protected: + /** + * @brief Calculate an element size to extimate the render size. + * @note Does not generate the with the same size. + * @param[in] _pos Position of colomn and Raw of the element. + * @return The estimate size of the element. + */ + vec2 calculateElementSize(const ivec2& _pos) override; + /** + * @brief Draw an element in the specific size and position. + * @param[in] _pos Position of colomn and Raw of the element. + * @param[in] _start Start display position. + * @param[in] _size Render raw size + * @return The estimate size of the element. + */ + void drawElement(const ivec2& _pos, const vec2& _start, const vec2& _size) override; + protected: + virtual void onChangePropertyOffsetTreeView(); + virtual void onChangePropertyTextDecorated(); + + bool onItemEvent(const ewol::event::Input& _event, const ivec2& _pos, const vec2& _mousePosition) override; + virtual void onItemExpandEvent(const ivec2& _pos) { }; + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/WSlider.cpp b/src/org/atriasoft/ewol/widget/WSlider.cpp new file mode 100644 index 0000000..be94b99 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/WSlider.cpp @@ -0,0 +1,353 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include + +#include +ETK_DECLARE_TYPE(enum ewol::widget::WSlider::sladingMode); +ETK_DECLARE_TYPE(ewol::widget::WSlider); + +static const char* l_listsladingMode[ewol::widget::WSlider::sladingTransition_count] = { + "transition vertical", + "transition horisantal" +}; + +etk::Stream& operator <<(etk::Stream& _os, const enum ewol::widget::WSlider::sladingMode _obj) { + _os << l_listsladingMode[_obj]; + return _os; +} + +ewol::widget::WSlider::WSlider() : + signalStartSlide(this, "start", ""), + signalStopSlide(this, "stop", ""), + propertyTransitionSpeed(this, "speed", + 1.0f, 0.0f, 200.0f, + "Transition speed of the slider"), + propertyTransitionMode(this, "mode", + sladingTransitionHori, + "Transition mode of the slider", + &ewol::widget::WSlider::onChangePropertyTransitionMode), + propertySelectWidget(this, "select", + "", + "Select the requested widget to display", + &ewol::widget::WSlider::onChangePropertySelectWidget), + m_windowsSources(0), + m_windowsDestination(0), + m_windowsRequested(-1), + m_slidingProgress(1.0f) { + addObjectType("ewol::widget::WSlider"); + propertyTransitionMode.add(sladingTransitionVert, "vert"); + propertyTransitionMode.add(sladingTransitionHori, "hori"); +} + +ewol::widget::WSlider::~WSlider() { + +} + + +void ewol::widget::WSlider::onChangeSize() { + ewol::widget::ContainerN::onChangeSize(); + if (m_windowsDestination == m_windowsSources) { + auto it = m_subWidget.begin(); + it+= m_windowsDestination; + if ( it != m_subWidget.end() + && *it != null) { + (*it)->setOrigin(m_origin+m_offset); + (*it)->setSize(m_size); + (*it)->onChangeSize(); + } + } else { + float factor = -1.0f; + if (m_windowsSources < m_windowsDestination) { + factor = 1.0f; + } + auto it = m_subWidget.begin(); + it += m_windowsSources; + if ( it != m_subWidget.end() + && *it != null) { + if (*propertyTransitionMode == sladingTransitionHori) { + (*it)->setOrigin( vec2(m_origin.x() + factor*(m_size.x()*m_slidingProgress), + m_origin.y()) + + m_offset); + } else { + (*it)->setOrigin( vec2(m_origin.x(), + m_origin.y() + factor*(m_size.y()*m_slidingProgress)) + + m_offset); + } + (*it)->setSize(m_size); + (*it)->onChangeSize(); + } + it = m_subWidget.begin(); + it += m_windowsDestination; + if ( it != m_subWidget.end() + && *it != null) { + if (*propertyTransitionMode == sladingTransitionHori) { + (*it)->setOrigin( vec2(m_origin.x() + factor*(m_size.x()*m_slidingProgress - m_size.x()), + m_origin.y()) + + m_offset); + } else { + (*it)->setOrigin( vec2(m_origin.x(), + m_origin.y() + factor*(m_size.y()*m_slidingProgress - m_size.y())) + + m_offset); + } + (*it)->setSize(m_size); + (*it)->onChangeSize(); + } + } + markToRedraw(); +} + +void ewol::widget::WSlider::subWidgetSelectSetVectorId(int32_t _id) { + if (_id<0) { + EWOL_ERROR("Can not change to a widget not present : vectID=" << _id); + return; + } + if (_id != m_windowsDestination) { + m_windowsRequested = _id; + signalStartSlide.emit(); + m_PCH = getObjectManager().periodicCall.connect(this, &ewol::widget::WSlider::periodicCall); + markToRedraw(); + } +} + +void ewol::widget::WSlider::subWidgetSelectSet(int32_t _id) { + size_t elementID = 0; + // search element in the list : + for (auto &it : m_subWidget) { + elementID ++; + if (it != null) { + if (it->getId() == _id) { + if (it->propertyName.get() != "") { + // change the internal event parameter (in case...) ==> no event generation + propertySelectWidget.setDirect(it->propertyName.get()); + } else { + propertySelectWidget.setDirect(""); + } + break; + } + } + } + if (elementID < m_subWidget.size()) { + subWidgetSelectSetVectorId(elementID); + } else { + subWidgetSelectSetVectorId(-1); + // change the internal event parameter (in case...) ==> no event generation + propertySelectWidget.setDirect(""); + } +} + +void ewol::widget::WSlider::subWidgetSelectSet(const ewol::WidgetShared& _widgetPointer) { + if (_widgetPointer == null) { + EWOL_ERROR("Can not change to a widget null"); + return; + } + int32_t iii = 0; + for (auto &it : m_subWidget) { + if ( it != null + && it == _widgetPointer) { + subWidgetSelectSetVectorId(iii); + if (_widgetPointer->propertyName.get() != "") { + // change the internal event parameter (in case...) ==> no event generation + propertySelectWidget.setDirect(_widgetPointer->propertyName.get()); + } else { + propertySelectWidget.setDirect(""); + } + return; + } + iii++; + } + EWOL_ERROR("Can not change to a widget not present"); +} + +void ewol::widget::WSlider::subWidgetSelectSet(const etk::String& _widgetName) { + if (_widgetName == "") { + EWOL_ERROR("Can not change to a widget with no name (input)"); + return; + } + EWOL_VERBOSE("Select a new sub-widget to dosplay : '" << _widgetName << "'"); + int32_t iii = 0; + for (auto &it : m_subWidget) { + if ( it != null + && it->propertyName.get() == _widgetName) { + subWidgetSelectSetVectorId(iii); + // change the internal event parameter (in case...) ==> no event generation + propertySelectWidget.setDirect(_widgetName); + return; + } + iii++; + } + EWOL_ERROR("Can not change to a widget not present"); +} +void ewol::widget::WSlider::periodicCall(const ewol::event::Time& _event) { + EWOL_ERROR("Periodic: " << m_slidingProgress << "/1.0 " << m_windowsSources << " ==> " << m_windowsDestination << " " << _event); + if (m_slidingProgress >= 1.0) { + m_windowsSources = m_windowsDestination; + if( m_windowsRequested != -1 + && m_windowsRequested != m_windowsSources) { + m_windowsDestination = m_windowsRequested; + m_slidingProgress = 0.0; + } else { + // end of periodic : + m_PCH.disconnect(); + signalStopSlide.emit(); + } + m_windowsRequested = -1; + } + + if (m_slidingProgress < 1.0) { + if ( m_windowsRequested != -1 + && m_slidingProgress<0.5 ) { + // invert sources with destination + int32_t tmppp = m_windowsDestination; + m_windowsDestination = m_windowsSources; + m_windowsSources = tmppp; + m_slidingProgress = 1.0f - m_slidingProgress; + if (m_windowsRequested == m_windowsDestination) { + m_windowsRequested = -1; + } + } + m_slidingProgress += _event.getDeltaCall()/propertyTransitionSpeed; + m_slidingProgress = etk::avg(0.0f, m_slidingProgress, 1.0f); + } + onChangeSize(); +} + +void ewol::widget::WSlider::systemDraw(const ewol::DrawProperty& _displayProp) { + if (*propertyHide == true){ + // widget is hidden ... + return; + } + // note : do not call the widget container == > overload this one ... + ewol::Widget::systemDraw(_displayProp); + + // subwidget draw + ewol::DrawProperty prop = _displayProp; + prop.limit(m_origin, m_size); + + if (m_windowsDestination == m_windowsSources) { + //EWOL_DEBUG("Draw : " << m_windowsDestination); + auto it = m_subWidget.begin(); + it += m_windowsDestination; + if ( it != m_subWidget.end() + && *it != null) { + //EWOL_INFO("Draw : [" << propertyName << "] t=" << getObjectType() << "o=" << m_origin << " s=" << m_size); + (*it)->systemDraw(prop); + } + } else { + //EWOL_DEBUG("Draw : " << m_windowsSources << "=>" << m_windowsDestination << "progress=" << ((float)m_slidingProgress/1000.) ); + // draw Sources : + auto it = m_subWidget.begin(); + it += m_windowsSources; + if ( it != m_subWidget.end() + && *it != null) { + (*it)->systemDraw(prop); + } + // draw Destination : + it = m_subWidget.begin(); + it += m_windowsDestination; + if ( it != m_subWidget.end() + && *it != null) { + (*it)->systemDraw(prop); + } + } +} + +void ewol::widget::WSlider::onRegenerateDisplay() { + if (m_windowsDestination == m_windowsSources) { + auto it = m_subWidget.begin(); + it += m_windowsDestination; + if ( it != m_subWidget.end() + && *it != null) { + (*it)->onRegenerateDisplay(); + } + } else { + auto it = m_subWidget.begin(); + it += m_windowsSources; + if ( it != m_subWidget.end() + && *it != null) { + (*it)->onRegenerateDisplay(); + } + it = m_subWidget.begin(); + it += m_windowsDestination; + if ( it != m_subWidget.end() + && *it != null) { + (*it)->onRegenerateDisplay(); + } + } +} + +void ewol::widget::WSlider::onChangePropertySelectWidget() { + if (propertySelectWidget.get() != "") { + EWOL_ERROR("SELECT new widget: " << propertySelectWidget.get()); + subWidgetSelectSet(*propertySelectWidget); + } +} + +void ewol::widget::WSlider::onChangePropertyTransitionMode() { + markToRedraw(); +} + + +ewol::WidgetShared ewol::widget::WSlider::getWidgetAtPos(const vec2& _pos) { + if (*propertyHide == true) { + return null; + } + if (m_windowsDestination == m_windowsSources) { + auto it = m_subWidget.begin(); + it += m_windowsDestination; + if ( it != m_subWidget.end() + && *it != null) { + vec2 tmpSize = (*it)->getSize(); + vec2 tmpOrigin = (*it)->getOrigin(); + if( (tmpOrigin.x() <= _pos.x() && tmpOrigin.x() + tmpSize.x() >= _pos.x()) + && (tmpOrigin.y() <= _pos.y() && tmpOrigin.y() + tmpSize.y() >= _pos.y()) ) + { + ewol::WidgetShared tmpWidget = (*it)->getWidgetAtPos(_pos); + if (tmpWidget != null) { + return tmpWidget; + } + return null; + } + } + } else { + auto it = m_subWidget.begin(); + it += m_windowsDestination; + if ( it != m_subWidget.end() + && *it != null) { + vec2 tmpSize = (*it)->getSize(); + vec2 tmpOrigin = (*it)->getOrigin(); + if( (tmpOrigin.x() <= _pos.x() && tmpOrigin.x() + tmpSize.x() >= _pos.x()) + && (tmpOrigin.y() <= _pos.y() && tmpOrigin.y() + tmpSize.y() >= _pos.y()) ) + { + ewol::WidgetShared tmpWidget = (*it)->getWidgetAtPos(_pos); + if (tmpWidget != null) { + return tmpWidget; + } + return null; + } + } + it = m_subWidget.begin(); + it += m_windowsSources; + if ( it != m_subWidget.end() + && *it != null) { + vec2 tmpSize = (*it)->getSize(); + vec2 tmpOrigin = (*it)->getOrigin(); + if( (tmpOrigin.x() <= _pos.x() && tmpOrigin.x() + tmpSize.x() >= _pos.x()) + && (tmpOrigin.y() <= _pos.y() && tmpOrigin.y() + tmpSize.y() >= _pos.y()) ) + { + ewol::WidgetShared tmpWidget = (*it)->getWidgetAtPos(_pos); + if (tmpWidget != null) { + return tmpWidget; + } + return null; + } + } + } + return null; +} + diff --git a/src/org/atriasoft/ewol/widget/WSlider.java b/src/org/atriasoft/ewol/widget/WSlider.java new file mode 100644 index 0000000..e64b10b --- /dev/null +++ b/src/org/atriasoft/ewol/widget/WSlider.java @@ -0,0 +1,87 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class WSlider; + using WSliderShared = ememory::SharedPtr; + using WSliderWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class WSlider :public ewol::widget::ContainerN { + public: + enum sladingMode { + sladingTransitionVert, + sladingTransitionHori, + sladingTransition_count, + }; + public: // signals: + esignal::Signal<> signalStartSlide; + esignal::Signal<> signalStopSlide; + public: // properties: + eproperty::Range propertyTransitionSpeed; //!< speed of the transition (default 1 == > 1s) + eproperty::List propertyTransitionMode; //!< mode to slide the widgets + eproperty::Value propertySelectWidget; //!< current select configuration + protected: + WSlider(); + public: + DECLARE_WIDGET_FACTORY(WSlider, "WSlider"); + virtual ~WSlider(); + private: + int32_t m_windowsSources; //!< widget source viewed + int32_t m_windowsDestination; //!< widget destinated viewed + int32_t m_windowsRequested; //!< widget destination requested when change in modification in progress + float m_slidingProgress; //!< ratio progression of a sliding + protected: + /** + * @brief Generate the move on the specific vector ID (This is not a public acces, because the vector can have some null pointer inside ...) + * @param[in] _id Id in the vector + */ + void subWidgetSelectSetVectorId(int32_t _id); + public: + /** + * @brief Select a new subwidget to display + * @param[in] _id Id of the subwidget requested + */ + void subWidgetSelectSet(int32_t _id); + /** + * @brief Select a new subwidget to display + * @param[in] _widgetPointer Pointer on the widget selected (must be added before) + */ + void subWidgetSelectSet(const ewol::WidgetShared& _widgetPointer); + /** + * @brief Select a new subwidget to display + * @param[in] _widgetName Name of the subwidget name + */ + void subWidgetSelectSet(const etk::String& _widgetName); + public: + void onChangeSize() override; + void systemDraw(const ewol::DrawProperty& _displayProp) override; + void onRegenerateDisplay() override; + ewol::WidgetShared getWidgetAtPos(const vec2& _pos) override; + protected: + esignal::Connection m_PCH; //!< Periodic call handle to remove it when needed + /** + * @brief Periodic call to update grapgic display + * @param[in] _event Time generic event + */ + void periodicCall(const ewol::event::Time& _event); + protected: + virtual void onChangePropertySelectWidget(); + virtual void onChangePropertyTransitionMode(); + }; + } + etk::Stream& operator <<(etk::Stream& _os, const enum ewol::widget::WSlider::sladingMode _obj); +} + diff --git a/src/org/atriasoft/ewol/widget/Widget.cpp b/src/org/atriasoft/ewol/widget/Widget.cpp new file mode 100644 index 0000000..c690b54 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Widget.cpp @@ -0,0 +1,636 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::Widget); + +ewol::Widget::Widget() : + propertyMinSize(this, "min-size", + gale::Dimension(vec2(0,0),gale::distance::pixel), + "User minimum size", + &ewol::Widget::onChangePropertyMinSize), + propertyMaxSize(this, "max-size", + gale::Dimension(vec2(ULTIMATE_MAX_SIZE,ULTIMATE_MAX_SIZE),gale::distance::pixel), + "User maximum size", + &ewol::Widget::onChangePropertyMaxSize), + propertyExpand(this, "expand", + bvec2(false,false), + "Request the widget Expand size wile space is available", + &ewol::Widget::onChangePropertyExpand), + propertyFill(this, "fill", + bvec2(true,true), + "Fill the widget available size", + &ewol::Widget::onChangePropertyFill), + propertyHide(this, "hide", + false, + "The widget start hided", + &ewol::Widget::onChangePropertyHide), + propertyGravity(this, "gravity", + ewol::gravity_buttomLeft, + "Gravity orientation", + &ewol::Widget::onChangePropertyGravity), + // TODO : je pense que c'est une erreur, c'est surement un event to get the cocus ... + propertyCanFocus(this, "focus", + false, + "enable the widget to have the focus capacity", + &ewol::Widget::onChangePropertyCanFocus), + m_size(10,10), + m_minSize(0,0), + m_maxSize(vec2(ULTIMATE_MAX_SIZE,ULTIMATE_MAX_SIZE)), + m_offset(0,0), + m_zoom(1.0f), + m_origin(0,0), + m_hasFocus(false), + m_limitMouseEvent(3), + m_allowRepeatKeyboardEvent(true), + signalShortcut(this, "shortcut", ""), + m_needRegenerateDisplay(true), + m_grabCursor(false), + m_cursorDisplay(gale::context::cursor::arrow){ + addObjectType("ewol::Widget"); + + // TODO : Set a static interface for list ==> this methode create a multiple allocation + propertyGravity.add(ewol::gravity_center, "center"); + propertyGravity.add(ewol::gravity_topLeft, "top-left"); + propertyGravity.add(ewol::gravity_top, "top"); + propertyGravity.add(ewol::gravity_topRight, "top-right"); + propertyGravity.add(ewol::gravity_right, "right"); + propertyGravity.add(ewol::gravity_buttomRight, "buttom-right"); + propertyGravity.add(ewol::gravity_buttom, "buttom"); + propertyGravity.add(ewol::gravity_buttomLeft, "buttom-left"); + propertyGravity.add(ewol::gravity_left, "left"); +} + + +void ewol::Widget::onChangeSize() { + EWOL_VERBOSE("[" << getId() << "] {" << getObjectType() << "} update size : " << m_size); + markToRedraw(); +} + +bool ewol::Widget::setFocus() { + EWOL_VERBOSE("set focus (start) *propertyCanFocus=" << *propertyCanFocus << " m_hasFocus=" << m_hasFocus); + if (*propertyCanFocus == true) { + if (m_hasFocus == false) { + m_hasFocus = true; + onGetFocus(); + } + EWOL_VERBOSE("set focus (stop) ret true"); + return true; + } + EWOL_VERBOSE("set focus (stop) ret false"); + return false; +} + +bool ewol::Widget::rmFocus() { + if (*propertyCanFocus == true) { + if (m_hasFocus == true) { + m_hasFocus = false; + onLostFocus(); + } + return true; + } + return false; +} + +void ewol::Widget::keepFocus() { + getWidgetManager().focusKeep(ememory::dynamicPointerCast(sharedFromThis())); +} + +void ewol::Widget::setOffset(const vec2& _newVal) { + EWOL_INFO("Set offset: " << _newVal); + if (m_offset != _newVal) { + m_offset = _newVal; + markToRedraw(); + } +} + +/* + /--> _displayProp.m_windowsSize + *------------------------------------------------------* + | | + | m_size | + | / | + | *-----------------------* | + | ' ' | + | ' _displayProp.m_size ' | + | Viewport ' / ' | + | o---------'---------o ' | + | | ' | ' | + | | ' | ' | + | | ' | ' | + | | ' | ' | + | | *-----------------------* | + | | / | | + | | m_offset | | + | | | | + | o-------------------o | + | / | + | _displayProp.m_origin | + | | + *------------------------------------------------------* + / + (0,0) +*/ +void ewol::Widget::systemDraw(const ewol::DrawProperty& _displayProp) { + //EWOL_INFO("[" << getId() << "] Draw : [" << propertyName << "] t=" << getObjectType() << " o=" << m_origin << " s=" << m_size << " hide=" << propertyHide); + if (*propertyHide == true){ + // widget is hidden ... + return; + } + vec2 displayOrigin = m_origin + m_offset; + + // check if the element is displayable in the windows : + if( _displayProp.m_windowsSize.x() < m_origin.x() + || _displayProp.m_windowsSize.y() < m_origin.y() ) { + // out of the windows == > nothing to display ... + return; + } + + ewol::DrawProperty tmpSize = _displayProp; + tmpSize.limit(m_origin, m_size); + if (tmpSize.m_size.x() <= 0 || tmpSize.m_size.y() <= 0) { + return; + } + glViewport( (int32_t)tmpSize.m_origin.x(), + (int32_t)tmpSize.m_origin.y(), + (int32_t)tmpSize.m_size.x(), + (int32_t)tmpSize.m_size.y()); + // special case, when origin < display origin, we need to cut the display : + ivec2 downOffset = m_origin - tmpSize.m_origin; + downOffset.setMin(ivec2(0,0)); + + mat4 tmpTranslate = etk::matTranslate(vec3ClipInt32(vec3(-tmpSize.m_size.x()/2+m_offset.x() + downOffset.x(), + -tmpSize.m_size.y()/2+m_offset.y() + downOffset.y(), + -1.0f))); + mat4 tmpScale = etk::matScale(vec3(m_zoom, m_zoom, 1.0f)); + mat4 tmpProjection = etk::matOrtho((int32_t)(-tmpSize.m_size.x())>>1, + (int32_t)( tmpSize.m_size.x())>>1, + (int32_t)(-tmpSize.m_size.y())>>1, + (int32_t)( tmpSize.m_size.y())>>1, + (int32_t)(-1), + (int32_t)( 1)); + mat4 tmpMat = tmpProjection * tmpScale * tmpTranslate; + + gale::openGL::push(); + // set internal matrix system : + gale::openGL::setMatrix(tmpMat); + //int64_t ___startTime = ewol::getTime(); + onDraw(); + + #ifdef old_PLOP + if( (_displayProp.m_origin.x() > m_origin.x()) + || (_displayProp.m_origin.x() + _displayProp.m_size.x() < m_size.x() + m_origin.x()) ) { + // here we invert the reference of the standard openGl view because the reference in the common display is Top left and not buttom left + int32_t tmpOriginX = etk::max(_displayProp.m_origin.x(), m_origin.x()); + int32_t tmppp1 = _displayProp.m_origin.x() + _displayProp.m_size.x(); + int32_t tmppp2 = m_origin.x() + m_size.x(); + int32_t tmpclipX = etk::min(tmppp1, tmppp2) - tmpOriginX; + + int32_t tmpOriginY = etk::max(_displayProp.m_origin.y(), m_origin.y()); + tmppp1 = _displayProp.m_origin.y() + _displayProp.m_size.y(); + tmppp2 = m_origin.y() + m_size.y(); + //int32_t tmpclipY = etk::min(tmppp1, tmppp2) - tmpOriginX; + + glViewport( tmpOriginX, + tmpOriginY, + tmpclipX, + m_size.y()); + mat4 tmpTranslate = etk::matTranslate(vec3((float)(-tmpclipX/2 - (tmpOriginX-m_origin.x())), (float)(-m_size.y()/2.0), -1.0f)); + mat4 tmpScale = etk::matScale(vec3(m_zoom, m_zoom, 1)); + mat4 tmpProjection = etk::matOrtho(-tmpclipX/2, tmpclipX/2, -m_size.y()/2, m_size.y()/2, -1, 1); + mat4 tmpMat = tmpProjection * tmpScale * tmpTranslate; + // set internal matrix system : + gale::openGL::setMatrix(tmpMat); + //int64_t ___startTime = ewol::getTime(); + onDraw(); + //float ___localTime = (float)(ewol::getTime() - ___startTime) / 1000.0f; + //EWOL_DEBUG(" Widget1 : " << ___localTime << "ms "); + } else { + EWOL_DEBUG("rasta.."); + glViewport( m_origin.x(), + m_origin.y(), + m_size.x(), + m_size.y()); + mat4 tmpTranslate = etk::matTranslate(vec3(-m_size.x()/2, -m_size.y()/2, -1.0f)); + mat4 tmpScale = etk::matScale(vec3(m_zoom, m_zoom, 1.0f)); + mat4 tmpProjection = etk::matOrtho(-m_size.x()/2, m_size.x()/2, -m_size.y()/2, m_size.y()/2, -1, 1); + mat4 tmpMat = tmpProjection * tmpScale * tmpTranslate; + // set internal matrix system : + gale::openGL::setMatrix(tmpMat); + //int64_t ___startTime = ewol::getTime(); + onDraw(); + //float ___localTime = (float)(ewol::getTime() - ___startTime) / 1000.0f; + //EWOL_DEBUG(" Widget2 : " << ___localTime << "ms "); + } + #endif + gale::openGL::pop(); + return; +} + +void ewol::Widget::markToRedraw() { + if (m_needRegenerateDisplay == true) { + return; + } + m_needRegenerateDisplay = true; + getWidgetManager().markDrawingIsNeeded(); +} + +void ewol::Widget::setZoom(float _newVal) { + if (m_zoom == _newVal) { + return; + } + m_zoom = etk::avg(0.0000001f,_newVal,1000000.0f); + markToRedraw(); +} + +float ewol::Widget::getZoom() { + return m_zoom; +} + +void ewol::Widget::setOrigin(const vec2& _pos) { + #if DEBUG_LEVEL > 2 + if( m_origin.x() < -5000 + || m_origin.y() < -5000) { + EWOL_WARNING("[" << getId() << "] set origin < 5000 : " << m_origin); + } + #endif + m_origin = _pos; +} + +vec2 ewol::Widget::getOrigin() { + return m_origin; +} + +vec2 ewol::Widget::relativePosition(const vec2& _pos) { + return _pos - m_origin; +} + +void ewol::Widget::calculateMinMaxSize() { + m_minSize = propertyMinSize->getPixel(); + //EWOL_ERROR("[" << getId() << "] convert in min size : " << propertyMinSize << " out=" << m_minSize); + m_maxSize = propertyMaxSize->getPixel(); + markToRedraw(); +} + +vec2 ewol::Widget::getCalculateMinSize() { + if (*propertyHide == false) { + return m_minSize; + } + return vec2(0,0); +} + +vec2 ewol::Widget::getCalculateMaxSize() { + if (*propertyHide == false) { + return m_maxSize; + } + return vec2(ULTIMATE_MAX_SIZE,ULTIMATE_MAX_SIZE); +} + +void ewol::Widget::setNoMinSize() { + propertyMinSize.set(gale::Dimension(vec2(0,0),gale::distance::pixel)); +} + +void ewol::Widget::checkMinSize() { + vec2 pixelSize = propertyMinSize->getPixel(); + m_minSize.setX(etk::max(m_minSize.x(), pixelSize.x())); + m_minSize.setY(etk::max(m_minSize.y(), pixelSize.y())); +} + +void ewol::Widget::setNoMaxSize() { + propertyMaxSize.set(gale::Dimension(vec2(ULTIMATE_MAX_SIZE,ULTIMATE_MAX_SIZE),gale::distance::pixel)); +} + +void ewol::Widget::checkMaxSize() { + vec2 pixelSize = propertyMaxSize->getPixel(); + m_maxSize.setX(etk::min(m_maxSize.x(), pixelSize.x())); + m_maxSize.setY(etk::min(m_maxSize.y(), pixelSize.y())); +} + +vec2 ewol::Widget::getSize() { + if (*propertyHide == false) { + return m_size; + } + return vec2(0,0); +} + +bvec2 ewol::Widget::canExpand() { + if (*propertyHide == false) { + return *propertyExpand; + } + return bvec2(false,false); +} + +const bvec2& ewol::Widget::canFill() { + return *propertyFill; +} + +// ---------------------------------------------------------------------------------------------------------------- +// -- Shortcut : management of the shortcut +// ---------------------------------------------------------------------------------------------------------------- + +void ewol::Widget::shortCutAdd(const etk::String& _descriptiveString, const etk::String& _message) { + if (_descriptiveString.size() == 0) { + EWOL_ERROR("try to add shortcut with no descriptive string ..."); + return; + } + EventShortCut tmpElement; + if (_message.size() == 0) { + tmpElement.message = _descriptiveString; + } else { + tmpElement.message = _message; + } + // parsing of the string: + //"ctrl+shift+alt+meta+s" + if(_descriptiveString.find("ctrl") != etk::String::npos) { + tmpElement.specialKey.setCtrlLeft(true); + } + if(_descriptiveString.find("shift") != etk::String::npos) { + tmpElement.specialKey.setShiftLeft(true); + } + if(_descriptiveString.find("alt") != etk::String::npos) { + tmpElement.specialKey.setAltLeft(true); + } + if(_descriptiveString.find("meta") != etk::String::npos) { + tmpElement.specialKey.setMetaLeft(true); + } + if(_descriptiveString.find("F12") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f12; + } else if(_descriptiveString.find("F11") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f11; + } else if(_descriptiveString.find("F10") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f10; + } else if(_descriptiveString.find("F9") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f9; + } else if(_descriptiveString.find("F8") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f8; + } else if(_descriptiveString.find("F7") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f7; + } else if(_descriptiveString.find("F6") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f6; + } else if(_descriptiveString.find("F5") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f5; + } else if(_descriptiveString.find("F4") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f4; + } else if(_descriptiveString.find("F3") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f3; + } else if(_descriptiveString.find("F2") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f2; + } else if(_descriptiveString.find("F1") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::f1; + } else if(_descriptiveString.find("LEFT") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::left; + } else if(_descriptiveString.find("RIGHT") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::right; + } else if(_descriptiveString.find("UP") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::up; + } else if(_descriptiveString.find("DOWN") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::down; + } else if(_descriptiveString.find("PAGE_UP") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::pageUp; + } else if(_descriptiveString.find("PAGE_DOWN") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::pageDown; + } else if(_descriptiveString.find("START") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::start; + } else if(_descriptiveString.find("END") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::end; + } else if(_descriptiveString.find("PRINT") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::print; + } else if(_descriptiveString.find("ARRET_DEFIL") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::stopDefil; + } else if(_descriptiveString.find("WAIT") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::wait; + } else if(_descriptiveString.find("INSERT") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::insert; + } else if(_descriptiveString.find("CAPLOCK") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::capLock; + } else if(_descriptiveString.find("CONTEXT_MENU") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::contextMenu; + } else if(_descriptiveString.find("NUM_LOCK") != etk::String::npos) { + tmpElement.keyboardMoveValue = gale::key::keyboard::numLock; + } else { + tmpElement.unicodeValue = _descriptiveString[_descriptiveString.size() -1]; + } + // add it on the List ... + m_localShortcut.pushBack(etk::move(tmpElement)); +} + +void ewol::Widget::shortCutRemove(const etk::String& _message) { + auto it(m_localShortcut.begin()); + while(it != m_localShortcut.end()) { + if (it->message != _message) { + ++it; + continue; + } + m_localShortcut.erase(it); + it = m_localShortcut.begin(); + } +} + +void ewol::Widget::shortCutClean() { + m_localShortcut.clear(); +} + +bool ewol::Widget::onEventShortCut(const gale::key::Special& _special, + char32_t _unicodeValue, + enum gale::key::keyboard _kbMove, + bool _isDown) { + if ( _unicodeValue >= 'A' + && _unicodeValue <= 'Z') { + _unicodeValue += 'a' - 'A'; + } + EWOL_VERBOSE("check shortcut...." << _special << " " << _unicodeValue << " " << _kbMove << " " << (_isDown?"DOWN":"UP") << " nb shortcut:" << m_localShortcut.size()); + // Remove the up event of the shortcut... + if (_isDown == false) { + for (int32_t iii=m_localShortcut.size()-1; iii >= 0; iii--) { + if (m_localShortcut[iii].isActive == false) { + continue; + } + if ( ( m_localShortcut[iii].keyboardMoveValue == gale::key::keyboard::unknow + && m_localShortcut[iii].unicodeValue == _unicodeValue) + || ( m_localShortcut[iii].keyboardMoveValue == _kbMove + && m_localShortcut[iii].unicodeValue == 0) + ) { + // In this case we grap the event in case of an error can occured ... + m_localShortcut[iii].isActive = false; + EWOL_VERBOSE("detect up of a shortcut"); + return true; + } + } + } + //EWOL_INFO("Try to find generic shortcut ..."); + for (int32_t iii=m_localShortcut.size()-1; iii >= 0; iii--) { + if ( m_localShortcut[iii].specialKey.getShift() == _special.getShift() + && m_localShortcut[iii].specialKey.getCtrl() == _special.getCtrl() + && m_localShortcut[iii].specialKey.getAlt() == _special.getAlt() + && m_localShortcut[iii].specialKey.getMeta() == _special.getMeta() + && ( ( m_localShortcut[iii].keyboardMoveValue == gale::key::keyboard::unknow + && m_localShortcut[iii].unicodeValue == _unicodeValue) + || ( m_localShortcut[iii].keyboardMoveValue == _kbMove + && m_localShortcut[iii].unicodeValue == 0) + ) + ) { + if (_isDown == true) { + m_localShortcut[iii].isActive = true; + EWOL_VERBOSE("Generate shortCut: " << m_localShortcut[iii].message); + signalShortcut.emit(m_localShortcut[iii].message); + } + return true; + } + } + return false; +} + + +void ewol::Widget::grabCursor() { + if (m_grabCursor == false) { + getContext().inputEventGrabPointer(ememory::dynamicPointerCast(sharedFromThis())); + m_grabCursor = true; + } +} + +void ewol::Widget::unGrabCursor() { + if (m_grabCursor == true) { + getContext().inputEventUnGrabPointer(); + m_grabCursor = false; + } +} + +bool ewol::Widget::getGrabStatus() { + return m_grabCursor; +} + +void ewol::Widget::setCursor(enum gale::context::cursor _newCursor) { + EWOL_DEBUG("Change Cursor in " << _newCursor); + m_cursorDisplay = _newCursor; + getContext().setCursor(m_cursorDisplay); +} + +enum gale::context::cursor ewol::Widget::getCursor() { + return m_cursorDisplay; +} + +bool ewol::Widget::loadXML(const exml::Element& _node) { + ewol::Object::loadXML(_node); + markToRedraw(); + return true; +} + +bool ewol::Widget::systemEventEntry(ewol::event::EntrySystem& _event) { + ewol::WidgetShared up = ememory::dynamicPointerCast(m_parent.lock()); + if (up != null) { + if (up->systemEventEntry(_event) == true) { + return true; + } + } + return onEventEntry(_event.m_event); +} + +bool ewol::Widget::systemEventInput(ewol::event::InputSystem& _event) { + ewol::WidgetShared up = ememory::dynamicPointerCast(m_parent.lock()); + if (up != null) { + if (up->systemEventInput(_event) == true) { + return true; + } + } + return onEventInput(_event.m_event); +} + +void ewol::Widget::onChangePropertyCanFocus() { + if (m_hasFocus == true) { + rmFocus(); + } +} + +void ewol::Widget::onChangePropertyGravity() { + markToRedraw(); + requestUpdateSize(); +} + +void ewol::Widget::onChangePropertyHide() { + markToRedraw(); + requestUpdateSize(); +} + +void ewol::Widget::onChangePropertyFill() { + markToRedraw(); + requestUpdateSize(); +} + +void ewol::Widget::onChangePropertyExpand() { + requestUpdateSize(); + markToRedraw(); +} + +void ewol::Widget::onChangePropertyMaxSize() { + vec2 pixelMin = propertyMinSize->getPixel(); + vec2 pixelMax = propertyMaxSize->getPixel(); + // check minimum & maximum compatibility : + bool error=false; + if (pixelMin.x()>pixelMax.x()) { + error=true; + } + if (pixelMin.y()>pixelMax.y()) { + error=true; + } + if (error == true) { + EWOL_ERROR("Can not set a 'min size' > 'max size' reset to maximum ..."); + propertyMaxSize.setDirect(gale::Dimension(vec2(ULTIMATE_MAX_SIZE,ULTIMATE_MAX_SIZE),gale::distance::pixel)); + } + requestUpdateSize(); +} + +void ewol::Widget::onChangePropertyMinSize() { + vec2 pixelMin = propertyMinSize->getPixel(); + vec2 pixelMax = propertyMaxSize->getPixel(); + // check minimum & maximum compatibility : + bool error=false; + if (pixelMin.x()>pixelMax.x()) { + error=true; + } + if (pixelMin.y()>pixelMax.y()) { + error=true; + } + if (error == true) { + EWOL_ERROR("Can not set a 'min size' > 'max size' set nothing ..."); + propertyMinSize.setDirect(gale::Dimension(vec2(0,0),gale::distance::pixel)); + } + requestUpdateSize(); +} + +void ewol::Widget::requestUpdateSize() { + getContext().requestUpdateSize(); +} + +ewol::widget::Manager& ewol::Widget::getWidgetManager() { + return getContext().getWidgetManager(); +} + +ewol::widget::WindowsShared ewol::Widget::getWindows() { + return getContext().getWindows(); +} + +void ewol::Widget::showKeyboard() { + getContext().keyboardShow(); +} + +void ewol::Widget::hideKeyboard() { + getContext().keyboardHide(); +} + +void ewol::Widget::drawWidgetTree(int32_t _level) { + etk::String space; + for (int32_t iii=0; iii<_level; ++iii) { + space += " "; + } + EWOL_PRINT(space << "[" << getId() << "] name='" << propertyName << "' type=" << getObjectType() << " o=" << m_origin << " s=" << m_size << " hide=" << propertyHide); +} \ No newline at end of file diff --git a/src/org/atriasoft/ewol/widget/Widget.java b/src/org/atriasoft/ewol/widget/Widget.java new file mode 100644 index 0000000..d96f860 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Widget.java @@ -0,0 +1,532 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace ewol { + class Widget; + namespace widget { + class Manager; + class Windows; + }; + using WidgetShared = ememory::SharedPtr; + using WidgetWeak = ememory::WeakPtr; +}; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ULTIMATE_MAX_SIZE (99999999) + +#define DECLARE_WIDGET_FACTORY(className, name) \ + DECLARE_FACTORY(className); \ + static void createManagerWidget(ewol::widget::Manager& _widgetManager) { \ + _widgetManager.addWidgetCreator(name, \ + []() -> ewol::WidgetShared { \ + return className::create(); \ + }, \ + [](const exml::Element& _node) -> ewol::WidgetShared { \ + return className::createXml(_node); \ + }); \ + } + +namespace ewol { + /** + * @not_in_doc + */ + // TODO: change position of this ... + class EventShortCut { + public: + etk::String message; //!< data link with the event + gale::key::Special specialKey; //!< special board key + char32_t unicodeValue; //!< 0 if not used + enum gale::key::keyboard keyboardMoveValue; //!< ewol::EVENT_KB_MOVE_TYPE_NONE if not used + bool isActive; //!< If true, we need to filter the up key of ascii element (not control) + EventShortCut() : + message(""), + specialKey(), + unicodeValue(0), + keyboardMoveValue(gale::key::keyboard::unknow), + isActive(false) { + // nothing to do + }; + virtual ~EventShortCut() { }; + }; + /** + * @brief Widget class is the main widget interface, it has some generic properties: + * :** known his parent + * :** Can be display at a special position with a special scale + * :** Can get focus + * :** Receive Event (keyboard / mouse / ...) + * + */ + class Widget : public ewol::Object { + public: // signals: + + public: // properties: + eproperty::Value propertyMinSize; //!< user define the minimum size of the widget + eproperty::Value propertyMaxSize; //!< user define the maximum size of the widget + eproperty::Value propertyExpand; //!< the widget will expand if possible + eproperty::Value propertyFill; //!< the widget will fill all the space provided by the parent. + eproperty::Value propertyHide; //!< hide a widget on the display + eproperty::List propertyGravity; //!< Gravity of the widget + eproperty::Value propertyCanFocus; //!< the focus can be done on this widget + protected: + /** + * @brief Constructor of the widget classes + * @return (no exception generated (not managed in embedded platform)) + */ + Widget(); + public: + /** + * @brief Destructor of the widget classes + */ + virtual ~Widget() = default; + // ---------------------------------------------------------------------------------------------------------------- + // -- Widget size: + // ---------------------------------------------------------------------------------------------------------------- + protected: + vec2 m_size; //!< internal: current size of the widget + vec2 m_minSize; //!< internal: minimum size of the widget + vec2 m_maxSize; //!< internal: maximum size of the widget + public: + /** + * @brief Convert the absolute position in the local Position (Relative) + * @param[in] _pos Absolute position that you request conversion. + * @return The relative position. + */ + virtual vec2 relativePosition(const vec2& _pos); + /** + * @brief Parent have set the size and the origin. The container need to update the child widget property + * @note INTERNAL EWOL SYSTEM + */ + virtual void onChangeSize(); + virtual void calculateSize() {}; + /** + * @brief get the widget size + * @return Requested size + * @note : INTERNAL EWOL SYSTEM + */ + virtual vec2 getSize(); + /** + * @brief set the widget size + * @return Requested size + * @note : INTERNAL EWOL SYSTEM Do not modify the size yourself: calculation is complex and need knowledge of around widget + */ + virtual void setSize(const vec2& _value) { + m_size = _value; + } + /** + * @brief calculate the minimum and maximum size (need to estimate expend properties of the widget) + * @note : INTERNAL EWOL SYSTEM + */ + virtual void calculateMinMaxSize(); + /** + * @brief get the widget minimum size calculated + * @return Requested size + * @note : INTERNAL EWOL SYSTEM + */ + virtual vec2 getCalculateMinSize(); + /** + * @brief get the widget maximum size calculated + * @return Requested size + * @note : INTERNAL EWOL SYSTEM + */ + virtual vec2 getCalculateMaxSize(); + protected: + vec2 m_offset; //!< Offset of the display in the view-port + public: + /** + * @brief set the zoom property of the widget. + * @param[in] _newVal offset value. + */ + virtual void setOffset(const vec2& _newVal); + /** + * @brief get the offset property of the widget. + * @return The current offset value. + */ + virtual const vec2& getOffset() { + return m_offset; + }; + protected: + // internal element calculated by the system + float m_zoom; //!< generic widget zoom + public: + /** + * @brief set the zoom property of the widget + * @param[in] _newVal newZoom value + */ + virtual void setZoom(float _newVal); + /** + * @brief get the zoom property of the widget + * @return the current zoom value + */ + virtual float getZoom(); + /** + * @brief Change Zoom property. + * @param[in] _range Range of the zoom change. + */ + virtual void changeZoom(float _range) {}; + protected: + vec2 m_origin; //!< internal ... I do not really known how if can use it ... + public: + /** + * @brief Set origin at the widget (must be an parent widget that set this parameter). + * This represent the absolute origin in the program windows. + * @param[in] _pos Position of the origin. + * @note : INTERNAL EWOL SYSTEM + */ + virtual void setOrigin(const vec2& _pos); + /** + * @brief Get the origin (absolute position in the windows). + * @return Coordinate of the origin requested. + */ + virtual vec2 getOrigin(); + public: + /** + * @brief User set No minimum size. + */ + void setNoMinSize(); // TODO : Remove ==> default ... of the property + /** + * @brief Check if the current min size is compatible with the user minimum size + * If it is not the user minimum size will overWrite the minimum size set. + * @note : INTERNAL EWOL SYSTEM + */ + virtual void checkMinSize(); + protected: + + public: + /** + * @brief User set No maximum size. + */ + void setNoMaxSize(); // TODO : Remove ==> default ... of the property + /** + * @brief Check if the current max size is compatible with the user maximum size + * If it is not the user maximum size will overWrite the maximum size set. + * @note : INTERNAL EWOL SYSTEM + */ + virtual void checkMaxSize(); + public: + /** + * @brief get the expend capabilities (x&y) + * @return 2D boolean represents the capacity to expend + * @note : INTERNAL EWOL SYSTEM + */ + virtual bvec2 canExpand(); + public: + /** + * @brief get the filling capabilities x&y + * @return bvec2 repensent the capacity to x&y filling + * @note : INTERNAL EWOL SYSTEM + */ + const bvec2& canFill(); + // ---------------------------------------------------------------------------------------------------------------- + // -- focus Area + // ---------------------------------------------------------------------------------------------------------------- + private: + bool m_hasFocus; //!< set the focus on this widget + + public: + /** + * @brief get the focus state of the widget + * @return focus state + */ + virtual bool getFocus() { + return m_hasFocus; + }; + /** + * @brief set focus on this widget + * @return return true if the widget keep the focus + */ + virtual bool setFocus(); + /** + * @brief remove the focus on this widget + * @return return true if the widget have release his focus (if he has it) + */ + virtual bool rmFocus(); + /** + * @brief keep the focus on this widget == > this remove the previous focus on all other widget + */ + virtual void keepFocus(); + protected: + /** + * @brief Event of the focus has been grabed by the current widget + */ + virtual void onGetFocus() {}; + /** + * @brief Event of the focus has been lost by the current widget + */ + virtual void onLostFocus() {}; + + // ---------------------------------------------------------------------------------------------------------------- + // -- Mouse event properties Area + // ---------------------------------------------------------------------------------------------------------------- + private: + int32_t m_limitMouseEvent; //!< this is to limit the number of mouse event that the widget can supported + public: + /** + * @brief get the number of mouse event supported + * @return return the number of event that the mouse supported [0..3] + */ + virtual int32_t getMouseLimit() { + return m_limitMouseEvent; + }; + /** + * @brief get the number of mouse event supported + * @param[in] _numberState The number of event that the mouse supported [0..3] + */ + virtual void setMouseLimit(int32_t _numberState) { + m_limitMouseEvent = _numberState; + }; + // ---------------------------------------------------------------------------------------------------------------- + // -- keyboard event properties Area + // ---------------------------------------------------------------------------------------------------------------- + private: + bool m_allowRepeatKeyboardEvent; //!< This remove the repeating keybord event due to the constant pressing key. + public: + /** + * @brief get the keyboard repeating event supporting. + * @return true : the event can be repeated. + * @return false : the event must not be repeated. + */ + virtual bool getKeyboardRepeat() { + return m_allowRepeatKeyboardEvent; + }; + protected: + /** + * @brief set the keyboard repeating event supporting. + * @param[in] _state The repeating status (true: enable, false disable). + */ + virtual void setKeyboardRepeat(bool _state) { + m_allowRepeatKeyboardEvent = _state; + }; + /** + * @brief display the virtual keyboard (if needed) + */ + virtual void showKeyboard(); + /** + * @brief Hide the virtual keyboard (if needed) + */ + virtual void hideKeyboard(); + public: + /** + * @brief get the widget at the specific windows absolute position + * @param[in] _pos gAbsolute position of the requested widget knowledge + * @return null No widget found + * @return pointer on the widget found + * @note : INTERNAL EWOL SYSTEM + */ + virtual ewol::WidgetShared getWidgetAtPos(const vec2& _pos) { + if (propertyHide.get() == false) { + return ememory::dynamicPointerCast(sharedFromThis()); + } + return null; + }; + + // event section: + public: + /** + * @brief {SYSTEM} system event input (only meta widget might overwrite this function). + * @param[in] _event Event properties + * @return true the event is used + * @return false the event is not used + */ + virtual bool systemEventInput(ewol::event::InputSystem& _event); + protected: + /** + * @brief Event on an input of this Widget (finger, mouse, stylet) + * @param[in] _event Event properties + * @return true the event is used + * @return false the event is not used + */ + virtual bool onEventInput(const ewol::event::Input& _event) { + return false; + }; + public: + /** + * @brief {SYSTEM} Entry event (only meta widget might overwrite this function). + * @param[in] _event Event properties + * @return true if the event has been used + * @return false if the event has not been used + */ + virtual bool systemEventEntry(ewol::event::EntrySystem& _event); + protected: + /** + * @brief Entry event. + * represent the physical event : + * - Keyboard (key event and move event) + * - Accelerometer + * - Joystick + * @param[in] _event Event properties + * @return true if the event has been used + * @return false if the event has not been used + */ + virtual bool onEventEntry(const ewol::event::Entry& _event) { + return false; + }; + public: + /** + * @brief Event on a past event == > this event is asynchronous due to all system does not support direct getting data. + * @note : need to have focus ... + * @param[in] mode Mode of data requested + */ + virtual void onEventClipboard(enum gale::context::clipBoard::clipboardListe _clipboardID) { }; + + // ---------------------------------------------------------------------------------------------------------------- + // -- Shortcut : management of the shortcut + // ---------------------------------------------------------------------------------------------------------------- + public: + esignal::Signal signalShortcut; //!< signal handle of the message + private: + etk::Vector m_localShortcut; //!< list of all shortcut in the widget + protected: + /** + * @brief add a specific shortcut with his description + * @param[in] _descriptiveString Description string of the shortcut + * @param[in] _message massage to generate (or shortcut name) + */ + virtual void shortCutAdd(const etk::String& _descriptiveString, + const etk::String& _message=""); + /** + * @brief remove all current shortCut + */ + virtual void shortCutClean(); + /** + * @brief remove a specific shortCut with his event name + * @param[in] _message generated event name + */ + virtual void shortCutRemove(const etk::String& _message); + public: + /** + * @brief Event on a short-cut of this Widget (in case of return false, the event on the keyevent will arrive in the function @ref onEventKb). + * @param[in] _special All the special kay pressed at this time. + * @param[in] _unicodeValue Key pressed by the user not used if the kbMove!=ewol::EVENT_KB_MOVE_TYPE_NONE. + * @param[in] _kbMove Special key of the keyboard. + * @return true if the event has been used. + * @return false if the event has not been used. + * @note To prevent some error when you get an event get it if it is down and Up ... ==> like this it could not generate some mistake in the error. + */ + virtual bool onEventShortCut(const gale::key::Special& _special, + char32_t _unicodeValue, + enum gale::key::keyboard _kbMove, + bool _isDown); + // ---------------------------------------------------------------------------------------------------------------- + // -- drawing : All drawing must be done in 2 separate buffer 1 for the current display and 1 for the working... + // ---------------------------------------------------------------------------------------------------------------- + protected: + bool m_needRegenerateDisplay; //!< the display might be done the next regeneration + public: + /** + * @brief The widget mark itself that it need to regenerate the nest time. + */ + virtual void markToRedraw(); + protected: + /** + * @brief get the need of the redrawing of the widget and reset it to false + * @return true if we need to redraw + * @return false if we have no need to redraw + */ + virtual bool needRedraw() { + bool tmpData = m_needRegenerateDisplay; + m_needRegenerateDisplay = false; + return tmpData; + }; + public: + /** + * @brief {SYSTEM} extern interface to request a draw ... (called by the drawing thread [Android, X11, ...]) + * This function generate a clipping with the view-port openGL system. Like this a widget draw can not draw over an other widget + * @note This function is virtual for the scrolled widget, and the more complicated openGL widget + * @param[in] _displayProp properties of the current display + * @note : INTERNAL EWOL SYSTEM + */ + virtual void systemDraw(const DrawProperty& _displayProp); + protected: + /** + * @brief Common widget drawing function (called by the drawing thread [Android, X11, ...]) + */ + virtual void onDraw() { }; + public: + /** + * @brief Event generated when a redraw is needed + */ + virtual void onRegenerateDisplay() { }; + // grab cursor mode + private: + bool m_grabCursor; + public: + /** + * @brief Grab the cursor : This get all the movement of the mouse in PC mode, and generate an offset instead of a position. + * @note : the generation of the offset is due to the fact the cursor position is forced at the center of the widget. + * @note This done nothing in "Finger" or "Stylet" mode. + */ + virtual void grabCursor(); + /** + * @brief Un-Grab the cursor (default mode cursor offset) + */ + virtual void unGrabCursor(); + /** + * @brief get the grabbing status of the cursor. + * @return true if the cursor is currently grabbed + */ + virtual bool getGrabStatus(); + private: + enum gale::context::cursor m_cursorDisplay; + public: + /** + * @brief set the cursor display type. + * @param[in] _newCursor selected new cursor. + */ + virtual void setCursor(enum gale::context::cursor _newCursor); + /** + * @brief get the current cursor. + * @return the type of the cursor. + */ + virtual enum gale::context::cursor getCursor(); + public: + virtual bool loadXML(const exml::Element& _node) override; + public: + /** + * @brief Need to be call When the size of the current widget have change ==> this force the system to recalculate all the widget positions. + */ + void requestUpdateSize(); + /** + * @brief Get the current Widget Manager. + */ + ewol::widget::Manager& getWidgetManager(); + /** + * @brief Get the current Windows. + */ + ememory::SharedPtr getWindows(); + protected: + virtual void onChangePropertyCanFocus(); + virtual void onChangePropertyGravity(); + virtual void onChangePropertyHide(); + virtual void onChangePropertyFill(); + virtual void onChangePropertyExpand(); + virtual void onChangePropertyMaxSize(); + virtual void onChangePropertyMinSize(); + public: + virtual void drawWidgetTree(int32_t _level=0); + }; +}; + +#include + diff --git a/src/org/atriasoft/ewol/widget/WidgetScrolled.cpp b/src/org/atriasoft/ewol/widget/WidgetScrolled.cpp new file mode 100644 index 0000000..a7cda4a --- /dev/null +++ b/src/org/atriasoft/ewol/widget/WidgetScrolled.cpp @@ -0,0 +1,501 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include + +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::WidgetScrolled); + +ewol::widget::WidgetScrolled::WidgetScrolled() : + propertyShapeVert(this, "shape-vert", + etk::Uri("THEME_GUI:///WidgetScrolled.json?lib=ewol"), + "shape for the vertical display", + &ewol::widget::WidgetScrolled::onChangePropertyShapeVert), + propertyShapeHori(this, "shape-hori", + etk::Uri("THEME_GUI:///WidgetScrolled.json?lib=ewol"), + "shape for the horizonal display", + &ewol::widget::WidgetScrolled::onChangePropertyShapeHori), + m_shaperH(), + m_shaperV(), + m_singleFingerMode(true) { + addObjectType("ewol::widget::WidgetScrolled"); + m_originScrooled.setValue(0,0); + m_pixelScrolling = 20; + m_highSpeedMode = ewol::widget::Scroll::speedModeDisable; + m_scroollingMode = scroolModeNormal; + m_highSpeedType = gale::key::type::unknow; + m_highSpeedButton = -1; + m_limitScrolling = vec2(0.5f, 0.5f); + + m_fingerScoolActivated = false; + for (size_t iii = 0; iii < CALCULATE_SIMULTANEOUS_FINGER; ++iii) { + m_fingerPresent[iii] = false; + } +} + +void ewol::widget::WidgetScrolled::init() { + ewol::Widget::init(); + propertyShapeVert.notifyChange(); + propertyShapeHori.notifyChange(); +} + +ewol::widget::WidgetScrolled::~WidgetScrolled() { + +} + +void ewol::widget::WidgetScrolled::onRegenerateDisplay() { + m_shaperH.clear(); + m_shaperV.clear(); + if (m_scroollingMode == scroolModeGame) { + // nothing to do ... + return; + } + ewol::Padding paddingVert = m_shaperV.getPadding(); + ewol::Padding paddingHori = m_shaperH.getPadding(); + if( m_size.y() < m_maxSize.y() + || m_originScrooled.y()!=0) { + float lenScrollBar = m_size.y()*m_size.y() / m_maxSize.y(); + lenScrollBar = etk::avg(10.0f, lenScrollBar, m_size.y()); + float originScrollBar = m_originScrooled.y() / (m_maxSize.y()-m_size.y()*m_limitScrolling.y()); + originScrollBar = etk::avg(0.0f, originScrollBar, 1.0f); + originScrollBar *= (m_size.y()-lenScrollBar); + m_shaperV.setShape(vec2(m_size.x() - paddingVert.x(), 0), + vec2(paddingVert.x(), m_size.y()), + vec2(m_size.x() - paddingVert.xRight(), m_size.y() - originScrollBar - lenScrollBar), + vec2(0, lenScrollBar)); + } + if( m_size.x() < m_maxSize.x() + || m_originScrooled.x()!=0) { + float lenScrollBar = (m_size.x()-paddingHori.xLeft())*(m_size.x()-paddingVert.x()) / m_maxSize.x(); + lenScrollBar = etk::avg(10.0f, lenScrollBar, (m_size.x()-paddingVert.x())); + float originScrollBar = m_originScrooled.x() / (m_maxSize.x()-m_size.x()*m_limitScrolling.x()); + originScrollBar = etk::avg(0.0f, originScrollBar, 1.0f); + originScrollBar *= (m_size.x()-paddingHori.xRight()-lenScrollBar); + m_shaperH.setShape(vec2(0, 0), + vec2(m_size.x()-paddingVert.x(), paddingHori.y()), + vec2(originScrollBar, paddingHori.yButtom()), + vec2(lenScrollBar, 0)); + } +} + +bool ewol::widget::WidgetScrolled::onEventInput(const ewol::event::Input& _event) { + EWOL_VERBOSE("event XXX " << _event); + vec2 relativePos = relativePosition(_event.getPos()); + // corection due to the open Gl invertion ... + relativePos.setY(m_size.y() - relativePos.y()); + ewol::Padding paddingV = m_shaperV.getPadding(); + ewol::Padding paddingH = m_shaperH.getPadding(); + if (m_scroollingMode == scroolModeNormal) { + if ( _event.getType() == gale::key::type::mouse + && ( m_highSpeedType == gale::key::type::unknow + || m_highSpeedType == gale::key::type::mouse) ) { + if ( _event.getId() == 1 + && _event.getStatus() == gale::key::status::down) { + // check if selected the scrolling position whth the scrolling bar ... + if (relativePos.x() >= (m_size.x()-paddingV.x())) { + if( m_size.y() < m_maxSize.y() + || m_originScrooled.y() != 0) { + m_highSpeedMode = ewol::widget::Scroll::speedModeEnableVertical; + m_highSpeedType = gale::key::type::mouse; + m_highSpeedStartPos.setX(relativePos.x()); + m_highSpeedStartPos.setY(m_originScrooled.y() / m_maxSize.y() * (m_size.y()-paddingV.yButtom()*2)); + m_highSpeedButton = 1; + // force direct scrolling in this case + m_originScrooled.setY((int32_t)(m_maxSize.y() * (relativePos.y()-paddingV.yButtom()) / (m_size.y()-paddingV.yButtom()*2))); + m_originScrooled.setY(etk::avg(0.0f, m_originScrooled.y(), (m_maxSize.y() - m_size.y()*m_limitScrolling.y()))); + markToRedraw(); + return true; + } + } else if (relativePos.y() >= (m_size.y()-paddingH.y())) { + if( m_size.x() < m_maxSize.x() + || m_originScrooled.x()!=0) { + m_highSpeedMode = ewol::widget::Scroll::speedModeEnableHorizontal; + m_highSpeedType = gale::key::type::mouse; + m_highSpeedStartPos.setX(m_originScrooled.x() / m_maxSize.x() * (m_size.x()-paddingH.xLeft()*2)); + m_highSpeedStartPos.setY(relativePos.y()); + m_highSpeedButton = 1; + // force direct scrolling in this case + m_originScrooled.setX((int32_t)(m_maxSize.x() * (relativePos.x()-paddingH.xLeft()) / (m_size.x()-paddingH.xLeft()*2))); + m_originScrooled.setX(etk::avg(0.0f, m_originScrooled.x(), (m_maxSize.x() - m_size.x()*m_limitScrolling.x()))); + markToRedraw(); + return true; + } + } + return false; + } else if ( _event.getId() == 4 + && _event.getStatus() == gale::key::status::up) { + if (true == _event.getSpecialKey().getCtrl()) { + changeZoom(1); + /* + float zoom = getZoom()*1.1; + zoom = etk::avg(0.1f, zoom, 5000.0f); + setZoom(zoom); + */ + } else { + if(m_size.y() < m_maxSize.y() + || m_originScrooled.y() != 0 + || m_size.y()*m_limitScrolling.y() < m_maxSize.y() ) { + m_originScrooled.setY(m_originScrooled.y()-m_pixelScrolling); + m_originScrooled.setY(etk::avg(0.0f, m_originScrooled.y(), (m_maxSize.y() - m_size.y()*m_limitScrolling.y()))); + markToRedraw(); + return true; + } + } + } else if ( _event.getId() == 5 + && _event.getStatus() == gale::key::status::up) { + if (true == _event.getSpecialKey().getCtrl()) { + changeZoom(-1); + /* + float zoom = getZoom()*0.9; + zoom = etk::avg(0.1f, zoom, 5000.0f); + setZoom(zoom); + */ + } else { + if(m_size.y() < m_maxSize.y() + || m_originScrooled.y()!=0 + || m_size.y()*m_limitScrolling.y() < m_maxSize.y() ) { + m_originScrooled.setY(m_originScrooled.y()+m_pixelScrolling); + m_originScrooled.setY(etk::avg(0.0f, m_originScrooled.y(), (m_maxSize.y() - m_size.y()*m_limitScrolling.y()))); + markToRedraw(); + return true; + } + } + } else if ( _event.getId() == 11 + && _event.getStatus() == gale::key::status::up) { + // Scrool Left + if(m_size.x() < m_maxSize.x() + || m_originScrooled.x()!=0 + || m_size.x()*m_limitScrolling.x() < m_maxSize.x() ) { + m_originScrooled.setX(m_originScrooled.x()-m_pixelScrolling); + m_originScrooled.setX(etk::avg(0.0f, m_originScrooled.x(), (m_maxSize.x() - m_size.x()*m_limitScrolling.x()))); + markToRedraw(); + return true; + } + } else if ( _event.getId() == 10 + && _event.getStatus() == gale::key::status::up) { + // Scrool Right + if(m_size.x() < m_maxSize.x() + || m_originScrooled.x()!=0 + || m_size.x()*m_limitScrolling.x() < m_maxSize.x() ) { + m_originScrooled.setX(m_originScrooled.x()+m_pixelScrolling); + m_originScrooled.setX(etk::avg(0.0f, m_originScrooled.x(), (m_maxSize.x() - m_size.x()*m_limitScrolling.x()))); + markToRedraw(); + return true; + } + }else if (_event.getId() == 2) { + /* + if (true == ewol::isSetCtrl()) { + if (gale::key::status::down == typeEvent) { + float zoom = 1.0; + setZoom(zoom); + } + } else */{ + if (_event.getStatus() == gale::key::status::down) { + m_highSpeedMode = ewol::widget::Scroll::speedModeInit; + m_highSpeedType = gale::key::type::mouse; + m_highSpeedStartPos.setValue(relativePos.x(), relativePos.y()); + m_highSpeedButton = 2; + return true; + } + } + } else if ( m_highSpeedMode != ewol::widget::Scroll::speedModeDisable + && _event.getStatus() == gale::key::status::leave) { + m_highSpeedMode = ewol::widget::Scroll::speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + markToRedraw(); + return true; + } + if ( _event.getId() == m_highSpeedButton + && m_highSpeedMode != ewol::widget::Scroll::speedModeDisable) { + if (_event.getStatus() == gale::key::status::upAfter) { + m_highSpeedMode = ewol::widget::Scroll::speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + return false; + } else if (m_highSpeedMode == ewol::widget::Scroll::speedModeGrepEndEvent) { + if (_event.getStatus() == gale::key::status::pressSingle) { + m_highSpeedMode = ewol::widget::Scroll::speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + m_highSpeedButton = -1; + markToRedraw(); + } + return true; + } else if (_event.getStatus() == gale::key::status::up) { + return true; + } else if ( m_highSpeedMode == ewol::widget::Scroll::speedModeInit + && _event.getStatus() == gale::key::status::move) { + // wait that the cursor move more than 10 px to enable it : + if( etk::abs(relativePos.x() - m_highSpeedStartPos.x()) > 10 + || etk::abs(relativePos.y() - m_highSpeedStartPos.y()) > 10 ) { + // the scrooling can start : + // select the direction : + if (relativePos.x() == m_highSpeedStartPos.x()) { + m_highSpeedMode = ewol::widget::Scroll::speedModeEnableVertical; + } else if (relativePos.y() == m_highSpeedStartPos.y()) { + m_highSpeedMode = ewol::widget::Scroll::speedModeEnableHorizontal; + } else { + float coef = (relativePos.y() - m_highSpeedStartPos.y()) / (relativePos.x() - m_highSpeedStartPos.x()); + if (etk::abs(coef) <= 1 ) { + m_highSpeedMode = ewol::widget::Scroll::speedModeEnableHorizontal; + } else { + m_highSpeedMode = ewol::widget::Scroll::speedModeEnableVertical; + } + } + if (m_highSpeedMode == ewol::widget::Scroll::speedModeEnableHorizontal) { + m_highSpeedStartPos.setX(m_originScrooled.x() / m_maxSize.x() * (m_size.x()-paddingV.x())); + } else { + m_highSpeedStartPos.setY(m_originScrooled.y() / m_maxSize.y() * (m_size.y()-paddingV.y())); + } + markToRedraw(); + } + m_originScrooled.setY(etk::avg(0.0f, m_originScrooled.y(), (m_maxSize.y() - m_size.y()*m_limitScrolling.y()))); + return true; + } + if ( m_highSpeedMode == ewol::widget::Scroll::speedModeEnableHorizontal + && _event.getStatus() == gale::key::status::move) { + m_originScrooled.setX((int32_t)(m_maxSize.x() * (relativePos.x()-paddingH.xLeft()) / (m_size.x()-paddingH.x()))); + m_originScrooled.setX(etk::avg(0.0f, m_originScrooled.x(), (m_maxSize.x() - m_size.x()*m_limitScrolling.x()))); + markToRedraw(); + return true; + } + if ( m_highSpeedMode == ewol::widget::Scroll::speedModeEnableVertical + && _event.getStatus() == gale::key::status::move) { + m_originScrooled.setY((int32_t)(m_maxSize.y() * (relativePos.y()-paddingV.yButtom()) / (m_size.y()-paddingV.y()))); + m_originScrooled.setY(etk::avg(0.0f, m_originScrooled.y(), (m_maxSize.y() - m_size.y()*m_limitScrolling.y()))); + markToRedraw(); + return true; + } + } + } else if ( _event.getType() == gale::key::type::finger + && ( m_highSpeedType == gale::key::type::unknow + || m_highSpeedType == gale::key::type::finger) ) { + if (m_singleFingerMode == false) { + // *********************** + // ** Two finger mode : ** + // *********************** + if (_event.getId() >= 3) { + return false; + } + int32_t idTable = _event.getId()-1; + if (_event.getStatus() == gale::key::status::down) { + m_fingerPresent[idTable] = true; + } else if (_event.getStatus() == gale::key::status::upAfter) { + m_fingerPresent[idTable] = false; + } + if (m_fingerScoolActivated == false) { + m_fingerMoveStartPos[idTable] = relativePos; + } + if ( m_fingerPresent[0] == true + && m_fingerPresent[1] == true + && m_fingerScoolActivated == false) { + m_fingerScoolActivated = true; + EWOL_VERBOSE("SCROOL == > START pos=" << m_fingerMoveStartPos); + } + if (m_fingerScoolActivated == true) { + // 1: scroll... + // 2: remove all unneeded sub event ... ==> maybe a better methode ... + if (_event.getStatus() == gale::key::status::move) { + m_originScrooled.setX(m_originScrooled.x() - (relativePos.x() - m_fingerMoveStartPos[idTable].x())*0.5f); + m_originScrooled.setY(m_originScrooled.y() - (relativePos.y() - m_fingerMoveStartPos[idTable].y())*0.5f); + m_originScrooled.setX(etk::avg(0.0f, m_originScrooled.x(), (m_maxSize.x() - m_size.x()*m_limitScrolling.x()))); + m_originScrooled.setY(etk::avg(0.0f, m_originScrooled.y(), (m_maxSize.y() - m_size.y()*m_limitScrolling.y()))); + m_fingerMoveStartPos[idTable] = relativePos; + EWOL_VERBOSE("SCROOL == > MOVE m_originScrooled=" << m_originScrooled << " " << relativePos << " " << m_highSpeedStartPos); + markToRedraw(); + } + if ( m_fingerPresent[0] == false + && m_fingerPresent[1] == false) { + if (_event.getStatus() == gale::key::status::upAfter) { + // TODO : Reset event ... + m_fingerScoolActivated = false; + _event.reset(); + } + } + return true; + } + } else { + // ************************** + // ** Single finger mode : ** + // ************************** + if (_event.getId() == 1) { + EWOL_VERBOSE("event 1 " << _event); + if (_event.getStatus() == gale::key::status::down) { + m_highSpeedMode = ewol::widget::Scroll::speedModeInit; + m_highSpeedType = gale::key::type::finger; + m_highSpeedStartPos.setValue(relativePos.x(), relativePos.y()); + EWOL_VERBOSE("SCROOL == > INIT"); + return true; + } else if (_event.getStatus() == gale::key::status::upAfter) { + m_highSpeedMode = ewol::widget::Scroll::speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + EWOL_VERBOSE("SCROOL == > DISABLE"); + markToRedraw(); + return true; + } else if ( m_highSpeedMode == ewol::widget::Scroll::speedModeInit + && _event.getStatus() == gale::key::status::move) { + // wait that the cursor move more than 10 px to enable it : + if( etk::abs(relativePos.x() - m_highSpeedStartPos.x()) > 10 + || etk::abs(relativePos.y() - m_highSpeedStartPos.y()) > 10 ) { + // the scrooling can start : + // select the direction : + m_highSpeedMode = ewol::widget::Scroll::speedModeEnableFinger; + EWOL_DEBUG("SCROOL == > ENABLE"); + markToRedraw(); + } + return true; + } else if ( m_highSpeedMode == ewol::widget::Scroll::speedModeEnableFinger + && _event.getStatus() == gale::key::status::pressSingle) { + // Keep all event in the range of moving + return true; + } else if ( m_highSpeedMode == ewol::widget::Scroll::speedModeEnableFinger + && _event.getStatus() == gale::key::status::pressDouble) { + // Keep all event in the range of moving + return true; + } if ( m_highSpeedMode == ewol::widget::Scroll::speedModeEnableFinger + && _event.getStatus() == gale::key::status::move) { + //m_originScrooled.x = (int32_t)(m_maxSize.x * x / m_size.x); + m_originScrooled.setX(m_originScrooled.x() - (relativePos.x() - m_highSpeedStartPos.x())); + m_originScrooled.setY(m_originScrooled.y() - (relativePos.y() - m_highSpeedStartPos.y())); + m_originScrooled.setX(etk::avg(0.0f, m_originScrooled.x(), (m_maxSize.x() - m_size.x()*m_limitScrolling.x()))); + m_originScrooled.setY(etk::avg(0.0f, m_originScrooled.y(), (m_maxSize.y() - m_size.y()*m_limitScrolling.y()))); + m_highSpeedStartPos.setValue(relativePos.x(), relativePos.y()); + EWOL_VERBOSE("SCROOL == > MOVE m_originScrooled=" << m_originScrooled << " " << relativePos << " " << m_highSpeedStartPos); + markToRedraw(); + return true; + } + } else if ( m_highSpeedMode == ewol::widget::Scroll::speedModeDisable + && _event.getStatus() == gale::key::status::leave) { + m_highSpeedMode = ewol::widget::Scroll::speedModeDisable; + m_highSpeedType = gale::key::type::unknow; + EWOL_VERBOSE("SCROOL == > DISABLE"); + markToRedraw(); + return true; + } + } + } + } else if (m_scroollingMode == scroolModeCenter) { + if (_event.getType() == gale::key::type::mouse) { + float tmp1=m_size.x() / m_maxSize.y(); + float tmp2=m_size.y() / m_maxSize.x(); + //EWOL_INFO(" elements Zoom : " << tmp1 << " " << tmp2); + tmp1 = etk::min(tmp1, tmp2); + if ( _event.getId() == 4 + && _event.getStatus() == gale::key::status::up) { + m_zoom -= 0.1; + if (tmp1 < 1.0) { + m_zoom = etk::max(tmp1, m_zoom); + } else { + m_zoom = etk::max(1.0f, m_zoom); + } + markToRedraw(); + return true; + } else if ( _event.getId() == 5 + && _event.getStatus() == gale::key::status::up) { + m_zoom += 0.1; + if (tmp1 > 1.0) { + m_zoom = etk::min(tmp1, m_zoom); + } else { + m_zoom = etk::min(1.0f, m_zoom); + } + markToRedraw(); + return true; + } + } + } else if (m_scroollingMode == scroolModeGame) { + + } else { + EWOL_ERROR("Scrolling mode unknow ... " << m_scroollingMode ); + } + return false; +} + + +void ewol::widget::WidgetScrolled::onDraw() { + m_shaperH.draw(); + m_shaperV.draw(); +} + +void ewol::widget::WidgetScrolled::systemDraw(const ewol::DrawProperty& _displayProp) { + gale::openGL::push(); + if (m_scroollingMode == scroolModeCenter) { + // here we invert the reference of the standard openGl view because the reference in the common display is Top left and not buttom left + gale::openGL::setViewPort(m_origin, m_size); + mat4 tmpProjection = etk::matOrtho(-m_size.x()/2, m_size.x()/2, -m_size.y()/2, m_size.y()/2, -1, 1); + mat4 tmpScale = etk::matScale(vec3(m_zoom, m_zoom, 1.0) ); + mat4 tmpTranslate = etk::matTranslate(vec3(-m_maxSize.x()/2, -m_maxSize.y()/2, -1.0) ); + mat4 tmpMat = tmpProjection * tmpScale * tmpTranslate; + // set internal matrix system : + gale::openGL::setMatrix(tmpMat); + // Call the widget drawing methode + onDraw(); + } if (m_scroollingMode == scroolModeGame) { + // here we invert the reference of the standard openGl view because the reference in the common display is Top left and not buttom left + gale::openGL::setViewPort(m_origin, m_size); + mat4 tmpProjection = etk::matOrtho(-m_size.x()/2, m_size.x()/2, -m_size.y()/2, m_size.y()/2, -1, 1); + mat4 tmpTranslate = etk::matTranslate(vec3( -m_maxSize.x()/2, -m_maxSize.y()/2, -1.0) ); + mat4 tmpMat = tmpProjection * tmpTranslate; + // set internal matrix system : + gale::openGL::setMatrix(tmpMat); + // Call the widget drawing methode + onDraw(); + } else { + ewol::Widget::systemDraw(_displayProp); + } + gale::openGL::pop(); +} + +void ewol::widget::WidgetScrolled::setScrollingPositionDynamic(vec2 _borderWidth, const vec2& _currentPosition, bool _center) { + if (true == _center) { + _borderWidth.setValue(m_size.x() / 2 - _borderWidth.x(), + m_size.y() / 2 - _borderWidth.y() ); + } + // check scrooling in X + if (_currentPosition.x() < (m_originScrooled.x() + _borderWidth.x()) ) { + m_originScrooled.setX(_currentPosition.x() - _borderWidth.x()); + m_originScrooled.setX(etk::max(0.0f, m_originScrooled.x())); + } else if (_currentPosition.x() > (m_originScrooled.x()+m_size.x()-2*_borderWidth.x()) ) { + m_originScrooled.setX(_currentPosition.x() - m_size.x() + 2*_borderWidth.x()); + m_originScrooled.setX(etk::max(0.0f, m_originScrooled.x())); + } + // check scrooling in Y + if (_currentPosition.y() < (m_originScrooled.y() + _borderWidth.y()) ) { + m_originScrooled.setY(_currentPosition.y() - _borderWidth.y()); + m_originScrooled.setY(etk::max(0.0f, m_originScrooled.y())); + } else if (_currentPosition.y() > (m_originScrooled.y()+m_size.y()-2*_borderWidth.y()) ) { + m_originScrooled.setY(_currentPosition.y() - m_size.y() + 2*_borderWidth.y()); + m_originScrooled.setY(etk::max(0.0f, m_originScrooled.y())); + } +} + +void ewol::widget::WidgetScrolled::scroolingMode(enum scrollingMode _newMode) { + m_scroollingMode = _newMode; + if (m_scroollingMode == scroolModeGame) { + // set the scene maximum size : + m_maxSize.setValue(etk::max(m_size.x(), m_size.y()), + m_maxSize.x()); + m_zoom = 1; + } +} + +void ewol::widget::WidgetScrolled::setSingleFinger(bool _status) { + if (m_singleFingerMode == _status) { + return; + } + m_singleFingerMode = _status; +} + +void ewol::widget::WidgetScrolled::onChangePropertyShapeVert() { + m_shaperV.setSource(propertyShapeVert); + markToRedraw(); +} +void ewol::widget::WidgetScrolled::onChangePropertyShapeHori() { + m_shaperH.setSource(propertyShapeHori); + markToRedraw(); +} + diff --git a/src/org/atriasoft/ewol/widget/WidgetScrolled.java b/src/org/atriasoft/ewol/widget/WidgetScrolled.java new file mode 100644 index 0000000..0e95ea2 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/WidgetScrolled.java @@ -0,0 +1,142 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +#define CALCULATE_SIMULTANEOUS_FINGER (5) + +namespace ewol { + namespace widget { + class WidgetScrolled; + using WidgetScrolledShared = ememory::SharedPtr; + using WidgetScrolledWeak = ememory::WeakPtr; + /** + * @brief Widget to integrate a scrool bar in a widget. This is not a stadalone widget. + */ + class WidgetScrolled : public ewol::Widget { + public: // properties: + eproperty::Value propertyShapeVert; //!< Vertical shaper name + eproperty::Value propertyShapeHori; //!< Horizontal shaper name + // TODO : All property + public: + enum scrollingMode { + scroolModeNormal, //!< No Zoom , can UP and down, left and right + scroolModeCenter, //!< Zoom enable, no move left and right + scroolModeGame, //!< Zoom enable, no move left and right + }; + private: + ewol::compositing::Shaper m_shaperH; //!< Compositing theme Horizontal. + ewol::compositing::Shaper m_shaperV; //!< Compositing theme Vertical. + protected: + vec2 m_originScrooled; //!< pixel distance from the origin of the display (Bottum left) + vec2 m_maxSize; //!< Maximum size of the Widget ==> to display scrollbar + vec2 m_limitScrolling; //!< Mimit scrolling represent the propertion of the minimel scrolling activate (0.2 ==> 20% migt all time be visible) + private: // Mouse section : + enum scrollingMode m_scroollingMode; //!< mode of management of the scrooling + float m_pixelScrolling; + vec2 m_highSpeedStartPos; + enum Scroll::highSpeedMode m_highSpeedMode; + int32_t m_highSpeedButton; + enum gale::key::type m_highSpeedType; + private: // finger section: + bool m_singleFingerMode; //!< in many case the moving in a subwidget is done with one finger, it is enought ==> the user select... + public: + /** + * @brief Set the single finger capabilities/ + * @param[in] _status True if single inger mode, two otherwise/ + */ + void setSingleFinger(bool _status); + /** + * @brief Get the single finger capabilities + * @return true The single finger mode is active + * @return false The To finger mode is active + */ + bool getSingleFinger() { + return m_singleFingerMode; + } + /** + * @brief Reset the scoll of the subWidget + */ + void resetScrollOrigin() { + m_originScrooled = vec2(0,0); + } + private: + bool m_fingerPresent[CALCULATE_SIMULTANEOUS_FINGER]; + bool m_fingerScoolActivated; + vec2 m_fingerMoveStartPos[CALCULATE_SIMULTANEOUS_FINGER]; + protected: + /** + * @brief Scroll Widget main constructor to be herited from an other widget (this is not a stand-alone widget) + * @param[in] _shaperName Shaper name if the scrolled widget. + */ + WidgetScrolled(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(WidgetScrolled, "WidgetScrolled"); + /** + * @brief Scroll widget destructor. + */ + virtual ~WidgetScrolled(); + protected: + void onDraw() override; + public: + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + void systemDraw(const ewol::DrawProperty& _displayProp) override; + protected: + /** + * @brief For mouse event when we have a scrolling UP and dows, specify the number of pixel that we scrooled + * @param[in] _nbPixel number of pixel scrolling + */ + void setScrollingSize(float _nbPixel) { + m_pixelScrolling = _nbPixel; + }; + /** + * @brief Specify the mode of scrolling for this windows + * @param[in] _newMode the selected mode for the scrolling... + */ + void scroolingMode(enum scrollingMode _newMode); + /** + * @brief set the specific mawimum size of the widget + * @param[in] _localSize new Maximum size + */ + void setMaxSize(const vec2& _localSize) { + m_maxSize = _localSize; + }; + /** + * @brief Request a specific position for the scrolling of the current windows. + * @param[in] _borderWidth size of the border that requested the element might not to be + * @param[in] _currentPosition Position that is requested to view + * @param[in] _center True if the position might be at the center of the widget + */ + void setScrollingPositionDynamic(vec2 _borderWidth, const vec2& _currentPosition, bool _center = false); + /** + * @brief set the scrolling limit when arriving at he end of the widget + * @param[in] _poucentageLimit pourcent of the limit of view nothing in the widget when arriving at the end ... + */ + void setLimitScrolling(float _poucentageLimit) { + _poucentageLimit = etk::avg(0.1f, _poucentageLimit,1.0f); + m_limitScrolling = vec2(_poucentageLimit, _poucentageLimit); + }; + /** + * @brief set the scrolling limit when arriving at he end of the widget + * @param[in] _poucentageLimit pourcent of the limit of view nothing in the widget when arriving at the end for axis specific... + */ + void setLimitScrolling(const vec2& _poucentageLimit) { + m_limitScrolling = vec2(etk::avg(0.1f, _poucentageLimit.x(),1.0f), etk::avg(0.1f, _poucentageLimit.y(),1.0f)); + }; + protected: + virtual void onChangePropertyShapeVert(); + virtual void onChangePropertyShapeHori(); + }; + } +} + diff --git a/src/org/atriasoft/ewol/widget/Windows.cpp b/src/org/atriasoft/ewol/widget/Windows.cpp new file mode 100644 index 0000000..cd1a25b --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Windows.cpp @@ -0,0 +1,290 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::Windows); + +ewol::widget::Windows::Windows() : + propertyColorConfiguration(this, + "file-color", + etk::Uri("THEME_COLOR:///Windows.json?lib=ewol"), + "File color of the Windows", + &ewol::widget::Windows::onChangePropertyColor), + propertyTitle(this, + "title", + "No title", + "Title of the windows", + &ewol::widget::Windows::onChangePropertyTitle), + m_resourceColor(null), + m_colorBg(-1) { + addObjectType("ewol::widget::Windows"); + propertyCanFocus.setDirectCheck(true); + //KeyboardShow(KEYBOARD_MODE_CODE); +} + + +void ewol::widget::Windows::init() { + ewol::Widget::init(); + onChangePropertyColor(); +} + +ewol::widget::Windows::~Windows() { + m_subWidget.reset(); + m_popUpWidgetList.clear(); +} + +void ewol::widget::Windows::onChangeSize() { + ewol::Widget::onChangeSize(); + if (m_subWidget != null) { + m_subWidget->calculateMinMaxSize(); + // TODO : do it better ... and manage gravity ... + m_subWidget->setSize(m_size); + m_subWidget->setOrigin(vec2(0.0f, 0.0f)); + m_subWidget->onChangeSize(); + } + for (auto &it : m_popUpWidgetList) { + if(it != null) { + it->calculateMinMaxSize(); + it->setSize(m_size); + it->setOrigin(vec2(0.0f, 0.0f)); + it->onChangeSize(); + } + } +} + +ewol::WidgetShared ewol::widget::Windows::getWidgetAtPos(const vec2& _pos) { + EWOL_VERBOSE("Get widget at pos : " << _pos); + // calculate relative position + vec2 relativePos = relativePosition(_pos); + // event go directly on the pop-up + if (m_popUpWidgetList.size() != 0) { + return m_popUpWidgetList.back()->getWidgetAtPos(_pos); + // otherwise in the normal windows + } else if (m_subWidget != null) { + return m_subWidget->getWidgetAtPos(_pos); + } + // otherwise the event go to this widget ... + return ememory::dynamicPointerCast(sharedFromThis()); +} + +void ewol::widget::Windows::sysDraw() { + EWOL_VERBOSE("Draw on " << m_size); + // set the size of the open GL system + gale::openGL::setViewPort(vec2(0,0), m_size); + gale::openGL::disable(gale::openGL::flag_dither); + //gale::openGL::disable(gale::openGL::flag_blend); + gale::openGL::disable(gale::openGL::flag_stencilTest); + gale::openGL::disable(gale::openGL::flag_alphaTest); + gale::openGL::disable(gale::openGL::flag_fog); + gale::openGL::disable(gale::openGL::flag_texture2D); + gale::openGL::disable(gale::openGL::flag_depthTest); + + gale::openGL::enable(gale::openGL::flag_blend); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + // clear the matrix system : + mat4 newOne; + gale::openGL::setBasicMatrix(newOne); + + ewol::DrawProperty displayProp; + displayProp.m_windowsSize = m_size; + displayProp.m_origin.setValue(0,0); + displayProp.m_size = m_size; + systemDraw(displayProp); + gale::openGL::disable(gale::openGL::flag_blend); + return; +} + +void ewol::widget::Windows::onRegenerateDisplay() { + if (m_subWidget != null) { + m_subWidget->onRegenerateDisplay(); + } + for (auto &it : m_popUpWidgetList) { + if (it != null) { + it->onRegenerateDisplay(); + } + } +} + +//#define TEST_PERFO_WINDOWS + +void ewol::widget::Windows::systemDraw(const ewol::DrawProperty& _displayProp) { + ewol::Widget::systemDraw(_displayProp); + #ifdef TEST_PERFO_WINDOWS + int64_t ___startTime0 = ewol::getTime(); + #endif + // clear the screen with transparency ... + etk::Color colorBg(0.5, 0.5, 0.5, 0.5); + if (m_resourceColor != null) { + colorBg = m_resourceColor->get(m_colorBg); + } + gale::openGL::clearColor(colorBg); + gale::openGL::clear( uint32_t(gale::openGL::clearFlag_colorBuffer) + | uint32_t(gale::openGL::clearFlag_depthBuffer)); + #ifdef TEST_PERFO_WINDOWS + float ___localTime0 = (float)(ewol::getTime() - ___startTime0) / 1000.0f; + EWOL_ERROR(" Windows000 : " << ___localTime0 << "ms "); + int64_t ___startTime1 = ewol::getTime(); + #endif + //EWOL_WARNING(" WINDOWS draw on " << m_currentDrawId); + // first display the windows on the display + if (m_subWidget != null) { + m_subWidget->systemDraw(_displayProp); + //EWOL_DEBUG("Draw Windows"); + } + #ifdef TEST_PERFO_WINDOWS + float ___localTime1 = (float)(ewol::getTime() - ___startTime1) / 1000.0f; + EWOL_ERROR(" Windows111 : " << ___localTime1 << "ms "); + int64_t ___startTime2 = ewol::getTime(); + #endif + // second display the pop-up + for (auto &it : m_popUpWidgetList) { + if (it != null) { + it->systemDraw(_displayProp); + //EWOL_DEBUG("Draw Pop-up"); + } + } + #ifdef TEST_PERFO_WINDOWS + float ___localTime2 = (float)(ewol::getTime() - ___startTime2) / 1000.0f; + EWOL_ERROR(" Windows222 : " << ___localTime2 << "ms "); + #endif +} + +void ewol::widget::Windows::setSubWidget(ewol::WidgetShared _widget) { + if (m_subWidget != null) { + EWOL_INFO("Remove current main windows Widget..."); + m_subWidget->removeParent(); + m_subWidget.reset(); + } + if (_widget != null) { + m_subWidget = _widget; + m_subWidget->setParent(sharedFromThis()); + } + + // Regenerate the size calculation : + onChangeSize(); +} + +void ewol::widget::Windows::popUpWidgetPush(ewol::WidgetShared _widget) { + if (_widget == null) { + // nothing to do an error appear : + EWOL_ERROR("can not set widget pop-up (null pointer)"); + return; + } + m_popUpWidgetList.pushBack(_widget); + _widget->setParent(sharedFromThis()); + // force the focus on the basic widget ==> this remove many time the virual keyboard area + _widget->keepFocus(); + // Regenerate the size calculation : + onChangeSize(); + // TODO : it is dangerous to access directly to the system ... + getContext().resetIOEvent(); +} + +void ewol::widget::Windows::popUpWidgetPop() { + if (m_popUpWidgetList.size() == 0) { + return; + } + m_popUpWidgetList.popBack(); +} + +void ewol::widget::Windows::onChangePropertyColor() { + m_resourceColor = ewol::resource::ColorFile::create(*propertyColorConfiguration); + if (m_resourceColor != null) { + m_colorBg = m_resourceColor->request("background"); + } else { + EWOL_WARNING("Can not open the default color configuration file for the windows: " << *propertyColorConfiguration); + } +} + +void ewol::widget::Windows::onChangePropertyTitle() { + ewol::Context& context = getContext(); + if (context.getWindows() == sharedFromThis()) { + context.setTitle(*propertyTitle); + } else { + EWOL_INFO("Set title is delayed ..."); + } +} + +void ewol::widget::Windows::requestDestroyFromChild(const ewol::ObjectShared& _child) { + EWOL_VERBOSE("A child has been removed"); + auto it = m_popUpWidgetList.begin(); + while (it != m_popUpWidgetList.end()) { + if (*it == _child) { + EWOL_VERBOSE(" Find it ..."); + if (*it == null) { + m_popUpWidgetList.erase(it); + it = m_popUpWidgetList.begin(); + continue; + } + (*it)->removeParent(); + (*it).reset(); + m_popUpWidgetList.erase(it); + it = m_popUpWidgetList.begin(); + markToRedraw(); + continue; + } + ++it; + } + if (m_subWidget == _child) { + EWOL_VERBOSE(" Find it ... 2"); + if (m_subWidget == null) { + return; + } + m_subWidget->removeParent(); + m_subWidget.reset(); + markToRedraw(); + } +} + +ewol::ObjectShared ewol::widget::Windows::getSubObjectNamed(const etk::String& _objectName) { + ewol::ObjectShared tmpObject = ewol::Widget::getSubObjectNamed(_objectName); + if (tmpObject != null) { + return tmpObject; + } + // check direct subwidget + if (m_subWidget != null) { + tmpObject = m_subWidget->getSubObjectNamed(_objectName); + if (tmpObject != null) { + return tmpObject; + } + } + // get all subwidget "pop-up" + for (auto &it : m_popUpWidgetList) { + if (it != null) { + tmpObject = it->getSubObjectNamed(_objectName); + if (tmpObject != null) { + return tmpObject; + } + } + } + // not find ... + return null; +} + +void ewol::widget::Windows::drawWidgetTree(int32_t _level) { + ewol::Widget::drawWidgetTree(_level); + _level++; + if (m_subWidget != null) { + m_subWidget->drawWidgetTree(_level); + } + for (auto &it: m_popUpWidgetList) { + if (it != null) { + it->drawWidgetTree(_level); + } + } +} + diff --git a/src/org/atriasoft/ewol/widget/Windows.java b/src/org/atriasoft/ewol/widget/Windows.java new file mode 100644 index 0000000..0f8b294 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/Windows.java @@ -0,0 +1,85 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class Windows; + using WindowsShared = ememory::SharedPtr; + using WindowsWeak = ememory::WeakPtr; + /** + * @brief Windows basic interface + */ + class Windows : public ewol::Widget { + public: + eproperty::Value propertyColorConfiguration; //!< Configuration file of the windows theme + eproperty::Value propertyTitle; //!< Current title of the windows + protected: + ememory::SharedPtr m_resourceColor; //!< theme color property (name of file in @ref propertyColorConfiguration) + int32_t m_colorBg; //!< Default background color of the windows + protected: + Windows(); + void init() override; + public: + virtual ~Windows(); + // internal event at ewol system: + public: + void sysDraw(); + protected: + ewol::WidgetShared m_subWidget; //!< main sub-widget of the Windows. + public: + /** + * @brief Set the main widget of the application. + * @param[in] _widget Widget to set in the windows. + */ + void setSubWidget(ewol::WidgetShared _widget); + protected: + etk::Vector m_popUpWidgetList; //!< List of pop-up displayed + public: + /** + * @brief Add a pop-up on the Windows. + * @param[in] _widget Widget to set on top of the pop-up. + */ + void popUpWidgetPush(ewol::WidgetShared _widget); + /** + * @brief Remove the pop-up on top. + */ + void popUpWidgetPop(); + /** + * @brief Get the number of pop-up + * @return Count of pop-up + */ + size_t popUpCount() { + return m_popUpWidgetList.size(); + } + protected: + void systemDraw(const ewol::DrawProperty& _displayProp) override; + public: + void onRegenerateDisplay() override; + void onChangeSize() override; + ewol::WidgetShared getWidgetAtPos(const vec2& _pos) override; + void requestDestroyFromChild(const ewol::ObjectShared& _child) override; + ewol::ObjectShared getSubObjectNamed(const etk::String& _objectName) override; + void drawWidgetTree(int32_t _level=0) override; + protected: + /** + * @brief Called when property change: Title + */ + virtual void onChangePropertyTitle(); + /** + * @brief Called when property change: Color configuration file + */ + virtual void onChangePropertyColor(); + }; + } +} + diff --git a/src/org/atriasoft/ewol/widget/meta/ColorChooser.cpp b/src/org/atriasoft/ewol/widget/meta/ColorChooser.cpp new file mode 100644 index 0000000..ef13956 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/ColorChooser.cpp @@ -0,0 +1,153 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +//#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::ColorChooser); + +extern "C" { + // file browsing ... + #include +} + +ewol::widget::ColorChooser::ColorChooser() : + signalChange(this, "change", ""), + propertyValue(this, "value", + etk::color::white, + "color to select", + &ewol::widget::ColorChooser::onChangePropertyValue) { + addObjectType("ewol::widget::ColorChooser"); +} + +void ewol::widget::ColorChooser::init() { + ewol::widget::Sizer::init(); + propertyMode.set(ewol::widget::Sizer::modeVert); + propertyLockExpand.set(bvec2(true,true)); + m_widgetColorBar = ewol::widget::ColorBar::create(); + m_widgetColorBar->signalChange.connect(sharedFromThis(), &ewol::widget::ColorChooser::onCallbackColorChange); + m_widgetColorBar->propertyFill.set(bvec2(true,true)); + subWidgetAdd(m_widgetColorBar); + + etk::Color<> sliderColor; + sliderColor = etk::color::black; + + m_widgetRed = ewol::widget::Slider::create(); + m_widgetRed->signalChange.connect(sharedFromThis(), &ewol::widget::ColorChooser::onCallbackColorChangeRed); + m_widgetRed->propertyExpand.set(bvec2(true,false)); + m_widgetRed->propertyFill.set(bvec2(true,false)); + m_widgetRed->propertyMinimum.set(0); + m_widgetRed->propertyMaximum.set(255); + sliderColor = etk::Color<>(0xFF, 0x00, 0x00, 0xFF); + m_widgetRed->setColor(sliderColor); + subWidgetAdd(m_widgetRed); + m_widgetGreen = ewol::widget::Slider::create(); + m_widgetGreen->signalChange.connect(sharedFromThis(), &ewol::widget::ColorChooser::onCallbackColorChangeGreen); + m_widgetGreen->propertyExpand.set(bvec2(true,false)); + m_widgetGreen->propertyFill.set(bvec2(true,false)); + m_widgetGreen->propertyMinimum.set(0); + m_widgetGreen->propertyMaximum.set(255); + sliderColor = etk::Color<>(0x00, 0xFF, 0x00, 0xFF); + m_widgetGreen->setColor(sliderColor); + subWidgetAdd(m_widgetGreen); + m_widgetBlue = ewol::widget::Slider::create(); + m_widgetBlue->signalChange.connect(sharedFromThis(), &ewol::widget::ColorChooser::onCallbackColorChangeBlue); + m_widgetBlue->propertyExpand.set(bvec2(true,false)); + m_widgetBlue->propertyFill.set(bvec2(true,false)); + m_widgetBlue->propertyMinimum.set(0); + m_widgetBlue->propertyMaximum.set(255); + sliderColor = etk::Color<>(0x00, 0x00, 0xFF, 0xFF); + m_widgetBlue->setColor(sliderColor); + subWidgetAdd(m_widgetBlue); + m_widgetAlpha = ewol::widget::Slider::create(); + m_widgetAlpha->signalChange.connect(sharedFromThis(), &ewol::widget::ColorChooser::onCallbackColorChangeAlpha); + m_widgetAlpha->propertyExpand.set(bvec2(true,false)); + m_widgetAlpha->propertyFill.set(bvec2(true,false)); + m_widgetAlpha->propertyMinimum.set(0); + m_widgetAlpha->propertyMaximum.set(255); + subWidgetAdd(m_widgetAlpha); +} + + +ewol::widget::ColorChooser::~ColorChooser() { + +} + + +void ewol::widget::ColorChooser::onChangePropertyValue() { + if (m_widgetRed != null) { + m_widgetRed->propertyValue.set(propertyValue->r()); + } + if (m_widgetGreen != null) { + m_widgetGreen->propertyValue.set(propertyValue->g()); + } + if (m_widgetBlue != null) { + m_widgetBlue->propertyValue.set(propertyValue->b()); + } + if (m_widgetAlpha != null) { + m_widgetAlpha->propertyValue.set(propertyValue->a()); + } + if (m_widgetColorBar != null) { + m_widgetColorBar->propertyValue.set(propertyValue); + } +} + +void ewol::widget::ColorChooser::onCallbackColorChangeRed(const float& _newColor) { + propertyValue.getDirect().setR(_newColor); + if (m_widgetColorBar != null) { + m_widgetColorBar->propertyValue.set(propertyValue); + } + signalChange.emit(propertyValue); +} + +void ewol::widget::ColorChooser::onCallbackColorChangeGreen(const float& _newColor) { + propertyValue.getDirect().setG(_newColor); + if (m_widgetColorBar != null) { + m_widgetColorBar->propertyValue.set(propertyValue); + } + signalChange.emit(propertyValue); +} + +void ewol::widget::ColorChooser::onCallbackColorChangeBlue(const float& _newColor) { + propertyValue.getDirect().setB(_newColor); + if (m_widgetColorBar != null) { + m_widgetColorBar->propertyValue.set(propertyValue); + } + signalChange.emit(propertyValue); +} + +void ewol::widget::ColorChooser::onCallbackColorChangeAlpha(const float& _newColor) { + propertyValue.getDirect().setA(_newColor); + if (m_widgetColorBar != null) { + m_widgetColorBar->propertyValue.set(propertyValue); + } + signalChange.emit(propertyValue); +} + +void ewol::widget::ColorChooser::onCallbackColorChange(const etk::Color<>& _newColor) { + // == > colorBar has change ... + uint8_t tmpAlpha = propertyValue->a(); + propertyValue.getDirect() = _newColor; + propertyValue.getDirect().setA(tmpAlpha); + if (m_widgetRed != null) { + m_widgetRed->propertyValue.set(propertyValue->r()); + } + if (m_widgetGreen != null) { + m_widgetGreen->propertyValue.set(propertyValue->g()); + } + if (m_widgetBlue != null) { + m_widgetBlue->propertyValue.set(propertyValue->b()); + } + if (m_widgetAlpha != null) { + m_widgetAlpha->propertyValue.set(propertyValue->a()); + } + signalChange.emit(propertyValue); +} \ No newline at end of file diff --git a/src/org/atriasoft/ewol/widget/meta/ColorChooser.java b/src/org/atriasoft/ewol/widget/meta/ColorChooser.java new file mode 100644 index 0000000..b963058 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/ColorChooser.java @@ -0,0 +1,53 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class ColorChooser; + using ColorChooserShared = ememory::SharedPtr; + using ColorChooserWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class ColorChooser : public ewol::widget::Sizer { + public: // signals + esignal::Signal> signalChange; + public: + eproperty::Value> propertyValue; + protected: + ColorChooser(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(ColorChooser, "ColorChooser"); + virtual ~ColorChooser(); + private: + ewol::widget::ColorBarShared m_widgetColorBar; + ewol::widget::SliderShared m_widgetRed; + ewol::widget::SliderShared m_widgetGreen; + ewol::widget::SliderShared m_widgetBlue; + ewol::widget::SliderShared m_widgetAlpha; + void onCallbackColorChangeRed(const float& _newColor); + void onCallbackColorChangeGreen(const float& _newColor); + void onCallbackColorChangeBlue(const float& _newColor); + void onCallbackColorChangeAlpha(const float& _newColor); + void onCallbackColorChange(const etk::Color<>& _newColor); + protected: + virtual void onChangePropertyValue(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/meta/FileChooser.cpp b/src/org/atriasoft/ewol/widget/meta/FileChooser.cpp new file mode 100644 index 0000000..3e20f9c --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/FileChooser.cpp @@ -0,0 +1,197 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include + +extern "C" { + // file browsing ... + #include +} + +#include +#include +ETK_DECLARE_TYPE(ewol::widget::FileChooser); + +ewol::widget::FileChooser::FileChooser() : + signalCancel(this, "cancel", ""), + signalValidate(this, "validate", ""), + propertyPath(this, "path", + etk::path::getHomePath(), + "", + &ewol::widget::FileChooser::onChangePropertyPath), + propertyFile(this, "file", + "", + "", + &ewol::widget::FileChooser::onChangePropertyFile), + propertyLabelTitle(this, "title", + "_T{FileChooser}", + "", + &ewol::widget::FileChooser::onChangePropertyLabelTitle), + propertyLabelValidate(this, "label-validate", + "_T{Validate}", + "", + &ewol::widget::FileChooser::onChangePropertyLabelValidate), + propertyLabelCancel(this, "label-cancel", + "_T{Cancel}", + "", + &ewol::widget::FileChooser::onChangePropertyLabelCancel) { + addObjectType("ewol::widget::FileChooser"); +} + +void ewol::widget::FileChooser::init() { + ewol::widget::Composer::init(); + // Load file with replacing the "{ID}" with the local ID of the widget ==> obtain unique ID + loadFromFile("DATA:///ewol-gui-file-chooser.xml?lib=ewol", getId()); + // Basic replacement of labels + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:title-label", "value", propertyLabelTitle); + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:validate-label", "value", propertyLabelValidate); + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:cancel-label", "value", propertyLabelCancel); + + subBind(ewol::widget::CheckBox, "[" + etk::toString(getId()) + "]file-shooser:show-hiden-file", signalValue, sharedFromThis(), &ewol::widget::FileChooser::onCallbackHidenFileChangeChangeValue); + subBind(ewol::widget::Button, "[" + etk::toString(getId()) + "]file-shooser:button-validate", signalPressed, sharedFromThis(), &ewol::widget::FileChooser::onCallbackListValidate); + subBind(ewol::widget::Button, "[" + etk::toString(getId()) + "]file-shooser:button-cancel", signalPressed, sharedFromThis(), &ewol::widget::FileChooser::onCallbackButtonCancelPressed); + subBind(ewol::widget::ListFileSystem, "[" + etk::toString(getId()) + "]file-shooser:list-folder", signalFolderValidate, sharedFromThis(), &ewol::widget::FileChooser::onCallbackListFolderSelectChange); + subBind(ewol::widget::ListFileSystem, "[" + etk::toString(getId()) + "]file-shooser:list-files", signalFileSelect, sharedFromThis(), &ewol::widget::FileChooser::onCallbackListFileSelectChange); + subBind(ewol::widget::ListFileSystem, "[" + etk::toString(getId()) + "]file-shooser:list-files", signalFileValidate, sharedFromThis(), &ewol::widget::FileChooser::onCallbackListFileValidate); + subBind(ewol::widget::Entry, "[" + etk::toString(getId()) + "]file-shooser:entry-file", signalModify, sharedFromThis(), &ewol::widget::FileChooser::onCallbackEntryFileChangeValue); + subBind(ewol::widget::Entry, "[" + etk::toString(getId()) + "]file-shooser:entry-file", signalEnter, sharedFromThis(), &ewol::widget::FileChooser::onCallbackEntryFileChangeValidate); + subBind(ewol::widget::Entry, "[" + etk::toString(getId()) + "]file-shooser:entry-folder", signalModify, sharedFromThis(), &ewol::widget::FileChooser::onCallbackEntryFolderChangeValue); + //composerBind(ewol::widget::CheckBox, "[" + etk::toString(getId()) + "]file-shooser:entry-folder", signalEnter, sharedFromThis(), &ewol::widget::FileChooser::); + subBind(ewol::widget::Image, "[" + etk::toString(getId()) + "]file-shooser:img-home", signalPressed, sharedFromThis(), &ewol::widget::FileChooser::onCallbackHomePressed); + // set the default Folder properties: + updateCurrentFolder(); + propertyCanFocus.set(true); +} + +void ewol::widget::FileChooser::onGetFocus() { + // transfert focus on a specific widget... + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:entry-file", "focus", "true"); +} + +ewol::widget::FileChooser::~FileChooser() { + +} + +void ewol::widget::FileChooser::onChangePropertyPath() { + propertyPath.getDirect() = *propertyPath + "/"; + updateCurrentFolder(); +} + +void ewol::widget::FileChooser::onChangePropertyFile() { + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:entry-file", "value", propertyFile->getFileName()); + //updateCurrentFolder(); +} + +void ewol::widget::FileChooser::onChangePropertyLabelTitle() { + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:title-label", "value", propertyLabelTitle); +} + +void ewol::widget::FileChooser::onChangePropertyLabelValidate() { + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:validate-label", "value", propertyLabelValidate); +} + +void ewol::widget::FileChooser::onChangePropertyLabelCancel() { + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:cancel-label", "value", propertyLabelCancel); +} + +void ewol::widget::FileChooser::onCallbackEntryFolderChangeValue(const etk::String& _value) { + // == > change the folder name + // TODO : change the folder, if it exit ... +} + +void ewol::widget::FileChooser::onCallbackEntryFileChangeValue(const etk::String& _value) { + // == > change the file name.get(.get( + propertyFile.setDirect(_value); + // update the selected file in the list : + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:list-files", "select", propertyFile.getString()); +} + +void ewol::widget::FileChooser::onCallbackButtonCancelPressed() { + // == > Auto remove ... + signalCancel.emit(); + autoDestroy(); +} + +void ewol::widget::FileChooser::onCallbackHidenFileChangeChangeValue(const bool& _value) { + if (_value == true) { + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:list-folder", "show-hidden", "true"); + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:list-files", "show-hidden", "true"); + } else { + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:list-folder", "show-hidden", "false"); + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:list-files", "show-hidden", "false"); + } +} + +void ewol::widget::FileChooser::onCallbackListFolderSelectChange(const etk::Path& _value) { + // == > this is an internal event ... + EWOL_DEBUG(" old PATH: '" << *propertyPath << "' ==> '" << _value << "'"); + propertyPath.setDirect(_value); + EWOL_DEBUG("new PATH: '" << *propertyPath << "'"); + propertyFile.setDirect(""); + updateCurrentFolder(); +} + +void ewol::widget::FileChooser::onCallbackListFileSelectChange(const etk::Path& _value) { + propertyFile.set(_value); + /* + etk::String tmpFileCompleatName = m_folder; + tmpFileCompleatName += m_file; + // TODO : generateEventId(_msg.getMessage(), tmpFileCompleatName); + */ +} + +void ewol::widget::FileChooser::onCallbackListFileValidate(const etk::Path& _value) { + // select the file == > generate a validate + propertyFile.set(_value); + EWOL_VERBOSE(" generate a fiel opening : '" << propertyFile << "'"); + signalValidate.emit(_value); + autoDestroy(); +} + +void ewol::widget::FileChooser::onCallbackEntryFileChangeValidate(const etk::String& _value) { + onCallbackListFileValidate(_value); +} + +void ewol::widget::FileChooser::onCallbackListValidate() { + if (propertyFile.get() == "") { + EWOL_WARNING(" Validate : '" << *propertyFile << "' ==> error No name ..."); + return; + } + EWOL_DEBUG(" generate a file opening : '" << *propertyFile << "'"); + signalValidate.emit(*propertyFile); + autoDestroy(); +} + +void ewol::widget::FileChooser::onCallbackHomePressed() { + etk::Path tmpUserFolder = etk::path::getHomePath(); + EWOL_DEBUG("new PATH: '" << tmpUserFolder << "'"); + + propertyPath.setDirect(tmpUserFolder); + propertyFile.setDirect(""); + updateCurrentFolder(); +} + +void ewol::widget::FileChooser::updateCurrentFolder() { + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:list-files", "path", propertyPath.getString()); + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:list-folder", "path", propertyPath.getString()); + propertySetOnWidgetNamed("[" + etk::toString(getId()) + "]file-shooser:entry-folder", "value", propertyPath.getString()); + markToRedraw(); +} diff --git a/src/org/atriasoft/ewol/widget/meta/FileChooser.java b/src/org/atriasoft/ewol/widget/meta/FileChooser.java new file mode 100644 index 0000000..0df12f4 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/FileChooser.java @@ -0,0 +1,106 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include + +namespace ewol { + namespace widget { + class FileChooser; + using FileChooserShared = ememory::SharedPtr; + using FileChooserWeak = ememory::WeakPtr; + /** + * @brief File Chooser is a simple selector of file for opening, saving, and what you want ... + * + * As all other pop-up methode ( wost case we can have) the creating is simple , but event back is not all the time simple: + * + * Fist global static declaration and inclusion: + * [code style=c++] + * #include + * [/code] + * + * The first step is to create the file chooser pop-up : (never in the constructor!!!) + * [code style=c++] + * ewol::widget::FileChooserShared tmpWidget = ewol::widget::FileChooser::create(); + * if (tmpWidget == null) { + * APPL_ERROR("Can not open File chooser !!! "); + * return -1; + * } + * // register on the Validate event: + * tmpWidget->signalValidate.connect(sharedFromThis(), &****::onCallbackOpenFile); + * // no need of this event watching ... + * tmpWidget->signalCancel.connect(sharedFromThis(), &****::onCallbackClosePopUp); + * // set the title: + * tmpWidget->propertyLabelTitle.set("Open files ..."); + * // Set the validate Label: + * tmpWidget->propertyLabelValidate.set("Open"); + * // simply set a folder (by default this is the home folder) + * //tmpWidget->propertyPath.set("/home/me"); + * // add the widget as windows pop-up ... + * ewol::widget::WindowsShared tmpWindows = getWindows(); + * if (tmpWindows == null) { + * APPL_ERROR("Can not get the current windows !!! "); + * return -1; + * } + * tmpWindows->popUpWidgetPush(tmpWidget); + * [/code] + * + * Now we just need to wait the the open event message. + * + * [code style=c++] + * void ****::onCallbackOpenFile(const etk::String& _value) { + * APPL_INFO("Request open file : '" << _value << "'"); + * } + * void ****::onCallbackClosePopUp() { + * APPL_INFO("The File chooser has been closed"); + * } + * [/code] + * This is the best example of a Meta-widget. + */ + class FileChooser : public ewol::widget::Composer { + public: // signals + esignal::Signal<> signalCancel; //!< abort the display of the pop-up or press cancel button + esignal::Signal signalValidate; //!< select file(s) + public: // properties + eproperty::Value propertyPath; //!< Current path to explore + eproperty::Value propertyFile; //!< Selected file + eproperty::Value propertyLabelTitle; //!< Label of the pop-up (can use translation) + eproperty::Value propertyLabelValidate; //!< Label of validate button of the pop-up (can use translation) + eproperty::Value propertyLabelCancel; //!< Label of cancel/close button of the pop-up (can use translation) + protected: + FileChooser(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(FileChooser, "FileChooser"); + virtual ~FileChooser(); + private: + void updateCurrentFolder(); + public: + void onGetFocus() override; + private: + // callback functions: + void onCallbackEntryFolderChangeValue(const etk::String& _value); + void onCallbackEntryFileChangeValue(const etk::String& _value); + void onCallbackEntryFileChangeValidate(const etk::String& _value); + void onCallbackButtonCancelPressed(); + void onCallbackHidenFileChangeChangeValue(const bool& _value); + void onCallbackListFolderSelectChange(const etk::Path& _value); + void onCallbackListFileSelectChange(const etk::Path& _value); + void onCallbackListFileValidate(const etk::Path& _value); + void onCallbackListValidate(); + void onCallbackHomePressed(); + protected: + virtual void onChangePropertyPath(); + virtual void onChangePropertyFile(); + virtual void onChangePropertyLabelTitle(); + virtual void onChangePropertyLabelValidate(); + virtual void onChangePropertyLabelCancel(); + }; + }; +}; diff --git a/src/org/atriasoft/ewol/widget/meta/Parameter.cpp b/src/org/atriasoft/ewol/widget/meta/Parameter.cpp new file mode 100644 index 0000000..822ec25 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/Parameter.cpp @@ -0,0 +1,255 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::Parameter); + +ewol::widget::Parameter::Parameter() : + signalClose(this, "close", ""), + propertyLabelTitle(this, "title", + "_T{Parameter}", + "Title of the parameter interface", + &ewol::widget::Parameter::onChangePropertyLabelTitle), + m_currentIdList(0), + m_widgetTitle(), + m_paramList() { + addObjectType("ewol::widget::Parameter"); +} + +void ewol::widget::Parameter::init() { + ewol::widget::PopUp::init(); + + ewol::widget::SizerShared mySizerVert = null; + ewol::widget::SizerShared mySizerHori = null; + ewol::widget::SpacerShared mySpacer = null; + #ifdef __TARGET_OS__Android + propertyMinSize.set(gale::Dimension(vec2(90, 90), gale::distance::pourcent)); + #else + propertyMinSize.set(gale::Dimension(vec2(80, 80), gale::distance::pourcent)); + #endif + + mySizerVert = ewol::widget::Sizer::create(); + if (mySizerVert == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + EWOL_INFO("add widget"); + mySizerVert->propertyMode.set(widget::Sizer::modeVert); + mySizerVert->propertyLockExpand.set(bvec2(true,true)); + mySizerVert->propertyExpand.set(bvec2(true,true)); + // set it in the pop-up-system : + setSubWidget(mySizerVert); + + mySizerHori = ewol::widget::Sizer::create(); + if (mySizerHori == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + mySizerHori->propertyMode.set(widget::Sizer::modeHori); + mySizerVert->subWidgetAdd(mySizerHori); + + mySpacer = ewol::widget::Spacer::create(); + if (mySpacer == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + mySpacer->propertyExpand.set(bvec2(true,false)); + mySizerHori->subWidgetAdd(mySpacer); + } + + ewol::widget::ButtonShared tmpButton = widget::Button::create(); + if (tmpButton == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + tmpButton->setSubWidget(ewol::widget::composerGenerateString( + "\n" + " \n" + " \n" + "\n")); + tmpButton->signalPressed.connect(sharedFromThis(), &ewol::widget::Parameter::onCallbackParameterSave); + mySizerHori->subWidgetAdd(tmpButton); + } + + mySpacer = ewol::widget::Spacer::create(); + if (mySpacer == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + mySpacer->propertyExpand.set(bvec2(false,false)); + mySpacer->propertyMinSize.set(gale::Dimension(vec2(10,0))); + mySizerHori->subWidgetAdd(mySpacer); + } + + tmpButton = ewol::widget::Button::create(); + if (tmpButton == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + tmpButton->setSubWidget(ewol::widget::composerGenerateString( + "\n" + " \n" + " \n" + "\n")); + tmpButton->signalPressed.connect(sharedFromThis(), &ewol::widget::Parameter::onCallbackMenuclosed); + mySizerHori->subWidgetAdd(tmpButton); + } + } + + mySizerHori = ewol::widget::Sizer::create(); + if (mySizerHori == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + mySizerHori->propertyMode.set(widget::Sizer::modeHori); + mySizerVert->subWidgetAdd(mySizerHori); + + m_paramList = ewol::widget::ParameterList::create(); + if (m_paramList == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + + m_paramList->signalSelect.connect(sharedFromThis(), &ewol::widget::Parameter::onCallbackMenuSelected); + m_paramList->propertyFill.set(bvec2(false,true)); + m_paramList->propertyExpand.set(bvec2(false,true)); + mySizerHori->subWidgetAdd(m_paramList); + } + mySpacer = ewol::widget::Spacer::create(); + if (mySpacer == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + mySpacer->propertyFill.set(bvec2(false,true)); + mySpacer->propertyMinSize.set(vec2(5,5)); + mySpacer->propertyColor.set(0x000000BF); + mySizerHori->subWidgetAdd(mySpacer); + } + + ewol::widget::SizerShared mySizerVert2 = widget::Sizer::create(); + if (mySizerVert2 == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + mySizerVert2->propertyMode.set(widget::Sizer::modeVert); + mySizerHori->subWidgetAdd(mySizerVert2); + + mySpacer = ewol::widget::Spacer::create(); + if (mySpacer == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + mySpacer->propertyExpand.set(bvec2(true,false)); + mySpacer->propertyMinSize.set(vec2(5,5)); + mySpacer->propertyColor.set(0x000000BF); + mySizerVert2->subWidgetAdd(mySpacer); + } + + m_wSlider = ewol::widget::WSlider::create(); + if (m_wSlider == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + m_wSlider->propertyTransitionSpeed.set(0.5); + m_wSlider->propertyTransitionMode.set(ewol::widget::WSlider::sladingTransitionVert); + m_wSlider->propertyExpand.set(bvec2(true,true)); + mySizerVert2->subWidgetAdd(m_wSlider); + } + } + } + + mySpacer = ewol::widget::Spacer::create(); + if (mySpacer == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + mySpacer->propertyExpand.set(bvec2(true,false)); + mySpacer->propertyMinSize.set(vec2(5,5)); + mySpacer->propertyColor.set(0x000000BF); + mySizerVert->subWidgetAdd(mySpacer); + } + + m_widgetTitle = ewol::widget::Label::create(); + if (m_widgetTitle == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + m_widgetTitle->propertyValue.set(propertyLabelTitle); + m_widgetTitle->propertyExpand.set(bvec2(true,false)); + mySizerVert->subWidgetAdd(m_widgetTitle); + } + } + markToRedraw(); +} + +ewol::widget::Parameter::~Parameter() { + +} + +void ewol::widget::Parameter::onChangePropertyLabelTitle() { + if (m_widgetTitle != null) { + m_widgetTitle->propertyValue.set(propertyLabelTitle); + } +} + +void ewol::widget::Parameter::onCallbackMenuclosed() { + // inform that the parameter windows is closed + signalClose.emit(); + // close this widget ... + autoDestroy(); +} +void ewol::widget::Parameter::onCallbackParameterSave() { + //ewol::userConfig::Save(); + EWOL_TODO("Save Parameter !!! "); +} +void ewol::widget::Parameter::onCallbackMenuSelected(const int32_t& _value) { + if (m_wSlider != null) { + EWOL_DEBUG("event on the parameter : Menu-select select ID=" << _value << ""); + m_wSlider->subWidgetSelectSet(_value); + } +} + +void ewol::widget::Parameter::menuAdd(etk::String _label, etk::String _image, ewol::WidgetShared _associateWidget) { + if (m_paramList != null) { + m_paramList->menuAdd(_label, m_currentIdList, _image); + if (m_wSlider != null) { + if (_associateWidget != null) { + m_wSlider->subWidgetAdd(_associateWidget); + } else { + EWOL_DEBUG("Associate an empty widget on it ..."); + ewol::widget::LabelShared myLabel = widget::Label::create(); + if (myLabel == null) { + EWOL_ERROR("Can not allocate widget == > display might be in error"); + } else { + myLabel->propertyValue.set(etk::String("No widget for : ") + _label); + myLabel->propertyExpand.set(bvec2(true,true)); + m_wSlider->subWidgetAdd(myLabel); + } + } + if (m_currentIdList == 0) { + m_wSlider->subWidgetSelectSet(0); + } + } + m_currentIdList++; + } +} +void ewol::widget::Parameter::menuAddGroup(etk::String _label) { + if (m_paramList != null) { + m_paramList->menuSeparator(); + m_paramList->menuAddGroup(_label); + } +} + +void ewol::widget::Parameter::menuClear() { + if (m_paramList != null) { + m_paramList->menuClear(); + m_currentIdList = 0; + } +} + +void ewol::widget::Parameter::menuSeparator() { + if (m_paramList != null) { + m_paramList->menuSeparator(); + } +} + diff --git a/src/org/atriasoft/ewol/widget/meta/Parameter.java b/src/org/atriasoft/ewol/widget/meta/Parameter.java new file mode 100644 index 0000000..44dbbbf --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/Parameter.java @@ -0,0 +1,58 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace ewol { + namespace widget { + class Parameter; + using ParameterShared = ememory::SharedPtr; + using ParameterWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class Parameter : public ewol::widget::PopUp { + public: // signals + esignal::Signal<> signalClose; + public: // properties + eproperty::Value propertyLabelTitle; + protected: + Parameter(); + void init(); + public: + DECLARE_WIDGET_FACTORY(Parameter, "Parameter"); + virtual ~Parameter(); + public: + void menuAdd(etk::String _label, etk::String _image, ewol::WidgetShared _associateWidget); + void menuAddGroup(etk::String _label); + void menuClear(); + void menuSeparator(); + private: + int32_t m_currentIdList; + ewol::widget::LabelShared m_widgetTitle; + ewol::widget::ParameterListShared m_paramList; + ewol::widget::WSliderShared m_wSlider; + private: + void onCallbackMenuclosed(); + void onCallbackParameterSave(); + void onCallbackMenuSelected(const int32_t& _value); + protected: + virtual void onChangePropertyLabelTitle(); + }; + }; +}; + diff --git a/src/org/atriasoft/ewol/widget/meta/ParameterList.cpp b/src/org/atriasoft/ewol/widget/meta/ParameterList.cpp new file mode 100644 index 0000000..58667bb --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/ParameterList.cpp @@ -0,0 +1,241 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include +ETK_DECLARE_TYPE(ewol::widget::ParameterList); + +ewol::widget::ParameterList::ParameterList() : + signalSelect(this, "select", "") { + addObjectType("ewol::widget::ParameterList"); + + m_idSelected = -1; + m_paddingSizeX = 2; + #ifdef __TARGET_OS__Android + m_paddingSizeY = 10; + #else + m_paddingSizeY = 2; + #endif +} + +void ewol::widget::ParameterList::init() { + ewol::widget::WidgetScrolled::init(); + propertyCanFocus.set(true); +} + +ewol::widget::ParameterList::~ParameterList() { + //clean all the object + m_listOObject.clear(); + menuClear(); +} + +void ewol::widget::ParameterList::calculateMinMaxSize() { + /*int32_t fontId = getDefaultFontId(); + int32_t minWidth = ewol::getWidth(fontId, m_label); + int32_t minHeight = ewol::getHeight(fontId); + m_minSize.x = 3+minWidth; + m_minSize.y = 3+minHeight; + */ + m_minSize.setValue(150, 150); +} + +void ewol::widget::ParameterList::addOObject(const ememory::SharedPtr& _newObject, int32_t _pos) { + if (_newObject == null) { + EWOL_ERROR("Try to add an empty object in the Widget generic display system"); + return; + } + if (_pos < 0 || (size_t)_pos >= m_listOObject.size() ) { + m_listOObject.pushBack(_newObject); + } else { + m_listOObject.insert(m_listOObject.begin()+_pos, _newObject); + } +} + +void ewol::widget::ParameterList::clearOObjectList() { + m_listOObject.clear(); +} + +void ewol::widget::ParameterList::onDraw() { + for (auto &it : m_listOObject) { + if (it != null) { + it->draw(); + } + } + WidgetScrolled::onDraw(); +} + +void ewol::widget::ParameterList::onRegenerateDisplay() { + if (needRedraw() == true) { + // clean the object list ... + clearOObjectList(); + //EWOL_DEBUG("OnRegenerateDisplay(" << m_size.x << "," << m_size.y << ")"); + + int32_t tmpOriginX = 0; + int32_t tmpOriginY = 0; + /* + if (true == m_userFill.x) { + tmpOriginX = 0; + } + if (true == m_userFill.y) { + tmpOriginY = 0; + }*/ + tmpOriginX += m_paddingSizeX; + tmpOriginY += m_paddingSizeY; + + /* + int32_t fontId = getDefaultFontId(); + //int32_t minWidth = ewol::getWidth(fontId, m_label); + int32_t minHeight = ewol::getHeight(fontId); + */ + // TODO : Rework this ... + int32_t minHeight=20; + + //uint32_t nbColomn = getNuberOfColomn(); + int32_t nbRaw = m_list.size(); + // For the scrooling windows + m_maxSize.setValue(m_size.x(), + (minHeight + 2*m_paddingSizeY) * nbRaw ); + + + etk::Vector listSizeColomn; + + // set background color : + ememory::SharedPtr tmpDraw = ememory::makeShared(); + if (tmpDraw == null) { + return; + } + tmpDraw->setColor(etk::Color<>(0xFF, 0xFF, 0xFF, 0xFF)); + tmpDraw->setPos(vec3(0,0,0) ); + tmpDraw->rectangleWidth(vec3(m_size.x(), m_size.y(), 0) ); + + uint32_t displayableRaw = m_size.y() / (minHeight + 2*m_paddingSizeY) +2; + + int32_t startRaw = m_originScrooled.y() / (minHeight + 2*m_paddingSizeY); + + if (startRaw >= nbRaw-1 ) { + startRaw = nbRaw - 1; + } + if (startRaw<0) { + startRaw = 0; + } + // calculate the real position ... + tmpOriginY = m_size.y() - (-m_originScrooled.y() + (startRaw+1)*(minHeight + 2*m_paddingSizeY)); + + for (int32_t iii=startRaw; iii fg(0x00, 0x00, 0x00, 0xFF); + if (m_list[iii] != null) { + myTextToWrite = TRANSLATE(m_list[iii]->m_label); + } + + ememory::SharedPtr tmpText = ememory::makeShared(); + + vec3 textPos; + textPos.setX((int32_t)tmpOriginX); + if (m_list[iii]->m_group == false) { + textPos.setX(textPos.x() + minHeight); + } + textPos.setY((int32_t)(tmpOriginY + m_paddingSizeY)); + tmpText->setPos(textPos); + tmpText->print(myTextToWrite); + + addOObject(tmpText); + tmpOriginY -= minHeight + 2* m_paddingSizeY; + } + addOObject(tmpDraw, 0); + + // call the herited class... + ewol::widget::WidgetScrolled::onRegenerateDisplay(); + } +} + + +bool ewol::widget::ParameterList::onEventInput(const ewol::event::Input& _event) { + if (true == WidgetScrolled::onEventInput(_event)) { + keepFocus(); + // nothing to do ... done on upper widet ... + return true; + } + if (_event.getId() == 1 && _event.getStatus() == gale::key::status::pressSingle) { + vec2 relativePos = relativePosition(_event.getPos()); + // corection for the openGl abstraction + relativePos.setY(m_size.y() - relativePos.y()); + // TODO : Rework this ... + /* + int32_t fontId = getDefaultFontId(); + //int32_t minWidth = ewol::getWidth(fontId, m_label.c_str()); + int32_t minHeight = ewol::getHeight(fontId); + */ + int32_t minHeight = 20; + int32_t rawID = (relativePos.y()+m_originScrooled.y()) / (minHeight + 2*m_paddingSizeY); + // generate an event on a rawId if the element request change and Select it ... + if (rawID >= 0 && (size_t)rawID < m_list.size()) { + if (m_list[rawID]!=null) { + if (m_list[rawID]->m_refId >= 0) { + signalSelect.emit(m_list[rawID]->m_refId); + m_idSelected = rawID; + markToRedraw(); + return true; + } + } + } + } + return false; +} + +void ewol::widget::ParameterList::onGetFocus() { + EWOL_DEBUG("Ewol::List get focus"); +} + +void ewol::widget::ParameterList::onLostFocus() { + EWOL_DEBUG("Ewol::List Lost focus"); +} + +void ewol::widget::ParameterList::menuAdd(etk::String& _label, int32_t _refId, etk::String& _image) { + ememory::SharedPtr tmpEmement = ememory::makeShared(_label, _refId, _image, false); + if (tmpEmement == null) { + EWOL_ERROR("Can not allocacte menu parameter"); + return; + } + m_list.pushBack(tmpEmement); + if (m_idSelected == -1 && _label != "---" && _refId>0) { + m_idSelected = m_list.size()-1; + } + markToRedraw(); +} + +void ewol::widget::ParameterList::menuAddGroup(etk::String& _label) { + etk::String image = ""; + ememory::SharedPtr tmpEmement = ememory::makeShared(_label, -1, image, true); + if (tmpEmement == null) { + EWOL_ERROR("Can not allocacte menu parameter"); + return; + } + m_list.pushBack(tmpEmement); + markToRedraw(); +} + +void ewol::widget::ParameterList::menuClear() { + m_idSelected = -1; + m_list.clear(); +} + +void ewol::widget::ParameterList::menuSeparator() { + if (m_list.size()>0) { + etk::String label = ""; + etk::String image = ""; + menuAdd(label, -1, image); + } +} + diff --git a/src/org/atriasoft/ewol/widget/meta/ParameterList.java b/src/org/atriasoft/ewol/widget/meta/ParameterList.java new file mode 100644 index 0000000..fec2cf3 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/ParameterList.java @@ -0,0 +1,81 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#pragma once + +#include +#include +#include + +namespace ewol { + namespace widget { + class elementPL { + public : + bool m_group; + etk::String m_label; + int32_t m_refId; + etk::String m_image; + elementPL(etk::String& _label, int32_t _refId, etk::String& _image, bool _isGroup) : + m_group(_isGroup), + m_label(_label), + m_refId(_refId), + m_image(_image) { + + }; + virtual ~elementPL() {}; + }; + class ParameterList; + using ParameterListShared = ememory::SharedPtr; + using ParameterListWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class ParameterList :public ewol::widget::WidgetScrolled { + public: //signals + esignal::Signal signalSelect; + public: // properties + + private: + int32_t m_idSelected; + etk::Vector> m_list; + protected: + ParameterList(); + void init() override; + public: + DECLARE_WIDGET_FACTORY(ParameterList, "ParameterList"); + virtual ~ParameterList(); + void setLabel(etk::String _newLabel); + // drawing capabilities .... + private: + etk::Vector> m_listOObject; //!< generic element to display... + public: + void addOObject(const ememory::SharedPtr& _newObject, int32_t _pos=-1); + void clearOObjectList(); + // list properties ... + private: + int32_t m_paddingSizeX; + int32_t m_paddingSizeY; + int32_t m_displayStartRaw; //!< Current starting diaplayed raw + int32_t m_displayCurrentNbLine; //!< Number of line in the display + public: + void menuAdd(etk::String& _label, int32_t _refId, etk::String& _image); + void menuAddGroup(etk::String& _label); + void menuClear(); + void menuSeparator(); + + public: + void onRegenerateDisplay() override; + bool onEventInput(const ewol::event::Input& _event) override; + void calculateMinMaxSize() override; + protected: + void onGetFocus() override; + void onLostFocus() override; + void onDraw() override; + }; + }; +}; + + diff --git a/src/org/atriasoft/ewol/widget/meta/SpinBase.cpp b/src/org/atriasoft/ewol/widget/meta/SpinBase.cpp new file mode 100644 index 0000000..c768110 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/SpinBase.cpp @@ -0,0 +1,152 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::SpinBase); +ETK_DECLARE_TYPE(enum ewol::widget::spinPosition); + +ewol::widget::SpinBase::SpinBase() : + propertyShape(this, "shape", + "", + "shape for the display", + &ewol::widget::SpinBase::onChangePropertyShape), + propertySpinMode(this, "spin-mode", + ewol::widget::spinPosition_RightRight, + "The display spin mode", + &ewol::widget::SpinBase::onChangePropertySpinMode), + m_confIdEntryShaper(-1), + m_confIdUpShaper(-1), + m_confIdDownShaper(-1), + m_confIdUpData(-1), + m_confIdDownData(-1) { + + addObjectType("ewol::widget::SpinBase"); + propertySpinMode.add(ewol::widget::spinPosition_noneNone, "none-none"); + propertySpinMode.add(ewol::widget::spinPosition_noneRight, "none-right"); + propertySpinMode.add(ewol::widget::spinPosition_leftNone, "left-none"); + propertySpinMode.add(ewol::widget::spinPosition_leftRight, "left-right"); + propertySpinMode.add(ewol::widget::spinPosition_leftLeft, "left-left"); + propertySpinMode.add(ewol::widget::spinPosition_RightRight, "right-right"); + propertyLockExpand.setDirectCheck(bvec2(true,true)); + propertyGravity.setDirectCheck(gravity_center); +} + +void ewol::widget::SpinBase::init() { + ewol::widget::Sizer::init(); + propertyShape.notifyChange(); + updateGui(); +} + +ewol::widget::SpinBase::~SpinBase() { + +} + +void ewol::widget::SpinBase::onChangePropertySpinMode() { + updateGui(); +} + +void ewol::widget::SpinBase::onChangePropertyShape() { + m_config = ewol::resource::ConfigFile::create(propertyShape); + if (m_config != null) { + m_confIdEntryShaper = m_config->request("entry-shaper"); + m_confIdUpShaper = m_config->request("up-shaper"); + m_confIdDownShaper = m_config->request("down-shaper"); + m_confIdUpData = m_config->request("up-data"); + m_confIdDownData = m_config->request("down-data"); + } + markToRedraw(); +} + + + +void ewol::widget::SpinBase::updateGui() { + subWidgetRemoveAll(); + markToRedraw(); + requestUpdateSize(); + if (m_widgetEntry == null) { + etk::String shaper; + if (m_config != null) { + shaper = m_config->getString(m_confIdEntryShaper); + EWOL_VERBOSE("shaper entry : " << shaper); + } + m_widgetEntry = ewol::widget::Entry::create("shape", shaper); + if (m_widgetEntry != null) { + m_widgetEntry->propertyExpand.set(bvec2(true,false)); + m_widgetEntry->propertyFill.set(bvec2(true,true)); + } + } + if (m_widgetButtonDown == null) { + etk::String shaper; + if (m_config != null) { + shaper = m_config->getString(m_confIdDownShaper); + EWOL_VERBOSE("shaper button DOWN : " << shaper); + } + m_widgetButtonDown = ewol::widget::Button::create("shape", shaper); + if (m_widgetButtonDown != null) { + m_widgetButtonDown->propertyExpand.set(bvec2(false,false)); + m_widgetButtonDown->propertyFill.set(bvec2(true,true)); + etk::String data = m_config->getString(m_confIdDownData); + ewol::WidgetShared widget = ewol::widget::composerGenerateString(data); + m_widgetButtonDown->setSubWidget(widget); + } + } + if (m_widgetButtonUp == null) { + etk::String shaper; + if (m_config != null) { + shaper = m_config->getString(m_confIdUpShaper); + EWOL_VERBOSE("shaper button UP : " << shaper); + } + m_widgetButtonUp = ewol::widget::Button::create("shape", shaper); + if (m_widgetButtonUp != null) { + m_widgetButtonUp->propertyExpand.set(bvec2(false,false)); + m_widgetButtonUp->propertyFill.set(bvec2(true,true)); + etk::String data = m_config->getString(m_confIdUpData); + ewol::WidgetShared widget = ewol::widget::composerGenerateString(data); + m_widgetButtonUp->setSubWidget(widget); + } + } + switch (propertySpinMode) { + case ewol::widget::spinPosition_noneNone: + subWidgetAdd(m_widgetEntry); + break; + case ewol::widget::spinPosition_noneRight: + subWidgetAdd(m_widgetEntry); + subWidgetAdd(m_widgetButtonUp); + break; + case ewol::widget::spinPosition_leftNone: + subWidgetAdd(m_widgetButtonDown); + subWidgetAdd(m_widgetEntry); + break; + case ewol::widget::spinPosition_leftRight: + subWidgetAdd(m_widgetButtonDown); + subWidgetAdd(m_widgetEntry); + subWidgetAdd(m_widgetButtonUp); + break; + case ewol::widget::spinPosition_leftLeft: + subWidgetAdd(m_widgetButtonDown); + subWidgetAdd(m_widgetButtonUp); + subWidgetAdd(m_widgetEntry); + break; + case ewol::widget::spinPosition_RightRight: + subWidgetAdd(m_widgetEntry); + subWidgetAdd(m_widgetButtonDown); + subWidgetAdd(m_widgetButtonUp); + break; + } +} + +bool ewol::widget::SpinBase::loadXML(const exml::Element& _node) { + if (_node.exist() == false) { + return false; + } + // parse generic properties: (we not parse the sizer property, it remove all subwidget) + return ewol::Widget::loadXML(_node); +} \ No newline at end of file diff --git a/src/org/atriasoft/ewol/widget/meta/SpinBase.java b/src/org/atriasoft/ewol/widget/meta/SpinBase.java new file mode 100644 index 0000000..9dbdff5 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/SpinBase.java @@ -0,0 +1,102 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ewol { + namespace widget { + enum spinPosition { + /** show like: + * *------------------------* + * | | + * *------------------------* + */ + spinPosition_noneNone, + /** show like: + * *--------------------*---* + * | | | + * *--------------------*---* + */ + spinPosition_noneRight, + /** show like: + * *---*--------------------* + * | | | + * *---*--------------------* + */ + spinPosition_leftNone, + /** show like: + * *---*----------------*---* + * | | | | + * *---*----------------*---* + */ + spinPosition_leftRight, + /** show like: + * *---*---*----------------* + * | | | | + * *---*---*----------------* + */ + spinPosition_leftLeft, + /** show like: + * *----------------*---*---* + * | | | | + * *----------------*---*---* + */ + spinPosition_RightRight + }; + class SpinBase; + using SpinBaseShared = ememory::SharedPtr; + using SpinBaseWeak = ememory::WeakPtr; + /** + * @ingroup ewolWidgetGroup + */ + class SpinBase : public ewol::widget::Sizer { + public: // properties list: + eproperty::Value propertyShape; //!< Shape of the widget + eproperty::List propertySpinMode; //!< How to display the spin base + public: + UN_DECLARE_FACTORY(SpinBase); + protected: + ememory::SharedPtr m_config; + int32_t m_confIdEntryShaper; + int32_t m_confIdUpShaper; + int32_t m_confIdDownShaper; + int32_t m_confIdUpData; + int32_t m_confIdDownData; + protected: + /** + * @brief Constructor + * @param[in] _mode The mode to display the elements + */ + SpinBase(); + void init() override; + public: + /** + * @brief Destructor + */ + virtual ~SpinBase(); + protected: + ewol::widget::EntryShared m_widgetEntry; + ewol::widget::ButtonShared m_widgetButtonDown; + ewol::widget::ButtonShared m_widgetButtonUp; + virtual void updateGui(); + public: + virtual bool loadXML(const exml::Element& _node) override; + protected: + virtual void onChangePropertySpinMode(); + virtual void onChangePropertyShape(); + }; + } +} + diff --git a/src/org/atriasoft/ewol/widget/meta/StdPopUp.cpp b/src/org/atriasoft/ewol/widget/meta/StdPopUp.cpp new file mode 100644 index 0000000..c41fa39 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/StdPopUp.cpp @@ -0,0 +1,132 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ + +#include +#include +#include +#include +#include +#include + +#include +ETK_DECLARE_TYPE(ewol::widget::StdPopUp); + +ewol::widget::StdPopUp::StdPopUp() : + propertyTitle(this, "title", + "Message", + "Title of the pop-up", + &ewol::widget::StdPopUp::onChangePropertyTitle), + propertyComment(this, "comment", + "No Label", + "Comment of the pop-up", + &ewol::widget::StdPopUp::onChangePropertyComment), + m_title(null), + m_comment(null), + m_subBar(null) { + addObjectType("ewol::widget::StdPopUp"); +} + +void ewol::widget::StdPopUp::init() { + ewol::widget::PopUp::init(); + propertyMinSize.set(gale::Dimension(vec2(20,10),gale::distance::pourcent)); + ewol::widget::SizerShared mySizerVert; + ewol::widget::SpacerShared mySpacer; + + mySizerVert = ewol::widget::Sizer::create(); + // set it in the pop-up-system : + setSubWidget(mySizerVert); + mySizerVert->propertyMode.set(widget::Sizer::modeVert); + m_subBar = ewol::widget::Sizer::create(); + m_subBar->propertyMode.set(widget::Sizer::modeHori); + m_subBar->propertyLockExpand.set(bvec2(true,true)); + m_subBar->propertyExpand.set(bvec2(true,false)); + mySizerVert->subWidgetAdd(m_subBar); + mySpacer = ewol::widget::Spacer::create(); + mySpacer->propertyExpand.set(bvec2(true,false)); + m_subBar->subWidgetAdd(mySpacer); + + mySpacer = ewol::widget::Spacer::create(); + mySpacer->propertyExpand.set(bvec2(true,false)); + mySpacer->propertyColor.set(etk::Color<>(0x88, 0x88, 0x88, 0xFF)); + mySpacer->propertyMinSize.set(gale::Dimension(vec2(0,3),gale::distance::pixel)); + mySizerVert->subWidgetAdd(mySpacer); + + mySpacer = ewol::widget::Spacer::create(); + mySpacer->propertyExpand.set(bvec2(true,false)); + mySpacer->propertyMinSize.set(gale::Dimension(vec2(0,5),gale::distance::pixel)); + mySizerVert->subWidgetAdd(mySpacer); + + m_comment = ewol::widget::Label::create(); + m_comment->propertyValue.set(*propertyComment); + m_comment->propertyExpand.set(bvec2(true,true)); + mySizerVert->subWidgetAdd(m_comment); + + mySpacer = ewol::widget::Spacer::create(); + mySpacer->propertyExpand.set(bvec2(true,false)); + mySpacer->propertyMinSize.set(gale::Dimension(vec2(0,5),gale::distance::pixel)); + mySizerVert->subWidgetAdd(mySpacer); + + mySpacer = ewol::widget::Spacer::create(); + mySpacer->propertyExpand.set(bvec2(true,false)); + mySpacer->propertyColor.set(etk::Color<>(0x88, 0x88, 0x88, 0xFF)); + mySpacer->propertyMinSize.set(gale::Dimension(vec2(0,3),gale::distance::pixel)); + mySizerVert->subWidgetAdd(mySpacer); + + m_title = ewol::widget::Label::create(); + m_title->propertyValue.set(*propertyTitle); + m_title->propertyExpand.set(bvec2(true,false)); + m_title->propertyFill.set(bvec2(true,true)); + mySizerVert->subWidgetAdd(m_title); +} + +ewol::widget::StdPopUp::~StdPopUp() { + +} + +void ewol::widget::StdPopUp::onChangePropertyTitle() { + if (m_title == null) { + return; + } + m_title->propertyValue.set(*propertyTitle); + markToRedraw(); +} + +void ewol::widget::StdPopUp::onChangePropertyComment() { + if (m_comment == null) { + return; + } + m_comment->propertyValue.set(*propertyComment); + markToRedraw(); +} + +ewol::widget::ButtonShared ewol::widget::StdPopUp::addButton(const etk::String& _text, bool _autoExit) { + if (m_subBar == null) { + EWOL_ERROR("button-bar does not existed ..."); + return null; + } + ewol::widget::ButtonShared myButton = widget::Button::create(); + if (myButton == null) { + EWOL_ERROR("Can not allocate new button ..."); + return null; + } + ewol::widget::LabelShared myLabel = ewol::widget::Label::create(); + if (myLabel == null) { + EWOL_ERROR("Can not allocate new label ..."); + return null; + } + myLabel->propertyValue.set(_text); + myButton->setSubWidget(myLabel); + if(_autoExit == true) { + myButton->signalPressed.connect(sharedFromThis(), &ewol::widget::StdPopUp::onCallBackButtonExit); + } + m_subBar->subWidgetAdd(myButton); + markToRedraw(); + return myButton; +} + +void ewol::widget::StdPopUp::onCallBackButtonExit() { + autoDestroy(); +} diff --git a/src/org/atriasoft/ewol/widget/meta/StdPopUp.java b/src/org/atriasoft/ewol/widget/meta/StdPopUp.java new file mode 100644 index 0000000..76d01e0 --- /dev/null +++ b/src/org/atriasoft/ewol/widget/meta/StdPopUp.java @@ -0,0 +1,81 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2011, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +#pragma once + +#include +#include +#include +#include +namespace ewol { + namespace widget { + class StdPopUp; + using StdPopUpShared = ememory::SharedPtr; + using StdPopUpWeak = ememory::WeakPtr; + /** + * @brief The std pop up widget is a siple message widget to notify user of some simple things, like: + * + * [pre] + * +---------------------------------+---+---+---+ + * | Windows name... | _ | O | X | + * +---------------------------------+---+---+---+ + * | | + * | | + * | | + * | +-------------------+ | + * | | Title: | | + * | | | | + * | | Message to diplay | | + * | | to user | | + * | | | | + * | | Close | | + * | +-------------------+ | + * | | + * | | + * | | + * +---------------------------------------------+ + * [/pre] + */ + class StdPopUp : public ewol::widget::PopUp { + public: // properties: + eproperty::Value propertyTitle; //!< Title of the pop-up + eproperty::Value propertyComment; //!< comment in the pop-up (can be decorated text) + protected: + /** + * @brief std-pop-up constructor. + */ + StdPopUp(); + void init(); + public: + DECLARE_WIDGET_FACTORY(StdPopUp, "StdPopUp"); + /** + * @brief std-pop-up destructor. + */ + virtual ~StdPopUp(); + protected: + ewol::widget::LabelShared m_title; //!< Title Label widget + /** + * @brief property callback when request a change of the title. + */ + void onChangePropertyTitle(); + ewol::widget::LabelShared m_comment; //!< Comment label widget + /** + * @brief property callback when request a change of the Comment. + */ + void onChangePropertyComment(); + protected: + ewol::widget::SizerShared m_subBar; //!< subwidget bar containing all the button. + public: + /** + * @brief Add a buttom button. + * @param[in] _text Decorated text to diplay in button. + */ + ewol::widget::ButtonShared addButton(const etk::String& _text, bool _autoExit=false); + public: + virtual void onCallBackButtonExit(); + }; + } +} + diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/test/src/test/atriasoft/etk/.keep b/test/src/test/atriasoft/etk/.keep new file mode 100644 index 0000000..e69de29 diff --git a/test/src/test/atriasoft/etk/Log.java b/test/src/test/atriasoft/etk/Log.java new file mode 100644 index 0000000..5c3b329 --- /dev/null +++ b/test/src/test/atriasoft/etk/Log.java @@ -0,0 +1,59 @@ +package test.atriasoft.etk; + +import io.scenarium.logger.LogLevel; +import io.scenarium.logger.Logger; + +public class Log { + private static final String LIB_NAME = "etk-test"; + private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME); + private static final boolean PRINT_CRITICAL = Logger.getNeedPrint(LIB_NAME, LogLevel.CRITICAL); + private static final boolean PRINT_ERROR = Logger.getNeedPrint(LIB_NAME, LogLevel.ERROR); + private static final boolean PRINT_WARNING = Logger.getNeedPrint(LIB_NAME, LogLevel.WARNING); + private static final boolean PRINT_INFO = Logger.getNeedPrint(LIB_NAME, LogLevel.INFO); + private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG); + private static final boolean PRINT_VERBOSE = Logger.getNeedPrint(LIB_NAME, LogLevel.VERBOSE); + private static final boolean PRINT_TODO = Logger.getNeedPrint(LIB_NAME, LogLevel.TODO); + private static final boolean PRINT_PRINT = Logger.getNeedPrint(LIB_NAME, LogLevel.PRINT); + + private Log() {} + + public static void print(String data) { + if (PRINT_PRINT) + Logger.print(LIB_NAME_DRAW, data); + } + + public static void critical(String data) { + if (PRINT_CRITICAL) + Logger.critical(LIB_NAME_DRAW, data); + } + + public static void error(String data) { + if (PRINT_ERROR) + Logger.error(LIB_NAME_DRAW, data); + } + + public static void warning(String data) { + if (PRINT_WARNING) + Logger.warning(LIB_NAME_DRAW, data); + } + + public static void info(String data) { + if (PRINT_INFO) + Logger.info(LIB_NAME_DRAW, data); + } + + public static void debug(String data) { + if (PRINT_DEBUG) + Logger.debug(LIB_NAME_DRAW, data); + } + + public static void verbose(String data) { + if (PRINT_VERBOSE) + Logger.verbose(LIB_NAME_DRAW, data); + } + + public static void todo(String data) { + if (PRINT_TODO) + Logger.todo(LIB_NAME_DRAW, data); + } +} diff --git a/test/src/test/atriasoft/etk/Log2.java b/test/src/test/atriasoft/etk/Log2.java new file mode 100644 index 0000000..6b57782 --- /dev/null +++ b/test/src/test/atriasoft/etk/Log2.java @@ -0,0 +1,18 @@ +package test.atriasoft.etk; + +import io.scenarium.logger.LogLevel; +import io.scenarium.logger.Logger; + +public class Log2 { + private static final String LIB_NAME = "etk-test-2"; + private static final String LIB_NAME_DRAW = Logger.getDrawableName(LIB_NAME); + private static final boolean PRINT_DEBUG = Logger.getNeedPrint(LIB_NAME, LogLevel.DEBUG); + + private Log2() {} + + public static void debug(String data) { + if (PRINT_DEBUG) + Logger.debug(LIB_NAME_DRAW, data); + } + +} diff --git a/test/src/test/atriasoft/etk/TestBasicLog.java b/test/src/test/atriasoft/etk/TestBasicLog.java new file mode 100644 index 0000000..6106c2c --- /dev/null +++ b/test/src/test/atriasoft/etk/TestBasicLog.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * Contributors: + * Edouard DUPIN - initial API and implementation + ******************************************************************************/ +package test.atriasoft.etk; + +import java.util.ArrayList; +import java.util.List; + +import io.scenarium.logger.Logger; + +import org.junit.Test; +import org.junit.jupiter.api.MethodOrderer.OrderAnnotation; +import org.junit.jupiter.api.Order; +//import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +@TestMethodOrder(OrderAnnotation.class) +public class TestBasicLog { + + @Test + @Order(1) + public void aaFirstInitialisation() { + List args = new ArrayList<>(); + args.add("--log-level=999"); + args.add("--log-level=1"); + args.add("--log-no-color"); + args.add("--log-color"); + args.add("--log-lib=sc-log-test+6"); + args.add("--log-lib=sc-log-test/6"); + args.add("--log-lib=sc-log-test:6"); + args.add("--log-lib=sc-log-test:verbose"); + args.add("--log-lib=sc-log-test2+3"); + args.add("--log-lib=sc-log-test"); + args.add("--log-with-stupid-parameter=sdkfjsqdlkf"); + args.add("--help"); + Logger.init(args); + } + + @Test + @Order(2) + public void bbSecondInitialisation() { + List args = new ArrayList<>(); + Logger.init(args); + } + + @Test + @Order(3) + public void ccBasicLogCall() { + Log.print("Simple print"); + Log.todo("Simple todo"); + Log.error("Simple error"); + Log.warning("Simple warning"); + Log.info("Simple info"); + Log.debug("Simple debug"); + Log.verbose("Simple verbose"); + } + + // TODO REFACTO REMOVE this and set it in the Test of the logger. + public static String getAAAAAAA(int dfsdf) { + int hhh = 0; + for (int kkk = 0; kkk < dfsdf; kkk++) + for (int iii = 0; iii < 10000; iii++) + for (int jjj = 0; jjj < 100000; jjj++) + for (int lll = 0; lll < 100000; lll++) + hhh++; + return "kkk" + hhh; + } + + public static void testLog() { + Log.print("test direct [START]"); + // test de 10 secondes contre 0.0?? second quand le niveau n'est pas assez grand ... + long timeStart = System.currentTimeMillis(); + for (int iii = 0; iii < 100000000; iii++) + Log2.debug("test direct"); + long timeStop = System.currentTimeMillis(); + Log.print("test direct [END] : " + timeStart + " to " + timeStop + " ==> delta=" + (timeStop - timeStart)); + Log.print("test concat [START]"); + // C'est très long dans les 2 cas ... + timeStart = System.currentTimeMillis(); + for (int iii = 0; iii < 6; iii++) + Log2.debug("test concat: non fonctionnel, il applelle le get a chaque log ... " + getAAAAAAA(iii)); + timeStop = System.currentTimeMillis(); + Log.print("test concat [END] : " + timeStart + " to " + timeStop + " ==> delta=" + (timeStop - timeStart)); + } + + @Test + @Order(4) + public void ddTestSimpleLog() { + testLog(); + } + + @Test + @Order(4) + public void eeUsage() { + Logger.usage(); + } + +} diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..6c6aa7c --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +0.1.0 \ No newline at end of file