diff --git a/README.md b/README.md index 0e64115..0e4c207 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ void BaseAppSampleApp::prepareSettings(ci::app::App::Settings* settings) { SettingsManager::setInstance(myApp::MyAppSettingsManager::getInstance()); // Initialize the settings manager with the cinder app settings and the settings json - SettingsManager::getInstance()->setup(settings, ci::app::getAssetPath("appSettings.json"), [](SettingsManager * manager) { + SettingsManager::getInstance()->setup(settings, ci::app::getAssetPath("settings.json"), [](SettingsManager * manager) { // Optional: Override json defaults at runtime manager->mFullscreen = false; manager->mWindowSize = ivec2(1280, 720); @@ -105,9 +105,11 @@ void BaseAppSampleApp::prepareSettings(ci::app::App::Settings* settings) { void BaseAppSampleApp::setup() { BaseApp::setup(); + + // Optional: Add touch simulator support BaseApp::addTouchSimulatorParams(); - // Optional: configure your root view + // Optional: Configure your root view getRootView()->setBackgroundColor(Color::gray(0.5f)); // Sample content diff --git a/assets/appSettings.json b/assets/settings.json similarity index 95% rename from assets/appSettings.json rename to assets/settings.json index 8894739..01cd74f 100644 --- a/assets/appSettings.json +++ b/assets/settings.json @@ -21,6 +21,7 @@ "drawMinimap": true, "drawTouches": false, "minimizeParams": true, + "collapseParams": false, "drawScreenLayout": false }, "touch": { diff --git a/cinderblock.xml b/cinderblock.xml index 6cf9884..ed05f13 100644 --- a/cinderblock.xml +++ b/cinderblock.xml @@ -14,7 +14,7 @@ org.libcinder.tuio com.bluecadet.cinder.text - assets/appSettings.json + assets/settings.json src/*.h src/*.cpp diff --git a/samples/AnimationsSample/assets/cinderblock.png b/samples/AnimationsSample/assets/cinderblock.png new file mode 100644 index 0000000..6f2de5c Binary files /dev/null and b/samples/AnimationsSample/assets/cinderblock.png differ diff --git a/samples/AnimationsSample/include/Resources.h b/samples/AnimationsSample/include/Resources.h new file mode 100644 index 0000000..d0e5c9f --- /dev/null +++ b/samples/AnimationsSample/include/Resources.h @@ -0,0 +1,7 @@ +#pragma once +#include "cinder/CinderResources.h" + +//#define RES_MY_RES CINDER_RESOURCE( ../resources/, image_name.png, 128, IMAGE ) + + + diff --git a/samples/AnimationsSample/resources/cinder_app_icon.ico b/samples/AnimationsSample/resources/cinder_app_icon.ico new file mode 100644 index 0000000..b35fb85 Binary files /dev/null and b/samples/AnimationsSample/resources/cinder_app_icon.ico differ diff --git a/samples/AnimationsSample/src/AnimationsSampleApp.cpp b/samples/AnimationsSample/src/AnimationsSampleApp.cpp new file mode 100644 index 0000000..5e04882 --- /dev/null +++ b/samples/AnimationsSample/src/AnimationsSampleApp.cpp @@ -0,0 +1,118 @@ +#include "cinder/app/App.h" +#include "cinder/app/RendererGl.h" +#include "cinder/gl/gl.h" +#include "cinder/Rand.h" + +#include "bluecadet/core/BaseApp.h" + +#include "bluecadet/views/TextView.h" +#include "bluecadet/views/TouchView.h" +#include "bluecadet/views/ImageView.h" +#include "bluecadet/views/FboView.h" +#include "bluecadet/views/EllipseView.h" + +using namespace ci; +using namespace ci::app; +using namespace std; + +using namespace bluecadet::core; +using namespace bluecadet::views; +using namespace bluecadet::touch; + +class AnimationsSampleApp : public BaseApp { +public: + static void prepareSettings(ci::app::App::Settings* settings); + void setup() override; + void update() override; + void draw() override; +}; + +void AnimationsSampleApp::prepareSettings(ci::app::App::Settings* settings) { + SettingsManager::getInstance()->setup(settings, [](SettingsManager * manager) { + manager->mFullscreen = false; + manager->mWindowSize = ivec2(960, 540); + manager->mConsoleWindowEnabled = false; + manager->mMinimizeParams = true; + manager->mCollapseParams = true; + }); +} + +void AnimationsSampleApp::setup() { + BaseApp::setup(); + + addTouchSimulatorParams(); + + vector views; + + { + auto textView = make_shared(); + textView->setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. \ + Donec ornare mi ut nulla iaculis accumsan. Sed placerat vitae nisl at lobortis. \ + Proin facilisis augue nec sodales sagittis. Lorem ipsum dolor sit amet, consectetur \ + adipiscing elit. Donec ornare mi ut nulla iaculis accumsan. Sed placerat vitae nisl \ + at lobortis. Proin facilisis augue nec sodales sagittis.Lorem ipsum dolor sit amet, \ + consectetur adipiscing elit. Donec ornare mi ut nulla iaculis accumsan. Sed placerat \ + vitae nisl at lobortis. Proin facilisis augue nec sodales sagittis."); + textView->setTextColor(Color::white()); + views.push_back(textView); + } + + { + auto imageView = make_shared(); + auto image = loadImage(getAssetPath("cinderblock.png")); + auto texture = gl::Texture::create(image); + imageView->setTexture(texture); + views.push_back(imageView); + } + + { + auto imageView = make_shared(); + auto image = loadImage(getAssetPath("cinderblock.png")); + auto texture = gl::Texture::create(image); + imageView->setTexture(texture); + + auto fboView = make_shared(); + fboView->addChild(imageView); + views.push_back(fboView); + } + + { + auto ellipseView = make_shared(); + ellipseView->setSmoothness(50.0f); + ellipseView->setTransformOrigin(vec2(220, 110)); + views.push_back(ellipseView); + } + + float numCols = 2; + float numRows = 2; + float widthPerView = getWindowWidth() / numCols; + float heightPerView = getWindowHeight() / numRows; + float delayPerView = 0.1f; + for (float i = 0; i < views.size(); ++i) { + auto view = views[(int)i]; + float col = glm::floor(glm::mod(i, numCols)); + float row = glm::floor(i / numRows); + + view->setBackgroundColor(hsvToRgb(vec3(randFloat(), 0.8f, 1.0f))); + view->setPosition(vec2(col * widthPerView, row * heightPerView) + view->getTransformOrigin()); + view->setSize(vec2(widthPerView, heightPerView)); + + view->getTimeline()->apply(&view->getSize(), view->getSize() * vec2(0.33f, 0.66f), 2.0f, easeInOutQuad) + .loop(true).pingPong(true).delay(i / (float)views.size()); + + getRootView()->addChild(view); + } +} + +void AnimationsSampleApp::update() { + // Optional override. BaseApp::update() will update all views. + BaseApp::update(); +} + +void AnimationsSampleApp::draw() { + // Optional override. BaseApp::draw() will draw all views. + BaseApp::draw(); +} + +// Make sure to pass a reference to prepareSettings to configure the app correctly. MSAA and other render options are optional. +CINDER_APP(AnimationsSampleApp, RendererGl(RendererGl::Options().msaa(4)), AnimationsSampleApp::prepareSettings); \ No newline at end of file diff --git a/samples/AnimationsSample/vc2013/AnimationsSample.sln b/samples/AnimationsSample/vc2013/AnimationsSample.sln new file mode 100644 index 0000000..f6f6752 --- /dev/null +++ b/samples/AnimationsSample/vc2013/AnimationsSample.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AnimationsSample", "AnimationsSample.vcxproj", "{F74AEFC9-E3D2-43FA-B133-4503AE34DBBE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Debug|x64 = Debug|x64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F74AEFC9-E3D2-43FA-B133-4503AE34DBBE}.Debug|Win32.ActiveCfg = Debug|Win32 + {F74AEFC9-E3D2-43FA-B133-4503AE34DBBE}.Debug|Win32.Build.0 = Debug|Win32 + {F74AEFC9-E3D2-43FA-B133-4503AE34DBBE}.Release|Win32.ActiveCfg = Release|Win32 + {F74AEFC9-E3D2-43FA-B133-4503AE34DBBE}.Release|Win32.Build.0 = Release|Win32 + {F74AEFC9-E3D2-43FA-B133-4503AE34DBBE}.Debug|x64.ActiveCfg = Debug|x64 + {F74AEFC9-E3D2-43FA-B133-4503AE34DBBE}.Debug|x64.Build.0 = Debug|x64 + {F74AEFC9-E3D2-43FA-B133-4503AE34DBBE}.Release|x64.ActiveCfg = Release|x64 + {F74AEFC9-E3D2-43FA-B133-4503AE34DBBE}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/AnimationsSample/vc2013/AnimationsSample.vcxproj b/samples/AnimationsSample/vc2013/AnimationsSample.vcxproj new file mode 100644 index 0000000..b175603 --- /dev/null +++ b/samples/AnimationsSample/vc2013/AnimationsSample.vcxproj @@ -0,0 +1,269 @@ + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {F74AEFC9-E3D2-43FA-B133-4503AE34DBBE} + AnimationsSample + Win32Proj + + + + Application + false + v120 + Unicode + false + + + Application + false + v120 + Unicode + false + + + Application + true + v120 + Unicode + + + Application + true + v120 + Unicode + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + $(ProjectDir)build\$(Platform)\$(Configuration)\ + $(ProjectDir)build\$(Platform)\$(Configuration)\intermediate\ + true + true + $(ProjectDir)build\$(Platform)\$(Configuration)\ + $(ProjectDir)build\$(Platform)\$(Configuration)\intermediate\ + false + false + + + $(ProjectDir)build\$(Platform)\$(Configuration)\ + $(ProjectDir)build\$(Platform)\$(Configuration)\intermediate\ + + + $(ProjectDir)build\$(Platform)\$(Configuration)\ + $(ProjectDir)build\$(Platform)\$(Configuration)\intermediate\ + + + + Disabled + ..\include;"..\..\..\..\..\include";..\..\..\..\Cinder-BluecadetText\src;..\..\..\src;..\..\..\..\OSC\src;..\..\..\..\TUIO\src + WIN32;_WIN32_WINNT=0x0601;_WINDOWS;NOMINMAX;_DEBUG;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + Level3 + EditAndContinue + true + + + "..\..\..\..\..\include";..\include + + + cinder.lib;OpenGL32.lib;%(AdditionalDependencies) + "..\..\..\..\..\lib\msw\$(PlatformTarget)";"..\..\..\..\..\lib\msw\$(PlatformTarget)\$(Configuration)\$(PlatformToolset)\" + true + Windows + false + + MachineX86 + LIBCMT;LIBCPMT + + + + + Disabled + ..\include;"..\..\..\..\..\include";..\..\..\..\Cinder-BluecadetText\src;..\..\..\src;..\..\..\..\OSC\src;..\..\..\..\TUIO\src + WIN32;_WIN32_WINNT=0x0601;_WINDOWS;NOMINMAX;_DEBUG;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + Level3 + ProgramDatabase + true + + + "..\..\..\..\..\include";..\include + + + cinder.lib;OpenGL32.lib;%(AdditionalDependencies) + "..\..\..\..\..\lib\msw\$(PlatformTarget)";"..\..\..\..\..\lib\msw\$(PlatformTarget)\$(Configuration)\$(PlatformToolset)\" + true + Windows + false + + LIBCMT;LIBCPMT + + + + + ..\include;"..\..\..\..\..\include";..\..\..\..\Cinder-BluecadetText\src;..\..\..\src;..\..\..\..\OSC\src;..\..\..\..\TUIO\src + WIN32;_WIN32_WINNT=0x0601;_WINDOWS;NOMINMAX;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + + Level3 + ProgramDatabase + true + + + true + + + "..\..\..\..\..\include";..\include + + + cinder.lib;OpenGL32.lib;%(AdditionalDependencies) + "..\..\..\..\..\lib\msw\$(PlatformTarget)";"..\..\..\..\..\lib\msw\$(PlatformTarget)\$(Configuration)\$(PlatformToolset)\" + false + true + Windows + true + + false + + MachineX86 + + + + + ..\include;"..\..\..\..\..\include";..\..\..\..\Cinder-BluecadetText\src;..\..\..\src;..\..\..\..\OSC\src;..\..\..\..\TUIO\src + WIN32;_WIN32_WINNT=0x0601;_WINDOWS;NOMINMAX;NDEBUG;%(PreprocessorDefinitions) + MultiThreaded + + Level3 + ProgramDatabase + true + + + true + + + "..\..\..\..\..\include";..\include + + + cinder.lib;OpenGL32.lib;%(AdditionalDependencies) + "..\..\..\..\..\lib\msw\$(PlatformTarget)\";"..\..\..\..\..\lib\msw\$(PlatformTarget)\$(Configuration)\$(PlatformToolset)\" + false + true + Windows + true + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/AnimationsSample/vc2013/AnimationsSample.vcxproj.filters b/samples/AnimationsSample/vc2013/AnimationsSample.vcxproj.filters new file mode 100644 index 0000000..f74afe6 --- /dev/null +++ b/samples/AnimationsSample/vc2013/AnimationsSample.vcxproj.filters @@ -0,0 +1,280 @@ + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {7698A5C6-E483-4EBE-9FCC-DA19E51FF0EA} + + + {60A5C2A6-575F-46CF-A864-20E40C24FC7E} + + + {0F11054A-54BF-4777-94AC-6845CC2B7E75} + + + {EAE90F96-EBB8-4D08-A93A-D99B83B095B2} + + + {B2B8C53C-E7E9-4460-BA3D-99B53367F847} + + + {2201C8BE-7A57-413E-9E4F-1ACDECDD1E43} + + + {036CF81F-83CE-411E-9FDC-360705F33051} + + + {02E01F77-24C0-441E-B278-F70F233AA512} + + + {4DB4F2A1-E1DB-4544-BD3F-A93E7468097C} + + + {E0E608B6-A98A-49A6-86C8-BD2480930F5C} + + + {C314367C-DEEA-441D-BC4C-D0E580C5EEB1} + + + {2FF21598-3CC7-41B2-B3CB-F43270CAA7DB} + + + {88327888-C955-4574-87E9-58EF225FCBC4} + + + {4A28F522-D047-4207-91E5-5A4639959131} + + + {DB10A8CF-0CE2-4D8F-9495-571A000312ED} + + + {979FD2B9-C2E3-4264-8220-5CC5A512B6A4} + + + {74ABC205-9439-4C12-81A8-09E1B3A9AEAE} + + + {5ED835CF-D497-4BED-8FFB-1682DC0A9EEA} + + + {EA375F23-C459-4B3C-8329-1C2D5299259F} + + + {780B6CDD-3CBF-4A86-9D8E-A0A8FF2FEF07} + + + + + Source Files + + + Source Files + + + Header Files + + + Blocks\BluecadetText\src\bluecadet\text + + + Blocks\BluecadetText\src\bluecadet\text + + + Blocks\BluecadetText\src\bluecadet\text + + + Blocks\BluecadetText\src\bluecadet\text + + + Blocks\BluecadetText\src\bluecadet\text + + + Blocks\BluecadetText\src\bluecadet\text + + + Blocks\BluecadetText\src\bluecadet\text + + + Blocks\BluecadetText\src\bluecadet\text + + + Blocks\BluecadetText\src\bluecadet\text + + + Blocks\BluecadetViews\src\bluecadet\core + + + Blocks\BluecadetViews\src\bluecadet\core + + + Blocks\BluecadetViews\src\bluecadet\core + + + Blocks\BluecadetViews\src\bluecadet\core + + + Blocks\BluecadetViews\src\bluecadet\core + + + Blocks\BluecadetViews\src\bluecadet\core + + + Blocks\BluecadetViews\src\bluecadet\core + + + Blocks\BluecadetViews\src\bluecadet\core + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\views + + + Blocks\BluecadetViews\src\bluecadet\touch + + + Blocks\BluecadetViews\src\bluecadet\touch + + + Blocks\BluecadetViews\src\bluecadet\touch + + + Blocks\BluecadetViews\src\bluecadet\touch + + + Blocks\BluecadetViews\src\bluecadet\touch + + + Blocks\BluecadetViews\src\bluecadet\touch\drivers + + + Blocks\BluecadetViews\src\bluecadet\touch\drivers + + + Blocks\BluecadetViews\src\bluecadet\touch\drivers + + + Blocks\BluecadetViews\src\bluecadet\touch\drivers + + + Blocks\BluecadetViews\src\bluecadet\touch\drivers + + + Blocks\BluecadetViews\src\bluecadet\touch\drivers + + + Blocks\BluecadetViews\src\bluecadet\touch\drivers + + + Blocks\BluecadetViews\src\bluecadet\touch\drivers + + + Blocks\OSC\src\cinder\osc + + + Blocks\OSC\src\cinder\osc + + + Blocks\TUIO\src\cinder\tuio + + + Blocks\TUIO\src\cinder\tuio + + + + + Header Files + + + Blocks\BluecadetViews\src\bluecadet\views + + + + + Resource Files + + + \ No newline at end of file diff --git a/samples/AnimationsSample/vc2013/Resources.rc b/samples/AnimationsSample/vc2013/Resources.rc new file mode 100644 index 0000000..282469b --- /dev/null +++ b/samples/AnimationsSample/vc2013/Resources.rc @@ -0,0 +1,3 @@ +#include "../include/Resources.h" + +1 ICON "..\\resources\\cinder_app_icon.ico" diff --git a/samples/TextViewSample/src/TextViewSampleApp.cpp b/samples/TextViewSample/src/TextViewSampleApp.cpp index af02913..1c159f1 100644 --- a/samples/TextViewSample/src/TextViewSampleApp.cpp +++ b/samples/TextViewSample/src/TextViewSampleApp.cpp @@ -17,7 +17,7 @@ class TextViewSampleApp : public BaseApp { public: static void prepareSettings(ci::app::App::Settings* settings); void setup() override; - void mouseMove(MouseEvent event) override; + void update() override; TextViewRef mTextView; }; @@ -25,6 +25,8 @@ void TextViewSampleApp::prepareSettings(ci::app::App::Settings* settings) { SettingsManager::getInstance()->setup(settings, "", [](SettingsManager * manager) { manager->mFullscreen = false; manager->mWindowSize = ivec2(1280, 720); + manager->mMinimizeParams = false; + manager->mCollapseParams = true; }); } @@ -32,22 +34,17 @@ void TextViewSampleApp::setup() { BaseApp::setup(); - // Get the params out of the way - SettingsManager::getInstance()->getParams()->minimize(); - // Optional: configure the size and background of your root view getRootView()->setBackgroundColor(Color::gray(0.5f)); - getRootView()->setSize(ScreenLayout::getInstance()->getAppSize()); // Sample content mTextView = TextViewRef(new TextView()); - // Setting only the width will cause the text to break and flow automatically. This is the same as calling setSize(400, -1) - mTextView->setWidth(400.0f); - //mTextView->setHeight(400.0f); // this would cause any text beyond 400 px to be cut off vertically + mTextView->setWidth(500.0f); // This will cause the text to break and flow automatically. This is the same as calling setSize(400, 0) + //mTextView->setHeight(500.0f); // This will cause any text beyond 400 px to be cut off vertically // Background color is independent of text styles - mTextView->setBackgroundColor(ColorA(1, 0, 1, 0.75f)); + mTextView->setBackgroundColor(ColorA(1.0f, 0, 0.5f, 0.75f)); // Set all styles before setting your text mTextView->setTextColor(Color(1.0f, 1.0f, 1.0f)); @@ -55,20 +52,61 @@ void TextViewSampleApp::setup() { mTextView->setTextAlign(TextAlign::Center); // All styles will be applied to text now - mTextView->setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nec vero alia sunt quaerenda contra Carneadeam illam sententiam. Atque haec coniunctio confusioque virtutum tamen a philosophis ratione quadam distinguitur. "); - - // Set new styles for additional text - mTextView->setTextColor(Color(0.25f, 0.25f, 1.0f)); - //mTextView->setTextColor(Color(0.25f, 0.25f, 1.0f), true); // this would apply the text color to all existing text - mTextView->appendText("Sit hoc ultimum bonorum, quod nunc a me defenditur; Duo Reges: constructio interrete. Quid est, quod ab ea absolvi et perfici debeat? Nunc haec primum fortasse audientis servire debemus. Scaevola tribunus plebis ferret ad plebem vellentne de ea re quaeri. Sed in rebus apertissimis nimium longi sumus."); + mTextView->setText("Lorem ipsum dolor sit amet, consectetur adipiscing elit.\n\nNec vero alia sunt quaerenda contra Carneadeam illam sententiam. Atque haec coniunctio confusioque virtutum tamen a philosophis ratione quadam distinguitur. "); + + // Configure debug parameters + static int clipMode = mTextView->getClipMode(); + static vector clipModes = {"Clip", "No Clip"}; + + static int layoutMode = mTextView->getLayoutMode(); + static vector layoutModes = {"Word Wrap", "No Wrap", "Single Line"}; + + static int textAlign = mTextView->getCurrentStyle().mTextAlign; + static vector textAligns = {"Left", "Right", "Center"}; + + auto params = SettingsManager::getInstance()->getParams(); + params->setSize(params->getSize() + ivec2(0, 200)); + + params->addSeparator(); + params->addParam("Clip Mode", clipModes, &clipMode).updateFn([&]() { mTextView->setClipMode((StyledTextLayout::ClipMode)clipMode); }); + params->addParam("Layout Mode", layoutModes, &layoutMode).updateFn([&]() { mTextView->setLayoutMode((StyledTextLayout::LayoutMode)layoutMode); }); + params->addParam("Text Align", textAligns, &textAlign).updateFn([&]() { mTextView->setTextAlign((TextAlign)textAlign); }); + params->addParam("Trim Text Size", [&](bool v) { mTextView->setSizeTrimmingEnabled(v); }, [&] { return mTextView->getSizeTrimmingEnabled(); }); + params->addSeparator(); + params->addButton("Set to Auto-Width", [&] { mTextView->setWidth(0); }); + params->addButton("Set to Auto-Height", [&] { mTextView->setHeight(0); }); + params->addSeparator(); + params->addParam("View Width", [&](float v) { mTextView->setWidth(v); }, [&] { return mTextView->getWidth(); }); + params->addParam("View Height", [&](float v) { mTextView->setHeight(v); }, [&] { return mTextView->getHeight(); }); + params->addSeparator(); + params->addParam("Padding Top", [&](float v) { mTextView->setPaddingTop(v); }, [&] { return mTextView->getPaddingTop(); }); + params->addParam("Padding Right", [&](float v) { mTextView->setPaddingRight(v); }, [&] { return mTextView->getPaddingRight(); }); + params->addParam("Padding Bottom", [&](float v) { mTextView->setPaddingBottom(v); }, [&] { return mTextView->getPaddingBottom(); }); + params->addParam("Padding Left", [&](float v) { mTextView->setPaddingLeft(v); }, [&] { return mTextView->getPaddingLeft(); }); + params->addSeparator(); + params->addParam("Leading Disabled", [&](bool v) { mTextView->setLeadingDisabled(v); }, [&] { return mTextView->getLeadingDisabled(); }); + params->addParam("Leading Offset", [&](float v) { mTextView->setLeadingOffset(v); }, [&] { return mTextView->getCurrentStyle().mLeadingOffset; }).step(1); + params->addSeparator(); + params->addParam("Max Width (read only)", [&](float v) {}, [&] { return mTextView->getMaxWidth(); }); + params->addParam("Max Height (read only)", [&](float v) {}, [&] { return mTextView->getMaxHeight(); }); + params->addParam("Text Width (read only)", [&](float v) {}, [&] { return mTextView->getTextWidth(); }); + params->addParam("Text Height (read only)", [&](float v) {}, [&] { return mTextView->getTextHeight(); }); + params->addSeparator(); getRootView()->addChild(mTextView); } -void TextViewSampleApp::mouseMove(MouseEvent event) { - float x = event.getX(); - mTextView->setWidth(x - mTextView->getPosition().value().x); +void TextViewSampleApp::update() { + BaseApp::update(); + + mTextView->setPosition((vec2(getWindowSize()) - mTextView->getSize()) * 0.5f); + + static bool initialized = false; + if (!initialized) { + initialized = true; + auto params = SettingsManager::getInstance()->getParams(); + params->setPosition(vec2(getWindowWidth() - params->getWidth() - params->getPosition().x, params->getPosition().y)); + } } -// Make sure to pass a reference to prepareSettings to configure the app correctly. MSAA and other render options are optional. CINDER_APP(TextViewSampleApp, RendererGl(RendererGl::Options().msaa(4)), TextViewSampleApp::prepareSettings); diff --git a/samples/TextViewSample/vc2013/TextViewSample.vcxproj b/samples/TextViewSample/vc2013/TextViewSample.vcxproj index fe408c9..96c76f7 100644 --- a/samples/TextViewSample/vc2013/TextViewSample.vcxproj +++ b/samples/TextViewSample/vc2013/TextViewSample.vcxproj @@ -78,6 +78,7 @@ Level3 ProgramDatabase true + false true @@ -88,13 +89,13 @@ cinder.lib;OpenGL32.lib;%(AdditionalDependencies) "..\..\..\..\..\lib\msw\$(PlatformTarget)";"..\..\..\..\..\lib\msw\$(PlatformTarget)\$(Configuration)\$(PlatformToolset)\" - false true Windows true false + false diff --git a/src/bluecadet/core/BaseApp.cpp b/src/bluecadet/core/BaseApp.cpp index 87eab45..e349ea4 100644 --- a/src/bluecadet/core/BaseApp.cpp +++ b/src/bluecadet/core/BaseApp.cpp @@ -68,21 +68,21 @@ void BaseApp::setup() { gl::enableAlphaBlending(); // Set up touches - if (SettingsManager::getInstance()->mMouseEnabled) { + if (settings->mMouseEnabled) { mMouseDriver.connect(); mMouseDriver.setVirtualMultiTouchEnabled(true); } - if (SettingsManager::getInstance()->mTuioTouchEnabled) { + if (settings->mTuioTouchEnabled) { mTuioDriver.connect(); } - if (SettingsManager::getInstance()->mNativeTouchEnabled) { + if (settings->mNativeTouchEnabled) { mNativeTouchDriver.connect(); } mSimulatedTouchDriver.setup(Rectf(vec2(0), getWindowSize()), 60); // Debugging - const float targetFps = (float)SettingsManager::getInstance()->mFps; + const float targetFps = (float)settings->mFps; mStats->setBackgroundColor(ColorA(0, 0, 0, 0.1f)); mStats->addGraph("FPS", 0, targetFps, ColorA(1.0f, 0.0f, 0.0f, 0.75f), ColorA(0.0f, 1.0f, 0.25f, 0.75f)); } @@ -188,9 +188,10 @@ void BaseApp::addTouchSimulatorParams(float touchesPerSecond) { mSimulatedTouchDriver.setTouchesPerSecond(touchesPerSecond); - const string groupName = "Touch-Sim"; + const string groupName = "Touch Sim"; + auto params = SettingsManager::getInstance()->getParams(); - SettingsManager::getInstance()->getParams()->addParam("Enabled", [&](bool v) { + params->addParam("Enabled", [&](bool v) { if (!mSimulatedTouchDriver.isRunning()) { SettingsManager::getInstance()->mDrawTouches = true; mSimulatedTouchDriver.setBounds(Rectf(vec2(0), getWindowSize())); @@ -206,7 +207,7 @@ void BaseApp::addTouchSimulatorParams(float touchesPerSecond) { static int stressTestMode = 0; static vector stressTestModes = {"Tap & Drag", "Slow Drag", "Tap"}; - SettingsManager::getInstance()->getParams()->addParam("Mode", stressTestModes, &stressTestMode).updateFn([&] { + params->addParam("Mode", stressTestModes, &stressTestMode).updateFn([&] { if (stressTestMode == 0) { mSimulatedTouchDriver.setMinTouchDuration(0); mSimulatedTouchDriver.setMaxTouchDuration(1.f); @@ -222,18 +223,21 @@ void BaseApp::addTouchSimulatorParams(float touchesPerSecond) { } }).group(groupName); - SettingsManager::getInstance()->getParams()->addParam("Touches/s", [&](float v) { + params->addParam("Touches/s", [&](float v) { mSimulatedTouchDriver.setTouchesPerSecond(v); }, [&]() { return mSimulatedTouchDriver.getTouchesPerSecond(); }).group(groupName); - SettingsManager::getInstance()->getParams()->addParam("Show Missed Touches", [&](bool v) { + params->addParam("Show Missed Touches", [&](bool v) { TouchManager::getInstance()->setDiscardMissedTouches(!v); }, [&]() { return !TouchManager::getInstance()->getDiscardMissedTouches(); }).group(groupName); + if (SettingsManager::getInstance()->mCollapseParams) { + params->setOptions(groupName, "opened=false"); + } } } diff --git a/src/bluecadet/core/BaseApp.h b/src/bluecadet/core/BaseApp.h index a2b0f2f..c5880a2 100644 --- a/src/bluecadet/core/BaseApp.h +++ b/src/bluecadet/core/BaseApp.h @@ -41,9 +41,6 @@ class BaseApp : public ci::app::App { virtual void handleAppSizeChange(const ci::ivec2 & appSize); virtual void handleViewportChange(const ci::Area & viewport); - //! Adds a set of params to control the touch simulator - void addTouchSimulatorParams(float touchesPerSecond = 50.f); - //! Use this view to add any children. The root view may be scaled and translated when using ScreenLayout to zoom/pan around the app. views::BaseViewRef getRootView() const { return mRootView; }; @@ -65,11 +62,10 @@ class BaseApp : public ci::app::App { //! The main mouse driver. Configured with the current window size at app launch, but needs to be started explicitly. touch::drivers::SimulatedTouchDriver & getTouchSimDriver() { return mSimulatedTouchDriver; } - //! The settings manager instance used during initialization - SettingsManagerRef getSettingsManager() const { return mSettingsManager; } + //! Adds a set of params to control the touch simulator + void addTouchSimulatorParams(float touchesPerSecond = 50.f); private: - SettingsManagerRef mSettingsManager; views::BaseViewRef mRootView; views::MiniMapViewRef mMiniMap; views::GraphViewRef mStats; diff --git a/src/bluecadet/core/ScreenLayout.h b/src/bluecadet/core/ScreenLayout.h index 737550d..708f894 100644 --- a/src/bluecadet/core/ScreenLayout.h +++ b/src/bluecadet/core/ScreenLayout.h @@ -32,7 +32,7 @@ class ScreenLayout { //! Must be called before calling draw. Adds a key-up event listener. - void setup(const ci::ivec2& dislaySize = ci::ivec2(1920, 1080), const int numRows = 1, const int numColumns = 1); + void setup(const ci::ivec2& dislaySize = ci::app::getWindowSize(), const int numRows = 1, const int numColumns = 1); //! Draws the current screen layout, transformed appropriately to match the position and scale of rootView void draw(); diff --git a/src/bluecadet/core/SettingsManager.cpp b/src/bluecadet/core/SettingsManager.cpp index 5522f5a..f8b0d7e 100644 --- a/src/bluecadet/core/SettingsManager.cpp +++ b/src/bluecadet/core/SettingsManager.cpp @@ -45,12 +45,7 @@ SettingsManager::SettingsManager() { } SettingsManager::~SettingsManager() {} -// Pull in the shared/standard app settings JSON void SettingsManager::setup(ci::app::App::Settings * appSettings, ci::fs::path jsonPath, std::function overrideCallback) { - // Set default path - if (jsonPath.empty()) { - jsonPath = ci::app::getAssetPath("appSettings.json"); - } // If the path exists, load it if (fs::exists(jsonPath)) { @@ -67,6 +62,10 @@ void SettingsManager::setup(ci::app::App::Settings * appSettings, ci::fs::path j CI_LOG_E("Settings file does not exist at '" << jsonPath << "'"); } + setup(appSettings, overrideCallback); +} + +void SettingsManager::setup(ci::app::App::Settings * appSettings, std::function overrideCallback) { if (overrideCallback) { overrideCallback(this); } @@ -87,6 +86,8 @@ void SettingsManager::setup(ci::app::App::Settings * appSettings, ci::fs::path j addCommandLineParser("draw_stats", [&](const string &value) { mDrawStats = value == "true"; }); addCommandLineParser("minimizeParams", [&](const string &value) { mMinimizeParams = value == "true"; }); addCommandLineParser("minimize_params", [&](const string &value) { mMinimizeParams = value == "true"; }); + addCommandLineParser("collapseParams", [&](const string &value) { mCollapseParams = value == "true"; }); + addCommandLineParser("collapse_params", [&](const string &value) { mCollapseParams = value == "true"; }); addCommandLineParser("zoom_toggle_hotkey", [&](const string &value) { mZoomToggleHotkeyEnabled = value == "true"; }); addCommandLineParser("display_id_hotkey", [&](const string &value) { mDisplayIdHotkeysEnabled = value == "true"; }); addCommandLineParser("size", [&](const string &value) { @@ -170,6 +171,7 @@ void SettingsManager::parseJson(ci::JsonTree & json) { setFieldFromJsonIfExists(&mDrawTouches, "settings.debug.drawTouches"); setFieldFromJsonIfExists(&mDrawScreenLayout, "settings.debug.drawScreenLayout"); setFieldFromJsonIfExists(&mMinimizeParams, "settings.debug.minimizeParams"); + setFieldFromJsonIfExists(&mCollapseParams, "settings.debug.collapseParams"); setFieldFromJsonIfExists(&mZoomToggleHotkeyEnabled, "settings.debug.zoomToggleHotkey"); setFieldFromJsonIfExists(&mDisplayIdHotkeysEnabled, "settings.debug.displayIdHotkeys"); @@ -207,16 +209,26 @@ ci::params::InterfaceGlRef SettingsManager::getParams() { if (!params) { params = ci::params::InterfaceGl::create("Settings", ci::ivec2(250, 250)); params->addParam("Show Layout", &mDrawScreenLayout).group("App").key("l"); - params->addParam("Show Touches", &mDrawTouches).group("App").key("t"); params->addParam("Show Minimap", &mDrawMinimap).group("App").key("m"); params->addParam("Show Stats", &mDrawStats).group("App").key("s"); + + params->addParam("Show Touches", &mDrawTouches).group("App").key("t"); params->addParam("Show Cursor", &mShowMouse).updateFn([&] { mShowMouse ? ci::app::AppBase::get()->showCursor() : ci::app::AppBase::get()->hideCursor(); }).key("c").group("App"); - params->addParam("Show Bounds", &bluecadet::views::BaseView::sDebugDrawBounds).group("App").key("b"); - params->addParam("Show Invisible Bounds", &bluecadet::views::BaseView::sDebugDrawInvisibleBounds).group("App"); + + static int boundIndex = 0; + params->addParam("View Bounds", {"None", "Visible", "All"}, [&](int i) { + boundIndex = i; + bluecadet::views::BaseView::sDebugDrawBounds = boundIndex >= 1; + bluecadet::views::BaseView::sDebugDrawInvisibleBounds = boundIndex >= 2; + }, [&] { return boundIndex; }).key("b").group("App"); if (mMinimizeParams) { params->minimize(); } + + if (mCollapseParams) { + params->setOptions("App", "opened=false"); + } } return params; } diff --git a/src/bluecadet/core/SettingsManager.h b/src/bluecadet/core/SettingsManager.h index a726ba7..e9ce420 100644 --- a/src/bluecadet/core/SettingsManager.h +++ b/src/bluecadet/core/SettingsManager.h @@ -38,10 +38,20 @@ class SettingsManager { //! Set up the settings manager with the path to the main json and the applications settings. Should be called in prepareSettings(). //! - //! jsonPath will default to getAssetPath("appSettings.json") if left empty. //! overrideCallback can be used to override arguments from the json file. //! - virtual void setup(ci::app::App::Settings * appSettings, ci::fs::path jsonPath = "", std::function overrideCallback = nullptr); + virtual void setup( + ci::app::App::Settings * appSettings, + ci::fs::path jsonPath = ci::app::getAssetPath("settings.json"), + std::function overrideCallback = nullptr + ); + + + //! Set up the settings manager without a json file + virtual void setup( + ci::app::App::Settings * appSettings, + std::function overrideCallback = nullptr + ); //! Adds a callback to parse a command line argument by key. @@ -89,9 +99,10 @@ class SettingsManager { bool mShowMouse = false; bool mDrawMinimap = false; bool mDrawStats = false; - bool mMinimizeParams = false; - bool mZoomToggleHotkeyEnabled = true; - bool mDisplayIdHotkeysEnabled = false; + bool mMinimizeParams = false; //! Minimizes the params window + bool mCollapseParams = false; //! Collapses all the default parameter groups like "App" + bool mZoomToggleHotkeyEnabled = true; //! When true, will bind 0 to toggle zoom to 100%/fit + bool mDisplayIdHotkeysEnabled = false; //! When true, will bind 1-9 to zoom directly to displays 1-9 // CLI/runtime only args ci::ivec2 mWindowSize; //! The window size on launch diff --git a/src/bluecadet/views/AnimOperators.h b/src/bluecadet/views/AnimOperators.h new file mode 100644 index 0000000..caf642c --- /dev/null +++ b/src/bluecadet/views/AnimOperators.h @@ -0,0 +1,204 @@ +#pragma once + +#include "cinder/Tween.h" + +//================================================== +// Anim + T +// + +template +inline T operator + (const ci::Anim & tween, const T & value) { + return tween.value() + value; +} + +template +inline T operator - (const ci::Anim & tween, const T & value) { + return tween.value() - value; +} + +template +inline T operator * (const ci::Anim & tween, const T & value) { + return tween.value() * value; +} + +template +inline T operator / (const ci::Anim & tween, const T & value) { + return tween.value() / value; +} + +template +inline T operator - (const ci::Anim & tween) { + return -tween.value(); +} + +//================================================== +// T + Anim +// + +template +inline T operator + (const T & value, const ci::Anim & tween) { + return value + tween.value(); +} + +template +inline T operator - (const T & value, const ci::Anim & tween) { + return value - tween.value(); +} + +template +inline T operator * (const T & value, const ci::Anim & tween) { + return value * tween.value(); +} + +template +inline T operator / (const T & value, const ci::Anim & tween) { + return value / tween.value(); +} + + +//================================================== +// U + Anim +// + +template +inline T operator + (const U & value, const ci::Anim & tween) { + return value + tween.value(); +} + +template +inline T operator - (const U & value, const ci::Anim & tween) { + return value - tween.value(); +} + +template +inline T operator * (const U & value, const ci::Anim & tween) { + return value * tween.value(); +} + +template +inline T operator / (const U & value, const ci::Anim & tween) { + return value / tween.value(); +} + + +//================================================== +// Anim + U +// + +template +inline T operator + (const ci::Anim & tween, const U & value) { + return tween.value() + value; +} + +template +inline T operator - (const ci::Anim & tween, const U & value) { + return tween.value() - value; +} + +template +inline T operator * (const ci::Anim & tween, const U & value) { + return tween.value() * value; +} + +template +inline T operator / (const ci::Anim & tween, const U & value) { + return tween.value() / value; +} + + +//================================================== +// Anim + Anim +// + +template +inline T operator + (const ci::Anim & lhs, const ci::Anim & rhs) { + return lhs.value() + rhs.value(); +} + +template +inline T operator - (const ci::Anim & lhs, const ci::Anim & rhs) { + return lhs.value() - rhs.value(); +} + +template +inline T operator * (const ci::Anim & lhs, const ci::Anim & rhs) { + return lhs.value() * rhs.value(); +} + +template +inline T operator / (const ci::Anim & lhs, const ci::Anim & rhs) { + return lhs.value() / rhs.value(); +} + + +//================================================== +// ==, != +// + +template +inline bool operator == (const ci::Anim & tween, const T & value) { + return tween.value() == value; +} + +template +inline bool operator == (const T & value, const ci::Anim & tween) { + return value == tween.value(); +} + +template +inline bool operator != (const ci::Anim & tween, const T & value) { + return tween.value() != value; +} + +template +inline bool operator != (const T & value, const ci::Anim & tween) { + return value != tween.value(); +} + + +//================================================== +// >, <, <=, >= +// + +template +inline bool operator > (const ci::Anim & tween, const T & value) { + return tween.value() > value; +} + +template +inline bool operator > (const T & value, const ci::Anim & tween) { + return value > tween.value(); +} + + +template +inline bool operator < (const ci::Anim & tween, const T & value) { + return tween.value() < value; +} + +template +inline bool operator < (const T & value, const ci::Anim & tween) { + return value < tween.value(); +} + + +template +inline bool operator >= (const ci::Anim & tween, const T & value) { + return tween.value() >= value; +} + +template +inline bool operator >= (const T & value, const ci::Anim & tween) { + return value >= tween.value(); +} + + +template +inline bool operator <= (const ci::Anim & tween, const T & value) { + return tween.value() <= value; +} + +template +inline bool operator <= (const T & value, const ci::Anim & tween) { + return value <= tween.value(); +} diff --git a/src/bluecadet/views/BaseView.cpp b/src/bluecadet/views/BaseView.cpp index fb284db..3a2f7ca 100644 --- a/src/bluecadet/views/BaseView.cpp +++ b/src/bluecadet/views/BaseView.cpp @@ -33,16 +33,16 @@ BaseView::BaseView() : mScale(vec2(1.0f)), mRotation(quat()), mHasInvalidTransforms(true), - mSize(0), + mSize(vec2(0)), mHasInvalidContent(true), mTint(Color::white()), mBackgroundColor(ColorA::zero()), mDrawColor(1.0f, 1.0f, 1.0f, 1.0f), - mAlpha(1.0), + mAlpha(1.0f), mIsHidden(false), - mShouldForceInvisibleDraw(false), + mShouldDrawWhenInvisible(false), mBlendMode(BlendMode::INHERIT), mShouldPropagateEvents(sEventPropagationEnabled), @@ -68,7 +68,7 @@ void BaseView::reset() { mGlobalTransform = mat4(); mHasInvalidTransforms = true; mHasInvalidContent = true; - mShouldForceInvisibleDraw = false; + mShouldDrawWhenInvisible = false; mShouldPropagateEvents = true; mTint = Color(1.0f, 1.0f, 1.0f); mDrawColor = ColorA(1.0f, 1.0f, 1.0f, 1.0f); @@ -159,6 +159,18 @@ void BaseView::removeAllChildren() { } } +BaseViewList::iterator BaseView::getChildIt(BaseViewRef child) { + if (!child || child->mParent != this) return mChildren.end(); + return std::find(mChildren.begin(), mChildren.end(), child); +} + +BaseViewList::iterator BaseView::getChildIt(BaseView* childPtr) { + if (!childPtr || childPtr->mParent != this) return mChildren.end(); + return std::find_if(mChildren.begin(), mChildren.end(), [&](BaseViewRef child) { + return child.get() == childPtr; + }); +} + //================================================== // Order and Sorting // @@ -254,10 +266,14 @@ void BaseView::setTransformOrigin(const vec2 & value, const bool compensateForOf // void BaseView::updateScene(const double deltaTime) { + if (mTimeline && !mTimeline->empty()) { - mTimeline->stepTo(timeline().getCurrentTime()); invalidate(); } + + if (mTimeline) { + mTimeline->stepTo(timeline().getCurrentTime()); + } if (mHasInvalidContent && mShouldDispatchContentInvalidation) { dispatchEvent(ViewEvent(ViewEvent::Type::CONTENT_INVALIDATED, getSharedViewPtr())); @@ -274,7 +290,7 @@ void BaseView::update(const double deltaTime) { } void BaseView::drawScene(const ColorA& parentTint) { - const bool shouldDraw = mShouldForceInvisibleDraw || (!mIsHidden && mAlpha > 0.0f); + const bool shouldDraw = mShouldDrawWhenInvisible || (!mIsHidden && mAlpha > 0.0f); if (shouldDraw || (sDebugDrawBounds && sDebugDrawInvisibleBounds)) { validateTransforms(); @@ -321,7 +337,7 @@ void BaseView::drawScene(const ColorA& parentTint) { void BaseView::draw() { // override this method for custom drawing - const auto size = getSize(); + const auto & size = getSize().value(); const auto & color = getBackgroundColor().value(); if (size.x <= 0 && size.y <= 0 && color.a <= 0) { @@ -336,11 +352,45 @@ void BaseView::draw() { batch->draw(); } -inline void BaseView::debugDrawOutline() { - const float hue = (float)mViewId / (float)sNumInstances; - const auto color = ColorAf(ci::hsvToRgb(vec3(hue, 1.0f, 1.0f)), 0.66f); - gl::color(color); - gl::drawStrokedRect(Rectf(vec2(0), getSize())); +void BaseView::drawChildren(const ci::ColorA& parentTint) { + for (auto child : mChildren) { + child->drawScene(parentTint); + } +} + +//================================================== +// Validation +// + +void BaseView::validateTransforms(const bool force) { + if (!mHasInvalidTransforms && !force) return; + + const ci::vec3 origin = ci::vec3(mTransformOrigin.value(), 0.0f); + + mRotationScaleTransform = glm::translate(origin) // offset by origin + * glm::scale(ci::vec3(mScale.value(), 1.0f)) + * glm::toMat4(mRotation.value()) + * glm::translate(-origin); // reset to original position + + mTransform = glm::translate(ci::vec3(mPosition.value(), 0.0f)) + * mRotationScaleTransform; + + mGlobalTransform = mParent ? mParent->getGlobalTransform() * mTransform : mTransform; + + mHasInvalidTransforms = false; +} + +void BaseView::invalidate(const int flags) { + if ((flags & ValidationFlags::TRANSFORMS) == ValidationFlags::TRANSFORMS){ + mHasInvalidTransforms = true; + for (auto child : mChildren) { + child->invalidate(ValidationFlags::TRANSFORMS); + } + } + + if ((flags & ValidationFlags::CONTENT) == ValidationFlags::CONTENT) { + mHasInvalidContent = true; + } } //================================================== @@ -443,5 +493,12 @@ gl::BatchRef BaseView::getDefaultDrawBatch() { return defaultBatch; } +void BaseView::debugDrawOutline() { + const float hue = (float)mViewId / (float)sNumInstances; + const auto color = ColorAf(ci::hsvToRgb(vec3(hue, 1.0f, 1.0f)), 0.66f); + gl::color(color); + gl::drawStrokedRect(Rectf(vec2(0), getSize())); +} + } } diff --git a/src/bluecadet/views/BaseView.h b/src/bluecadet/views/BaseView.h index 7d9098c..7661f8a 100644 --- a/src/bluecadet/views/BaseView.h +++ b/src/bluecadet/views/BaseView.h @@ -17,6 +17,7 @@ #include "boost/variant.hpp" #include "ViewEvent.h" +#include "AnimOperators.h" namespace bluecadet { namespace views { @@ -47,10 +48,15 @@ class BaseView : public std::enable_shared_from_this { > UserInfoTypes; typedef std::map UserInfo; - typedef ci::signals::Signal EventSignal; + typedef ci::signals::Signal EventSignal; typedef ci::signals::Connection EventConnection; typedef EventSignal::CallbackFn EventCallback; + enum ValidationFlags { + TRANSFORMS = (1 << 0), + CONTENT = (1 << 1) + }; + //================================================== // Construct/destruct @@ -97,7 +103,7 @@ class BaseView : public std::enable_shared_from_this { ci::TimelineRef getTimeline(); //! Returns a shared pointer to this instance - inline BaseViewRef getSharedViewPtr() { return shared_from_this(); } + BaseViewRef getSharedViewPtr() { return shared_from_this(); } //! Resets all animatable properties to their defaults and resets all animations. Does not remove children. virtual void reset(); @@ -163,20 +169,16 @@ class BaseView : public std::enable_shared_from_this { virtual void setPosition(const ci::vec2& position) { mPosition = position; invalidate(); } virtual void setPosition(const ci::vec3& position) { mPosition = ci::vec2(position.x, position.y); invalidate(); } - //! Shorthand for combining position and size to center the view at `center` - virtual void setCenter(const ci::vec2 center) { setPosition(center - 0.5f * mSize); } - - //! Shorthand for getting the center based on the current position and size - virtual ci::vec2 getCenter() { return getPosition().value() + 0.5f * mSize; } - //! Local scale relative to parent view virtual ci::Anim& getScale() { return mScale; } virtual void setScale(const float& scale) { mScale = ci::vec2(scale, scale); invalidate(); } virtual void setScale(const ci::vec2& scale) { mScale = scale; invalidate(); } virtual void setScale(const ci::vec3& scale) { mScale = ci::vec2(scale.x, scale.y); invalidate(); } - //! Local rotation relative to parent view. Changing this value invalidates transforms. + //! Local rotation as quaternion. Changing this value invalidates transforms. virtual ci::Anim& getRotation() { return mRotation; } + //! Local rotation around Z axis in radians. + virtual float getRotationZ() const { return glm::two_pi() - glm::angle(mRotation.value()); } virtual void setRotation(const float radians) { mRotation = glm::angleAxis(radians, ci::vec3(0, 0, 1)); invalidate(); } virtual void setRotation(const ci::quat& rotation) { mRotation = rotation; invalidate(); } @@ -191,26 +193,26 @@ class BaseView : public std::enable_shared_from_this { void setTransformOrigin(const ci::vec2& value, const bool compensateForOffset); //! Size of this view. Defaults to 0, 0 and is not affected by children. Does not affect transforms (position, rotation, scale). - virtual const ci::vec2 getSize() { return mSize; } - virtual void setSize(const ci::vec2& size) { mSize = size; invalidate(false, true); } + virtual ci::Anim & getSize() { return mSize; } + virtual void setSize(const ci::vec2 & size) { if (mSize != size) { mSize = size; invalidate(ValidationFlags::CONTENT); } } //! Width of this view. Defaults to 0 and is not affected by children. - virtual float getWidth() { return getSize().x; } - virtual void setWidth(const float width) { ci::vec2 s = getSize(); setSize(ci::vec2(width, s.y)); } + virtual float getWidth() { return getSize().value().x; } + virtual void setWidth(const float width) { setSize(ci::vec2(width, getHeight())); } //! Height of this view. Defaults to 0 and is not affected by children. - virtual float getHeight() { return getSize().y; } - virtual void setHeight(const float height) { ci::vec2 s = getSize(); setSize(ci::vec2(s.x, height)); } + virtual float getHeight() { return getSize().value().y; } + virtual void setHeight(const float height) { setSize(ci::vec2(getWidth(), height)); } //! The fill color used when drawing the bounding rect when a size greater than 0, 0 is given. virtual ci::Anim& getBackgroundColor() { return mBackgroundColor; } - virtual void setBackgroundColor(const ci::Color color) { mBackgroundColor = ci::ColorA(color, 1.0f); invalidate(false, true); } //! Sets background color with 100% alpha - virtual void setBackgroundColor(const ci::ColorA color) { mBackgroundColor = color; invalidate(false, true); } + virtual void setBackgroundColor(const ci::Color color) { mBackgroundColor = ci::ColorA(color, 1.0f); invalidate(ValidationFlags::CONTENT); } //! Sets background color with 100% alpha + virtual void setBackgroundColor(const ci::ColorA color) { mBackgroundColor = color; invalidate(ValidationFlags::CONTENT); } //! Applied before each draw together with mAlpha; Defaults to white virtual ci::Anim& getTint() { return mTint; } - virtual void setTint(const ci::Color tint) { mTint = tint; invalidate(false, true); } //! Sets tint while preserving current alpha - virtual void setTint(const ci::ColorA tint) { mTint = tint; mAlpha = tint.a; invalidate(false, true); } //! Sets mTint and mAlpha properties + virtual void setTint(const ci::Color tint) { mTint = tint; invalidate(ValidationFlags::CONTENT); } //! Sets tint while preserving current alpha + virtual void setTint(const ci::ColorA tint) { mTint = tint; mAlpha = tint.a; invalidate(ValidationFlags::CONTENT); } //! Sets mTint and mAlpha properties //! Applied before each draw together with mTint; Gets multiplied with parent alpha; Defaults to 1.0f virtual ci::Anim& getAlpha() { return mAlpha; } @@ -228,15 +230,15 @@ class BaseView : public std::enable_shared_from_this { virtual void setHidden(const bool isHidden) { mIsHidden = isHidden; } //! Forces redrawing even when hidden or alpha <= 0; Defaults to false - virtual bool shouldForceInvisibleDraw() const { return mShouldForceInvisibleDraw; } - virtual void setShouldForceInvisibleDraw(const bool value) { mShouldForceInvisibleDraw = value; } + virtual bool getShouldDrawWhenInvisible() const { return mShouldDrawWhenInvisible; } + virtual void setShouldDrawWhenInvisible(const bool value) { mShouldDrawWhenInvisible = value; } //! Setting this to false will prevent events from propagating from this view to its parent. Defaults to true. - bool shouldPropagateEvents() const { return mShouldPropagateEvents; } + bool setShouldPropagateEvents() const { return mShouldPropagateEvents; } void setShouldPropagateEvents(const bool value) { mShouldPropagateEvents = value; } //! Setting this to false will prevent content invalidation events from being dispatched from this view. Defaults to true. - bool shouldDispatchContentInvalidation() const { return mShouldDispatchContentInvalidation; } + bool setShouldDispatchContentInvalidation() const { return mShouldDispatchContentInvalidation; } void setShouldDispatchContentInvalidation(const bool value) { mShouldDispatchContentInvalidation = value; } //! Unique ID per view. @@ -303,38 +305,51 @@ class BaseView : public std::enable_shared_from_this { protected: - virtual void update(const double deltaTime); //! Gets called before draw() and after any parent's update. Override this method to plug into the update loop. + //! Override this method to plug into the update loop. + //! Gets called before draw() and after any parent's update. + //! Always gets called, even if view is hidden or alpha is <= 0 + virtual void update(const double deltaTime); - inline virtual void willDraw() {} //! Called by drawScene before draw() - virtual void draw(); //! Called by drawScene and allows for drawing content for this node. By default draws a rectangle with the current size and background color (only if x/y /bg-alpha > 0) - virtual void debugDrawOutline(); //! Called in DEBUG if sDebugDrawBounds is set to true. - inline virtual void drawChildren(const ci::ColorA& parentTint); //! Called by drawScene() after draw() and before didDraw(). Implemented at bottom of class. - inline virtual void didDraw() {} //! Called by drawScene after draw() + //! Override this method to plug into the draw loop. + //! Called by drawScene and allows for drawing content for this node. + //! By default draws a rectangle with the current size and background color. + //! Only gets called if visible (not hidden or alpha > 0), unless getShouldDrawWhenInvisible() is true. + virtual void draw(); - inline virtual void didMoveToView(BaseView* parent) {} //! Called when moved to a parent - inline virtual void willMoveFromView(BaseView* parent) {} //! Called when removed from a parent + virtual void willDraw() {} //! Called by drawScene before draw() + virtual void drawChildren(const ci::ColorA& parentTint); //! Called by drawScene() after draw() and before didDraw(). Implemented at bottom of class. + virtual void didDraw() {} //! Called by drawScene after draw() - const ci::ColorA& getDrawColor() const { return mDrawColor; } //! The color used for drawing, which is a composite of the alpha and tint colors. + virtual void didMoveToView(BaseView* parent) {} //! Called when moved to a parent + virtual void willMoveFromView(BaseView* parent) {} //! Called when removed from a parent + + virtual void handleSizeUpdated(const ci::vec2 & size) {}; //! Called when size is updated via an animation or setSize() + + //! The color used for drawing, which is a composite of the alpha and tint colors. + const ci::ColorA& getDrawColor() const { return mDrawColor; } //! This will recalculate the transformation matrix based on the current position, scale and rotation. Gets called automatically before getTransforms(), getGlobalTransforms() or getGlobalPosition() is called. - inline void validateTransforms(const bool force = false); + virtual void validateTransforms(const bool force = false); //! Marks the transformation matrix (and all of its children's matrices) as invalid. This will cause the matrices to be re-calculated when necessary. //! When content is true, marks the content as invalid and will dispatch a content updated event - inline void invalidate(const bool transforms = true, const bool content = true); + virtual void invalidate(const int flags = (ValidationFlags::TRANSFORMS | ValidationFlags::CONTENT)); //! True if any properties that visually modifies this view has been changed since the last call of validateContent(). virtual bool hasInvalidContent() const { return mHasInvalidContent; } virtual void validateContent() { mHasInvalidContent = false; } + //! Called in DEBUG if sDebugDrawBounds is set to true. + virtual void debugDrawOutline(); + private: // Helpers - inline BaseViewList::iterator getChildIt(BaseViewRef child); - inline BaseViewList::iterator getChildIt(BaseView* childPtr); + BaseViewList::iterator getChildIt(BaseViewRef child); + BaseViewList::iterator getChildIt(BaseView* childPtr); - inline static ci::gl::BatchRef getDefaultDrawBatch(); //! Default shader batch that draws the background in the default implementation of draw(). - inline static ci::gl::GlslProgRef getDefaultDrawProg(); //! Default glsl program used by the default batch that draws a rectangular background using background color and size. + static ci::gl::BatchRef getDefaultDrawBatch(); //! Default shader batch that draws the background in the default implementation of draw(). + static ci::gl::GlslProgRef getDefaultDrawProg(); //! Default glsl program used by the default batch that draws a rectangular background using background color and size. static size_t sNumInstances; @@ -346,10 +361,10 @@ class BaseView : public std::enable_shared_from_this { ci::Anim mAlpha; ci::Anim mTint; ci::Anim mBackgroundColor; - ci::vec2 mSize; + ci::Anim mSize; bool mIsHidden; - bool mShouldForceInvisibleDraw; + bool mShouldDrawWhenInvisible; BlendMode mBlendMode; ci::ColorA mDrawColor; //! Combines mAlpha and mTint for faster draw @@ -382,59 +397,5 @@ class BaseView : public std::enable_shared_from_this { -//================================================== -// Inline implementations to improve speed on frequently used methods -// - -void BaseView::drawChildren(const ci::ColorA& parentTint) { - for (auto child : mChildren) { - child->drawScene(parentTint); - } -} - -void BaseView::validateTransforms(const bool force) { - if (!mHasInvalidTransforms && !force) return; - - const ci::vec3 origin = ci::vec3(mTransformOrigin.value(), 0.0f); - - mRotationScaleTransform = glm::translate(origin) // offset by origin - * glm::scale(ci::vec3(mScale.value(), 1.0f)) - * glm::toMat4(mRotation.value()) - * glm::translate(-origin); // reset to original position - - mTransform = glm::translate(ci::vec3(mPosition.value(), 0.0f)) - * mRotationScaleTransform; - - mGlobalTransform = mParent ? mParent->getGlobalTransform() * mTransform : mTransform; - - mHasInvalidTransforms = false; -} - -inline void BaseView::invalidate(const bool transforms, const bool content) { - if (transforms) { - mHasInvalidTransforms = true; - for (auto child : mChildren) { - child->invalidate(true, false); - } - } - - if (content) { - mHasInvalidContent = true; - } -} - -BaseViewList::iterator BaseView::getChildIt(BaseViewRef child) { - if (!child || child->mParent != this) return mChildren.end(); - return std::find(mChildren.begin(), mChildren.end(), child); -} - -BaseViewList::iterator BaseView::getChildIt(BaseView* childPtr) { - if (!childPtr || childPtr->mParent != this) return mChildren.end(); - return std::find_if(mChildren.begin(), mChildren.end(), [&](BaseViewRef child) { - return child.get() == childPtr; - }); -} - - } } diff --git a/src/bluecadet/views/CircleOutlineView.cpp b/src/bluecadet/views/CircleOutlineView.cpp index 5528adb..c473ac8 100644 --- a/src/bluecadet/views/CircleOutlineView.cpp +++ b/src/bluecadet/views/CircleOutlineView.cpp @@ -35,8 +35,8 @@ void CircleOutlineView::setRadius(const float radius) { } void CircleOutlineView::draw() { - const auto& bgColor = getBackgroundColor().value(); - const auto& size = getSize(); + const auto & bgColor = getBackgroundColor().value(); + const auto & size = getSize().value(); if (size.x <= 0 && size.y <= 0 && bgColor.a <= 0) { return; @@ -44,7 +44,7 @@ void CircleOutlineView::draw() { auto batch = getSharedEllipseBatch(); auto prog = batch->getGlslProg(); - prog->uniform("uSize", getSize()); + prog->uniform("uSize", size); prog->uniform("uBackgroundColor", vec4(bgColor.r, bgColor.g, bgColor.b, bgColor.a)); prog->uniform("uSmoothness", mSmoothness); prog->uniform("uBorderThickness", mBorderThickness); diff --git a/src/bluecadet/views/CircleOutlineView.h b/src/bluecadet/views/CircleOutlineView.h index f0b9fa1..a09c3dd 100644 --- a/src/bluecadet/views/CircleOutlineView.h +++ b/src/bluecadet/views/CircleOutlineView.h @@ -28,15 +28,15 @@ class CircleOutlineView : public BaseView { void setRadius(const float radius); //! The smoothness of the ellipse's edge - inline float getSmoothness() const { return mSmoothness; } - inline void setSmoothness(const float value) { mSmoothness = value; invalidate(false, true); } + float getSmoothness() const { return mSmoothness; } + void setSmoothness(const float value) { mSmoothness = value; invalidate(ValidationFlags::CONTENT); } - inline float getBorderThickness() const { return mBorderThickness; } - inline void setBorderThickness(const float value) { mBorderThickness = value; invalidate(false, true); } + float getBorderThickness() const { return mBorderThickness; } + void setBorderThickness(const float value) { mBorderThickness = value; invalidate(ValidationFlags::CONTENT); } protected: - virtual void draw() override; - virtual void debugDrawOutline() override; + void draw() override; + void debugDrawOutline() override; static ci::gl::BatchRef getSharedEllipseBatch(); static ci::gl::GlslProgRef getSharedEllipseProg(); diff --git a/src/bluecadet/views/EllipseView.cpp b/src/bluecadet/views/EllipseView.cpp index 22c4c0b..6530b9c 100644 --- a/src/bluecadet/views/EllipseView.cpp +++ b/src/bluecadet/views/EllipseView.cpp @@ -34,8 +34,8 @@ void EllipseView::setRadius(const float radius) } void EllipseView::draw() { - const auto& bgColor = getBackgroundColor().value(); - const auto& size = getSize(); + const auto & bgColor = getBackgroundColor().value(); + const auto & size = getSize().value(); if (size.x <= 0 && size.y <= 0 && bgColor.a <= 0) { return; @@ -43,7 +43,7 @@ void EllipseView::draw() { auto batch = getSharedEllipseBatch(); auto prog = batch->getGlslProg(); - prog->uniform("uSize", getSize()); + prog->uniform("uSize", size); prog->uniform("uBackgroundColor", vec4(bgColor.r, bgColor.g, bgColor.b, bgColor.a)); prog->uniform("uSmoothness", mSmoothness); batch->draw(); diff --git a/src/bluecadet/views/EllipseView.h b/src/bluecadet/views/EllipseView.h index 8e7afae..3f69993 100644 --- a/src/bluecadet/views/EllipseView.h +++ b/src/bluecadet/views/EllipseView.h @@ -29,11 +29,11 @@ class EllipseView : public BaseView { //! The smoothness of the ellipse's edge ci::Anim & getSmoothness() { return mSmoothness; } - void setSmoothness(const float value) { mSmoothness = value; invalidate(false, true); } + void setSmoothness(const float value) { mSmoothness = value; invalidate(ValidationFlags::CONTENT); } protected: - virtual void draw() override; - virtual void debugDrawOutline() override; + void draw() override; + void debugDrawOutline() override; static ci::gl::BatchRef getSharedEllipseBatch(); static ci::gl::GlslProgRef getSharedEllipseProg(); diff --git a/src/bluecadet/views/FboView.cpp b/src/bluecadet/views/FboView.cpp index e33978b..cefb41c 100644 --- a/src/bluecadet/views/FboView.cpp +++ b/src/bluecadet/views/FboView.cpp @@ -1,4 +1,5 @@ #include "FboView.h" +#include "cinder/Log.h" using namespace ci; using namespace ci::app; @@ -48,12 +49,12 @@ void FboView::validateFbo(){ if (size.x > 0 && size.y > 0) { mFbo = createFbo(size, getFboFormat()); // Invalidate content to confirm it will redraw to fbo - invalidate(false, true); + invalidate(ValidationFlags::CONTENT); } } -inline void FboView::validateContent(){ - if (!mFbo) { +void FboView::validateContent(){ + if (!mFbo || mFbo->getSize() != ivec2(getSize().value())) { validateFbo(); } @@ -83,21 +84,21 @@ inline void FboView::validateContent(){ BaseView::validateContent(); } else { - console() << "FboView Warning: No fbo to validate content in (size: " << getSize() << ")" << endl; + CI_LOG_W("No fbo to validate content in (size: " << getSize().value() << ")"); } } void FboView::handleEvent(ViewEvent& event) { if (event.type == ViewEvent::Type::CONTENT_INVALIDATED) { - invalidate(false, true); + invalidate(ValidationFlags::CONTENT); } } void FboView::draw() { if (!mFbo) { - console() << "FboView Warning: No fbo to draw to (size: " << getSize() << ")" << endl; + CI_LOG_W("No fbo to validate content in (size: " << getSize().value() << ")"); return; } diff --git a/src/bluecadet/views/FboView.h b/src/bluecadet/views/FboView.h index ad9ce98..bc466ca 100644 --- a/src/bluecadet/views/FboView.h +++ b/src/bluecadet/views/FboView.h @@ -24,7 +24,7 @@ class FboView : public BaseView { void setSize(const ci::vec2 & size) override; //! Will re-create the current fbo on the next draw call and marks the content to be re-drawn. - virtual void invalidateFbo() { mFbo = nullptr; invalidate(false, true); } + virtual void invalidateFbo() { mFbo = nullptr; invalidate(ValidationFlags::CONTENT); } //! Will create a new fbo with this format. virtual void setFboFormat(const ci::gl::Fbo::Format & format) { mFboFormat = format; invalidateFbo(); } @@ -64,7 +64,7 @@ class FboView : public BaseView { void validateFbo(); //! Redraw the fbo children - inline void validateContent() override; + void validateContent() override; //! Draw content within this view void draw() override; diff --git a/src/bluecadet/views/GraphView.cpp b/src/bluecadet/views/GraphView.cpp index 6c31f3f..bb08509 100644 --- a/src/bluecadet/views/GraphView.cpp +++ b/src/bluecadet/views/GraphView.cpp @@ -112,7 +112,7 @@ inline void GraphView::render() { gl::clear(ColorA(0, 0, 0, 0.25)); static const Font labelFont("Arial", 16); - vec2 labelPos(0, getSize().y); + vec2 labelPos(0, getSize().value().y); for (const auto & graphPair : mGraphs) { const auto & graph = graphPair.second; diff --git a/src/bluecadet/views/ImageView.cpp b/src/bluecadet/views/ImageView.cpp index 642581a..9ecd15d 100644 --- a/src/bluecadet/views/ImageView.cpp +++ b/src/bluecadet/views/ImageView.cpp @@ -10,7 +10,7 @@ namespace views { ImageView::ImageView() : BaseView(), mTexture(nullptr), -mScaleMode(ScaleMode::NONE) +mScaleMode(ScaleMode::STRETCH) { } @@ -26,7 +26,6 @@ void ImageView::clearTexture() { mTexture = nullptr; mDrawingDestRect = Rectf(); mDrawingArea = Area(); - mScaleMode = ScaleMode::NONE; } void ImageView::setup(const gl::TextureRef texture, const ci::vec2 &size, const ScaleMode scaleMode) { @@ -54,13 +53,15 @@ void ImageView::setTexture(ci::gl::TextureRef texture, const bool resizeToTextur } } - invalidate(false, true); + invalidate(ValidationFlags::CONTENT); } -void ImageView::setSize(const ci::vec2& size) { - BaseView::setSize(size); +void ImageView::validateContent() { + if (!hasInvalidContent()) { + return; + } - mDrawingDestRect = Rectf(vec2(0), size); + mDrawingDestRect = Rectf(vec2(0), getSize().value()); if (mTexture) { // Aspect fill drawing area @@ -68,6 +69,8 @@ void ImageView::setSize(const ci::vec2& size) { } else { mDrawingArea = Area(); } + + BaseView::validateContent(); } void ImageView::draw() { diff --git a/src/bluecadet/views/ImageView.h b/src/bluecadet/views/ImageView.h index beaceb8..8ce0890 100644 --- a/src/bluecadet/views/ImageView.h +++ b/src/bluecadet/views/ImageView.h @@ -36,8 +36,6 @@ class ImageView : public BaseView { virtual void setup(const ci::gl::TextureRef texture, const ci::vec2& size = ci::vec2(0), const ScaleMode scaleMode = ScaleMode::COVER); - virtual void setSize(const ci::vec2& size) override; - inline ci::gl::TextureRef getTexture() const { return mTexture; } inline void setTexture(const ci::gl::TextureRef value, const bool resizeToTexture = true); @@ -45,8 +43,8 @@ class ImageView : public BaseView { inline void setScaleMode(const ScaleMode scaleMode) { mScaleMode = scaleMode; } private: - - virtual void draw() override; + void validateContent() override; + void draw() override; ci::gl::TextureRef mTexture; ci::Rectf mDrawingDestRect; diff --git a/src/bluecadet/views/LineView.h b/src/bluecadet/views/LineView.h index 2b2c77d..104a241 100644 --- a/src/bluecadet/views/LineView.h +++ b/src/bluecadet/views/LineView.h @@ -25,11 +25,11 @@ class LineView : public BaseView { //! The thickness of the line. Defaults to 1.0f. inline ci::Anim getLineWidth() const { return mLineWidth; } - inline void setLineWidth(const float value) { mLineWidth = value; invalidate(false, true); } + inline void setLineWidth(const float value) { mLineWidth = value; invalidate(ValidationFlags::CONTENT); } //! The color of the line. Defaults to fully opaque white. inline const ci::Anim& getLineColor() const { return mLineColor; } - inline void setLineColor(const ci::ColorA& value) { mLineColor = value; invalidate(false, true); } + inline void setLineColor(const ci::ColorA& value) { mLineColor = value; invalidate(ValidationFlags::CONTENT); } protected: virtual void draw() override; diff --git a/src/bluecadet/views/TextView.cpp b/src/bluecadet/views/TextView.cpp index daedb74..5cde944 100644 --- a/src/bluecadet/views/TextView.cpp +++ b/src/bluecadet/views/TextView.cpp @@ -1,6 +1,7 @@ #include "TextView.h" #include "bluecadet/text/StyleManager.h" +#include "cinder/Log.h" #if defined(CINDER_MSW) @@ -64,6 +65,55 @@ void TextView::willDraw() { } } +void TextView::setSize(const ci::vec2& size) { + BaseView::setSize(size); + StyledTextLayout::setMaxSize(size); +} + +void TextView::setWidth(float value) { + BaseView::setSize(vec2(value, getHeight())); + StyledTextLayout::setMaxSize(vec2(value, getMaxHeight())); +} + +void TextView::setHeight(float value) { + BaseView::setSize(vec2(getWidth(), value)); + StyledTextLayout::setMaxSize(vec2(getMaxWidth(), value)); +} + +ci::Anim& TextView::getSize() { + validateContent(); + return BaseView::getSize(); +} + +void TextView::validateContent() { + if (!hasInvalidContent()) { + return; + } + + // Check if max size should be changed to view size + vec2 viewSize = BaseView::getSize().value(); + vec2 maxSize = StyledTextLayout::getMaxSize(); + + if (viewSize.x > 0 && maxSize.x > 0) { + maxSize.x = viewSize.x; + } + if (viewSize.y > 0 && maxSize.y > 0) { + maxSize.x = viewSize.x; + } + + StyledTextLayout::setMaxSize(maxSize); + StyledTextLayout::validateSize(); + + // Check if view size should be changed to text size + const vec2 & textSize = StyledTextLayout::getTextSize(); + + viewSize.x = glm::max(maxSize.x, textSize.x); + viewSize.y = glm::max(maxSize.y, textSize.y); + + BaseView::setSize(viewSize); + BaseView::validateContent(); +} + void TextView::draw() { BaseView::draw(); if (mTexture) { @@ -91,7 +141,12 @@ void TextView::renderContent(bool surfaceOnly, bool alpha, bool premultiplied, b mTexture = nullptr; // reset texture to save memory } else { - mTexture = gl::Texture2d::create(mSurface, createTextureFormat(mSmoothScalingEnabled)); + if (mTexture && mTexture->getSize() == mSurface.getSize()) { + mTexture->update(mSurface); + } else { + mTexture = gl::Texture2d::create(mSurface, createTextureFormat(mSmoothScalingEnabled)); + } + mSurface = ci::Surface(); // reset surface to save memory } @@ -99,10 +154,18 @@ void TextView::renderContent(bool surfaceOnly, bool alpha, bool premultiplied, b } void TextView::invalidate(const bool layout, const bool size) { + BaseView::invalidate(ValidationFlags::CONTENT); StyledTextLayout::invalidate(layout, size); mHasInvalidRenderedContent = true; +} - BaseView::invalidate(false, true); +void TextView::invalidate(const int flags) { + BaseView::invalidate(flags); + + const bool contentChanged = (flags & ValidationFlags::CONTENT) == ValidationFlags::CONTENT; + StyledTextLayout::invalidate(contentChanged, contentChanged); + + mHasInvalidRenderedContent = mHasInvalidRenderedContent || contentChanged; } void TextView::resetRenderedContent() { @@ -110,30 +173,6 @@ void TextView::resetRenderedContent() { mSurface = ci::Surface(); } -void TextView::setSize(const ci::vec2& size) { - invalidate(); - setMaxSize(size); -} - -inline void TextView::setWidth(const float width){ - invalidate(); - setMaxWidth(width); -} - -inline void TextView::setHeight(const float height){ - invalidate(); - setMaxHeight(height); -} - -const ci::vec2 TextView::getSize() { - const vec2 maxSize = StyledTextLayout::getTextSize(); - const vec2 textSize = StyledTextLayout::getTextSize(); - return vec2( - max(maxSize.x, textSize.x), - max(maxSize.y, textSize.y) - ); -} - ci::gl::Texture::Format TextView::createTextureFormat(bool smoothScaling) const { gl::Texture::Format format; format.immutableStorage(true); diff --git a/src/bluecadet/views/TextView.h b/src/bluecadet/views/TextView.h index b6e2a31..9f0aa61 100644 --- a/src/bluecadet/views/TextView.h +++ b/src/bluecadet/views/TextView.h @@ -59,31 +59,29 @@ class TextView : public BaseView, public text::StyledTextLayout { bool getPremultiplied() const { return mPremultiplied; } void setPremultiplied(const bool value) { mPremultiplied = value; } - //! Sets a fixed size for the text view. Any values below 0 will allow the text view to automatically expand in that direction. - virtual inline void setSize(const ci::vec2& size) override; - virtual inline void setWidth(const float width) override; - virtual inline void setHeight(const float height) override; + //! Sets a fixed, max size for the text view. Any values below 0 will allow the text view to automatically expand in that direction. + void setSize(const ci::vec2& size) override; + void setWidth(const float value) override; + void setHeight(const float value) override; + + ci::Anim & getSize() override; - //! Returns the actual size of the text including padding. - //! In advanced use-cases this can differ from what was set in setSize(), e.g. if a special clip mode is set or size-trimming is enabled. - virtual inline const ci::vec2 getSize() override; protected: //! Will update the text texture if necessary. - virtual void willDraw() override; - virtual void draw() override; + void willDraw() override; + void draw() override; ci::gl::Texture::Format createTextureFormat(bool smoothScaling) const; - inline void invalidate(const bool layout = true, const bool size = true) override; + void validateContent() override; + void invalidate(const bool layout, const bool) override; + void invalidate(const int flags) override; // Change visibility of these methods from public to protected since setSize()/getSize() should be used. - virtual ci::vec2 getMaxSize() const override { return StyledTextLayout::getMaxSize(); }; - virtual void setMaxSize(const ci::vec2& size) override { return StyledTextLayout::setMaxSize(size); }; - virtual float getMaxWidth() const override { return StyledTextLayout::getMaxWidth(); }; - virtual void setMaxWidth(const float value) override { return StyledTextLayout::setMaxWidth(value); }; - virtual float getMaxHeight() const override { return StyledTextLayout::getMaxHeight(); }; - virtual void setMaxHeight(const float value) override { return StyledTextLayout::setMaxHeight(value); }; + void setMaxSize(const ci::vec2& size) override { return StyledTextLayout::setMaxSize(size); }; + void setMaxWidth(const float value) override { return StyledTextLayout::setMaxWidth(value); }; + void setMaxHeight(const float value) override { return StyledTextLayout::setMaxHeight(value); }; bool mHasInvalidRenderedContent; bool mSmoothScalingEnabled; diff --git a/src/bluecadet/views/TouchView.h b/src/bluecadet/views/TouchView.h index 3815d81..525ae68 100644 --- a/src/bluecadet/views/TouchView.h +++ b/src/bluecadet/views/TouchView.h @@ -34,7 +34,7 @@ class TouchView : public BaseView { virtual ~TouchView(); //! Calls BaseView::reset() and cancels/ends all existing touches on this view. - virtual void reset() override; + void reset() override; //! Sets the size of this touch view and clears any existing touch path. You also just call setSize(). virtual void setup(const ci::vec2 size);