Merge pull request #71 from nem0/gui

additional GUI features and redirected error stream of script compiler
This commit is contained in:
tluqo 2014-01-04 04:07:15 -08:00
commit 0486cd4f8e
15 changed files with 320 additions and 22 deletions

View file

@ -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" />

View file

@ -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">

View file

@ -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;

View file

@ -4,12 +4,14 @@
#include "editor/server_message_types.h"
#include "editor_native/main_frame.h"
#include "gui/controls/scrollable.h"
#include "gui/gui.h"
LogUI::LogUI(MainFrame& main_frame)
: Dockable(main_frame.getGui(), NULL)
, m_main_frame(main_frame)
{
m_scrollable = NULL;
main_frame.getDockable().dock(*this, Dockable::BOTTOM);
main_frame.getEditorClient()->getEventManager().addListener(Lux::ServerMessageType::LOG_MESSAGE).bind<LogUI, &LogUI::onLogMessage>(this);
Lux::UI::Block* handle = LUX_NEW(Lux::UI::Block)(getGui(), this, "_box");
@ -30,7 +32,31 @@ void LogUI::onLogMessage(Lux::Event& evt)
cell->setArea(0, 0, 0, y, 0.3f, 0, 0, y + 20);
cell = LUX_NEW(Lux::UI::Block)(getGui(), container, "_text");
float w, h;
getGui().getRenderer().measureText(log_evt.message.c_str(), &w, &h, getGlobalWidth() * 0.7f);
cell->setBlockText(log_evt.message.c_str());
cell->setArea(0.3f, 0, 0, y, 1, 0, 0, y + 20);
cell->setArea(0.3f, 0, 0, y, 1, 0, 0, y + h + 5);
layout();
}
void LogUI::layout()
{
Dockable::layout();
if(m_scrollable)
{
Lux::UI::Block* container = m_scrollable->getContainer();
float w, h;
float y = 0;
for(int i = 1; i < container->getChildCount(); i += 2)
{
getGui().getRenderer().measureText(container->getChild(i)->getBlockText().c_str(), &w, &h, getGlobalWidth() * 0.7f);
container->getChild(i-1)->getLocalArea().top = y;
container->getChild(i)->getLocalArea().top = y;
y += h + 5;
}
Dockable::layout();
}
}

View file

@ -27,6 +27,7 @@ class LogUI : public Lux::UI::Dockable
{
public:
LogUI(MainFrame& main_frame);
virtual void layout() LUX_OVERRIDE;
private:
void onLogMessage(Lux::Event& evt);

View file

@ -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");

View file

@ -38,8 +38,9 @@ void ScriptCompiler::compile(const char path[])
CreatePipe(&read_pipe, &write_pipe, &saAttr, 0);
SetHandleInformation(read_pipe, HANDLE_FLAG_INHERIT, 0);
si.hStdInput = read_pipe;
//si.hStdInput = read_pipe;
si.hStdOutput = write_pipe;
si.hStdError = write_pipe;
si.dwFlags |= STARTF_USESTDHANDLES;
sprintf(cmd_line, "/C scripts\\compile.bat %s", path);
if ( CreateProcess("C:\\windows\\system32\\cmd.exe", // Application name
@ -53,7 +54,7 @@ void ScriptCompiler::compile(const char path[])
&si,
&pi) == TRUE)
{
Process* p = LUX_NEW(Process)();
Process* p = new Process();
p->m_handle = pi.hProcess;
p->m_path = path;
p->m_pipe = read_pipe;
@ -78,7 +79,7 @@ void ScriptCompiler::checkFinished()
Process* p = m_processes[i];
m_processes.eraseFast(i);
m_delegates.invoke(p->m_path.c_str(), code);
char buf[512];
char buf[513];
DWORD read;
if(code != 0)
{
@ -95,7 +96,7 @@ void ScriptCompiler::checkFinished()
}
CloseHandle(p->m_pipe);
CloseHandle(p->m_write_pipe);
LUX_DELETE(p);
delete p;
}
}
}

View file

@ -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();
}

View file

@ -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;
};

View 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

View 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

View file

@ -18,15 +18,15 @@ namespace UI
void TextDecorator::render(IRenderer& renderer, Block& block)
{
float w, h;
renderer.measureText(block.getBlockText().c_str(), &w, &h);
if(m_is_text_centered)
{
renderer.renderText(block.getBlockText().c_str(), (block.getGlobalRight() + block.getGlobalLeft() - w) / 2, (float)block.getGlobalTop(), block.getZ());
float w, h;
renderer.measureText(block.getBlockText().c_str(), &w, &h, block.getGlobalWidth());
renderer.renderText(block.getBlockText().c_str(), (block.getGlobalRight() + block.getGlobalLeft() - w) / 2, (float)block.getGlobalTop(), block.getZ(), block.getGlobalWidth());
}
else
{
renderer.renderText(block.getBlockText().c_str(), block.getGlobalLeft(), (float)block.getGlobalTop(), block.getZ());
renderer.renderText(block.getBlockText().c_str(), block.getGlobalLeft(), (float)block.getGlobalTop(), block.getZ(), block.getGlobalWidth());
}
}

View file

@ -2,6 +2,7 @@
#include "core/lux.h"
#include "gui/block.h"
namespace Lux
@ -26,8 +27,9 @@ 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 void measureText(const char* text, float* w, float* h) = 0;
virtual void renderText(const char* text, float x, float y, float z) = 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;
virtual void popScissorArea() = 0;
};

View file

@ -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,7 +222,74 @@ namespace UI
glLoadIdentity();
}
void OpenGLRenderer::measureText(const char* text, float* w, float* h)
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)
{
@ -231,7 +299,9 @@ namespace UI
}
float width = 0;
float height = 0;
float prev_h = 0;
const char* c = text;
bool is_multiline = false;
while(*c)
{
OpenGLRendererImpl::Character character;
@ -239,11 +309,23 @@ namespace UI
{
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;
}
*w = width;
*h = height;
*w = is_multiline ? max_width : width;
*h = height + prev_h;
}
void OpenGLRenderer::pushScissorArea(float left, float top, float right, float bottom)
@ -287,7 +369,7 @@ namespace UI
}
}
void OpenGLRenderer::renderText(const char* text, float x, float y, float z)
void OpenGLRenderer::renderText(const char* text, float x, float y, float z, float max_width)
{
if(!text)
{
@ -306,13 +388,16 @@ namespace UI
uvs.resize(len * 6);
const char* c = text;
float cur_x = x;
float line_h = 0;
float line_base = y;
int i = 0;
while(*c)
{
OpenGLRendererImpl::Character character;
if(m_impl->m_characters.find(*c, character))
{
float cur_y = y + character.y_offset;
float cur_y = line_base + character.y_offset;
line_h = Math::max(line_h, character.pixel_h);
verts[i*6].set(cur_x, cur_y, z);
verts[i*6+1].set(cur_x, cur_y + character.pixel_h, z);
verts[i*6+2].set(cur_x + character.pixel_w, cur_y + character.pixel_h, z);
@ -323,6 +408,12 @@ namespace UI
cur_x += character.x_advance;
if(cur_x - x > max_width)
{
cur_x = x;
line_base += line_h;
}
uvs[i*6].set(character.left, character.top);
uvs[i*6+1].set(character.left, character.bottom);
uvs[i*6+2].set(character.right, character.bottom);
@ -332,6 +423,11 @@ namespace UI
uvs[i*6+5].set(character.right, character.top);
++i;
}
else if(*c == '\n')
{
cur_x = x;
line_base += line_h;
}
++c;
}
glEnable(GL_BLEND);

View file

@ -24,8 +24,9 @@ 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 void measureText(const char* text, float* w, float* h) LUX_OVERRIDE;
virtual void renderText(const char* text, float x, float y, float z) 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;
virtual void popScissorArea() LUX_OVERRIDE;
void setWindowHeight(int height);