diff --git a/specter/include/Specter/FileBrowser.hpp b/specter/include/Specter/FileBrowser.hpp index c565c1210..e91c83377 100644 --- a/specter/include/Specter/FileBrowser.hpp +++ b/specter/include/Specter/FileBrowser.hpp @@ -97,7 +97,50 @@ class FileBrowser : public ModalWindow } } m_fileFieldBind; - ViewChild> m_fileScroll; + struct TableDataBind : ITableDataBinding + { + std::string m_nameCol = "Name"; + std::vector m_names = {"One", "Two", "Three"}; + + std::string m_typeCol = "Type"; + std::vector m_types = {"t1", "t2", "t3"}; + + std::string m_sizeCol = "Size"; + std::vector m_sizes = {"s1", "s2", "s3"}; + + size_t columnCount() const {return 3;} + size_t rowCount() const {return 3;} + + const std::string* header(size_t cIdx) const + { + switch (cIdx) + { + case 0: + return &m_nameCol; + case 1: + return &m_typeCol; + case 2: + return &m_sizeCol; + default: break; + } + return nullptr; + } + + const std::string* cell(size_t cIdx, size_t rIdx) const + { + switch (cIdx) + { + case 0: + return &m_names.at(rIdx); + case 1: + return &m_types.at(rIdx); + case 2: + return &m_sizes.at(rIdx); + default: break; + } + return nullptr; + } + } m_fileListingBind; ViewChild> m_fileListing; public: diff --git a/specter/include/Specter/ModalWindow.hpp b/specter/include/Specter/ModalWindow.hpp index cddb582f0..8bb6f7dbc 100644 --- a/specter/include/Specter/ModalWindow.hpp +++ b/specter/include/Specter/ModalWindow.hpp @@ -8,8 +8,8 @@ namespace Specter { class ModalWindow : public View { - unsigned m_frame = 0; - unsigned m_contentStartFrame = 0; + int m_frame = 0; + int m_contentStartFrame = 0; float m_lineTime = 0.0; enum class Phase @@ -29,6 +29,7 @@ class ModalWindow : public View Zeus::CColor m_windowBgClear; Zeus::CColor m_line1; Zeus::CColor m_line2; + Zeus::CColor m_line2Clear; ViewBlock m_viewBlock; boo::IGraphicsBufferD* m_viewBlockBuf; @@ -39,7 +40,9 @@ class ModalWindow : public View } m_verts; void setLineVerts(int width, int height, float pf, float t); + void setLineVertsOut(int width, int height, float pf, float t); void setLineColors(float t); + void setLineColorsOut(float t); void setFillVerts(int width, int height, float pf); void setFillColors(float t); @@ -59,6 +62,8 @@ public: ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint); void think(); bool skipBuildInAnimation(); + void close(); + bool closed() const {return m_phase >= Phase::BuildOut;} void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); void draw(boo::IGraphicsCommandQueue* gfxQ); diff --git a/specter/include/Specter/ScrollView.hpp b/specter/include/Specter/ScrollView.hpp index 79c317ed5..6cbf7a897 100644 --- a/specter/include/Specter/ScrollView.hpp +++ b/specter/include/Specter/ScrollView.hpp @@ -20,6 +20,11 @@ private: public: ScrollView(ViewResources& res, View& parentView); + void setContentView(View* v) + { + m_contentView = v; + updateSize(); + } }; } diff --git a/specter/include/Specter/Table.hpp b/specter/include/Specter/Table.hpp index b82232108..0e4deb4f9 100644 --- a/specter/include/Specter/Table.hpp +++ b/specter/include/Specter/Table.hpp @@ -2,14 +2,66 @@ #define SPECTER_TABLE_HPP #include "View.hpp" +#include "ScrollView.hpp" namespace Specter { +#define SPECTER_TABLE_MAX_ROWS 128 + +enum class SortDirection +{ + None, + Ascending, + Descending +}; + +struct ITableDataBinding +{ + virtual size_t columnCount() const=0; + virtual size_t rowCount() const=0; + virtual const std::string* header(size_t cIdx) const {return nullptr;} + virtual const std::string* cell(size_t cIdx, size_t rIdx) const {return nullptr;} +}; + +struct ITableStateBinding +{ + virtual float columnSplit(size_t cIdx) {return -1.0;} + virtual void setColumnSplit(size_t cIdx, float split) {} + virtual SortDirection sort(size_t cIdx) {return SortDirection::None;} + virtual void setSort(size_t cIdx, SortDirection dir) {} +}; class Table : public View { + ITableDataBinding* m_data; + ITableStateBinding* m_state; + + SolidShaderVert m_verts[SPECTER_TABLE_MAX_ROWS * 6]; + boo::IGraphicsBufferD* m_vertsBuf = nullptr; + boo::IVertexFormat* m_vtxFmt = nullptr; /* OpenGL only */ + boo::IShaderDataBinding* m_shaderBinding = nullptr; + + ViewChild> m_scroll; + + struct RowsView : public View + { + Table& m_t; + RowsView(Table& t, ViewResources& res) : View(res, t), m_t(t) {} + void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); + void draw(boo::IGraphicsCommandQueue* gfxQ); + } m_rowsView; + public: - Table(ViewResources& res, View& parentView); + Table(ViewResources& res, View& parentView, ITableDataBinding* data, ITableStateBinding* state=nullptr); + + void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey); + void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey); + void mouseEnter(const boo::SWindowCoord&); + void mouseLeave(const boo::SWindowCoord&); + void scroll(const boo::SWindowCoord&, const boo::SScrollDelta&); + + void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); + void draw(boo::IGraphicsCommandQueue* gfxQ); }; } diff --git a/specter/include/Specter/View.hpp b/specter/include/Specter/View.hpp index 5a1c202cd..9f0e33e2a 100644 --- a/specter/include/Specter/View.hpp +++ b/specter/include/Specter/View.hpp @@ -212,7 +212,7 @@ public: template struct ViewChild { - ViewPtrType m_view; + ViewPtrType m_view = ViewPtrType(); bool m_mouseIn = false; int m_mouseDown = 0; @@ -280,6 +280,14 @@ struct ViewChild m_mouseIn = false; } } + + void scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll) + { + if (!m_view) + return; + if (m_mouseIn) + m_view->scroll(coord, scroll); + } }; } diff --git a/specter/lib/FileBrowser.cpp b/specter/lib/FileBrowser.cpp index d762ea512..82fa0ce4a 100644 --- a/specter/lib/FileBrowser.cpp +++ b/specter/lib/FileBrowser.cpp @@ -61,7 +61,7 @@ FileBrowser::FileBrowser(ViewResources& res, View& parentView, const std::string m_pathButtons.emplace_back(*this, res, idx++, c); m_fileField.m_view.reset(new TextField(res, *this, &m_fileFieldBind)); - m_fileListing.m_view.reset(new Table(res, *this)); + m_fileListing.m_view.reset(new Table(res, *this, &m_fileListingBind)); m_fileListing.m_view->setBackground(Zeus::CColor::skBlue); m_split.m_view.reset(new SplitView(res, *this, SplitView::Axis::Vertical, @@ -91,6 +91,7 @@ void FileBrowser::okActivated() void FileBrowser::cancelActivated() { + close(); } void FileBrowser::pathButtonActivated(size_t idx) @@ -99,7 +100,7 @@ void FileBrowser::pathButtonActivated(size_t idx) void FileBrowser::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) { - if (skipBuildInAnimation()) + if (skipBuildInAnimation() || closed()) return; m_split.mouseDown(coord, button, mod); for (PathButton& b : m_pathButtons) @@ -112,6 +113,8 @@ void FileBrowser::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton bu void FileBrowser::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) { + if (closed()) + return; m_split.mouseUp(coord, button, mod); for (PathButton& b : m_pathButtons) b.m_button.mouseUp(coord, button, mod); @@ -123,6 +126,8 @@ void FileBrowser::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton butt void FileBrowser::mouseMove(const boo::SWindowCoord& coord) { + if (closed()) + return; m_split.mouseMove(coord); for (PathButton& b : m_pathButtons) b.m_button.mouseMove(coord); @@ -138,6 +143,8 @@ void FileBrowser::mouseEnter(const boo::SWindowCoord& coord) void FileBrowser::mouseLeave(const boo::SWindowCoord& coord) { + if (closed()) + return; m_split.mouseLeave(coord); for (PathButton& b : m_pathButtons) b.m_button.mouseLeave(coord); diff --git a/specter/lib/ModalWindow.cpp b/specter/lib/ModalWindow.cpp index f516d6cec..f2f58fe74 100644 --- a/specter/lib/ModalWindow.cpp +++ b/specter/lib/ModalWindow.cpp @@ -6,11 +6,11 @@ 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 WIRE_FRAMES 40 +#define SOLID_START 30 +#define SOLID_FRAMES 20 +#define CONTENT_START 40 +#define CONTENT_FRAMES 10 #define LINE_WIDTH 2 #define CONTENT_MARGIN 10 @@ -65,6 +65,55 @@ void ModalWindow::setLineVerts(int width, int height, float pf, float t) m_verts.lineVerts[21].m_pos = Zeus::CVector3f::lerp({lineLeft, lineBottom, 0}, {lineRight, lineBottom, 0}, t2); } +void ModalWindow::setLineVertsOut(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, 1.f); + float t2 = Zeus::Math::clamp(0.f, t * 2.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 = Zeus::CVector3f::lerp({lineLeft, lineBottom, 0}, {lineLeft, lineTop, 0}, t1); + m_verts.lineVerts[1].m_pos.assign(lineLeft, lineBottom, 0); + m_verts.lineVerts[2].m_pos = Zeus::CVector3f::lerp({lineRight, lineBottom, 0}, {lineRight, lineTop, 0}, t1); + m_verts.lineVerts[3].m_pos.assign(lineRight, lineBottom, 0); + 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 = Zeus::CVector3f::lerp({lineRight, lineTop, 0}, {lineLeft, lineTop, 0}, t1); + m_verts.lineVerts[6].m_pos = m_verts.lineVerts[5].m_pos; + m_verts.lineVerts[7].m_pos = Zeus::CVector3f::lerp({lineRight, lineBottom, 0}, {lineLeft, lineBottom, 0}, t1); + m_verts.lineVerts[8].m_pos.assign(lineRight, lineTop, 0); + m_verts.lineVerts[9].m_pos.assign(lineRight, lineBottom, 0); + 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 = Zeus::CVector3f::lerp({lineLeft, lineBottom, 0}, {lineLeft, lineTop, 0}, t2); + m_verts.lineVerts[12].m_pos = m_verts.lineVerts[11].m_pos; + m_verts.lineVerts[13].m_pos.assign(lineLeft, lineBottom, 0); + m_verts.lineVerts[14].m_pos = Zeus::CVector3f::lerp({lineRight, lineBottom, 0}, {lineRight, lineTop, 0}, t2); + m_verts.lineVerts[15].m_pos.assign(lineRight, lineBottom, 0); + 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 = Zeus::CVector3f::lerp({lineRight, lineTop, 0}, {lineLeft, lineTop, 0}, t2); + m_verts.lineVerts[18].m_pos = m_verts.lineVerts[17].m_pos; + m_verts.lineVerts[19].m_pos = Zeus::CVector3f::lerp({lineRight, lineBottom, 0}, {lineLeft, lineBottom, 0}, t2); + m_verts.lineVerts[20].m_pos.assign(lineRight, lineTop, 0); + m_verts.lineVerts[21].m_pos.assign(lineRight, lineBottom, 0); +} + void ModalWindow::setLineColors(float t) { float t1 = Zeus::Math::clamp(0.f, t * 2.f, 1.f); @@ -85,6 +134,7 @@ void ModalWindow::setLineColors(float t) else if (t < 1.0) { m_cornersOutline[1]->colorGlyphs(c2); + m_cornersOutline[2]->colorGlyphs(Zeus::CColor::skClear); m_cornersOutline[3]->colorGlyphs(c2); } else @@ -121,6 +171,63 @@ void ModalWindow::setLineColors(float t) m_verts.lineVerts[21].m_color = m_verts.lineVerts[20].m_color; } +void ModalWindow::setLineColorsOut(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_line2Clear, m_line2, t1); + Zeus::CColor c2 = Zeus::CColor::lerp(m_line2Clear, m_line2, t2); + Zeus::CColor c3 = Zeus::CColor::lerp(m_line2Clear, m_line2, t3); + + m_cornersOutline[2]->colorGlyphs(c1); + if (t < 0.5) + { + m_cornersOutline[1]->colorGlyphs(Zeus::CColor::skClear); + m_cornersOutline[0]->colorGlyphs(Zeus::CColor::skClear); + m_cornersOutline[3]->colorGlyphs(Zeus::CColor::skClear); + } + else if (t < 1.0) + { + m_cornersOutline[1]->colorGlyphs(c2); + m_cornersOutline[0]->colorGlyphs(Zeus::CColor::skClear); + m_cornersOutline[3]->colorGlyphs(c2); + } + else + { + m_cornersOutline[1]->colorGlyphs(c2); + m_cornersOutline[0]->colorGlyphs(c3); + m_cornersOutline[3]->colorGlyphs(c2); + } + + m_verts.lineVerts[0].m_color = c3; + 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 = c3; + 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 = c1; + 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 = c1; + 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); @@ -174,9 +281,11 @@ ModalWindow::ModalWindow(ViewResources& res, View& parentView, const RectangleCo m_windowBg(res.themeData().splashBackground()), m_windowBgClear(m_windowBg), m_line1(res.themeData().splash1()), - m_line2(res.themeData().splash2()) + m_line2(res.themeData().splash2()), + m_line2Clear(m_line2) { m_windowBgClear[3] = 0.0; + m_line2Clear[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); @@ -236,7 +345,9 @@ void ModalWindow::think() Specter::ViewResources& res = rootView().viewRes(); float pf = res.pixelFactor(); - if (m_phase == Phase::BuildIn) + switch (m_phase) + { + case Phase::BuildIn: { bool loadVerts = false; if (m_frame > WIRE_START) @@ -268,14 +379,44 @@ void ModalWindow::think() if (loadVerts) m_vertsBuf->load(&m_verts, sizeof(m_verts)); ++m_frame; + break; } - else if (m_phase == Phase::ResWait) + case Phase::ResWait: { if (res.fontCacheReady()) { updateContentOpacity(1.0); m_phase = Phase::Showing; } + break; + } + case Phase::BuildOut: + { + { + float wt = (WIRE_FRAMES - m_frame) / float(WIRE_FRAMES); + wt = Zeus::Math::clamp(0.f, wt, 1.f); + m_lineTime = CubicEase(wt); + setLineVertsOut(m_width, m_height, pf, m_lineTime); + setLineColorsOut(wt); + if (wt == 0.f) + m_phase = Phase::Done; + } + { + float ft = (SOLID_FRAMES - m_frame) / float(SOLID_FRAMES); + ft = Zeus::Math::clamp(0.f, ft, 1.f); + setFillColors(ft); + } + if (res.fontCacheReady()) + { + float tt = (CONTENT_FRAMES - m_frame) / float(CONTENT_FRAMES); + tt = Zeus::Math::clamp(0.f, tt, 1.f); + updateContentOpacity(tt); + } + m_vertsBuf->load(&m_verts, sizeof(m_verts)); + ++m_frame; + break; + } + default: break; } } @@ -296,6 +437,12 @@ bool ModalWindow::skipBuildInAnimation() return true; } +void ModalWindow::close() +{ + m_phase = Phase::BuildOut; + m_frame = 0; +} + void ModalWindow::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) { float pf = rootView().viewRes().pixelFactor(); @@ -335,6 +482,9 @@ void ModalWindow::resized(const boo::SWindowRect& root, const boo::SWindowRect& void ModalWindow::draw(boo::IGraphicsCommandQueue* gfxQ) { + if (m_phase == Phase::Done) + return; + gfxQ->setShaderDataBinding(m_vertsShaderBinding); gfxQ->setDrawPrimitive(boo::Primitive::TriStrips); gfxQ->draw(0, 22); diff --git a/specter/lib/Table.cpp b/specter/lib/Table.cpp index a98e8fad3..d72fe9e37 100644 --- a/specter/lib/Table.cpp +++ b/specter/lib/Table.cpp @@ -1,12 +1,84 @@ #include "Specter/Table.hpp" +#include "Specter/ViewResources.hpp" namespace Specter { -Table::Table(ViewResources& res, View& parentView) -: View(res, parentView) +Table::Table(ViewResources& res, View& parentView, ITableDataBinding* data, ITableStateBinding* state) +: View(res, parentView), m_data(data), m_state(state), m_rowsView(*this, res) { + m_vertsBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(SolidShaderVert), + SPECTER_TABLE_MAX_ROWS * 6); + + if (!res.m_viewRes.m_texVtxFmt) + { + boo::VertexElementDescriptor vdescs[] = + { + {m_vertsBuf, nullptr, boo::VertexSemantic::Position4}, + {m_vertsBuf, nullptr, boo::VertexSemantic::Color} + }; + m_vtxFmt = res.m_factory->newVertexFormat(2, vdescs); + boo::IGraphicsBuffer* bufs[] = {m_viewVertBlockBuf}; + m_shaderBinding = res.m_factory->newShaderDataBinding(res.m_viewRes.m_solidShader, + m_vtxFmt, m_vertsBuf, nullptr, + nullptr, 1, bufs, 0, nullptr); + } + else + { + boo::IGraphicsBuffer* bufs[] = {m_viewVertBlockBuf}; + m_shaderBinding = res.m_factory->newShaderDataBinding(res.m_viewRes.m_solidShader, + res.m_viewRes.m_texVtxFmt, + m_vertsBuf, nullptr, + nullptr, 1, bufs, 0, nullptr); + } commitResources(res); + + m_scroll.m_view.reset(new ScrollView(res, *this)); + m_scroll.m_view->setContentView(&m_rowsView); +} + +void Table::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) +{ + m_scroll.mouseDown(coord, button, mod); +} + +void Table::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) +{ + m_scroll.mouseUp(coord, button, mod); +} + +void Table::mouseEnter(const boo::SWindowCoord& coord) +{ + m_scroll.mouseEnter(coord); +} + +void Table::mouseLeave(const boo::SWindowCoord& coord) +{ + m_scroll.mouseLeave(coord); +} + +void Table::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll) +{ + m_scroll.scroll(coord, scroll); +} + +void Table::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) +{ + boo::SWindowRect rowsRect = sub; + m_scroll.m_view->resized(root, rowsRect); +} + +void Table::RowsView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) +{ +} + +void Table::draw(boo::IGraphicsCommandQueue* gfxQ) +{ + m_scroll.m_view->draw(gfxQ); +} + +void Table::RowsView::draw(boo::IGraphicsCommandQueue* gfxQ) +{ } } diff --git a/specter/resources/fonts/SpecterCurveGlyphs.ttf.gz b/specter/resources/fonts/SpecterCurveGlyphs.ttf.gz index e9d3a7c91..147031a2a 100644 Binary files a/specter/resources/fonts/SpecterCurveGlyphs.ttf.gz and b/specter/resources/fonts/SpecterCurveGlyphs.ttf.gz differ