From 962639c6841961d077273697581b087abbf1f73b Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Tue, 15 Dec 2015 11:53:15 -1000 Subject: [PATCH] Made SplashScreen background a generic ModalWindow class --- specter/CMakeLists.txt | 4 + specter/include/Specter/Button.hpp | 9 + specter/include/Specter/Control.hpp | 2 +- specter/include/Specter/FileBrowser.hpp | 58 ++++ specter/include/Specter/ModalWindow.hpp | 71 +++++ specter/include/Specter/ScrollView.hpp | 12 +- specter/include/Specter/Table.hpp | 13 + specter/include/Specter/TextField.hpp | 13 + specter/include/Specter/View.hpp | 82 ++++++ specter/lib/FileBrowser.cpp | 129 +++++++++ specter/lib/ModalWindow.cpp | 357 ++++++++++++++++++++++++ specter/lib/ScrollView.cpp | 4 +- specter/lib/Table.cpp | 11 + specter/lib/TextField.cpp | 11 + specter/lib/TextView.cpp | 6 +- specter/lib/View.cpp | 21 +- 16 files changed, 789 insertions(+), 14 deletions(-) create mode 100644 specter/include/Specter/FileBrowser.hpp create mode 100644 specter/include/Specter/ModalWindow.hpp create mode 100644 specter/lib/FileBrowser.cpp create mode 100644 specter/lib/ModalWindow.cpp diff --git a/specter/CMakeLists.txt b/specter/CMakeLists.txt index f9455427c..74d62b2bc 100644 --- a/specter/CMakeLists.txt +++ b/specter/CMakeLists.txt @@ -35,6 +35,7 @@ list(APPEND SPECTER_HEADERS include/Specter/DeferredWindowEvents.hpp include/Specter/View.hpp include/Specter/RootView.hpp + include/Specter/ModalWindow.hpp include/Specter/Tooltip.hpp include/Specter/SplitView.hpp include/Specter/ScrollView.hpp @@ -52,6 +53,7 @@ list(APPEND SPECTER_HEADERS include/Specter/Menu.hpp include/Specter/Node.hpp include/Specter/NodeSocket.hpp + include/Specter/FileBrowser.hpp include/Specter/FontCache.hpp include/Specter/Translator.hpp) @@ -62,6 +64,7 @@ list(APPEND SPECTER_SOURCES lib/ViewResources.cpp lib/View.cpp lib/RootView.cpp + lib/ModalWindow.cpp lib/Tooltip.cpp lib/SplitView.cpp lib/ScrollView.cpp @@ -79,6 +82,7 @@ list(APPEND SPECTER_SOURCES lib/Menu.cpp lib/Node.cpp lib/NodeSocket.cpp + lib/FileBrowser.cpp lib/FontCache.cpp lib/Translator.cpp atdna_FontCache.cpp) diff --git a/specter/include/Specter/Button.hpp b/specter/include/Specter/Button.hpp index bfe723147..7d69a983a 100644 --- a/specter/include/Specter/Button.hpp +++ b/specter/include/Specter/Button.hpp @@ -63,9 +63,18 @@ public: void setText(const std::string& text, const Zeus::CColor& textColor); void setText(const std::string& text); + const std::string& getText() const {return m_textStr;} void colorGlyphs(const Zeus::CColor& newColor); int nominalWidth() const {return m_nomWidth;} int nominalHeight() const {return m_nomHeight;} + + void setMultiplyColor(const Zeus::CColor& color) + { + View::setMultiplyColor(color); + m_bBlock.m_color = color; + m_bBlockBuf->load(&m_bBlock, sizeof(ViewBlock)); + m_text->setMultiplyColor(color); + } }; } diff --git a/specter/include/Specter/Control.hpp b/specter/include/Specter/Control.hpp index a31b55183..2cac3a102 100644 --- a/specter/include/Specter/Control.hpp +++ b/specter/include/Specter/Control.hpp @@ -10,7 +10,7 @@ namespace Specter struct IControlBinding { virtual const char* name() const=0; - virtual const char* help() const=0; + virtual const char* help() const {return nullptr;} }; struct IButtonBinding : IControlBinding diff --git a/specter/include/Specter/FileBrowser.hpp b/specter/include/Specter/FileBrowser.hpp new file mode 100644 index 000000000..a5a17eaf7 --- /dev/null +++ b/specter/include/Specter/FileBrowser.hpp @@ -0,0 +1,58 @@ +#ifndef SPECTER_FILEBROWSER_HPP +#define SPECTER_FILEBROWSER_HPP + +#include "View.hpp" +#include "ModalWindow.hpp" +#include "Button.hpp" +#include "TextField.hpp" +#include "ScrollView.hpp" +#include "Table.hpp" +#include + +namespace Specter +{ + +class FileBrowser : public ModalWindow +{ + std::vector m_comps; + + void pathButtonActivated(size_t idx); + struct PathButton : Specter::IButtonBinding + { + FileBrowser& m_fb; + size_t m_idx; + Specter::ViewChild m_button; + PathButton(FileBrowser& fb, ViewResources& res, size_t idx, const HECL::SystemString& str) + : m_fb(fb), m_idx(idx) + { + HECL::SystemUTF8View utf8View(str); + m_button.m_view.reset(new Specter::Button(res, fb, this, utf8View)); + } + const char* name() const {return m_button.m_view->getText().c_str();} + void activated(const boo::SWindowCoord&) {m_fb.pathButtonActivated(m_idx);} + }; + friend struct PathButton; + std::vector m_pathButtons; + + Specter::ViewChild m_fileField; + Specter::ViewChild m_fileScroll; + Specter::ViewChild m_fileListing; + +public: + FileBrowser(ViewResources& res, View& parentView) + : FileBrowser(res, parentView, HECL::GetcwdStr()) {} + FileBrowser(ViewResources& res, View& parentView, const HECL::SystemString& initialPath); + void updateContentOpacity(float opacity); + + void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey); + void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey); + void mouseMove(const boo::SWindowCoord&); + void mouseEnter(const boo::SWindowCoord&); + void mouseLeave(const boo::SWindowCoord&); + void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); + void draw(boo::IGraphicsCommandQueue* gfxQ); +}; + +} + +#endif // SPECTER_FILEBROWSER_HPP diff --git a/specter/include/Specter/ModalWindow.hpp b/specter/include/Specter/ModalWindow.hpp new file mode 100644 index 000000000..bf47f2d9c --- /dev/null +++ b/specter/include/Specter/ModalWindow.hpp @@ -0,0 +1,71 @@ +#ifndef SPECTER_MODAL_WINDOW_HPP +#define SPECTER_MODAL_WINDOW_HPP + +#include +#include + +namespace Specter +{ +class ModalWindow : public View +{ + unsigned m_frame = 0; + unsigned m_contentStartFrame = 0; + float m_lineTime = 0.0; + + enum class Phase + { + BuildIn, + ResWait, + Showing, + BuildOut, + Done + } m_phase = Phase::BuildIn; + + int m_width = 0; + int m_height = 0; + int m_widthConstrain; + int m_heightConstrain; + + Zeus::CColor m_windowBg; + Zeus::CColor m_windowBgClear; + Zeus::CColor m_line1; + Zeus::CColor m_line2; + + ViewBlock m_viewBlock; + boo::IGraphicsBufferD* m_viewBlockBuf; + struct + { + SolidShaderVert lineVerts[22]; + SolidShaderVert fillVerts[16]; + } m_verts; + + void setLineVerts(int width, int height, float pf, float t); + void setLineColors(float t); + void setFillVerts(int width, int height, float pf); + void setFillColors(float t); + + boo::IGraphicsBufferD* m_vertsBuf; + boo::IVertexFormat* m_vertsVtxFmt; /* OpenGL only */ + boo::IShaderDataBinding* m_vertsShaderBinding; + + boo::IGraphicsDataToken m_windowGfxData; + + std::unique_ptr m_cornersOutline[4]; + std::unique_ptr m_cornersFilled[4]; + +protected: + virtual void updateContentOpacity(float opacity) {} + +public: + ModalWindow(ViewResources& res, View& parentView, int widthConstrain=-1, int heightConstrain=-1); + void think(); + bool skipBuildInAnimation(); + + void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); + void draw(boo::IGraphicsCommandQueue* gfxQ); +}; + +} + + +#endif // SPECTER_MODAL_WINDOW_HPP diff --git a/specter/include/Specter/ScrollView.hpp b/specter/include/Specter/ScrollView.hpp index 46a9937e7..79c317ed5 100644 --- a/specter/include/Specter/ScrollView.hpp +++ b/specter/include/Specter/ScrollView.hpp @@ -9,9 +9,17 @@ class ViewResources; class ScrollView : public View { - View& m_contentView; public: - ScrollView(ViewResources& res, View& parentView, View& contentView); + enum class Style + { + + }; + +private: + View* m_contentView = nullptr; + +public: + ScrollView(ViewResources& res, View& parentView); }; } diff --git a/specter/include/Specter/Table.hpp b/specter/include/Specter/Table.hpp index 29e212357..b82232108 100644 --- a/specter/include/Specter/Table.hpp +++ b/specter/include/Specter/Table.hpp @@ -1,4 +1,17 @@ #ifndef SPECTER_TABLE_HPP #define SPECTER_TABLE_HPP +#include "View.hpp" + +namespace Specter +{ + +class Table : public View +{ +public: + Table(ViewResources& res, View& parentView); +}; + +} + #endif // SPECTER_TABLE_HPP diff --git a/specter/include/Specter/TextField.hpp b/specter/include/Specter/TextField.hpp index 30737c263..0e3307863 100644 --- a/specter/include/Specter/TextField.hpp +++ b/specter/include/Specter/TextField.hpp @@ -1,4 +1,17 @@ #ifndef SPECTER_TEXTFIELD_HPP #define SPECTER_TEXTFIELD_HPP +#include "View.hpp" + +namespace Specter +{ + +class TextField : public View +{ +public: + TextField(ViewResources& res, View& parentView); +}; + +} + #endif // SPECTER_TEXTFIELD_HPP diff --git a/specter/include/Specter/View.hpp b/specter/include/Specter/View.hpp index 3fe763b9b..d4aff70d7 100644 --- a/specter/include/Specter/View.hpp +++ b/specter/include/Specter/View.hpp @@ -49,6 +49,7 @@ protected: struct ViewBlock { Zeus::CMatrix4f m_mv; + Zeus::CColor m_color = Zeus::CColor::skWhite; void setViewRect(const boo::SWindowRect& root, const boo::SWindowRect& sub) { m_mv[0][0] = 2.0f / root.size[0]; @@ -61,16 +62,19 @@ protected: "uniform SpecterViewBlock\n"\ "{\n"\ " mat4 mv;\n"\ + " vec4 mulColor;\n"\ "};\n" #define SPECTER_VIEW_VERT_BLOCK_HLSL\ "cbuffer SpecterViewBlock : register(b0)\n"\ "{\n"\ " float4x4 mv;\n"\ + " float4 mulColor;\n"\ "};\n" #define SPECTER_VIEW_VERT_BLOCK_METAL\ "struct SpecterViewBlock\n"\ "{\n"\ " float4x4 mv;\n"\ + " float4 mulColor;\n"\ "};\n" boo::IGraphicsBufferD* m_viewVertBlockBuf; @@ -114,6 +118,11 @@ public: m_bgRect[i].m_color = color; m_bgVertBuf->load(&m_bgRect, sizeof(SolidShaderVert) * 4); } + void setMultiplyColor(const Zeus::CColor& color) + { + m_viewVertBlock.m_color = color; + m_viewVertBlockBuf->load(&m_viewVertBlock, sizeof(ViewBlock)); + } virtual int nominalWidth() const {return 0;} virtual int nominalHeight() const {return 0;} @@ -128,6 +137,79 @@ public: virtual void draw(boo::IGraphicsCommandQueue* gfxQ); }; +template +struct ViewChild +{ + std::unique_ptr m_view; + bool m_mouseIn = false; + bool m_mouseDown = false; + + void mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) + { + if (!m_view) + return; + if (m_view->subRect().coordInRect(coord)) + { + if (!m_mouseDown) + { + m_view->mouseDown(coord, button, mod); + m_mouseDown = true; + } + } + } + + void mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) + { + if (!m_view) + return; + if (m_mouseDown) + { + m_view->mouseUp(coord, button, mod); + m_mouseDown = false; + } + } + + void mouseMove(const boo::SWindowCoord& coord) + { + if (!m_view) + return; + if (m_view->subRect().coordInRect(coord)) + { + if (!m_mouseIn) + { + m_view->mouseEnter(coord); + m_mouseIn = true; + } + m_view->mouseMove(coord); + } + else + { + if (m_mouseIn) + { + m_view->mouseLeave(coord); + m_mouseIn = false; + } + } + } + + void mouseEnter(const boo::SWindowCoord& coord) + { + if (!m_view) + return; + } + + void mouseLeave(const boo::SWindowCoord& coord) + { + if (!m_view) + return; + if (m_mouseIn) + { + m_view->mouseLeave(coord); + m_mouseIn = false; + } + } +}; + } #endif // SPECTER_VIEW_HPP diff --git a/specter/lib/FileBrowser.cpp b/specter/lib/FileBrowser.cpp new file mode 100644 index 000000000..caa1e18d5 --- /dev/null +++ b/specter/lib/FileBrowser.cpp @@ -0,0 +1,129 @@ +#include "Specter/FileBrowser.hpp" +#include "Specter/RootView.hpp" + +namespace Specter +{ + +#define BROWSER_MARGIN 30 +#define BROWSER_MIN_WIDTH 100 +#define BROWSER_MIN_HEIGHT 100 + +static std::vector PathComponents(const HECL::SystemString& path) +{ + std::vector ret; + HECL::SystemString sPath = path; + HECL::SanitizePath(sPath); + if (sPath.empty()) + return ret; + auto it = sPath.cbegin(); + if (*it == _S('/')) + { + ret.push_back("/"); + ++it; + } + HECL::SystemString comp; + for (; it != sPath.cend() ; ++it) + { + if (*it == _S('/')) + { + if (comp.empty()) + continue; + ret.push_back(std::move(comp)); + comp.clear(); + continue; + } + comp += *it; + } + if (comp.size()) + ret.push_back(std::move(comp)); + return ret; +} + +FileBrowser::FileBrowser(ViewResources& res, View& parentView, const HECL::SystemString& initialPath) +: ModalWindow(res, parentView), m_comps(PathComponents(initialPath)) +{ + commitResources(res); + setBackground({0,0,0,0.5}); + + m_pathButtons.reserve(m_comps.size()); + size_t idx = 0; + for (const HECL::SystemString& c : m_comps) + m_pathButtons.emplace_back(*this, res, idx++, c); + + updateContentOpacity(0.0); +} + +void FileBrowser::updateContentOpacity(float opacity) +{ + Zeus::CColor color = Zeus::CColor::lerp({1,1,1,0}, {1,1,1,1}, opacity); + for (PathButton& b : m_pathButtons) + b.m_button.m_view->setMultiplyColor(color); +} + +void FileBrowser::pathButtonActivated(size_t idx) +{ +} + +void FileBrowser::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) +{ + if (skipBuildInAnimation()) + return; + for (PathButton& b : m_pathButtons) + b.m_button.mouseDown(coord, button, mod); +} + +void FileBrowser::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) +{ + for (PathButton& b : m_pathButtons) + b.m_button.mouseUp(coord, button, mod); +} + +void FileBrowser::mouseMove(const boo::SWindowCoord& coord) +{ + for (PathButton& b : m_pathButtons) + b.m_button.mouseMove(coord); +} + +void FileBrowser::mouseEnter(const boo::SWindowCoord& coord) +{ + for (PathButton& b : m_pathButtons) + b.m_button.mouseEnter(coord); +} + +void FileBrowser::mouseLeave(const boo::SWindowCoord& coord) +{ + for (PathButton& b : m_pathButtons) + b.m_button.mouseLeave(coord); +} + +void FileBrowser::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) +{ + ModalWindow::resized(root, root); + float pf = rootView().viewRes().pixelFactor(); + + boo::SWindowRect centerRect = sub; + centerRect.size[0] = std::max(root.size[0] - BROWSER_MARGIN * 2 * pf, BROWSER_MIN_WIDTH * pf); + centerRect.size[1] = std::max(root.size[1] - BROWSER_MARGIN * 2 * pf, BROWSER_MIN_HEIGHT * pf); + centerRect.location[0] = root.size[0] / 2 - (centerRect.size[0] / 2.0); + centerRect.location[1] = root.size[1] / 2 - (centerRect.size[1] / 2.0); + + boo::SWindowRect pathRect = centerRect; + pathRect.location[0] += 10 * pf; + pathRect.location[1] += pathRect.size[1] - 20 * pf; + for (PathButton& b : m_pathButtons) + { + pathRect.size[0] = b.m_button.m_view->nominalWidth(); + pathRect.size[1] = b.m_button.m_view->nominalHeight(); + b.m_button.m_view->resized(root, pathRect); + pathRect.location[0] += pathRect.size[0]; + } +} + +void FileBrowser::draw(boo::IGraphicsCommandQueue* gfxQ) +{ + ModalWindow::draw(gfxQ); + for (PathButton& b : m_pathButtons) + b.m_button.m_view->draw(gfxQ); +} + +} diff --git a/specter/lib/ModalWindow.cpp b/specter/lib/ModalWindow.cpp new file mode 100644 index 000000000..32a01e1e5 --- /dev/null +++ b/specter/lib/ModalWindow.cpp @@ -0,0 +1,357 @@ +#include "Specter/ModalWindow.hpp" +#include "Specter/ViewResources.hpp" +#include "Specter/RootView.hpp" + +namespace Specter +{ + +#define WIRE_START 0 +#define WIRE_FRAMES 60 +#define SOLID_START 40 +#define SOLID_FRAMES 40 +#define CONTENT_START 80 +#define CONTENT_FRAMES 40 + +#define LINE_WIDTH 2 +#define CONTENT_MARGIN 10 +#define WINDOW_MIN_DIM 16 + +void ModalWindow::setLineVerts(int width, int height, float pf, float t) +{ + std::pair margin = m_cornersOutline[0]->queryGlyphDimensions(0); + float t1 = Zeus::Math::clamp(0.f, t * 2.f, 1.f); + float t2 = Zeus::Math::clamp(0.f, t * 2.f - 1.f, 1.f); + + float lineLeft = 0; + float lineRight = pf*LINE_WIDTH; + float lineTop = height-margin.second; + float lineBottom = margin.second; + m_verts.lineVerts[0].m_pos.assign(lineLeft, lineTop, 0); + m_verts.lineVerts[1].m_pos = Zeus::CVector3f::lerp({lineLeft, lineTop, 0}, {lineLeft, lineBottom, 0}, t1); + m_verts.lineVerts[2].m_pos.assign(lineRight, lineTop, 0); + m_verts.lineVerts[3].m_pos = Zeus::CVector3f::lerp({lineRight, lineTop, 0}, {lineRight, lineBottom, 0}, t1); + m_verts.lineVerts[4].m_pos = m_verts.lineVerts[3].m_pos; + + lineLeft = margin.first; + lineRight = width-margin.first; + lineTop = height; + lineBottom = height-pf*LINE_WIDTH; + m_verts.lineVerts[5].m_pos.assign(lineLeft, lineTop, 0); + m_verts.lineVerts[6].m_pos = m_verts.lineVerts[5].m_pos; + m_verts.lineVerts[7].m_pos.assign(lineLeft, lineBottom, 0); + m_verts.lineVerts[8].m_pos = Zeus::CVector3f::lerp({lineLeft, lineTop, 0}, {lineRight, lineTop, 0}, t1); + m_verts.lineVerts[9].m_pos = Zeus::CVector3f::lerp({lineLeft, lineBottom, 0}, {lineRight, lineBottom, 0}, t1); + m_verts.lineVerts[10].m_pos = m_verts.lineVerts[9].m_pos; + + lineLeft = width-pf*LINE_WIDTH; + lineRight = width; + lineTop = height-margin.second; + lineBottom = margin.second; + m_verts.lineVerts[11].m_pos.assign(lineLeft, lineTop, 0); + m_verts.lineVerts[12].m_pos = m_verts.lineVerts[11].m_pos; + m_verts.lineVerts[13].m_pos = Zeus::CVector3f::lerp({lineLeft, lineTop, 0}, {lineLeft, lineBottom, 0}, t2); + m_verts.lineVerts[14].m_pos.assign(lineRight, lineTop, 0); + m_verts.lineVerts[15].m_pos = Zeus::CVector3f::lerp({lineRight, lineTop, 0}, {lineRight, lineBottom, 0}, t2); + m_verts.lineVerts[16].m_pos = m_verts.lineVerts[15].m_pos; + + lineLeft = margin.first; + lineRight = width-margin.first; + lineTop = pf*LINE_WIDTH; + lineBottom = 0; + m_verts.lineVerts[17].m_pos.assign(lineLeft, lineTop, 0); + m_verts.lineVerts[18].m_pos = m_verts.lineVerts[17].m_pos; + m_verts.lineVerts[19].m_pos.assign(lineLeft, lineBottom, 0); + m_verts.lineVerts[20].m_pos = Zeus::CVector3f::lerp({lineLeft, lineTop, 0}, {lineRight, lineTop, 0}, t2); + m_verts.lineVerts[21].m_pos = Zeus::CVector3f::lerp({lineLeft, lineBottom, 0}, {lineRight, lineBottom, 0}, t2); +} + +void ModalWindow::setLineColors(float t) +{ + float t1 = Zeus::Math::clamp(0.f, t * 2.f, 1.f); + float t2 = Zeus::Math::clamp(0.f, t * 2.f - 1.f, 1.f); + float t3 = Zeus::Math::clamp(0.f, t * 2.f - 2.f, 1.f); + + Zeus::CColor c1 = Zeus::CColor::lerp(m_line1, m_line2, t1); + Zeus::CColor c2 = Zeus::CColor::lerp(m_line1, m_line2, t2); + Zeus::CColor c3 = Zeus::CColor::lerp(m_line1, m_line2, t3); + + m_cornersOutline[0]->colorGlyphs(c1); + if (t < 0.5) + { + m_cornersOutline[1]->colorGlyphs(Zeus::CColor::skClear); + m_cornersOutline[2]->colorGlyphs(Zeus::CColor::skClear); + m_cornersOutline[3]->colorGlyphs(Zeus::CColor::skClear); + } + else if (t < 1.0) + { + m_cornersOutline[1]->colorGlyphs(c2); + m_cornersOutline[3]->colorGlyphs(c2); + } + else + { + m_cornersOutline[1]->colorGlyphs(c2); + m_cornersOutline[2]->colorGlyphs(c3); + m_cornersOutline[3]->colorGlyphs(c2); + } + + m_verts.lineVerts[0].m_color = c1; + m_verts.lineVerts[1].m_color = c2; + m_verts.lineVerts[2].m_color = m_verts.lineVerts[0].m_color; + m_verts.lineVerts[3].m_color = m_verts.lineVerts[1].m_color; + m_verts.lineVerts[4].m_color = m_verts.lineVerts[3].m_color; + + m_verts.lineVerts[5].m_color = c1; + m_verts.lineVerts[6].m_color = m_verts.lineVerts[5].m_color; + m_verts.lineVerts[7].m_color = m_verts.lineVerts[6].m_color; + m_verts.lineVerts[8].m_color = c2; + m_verts.lineVerts[9].m_color = m_verts.lineVerts[8].m_color; + m_verts.lineVerts[10].m_color = m_verts.lineVerts[9].m_color; + + m_verts.lineVerts[11].m_color = c2; + m_verts.lineVerts[12].m_color = m_verts.lineVerts[11].m_color; + m_verts.lineVerts[13].m_color = c3; + m_verts.lineVerts[14].m_color = m_verts.lineVerts[12].m_color; + m_verts.lineVerts[15].m_color = m_verts.lineVerts[13].m_color; + m_verts.lineVerts[16].m_color = m_verts.lineVerts[15].m_color; + + m_verts.lineVerts[17].m_color = c2; + m_verts.lineVerts[18].m_color = m_verts.lineVerts[17].m_color; + m_verts.lineVerts[19].m_color = m_verts.lineVerts[18].m_color; + m_verts.lineVerts[20].m_color = c3; + m_verts.lineVerts[21].m_color = m_verts.lineVerts[20].m_color; +} + +void ModalWindow::setFillVerts(int width, int height, float pf) +{ + std::pair margin = m_cornersFilled[0]->queryGlyphDimensions(0); + + float fillLeft = pf*LINE_WIDTH; + float fillRight = width-pf*LINE_WIDTH; + float fillTop = height-margin.second; + float fillBottom = margin.second; + m_verts.fillVerts[0].m_pos.assign(fillLeft, fillTop, 0); + m_verts.fillVerts[1].m_pos.assign(fillLeft, fillBottom, 0); + m_verts.fillVerts[2].m_pos.assign(fillRight, fillTop, 0); + m_verts.fillVerts[3].m_pos.assign(fillRight, fillBottom, 0); + m_verts.fillVerts[4].m_pos = m_verts.fillVerts[3].m_pos; + + fillLeft = margin.first; + fillRight = width-margin.first; + fillTop = height-pf*LINE_WIDTH; + fillBottom = height-margin.second; + m_verts.fillVerts[5].m_pos.assign(fillLeft, fillTop, 0); + m_verts.fillVerts[6].m_pos = m_verts.fillVerts[5].m_pos; + m_verts.fillVerts[7].m_pos.assign(fillLeft, fillBottom, 0); + m_verts.fillVerts[8].m_pos.assign(fillRight, fillTop, 0); + m_verts.fillVerts[9].m_pos.assign(fillRight, fillBottom, 0); + m_verts.fillVerts[10].m_pos = m_verts.fillVerts[9].m_pos; + + fillLeft = margin.first; + fillRight = width-margin.first; + fillTop = margin.second; + fillBottom = pf*LINE_WIDTH; + m_verts.fillVerts[11].m_pos.assign(fillLeft, fillTop, 0); + m_verts.fillVerts[12].m_pos = m_verts.fillVerts[11].m_pos; + m_verts.fillVerts[13].m_pos.assign(fillLeft, fillBottom, 0); + m_verts.fillVerts[14].m_pos.assign(fillRight, fillTop, 0); + m_verts.fillVerts[15].m_pos.assign(fillRight, fillBottom, 0); +} + +void ModalWindow::setFillColors(float t) +{ + t = Zeus::Math::clamp(0.f, t, 1.f); + Zeus::CColor color = Zeus::CColor::lerp(m_windowBgClear, m_windowBg, t); + + for (int i=0 ; i<16 ; ++i) + m_verts.fillVerts[i].m_color = color; + for (int i=0 ; i<4 ; ++i) + m_cornersFilled[i]->colorGlyphs(color); +} + +ModalWindow::ModalWindow(ViewResources& res, View& parentView, int widthConstrain, int heightConstrain) +: View(res, parentView), + m_widthConstrain(widthConstrain), + m_heightConstrain(heightConstrain), + m_windowBg(res.themeData().splashBackground()), + m_windowBgClear(m_windowBg), + m_line1(res.themeData().splash1()), + m_line2(res.themeData().splash2()) +{ + m_windowBgClear[3] = 0.0; + m_viewBlockBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Uniform, sizeof(ViewBlock), 1); + m_vertsBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(SolidShaderVert), 38); + + if (!res.m_viewRes.m_solidVtxFmt) + { + boo::VertexElementDescriptor vdescs[] = + { + {m_vertsBuf, nullptr, boo::VertexSemantic::Position4}, + {m_vertsBuf, nullptr, boo::VertexSemantic::Color} + }; + m_vertsVtxFmt = res.m_factory->newVertexFormat(2, vdescs); + boo::IGraphicsBuffer* bufs[] = {m_viewBlockBuf}; + m_vertsShaderBinding = res.m_factory->newShaderDataBinding(res.m_viewRes.m_solidShader, + m_vertsVtxFmt, m_vertsBuf, nullptr, + nullptr, 1, bufs, 0, nullptr); + } + else + { + boo::IGraphicsBuffer* bufs[] = {m_viewBlockBuf}; + m_vertsShaderBinding = res.m_factory->newShaderDataBinding(res.m_viewRes.m_solidShader, + res.m_viewRes.m_solidVtxFmt, + m_vertsBuf, nullptr, + nullptr, 1, bufs, 0, nullptr); + } + m_windowGfxData = res.m_factory->commit(); + + for (int i=0 ; i<4 ; ++i) + { + m_cornersOutline[i].reset(new Specter::TextView(res, *this, res.m_curveFont, Specter::TextView::Alignment::Left, 1)); + m_cornersFilled[i].reset(new Specter::TextView(res, *this, res.m_curveFont, Specter::TextView::Alignment::Left, 1)); + } + m_cornersOutline[0]->typesetGlyphs(L"\xF4F0"); + m_cornersFilled[0]->typesetGlyphs(L"\xF4F1", res.themeData().splashBackground()); + m_cornersOutline[1]->typesetGlyphs(L"\xF4F2"); + m_cornersFilled[1]->typesetGlyphs(L"\xF4F3", res.themeData().splashBackground()); + m_cornersOutline[2]->typesetGlyphs(L"\xF4F4"); + m_cornersFilled[2]->typesetGlyphs(L"\xF4F5", res.themeData().splashBackground()); + m_cornersOutline[3]->typesetGlyphs(L"\xF4F6"); + m_cornersFilled[3]->typesetGlyphs(L"\xF4F7", res.themeData().splashBackground()); + + setLineColors(0.0); + setFillColors(0.0); + + m_vertsBuf->load(&m_verts, sizeof(m_verts)); +} + +static float CubicEase(float t) +{ + t *= 2.f; + if (t < 1) return 1.f/2.f*t*t*t; + t -= 2.f; + return 1.f/2.f*(t*t*t + 2.f); +} + +void ModalWindow::think() +{ + Specter::ViewResources& res = rootView().viewRes(); + float pf = res.pixelFactor(); + + if (m_phase == Phase::BuildIn) + { + bool loadVerts = false; + if (m_frame > WIRE_START) + { + float wt = (m_frame-WIRE_START) / float(WIRE_FRAMES); + wt = Zeus::Math::clamp(0.f, wt, 2.f); + m_lineTime = CubicEase(wt); + setLineVerts(m_width, m_height, pf, m_lineTime); + setLineColors(wt); + loadVerts = true; + } + if (m_frame > SOLID_START) + { + float ft = (m_frame-SOLID_START) / float(SOLID_FRAMES); + ft = Zeus::Math::clamp(0.f, ft, 2.f); + setFillColors(ft); + loadVerts = true; + } + if (res.fontCacheReady() && m_frame > CONTENT_START) + { + if (!m_contentStartFrame) + m_contentStartFrame = m_frame; + float tt = (m_frame-m_contentStartFrame) / float(CONTENT_FRAMES); + tt = Zeus::Math::clamp(0.f, tt, 1.f); + updateContentOpacity(tt); + if (tt == 1.f) + m_phase = Phase::Showing; + } + if (loadVerts) + m_vertsBuf->load(&m_verts, sizeof(m_verts)); + ++m_frame; + } + else if (m_phase == Phase::ResWait) + { + if (res.fontCacheReady()) + { + updateContentOpacity(1.0); + m_phase = Phase::Showing; + } + } +} + +bool ModalWindow::skipBuildInAnimation() +{ + if (m_phase != Phase::BuildIn) + return false; + + Specter::ViewResources& res = rootView().viewRes(); + float pf = res.pixelFactor(); + + m_lineTime = 1.0; + setLineVerts(m_width, m_height, pf, 1.0); + setLineColors(2.0); + setFillColors(2.0); + m_vertsBuf->load(&m_verts, sizeof(m_verts)); + m_phase = Phase::ResWait; + return true; +} + +void ModalWindow::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) +{ + float pf = rootView().viewRes().pixelFactor(); + + boo::SWindowRect centerRect = sub; + m_width = m_widthConstrain < 0 ? root.size[0] - CONTENT_MARGIN * pf * 2 : m_widthConstrain; + m_height = m_heightConstrain < 0 ? root.size[1] - CONTENT_MARGIN * pf * 2 : m_heightConstrain; + m_width = std::max(m_width, int(WINDOW_MIN_DIM * pf)); + m_height = std::max(m_height, int(WINDOW_MIN_DIM * pf)); + centerRect.size[0] = m_width; + centerRect.size[1] = m_height; + centerRect.location[0] = root.size[0] / 2 - m_width / 2.0; + centerRect.location[1] = root.size[1] / 2 - m_height / 2.0; + View::resized(root, centerRect); + m_viewBlock.setViewRect(root, centerRect); + m_viewBlockBuf->load(&m_viewBlock, sizeof(m_viewBlock)); + + setLineVerts(m_width, m_height, pf, m_lineTime); + setFillVerts(m_width, m_height, pf); + m_vertsBuf->load(&m_verts, sizeof(m_verts)); + + boo::SWindowRect cornerRect = centerRect; + cornerRect.size[0] = cornerRect.size[1] = 8 * pf; + cornerRect.location[1] = centerRect.location[1] + m_height - 8 * pf; + m_cornersOutline[0]->resized(root, cornerRect); + m_cornersFilled[0]->resized(root, cornerRect); + cornerRect.location[0] = centerRect.location[0] + m_width - 8 * pf; + m_cornersOutline[1]->resized(root, cornerRect); + m_cornersFilled[1]->resized(root, cornerRect); + cornerRect.location[1] = centerRect.location[1]; + m_cornersOutline[2]->resized(root, cornerRect); + m_cornersFilled[2]->resized(root, cornerRect); + cornerRect.location[0] = centerRect.location[0]; + m_cornersOutline[3]->resized(root, cornerRect); + m_cornersFilled[3]->resized(root, cornerRect); +} + +void ModalWindow::draw(boo::IGraphicsCommandQueue* gfxQ) +{ + gfxQ->setShaderDataBinding(m_vertsShaderBinding); + gfxQ->setDrawPrimitive(boo::Primitive::TriStrips); + if (m_frame > WIRE_START) + gfxQ->draw(0, 22); + if (m_frame > SOLID_START) + gfxQ->draw(22, 16); + + m_cornersFilled[0]->draw(gfxQ); + m_cornersFilled[1]->draw(gfxQ); + m_cornersFilled[2]->draw(gfxQ); + m_cornersFilled[3]->draw(gfxQ); + + m_cornersOutline[0]->draw(gfxQ); + m_cornersOutline[1]->draw(gfxQ); + m_cornersOutline[2]->draw(gfxQ); + m_cornersOutline[3]->draw(gfxQ); +} + +} diff --git a/specter/lib/ScrollView.cpp b/specter/lib/ScrollView.cpp index 9e1475739..f1e5acaf7 100644 --- a/specter/lib/ScrollView.cpp +++ b/specter/lib/ScrollView.cpp @@ -3,8 +3,8 @@ namespace Specter { -ScrollView::ScrollView(ViewResources& system, View& parentView, View& contentView) -: View(system, parentView), m_contentView(contentView) +ScrollView::ScrollView(ViewResources& system, View& parentView) +: View(system, parentView) { } diff --git a/specter/lib/Table.cpp b/specter/lib/Table.cpp index e69de29bb..f989daf6f 100644 --- a/specter/lib/Table.cpp +++ b/specter/lib/Table.cpp @@ -0,0 +1,11 @@ +#include "Specter/Table.hpp" + +namespace Specter +{ + +Table::Table(ViewResources& res, View& parentView) +: View(res, parentView) +{ +} + +} diff --git a/specter/lib/TextField.cpp b/specter/lib/TextField.cpp index e69de29bb..5ecd0c003 100644 --- a/specter/lib/TextField.cpp +++ b/specter/lib/TextField.cpp @@ -0,0 +1,11 @@ +#include "Specter/TextField.hpp" + +namespace Specter +{ + +TextField::TextField(ViewResources& res, View& parentView) +: View(res, parentView) +{ +} + +} diff --git a/specter/lib/TextView.cpp b/specter/lib/TextView.cpp index 54d74e908..a655b319b 100644 --- a/specter/lib/TextView.cpp +++ b/specter/lib/TextView.cpp @@ -29,7 +29,7 @@ void TextView::Resources::init(boo::GLDataFactory* factory, FontCache* fcache) "void main()\n" "{\n" " vtf.uv = uvIn[gl_VertexID];\n" - " vtf.color = colorIn;\n" + " vtf.color = colorIn * mulColor;\n" " gl_Position = mv * mvMtx * vec4(posIn[gl_VertexID], 1.0);\n" "}\n"; @@ -104,7 +104,7 @@ void TextView::Resources::init(boo::ID3DDataFactory* factory, FontCache* fcache) "{\n" " VertToFrag vtf;\n" " vtf.uv = v.uvIn[vertId];\n" - " vtf.color = v.colorIn;\n" + " vtf.color = v.colorIn * mulColor;\n" " vtf.position = mul(mv, mul(v.mvMtx, float4(v.posIn[vertId], 1.0)));\n" " return vtf;\n" "}\n"; @@ -211,7 +211,7 @@ void TextView::Resources::init(boo::MetalDataFactory* factory, FontCache* fcache " VertToFrag vtf;\n" " constant VertData& v = va[instId];\n" " vtf.uv = v.uvIn[vertId];\n" - " vtf.color = v.colorIn;\n" + " vtf.color = v.colorIn * view.mulColor;\n" " vtf.position = view.mv * v.mvMtx * float4(v.posIn[vertId], 1.0);\n" " return vtf;\n" "}\n"; diff --git a/specter/lib/View.cpp b/specter/lib/View.cpp index 2e8023c97..6750ff2f4 100644 --- a/specter/lib/View.cpp +++ b/specter/lib/View.cpp @@ -19,7 +19,7 @@ void View::Resources::init(boo::GLDataFactory* factory, const ThemeData& theme) "out VertToFrag vtf;\n" "void main()\n" "{\n" - " vtf.color = colorIn;\n" + " vtf.color = colorIn * mulColor;\n" " gl_Position = mv * vec4(posIn, 1.0);\n" "}\n"; @@ -43,12 +43,14 @@ void View::Resources::init(boo::GLDataFactory* factory, const ThemeData& theme) SPECTER_VIEW_VERT_BLOCK_GLSL "struct VertToFrag\n" "{\n" + " vec4 color;\n" " vec2 uv;\n" "};\n" "out VertToFrag vtf;\n" "void main()\n" "{\n" " vtf.uv = uvIn;\n" + " vtf.color = mulColor;\n" " gl_Position = mv * vec4(posIn, 1.0);\n" "}\n"; @@ -56,6 +58,7 @@ void View::Resources::init(boo::GLDataFactory* factory, const ThemeData& theme) "#version 330\n" "struct VertToFrag\n" "{\n" + " vec4 color;\n" " vec2 uv;\n" "};\n" "in VertToFrag vtf;\n" @@ -63,7 +66,7 @@ void View::Resources::init(boo::GLDataFactory* factory, const ThemeData& theme) "layout(location=0) out vec4 colorOut;\n" "void main()\n" "{\n" - " colorOut = texture(tex, vtf.uv);\n" + " colorOut = texture(tex, vtf.uv) * vtf.color;\n" "}\n"; static const char* BlockNames[] = {"SpecterViewBlock"}; @@ -96,7 +99,7 @@ void View::Resources::init(boo::ID3DDataFactory* factory, const ThemeData& theme "VertToFrag main(in VertData v)\n" "{\n" " VertToFrag vtf;\n" - " vtf.color = v.colorIn;\n" + " vtf.color = v.colorIn * mulColor;\n" " vtf.position = mul(mv, float4(v.posIn, 1.0));\n" " return vtf;\n" "}\n"; @@ -122,12 +125,14 @@ void View::Resources::init(boo::ID3DDataFactory* factory, const ThemeData& theme "struct VertToFrag\n" "{\n" " float4 position : SV_Position;\n" + " float4 color : COLOR;\n" " float2 uv : UV;\n" "};\n" "VertToFrag main(in VertData v)\n" "{\n" " VertToFrag vtf;\n" " vtf.uv = v.uvIn;\n" + " vtf.color = mulColor;\n" " vtf.position = mul(mv, float4(v.posIn, 1.0));\n" " return vtf;\n" "}\n"; @@ -136,13 +141,14 @@ void View::Resources::init(boo::ID3DDataFactory* factory, const ThemeData& theme "struct VertToFrag\n" "{\n" " float4 position : SV_Position;\n" + " float4 color : COLOR;\n" " float2 uv : UV;\n" "};\n" "Texture2D tex : register(t0);\n" "SamplerState samp : register(s0);\n" "float4 main(in VertToFrag vtf) : SV_Target0\n" "{\n" - " return tex.Sample(samp, vtf.uv);\n" + " return tex.Sample(samp, vtf.uv) * vtf.color;\n" "}\n"; boo::VertexElementDescriptor solidvdescs[] = @@ -195,7 +201,7 @@ void View::Resources::init(boo::MetalDataFactory* factory, const ThemeData& them "vertex VertToFrag vmain(VertData v [[ stage_in ]], constant SpecterViewBlock& view [[ buffer(2) ]])\n" "{\n" " VertToFrag vtf;\n" - " vtf.color = v.colorIn;\n" + " vtf.color = v.colorIn * view.mulColor;\n" " vtf.position = view.mv * float4(v.posIn, 1.0);\n" " return vtf;\n" "}\n"; @@ -225,12 +231,14 @@ void View::Resources::init(boo::MetalDataFactory* factory, const ThemeData& them "struct VertToFrag\n" "{\n" " float4 position [[ position ]];\n" + " float4 color;\n" " float2 uv;\n" "};\n" "vertex VertToFrag vmain(VertData v [[ stage_in ]], constant SpecterViewBlock& view [[ buffer(2) ]])\n" "{\n" " VertToFrag vtf;\n" " vtf.uv = v.uvIn;\n" + " vtf.color = view.mulColor;\n" " vtf.position = view.mv * float4(v.posIn, 1.0);\n" " return vtf;\n" "}\n"; @@ -242,11 +250,12 @@ void View::Resources::init(boo::MetalDataFactory* factory, const ThemeData& them "struct VertToFrag\n" "{\n" " float4 position [[ position ]];\n" + " float4 color;\n" " float2 uv;\n" "};\n" "fragment float4 fmain(VertToFrag vtf [[ stage_in ]], texture2d tex [[ texture(0) ]])\n" "{\n" - " return tex.sample(samp, vtf.uv);\n" + " return tex.sample(samp, vtf.uv) * vtf.color;\n" "}\n"; boo::VertexElementDescriptor solidvdescs[] =