GUI: cursor in textbox
This commit is contained in:
parent
7ab45ce6ba
commit
b8465e682a
11 changed files with 246 additions and 4 deletions
|
@ -97,6 +97,7 @@
|
|||
<ClInclude Include="..\..\src\gui\controls\text_box.h" />
|
||||
<ClInclude Include="..\..\src\gui\decorators\box_decorator.h" />
|
||||
<ClInclude Include="..\..\src\gui\decorators\check_box_decorator.h" />
|
||||
<ClInclude Include="..\..\src\gui\decorators\cursor_decorator.h" />
|
||||
<ClInclude Include="..\..\src\gui\decorators\dockable_decorator.h" />
|
||||
<ClInclude Include="..\..\src\gui\decorators\scrollbar_decorator.h" />
|
||||
<ClInclude Include="..\..\src\gui\decorators\text_decorator.h" />
|
||||
|
@ -121,6 +122,7 @@
|
|||
<ClCompile Include="..\..\src\gui\controls\text_box.cpp" />
|
||||
<ClCompile Include="..\..\src\gui\decorators\box_decorator.cpp" />
|
||||
<ClCompile Include="..\..\src\gui\decorators\check_box_decorator.cpp" />
|
||||
<ClCompile Include="..\..\src\gui\decorators\cursor_decorator.cpp" />
|
||||
<ClCompile Include="..\..\src\gui\decorators\dockable_decorator.cpp" />
|
||||
<ClCompile Include="..\..\src\gui\decorators\scrollbar_decorator.cpp" />
|
||||
<ClCompile Include="..\..\src\gui\decorators\text_decorator.cpp" />
|
||||
|
|
|
@ -50,6 +50,9 @@
|
|||
<ClInclude Include="..\..\src\gui\decorators\dockable_decorator.h">
|
||||
<Filter>decorators</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\gui\decorators\cursor_decorator.h">
|
||||
<Filter>decorators</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\src\gui\gui.cpp" />
|
||||
|
@ -98,6 +101,9 @@
|
|||
<ClCompile Include="..\..\src\gui\decorators\dockable_decorator.cpp">
|
||||
<Filter>decorators</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\gui\decorators\cursor_decorator.cpp">
|
||||
<Filter>decorators</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="decorators">
|
||||
|
|
|
@ -167,6 +167,15 @@ class base_string
|
|||
return ret;
|
||||
}
|
||||
|
||||
void erase(size_t pos)
|
||||
{
|
||||
if(pos >= 0 && pos < m_size)
|
||||
{
|
||||
base_string<T>::strcpy(m_cstr + pos, m_cstr + pos + 1);
|
||||
--m_size;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static const int npos = 0xffFFffFF;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "graphics/renderer.h"
|
||||
#include "gui/block.h"
|
||||
#include "gui/decorators/box_decorator.h"
|
||||
#include "gui/decorators/cursor_decorator.h"
|
||||
#include "gui/decorators/check_box_decorator.h"
|
||||
#include "gui/decorators/dockable_decorator.h"
|
||||
#include "gui/decorators/text_decorator.h"
|
||||
|
@ -30,6 +31,7 @@ void initGui(Lux::EditorClient& client, Lux::EditorServer& server)
|
|||
renderer->create();
|
||||
renderer->loadFont("gui/font.tga", server.getEngine().getFileSystem());
|
||||
renderer->setWindowHeight(600);
|
||||
Lux::UI::CursorDecorator* cursor_decorator = LUX_NEW(Lux::UI::CursorDecorator)("_cursor");
|
||||
Lux::UI::CheckBoxDecorator* check_box_decorator = LUX_NEW(Lux::UI::CheckBoxDecorator)("_check_box");
|
||||
Lux::UI::TextDecorator* text_decorator = LUX_NEW(Lux::UI::TextDecorator)("_text");
|
||||
Lux::UI::TextDecorator* text_centered_decorator = LUX_NEW(Lux::UI::TextDecorator)("_text_centered");
|
||||
|
@ -39,6 +41,7 @@ void initGui(Lux::EditorClient& client, Lux::EditorServer& server)
|
|||
Lux::UI::ScrollbarDecorator* scrollbar_decorator = LUX_NEW(Lux::UI::ScrollbarDecorator)("_scrollbar");
|
||||
server.getEngine().loadPlugin("gui.dll");
|
||||
Lux::UI::Gui* gui = (Lux::UI::Gui*)server.getEngine().getPluginManager().getPlugin("gui");
|
||||
gui->addDecorator(*cursor_decorator);
|
||||
gui->addDecorator(*text_decorator);
|
||||
gui->addDecorator(*text_centered_decorator);
|
||||
gui->addDecorator(*box_decorator);
|
||||
|
@ -46,6 +49,7 @@ void initGui(Lux::EditorClient& client, Lux::EditorServer& server)
|
|||
gui->addDecorator(*scrollbar_decorator);
|
||||
gui->addDecorator(*check_box_decorator);
|
||||
gui->setRenderer(*renderer);
|
||||
cursor_decorator->create(*gui, "gui/skin.atl");
|
||||
check_box_decorator->create(*gui, "gui/skin.atl");
|
||||
scrollbar_decorator->create(*gui, "gui/skin.atl");
|
||||
box_decorator->create(*gui, "gui/skin.atl");
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "gui/controls/text_box.h"
|
||||
#include "core/crc32.h"
|
||||
#include "core/iserializer.h"
|
||||
#include "gui/gui.h"
|
||||
|
||||
|
||||
namespace Lux
|
||||
|
@ -17,29 +18,77 @@ TextBox::TextBox(const char* text, Gui& gui, Block* parent)
|
|||
label_ui->setBlockText(text);
|
||||
label_ui->setArea(0, 3, 0, 0, 1, 0, 1, 0);
|
||||
label_ui->onEvent("key_down").bind<TextBox, &TextBox::keyDown>(this);
|
||||
label_ui->onEvent("focus").bind<TextBox, &TextBox::focused>(this);
|
||||
label_ui->onEvent("blur").bind<TextBox, &TextBox::blurred>(this);
|
||||
label_ui->setIsClipping(true);
|
||||
m_cursor_pos = 0;
|
||||
m_cursor = LUX_NEW(Block)(gui, label_ui, "_cursor");
|
||||
m_cursor->hide();
|
||||
}
|
||||
|
||||
|
||||
void TextBox::setCursorArea()
|
||||
{
|
||||
Block::Area area = getGui().getRenderer().getCharArea(getChild(0)->getBlockText().c_str(), m_cursor_pos, getGlobalWidth());
|
||||
m_cursor->setArea(area);
|
||||
layout();
|
||||
}
|
||||
|
||||
|
||||
void TextBox::blurred(Block& block, void* user_data)
|
||||
{
|
||||
m_cursor->hide();
|
||||
}
|
||||
|
||||
|
||||
void TextBox::focused(Block& block, void* user_data)
|
||||
{
|
||||
m_cursor_pos = getChild(0)->getBlockText().length();
|
||||
m_cursor->show();
|
||||
setCursorArea();
|
||||
}
|
||||
|
||||
static const int32_t KEY_RIGHT = 79 + (1 << 30);
|
||||
static const int32_t KEY_LEFT = 80 + (1 << 30);
|
||||
static const int32_t KEY_UP = 81 + (1 << 30);
|
||||
static const int32_t KEY_DOWN = 82 + (1 << 30);
|
||||
static const int32_t KEY_BACKSPACE = '\b';
|
||||
static const int32_t KEY_DELETE = '\177';
|
||||
|
||||
void TextBox::keyDown(Block& block, void* user_data)
|
||||
{
|
||||
Lux::string s = block.getBlockText();
|
||||
char c[2];
|
||||
switch((int32_t)user_data)
|
||||
{
|
||||
case KEY_RIGHT:
|
||||
m_cursor_pos = m_cursor_pos > s.length() - 1 ? s.length() : m_cursor_pos + 1;
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
m_cursor_pos = m_cursor_pos < 1 ? 0 : m_cursor_pos - 1;
|
||||
break;
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
break;
|
||||
case '\r':
|
||||
block.emitEvent("text_accepted");
|
||||
break;
|
||||
case '\b':
|
||||
s = s.substr(0, s.length() - 1);
|
||||
case KEY_BACKSPACE:
|
||||
s.erase(m_cursor_pos - 1);
|
||||
if(m_cursor_pos > 0)
|
||||
{
|
||||
--m_cursor_pos;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
c[0] = (char)user_data;
|
||||
c[1] = '\0';
|
||||
s += c;
|
||||
++m_cursor_pos;
|
||||
break;
|
||||
}
|
||||
block.setBlockText(s.c_str());
|
||||
setCursorArea();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,13 @@ namespace UI
|
|||
|
||||
private:
|
||||
void keyDown(Block& block, void* user_data);
|
||||
void focused(Block& block, void* user_data);
|
||||
void blurred(Block& block, void* user_data);
|
||||
void setCursorArea();
|
||||
|
||||
private:
|
||||
int m_cursor_pos;
|
||||
Lux::UI::Block* m_cursor;
|
||||
};
|
||||
|
||||
|
||||
|
|
54
src/gui/decorators/cursor_decorator.cpp
Normal file
54
src/gui/decorators/cursor_decorator.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include "gui/decorators/cursor_decorator.h"
|
||||
#include "core/crc32.h"
|
||||
#include "gui/atlas.h"
|
||||
#include "gui/block.h"
|
||||
#include "gui/controls/dockable.h"
|
||||
#include "gui/gui.h"
|
||||
#include "gui/irenderer.h"
|
||||
#include "gui/texture_base.h"
|
||||
|
||||
|
||||
namespace Lux
|
||||
{
|
||||
namespace UI
|
||||
{
|
||||
|
||||
static const uint32_t dockable_hash = crc32("dockable");
|
||||
|
||||
void CursorDecorator::setVertices(Vec3* verts, float left, float top, float right, float bottom, float z) const
|
||||
{
|
||||
verts[0].set(left, top, z);
|
||||
verts[1].set(left, bottom, z);
|
||||
verts[2].set(right, bottom, z);
|
||||
verts[3].set(left, top, z);
|
||||
verts[4].set(right, bottom, z);
|
||||
verts[5].set(right, top, z);
|
||||
}
|
||||
|
||||
|
||||
void CursorDecorator::render(IRenderer& renderer, Block& block)
|
||||
{
|
||||
m_part = m_part ? m_part : m_atlas->getPart("cursor");
|
||||
|
||||
if(m_part)
|
||||
{
|
||||
setVertices(m_vertices, block.getGlobalLeft(), block.getGlobalTop(), block.getGlobalLeft() + m_part->m_pixel_width, block.getGlobalBottom(), block.getZ());
|
||||
m_part->getUvs(&m_uvs[0]);
|
||||
if(m_atlas->getTexture())
|
||||
{
|
||||
renderer.renderImage(m_atlas->getTexture(), &m_vertices[0].x, m_uvs, 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool CursorDecorator::create(Gui& gui, const char* atlas)
|
||||
{
|
||||
m_part = NULL;
|
||||
m_atlas = gui.loadAtlas(atlas);
|
||||
return m_atlas != NULL;
|
||||
}
|
||||
|
||||
|
||||
} // ~namespace UI
|
||||
} // ~namespace Lux
|
40
src/gui/decorators/cursor_decorator.h
Normal file
40
src/gui/decorators/cursor_decorator.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
|
||||
#include "core/lux.h"
|
||||
#include "core/vec3.h"
|
||||
#include "gui/atlas.h"
|
||||
#include "gui/decorator_base.h"
|
||||
|
||||
|
||||
namespace Lux
|
||||
{
|
||||
namespace UI
|
||||
{
|
||||
|
||||
class Dockable;
|
||||
class Gui;
|
||||
class IRenderer;
|
||||
class TextureBase;
|
||||
|
||||
|
||||
class LUX_GUI_API CursorDecorator : public DecoratorBase
|
||||
{
|
||||
public:
|
||||
CursorDecorator(const char* name) : DecoratorBase(name) {}
|
||||
|
||||
bool create(Gui& gui, const char* atlas);
|
||||
virtual void render(IRenderer& renderer, Block& block) LUX_OVERRIDE;
|
||||
|
||||
private:
|
||||
void setVertices(Vec3* verts, float left, float top, float right, float bottom, float z) const;
|
||||
|
||||
private:
|
||||
Atlas* m_atlas;
|
||||
const Atlas::Part* m_part;
|
||||
Vec3 m_vertices[24];
|
||||
float m_uvs[48];
|
||||
};
|
||||
|
||||
} // ~namespace UI
|
||||
} // ~namespace Lux
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
|
||||
#include "core/lux.h"
|
||||
#include "gui/block.h"
|
||||
|
||||
|
||||
namespace Lux
|
||||
|
@ -26,6 +27,7 @@ namespace UI
|
|||
virtual TextureBase* loadImage(const char* name, FS::FileSystem& file_system) = 0;
|
||||
virtual void beginRender(float w, float h) = 0;
|
||||
virtual void renderImage(TextureBase* image, float* vertices, float* tex_coords, int vertex_count) = 0;
|
||||
virtual Block::Area getCharArea(const char* text, int pos, float max_width) = 0;
|
||||
virtual void measureText(const char* text, float* w, float* h, float max_width) = 0;
|
||||
virtual void renderText(const char* text, float x, float y, float z, float max_width) = 0;
|
||||
virtual void pushScissorArea(float left, float top, float right, float bottom) = 0;
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
#include "gui/opengl_renderer.h"
|
||||
#include <cstdio>
|
||||
#include <Windows.h>
|
||||
#include <gl/GL.h>
|
||||
#include "gui/opengl_renderer.h"
|
||||
#include "core/array.h"
|
||||
#include "core/delegate_list.h"
|
||||
#include "core/file_system.h"
|
||||
#include "core/ifile.h"
|
||||
#include "core/map.h"
|
||||
#include "core/math_utils.h"
|
||||
#include "core/pod_array.h"
|
||||
#include "core/string.h"
|
||||
#include "core/vec3.h"
|
||||
|
@ -221,6 +222,73 @@ namespace UI
|
|||
glLoadIdentity();
|
||||
}
|
||||
|
||||
Block::Area OpenGLRenderer::getCharArea(const char* text, int pos, float max_width)
|
||||
{
|
||||
Block::Area area;
|
||||
if(text)
|
||||
{
|
||||
float width = 0;
|
||||
float height = 0;
|
||||
float prev_h = 0;
|
||||
const char* c = text;
|
||||
bool is_multiline = false;
|
||||
OpenGLRendererImpl::Character character;
|
||||
bool found = false;
|
||||
bool is_some_char = false;
|
||||
while(*c)
|
||||
{
|
||||
if(m_impl->m_characters.find(*c, character))
|
||||
{
|
||||
is_some_char = true;
|
||||
if(c - text == pos)
|
||||
{
|
||||
found = true;
|
||||
area.left = width;
|
||||
area.top = prev_h + character.y_offset;
|
||||
area.right = width + character.x_advance;
|
||||
area.bottom = prev_h + character.pixel_h + character.y_offset;
|
||||
area.rel_bottom = area.rel_left = area.rel_right = area.rel_top = 0;
|
||||
break;
|
||||
}
|
||||
width += character.x_advance;
|
||||
height = Math::max(height, character.pixel_h);
|
||||
if(width > max_width || *c == '\n')
|
||||
{
|
||||
is_multiline = true;
|
||||
width = 0;
|
||||
prev_h += height;
|
||||
}
|
||||
}
|
||||
else if(*c == '\n')
|
||||
{
|
||||
is_multiline = true;
|
||||
width = 0;
|
||||
prev_h += height;
|
||||
}
|
||||
++c;
|
||||
}
|
||||
if(!found)
|
||||
{
|
||||
if(is_some_char)
|
||||
{
|
||||
area.left = width;
|
||||
area.top = prev_h + character.y_offset;
|
||||
area.right = width + character.x_advance;
|
||||
area.bottom = prev_h + character.pixel_h + character.y_offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
area.left = 0;
|
||||
area.right = 3;
|
||||
area.top = 0;
|
||||
area.bottom = 20;
|
||||
}
|
||||
area.rel_bottom = area.rel_left = area.rel_right = area.rel_top = 0;
|
||||
}
|
||||
}
|
||||
return area;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::measureText(const char* text, float* w, float* h, float max_width)
|
||||
{
|
||||
if(!text)
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace UI
|
|||
virtual void loadFont(const char* path, FS::FileSystem& file_system) LUX_OVERRIDE;
|
||||
virtual void beginRender(float w, float h) LUX_OVERRIDE;
|
||||
virtual void renderImage(TextureBase* image, float* vertices, float* tex_coords, int vertex_count) LUX_OVERRIDE;
|
||||
virtual Block::Area getCharArea(const char* text, int pos, float max_width) LUX_OVERRIDE;
|
||||
virtual void measureText(const char* text, float* w, float* h, float max_width) LUX_OVERRIDE;
|
||||
virtual void renderText(const char* text, float x, float y, float z, float max_width) LUX_OVERRIDE;
|
||||
virtual void pushScissorArea(float left, float top, float right, float bottom) LUX_OVERRIDE;
|
||||
|
|
Loading…
Reference in a new issue