Files
panopainter/src/node_text_input.cpp
2019-09-17 13:57:37 +02:00

247 lines
6.5 KiB
C++

#include "pch.h"
#include "app.h"
#include "log.h"
#include "node_text_input.h"
#include "node_border.h"
Node* NodeTextInput::clone_instantiate() const
{
return new NodeTextInput();
}
void NodeTextInput::on_tick(float dt)
{
timer += dt;
bool focus = root()->current_key_capture.get() == this;
if (!focus)
m_cursor_visible = false;
m_thinkness = focus;
if (timer > 1.0)
{
timer = 0;
if (focus)
{
m_cursor_visible = !m_cursor_visible;
app_redraw();
}
}
}
void NodeTextInput::clone_copy(Node* dest) const
{
NodeBorder::clone_copy(dest);
NodeTextInput* n = static_cast<NodeTextInput*>(dest);
n->m_multiline = m_multiline;
n->m_text_mesh.max_width = m_text_mesh.max_width;
n->m_text_mesh.create();
n->m_text_mesh.update(font_id, m_text);
n->m_text = m_text;
n->m_font = m_font;
n->m_color = m_color;
n->m_font_size = m_font_size;
n->font_id = font_id;
n->m_off = m_off;
n->m_text_align_v = m_text_align_v;
n->m_text_align_h = m_text_align_h;
}
kEventResult NodeTextInput::handle_event(Event* e)
{
KeyEvent* ke = (KeyEvent*)e;
switch (e->m_type)
{
case kEventType::MouseDownL:
App::I->showKeyboard();
break;
case kEventType::MouseUpL:
key_capture();
timer = 0;
m_cursor_visible = true;
break;
case kEventType::KeyDown:
//switch (ke->m_key)
//{
//case VK_BACK:
// m_string.erase(m_string.end() - 1);
// m_text->set_text(m_string);
// break;
//default:
// break;
//}
break;
case kEventType::KeyUp:
if (ke->m_key == kKey::KeyEnter && on_return)
on_return(this);
if (ke->m_key == kKey::KeyBackspace)
{
if (!m_text.empty())
{
m_text.erase(m_text.end() - 1);
set_text(m_text);
}
}
break;
case kEventType::KeyChar:
timer = 0;
m_cursor_visible = true;
if (ke->m_char == '\b' // backspace
|| ke->m_char == 0x7f // DEL
)
{
if (!m_text.empty())
{
m_text.erase(m_text.end() - 1);
set_text(m_text);
}
}
else if (ke->m_char == '\n' || ke->m_char == '\r') // enter/return
{
if (m_multiline)
{
m_text += '\n';
set_text(m_text);
}
else if (on_return)
{
on_return(this);
}
}
else if (ke->m_char >= 32 && ke->m_char < (32 + 96))
{
m_text += (char)ke->m_char;
set_text(m_text);
}
break;
default:
return kEventResult::Available;
break;
}
return kEventResult::Consumed;
}
void NodeTextInput::set_text(const std::string& s)
{
m_text = s;
m_text_mesh.update(font_id, s);
update_layout();
}
void NodeTextInput::set_text_format(const char* fmt, ...)
{
static char buffer[4096];
va_list args;
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
m_text = buffer;
m_text_mesh.update(font_id, buffer);
update_layout();
}
void NodeTextInput::update_layout()
{
auto pad = GetPadding();
float h = GetHeight() - (pad[1] + pad[3]);
float w = GetWidth() - (pad[0] + pad[2]);
if (m_text_align_v == TextAlign::Begin)
m_off.y = pad[0];
else if (m_text_align_v == TextAlign::Center)
m_off.y = (h - m_text_mesh.bb.y) * 0.5f + pad[0];
else
m_off.y = (h - m_text_mesh.bb.y) + pad[0];
if (m_text_align_h == TextAlign::Begin)
m_off.x = pad[3];
else if (m_text_align_v == TextAlign::Center)
m_off.x = (w - m_text_mesh.bb.x) * 0.5f + pad[3];
else
m_off.x = (w - m_text_mesh.bb.x) + pad[3];
}
void NodeTextInput::handle_resize(glm::vec2 old_size, glm::vec2 new_size, float zoom)
{
auto pad = GetPadding();
m_text_mesh.max_width = m_multiline ? new_size.x - (pad[1] + pad[3]) : 0;
update_layout();
}
void NodeTextInput::create()
{
NodeBorder::create();
if (!m_font.empty())
{
char font[64];
sprintf(font, "%s-%d", m_font.c_str(), m_font_size);
font_id = (kFont)const_hash(font);
m_text_mesh.create();
m_text_mesh.update(font_id, m_text);
update_layout();
}
}
void NodeTextInput::draw()
{
NodeBorder::draw();
glm::mat4 pos = glm::translate(glm::vec3(glm::floor(m_pos + m_off), 0));
ShaderManager::use(kShader::Font);
ShaderManager::u_int(kShaderUniform::Tex, 0);
ShaderManager::u_mat4(kShaderUniform::MVP, m_proj * pos);
ShaderManager::u_vec4(kShaderUniform::Col, m_color);
glEnable(GL_BLEND);
m_text_mesh.draw();
glDisable(GL_BLEND);
if (m_cursor_visible)
{
glDisable(GL_BLEND);
glm::mat4 cur_pos = glm::translate(glm::vec3(m_pos + m_off + xy(m_text_mesh.cur_box), 0));
glm::mat4 cur_scale = glm::scale(glm::vec3(zw(m_text_mesh.cur_box), 1));
glm::mat4 cur_pivot = glm::translate(glm::vec3(0.5, 0.5, 0));
ShaderManager::use(kShader::Color);
ShaderManager::u_mat4(kShaderUniform::MVP, m_proj * cur_pos * cur_scale * cur_pivot);
ShaderManager::u_vec4(kShaderUniform::Col, { 0, 0, 0, 1 });
m_plane.draw_fill();
}
}
void NodeTextInput::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* attr)
{
switch (ka)
{
case kAttribute::Multiline:
m_multiline = attr->BoolValue();
break;
case kAttribute::TextAlign:
if (strcmp(attr->Value(), "left") == 0)
m_text_align_h = TextAlign::Begin;
else if (strcmp(attr->Value(), "center") == 0)
m_text_align_h = TextAlign::Center;
else if (strcmp(attr->Value(), "right") == 0)
m_text_align_h = TextAlign::End;
break;
case kAttribute::TextVerticalAlign:
if (strcmp(attr->Value(), "top") == 0)
m_text_align_v = TextAlign::Begin;
else if (strcmp(attr->Value(), "center") == 0)
m_text_align_v = TextAlign::Center;
else if (strcmp(attr->Value(), "bottom") == 0)
m_text_align_v = TextAlign::End;
break;
default:
NodeBorder::parse_attributes(ka, attr);
}
}
void NodeTextInput::destroy()
{
if (root()->current_key_capture.get() == this)
App::I->hideKeyboard();
NodeBorder::destroy();
}