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 mouseEnter(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 think();
|
||||
void draw(boo::IGraphicsCommandQueue* gfxQ);
|
||||
};
|
||||
|
||||
|
|
|
@ -23,8 +23,7 @@ class ModalWindow : public View
|
|||
|
||||
int m_width = 0;
|
||||
int m_height = 0;
|
||||
int m_widthConstrain;
|
||||
int m_heightConstrain;
|
||||
RectangleConstraint m_constraint;
|
||||
|
||||
Zeus::CColor m_windowBg;
|
||||
Zeus::CColor m_windowBgClear;
|
||||
|
@ -57,7 +56,7 @@ protected:
|
|||
virtual void updateContentOpacity(float opacity) {}
|
||||
|
||||
public:
|
||||
ModalWindow(ViewResources& res, View& parentView, int widthConstrain=-1, int heightConstrain=-1);
|
||||
ModalWindow(ViewResources& res, View& parentView, const RectangleConstraint& constraint);
|
||||
void think();
|
||||
bool skipBuildInAnimation();
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "View.hpp"
|
||||
#include "ViewResources.hpp"
|
||||
#include "MultiLineTextView.hpp"
|
||||
#include "TextField.hpp"
|
||||
#include "SplitView.hpp"
|
||||
#include "Tooltip.hpp"
|
||||
#include "FontCache.hpp"
|
||||
|
@ -26,6 +27,7 @@ class RootView : public View
|
|||
bool m_destroyed = false;
|
||||
IViewManager& m_viewMan;
|
||||
ViewResources* m_viewRes;
|
||||
View* m_activeTextView = nullptr;
|
||||
|
||||
DeferredWindowEvents<RootView> m_events;
|
||||
|
||||
|
@ -64,6 +66,13 @@ public:
|
|||
const ThemeData& themeData() const {return m_viewRes->m_theme;}
|
||||
|
||||
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 displayTooltip(const std::string& name, const std::string& help);
|
||||
|
|
|
@ -12,7 +12,7 @@ class TextField : public Control
|
|||
std::string m_textStr;
|
||||
std::unique_ptr<TextView> m_text;
|
||||
|
||||
SolidShaderVert m_verts[28];
|
||||
SolidShaderVert m_verts[32];
|
||||
boo::IGraphicsBufferD* m_bVertsBuf = nullptr;
|
||||
boo::IVertexFormat* m_bVtxFmt = nullptr; /* OpenGL only */
|
||||
boo::IShaderDataBinding* m_bShaderBinding = nullptr;
|
||||
|
@ -20,6 +20,13 @@ class TextField : public Control
|
|||
int m_nomWidth = 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 setHover();
|
||||
void setDisabled();
|
||||
|
@ -27,19 +34,29 @@ class TextField : public Control
|
|||
public:
|
||||
TextField(ViewResources& res, View& parentView, IStringBinding* strBind);
|
||||
|
||||
const std::string& getText() const {return m_textStr;}
|
||||
void setText(const std::string& str);
|
||||
|
||||
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&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 draw(boo::IGraphicsCommandQueue* gfxQ);
|
||||
|
||||
int nominalWidth() const {return m_nomWidth;}
|
||||
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)
|
||||
{
|
||||
View::setMultiplyColor(color);
|
||||
|
|
|
@ -67,6 +67,7 @@ public:
|
|||
RenderGlyph(int& adv, const FontAtlas::Glyph& glyph, const Zeus::CColor& defaultColor);
|
||||
};
|
||||
std::vector<RenderGlyph>& accessGlyphs() {return m_glyphs;}
|
||||
const std::vector<RenderGlyph>& accessGlyphs() const {return m_glyphs;}
|
||||
void updateGlyphs() {m_valid = false;}
|
||||
|
||||
void typesetGlyphs(const std::string& str,
|
||||
|
@ -85,10 +86,13 @@ public:
|
|||
int nominalHeight() const {return m_fontAtlas.FT_LineHeight() >> 6;}
|
||||
|
||||
std::pair<int,int> queryGlyphDimensions(size_t pos) const;
|
||||
size_t reverseSelectGlyph(int x) const;
|
||||
int queryReverseAdvance(size_t idx) const;
|
||||
|
||||
private:
|
||||
std::vector<RenderGlyph> m_glyphs;
|
||||
std::vector<std::pair<int,int>> m_glyphDims;
|
||||
std::vector<int> m_glyphAdvs;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,65 @@ class ThemeData;
|
|||
class ViewResources;
|
||||
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
|
||||
{
|
||||
public:
|
||||
|
@ -127,13 +186,26 @@ public:
|
|||
virtual int nominalWidth() 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 mouseUp(const boo::SWindowCoord&, boo::EMouseButton, boo::EModifierKey) {}
|
||||
virtual void mouseMove(const boo::SWindowCoord&) {}
|
||||
virtual void mouseEnter(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 think() {}
|
||||
virtual void draw(boo::IGraphicsCommandQueue* gfxQ);
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ class ThemeData
|
|||
{
|
||||
Zeus::CColor m_uiText = Zeus::CColor::skWhite;
|
||||
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_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_textfield2Disabled = {0.7823, 0.7823, 0.7823, 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:
|
||||
virtual const Zeus::CColor& uiText() const {return m_uiText;}
|
||||
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& toolbarBackground() const {return m_tbBg;}
|
||||
|
@ -66,6 +69,7 @@ public:
|
|||
virtual const Zeus::CColor& textfield2Hover() const {return m_textfield2Hover;}
|
||||
virtual const Zeus::CColor& textfield1Disabled() const {return m_textfield1Disabled;}
|
||||
virtual const Zeus::CColor& textfield2Disabled() const {return m_textfield2Disabled;}
|
||||
virtual const Zeus::CColor& textfieldSelection() const {return m_textfieldSelection;}
|
||||
};
|
||||
|
||||
class ViewResources
|
||||
|
|
|
@ -5,8 +5,8 @@ namespace Specter
|
|||
{
|
||||
|
||||
#define BROWSER_MARGIN 30
|
||||
#define BROWSER_MIN_WIDTH 100
|
||||
#define BROWSER_MIN_HEIGHT 100
|
||||
#define BROWSER_MIN_WIDTH 600
|
||||
#define BROWSER_MIN_HEIGHT 300
|
||||
|
||||
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)
|
||||
: 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_fileFieldBind(*this)
|
||||
{
|
||||
|
@ -102,20 +105,34 @@ void FileBrowser::mouseLeave(const boo::SWindowCoord& 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)
|
||||
{
|
||||
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);
|
||||
boo::SWindowRect centerRect = subRect();
|
||||
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;
|
||||
pathRect.location[0] += 25 * pf;
|
||||
pathRect.location[1] += pathRect.size[1] - 50 * pf;
|
||||
for (PathButton& b : m_pathButtons)
|
||||
{
|
||||
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] = centerRect.location[0] + 10 * pf;
|
||||
pathRect.location[0] = centerRect.location[0] + 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();
|
||||
m_fileField.m_view->resized(root, pathRect);
|
||||
}
|
||||
|
||||
void FileBrowser::think()
|
||||
{
|
||||
ModalWindow::think();
|
||||
m_fileField.m_view->think();
|
||||
}
|
||||
|
||||
void FileBrowser::draw(boo::IGraphicsCommandQueue* gfxQ)
|
||||
{
|
||||
ModalWindow::draw(gfxQ);
|
||||
|
|
|
@ -168,10 +168,9 @@ void ModalWindow::setFillColors(float t)
|
|||
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),
|
||||
m_widthConstrain(widthConstrain),
|
||||
m_heightConstrain(heightConstrain),
|
||||
m_constraint(constraint),
|
||||
m_windowBg(res.themeData().splashBackground()),
|
||||
m_windowBgClear(m_windowBg),
|
||||
m_line1(res.themeData().splash1()),
|
||||
|
@ -302,10 +301,10 @@ void ModalWindow::resized(const boo::SWindowRect& root, const boo::SWindowRect&
|
|||
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));
|
||||
std::pair<int,int> constrained = m_constraint.solve(root.size[0] - CONTENT_MARGIN * pf * 2,
|
||||
root.size[1] - CONTENT_MARGIN * pf * 2);
|
||||
m_width = std::max(constrained.first, int(WINDOW_MIN_DIM * pf));
|
||||
m_height = std::max(constrained.second, 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;
|
||||
|
|
|
@ -80,44 +80,79 @@ void RootView::mouseLeave(const boo::SWindowCoord& coord)
|
|||
|
||||
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)
|
||||
{
|
||||
if (m_view)
|
||||
m_view->touchDown(coord, 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)
|
||||
{
|
||||
if (m_view)
|
||||
m_view->touchMove(coord, tid);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (key == boo::ESpecialKey::Enter && (mods & boo::EModifierKey::Alt) != boo::EModifierKey::None)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (m_view)
|
||||
m_view->specialKeyUp(key, mods);
|
||||
if (m_activeTextView)
|
||||
m_activeTextView->specialKeyUp(key, mods);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (m_view)
|
||||
m_view->modKeyUp(mod);
|
||||
if (m_activeTextView)
|
||||
m_activeTextView->modKeyUp(mod);
|
||||
}
|
||||
|
||||
View* RootView::setContentView(View* view)
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Specter
|
|||
TextField::TextField(ViewResources& res, View& parentView, IStringBinding* 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)
|
||||
{
|
||||
|
@ -40,7 +40,9 @@ TextField::TextField(ViewResources& res, View& parentView, IStringBinding* strBi
|
|||
m_verts[4].m_color = rootView().themeData().textfield2Inactive();
|
||||
for (int i=5 ; i<28 ; ++i)
|
||||
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));
|
||||
setText("Test");
|
||||
|
@ -48,8 +50,13 @@ TextField::TextField(ViewResources& res, View& parentView, IStringBinding* strBi
|
|||
|
||||
void TextField::setText(const std::string& str)
|
||||
{
|
||||
m_textStr = str;
|
||||
m_text->typesetGlyphs(str, rootView().themeData().fieldText());
|
||||
clearSelectionRange();
|
||||
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()
|
||||
|
@ -59,7 +66,7 @@ void TextField::setInactive()
|
|||
m_verts[2].m_color = rootView().themeData().textfield1Inactive();
|
||||
m_verts[3].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()
|
||||
|
@ -69,7 +76,7 @@ void TextField::setHover()
|
|||
m_verts[2].m_color = rootView().themeData().textfield1Hover();
|
||||
m_verts[3].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()
|
||||
|
@ -79,11 +86,19 @@ void TextField::setDisabled()
|
|||
m_verts[2].m_color = rootView().themeData().textfield1Disabled();
|
||||
m_verts[3].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)
|
||||
{
|
||||
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)
|
||||
|
@ -97,11 +112,120 @@ void TextField::mouseMove(const boo::SWindowCoord& coord)
|
|||
void TextField::mouseEnter(const boo::SWindowCoord& coord)
|
||||
{
|
||||
setHover();
|
||||
rootView().window()->setCursor(boo::EMouseCursor::IBeam);
|
||||
}
|
||||
|
||||
void TextField::mouseLeave(const boo::SWindowCoord& coord)
|
||||
{
|
||||
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)
|
||||
|
@ -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[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_nomHeight = height;
|
||||
|
@ -163,6 +287,16 @@ void TextField::draw(boo::IGraphicsCommandQueue* gfxQ)
|
|||
gfxQ->setShaderDataBinding(m_bShaderBinding);
|
||||
gfxQ->setDrawPrimitive(boo::Primitive::TriStrips);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -355,6 +355,8 @@ void TextView::typesetGlyphs(const std::string& str, const Zeus::CColor& default
|
|||
m_glyphs.reserve(str.size());
|
||||
m_glyphDims.clear();
|
||||
m_glyphDims.reserve(str.size());
|
||||
m_glyphAdvs.clear();
|
||||
m_glyphAdvs.reserve(str.size());
|
||||
int adv = 0;
|
||||
|
||||
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);
|
||||
m_glyphs.emplace_back(adv, *glyph, defaultColor);
|
||||
m_glyphDims.emplace_back(glyph->m_width, glyph->m_height);
|
||||
m_glyphAdvs.push_back(adv);
|
||||
|
||||
lCh = glyph->m_glyphIdx;
|
||||
rem -= sz;
|
||||
|
@ -422,6 +425,8 @@ void TextView::typesetGlyphs(const std::wstring& str, const Zeus::CColor& defaul
|
|||
m_glyphs.reserve(str.size());
|
||||
m_glyphDims.clear();
|
||||
m_glyphDims.reserve(str.size());
|
||||
m_glyphAdvs.clear();
|
||||
m_glyphAdvs.reserve(str.size());
|
||||
int adv = 0;
|
||||
|
||||
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);
|
||||
m_glyphs.emplace_back(adv, *glyph, defaultColor);
|
||||
m_glyphDims.emplace_back(glyph->m_width, glyph->m_height);
|
||||
m_glyphAdvs.push_back(adv);
|
||||
|
||||
lCh = glyph->m_glyphIdx;
|
||||
|
||||
|
@ -516,5 +522,32 @@ std::pair<int,int> TextView::queryGlyphDimensions(size_t pos) const
|
|||
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