diff --git a/specter/include/Specter/ScrollView.hpp b/specter/include/Specter/ScrollView.hpp index 6cbf7a897..80029039a 100644 --- a/specter/include/Specter/ScrollView.hpp +++ b/specter/include/Specter/ScrollView.hpp @@ -17,6 +17,7 @@ public: private: View* m_contentView = nullptr; + int m_scroll[2] = {}; public: ScrollView(ViewResources& res, View& parentView); @@ -25,6 +26,11 @@ public: m_contentView = v; updateSize(); } + + void scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll); + + void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); + void draw(boo::IGraphicsCommandQueue* gfxQ); }; } diff --git a/specter/include/Specter/Table.hpp b/specter/include/Specter/Table.hpp index 0e4deb4f9..703ce2ea2 100644 --- a/specter/include/Specter/Table.hpp +++ b/specter/include/Specter/Table.hpp @@ -3,6 +3,7 @@ #include "View.hpp" #include "ScrollView.hpp" +#include "TextView.hpp" namespace Specter { @@ -36,10 +37,26 @@ class Table : public View ITableDataBinding* m_data; ITableStateBinding* m_state; + size_t m_rows = 0; + size_t m_columns = 0; + struct CellView : public View + { + Table& m_t; + std::unique_ptr m_text; + CellView(Table& t, ViewResources& res); + void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); + void draw(boo::IGraphicsCommandQueue* gfxQ); + }; + std::vector> m_headerViews; + std::vector>> m_cellViews; + bool m_header = false; + 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; + size_t m_visibleRows = 0; + void _setRowVerts(const boo::SWindowRect& rowsRect); ViewChild> m_scroll; @@ -47,19 +64,25 @@ class Table : 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); + int nominalHeight() const; + void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub, + const boo::SWindowRect& scissor); void draw(boo::IGraphicsCommandQueue* gfxQ); } m_rowsView; public: Table(ViewResources& res, View& parentView, ITableDataBinding* data, ITableStateBinding* state=nullptr); + void setMultiplyColor(const Zeus::CColor& color); + 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 scroll(const boo::SWindowCoord&, const boo::SScrollDelta&); + void updateData(); 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 9f0e33e2a..628a468b0 100644 --- a/specter/include/Specter/View.hpp +++ b/specter/include/Specter/View.hpp @@ -166,6 +166,7 @@ public: View& parentView() {return m_parentView;} RootView& rootView() {return m_rootView;} + const RootView& rootView() const {return m_rootView;} const boo::SWindowRect& subRect() const {return m_subRect;} int width() const {return m_subRect.size[0];} int height() const {return m_subRect.size[1];} @@ -205,6 +206,8 @@ public: virtual void modKeyUp(boo::EModifierKey) {} virtual void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub); + virtual void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub, + const boo::SWindowRect& scissor) {resized(root, sub);} virtual void think() {} virtual void draw(boo::IGraphicsCommandQueue* gfxQ); }; diff --git a/specter/include/Specter/ViewResources.hpp b/specter/include/Specter/ViewResources.hpp index 5d52c0851..66909b795 100644 --- a/specter/include/Specter/ViewResources.hpp +++ b/specter/include/Specter/ViewResources.hpp @@ -43,6 +43,9 @@ class ThemeData Zeus::CColor m_textfieldSelection = {0.2725, 0.2725, 0.2725, 1.0}; Zeus::CColor m_textfieldMarkSelection = {1.0, 1.0, 0.2725, 1.0}; + Zeus::CColor m_tableCellBg1 = {0.1725, 0.1725, 0.1725, 0.75}; + Zeus::CColor m_tableCellBg2 = {0.2425, 0.2425, 0.2425, 0.75}; + public: virtual const Zeus::CColor& uiText() const {return m_uiText;} virtual const Zeus::CColor& fieldText() const {return m_fieldText;} @@ -74,6 +77,9 @@ public: virtual const Zeus::CColor& textfield2Disabled() const {return m_textfield2Disabled;} virtual const Zeus::CColor& textfieldSelection() const {return m_textfieldSelection;} virtual const Zeus::CColor& textfieldMarkSelection() const {return m_textfieldMarkSelection;} + + virtual const Zeus::CColor& tableCellBg1() const {return m_tableCellBg1;} + virtual const Zeus::CColor& tableCellBg2() const {return m_tableCellBg2;} }; class ViewResources diff --git a/specter/lib/FileBrowser.cpp b/specter/lib/FileBrowser.cpp index 82fa0ce4a..d92e9eca5 100644 --- a/specter/lib/FileBrowser.cpp +++ b/specter/lib/FileBrowser.cpp @@ -156,6 +156,7 @@ void FileBrowser::mouseLeave(const boo::SWindowCoord& coord) void FileBrowser::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll) { + m_fileListing.scroll(coord, scroll); } void FileBrowser::touchDown(const boo::STouchCoord& coord, uintptr_t tid) diff --git a/specter/lib/ScrollView.cpp b/specter/lib/ScrollView.cpp index f1e5acaf7..5cdcb44da 100644 --- a/specter/lib/ScrollView.cpp +++ b/specter/lib/ScrollView.cpp @@ -3,9 +3,35 @@ namespace Specter { -ScrollView::ScrollView(ViewResources& system, View& parentView) -: View(system, parentView) +ScrollView::ScrollView(ViewResources& res, View& parentView) +: View(res, parentView) { + commitResources(res); +} + +void ScrollView::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll) +{ + m_scroll[0] += scroll.delta[0]; + m_scroll[1] += scroll.delta[1]; + updateSize(); +} + +void ScrollView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) +{ + View::resized(root, sub); + if (m_contentView) + { + boo::SWindowRect cRect = sub; + cRect.location[0] += m_scroll[0]; + cRect.location[1] += sub.size[1] - m_contentView->nominalHeight() + m_scroll[1]; + m_contentView->resized(root, cRect, sub); + } +} + +void ScrollView::draw(boo::IGraphicsCommandQueue* gfxQ) +{ + if (m_contentView) + m_contentView->draw(gfxQ); } } diff --git a/specter/lib/SplitView.cpp b/specter/lib/SplitView.cpp index ce2541309..c5782821d 100644 --- a/specter/lib/SplitView.cpp +++ b/specter/lib/SplitView.cpp @@ -18,37 +18,37 @@ void SplitView::Resources::init(boo::IGraphicsDataFactory* factory, const ThemeD m_shadingTex = factory->newStaticTexture(3, 1, 1, boo::TextureFormat::RGBA8, tex, 12); } -SplitView::SplitView(ViewResources& system, View& parentView, Axis axis, int clearanceA, int clearanceB) -: View(system, parentView), m_axis(axis), m_clearanceA(clearanceA), m_clearanceB(clearanceB) +SplitView::SplitView(ViewResources& res, View& parentView, Axis axis, int clearanceA, int clearanceB) +: View(res, parentView), m_axis(axis), m_clearanceA(clearanceA), m_clearanceB(clearanceB) { - m_splitBlockBuf = system.m_factory->newDynamicBuffer(boo::BufferUse::Uniform, sizeof(ViewBlock), 1); - m_splitVertsBuf = system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(TexShaderVert), 4); + m_splitBlockBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Uniform, sizeof(ViewBlock), 1); + m_splitVertsBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(TexShaderVert), 4); - if (!system.m_viewRes.m_texVtxFmt) + if (!res.m_viewRes.m_texVtxFmt) { boo::VertexElementDescriptor vdescs[] = { {m_splitVertsBuf, nullptr, boo::VertexSemantic::Position4}, {m_splitVertsBuf, nullptr, boo::VertexSemantic::UV4} }; - m_splitVtxFmt = system.m_factory->newVertexFormat(2, vdescs); + m_splitVtxFmt = res.m_factory->newVertexFormat(2, vdescs); boo::IGraphicsBuffer* bufs[] = {m_splitBlockBuf}; - boo::ITexture* texs[] = {system.m_splitRes.m_shadingTex}; - m_splitShaderBinding = system.m_factory->newShaderDataBinding(system.m_viewRes.m_texShader, - m_splitVtxFmt, m_splitVertsBuf, nullptr, - nullptr, 1, bufs, 1, texs); + boo::ITexture* texs[] = {res.m_splitRes.m_shadingTex}; + m_splitShaderBinding = res.m_factory->newShaderDataBinding(res.m_viewRes.m_texShader, + m_splitVtxFmt, m_splitVertsBuf, nullptr, + nullptr, 1, bufs, 1, texs); } else { boo::IGraphicsBuffer* bufs[] = {m_splitBlockBuf}; - boo::ITexture* texs[] = {system.m_splitRes.m_shadingTex}; - m_splitShaderBinding = system.m_factory->newShaderDataBinding(system.m_viewRes.m_texShader, - system.m_viewRes.m_texVtxFmt, - m_splitVertsBuf, nullptr, - nullptr, 1, bufs, 1, texs); + boo::ITexture* texs[] = {res.m_splitRes.m_shadingTex}; + m_splitShaderBinding = res.m_factory->newShaderDataBinding(res.m_viewRes.m_texShader, + res.m_viewRes.m_texVtxFmt, + m_splitVertsBuf, nullptr, + nullptr, 1, bufs, 1, texs); } - commitResources(system); + commitResources(res); } View* SplitView::setContentView(int slot, View* view) diff --git a/specter/lib/Table.cpp b/specter/lib/Table.cpp index d72fe9e37..7312d13dc 100644 --- a/specter/lib/Table.cpp +++ b/specter/lib/Table.cpp @@ -1,8 +1,11 @@ #include "Specter/Table.hpp" #include "Specter/ViewResources.hpp" +#include "Specter/RootView.hpp" namespace Specter { +#define ROW_HEIGHT 18 +#define ROW_SPACING 2 Table::Table(ViewResources& res, View& parentView, ITableDataBinding* data, ITableStateBinding* state) : View(res, parentView), m_data(data), m_state(state), m_rowsView(*this, res) @@ -35,6 +38,53 @@ Table::Table(ViewResources& res, View& parentView, ITableDataBinding* data, ITab m_scroll.m_view.reset(new ScrollView(res, *this)); m_scroll.m_view->setContentView(&m_rowsView); + updateData(); +} + +Table::CellView::CellView(Table& t, ViewResources& res) +: View(res, t), m_t(t), m_text(new TextView(res, *this, res.m_mainFont)) {} + +void Table::_setRowVerts(const boo::SWindowRect& rowsRect) +{ + SolidShaderVert* v = m_verts; + const ThemeData& theme = rootView().themeData(); + float pf = rootView().viewRes().pixelFactor(); + int rowHeight = ROW_HEIGHT * pf; + int rowSpace = ROW_SPACING * pf; + int hAdv = rowHeight + rowSpace; + int yOff = rowsRect.size[1] - hAdv; + size_t i; + for (i=0 ; i= 0 ; ++i) + { + v[0].m_pos.assign(0, yOff, 0); + v[0].m_color = (i&1) ? theme.tableCellBg1() : theme.tableCellBg2(); + v[1] = v[0]; + v[2].m_pos.assign(0, yOff - rowHeight, 0); + v[2].m_color = v[0].m_color; + v[3].m_pos.assign(rowsRect.size[0], yOff, 0); + v[3].m_color = v[0].m_color; + v[4].m_pos.assign(rowsRect.size[0], yOff - rowHeight, 0); + v[4].m_color = v[0].m_color; + v[5] = v[4]; + yOff -= hAdv; + v += 6; + } + m_visibleRows = i; + m_vertsBuf->load(m_verts, sizeof(SolidShaderVert) * 6 * i); +} + +void Table::setMultiplyColor(const Zeus::CColor& color) +{ + View::setMultiplyColor(color); + for (std::unique_ptr& hv : m_headerViews) + if (hv) + hv->m_text->setMultiplyColor(color); + for (auto& col : m_cellViews) + { + for (std::unique_ptr& cv : col) + if (cv) + cv->m_text->setMultiplyColor(color); + } } void Table::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod) @@ -47,6 +97,11 @@ void Table::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, bo m_scroll.mouseUp(coord, button, mod); } +void Table::mouseMove(const boo::SWindowCoord& coord) +{ + m_scroll.mouseMove(coord); +} + void Table::mouseEnter(const boo::SWindowCoord& coord) { m_scroll.mouseEnter(coord); @@ -62,23 +117,139 @@ void Table::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scro m_scroll.scroll(coord, scroll); } -void Table::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) +void Table::updateData() { - boo::SWindowRect rowsRect = sub; - m_scroll.m_view->resized(root, rowsRect); + m_header = false; + m_headerViews.clear(); + m_cellViews.clear(); + m_rows = m_data->rowCount(); + m_columns = m_data->columnCount(); + if (!m_columns) + return; + + m_headerViews.reserve(m_columns); + m_cellViews.reserve(m_columns); + + ViewResources& res = rootView().viewRes(); + const Zeus::CColor& textColor = rootView().themeData().uiText(); + for (size_t c=0 ; cheader(c); + if (headerText) + { + m_header = true; + CellView* cv = new CellView(*this, res); + m_headerViews.emplace_back(cv); + cv->m_text->typesetGlyphs(*headerText, textColor); + } + else + m_headerViews.emplace_back(); + + m_cellViews.emplace_back(); + std::vector>& col = m_cellViews.back(); + col.reserve(m_rows); + for (size_t r=0 ; rcell(c, r); + if (cellText) + { + CellView* cv = new CellView(*this, res); + col.emplace_back(cv); + cv->m_text->typesetGlyphs(*cellText, textColor); + } + else + col.emplace_back(); + } + } + + updateSize(); } -void Table::RowsView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) +void Table::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) { + View::resized(root, sub); + if (m_scroll.m_view) + m_scroll.m_view->resized(root, sub); + + float pf = rootView().viewRes().pixelFactor(); + boo::SWindowRect cell = sub; + cell.size[1] = ROW_HEIGHT * pf; + cell.location[1] += sub.size[1] - cell.size[1]; + int div = sub.size[0] / m_cellViews.size(); + + for (std::unique_ptr& hv : m_headerViews) + { + if (hv) + hv->resized(root, cell); + cell.location[0] += div; + } + + int spacing = ROW_HEIGHT + ROW_SPACING * pf; + cell.location[0] = sub.location[0]; + int hStart = cell.location[1]; + for (auto& col : m_cellViews) + { + cell.location[1] = hStart; + for (std::unique_ptr& cv : col) + { + cell.location[1] -= spacing; + if (cv) + cv->resized(root, cell); + } + cell.location[0] += div; + } +} + +int Table::RowsView::nominalHeight() const +{ + float pf = rootView().viewRes().pixelFactor(); + return m_t.m_rows * (ROW_HEIGHT + ROW_SPACING) * pf; +} + +void Table::RowsView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub, + const boo::SWindowRect& scissor) +{ + m_t._setRowVerts(sub); +} + +void Table::CellView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub) +{ + View::resized(root, sub); + boo::SWindowRect textRect = sub; + float pf = rootView().viewRes().pixelFactor(); + textRect.location[0] += 5 * pf; + textRect.location[1] += 6 * pf; + m_text->resized(root, textRect); } void Table::draw(boo::IGraphicsCommandQueue* gfxQ) { - m_scroll.m_view->draw(gfxQ); + if (m_scroll.m_view) + m_scroll.m_view->draw(gfxQ); } void Table::RowsView::draw(boo::IGraphicsCommandQueue* gfxQ) { + gfxQ->setShaderDataBinding(m_t.m_shaderBinding); + gfxQ->setDrawPrimitive(boo::Primitive::TriStrips); + gfxQ->setScissor(subRect()); + size_t rows = std::min(m_t.m_visibleRows, m_t.m_rows); + gfxQ->draw(1, rows * 6 - 2); + for (std::unique_ptr& hv : m_t.m_headerViews) + if (hv) + hv->draw(gfxQ); + for (auto& col : m_t.m_cellViews) + { + for (std::unique_ptr& cv : col) + if (cv) + cv->draw(gfxQ); + } + gfxQ->setScissor(rootView().subRect()); +} + +void Table::CellView::draw(boo::IGraphicsCommandQueue* gfxQ) +{ + m_text->draw(gfxQ); } } diff --git a/specter/lib/View.cpp b/specter/lib/View.cpp index 6750ff2f4..0cf7692f8 100644 --- a/specter/lib/View.cpp +++ b/specter/lib/View.cpp @@ -283,52 +283,52 @@ void View::Resources::init(boo::MetalDataFactory* factory, const ThemeData& them #endif -void View::buildResources(ViewResources& system) +void View::buildResources(ViewResources& res) { m_bgVertBuf = - system.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, - sizeof(SolidShaderVert), 4); + res.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, + sizeof(SolidShaderVert), 4); m_viewVertBlockBuf = - system.m_factory->newDynamicBuffer(boo::BufferUse::Uniform, - sizeof(ViewBlock), 1); + res.m_factory->newDynamicBuffer(boo::BufferUse::Uniform, + sizeof(ViewBlock), 1); - if (!system.m_viewRes.m_solidVtxFmt) + if (!res.m_viewRes.m_solidVtxFmt) { boo::VertexElementDescriptor vdescs[] = { {m_bgVertBuf, nullptr, boo::VertexSemantic::Position4}, {m_bgVertBuf, nullptr, boo::VertexSemantic::Color} }; - m_bgVtxFmt = system.m_factory->newVertexFormat(2, vdescs); + m_bgVtxFmt = res.m_factory->newVertexFormat(2, vdescs); m_bgShaderBinding = - system.m_factory->newShaderDataBinding(system.m_viewRes.m_solidShader, m_bgVtxFmt, - m_bgVertBuf, nullptr, nullptr, 1, - (boo::IGraphicsBuffer**)&m_viewVertBlockBuf, - 0, nullptr); + res.m_factory->newShaderDataBinding(res.m_viewRes.m_solidShader, m_bgVtxFmt, + m_bgVertBuf, nullptr, nullptr, 1, + (boo::IGraphicsBuffer**)&m_viewVertBlockBuf, + 0, nullptr); } else { m_bgShaderBinding = - system.m_factory->newShaderDataBinding(system.m_viewRes.m_solidShader, system.m_viewRes.m_solidVtxFmt, - m_bgVertBuf, nullptr, nullptr, 1, - (boo::IGraphicsBuffer**)&m_viewVertBlockBuf, - 0, nullptr); + res.m_factory->newShaderDataBinding(res.m_viewRes.m_solidShader, res.m_viewRes.m_solidVtxFmt, + m_bgVertBuf, nullptr, nullptr, 1, + (boo::IGraphicsBuffer**)&m_viewVertBlockBuf, + 0, nullptr); } } -View::View(ViewResources& system) +View::View(ViewResources& res) : m_rootView(*static_cast(this)), m_parentView(*static_cast(this)) { - buildResources(system); + buildResources(res); } -View::View(ViewResources& system, View& parentView) +View::View(ViewResources& res, View& parentView) : m_rootView(parentView.rootView()), m_parentView(parentView) { - buildResources(system); + buildResources(res); } void View::updateSize() @@ -355,9 +355,9 @@ void View::draw(boo::IGraphicsCommandQueue* gfxQ) gfxQ->draw(0, 4); } -void View::commitResources(ViewResources& system) +void View::commitResources(ViewResources& res) { - m_gfxData = system.m_factory->commit(); + m_gfxData = res.m_factory->commit(); } }