add newline feature to the text node, add about window with credits, add about menu with submenus

This commit is contained in:
2018-09-22 19:23:17 +02:00
parent fd8d6ff2d1
commit 3191730c31
18 changed files with 255 additions and 32 deletions

View File

@@ -187,6 +187,7 @@
<ClCompile Include="src\log.cpp" />
<ClCompile Include="src\main.cpp" />
<ClCompile Include="src\node.cpp" />
<ClCompile Include="src\node_about.cpp" />
<ClCompile Include="src\node_border.cpp" />
<ClCompile Include="src\node_button.cpp" />
<ClCompile Include="src\node_button_custom.cpp" />
@@ -302,6 +303,7 @@
<ClInclude Include="src\layout.h" />
<ClInclude Include="src\log.h" />
<ClInclude Include="src\node.h" />
<ClInclude Include="src\node_about.h" />
<ClInclude Include="src\node_border.h" />
<ClInclude Include="src\node_button.h" />
<ClInclude Include="src\node_button_custom.h" />

View File

@@ -252,6 +252,9 @@
<ClCompile Include="src\version.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\node_about.cpp">
<Filter>Source Files\ui</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\app.h">
@@ -449,6 +452,9 @@
<ClInclude Include="src\version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\node_about.h">
<Filter>Header Files\ui</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="PanoPainter.rc">

View File

@@ -56,6 +56,7 @@ add_library(
../src/layout.cpp
../src/version.cpp
../src/node.cpp
../src/node_about.cpp
../src/node_border.cpp
../src/node_button.cpp
../src/node_button_custom.cpp

View File

@@ -583,6 +583,67 @@
</border>
</layout>
<!--About window-->
<layout id="about">
<border positioning="absolute" position="0 0" color=".4 .4 .4 .8" width="100%" height="100%" align="center" justify="center">
<border thickness="1" border-color=".2" pad="3" max-width="650">
<border width="100%" height="30" color=".2 .2 .2 .9" dir="row" align="center" justify="center">
<text text="About PanoPainter" font-face="arial" font-size="11"></text>
</border>
<border width="100%" color="0 0 0 .9" pad="10" dir="col">
<!--window content-->
<border color=".2" width="100%" height="300">
<scroll pad="10" margin="5" color=".3 .3 .3 .4" height="100%" dir="col" wrap="0" shrink="1">
<text margin="0 0 0 5" font-face="arial" font-size="11" text=
"
--------------------------------------------------- ABOUT PANOPAINTER -----------------------------------------------------
PanoPainter - Copyright 2018 OmixLab Ltd
Thanks for using PanoPainter.
My name is Omar Mohamed Ali Mudhir and I'm the developer of this unique application.
In the late 2016 Facebook started to make it possible for users to post 360 content
captured from the first 360 cameras born after the advent of the VR to the market.
That's where me and a bounch or artists started to wonder about making art in 360.
I then started coding in my spare time to create something that would have helped
artists in the long process of creating a panoramic painting (panopainting).
Today this software has evolved a lot and reached a mature version ready for early
adopters that want to break the rules of traditional digital art and get into the
future of immersive painting.
Feel free to follow me on:
- Instagram: @panopainter
- Twitter: @panopainter
- Facebook: fb.me/panopainter
------------------------------------------------- FREE SOFTWARE LICENSES -------------------------------------------------
Free brushes:
The free brushes are provided by the freely available Brush Pack v3 from Fenris31
Link: https://www.deviantart.com/fenris31/art/Brush-Pack-v3-549566626
Roboto Font License:
Copyright 2018 OmixLab Ltd
Licensed under the Apache License, Version 2.0 (the 'License');
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an 'AS IS' BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License."/>
</scroll>
</border>
<!--footer buttons-->
<node height="40" grow="1" dir="row" align="flex-end" justify="flex-end">
<button id="btn-ok" text="Ok" width="100" height="30" margin="0 10 0 0"/>
</node>
</border>
</border>
</border>
</layout>
<!--popup menu-->
<layout id="popup-menu">
<popup-menu positioning="absolute" position="100 100" width="150" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col">
@@ -611,7 +672,7 @@
<!--file menu-->
<layout id="file-menu">
<popup-menu positioning="absolute" position="100 100" width="200" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col">
<popup-menu positioning="absolute" position="100 100" width="210" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col">
<!--
<button-custom height="30" align="center" color=".2" pad="0 20 0 10" dir="row">
<checkbox width="20" height="20"/>
@@ -678,10 +739,10 @@
<icon icon="weather_clouds" width="20"/>
<text text="Cloud Browse" grow="1" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom text="Menu" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<!--<button-custom text="Menu" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon width="20"/>
<text text="Quit" grow="1" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
</button-custom>-->
</popup-menu>
</layout>
@@ -705,13 +766,13 @@
<!--layers menu-->
<layout id="layers-menu">
<popup-menu positioning="absolute" position="100 100" width="250" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col">
<popup-menu positioning="absolute" position="100 100" width="270" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col">
<button-custom id="layer-clear" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="cancel" width="20"/>
<text id="menu-label" text="Clear layer" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom id="clear-grids" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="add" width="20"/>
<icon icon="bin" width="20"/>
<text text="Clear grids" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom id="layer-rename" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
@@ -729,20 +790,39 @@
<layout id="timelapse-menu">
<popup-menu positioning="absolute" position="100 100" width="150" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col">
<button-custom id="timelapse-start" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="cancel" width="20"/>
<icon icon="camera" width="20"/>
<text id="menu-label" text="Start Recording" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom id="timelapse-clear" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="cancel" width="20"/>
<icon icon="bin" width="20"/>
<text id="menu-label" text="Clear Frames" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom id="timelapse-export" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="cancel" width="20"/>
<icon icon="film_save" width="20"/>
<text id="menu-label" text="Export MP4" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
</popup-menu>
</layout>
<!-- about menu -->
<layout id="about-menu">
<popup-menu positioning="absolute" position="100 100" width="200" thickness="1" border-color=".1" color=".4 .4 .4 .8" dir="col">
<button-custom id="about-doc" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="help" width="20"/>
<text id="menu-label" text="Help Guide" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom id="about-app" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="application_view_gallery" width="20"/>
<text id="menu-label" text="About PanoPainter" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
<button-custom id="about-news" height="40" align="center" color=".2" pad="0 0 0 10" dir="row">
<icon icon="bug" width="20"/>
<text id="menu-label" text="What's new?" margin="0 0 0 5" font-face="arial" font-size="11"/>
</button-custom>
</popup-menu>
</layout>
<!--main-->
<layout id="main">
<node dir="col" wrap="0" width="100%" height="100%" pad="0">
@@ -768,7 +848,7 @@
<text id="txt-rec" text="" font-face="arial" font-size="11" margin="0 10 0 0" color=".6 .6 .6 1"/>
<text id="txt-memory" text="History memory: 0.00 Mb" font-face="arial" font-size="11" margin="0 5 0 0" color=".6 .6 .6 1"/>
<button-custom id="btn-clean-memory" margin="0 20 0 0">
<icon icon="delete" width="20"/>
<icon icon="cancel" width="20"/>
</button-custom>
<text id="version" text="PanoPainter" font-face="arial" font-size="11" margin="0 10 0 0" color=".2 .5 1 1"/>
</node>
@@ -795,12 +875,10 @@
<button-custom id="menu-timelapse" width="80" height="100%" margin="0 0 0 0" justify="center" align="center" pad="8" color=".1">
<text text="Timelapse" font-face="arial" font-size="11"/>
</button-custom>
<!--
<button-custom id="menu-about" width="60" height="100%" margin="0 0 0 0" justify="center" align="center" pad="8" color=".1">
<text text="About" font-face="arial" font-size="11"/>
</button-custom>
<button id="btn-anim" width="70" height="100%" margin="1 0 0 10" text="Animate"/>
-->
<!--<button id="btn-anim" width="70" height="100%" margin="1 0 0 10" text="Animate"/>-->
<node dir="row" justify="center" grow="1">
<button-custom id="btn-pen" width="50" height="100%" margin="0 0 0 5" thickness="1" border-color="0 0 0 1" pad="2">
<image path="data/ui/pen.png" width="100%" height="100%" align="center" justify="flex-end"/>

View File

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

View File

@@ -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] {

View File

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

View File

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

View File

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

View File

@@ -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:
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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