mirror of https://github.com/AxioDL/metaforce.git
Work on TextField
This commit is contained in:
parent
5d56ef2cf6
commit
95fd2f90a9
|
@ -60,7 +60,13 @@ public:
|
||||||
void mouseMove(const boo::SWindowCoord&);
|
void mouseMove(const boo::SWindowCoord&);
|
||||||
void mouseEnter(const boo::SWindowCoord&);
|
void mouseEnter(const boo::SWindowCoord&);
|
||||||
void mouseLeave(const boo::SWindowCoord&);
|
void mouseLeave(const boo::SWindowCoord&);
|
||||||
|
void scroll(const boo::SWindowCoord&, const boo::SScrollDelta&);
|
||||||
|
void touchDown(const boo::STouchCoord&, uintptr_t);
|
||||||
|
void touchUp(const boo::STouchCoord&, uintptr_t);
|
||||||
|
void touchMove(const boo::STouchCoord&, uintptr_t);
|
||||||
|
|
||||||
void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub);
|
void resized(const boo::SWindowRect& root, const boo::SWindowRect& sub);
|
||||||
|
void think();
|
||||||
void draw(boo::IGraphicsCommandQueue* gfxQ);
|
void draw(boo::IGraphicsCommandQueue* gfxQ);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -23,8 +23,7 @@ class ModalWindow : public View
|
||||||
|
|
||||||
int m_width = 0;
|
int m_width = 0;
|
||||||
int m_height = 0;
|
int m_height = 0;
|
||||||
int m_widthConstrain;
|
RectangleConstraint m_constraint;
|
||||||
int m_heightConstrain;
|
|
||||||
|
|
||||||
Zeus::CColor m_windowBg;
|
Zeus::CColor m_windowBg;
|
||||||
Zeus::CColor m_windowBgClear;
|
Zeus::CColor m_windowBgClear;
|
||||||
|
@ -57,7 +56,7 @@ protected:
|
||||||
virtual void updateContentOpacity(float opacity) {}
|
virtual void updateContentOpacity(float opacity) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ModalWindow(ViewResources& res, View& parentView, int widthConstrain=-1, int heightConstrain=-1);
|
ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint);
|
||||||
void think();
|
void think();
|
||||||
bool skipBuildInAnimation();
|
bool skipBuildInAnimation();
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "View.hpp"
|
#include "View.hpp"
|
||||||
#include "ViewResources.hpp"
|
#include "ViewResources.hpp"
|
||||||
#include "MultiLineTextView.hpp"
|
#include "MultiLineTextView.hpp"
|
||||||
|
#include "TextField.hpp"
|
||||||
#include "SplitView.hpp"
|
#include "SplitView.hpp"
|
||||||
#include "Tooltip.hpp"
|
#include "Tooltip.hpp"
|
||||||
#include "FontCache.hpp"
|
#include "FontCache.hpp"
|
||||||
|
@ -26,6 +27,7 @@ class RootView : public View
|
||||||
bool m_destroyed = false;
|
bool m_destroyed = false;
|
||||||
IViewManager& m_viewMan;
|
IViewManager& m_viewMan;
|
||||||
ViewResources* m_viewRes;
|
ViewResources* m_viewRes;
|
||||||
|
View* m_activeTextView = nullptr;
|
||||||
|
|
||||||
DeferredWindowEvents<RootView> m_events;
|
DeferredWindowEvents<RootView> m_events;
|
||||||
|
|
||||||
|
@ -64,6 +66,13 @@ public:
|
||||||
const ThemeData& themeData() const {return m_viewRes->m_theme;}
|
const ThemeData& themeData() const {return m_viewRes->m_theme;}
|
||||||
|
|
||||||
View* setContentView(View* view);
|
View* setContentView(View* view);
|
||||||
|
void setActiveTextView(View* textView)
|
||||||
|
{
|
||||||
|
if (m_activeTextView)
|
||||||
|
m_activeTextView->setActive(false);
|
||||||
|
m_activeTextView = textView;
|
||||||
|
textView->setActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
void resetTooltip(ViewResources& res);
|
void resetTooltip(ViewResources& res);
|
||||||
void displayTooltip(const std::string& name, const std::string& help);
|
void displayTooltip(const std::string& name, const std::string& help);
|
||||||
|
|
|
@ -12,7 +12,7 @@ class TextField : public Control
|
||||||
std::string m_textStr;
|
std::string m_textStr;
|
||||||
std::unique_ptr<TextView> m_text;
|
std::unique_ptr<TextView> m_text;
|
||||||
|
|
||||||
SolidShaderVert m_verts[28];
|
SolidShaderVert m_verts[32];
|
||||||
boo::IGraphicsBufferD* m_bVertsBuf = nullptr;
|
boo::IGraphicsBufferD* m_bVertsBuf = nullptr;
|
||||||
boo::IVertexFormat* m_bVtxFmt = nullptr; /* OpenGL only */
|
boo::IVertexFormat* m_bVtxFmt = nullptr; /* OpenGL only */
|
||||||
boo::IShaderDataBinding* m_bShaderBinding = nullptr;
|
boo::IShaderDataBinding* m_bShaderBinding = nullptr;
|
||||||
|
@ -20,6 +20,13 @@ class TextField : public Control
|
||||||
int m_nomWidth = 0;
|
int m_nomWidth = 0;
|
||||||
int m_nomHeight = 0;
|
int m_nomHeight = 0;
|
||||||
|
|
||||||
|
size_t m_selectionStart = 0;
|
||||||
|
size_t m_selectionCount = 0;
|
||||||
|
size_t m_cursorPos = 0;
|
||||||
|
size_t m_cursorFrames = 0;
|
||||||
|
|
||||||
|
bool m_active = false;
|
||||||
|
|
||||||
void setInactive();
|
void setInactive();
|
||||||
void setHover();
|
void setHover();
|
||||||
void setDisabled();
|
void setDisabled();
|
||||||
|
@ -27,19 +34,29 @@ class TextField : public Control
|
||||||
public:
|
public:
|
||||||
TextField(ViewResources& res, View& parentView, IStringBinding* strBind);
|
TextField(ViewResources& res, View& parentView, IStringBinding* strBind);
|
||||||
|
|
||||||
|
const std::string& getText() const {return m_textStr;}
|
||||||
void setText(const std::string& str);
|
void setText(const std::string& str);
|
||||||
|
|
||||||
void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
|
void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
|
||||||
void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
|
void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey);
|
||||||
void mouseMove(const boo::SWindowCoord&);
|
void mouseMove(const boo::SWindowCoord&);
|
||||||
void mouseEnter(const boo::SWindowCoord&);
|
void mouseEnter(const boo::SWindowCoord&);
|
||||||
void mouseLeave(const boo::SWindowCoord&coord);
|
void mouseLeave(const boo::SWindowCoord&);
|
||||||
|
void charKeyDown(unsigned long, boo::EModifierKey, bool);
|
||||||
|
void specialKeyDown(boo::ESpecialKey, boo::EModifierKey, bool);
|
||||||
|
void think();
|
||||||
void resized(const boo::SWindowRect& rootView, const boo::SWindowRect& sub);
|
void resized(const boo::SWindowRect& rootView, const boo::SWindowRect& sub);
|
||||||
void draw(boo::IGraphicsCommandQueue* gfxQ);
|
void draw(boo::IGraphicsCommandQueue* gfxQ);
|
||||||
|
|
||||||
int nominalWidth() const {return m_nomWidth;}
|
int nominalWidth() const {return m_nomWidth;}
|
||||||
int nominalHeight() const {return m_nomHeight;}
|
int nominalHeight() const {return m_nomHeight;}
|
||||||
|
|
||||||
|
void setActive(bool active);
|
||||||
|
void setCursorPos(size_t pos);
|
||||||
|
|
||||||
|
void setSelectionRange(size_t start, size_t count);
|
||||||
|
void clearSelectionRange();
|
||||||
|
|
||||||
void setMultiplyColor(const Zeus::CColor& color)
|
void setMultiplyColor(const Zeus::CColor& color)
|
||||||
{
|
{
|
||||||
View::setMultiplyColor(color);
|
View::setMultiplyColor(color);
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, const Zeus::CColor& defaultColor);
|
RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, const Zeus::CColor& defaultColor);
|
||||||
};
|
};
|
||||||
std::vector<RenderGlyph>& accessGlyphs() {return m_glyphs;}
|
std::vector<RenderGlyph>& accessGlyphs() {return m_glyphs;}
|
||||||
|
const std::vector<RenderGlyph>& accessGlyphs() const {return m_glyphs;}
|
||||||
void updateGlyphs() {m_valid = false;}
|
void updateGlyphs() {m_valid = false;}
|
||||||
|
|
||||||
void typesetGlyphs(const std::string& str,
|
void typesetGlyphs(const std::string& str,
|
||||||
|
@ -85,10 +86,13 @@ public:
|
||||||
int nominalHeight() const {return m_fontAtlas.FT_LineHeight() >> 6;}
|
int nominalHeight() const {return m_fontAtlas.FT_LineHeight() >> 6;}
|
||||||
|
|
||||||
std::pair<int,int> queryGlyphDimensions(size_t pos) const;
|
std::pair<int,int> queryGlyphDimensions(size_t pos) const;
|
||||||
|
size_t reverseSelectGlyph(int x) const;
|
||||||
|
int queryReverseAdvance(size_t idx) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<RenderGlyph> m_glyphs;
|
std::vector<RenderGlyph> m_glyphs;
|
||||||
std::vector<std::pair<int,int>> m_glyphDims;
|
std::vector<std::pair<int,int>> m_glyphDims;
|
||||||
|
std::vector<int> m_glyphAdvs;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,65 @@ class ThemeData;
|
||||||
class ViewResources;
|
class ViewResources;
|
||||||
class RootView;
|
class RootView;
|
||||||
|
|
||||||
|
class RectangleConstraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Test
|
||||||
|
{
|
||||||
|
Fixed,
|
||||||
|
Minimum,
|
||||||
|
Maximum
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
int m_x, m_y;
|
||||||
|
Test m_xtest, m_ytest;
|
||||||
|
public:
|
||||||
|
RectangleConstraint(int x=-1, int y=-1, Test xtest=Test::Fixed, Test ytest=Test::Fixed)
|
||||||
|
: m_x(x), m_y(y), m_xtest(xtest), m_ytest(ytest) {}
|
||||||
|
std::pair<int,int> solve(int x, int y) const
|
||||||
|
{
|
||||||
|
std::pair<int,int> ret;
|
||||||
|
|
||||||
|
if (m_x < 0)
|
||||||
|
ret.first = x;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (m_xtest)
|
||||||
|
{
|
||||||
|
case Test::Fixed:
|
||||||
|
ret.first = m_x;
|
||||||
|
break;
|
||||||
|
case Test::Minimum:
|
||||||
|
ret.first = std::max(m_x, x);
|
||||||
|
break;
|
||||||
|
case Test::Maximum:
|
||||||
|
ret.first = std::min(m_x, x);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_y < 0)
|
||||||
|
ret.second = y;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (m_ytest)
|
||||||
|
{
|
||||||
|
case Test::Fixed:
|
||||||
|
ret.second = m_y;
|
||||||
|
break;
|
||||||
|
case Test::Minimum:
|
||||||
|
ret.second = std::max(m_y, y);
|
||||||
|
break;
|
||||||
|
case Test::Maximum:
|
||||||
|
ret.second = std::min(m_y, y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class View
|
class View
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -127,13 +186,26 @@ public:
|
||||||
virtual int nominalWidth() const {return 0;}
|
virtual int nominalWidth() const {return 0;}
|
||||||
virtual int nominalHeight() const {return 0;}
|
virtual int nominalHeight() const {return 0;}
|
||||||
|
|
||||||
virtual void updateCVar(HECL::CVar* cvar) {}
|
virtual void setActive(bool) {}
|
||||||
|
|
||||||
virtual void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey) {}
|
virtual void mouseDown(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey) {}
|
||||||
virtual void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey) {}
|
virtual void mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey) {}
|
||||||
virtual void mouseMove(const boo::SWindowCoord&) {}
|
virtual void mouseMove(const boo::SWindowCoord&) {}
|
||||||
virtual void mouseEnter(const boo::SWindowCoord&) {}
|
virtual void mouseEnter(const boo::SWindowCoord&) {}
|
||||||
virtual void mouseLeave(const boo::SWindowCoord&) {}
|
virtual void mouseLeave(const boo::SWindowCoord&) {}
|
||||||
|
virtual void scroll(const boo::SWindowCoord&, const boo::SScrollDelta&) {}
|
||||||
|
virtual void touchDown(const boo::STouchCoord&, uintptr_t) {}
|
||||||
|
virtual void touchUp(const boo::STouchCoord&, uintptr_t) {}
|
||||||
|
virtual void touchMove(const boo::STouchCoord&, uintptr_t) {}
|
||||||
|
virtual void charKeyDown(unsigned long, boo::EModifierKey, bool) {}
|
||||||
|
virtual void charKeyUp(unsigned long, boo::EModifierKey) {}
|
||||||
|
virtual void specialKeyDown(boo::ESpecialKey, boo::EModifierKey, bool) {}
|
||||||
|
virtual void specialKeyUp(boo::ESpecialKey, boo::EModifierKey) {}
|
||||||
|
virtual void modKeyDown(boo::EModifierKey, bool) {}
|
||||||
|
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);
|
||||||
|
virtual void think() {}
|
||||||
virtual void draw(boo::IGraphicsCommandQueue* gfxQ);
|
virtual void draw(boo::IGraphicsCommandQueue* gfxQ);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ class ThemeData
|
||||||
{
|
{
|
||||||
Zeus::CColor m_uiText = Zeus::CColor::skWhite;
|
Zeus::CColor m_uiText = Zeus::CColor::skWhite;
|
||||||
Zeus::CColor m_fieldText = Zeus::CColor::skBlack;
|
Zeus::CColor m_fieldText = Zeus::CColor::skBlack;
|
||||||
|
Zeus::CColor m_selectedFieldText = Zeus::CColor::skWhite;
|
||||||
|
|
||||||
Zeus::CColor m_vpBg = {0.2, 0.2, 0.2, 1.0};
|
Zeus::CColor m_vpBg = {0.2, 0.2, 0.2, 1.0};
|
||||||
Zeus::CColor m_tbBg = {0.4, 0.4, 0.4, 1.0};
|
Zeus::CColor m_tbBg = {0.4, 0.4, 0.4, 1.0};
|
||||||
|
@ -38,10 +39,12 @@ class ThemeData
|
||||||
Zeus::CColor m_textfield1Hover = {0.6425, 0.6425, 0.6425, 1.0};
|
Zeus::CColor m_textfield1Hover = {0.6425, 0.6425, 0.6425, 1.0};
|
||||||
Zeus::CColor m_textfield2Disabled = {0.7823, 0.7823, 0.7823, 0.5};
|
Zeus::CColor m_textfield2Disabled = {0.7823, 0.7823, 0.7823, 0.5};
|
||||||
Zeus::CColor m_textfield1Disabled = {0.5725, 0.5725, 0.5725, 0.5};
|
Zeus::CColor m_textfield1Disabled = {0.5725, 0.5725, 0.5725, 0.5};
|
||||||
|
Zeus::CColor m_textfieldSelection = {0.2725, 0.2725, 0.2725, 1.0};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual const Zeus::CColor& uiText() const {return m_uiText;}
|
virtual const Zeus::CColor& uiText() const {return m_uiText;}
|
||||||
virtual const Zeus::CColor& fieldText() const {return m_fieldText;}
|
virtual const Zeus::CColor& fieldText() const {return m_fieldText;}
|
||||||
|
virtual const Zeus::CColor& selectedFieldText() const {return m_selectedFieldText;}
|
||||||
|
|
||||||
virtual const Zeus::CColor& viewportBackground() const {return m_vpBg;}
|
virtual const Zeus::CColor& viewportBackground() const {return m_vpBg;}
|
||||||
virtual const Zeus::CColor& toolbarBackground() const {return m_tbBg;}
|
virtual const Zeus::CColor& toolbarBackground() const {return m_tbBg;}
|
||||||
|
@ -66,6 +69,7 @@ public:
|
||||||
virtual const Zeus::CColor& textfield2Hover() const {return m_textfield2Hover;}
|
virtual const Zeus::CColor& textfield2Hover() const {return m_textfield2Hover;}
|
||||||
virtual const Zeus::CColor& textfield1Disabled() const {return m_textfield1Disabled;}
|
virtual const Zeus::CColor& textfield1Disabled() const {return m_textfield1Disabled;}
|
||||||
virtual const Zeus::CColor& textfield2Disabled() const {return m_textfield2Disabled;}
|
virtual const Zeus::CColor& textfield2Disabled() const {return m_textfield2Disabled;}
|
||||||
|
virtual const Zeus::CColor& textfieldSelection() const {return m_textfieldSelection;}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ViewResources
|
class ViewResources
|
||||||
|
|
|
@ -5,8 +5,8 @@ namespace Specter
|
||||||
{
|
{
|
||||||
|
|
||||||
#define BROWSER_MARGIN 30
|
#define BROWSER_MARGIN 30
|
||||||
#define BROWSER_MIN_WIDTH 100
|
#define BROWSER_MIN_WIDTH 600
|
||||||
#define BROWSER_MIN_HEIGHT 100
|
#define BROWSER_MIN_HEIGHT 300
|
||||||
|
|
||||||
static std::vector<HECL::SystemString> PathComponents(const HECL::SystemString& path)
|
static std::vector<HECL::SystemString> PathComponents(const HECL::SystemString& path)
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,10 @@ static std::vector<HECL::SystemString> PathComponents(const HECL::SystemString&
|
||||||
}
|
}
|
||||||
|
|
||||||
FileBrowser::FileBrowser(ViewResources& res, View& parentView, const HECL::SystemString& initialPath)
|
FileBrowser::FileBrowser(ViewResources& res, View& parentView, const HECL::SystemString& initialPath)
|
||||||
: ModalWindow(res, parentView),
|
: ModalWindow(res, parentView, RectangleConstraint(BROWSER_MIN_WIDTH * res.pixelFactor(),
|
||||||
|
BROWSER_MIN_HEIGHT * res.pixelFactor(),
|
||||||
|
RectangleConstraint::Test::Minimum,
|
||||||
|
RectangleConstraint::Test::Minimum)),
|
||||||
m_comps(PathComponents(initialPath)),
|
m_comps(PathComponents(initialPath)),
|
||||||
m_fileFieldBind(*this)
|
m_fileFieldBind(*this)
|
||||||
{
|
{
|
||||||
|
@ -102,20 +105,34 @@ void FileBrowser::mouseLeave(const boo::SWindowCoord& coord)
|
||||||
m_fileField.mouseLeave(coord);
|
m_fileField.mouseLeave(coord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileBrowser::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileBrowser::touchDown(const boo::STouchCoord& coord, uintptr_t tid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileBrowser::touchUp(const boo::STouchCoord& coord, uintptr_t tid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileBrowser::touchMove(const boo::STouchCoord& coord, uintptr_t tid)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void FileBrowser::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
|
void FileBrowser::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
|
||||||
{
|
{
|
||||||
ModalWindow::resized(root, root);
|
ModalWindow::resized(root, root);
|
||||||
float pf = rootView().viewRes().pixelFactor();
|
float pf = rootView().viewRes().pixelFactor();
|
||||||
|
|
||||||
boo::SWindowRect centerRect = sub;
|
boo::SWindowRect centerRect = subRect();
|
||||||
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[0] = root.size[0] / 2 - (centerRect.size[0] / 2.0);
|
||||||
centerRect.location[1] = root.size[1] / 2 - (centerRect.size[1] / 2.0);
|
centerRect.location[1] = root.size[1] / 2 - (centerRect.size[1] / 2.0);
|
||||||
|
|
||||||
boo::SWindowRect pathRect = centerRect;
|
boo::SWindowRect pathRect = centerRect;
|
||||||
pathRect.location[0] += 10 * pf;
|
pathRect.location[0] += 25 * pf;
|
||||||
pathRect.location[1] += pathRect.size[1] - 20 * pf;
|
pathRect.location[1] += pathRect.size[1] - 50 * pf;
|
||||||
for (PathButton& b : m_pathButtons)
|
for (PathButton& b : m_pathButtons)
|
||||||
{
|
{
|
||||||
pathRect.size[0] = b.m_button.m_view->nominalWidth();
|
pathRect.size[0] = b.m_button.m_view->nominalWidth();
|
||||||
|
@ -124,13 +141,19 @@ void FileBrowser::resized(const boo::SWindowRect& root, const boo::SWindowRect&
|
||||||
pathRect.location[0] += pathRect.size[0] + 2;
|
pathRect.location[0] += pathRect.size[0] + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
pathRect.location[0] = centerRect.location[0] + 10 * pf;
|
pathRect.location[0] = centerRect.location[0] + 25 * pf;
|
||||||
pathRect.location[1] -= 25 * pf;
|
pathRect.location[1] -= 25 * pf;
|
||||||
pathRect.size[0] = centerRect.size[0] - 20 * pf;
|
pathRect.size[0] = centerRect.size[0] - 50 * pf;
|
||||||
pathRect.size[1] = m_fileField.m_view->nominalHeight();
|
pathRect.size[1] = m_fileField.m_view->nominalHeight();
|
||||||
m_fileField.m_view->resized(root, pathRect);
|
m_fileField.m_view->resized(root, pathRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FileBrowser::think()
|
||||||
|
{
|
||||||
|
ModalWindow::think();
|
||||||
|
m_fileField.m_view->think();
|
||||||
|
}
|
||||||
|
|
||||||
void FileBrowser::draw(boo::IGraphicsCommandQueue* gfxQ)
|
void FileBrowser::draw(boo::IGraphicsCommandQueue* gfxQ)
|
||||||
{
|
{
|
||||||
ModalWindow::draw(gfxQ);
|
ModalWindow::draw(gfxQ);
|
||||||
|
|
|
@ -168,10 +168,9 @@ void ModalWindow::setFillColors(float t)
|
||||||
m_cornersFilled[i]->colorGlyphs(color);
|
m_cornersFilled[i]->colorGlyphs(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModalWindow::ModalWindow(ViewResources& res, View& parentView, int widthConstrain, int heightConstrain)
|
ModalWindow::ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint)
|
||||||
: View(res, parentView),
|
: View(res, parentView),
|
||||||
m_widthConstrain(widthConstrain),
|
m_constraint(constraint),
|
||||||
m_heightConstrain(heightConstrain),
|
|
||||||
m_windowBg(res.themeData().splashBackground()),
|
m_windowBg(res.themeData().splashBackground()),
|
||||||
m_windowBgClear(m_windowBg),
|
m_windowBgClear(m_windowBg),
|
||||||
m_line1(res.themeData().splash1()),
|
m_line1(res.themeData().splash1()),
|
||||||
|
@ -302,10 +301,10 @@ void ModalWindow::resized(const boo::SWindowRect& root, const boo::SWindowRect&
|
||||||
float pf = rootView().viewRes().pixelFactor();
|
float pf = rootView().viewRes().pixelFactor();
|
||||||
|
|
||||||
boo::SWindowRect centerRect = sub;
|
boo::SWindowRect centerRect = sub;
|
||||||
m_width = m_widthConstrain < 0 ? root.size[0] - CONTENT_MARGIN * pf * 2 : m_widthConstrain;
|
std::pair<int,int> constrained = m_constraint.solve(root.size[0] - CONTENT_MARGIN * pf * 2,
|
||||||
m_height = m_heightConstrain < 0 ? root.size[1] - CONTENT_MARGIN * pf * 2 : m_heightConstrain;
|
root.size[1] - CONTENT_MARGIN * pf * 2);
|
||||||
m_width = std::max(m_width, int(WINDOW_MIN_DIM * pf));
|
m_width = std::max(constrained.first, int(WINDOW_MIN_DIM * pf));
|
||||||
m_height = std::max(m_height, int(WINDOW_MIN_DIM * pf));
|
m_height = std::max(constrained.second, int(WINDOW_MIN_DIM * pf));
|
||||||
centerRect.size[0] = m_width;
|
centerRect.size[0] = m_width;
|
||||||
centerRect.size[1] = m_height;
|
centerRect.size[1] = m_height;
|
||||||
centerRect.location[0] = root.size[0] / 2 - m_width / 2.0;
|
centerRect.location[0] = root.size[0] / 2 - m_width / 2.0;
|
||||||
|
|
|
@ -80,44 +80,79 @@ void RootView::mouseLeave(const boo::SWindowCoord& coord)
|
||||||
|
|
||||||
void RootView::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll)
|
void RootView::scroll(const boo::SWindowCoord& coord, const boo::SScrollDelta& scroll)
|
||||||
{
|
{
|
||||||
|
if (m_view)
|
||||||
|
m_view->scroll(coord, scroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootView::touchDown(const boo::STouchCoord& coord, uintptr_t tid)
|
void RootView::touchDown(const boo::STouchCoord& coord, uintptr_t tid)
|
||||||
{
|
{
|
||||||
|
if (m_view)
|
||||||
|
m_view->touchDown(coord, tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootView::touchUp(const boo::STouchCoord& coord, uintptr_t tid)
|
void RootView::touchUp(const boo::STouchCoord& coord, uintptr_t tid)
|
||||||
{
|
{
|
||||||
|
if (m_view)
|
||||||
|
m_view->touchUp(coord, tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootView::touchMove(const boo::STouchCoord& coord, uintptr_t tid)
|
void RootView::touchMove(const boo::STouchCoord& coord, uintptr_t tid)
|
||||||
{
|
{
|
||||||
|
if (m_view)
|
||||||
|
m_view->touchMove(coord, tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootView::charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat)
|
void RootView::charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat)
|
||||||
{
|
{
|
||||||
|
if (m_view)
|
||||||
|
m_view->charKeyDown(charCode, mods, isRepeat);
|
||||||
|
if (m_activeTextView)
|
||||||
|
m_activeTextView->charKeyDown(charCode, mods, isRepeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootView::charKeyUp(unsigned long charCode, boo::EModifierKey mods)
|
void RootView::charKeyUp(unsigned long charCode, boo::EModifierKey mods)
|
||||||
{
|
{
|
||||||
|
if (m_view)
|
||||||
|
m_view->charKeyUp(charCode, mods);
|
||||||
|
if (m_activeTextView)
|
||||||
|
m_activeTextView->charKeyUp(charCode, mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootView::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat)
|
void RootView::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat)
|
||||||
{
|
{
|
||||||
if (key == boo::ESpecialKey::Enter && (mods & boo::EModifierKey::Alt) != boo::EModifierKey::None)
|
if (key == boo::ESpecialKey::Enter && (mods & boo::EModifierKey::Alt) != boo::EModifierKey::None)
|
||||||
|
{
|
||||||
m_window->setFullscreen(!m_window->isFullscreen());
|
m_window->setFullscreen(!m_window->isFullscreen());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_view)
|
||||||
|
m_view->specialKeyDown(key, mods, isRepeat);
|
||||||
|
if (m_activeTextView)
|
||||||
|
m_activeTextView->specialKeyDown(key, mods, isRepeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootView::specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods)
|
void RootView::specialKeyUp(boo::ESpecialKey key, boo::EModifierKey mods)
|
||||||
{
|
{
|
||||||
|
if (m_view)
|
||||||
|
m_view->specialKeyUp(key, mods);
|
||||||
|
if (m_activeTextView)
|
||||||
|
m_activeTextView->specialKeyUp(key, mods);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootView::modKeyDown(boo::EModifierKey mod, bool isRepeat)
|
void RootView::modKeyDown(boo::EModifierKey mod, bool isRepeat)
|
||||||
{
|
{
|
||||||
|
if (m_view)
|
||||||
|
m_view->modKeyDown(mod, isRepeat);
|
||||||
|
if (m_activeTextView)
|
||||||
|
m_activeTextView->modKeyDown(mod, isRepeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RootView::modKeyUp(boo::EModifierKey mod)
|
void RootView::modKeyUp(boo::EModifierKey mod)
|
||||||
{
|
{
|
||||||
|
if (m_view)
|
||||||
|
m_view->modKeyUp(mod);
|
||||||
|
if (m_activeTextView)
|
||||||
|
m_activeTextView->modKeyUp(mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
View* RootView::setContentView(View* view)
|
View* RootView::setContentView(View* view)
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Specter
|
||||||
TextField::TextField(ViewResources& res, View& parentView, IStringBinding* strBind)
|
TextField::TextField(ViewResources& res, View& parentView, IStringBinding* strBind)
|
||||||
: Control(res, parentView, strBind)
|
: Control(res, parentView, strBind)
|
||||||
{
|
{
|
||||||
m_bVertsBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(SolidShaderVert), 28);
|
m_bVertsBuf = res.m_factory->newDynamicBuffer(boo::BufferUse::Vertex, sizeof(SolidShaderVert), 32);
|
||||||
|
|
||||||
if (!res.m_viewRes.m_texVtxFmt)
|
if (!res.m_viewRes.m_texVtxFmt)
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,9 @@ TextField::TextField(ViewResources& res, View& parentView, IStringBinding* strBi
|
||||||
m_verts[4].m_color = rootView().themeData().textfield2Inactive();
|
m_verts[4].m_color = rootView().themeData().textfield2Inactive();
|
||||||
for (int i=5 ; i<28 ; ++i)
|
for (int i=5 ; i<28 ; ++i)
|
||||||
m_verts[i].m_color = res.themeData().textfield2Inactive();
|
m_verts[i].m_color = res.themeData().textfield2Inactive();
|
||||||
m_bVertsBuf->load(m_verts, sizeof(SolidShaderVert) * 28);
|
for (int i=28 ; i<32 ; ++i)
|
||||||
|
m_verts[i].m_color = res.themeData().textfieldSelection();
|
||||||
|
m_bVertsBuf->load(m_verts, sizeof(m_verts));
|
||||||
|
|
||||||
m_text.reset(new TextView(res, *this, res.m_mainFont, TextView::Alignment::Left, 1024));
|
m_text.reset(new TextView(res, *this, res.m_mainFont, TextView::Alignment::Left, 1024));
|
||||||
setText("Test");
|
setText("Test");
|
||||||
|
@ -48,8 +50,13 @@ TextField::TextField(ViewResources& res, View& parentView, IStringBinding* strBi
|
||||||
|
|
||||||
void TextField::setText(const std::string& str)
|
void TextField::setText(const std::string& str)
|
||||||
{
|
{
|
||||||
m_textStr = str;
|
clearSelectionRange();
|
||||||
m_text->typesetGlyphs(str, rootView().themeData().fieldText());
|
auto it = str.cbegin();
|
||||||
|
for (; it != str.cend() ; ++it)
|
||||||
|
if (*it == '\n')
|
||||||
|
break;
|
||||||
|
m_textStr.assign(str.cbegin(), it);
|
||||||
|
m_text->typesetGlyphs(m_textStr, rootView().themeData().fieldText());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextField::setInactive()
|
void TextField::setInactive()
|
||||||
|
@ -59,7 +66,7 @@ void TextField::setInactive()
|
||||||
m_verts[2].m_color = rootView().themeData().textfield1Inactive();
|
m_verts[2].m_color = rootView().themeData().textfield1Inactive();
|
||||||
m_verts[3].m_color = rootView().themeData().textfield2Inactive();
|
m_verts[3].m_color = rootView().themeData().textfield2Inactive();
|
||||||
m_verts[4].m_color = rootView().themeData().textfield2Inactive();
|
m_verts[4].m_color = rootView().themeData().textfield2Inactive();
|
||||||
m_bVertsBuf->load(m_verts, sizeof(SolidShaderVert) * 28);
|
m_bVertsBuf->load(m_verts, sizeof(m_verts));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextField::setHover()
|
void TextField::setHover()
|
||||||
|
@ -69,7 +76,7 @@ void TextField::setHover()
|
||||||
m_verts[2].m_color = rootView().themeData().textfield1Hover();
|
m_verts[2].m_color = rootView().themeData().textfield1Hover();
|
||||||
m_verts[3].m_color = rootView().themeData().textfield2Hover();
|
m_verts[3].m_color = rootView().themeData().textfield2Hover();
|
||||||
m_verts[4].m_color = rootView().themeData().textfield2Hover();
|
m_verts[4].m_color = rootView().themeData().textfield2Hover();
|
||||||
m_bVertsBuf->load(m_verts, sizeof(SolidShaderVert) * 28);
|
m_bVertsBuf->load(m_verts, sizeof(m_verts));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextField::setDisabled()
|
void TextField::setDisabled()
|
||||||
|
@ -79,11 +86,19 @@ void TextField::setDisabled()
|
||||||
m_verts[2].m_color = rootView().themeData().textfield1Disabled();
|
m_verts[2].m_color = rootView().themeData().textfield1Disabled();
|
||||||
m_verts[3].m_color = rootView().themeData().textfield2Disabled();
|
m_verts[3].m_color = rootView().themeData().textfield2Disabled();
|
||||||
m_verts[4].m_color = rootView().themeData().textfield2Disabled();
|
m_verts[4].m_color = rootView().themeData().textfield2Disabled();
|
||||||
m_bVertsBuf->load(m_verts, sizeof(SolidShaderVert) * 28);
|
m_bVertsBuf->load(m_verts, sizeof(m_verts));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextField::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
void TextField::mouseDown(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
||||||
{
|
{
|
||||||
|
if (!m_active)
|
||||||
|
{
|
||||||
|
rootView().setActiveTextView(this);
|
||||||
|
if (!m_selectionCount)
|
||||||
|
setSelectionRange(0, m_textStr.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
setCursorPos(m_text->reverseSelectGlyph(coord.pixel[0] - m_text->subRect().location[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextField::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
void TextField::mouseUp(const boo::SWindowCoord& coord, boo::EMouseButton button, boo::EModifierKey mod)
|
||||||
|
@ -97,11 +112,120 @@ void TextField::mouseMove(const boo::SWindowCoord& coord)
|
||||||
void TextField::mouseEnter(const boo::SWindowCoord& coord)
|
void TextField::mouseEnter(const boo::SWindowCoord& coord)
|
||||||
{
|
{
|
||||||
setHover();
|
setHover();
|
||||||
|
rootView().window()->setCursor(boo::EMouseCursor::IBeam);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextField::mouseLeave(const boo::SWindowCoord& coord)
|
void TextField::mouseLeave(const boo::SWindowCoord& coord)
|
||||||
{
|
{
|
||||||
setInactive();
|
setInactive();
|
||||||
|
rootView().window()->setCursor(boo::EMouseCursor::Pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextField::charKeyDown(unsigned long charCode, boo::EModifierKey mods, bool isRepeat)
|
||||||
|
{
|
||||||
|
if (m_selectionCount)
|
||||||
|
{
|
||||||
|
std::string newStr(m_textStr.cbegin(), m_textStr.cbegin() + m_selectionStart);
|
||||||
|
utf8proc_uint8_t theChar[5] = {};
|
||||||
|
utf8proc_ssize_t sz = utf8proc_encode_char(charCode, theChar);
|
||||||
|
if (sz > 0)
|
||||||
|
newStr += (char*)theChar;
|
||||||
|
newStr.append(m_textStr.cbegin() + m_selectionStart + m_selectionCount, m_textStr.cend());
|
||||||
|
setText(newStr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string newStr(m_textStr.cbegin(), m_textStr.cbegin() + m_cursorPos);
|
||||||
|
utf8proc_uint8_t theChar[5] = {};
|
||||||
|
utf8proc_ssize_t sz = utf8proc_encode_char(charCode, theChar);
|
||||||
|
if (sz > 0)
|
||||||
|
newStr += (char*)theChar;
|
||||||
|
newStr.append(m_textStr.cbegin() + m_cursorPos, m_textStr.cend());
|
||||||
|
setText(newStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextField::specialKeyDown(boo::ESpecialKey key, boo::EModifierKey mods, bool isRepeat)
|
||||||
|
{
|
||||||
|
if (key == boo::ESpecialKey::Left)
|
||||||
|
{
|
||||||
|
if (m_selectionCount)
|
||||||
|
m_cursorPos = m_selectionStart;
|
||||||
|
setCursorPos(m_cursorPos==0 ? 0 : (m_cursorPos-1));
|
||||||
|
}
|
||||||
|
else if (key == boo::ESpecialKey::Right)
|
||||||
|
{
|
||||||
|
if (m_selectionCount)
|
||||||
|
m_cursorPos = m_selectionStart + m_selectionCount - 1;
|
||||||
|
setCursorPos(m_cursorPos+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextField::think()
|
||||||
|
{
|
||||||
|
++m_cursorFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextField::setActive(bool active)
|
||||||
|
{
|
||||||
|
m_active = active;
|
||||||
|
if (!active)
|
||||||
|
clearSelectionRange();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextField::setCursorPos(size_t pos)
|
||||||
|
{
|
||||||
|
clearSelectionRange();
|
||||||
|
m_cursorPos = std::min(pos, m_textStr.size());
|
||||||
|
m_cursorFrames = 0;
|
||||||
|
|
||||||
|
float pf = rootView().viewRes().pixelFactor();
|
||||||
|
int offset1 = 4 * pf + m_text->queryReverseAdvance(m_cursorPos);
|
||||||
|
int offset2 = offset1 + 2 * pf;
|
||||||
|
m_verts[28].m_pos.assign(offset1, 18 * pf, 0);
|
||||||
|
m_verts[29].m_pos.assign(offset1, 4 * pf, 0);
|
||||||
|
m_verts[30].m_pos.assign(offset2, 18 * pf, 0);
|
||||||
|
m_verts[31].m_pos.assign(offset2, 4 * pf, 0);
|
||||||
|
m_bVertsBuf->load(m_verts, sizeof(m_verts));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextField::setSelectionRange(size_t start, size_t count)
|
||||||
|
{
|
||||||
|
m_selectionStart = std::min(start, m_textStr.size()-1);
|
||||||
|
m_selectionCount = std::min(count, m_textStr.size()-m_selectionStart);
|
||||||
|
|
||||||
|
ViewResources& res = rootView().viewRes();
|
||||||
|
float pf = res.pixelFactor();
|
||||||
|
int offset1 = 5 * pf;
|
||||||
|
int offset2 = offset1;
|
||||||
|
std::vector<TextView::RenderGlyph>& glyphs = m_text->accessGlyphs();
|
||||||
|
offset1 += glyphs[m_selectionStart].m_pos[0][0];
|
||||||
|
offset2 += glyphs[m_selectionStart+m_selectionCount-1].m_pos[2][0];
|
||||||
|
for (size_t i=0 ; i<glyphs.size() ; ++i)
|
||||||
|
{
|
||||||
|
if (i >= m_selectionStart && i< m_selectionStart + m_selectionCount)
|
||||||
|
glyphs[i].m_color = rootView().themeData().selectedFieldText();
|
||||||
|
else
|
||||||
|
glyphs[i].m_color = rootView().themeData().fieldText();
|
||||||
|
}
|
||||||
|
m_text->updateGlyphs();
|
||||||
|
|
||||||
|
m_verts[28].m_pos.assign(offset1, 18 * pf, 0);
|
||||||
|
m_verts[29].m_pos.assign(offset1, 4 * pf, 0);
|
||||||
|
m_verts[30].m_pos.assign(offset2, 18 * pf, 0);
|
||||||
|
m_verts[31].m_pos.assign(offset2, 4 * pf, 0);
|
||||||
|
m_bVertsBuf->load(m_verts, sizeof(m_verts));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextField::clearSelectionRange()
|
||||||
|
{
|
||||||
|
m_selectionStart = 0;
|
||||||
|
m_selectionCount = 0;
|
||||||
|
|
||||||
|
std::vector<TextView::RenderGlyph>& glyphs = m_text->accessGlyphs();
|
||||||
|
for (size_t i=0 ; i<glyphs.size() ; ++i)
|
||||||
|
glyphs[i].m_color = rootView().themeData().fieldText();
|
||||||
|
m_text->updateGlyphs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextField::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
|
void TextField::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
|
||||||
|
@ -146,7 +270,7 @@ void TextField::resized(const boo::SWindowRect& root, const boo::SWindowRect& su
|
||||||
m_verts[26].m_pos.assign(width+1, 1, 0);
|
m_verts[26].m_pos.assign(width+1, 1, 0);
|
||||||
m_verts[27].m_pos.assign(width+1, 0, 0);
|
m_verts[27].m_pos.assign(width+1, 0, 0);
|
||||||
|
|
||||||
m_bVertsBuf->load(m_verts, sizeof(SolidShaderVert) * 28);
|
m_bVertsBuf->load(m_verts, sizeof(m_verts));
|
||||||
|
|
||||||
m_nomWidth = width;
|
m_nomWidth = width;
|
||||||
m_nomHeight = height;
|
m_nomHeight = height;
|
||||||
|
@ -163,6 +287,16 @@ void TextField::draw(boo::IGraphicsCommandQueue* gfxQ)
|
||||||
gfxQ->setShaderDataBinding(m_bShaderBinding);
|
gfxQ->setShaderDataBinding(m_bShaderBinding);
|
||||||
gfxQ->setDrawPrimitive(boo::Primitive::TriStrips);
|
gfxQ->setDrawPrimitive(boo::Primitive::TriStrips);
|
||||||
gfxQ->draw(0, 28);
|
gfxQ->draw(0, 28);
|
||||||
|
if (m_active)
|
||||||
|
{
|
||||||
|
if (!m_selectionCount)
|
||||||
|
{
|
||||||
|
if (m_cursorFrames % 60 < 30)
|
||||||
|
gfxQ->draw(28, 4);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gfxQ->draw(28, 4);
|
||||||
|
}
|
||||||
m_text->draw(gfxQ);
|
m_text->draw(gfxQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -355,6 +355,8 @@ void TextView::typesetGlyphs(const std::string& str, const Zeus::CColor& default
|
||||||
m_glyphs.reserve(str.size());
|
m_glyphs.reserve(str.size());
|
||||||
m_glyphDims.clear();
|
m_glyphDims.clear();
|
||||||
m_glyphDims.reserve(str.size());
|
m_glyphDims.reserve(str.size());
|
||||||
|
m_glyphAdvs.clear();
|
||||||
|
m_glyphAdvs.reserve(str.size());
|
||||||
int adv = 0;
|
int adv = 0;
|
||||||
|
|
||||||
while (rem)
|
while (rem)
|
||||||
|
@ -378,6 +380,7 @@ void TextView::typesetGlyphs(const std::string& str, const Zeus::CColor& default
|
||||||
adv += DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas);
|
adv += DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas);
|
||||||
m_glyphs.emplace_back(adv, *glyph, defaultColor);
|
m_glyphs.emplace_back(adv, *glyph, defaultColor);
|
||||||
m_glyphDims.emplace_back(glyph->m_width, glyph->m_height);
|
m_glyphDims.emplace_back(glyph->m_width, glyph->m_height);
|
||||||
|
m_glyphAdvs.push_back(adv);
|
||||||
|
|
||||||
lCh = glyph->m_glyphIdx;
|
lCh = glyph->m_glyphIdx;
|
||||||
rem -= sz;
|
rem -= sz;
|
||||||
|
@ -422,6 +425,8 @@ void TextView::typesetGlyphs(const std::wstring& str, const Zeus::CColor& defaul
|
||||||
m_glyphs.reserve(str.size());
|
m_glyphs.reserve(str.size());
|
||||||
m_glyphDims.clear();
|
m_glyphDims.clear();
|
||||||
m_glyphDims.reserve(str.size());
|
m_glyphDims.reserve(str.size());
|
||||||
|
m_glyphAdvs.clear();
|
||||||
|
m_glyphAdvs.reserve(str.size());
|
||||||
int adv = 0;
|
int adv = 0;
|
||||||
|
|
||||||
for (wchar_t ch : str)
|
for (wchar_t ch : str)
|
||||||
|
@ -437,6 +442,7 @@ void TextView::typesetGlyphs(const std::wstring& str, const Zeus::CColor& defaul
|
||||||
adv += DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas);
|
adv += DoKern(m_fontAtlas.lookupKern(lCh, glyph->m_glyphIdx), m_fontAtlas);
|
||||||
m_glyphs.emplace_back(adv, *glyph, defaultColor);
|
m_glyphs.emplace_back(adv, *glyph, defaultColor);
|
||||||
m_glyphDims.emplace_back(glyph->m_width, glyph->m_height);
|
m_glyphDims.emplace_back(glyph->m_width, glyph->m_height);
|
||||||
|
m_glyphAdvs.push_back(adv);
|
||||||
|
|
||||||
lCh = glyph->m_glyphIdx;
|
lCh = glyph->m_glyphIdx;
|
||||||
|
|
||||||
|
@ -516,5 +522,32 @@ std::pair<int,int> TextView::queryGlyphDimensions(size_t pos) const
|
||||||
return m_glyphDims[pos];
|
return m_glyphDims[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t TextView::reverseSelectGlyph(int x) const
|
||||||
|
{
|
||||||
|
size_t ret = 0;
|
||||||
|
size_t idx = 1;
|
||||||
|
int minDelta = abs(x);
|
||||||
|
for (int adv : m_glyphAdvs)
|
||||||
|
{
|
||||||
|
int thisDelta = abs(adv-x);
|
||||||
|
if (thisDelta < minDelta)
|
||||||
|
{
|
||||||
|
minDelta = thisDelta;
|
||||||
|
ret = idx;
|
||||||
|
}
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TextView::queryReverseAdvance(size_t idx) const
|
||||||
|
{
|
||||||
|
if (idx > m_glyphAdvs.size())
|
||||||
|
Log.report(LogVisor::FatalError,
|
||||||
|
"TextView::queryReverseGlyph(%" PRISize ") out of inclusive bounds: %" PRISize,
|
||||||
|
idx, m_glyphAdvs.size());
|
||||||
|
if (!idx) return 0;
|
||||||
|
return m_glyphAdvs[idx-1];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue