From 8cbbe2f94e4731808a8afb224dfdb1fb7f7b3849 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Mon, 22 Feb 2021 22:02:48 +0100 Subject: [PATCH] [DEV] basic port --- .checkstyle | 7 + .classpath | 30 + .gitignore | 17 + .project | 24 + CheckStyle.xml | 66 + CleanUp.xml | 106 ++ Formatter.xml | 390 ++++++ LICENSE | 373 ++++++ src/module-info.java | 9 + src/org/atriasoft/ewol/DrawProperty.cpp | 24 + src/org/atriasoft/ewol/DrawProperty.java | 48 + src/org/atriasoft/ewol/Padding.cpp | 93 ++ src/org/atriasoft/ewol/Padding.java | 43 + src/org/atriasoft/ewol/compositing/Area.cpp | 142 +++ src/org/atriasoft/ewol/compositing/Area.java | 101 ++ .../ewol/compositing/Compositing.cpp | 47 + .../ewol/compositing/Compositing.java | 58 + .../atriasoft/ewol/compositing/Drawing.cpp | 558 +++++++++ .../atriasoft/ewol/compositing/Drawing.java | 229 ++++ src/org/atriasoft/ewol/compositing/Image.cpp | 364 ++++++ src/org/atriasoft/ewol/compositing/Image.java | 193 +++ src/org/atriasoft/ewol/compositing/Shaper.cpp | 693 ++++++++++ .../atriasoft/ewol/compositing/Shaper.java | 296 +++++ src/org/atriasoft/ewol/compositing/Sprite.cpp | 39 + .../atriasoft/ewol/compositing/Sprite.java | 29 + src/org/atriasoft/ewol/compositing/Text.cpp | 372 ++++++ src/org/atriasoft/ewol/compositing/Text.java | 56 + .../atriasoft/ewol/compositing/TextBase.cpp | 1116 +++++++++++++++++ .../atriasoft/ewol/compositing/TextBase.java | 478 +++++++ src/org/atriasoft/ewol/compositing/TextDF.cpp | 407 ++++++ .../atriasoft/ewol/compositing/TextDF.java | 70 ++ .../atriasoft/ewol/context/Application.cpp | 49 + .../atriasoft/ewol/context/Application.java | 54 + src/org/atriasoft/ewol/context/ConfigFont.cpp | 43 + .../atriasoft/ewol/context/ConfigFont.java | 92 ++ src/org/atriasoft/ewol/context/Context.cpp | 382 ++++++ src/org/atriasoft/ewol/context/Context.java | 159 +++ .../atriasoft/ewol/context/InputManager.cpp | 502 ++++++++ .../atriasoft/ewol/context/InputManager.java | 120 ++ src/org/atriasoft/ewol/debug.cpp | 12 + src/org/atriasoft/ewol/event/Entry.cpp | 25 + src/org/atriasoft/ewol/event/Entry.java | 70 ++ src/org/atriasoft/ewol/event/Input.cpp | 24 + src/org/atriasoft/ewol/event/Input.java | 104 ++ src/org/atriasoft/ewol/event/Time.cpp | 35 + src/org/atriasoft/ewol/event/Time.java | 69 + src/org/atriasoft/ewol/ewol.cpp | 32 + src/org/atriasoft/ewol/ewol.java | 30 + src/org/atriasoft/ewol/gravity.cpp | 86 ++ src/org/atriasoft/ewol/gravity.java | 31 + src/org/atriasoft/ewol/internal/Log.java | 68 + src/org/atriasoft/ewol/object/Manager.cpp | 161 +++ src/org/atriasoft/ewol/object/Manager.java | 105 ++ src/org/atriasoft/ewol/object/Object.cpp | 186 +++ src/org/atriasoft/ewol/object/Object.java | 339 +++++ src/org/atriasoft/ewol/object/Worker.cpp | 29 + src/org/atriasoft/ewol/object/Worker.java | 39 + src/org/atriasoft/ewol/resource/ColorFile.cpp | 86 ++ .../atriasoft/ewol/resource/ColorFile.java | 73 ++ .../ewol/resource/Colored3DObject.cpp | 527 ++++++++ .../ewol/resource/Colored3DObject.java | 89 ++ .../atriasoft/ewol/resource/ConfigFile.cpp | 92 ++ .../atriasoft/ewol/resource/ConfigFile.java | 44 + .../ewol/resource/DistanceFieldFont.cpp | 470 +++++++ .../ewol/resource/DistanceFieldFont.java | 96 ++ .../atriasoft/ewol/resource/FontFreeType.cpp | 384 ++++++ .../atriasoft/ewol/resource/FontFreeType.java | 61 + src/org/atriasoft/ewol/resource/ImageDF.cpp | 225 ++++ src/org/atriasoft/ewol/resource/ImageDF.java | 47 + src/org/atriasoft/ewol/resource/Texture.cpp | 319 +++++ src/org/atriasoft/ewol/resource/Texture.java | 91 ++ .../atriasoft/ewol/resource/TextureFile.cpp | 119 ++ .../atriasoft/ewol/resource/TextureFile.java | 47 + .../atriasoft/ewol/resource/TexturedFont.cpp | 369 ++++++ .../atriasoft/ewol/resource/TexturedFont.java | 98 ++ .../ewol/resource/font/FontBase.java | 55 + .../ewol/resource/font/GlyphProperty.java | 103 ++ .../atriasoft/ewol/resource/font/Kerning.java | 69 + src/org/atriasoft/ewol/tools/message.cpp | 65 + src/org/atriasoft/ewol/tools/message.java | 52 + src/org/atriasoft/ewol/widget/Button.cpp | 288 +++++ src/org/atriasoft/ewol/widget/Button.java | 107 ++ src/org/atriasoft/ewol/widget/ButtonColor.cpp | 228 ++++ .../atriasoft/ewol/widget/ButtonColor.java | 78 ++ src/org/atriasoft/ewol/widget/CheckBox.cpp | 216 ++++ src/org/atriasoft/ewol/widget/CheckBox.java | 85 ++ src/org/atriasoft/ewol/widget/ColorBar.cpp | 223 ++++ src/org/atriasoft/ewol/widget/ColorBar.java | 44 + src/org/atriasoft/ewol/widget/Composer.cpp | 162 +++ src/org/atriasoft/ewol/widget/Composer.java | 63 + src/org/atriasoft/ewol/widget/Container.cpp | 215 ++++ src/org/atriasoft/ewol/widget/Container.java | 73 ++ src/org/atriasoft/ewol/widget/Container2.cpp | 261 ++++ src/org/atriasoft/ewol/widget/Container2.java | 174 +++ src/org/atriasoft/ewol/widget/ContainerN.cpp | 342 +++++ src/org/atriasoft/ewol/widget/ContainerN.java | 105 ++ src/org/atriasoft/ewol/widget/ContextMenu.cpp | 267 ++++ .../atriasoft/ewol/widget/ContextMenu.java | 70 ++ src/org/atriasoft/ewol/widget/Entry.cpp | 612 +++++++++ src/org/atriasoft/ewol/widget/Entry.java | 141 +++ src/org/atriasoft/ewol/widget/Gird.cpp | 330 +++++ src/org/atriasoft/ewol/widget/Gird.java | 146 +++ src/org/atriasoft/ewol/widget/Image.cpp | 239 ++++ src/org/atriasoft/ewol/widget/Image.java | 82 ++ src/org/atriasoft/ewol/widget/Joystick.cpp | 190 +++ src/org/atriasoft/ewol/widget/Joystick.java | 90 ++ src/org/atriasoft/ewol/widget/Label.cpp | 175 +++ src/org/atriasoft/ewol/widget/Label.java | 64 + src/org/atriasoft/ewol/widget/Layer.cpp | 43 + src/org/atriasoft/ewol/widget/Layer.java | 38 + src/org/atriasoft/ewol/widget/List.cpp | 332 +++++ src/org/atriasoft/ewol/widget/List.java | 130 ++ .../atriasoft/ewol/widget/ListFileSystem.cpp | 256 ++++ .../atriasoft/ewol/widget/ListFileSystem.java | 83 ++ src/org/atriasoft/ewol/widget/Manager.cpp | 249 ++++ src/org/atriasoft/ewol/widget/Manager.java | 115 ++ src/org/atriasoft/ewol/widget/Menu.cpp | 330 +++++ src/org/atriasoft/ewol/widget/Menu.hpp | 63 + src/org/atriasoft/ewol/widget/Panned.cpp | 0 src/org/atriasoft/ewol/widget/Panned.java | 0 src/org/atriasoft/ewol/widget/PopUp.cpp | 179 +++ src/org/atriasoft/ewol/widget/PopUp.java | 58 + src/org/atriasoft/ewol/widget/ProgressBar.cpp | 97 ++ .../atriasoft/ewol/widget/ProgressBar.java | 50 + src/org/atriasoft/ewol/widget/Scroll.cpp | 444 +++++++ src/org/atriasoft/ewol/widget/Scroll.java | 66 + src/org/atriasoft/ewol/widget/Select.cpp | 205 +++ src/org/atriasoft/ewol/widget/Select.java | 68 + src/org/atriasoft/ewol/widget/Sizer.cpp | 300 +++++ src/org/atriasoft/ewol/widget/Sizer.java | 68 + src/org/atriasoft/ewol/widget/Slider.cpp | 134 ++ src/org/atriasoft/ewol/widget/Slider.java | 60 + src/org/atriasoft/ewol/widget/Spacer.cpp | 50 + src/org/atriasoft/ewol/widget/Spacer.java | 50 + src/org/atriasoft/ewol/widget/Spin.cpp | 106 ++ src/org/atriasoft/ewol/widget/Spin.java | 63 + src/org/atriasoft/ewol/widget/TreeView.cpp | 186 +++ src/org/atriasoft/ewol/widget/TreeView.java | 60 + src/org/atriasoft/ewol/widget/WSlider.cpp | 353 ++++++ src/org/atriasoft/ewol/widget/WSlider.java | 87 ++ src/org/atriasoft/ewol/widget/Widget.cpp | 636 ++++++++++ src/org/atriasoft/ewol/widget/Widget.java | 532 ++++++++ .../atriasoft/ewol/widget/WidgetScrolled.cpp | 501 ++++++++ .../atriasoft/ewol/widget/WidgetScrolled.java | 142 +++ src/org/atriasoft/ewol/widget/Windows.cpp | 290 +++++ src/org/atriasoft/ewol/widget/Windows.java | 85 ++ .../ewol/widget/meta/ColorChooser.cpp | 153 +++ .../ewol/widget/meta/ColorChooser.java | 53 + .../ewol/widget/meta/FileChooser.cpp | 197 +++ .../ewol/widget/meta/FileChooser.java | 106 ++ .../atriasoft/ewol/widget/meta/Parameter.cpp | 255 ++++ .../atriasoft/ewol/widget/meta/Parameter.java | 58 + .../ewol/widget/meta/ParameterList.cpp | 241 ++++ .../ewol/widget/meta/ParameterList.java | 81 ++ .../atriasoft/ewol/widget/meta/SpinBase.cpp | 152 +++ .../atriasoft/ewol/widget/meta/SpinBase.java | 102 ++ .../atriasoft/ewol/widget/meta/StdPopUp.cpp | 132 ++ .../atriasoft/ewol/widget/meta/StdPopUp.java | 81 ++ test/.gitignore | 1 + test/src/test/atriasoft/etk/.keep | 0 test/src/test/atriasoft/etk/Log.java | 59 + test/src/test/atriasoft/etk/Log2.java | 18 + test/src/test/atriasoft/etk/TestBasicLog.java | 103 ++ version.txt | 1 + 164 files changed, 26277 insertions(+) create mode 100644 .checkstyle create mode 100644 .classpath create mode 100644 .gitignore create mode 100644 .project create mode 100755 CheckStyle.xml create mode 100644 CleanUp.xml create mode 100644 Formatter.xml create mode 100644 LICENSE create mode 100644 src/module-info.java create mode 100644 src/org/atriasoft/ewol/DrawProperty.cpp create mode 100644 src/org/atriasoft/ewol/DrawProperty.java create mode 100644 src/org/atriasoft/ewol/Padding.cpp create mode 100644 src/org/atriasoft/ewol/Padding.java create mode 100644 src/org/atriasoft/ewol/compositing/Area.cpp create mode 100644 src/org/atriasoft/ewol/compositing/Area.java create mode 100644 src/org/atriasoft/ewol/compositing/Compositing.cpp create mode 100644 src/org/atriasoft/ewol/compositing/Compositing.java create mode 100644 src/org/atriasoft/ewol/compositing/Drawing.cpp create mode 100644 src/org/atriasoft/ewol/compositing/Drawing.java create mode 100644 src/org/atriasoft/ewol/compositing/Image.cpp create mode 100644 src/org/atriasoft/ewol/compositing/Image.java create mode 100644 src/org/atriasoft/ewol/compositing/Shaper.cpp create mode 100644 src/org/atriasoft/ewol/compositing/Shaper.java create mode 100644 src/org/atriasoft/ewol/compositing/Sprite.cpp create mode 100644 src/org/atriasoft/ewol/compositing/Sprite.java create mode 100644 src/org/atriasoft/ewol/compositing/Text.cpp create mode 100644 src/org/atriasoft/ewol/compositing/Text.java create mode 100644 src/org/atriasoft/ewol/compositing/TextBase.cpp create mode 100644 src/org/atriasoft/ewol/compositing/TextBase.java create mode 100644 src/org/atriasoft/ewol/compositing/TextDF.cpp create mode 100644 src/org/atriasoft/ewol/compositing/TextDF.java create mode 100644 src/org/atriasoft/ewol/context/Application.cpp create mode 100644 src/org/atriasoft/ewol/context/Application.java create mode 100644 src/org/atriasoft/ewol/context/ConfigFont.cpp create mode 100644 src/org/atriasoft/ewol/context/ConfigFont.java create mode 100644 src/org/atriasoft/ewol/context/Context.cpp create mode 100644 src/org/atriasoft/ewol/context/Context.java create mode 100644 src/org/atriasoft/ewol/context/InputManager.cpp create mode 100644 src/org/atriasoft/ewol/context/InputManager.java create mode 100644 src/org/atriasoft/ewol/debug.cpp create mode 100644 src/org/atriasoft/ewol/event/Entry.cpp create mode 100644 src/org/atriasoft/ewol/event/Entry.java create mode 100644 src/org/atriasoft/ewol/event/Input.cpp create mode 100644 src/org/atriasoft/ewol/event/Input.java create mode 100644 src/org/atriasoft/ewol/event/Time.cpp create mode 100644 src/org/atriasoft/ewol/event/Time.java create mode 100644 src/org/atriasoft/ewol/ewol.cpp create mode 100644 src/org/atriasoft/ewol/ewol.java create mode 100644 src/org/atriasoft/ewol/gravity.cpp create mode 100644 src/org/atriasoft/ewol/gravity.java create mode 100644 src/org/atriasoft/ewol/internal/Log.java create mode 100644 src/org/atriasoft/ewol/object/Manager.cpp create mode 100644 src/org/atriasoft/ewol/object/Manager.java create mode 100644 src/org/atriasoft/ewol/object/Object.cpp create mode 100644 src/org/atriasoft/ewol/object/Object.java create mode 100644 src/org/atriasoft/ewol/object/Worker.cpp create mode 100644 src/org/atriasoft/ewol/object/Worker.java create mode 100644 src/org/atriasoft/ewol/resource/ColorFile.cpp create mode 100644 src/org/atriasoft/ewol/resource/ColorFile.java create mode 100644 src/org/atriasoft/ewol/resource/Colored3DObject.cpp create mode 100644 src/org/atriasoft/ewol/resource/Colored3DObject.java create mode 100644 src/org/atriasoft/ewol/resource/ConfigFile.cpp create mode 100644 src/org/atriasoft/ewol/resource/ConfigFile.java create mode 100644 src/org/atriasoft/ewol/resource/DistanceFieldFont.cpp create mode 100644 src/org/atriasoft/ewol/resource/DistanceFieldFont.java create mode 100644 src/org/atriasoft/ewol/resource/FontFreeType.cpp create mode 100644 src/org/atriasoft/ewol/resource/FontFreeType.java create mode 100644 src/org/atriasoft/ewol/resource/ImageDF.cpp create mode 100644 src/org/atriasoft/ewol/resource/ImageDF.java create mode 100644 src/org/atriasoft/ewol/resource/Texture.cpp create mode 100644 src/org/atriasoft/ewol/resource/Texture.java create mode 100644 src/org/atriasoft/ewol/resource/TextureFile.cpp create mode 100644 src/org/atriasoft/ewol/resource/TextureFile.java create mode 100644 src/org/atriasoft/ewol/resource/TexturedFont.cpp create mode 100644 src/org/atriasoft/ewol/resource/TexturedFont.java create mode 100644 src/org/atriasoft/ewol/resource/font/FontBase.java create mode 100644 src/org/atriasoft/ewol/resource/font/GlyphProperty.java create mode 100644 src/org/atriasoft/ewol/resource/font/Kerning.java create mode 100644 src/org/atriasoft/ewol/tools/message.cpp create mode 100644 src/org/atriasoft/ewol/tools/message.java create mode 100644 src/org/atriasoft/ewol/widget/Button.cpp create mode 100644 src/org/atriasoft/ewol/widget/Button.java create mode 100644 src/org/atriasoft/ewol/widget/ButtonColor.cpp create mode 100644 src/org/atriasoft/ewol/widget/ButtonColor.java create mode 100644 src/org/atriasoft/ewol/widget/CheckBox.cpp create mode 100644 src/org/atriasoft/ewol/widget/CheckBox.java create mode 100644 src/org/atriasoft/ewol/widget/ColorBar.cpp create mode 100644 src/org/atriasoft/ewol/widget/ColorBar.java create mode 100644 src/org/atriasoft/ewol/widget/Composer.cpp create mode 100644 src/org/atriasoft/ewol/widget/Composer.java create mode 100644 src/org/atriasoft/ewol/widget/Container.cpp create mode 100644 src/org/atriasoft/ewol/widget/Container.java create mode 100644 src/org/atriasoft/ewol/widget/Container2.cpp create mode 100644 src/org/atriasoft/ewol/widget/Container2.java create mode 100644 src/org/atriasoft/ewol/widget/ContainerN.cpp create mode 100644 src/org/atriasoft/ewol/widget/ContainerN.java create mode 100644 src/org/atriasoft/ewol/widget/ContextMenu.cpp create mode 100644 src/org/atriasoft/ewol/widget/ContextMenu.java create mode 100644 src/org/atriasoft/ewol/widget/Entry.cpp create mode 100644 src/org/atriasoft/ewol/widget/Entry.java create mode 100644 src/org/atriasoft/ewol/widget/Gird.cpp create mode 100644 src/org/atriasoft/ewol/widget/Gird.java create mode 100644 src/org/atriasoft/ewol/widget/Image.cpp create mode 100644 src/org/atriasoft/ewol/widget/Image.java create mode 100644 src/org/atriasoft/ewol/widget/Joystick.cpp create mode 100644 src/org/atriasoft/ewol/widget/Joystick.java create mode 100644 src/org/atriasoft/ewol/widget/Label.cpp create mode 100644 src/org/atriasoft/ewol/widget/Label.java create mode 100644 src/org/atriasoft/ewol/widget/Layer.cpp create mode 100644 src/org/atriasoft/ewol/widget/Layer.java create mode 100644 src/org/atriasoft/ewol/widget/List.cpp create mode 100644 src/org/atriasoft/ewol/widget/List.java create mode 100644 src/org/atriasoft/ewol/widget/ListFileSystem.cpp create mode 100644 src/org/atriasoft/ewol/widget/ListFileSystem.java create mode 100644 src/org/atriasoft/ewol/widget/Manager.cpp create mode 100644 src/org/atriasoft/ewol/widget/Manager.java create mode 100644 src/org/atriasoft/ewol/widget/Menu.cpp create mode 100644 src/org/atriasoft/ewol/widget/Menu.hpp create mode 100644 src/org/atriasoft/ewol/widget/Panned.cpp create mode 100644 src/org/atriasoft/ewol/widget/Panned.java create mode 100644 src/org/atriasoft/ewol/widget/PopUp.cpp create mode 100644 src/org/atriasoft/ewol/widget/PopUp.java create mode 100644 src/org/atriasoft/ewol/widget/ProgressBar.cpp create mode 100644 src/org/atriasoft/ewol/widget/ProgressBar.java create mode 100644 src/org/atriasoft/ewol/widget/Scroll.cpp create mode 100644 src/org/atriasoft/ewol/widget/Scroll.java create mode 100644 src/org/atriasoft/ewol/widget/Select.cpp create mode 100644 src/org/atriasoft/ewol/widget/Select.java create mode 100644 src/org/atriasoft/ewol/widget/Sizer.cpp create mode 100644 src/org/atriasoft/ewol/widget/Sizer.java create mode 100644 src/org/atriasoft/ewol/widget/Slider.cpp create mode 100644 src/org/atriasoft/ewol/widget/Slider.java create mode 100644 src/org/atriasoft/ewol/widget/Spacer.cpp create mode 100644 src/org/atriasoft/ewol/widget/Spacer.java create mode 100644 src/org/atriasoft/ewol/widget/Spin.cpp create mode 100644 src/org/atriasoft/ewol/widget/Spin.java create mode 100644 src/org/atriasoft/ewol/widget/TreeView.cpp create mode 100644 src/org/atriasoft/ewol/widget/TreeView.java create mode 100644 src/org/atriasoft/ewol/widget/WSlider.cpp create mode 100644 src/org/atriasoft/ewol/widget/WSlider.java create mode 100644 src/org/atriasoft/ewol/widget/Widget.cpp create mode 100644 src/org/atriasoft/ewol/widget/Widget.java create mode 100644 src/org/atriasoft/ewol/widget/WidgetScrolled.cpp create mode 100644 src/org/atriasoft/ewol/widget/WidgetScrolled.java create mode 100644 src/org/atriasoft/ewol/widget/Windows.cpp create mode 100644 src/org/atriasoft/ewol/widget/Windows.java create mode 100644 src/org/atriasoft/ewol/widget/meta/ColorChooser.cpp create mode 100644 src/org/atriasoft/ewol/widget/meta/ColorChooser.java create mode 100644 src/org/atriasoft/ewol/widget/meta/FileChooser.cpp create mode 100644 src/org/atriasoft/ewol/widget/meta/FileChooser.java create mode 100644 src/org/atriasoft/ewol/widget/meta/Parameter.cpp create mode 100644 src/org/atriasoft/ewol/widget/meta/Parameter.java create mode 100644 src/org/atriasoft/ewol/widget/meta/ParameterList.cpp create mode 100644 src/org/atriasoft/ewol/widget/meta/ParameterList.java create mode 100644 src/org/atriasoft/ewol/widget/meta/SpinBase.cpp create mode 100644 src/org/atriasoft/ewol/widget/meta/SpinBase.java create mode 100644 src/org/atriasoft/ewol/widget/meta/StdPopUp.cpp create mode 100644 src/org/atriasoft/ewol/widget/meta/StdPopUp.java create mode 100644 test/.gitignore create mode 100644 test/src/test/atriasoft/etk/.keep create mode 100644 test/src/test/atriasoft/etk/Log.java create mode 100644 test/src/test/atriasoft/etk/Log2.java create mode 100644 test/src/test/atriasoft/etk/TestBasicLog.java create mode 100644 version.txt 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