add newline feature to the text node, add about window with credits, add about menu with submenus
This commit is contained in:
@@ -139,6 +139,8 @@ public:
|
||||
void init_menu_edit();
|
||||
void init_menu_layer();
|
||||
void init_menu_timelapse();
|
||||
void init_menu_about();
|
||||
void dialog_about();
|
||||
void dialog_newdoc();
|
||||
void dialog_save();
|
||||
void dialog_save_ver();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "node_dialog_open.h"
|
||||
#include "node_dialog_browse.h"
|
||||
#include "node_dialog_cloud.h"
|
||||
#include "node_about.h"
|
||||
|
||||
std::shared_ptr<NodeProgressBar> App::show_progress(const std::string& title)
|
||||
{
|
||||
@@ -17,6 +18,17 @@ std::shared_ptr<NodeProgressBar> App::show_progress(const std::string& title)
|
||||
return pb;
|
||||
}
|
||||
|
||||
void App::dialog_about()
|
||||
{
|
||||
auto dialog = std::make_shared<NodeAbout>();
|
||||
dialog->m_manager = &layout;
|
||||
dialog->init();
|
||||
dialog->create();
|
||||
dialog->loaded();
|
||||
|
||||
layout[main_id]->add_child(dialog);
|
||||
layout[main_id]->update();
|
||||
}
|
||||
void App::dialog_newdoc()
|
||||
{
|
||||
auto show_dialog = [this] {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "node_text.h"
|
||||
#include "node_progress_bar.h"
|
||||
#include "node_dialog_picker.h"
|
||||
#include "node_about.h"
|
||||
|
||||
using namespace ui;
|
||||
|
||||
@@ -520,6 +521,53 @@ void App::init_menu_timelapse()
|
||||
}
|
||||
}
|
||||
|
||||
void App::init_menu_about()
|
||||
{
|
||||
if (auto* menu_file = layout[main_id]->find<NodeButtonCustom>("menu-about"))
|
||||
{
|
||||
menu_file->on_click = [=](Node*) {
|
||||
glm::vec2 pos = menu_file->m_pos + glm::vec2(0, menu_file->m_size.y);
|
||||
popup = (NodePopupMenu*)layout[const_hash("about-menu")]->m_children[0]->clone();
|
||||
popup->update();
|
||||
if (YGNodeStyleGetDirection(layout[main_id]->y_node) == YGDirectionRTL)
|
||||
pos.x = pos.x - popup->m_size.x + menu_file->m_size.x;
|
||||
popup->SetPositioning(YGPositionTypeAbsolute);
|
||||
popup->SetPosition(pos.x, pos.y);
|
||||
layout[main_id]->add_child(popup);
|
||||
layout[main_id]->update();
|
||||
popup->mouse_capture();
|
||||
popup->m_mouse_ignore = false;
|
||||
popup->m_flood_events = true;
|
||||
popup->m_capture_children = false;
|
||||
|
||||
popup->find<NodeButtonCustom>("about-app")->on_click = [this](Node*) {
|
||||
dialog_about();
|
||||
popup->mouse_release();
|
||||
popup->destroy();
|
||||
};
|
||||
|
||||
popup->find<NodeButtonCustom>("about-doc")->on_click = [this](Node*) {
|
||||
popup->mouse_release();
|
||||
popup->destroy();
|
||||
};
|
||||
|
||||
if (auto item = popup->find<NodeButtonCustom>("about-news"))
|
||||
{
|
||||
if (auto text = item->find<NodeText>("menu-label"))
|
||||
{
|
||||
static char label[128];
|
||||
sprintf(label, "What's new in %d.%d.%d?", g_version_major, g_version_minor, g_version_fix);
|
||||
text->set_text(label);
|
||||
}
|
||||
item->on_click = [this](Node*) {
|
||||
popup->mouse_release();
|
||||
popup->destroy();
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void App::brush_update()
|
||||
{
|
||||
// brushes->select_brush(canvas->m_brush.id);
|
||||
@@ -643,6 +691,7 @@ void App::initLayout()
|
||||
init_menu_edit();
|
||||
init_menu_layer();
|
||||
init_menu_timelapse();
|
||||
init_menu_about();
|
||||
|
||||
// set version string
|
||||
if (auto* version_label = layout[main_id]->find<NodeText>("version"))
|
||||
@@ -650,15 +699,6 @@ void App::initLayout()
|
||||
version_label->set_text(g_version);
|
||||
}
|
||||
|
||||
|
||||
if (auto* menu_entry = layout[main_id]->find<NodeButtonCustom>("menu-about"))
|
||||
{
|
||||
menu_entry->on_click = [=](Node*) {
|
||||
// int x = 0;
|
||||
// sin(time(0) / x);
|
||||
};
|
||||
}
|
||||
|
||||
Brush b;
|
||||
int br_idx = brushes->find_brush("Round-Hard");
|
||||
b.m_tex_id = brushes->get_texture_id(br_idx);
|
||||
|
||||
13
src/font.cpp
13
src/font.cpp
@@ -19,6 +19,7 @@ bool Font::load(const char* ttf, int font_size)
|
||||
stbtt_BakeFontBitmap(file.m_data, 0, (float)font_size*2, bitmap.get(), w, h, start_char, num_chars, chars.data());
|
||||
font_tex.create(w, h, GL_R8, GL_RED, bitmap.get());
|
||||
file.close();
|
||||
size = font_size;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -71,6 +72,12 @@ void TextMesh::update(kFont id, const char* text)
|
||||
glm::vec2 bbmax(-FLT_MAX);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (text[i] == '\n')
|
||||
{
|
||||
x = 0;
|
||||
y += f.size *2;
|
||||
continue;
|
||||
}
|
||||
int c = text[i] - f.start_char;
|
||||
stbtt_aligned_quad q;
|
||||
stbtt_GetBakedQuad((stbtt_bakedchar*)f.chars.data(), f.w, f.h, c, &x, &y, &q, true);
|
||||
@@ -88,10 +95,8 @@ void TextMesh::update(kFont id, const char* text)
|
||||
bbmin = glm::min(bbmin, { q.x0/2.f, q.y0/2.f });
|
||||
bbmax = glm::max(bbmax, { q.x1/2.f, q.y1/2.f });
|
||||
}
|
||||
for (int i = 0; i < len*4; i++)
|
||||
{
|
||||
v[i] -= glm::vec4(bbmin, 0, 0);
|
||||
}
|
||||
for (auto& vi : v)
|
||||
vi -= glm::vec4(bbmin, 0, 0);
|
||||
bb = bbmax - bbmin;
|
||||
font_array_count = (int)idx.size();
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
|
||||
|
||||
@@ -16,6 +16,7 @@ public:
|
||||
const int h = 512;
|
||||
const int num_chars = 96;
|
||||
const int start_char = 32;
|
||||
int size = 0;
|
||||
stbtt_fontinfo font;
|
||||
Texture2D font_tex;
|
||||
std::vector<stbtt_bakedchar> chars;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "node_colorwheel.h"
|
||||
#include "node_dialog_picker.h"
|
||||
#include "node_panel_grid.h"
|
||||
#include "node_about.h"
|
||||
|
||||
void Node::async_start()
|
||||
{
|
||||
@@ -897,6 +898,7 @@ void Node::load_internal(const tinyxml2::XMLElement* x_node)
|
||||
CASE(kWidget::DialogCloudItem, NodeDialogCloudItem);
|
||||
CASE(kWidget::ColorWheel, NodeColorWheel);
|
||||
CASE(kWidget::ColorPicker, NodeColorPicker);
|
||||
CASE(kWidget::About, NodeAbout);
|
||||
#undef CASE
|
||||
case kWidget::Ref:
|
||||
{
|
||||
|
||||
@@ -81,6 +81,7 @@ enum class kWidget : uint16_t
|
||||
DialogCloudItem = const_hash("dialog-cloud-item"),
|
||||
ColorWheel = const_hash("colorwheel"),
|
||||
ColorPicker = const_hash("color-picker"),
|
||||
About = const_hash("about"),
|
||||
};
|
||||
|
||||
class Node
|
||||
|
||||
26
src/node_about.cpp
Normal file
26
src/node_about.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "pch.h"
|
||||
#include "log.h"
|
||||
#include "node_about.h"
|
||||
#include "layout.h"
|
||||
|
||||
Node* NodeAbout::clone_instantiate() const
|
||||
{
|
||||
return new NodeAbout();
|
||||
}
|
||||
|
||||
void NodeAbout::init()
|
||||
{
|
||||
SetPosition(0, 0);
|
||||
SetWidthP(100);
|
||||
SetHeightP(100);
|
||||
SetPositioning(YGPositionTypeAbsolute);
|
||||
m_template = (*m_manager)[const_hash("about")]->m_children[0]->clone();
|
||||
add_child(m_template);
|
||||
btn_ok = m_template->find<NodeButton>("btn-ok");
|
||||
btn_ok->on_click = [&](Node*) { destroy(); };
|
||||
}
|
||||
|
||||
kEventResult NodeAbout::handle_event(Event* e)
|
||||
{
|
||||
return kEventResult::Consumed;
|
||||
}
|
||||
13
src/node_about.h
Normal file
13
src/node_about.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "node.h"
|
||||
#include "node_button.h"
|
||||
|
||||
class NodeAbout : public Node
|
||||
{
|
||||
Node* m_template;
|
||||
NodeButton* btn_ok;
|
||||
public:
|
||||
virtual Node* clone_instantiate() const override;
|
||||
virtual void init() override;
|
||||
virtual kEventResult handle_event(Event* e) override;
|
||||
};
|
||||
@@ -3,6 +3,14 @@
|
||||
#include "node_scroll.h"
|
||||
#include "event.h"
|
||||
|
||||
NodeScroll::NodeScroll()
|
||||
{
|
||||
m_drag_start = glm::vec2(0);
|
||||
m_offset_start = glm::vec2(0);
|
||||
m_offset = glm::vec2(0);
|
||||
m_mask = glm::vec2(0, 1);
|
||||
}
|
||||
|
||||
Node* NodeScroll::clone_instantiate() const
|
||||
{
|
||||
return new NodeScroll;
|
||||
@@ -43,7 +51,7 @@ kEventResult NodeScroll::handle_event(Event* e)
|
||||
m_dragging = false;
|
||||
break;
|
||||
case kEventType::MouseScroll:
|
||||
m_offset += me->m_scroll_delta * 50;
|
||||
m_offset += me->m_scroll_delta * 50 * m_mask;
|
||||
fix_scroll();
|
||||
break;
|
||||
case kEventType::GestureStart:
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
class NodeScroll : public NodeBorder
|
||||
{
|
||||
bool m_dragging = false;
|
||||
glm::vec2 m_drag_start;
|
||||
glm::vec2 m_offset_start;
|
||||
glm::vec2 m_offset;
|
||||
glm::vec2 m_mask{ 0, 1 };
|
||||
glm::vec2 m_drag_start = glm::vec2(0);
|
||||
glm::vec2 m_offset_start = glm::vec2(0);
|
||||
glm::vec2 m_offset = glm::vec2(0);
|
||||
glm::vec2 m_mask = glm::vec2(1, 0);
|
||||
public:
|
||||
NodeScroll();
|
||||
virtual Node* clone_instantiate() const override;
|
||||
virtual kEventResult handle_event(Event* e) override;
|
||||
void fix_scroll();
|
||||
|
||||
@@ -54,7 +54,7 @@ void NodeText::parse_attributes(kAttribute ka, const tinyxml2::XMLAttribute* att
|
||||
switch (ka)
|
||||
{
|
||||
case kAttribute::Text:
|
||||
m_text = attr->Value();
|
||||
m_text = unescape(attr->Value());
|
||||
break;
|
||||
case kAttribute::FontFace:
|
||||
m_font = attr->Value();
|
||||
|
||||
25
src/util.cpp
25
src/util.cpp
@@ -105,6 +105,31 @@ std::vector<std::string> split(const std::string& subject, char d, int max_split
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string unescape(const std::string& s)
|
||||
{
|
||||
std::string res;
|
||||
std::string::const_iterator it = s.begin();
|
||||
while (it != s.end())
|
||||
{
|
||||
char c = *it++;
|
||||
if (c == '\\' && it != s.end())
|
||||
{
|
||||
switch (*it++) {
|
||||
case '\\': c = '\\'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 't': c = '\t'; break;
|
||||
// all other escapes
|
||||
default:
|
||||
// invalid escape sequence - skip it. alternatively you can copy it as is, throw an exception...
|
||||
continue;
|
||||
}
|
||||
}
|
||||
res += c;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static const char* gl2str(GLenum err)
|
||||
{
|
||||
switch (err)
|
||||
|
||||
@@ -16,6 +16,7 @@ glm::vec4 rand_color();
|
||||
glm::vec3 convert_hsv2rgb(const glm::vec3 c);
|
||||
glm::vec3 convert_rgb2hsv(const glm::vec3 c);
|
||||
std::vector<std::string> split(const std::string& subject, char d, int max_split = 0);
|
||||
std::string unescape(const std::string& s);
|
||||
|
||||
size_t curl_data_handler(void *contents, size_t size, size_t nmemb, void *userp);
|
||||
size_t curl_data_write(void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
@@ -26,7 +27,6 @@ inline glm::vec2 zw(const glm::vec4& v) { return glm::vec2(v.z, v.w); }
|
||||
inline glm::ivec2 xy(const glm::ivec4& v) { return glm::ivec2(v.x, v.y); }
|
||||
inline glm::ivec3 xyz(const glm::ivec4& v) { return glm::ivec3(v.x, v.y, v.z); }
|
||||
inline glm::ivec2 zw(const glm::ivec4& v) { return glm::ivec2(v.z, v.w); }
|
||||
|
||||
inline glm::vec2 xy(const glm::vec3& v) { return glm::vec2(v.x, v.y); }
|
||||
|
||||
template<typename T, int N> struct cbuffer
|
||||
|
||||
Reference in New Issue
Block a user