Open and draw a story teller project format

This commit is contained in:
Anthony Rabine 2023-12-10 22:37:12 +01:00
parent 3c01a29c66
commit 8b13a63e6b
35 changed files with 14091 additions and 2209 deletions

4
.gitignore vendored
View file

@ -59,3 +59,7 @@ story-editor-v2/src/CMakeSettings.json
story-editor-v2/imgui.ini
story-editor-v2/src/.vscode/
build-story-editor-v2-Desktop-Debug/
build-story-editor-Desktop-Debug/

View file

@ -22,64 +22,79 @@ if(POLICY CMP0072)
endif()
find_package(OpenGL REQUIRED)
set(IMGUI_VERSION 1.89.9)
set(IMGUI_VERSION 1.90)
include(FetchContent)
#=========================================================================================================================
# IMGUI and plugins
#=========================================================================================================================
FetchContent_Declare(imgui
URL https://github.com/ocornut/imgui/archive/refs/tags/v${IMGUI_VERSION}-docking.zip
)
FetchContent_GetProperties(imgui)
if (NOT imgui_POPULATED) # Have we downloaded raylib yet?
if (NOT imgui_POPULATED)
set(FETCHCONTENT_QUIET NO)
FetchContent_Populate(imgui)
endif()
# ImGuiFileDialog
include_directories(${imgui_SOURCE_DIR})
add_compile_definitions(CUSTOM_IMGUIFILEDIALOG_CONFIG="${CMAKE_SOURCE_DIR}/src/CustomImGuiFileDialogConfig.h")
add_compile_definitions(IMGUI_INCLUDE="imgui.h")
add_subdirectory(libs/ImGuiFileDialog)
#=========================================================================================================================
# SDL3
# SDL
#=========================================================================================================================
include(FetchContent)
Set(FETCHCONTENT_QUIET FALSE)
FetchContent_Declare(
SDL3
sdl2
GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
GIT_TAG origin/main
GIT_TAG origin/SDL2
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
set(BUILD_SHARED_LIBS TRUE)
set(SDL_STATIC TRUE)
FetchContent_MakeAvailable(SDL3)
FetchContent_MakeAvailable(sdl2)
#add_subdirectory(libs/SDL)
#include_directories(libs/SDL/include)
#=========================================================================================================================
# SDL3-Image
#=========================================================================================================================
FetchContent_Declare(
SDL2_image
GIT_REPOSITORY https://github.com/libsdl-org/SDL_image.git
GIT_TAG origin/main
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
#FetchContent_Declare(
# SDL2_image
# GIT_REPOSITORY https://github.com/libsdl-org/SDL_image.git
# GIT_TAG origin/main
# GIT_SHALLOW TRUE
# GIT_PROGRESS TRUE
#)
# START ADDITION
set(SDL2IMAGE_INSTALL OFF)
set(BUILD_SHARED_LIBS FALSE)
# END ADDITION
## START ADDITION
#set(SDL2IMAGE_INSTALL OFF)
#set(BUILD_SHARED_LIBS FALSE)
## END ADDITION
FetchContent_MakeAvailable(SDL2_image)
#FetchContent_MakeAvailable(SDL2_image)
set(SRCS
src/main.cpp
src/window_base.h
src/window_base.cpp
src/console_window.cpp
src/console_window.h
@ -95,6 +110,9 @@ set(SRCS
src/media_node.h
src/media_node.cpp
src/platform_folders.cpp
src/platform_folders.h
src/base_node.h
src/base_node.cpp
@ -115,8 +133,8 @@ set(SRCS
libs/imgui-node-editor/crude_json.cpp
libs/ImGuiFileDialog/ImGuiFileDialog.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_sdl2.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer2.cpp
${imgui_SOURCE_DIR}/backends/imgui_impl_opengl3.cpp
${imgui_SOURCE_DIR}/imgui.cpp
${imgui_SOURCE_DIR}/imgui_widgets.cpp
@ -144,11 +162,13 @@ endif()
add_executable(${STORY_EDITOR_PROJECT}
${SRCS}
src/uuid.h
src/window_base.h src/window_base.cpp
)
target_include_directories(${STORY_EDITOR_PROJECT} PUBLIC
${imgui_SOURCE_DIR}
${sdl3_SOURCE_DIR}/include
${sdl2_SOURCE_DIR}/include
libs/ImGuiColorTextEdit/
${imgui_SOURCE_DIR}/backends
libs/ImGuiFileDialog
@ -159,21 +179,23 @@ target_include_directories(${STORY_EDITOR_PROJECT} PUBLIC
)
add_definitions(-DIMGUI_USE_WCHAR32)
add_link_options(-static-libgcc -static-libstdc++)
target_compile_definitions(${STORY_EDITOR_PROJECT} PUBLIC cimg_display=0)
target_link_directories(${STORY_EDITOR_PROJECT} PUBLIC ${sdl3_BINARY_DIR})
message(${sdl3_BINARY_DIR})
target_compile_definitions(${STORY_EDITOR_PROJECT} PUBLIC "$<$<CONFIG:DEBUG>:DEBUG>")
target_link_directories(${STORY_EDITOR_PROJECT} PUBLIC ${sdl2_BINARY_DIR})
message(${sdl2_BINARY_DIR})
if (UNIX)
target_link_libraries(${STORY_EDITOR_PROJECT}
pthread
udev
glfw
OpenGL::GL
dl
SDL3
SDL2
)
elseif(WIN32)
target_link_libraries(${STORY_EDITOR_PROJECT}

View file

@ -0,0 +1,15 @@
cmake_minimum_required(VERSION 3.5)
project(ImGuiFileDialog)
add_library(ImGuiFileDialog STATIC
ImGuiFileDialog.cpp
ImGuiFileDialog.h
ImGuiFileDialogConfig.h
)
target_include_directories(ImGuiFileDialog PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
if(UNIX)
target_compile_options(ImGuiFileDialog PUBLIC "-Wno-unknown-pragmas")
endif()

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,8 +2,12 @@
// uncomment and modify defines under for customize ImGuiFileDialog
//this options need c++17
//#define USE_STD_FILESYSTEM
// uncomment if you need to use your FileSystem Interface
// if commented, you have two defualt interface, std::filesystem or dirent
// #define USE_CUSTOM_FILESYSTEM
// this options need c++17
// #define USE_STD_FILESYSTEM
//#define MAX_FILE_DIALOG_NAME_BUFFER 1024
//#define MAX_PATH_BUFFER_SIZE 1024

View file

@ -1,7 +1,7 @@
[![Win](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Win.yml/badge.svg?branch=DemoApp)](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Win.yml)
[![Linux](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Linux.yml/badge.svg?branch=DemoApp)](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Linux.yml)
[![Osx](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Osx.yml/badge.svg?branch=DemoApp)](https://github.com/aiekick/ImGuiFileDialog/actions/workflows/Osx.yml)
[![Wrapped Dear ImGui Version](https://img.shields.io/badge/Dear%20ImGui%20Version-1.89.9-blue.svg)](https://github.com/ocornut/imgui)
[![Wrapped Dear ImGui Version](https://img.shields.io/badge/Dear%20ImGui%20Version-1.90.1-blue.svg)](https://github.com/ocornut/imgui)
# ImGuiFileDialog
@ -14,7 +14,7 @@ solutions.
## ImGui Supported Version
ImGuiFileDialog follow the master and docking branch of ImGui . currently ImGui 1.89.9
ImGuiFileDialog follow the master and docking branch of ImGui. Currently ImGui 1.90.1
## Structure
@ -67,7 +67,7 @@ Android Requirements : Api 21 mini
- 0 => Infinite
- 1 => One file (default)
- n => n files
- Compatible with MacOs, Linux, Windows
- Compatible with MacOs, Linux, Windows, Emscripten
- Windows version can list drives
- Supports modal or standard dialog types
- Select files or directories
@ -86,6 +86,9 @@ Android Requirements : Api 21 mini
- multi layer extentions like : .a.b.c .json.cpp .vcxproj.filters etc..
- advanced behavior regarding asterisk based filter. like : .* .*.* .vcx.* .*.filters .vcs*.filt.* etc.. (internally regex is used)
- result modes GetFilePathName, GetFileName and GetSelection (overwrite file ext, keep file, add ext if no user ext exist)
- you can use your own FileSystem Api
- by default Api Dirent and std::filesystem are defined
- you can override GetDrieveList for specify by ex on android other fs, like local and SDCards
### WARNINGS :
- the nav system keyboard behavior is not working as expected, so maybe full of bug for ImGuiFileDialog
@ -938,9 +941,28 @@ to note :
</blockquote></details>
<details open><summary><h2>Api's C/C++ :</h2></summary><blockquote>
<details open><summary><h2>Custom FileSystem</h2></summary><blockquote>
### the C Api
you can use your custom file system interface.
by default IGFD come with the File System Interfaces for Dirent or std::filesystem
but you have now a FileSystem interface called IFileSystem who can be overrided with your needs
by ex for android, emscripten, or boost
2 steps :
1) create a include file who must contain :
- your override of IGFD::IFileSystem
- a define of your class name in FILE_SYSTEM_OVERRIDE (ex : #define FILE_SYSTEM_OVERRIDE FileSystemBoost)
2) define your file system include file path in the preprocessor var "CUSTOM_FILESYSTEM_INCLUDE"
ex : #define CUSTOM_FILESYSTEM_INCLUDE "src/FileSystemBoost.hpp"
you can check the DemoApp who is using an override for the Boost::filesystem
</blockquote></details>
<details open><summary><h2>C Api :</h2></summary><blockquote>
this api was sucessfully tested with CImGui

View file

@ -0,0 +1,37 @@
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,165 @@
<!--- THIS FILE IS AUTOMATICALLY GENERATED, DO NOT CHANGE IT BY HAND --->
stb
===
single-file public domain (or MIT licensed) libraries for C/C++
Noteworthy:
* image loader: [stb_image.h](stb_image.h)
* image writer: [stb_image_write.h](stb_image_write.h)
* image resizer: [stb_image_resize.h](stb_image_resize.h)
* font text rasterizer: [stb_truetype.h](stb_truetype.h)
* typesafe containers: [stb_ds.h](stb_ds.h)
Most libraries by stb, except: stb_dxt by Fabian "ryg" Giesen, stb_image_resize
by Jorge L. "VinoBS" Rodriguez, and stb_sprintf by Jeff Roberts.
<a name="stb_libs"></a>
library | lastest version | category | LoC | description
--------------------- | ---- | -------- | --- | --------------------------------
**[stb_vorbis.c](stb_vorbis.c)** | 1.20 | audio | 5563 | decode ogg vorbis files from file/memory to float/16-bit signed output
**[stb_image.h](stb_image.h)** | 2.26 | graphics | 7762 | image loading/decoding from file/memory: JPG, PNG, TGA, BMP, PSD, GIF, HDR, PIC
**[stb_truetype.h](stb_truetype.h)** | 1.24 | graphics | 5011 | parse, decode, and rasterize characters from truetype fonts
**[stb_image_write.h](stb_image_write.h)** | 1.15 | graphics | 1690 | image writing to disk: PNG, TGA, BMP
**[stb_image_resize.h](stb_image_resize.h)** | 0.96 | graphics | 2631 | resize images larger/smaller with good quality
**[stb_rect_pack.h](stb_rect_pack.h)** | 1.00 | graphics | 628 | simple 2D rectangle packer with decent quality
**[stb_ds.h](stb_ds.h)** | 0.65 | utility | 1880 | typesafe dynamic array and hash tables for C, will compile in C++
**[stb_sprintf.h](stb_sprintf.h)** | 1.09 | utility | 1879 | fast sprintf, snprintf for C/C++
**[stretchy_buffer.h](stretchy_buffer.h)** | 1.04 | utility | 263 | typesafe dynamic array for C (i.e. approximation to vector<>), doesn't compile as C++
**[stb_textedit.h](stb_textedit.h)** | 1.13 | user&nbsp;interface | 1404 | guts of a text editor for games etc implementing them from scratch
**[stb_voxel_render.h](stb_voxel_render.h)** | 0.89 | 3D&nbsp;graphics | 3807 | Minecraft-esque voxel rendering "engine" with many more features
**[stb_dxt.h](stb_dxt.h)** | 1.10 | 3D&nbsp;graphics | 753 | Fabian "ryg" Giesen's real-time DXT compressor
**[stb_perlin.h](stb_perlin.h)** | 0.5 | 3D&nbsp;graphics | 428 | revised Perlin noise (3D input, 1D output)
**[stb_easy_font.h](stb_easy_font.h)** | 1.1 | 3D&nbsp;graphics | 305 | quick-and-dirty easy-to-deploy bitmap font for printing frame rate, etc
**[stb_tilemap_editor.h](stb_tilemap_editor.h)** | 0.41 | game&nbsp;dev | 4161 | embeddable tilemap editor
**[stb_herringbone_wa...](stb_herringbone_wang_tile.h)** | 0.7 | game&nbsp;dev | 1221 | herringbone Wang tile map generator
**[stb_c_lexer.h](stb_c_lexer.h)** | 0.11 | parsing | 966 | simplify writing parsers for C-like languages
**[stb_divide.h](stb_divide.h)** | 0.93 | math | 430 | more useful 32-bit modulus e.g. "euclidean divide"
**[stb_connected_comp...](stb_connected_components.h)** | 0.96 | misc | 1049 | incrementally compute reachability on grids
**[stb.h](stb.h)** | 2.37 | misc | 14454 | helper functions for C, mostly redundant in C++; basically author's personal stuff
**[stb_leakcheck.h](stb_leakcheck.h)** | 0.6 | misc | 194 | quick-and-dirty malloc/free leak-checking
**[stb_include.h](stb_include.h)** | 0.02 | misc | 295 | implement recursive #include support, particularly for GLSL
Total libraries: 22
Total lines of C code: 56774
FAQ
---
#### What's the license?
These libraries are in the public domain. You can do anything you
want with them. You have no legal obligation
to do anything else, although I appreciate attribution.
They are also licensed under the MIT open source license, if you have lawyers
who are unhappy with public domain. Every source file includes an explicit
dual-license for you to choose from.
#### <a name="other_libs"></a> Are there other single-file public-domain/open source libraries with minimal dependencies out there?
[Yes.](https://github.com/nothings/single_file_libs)
#### If I wrap an stb library in a new library, does the new library have to be public domain/MIT?
No, because it's public domain you can freely relicense it to whatever license your new
library wants to be.
#### What's the deal with SSE support in GCC-based compilers?
stb_image will either use SSE2 (if you compile with -msse2) or
will not use any SIMD at all, rather than trying to detect the
processor at runtime and handle it correctly. As I understand it,
the approved path in GCC for runtime-detection require
you to use multiple source files, one for each CPU configuration.
Because stb_image is a header-file library that compiles in only
one source file, there's no approved way to build both an
SSE-enabled and a non-SSE-enabled variation.
While we've tried to work around it, we've had multiple issues over
the years due to specific versions of gcc breaking what we're doing,
so we've given up on it. See https://github.com/nothings/stb/issues/280
and https://github.com/nothings/stb/issues/410 for examples.
#### Some of these libraries seem redundant to existing open source libraries. Are they better somehow?
Generally they're only better in that they're easier to integrate,
easier to use, and easier to release (single file; good API; no
attribution requirement). They may be less featureful, slower,
and/or use more memory. If you're already using an equivalent
library, there's probably no good reason to switch.
#### Can I link directly to the table of stb libraries?
You can use [this URL](https://github.com/nothings/stb#stb_libs) to link directly to that list.
#### Why do you list "lines of code"? It's a terrible metric.
Just to give you some idea of the internal complexity of the library,
to help you manage your expectations, or to let you know what you're
getting into. While not all the libraries are written in the same
style, they're certainly similar styles, and so comparisons between
the libraries are probably still meaningful.
Note though that the lines do include both the implementation, the
part that corresponds to a header file, and the documentation.
#### Why single-file headers?
Windows doesn't have standard directories where libraries
live. That makes deploying libraries in Windows a lot more
painful than open source developers on Unix-derivates generally
realize. (It also makes library dependencies a lot worse in Windows.)
There's also a common problem in Windows where a library was built
against a different version of the runtime library, which causes
link conflicts and confusion. Shipping the libs as headers means
you normally just compile them straight into your project without
making libraries, thus sidestepping that problem.
Making them a single file makes it very easy to just
drop them into a project that needs them. (Of course you can
still put them in a proper shared library tree if you want.)
Why not two files, one a header and one an implementation?
The difference between 10 files and 9 files is not a big deal,
but the difference between 2 files and 1 file is a big deal.
You don't need to zip or tar the files up, you don't have to
remember to attach *two* files, etc.
#### Why "stb"? Is this something to do with Set-Top Boxes?
No, they are just the initials for my name, Sean T. Barrett.
This was not chosen out of egomania, but as a moderately sane
way of namespacing the filenames and source function names.
#### Will you add more image types to stb_image.h?
No. As stb_image use has grown, it has become more important
for us to focus on security of the codebase. Adding new image
formats increases the amount of code we need to secure, so it
is no longer worth adding new formats.
#### Do you have any advice on how to create my own single-file library?
Yes. https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
#### Why public domain?
I prefer it over GPL, LGPL, BSD, zlib, etc. for many reasons.
Some of them are listed here:
https://github.com/nothings/stb/blob/master/docs/why_public_domain.md
#### Why C?
Primarily, because I use C, not C++. But it does also make it easier
for other people to use them from other languages.
#### Why not C99? stdint.h, declare-anywhere, etc.
I still use MSVC 6 (1998) as my IDE because it has better human factors
for me than later versions of MSVC.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,135 @@
#pragma once
// uncomment and modify defines under for customize ImGuiFileDialog
// uncomment if you need to use your FileSystem Interface
// if commented, you have two defualt interface, std::filesystem or dirent
// #define USE_CUSTOM_FILESYSTEM
// this options need c++17
// #define USE_STD_FILESYSTEM
//#define MAX_FILE_DIALOG_NAME_BUFFER 1024
//#define MAX_PATH_BUFFER_SIZE 1024
// the slash's buttons in path cna be used for quick select parallles directories
//#define USE_QUICK_PATH_SELECT
// the spacing between button path's can be customized.
// if disabled the spacing is defined by the imgui theme
// define the space between path buttons
//#define CUSTOM_PATH_SPACING 2
//#define USE_THUMBNAILS
//the thumbnail generation use the stb_image and stb_resize lib who need to define the implementation
//btw if you already use them in your app, you can have compiler error due to "implemntation found in double"
//so uncomment these line for prevent the creation of implementation of these libs again
//#define DONT_DEFINE_AGAIN__STB_IMAGE_IMPLEMENTATION
//#define DONT_DEFINE_AGAIN__STB_IMAGE_RESIZE_IMPLEMENTATION
//#define IMGUI_RADIO_BUTTON RadioButton
//#define DisplayMode_ThumbailsList_ImageHeight 32.0f
//#define tableHeaderFileThumbnailsString "Thumbnails"
//#define DisplayMode_FilesList_ButtonString "FL"
//#define DisplayMode_FilesList_ButtonHelp "File List"
//#define DisplayMode_ThumbailsList_ButtonString "TL"
//#define DisplayMode_ThumbailsList_ButtonHelp "Thumbnails List"
// todo
//#define DisplayMode_ThumbailsGrid_ButtonString "TG"
//#define DisplayMode_ThumbailsGrid_ButtonHelp "Thumbnails Grid"
//#define USE_EXPLORATION_BY_KEYS
// this mapping by default is for GLFW but you can use another
//#include <GLFW/glfw3.h>
// Up key for explore to the top
//#define IGFD_KEY_UP ImGuiKey_UpArrow
// Down key for explore to the bottom
//#define IGFD_KEY_DOWN ImGuiKey_DownArrow
// Enter key for open directory
//#define IGFD_KEY_ENTER ImGuiKey_Enter
// BackSpace for comming back to the last directory
//#define IGFD_KEY_BACKSPACE ImGuiKey_Backspace
// by ex you can quit the dialog by pressing the key excape
//#define USE_DIALOG_EXIT_WITH_KEY
//#define IGFD_EXIT_KEY ImGuiKey_Escape
// widget
// begin combo widget
//#define IMGUI_BEGIN_COMBO ImGui::BeginCombo
// when auto resized, FILTER_COMBO_MIN_WIDTH will be considered has minimum width
// FILTER_COMBO_AUTO_SIZE is enabled by default now to 1
// uncomment if you want disable
//#define FILTER_COMBO_AUTO_SIZE 0
// filter combobox width
//#define FILTER_COMBO_MIN_WIDTH 120.0f
// button widget use for compose path
//#define IMGUI_PATH_BUTTON ImGui::Button
// standard button
//#define IMGUI_BUTTON ImGui::Button
// locales string
//#define createDirButtonString "+"
//#define resetButtonString "R"
//#define drivesButtonString "Drives"
//#define editPathButtonString "E"
//#define searchString "Search"
//#define dirEntryString "[DIR] "
//#define linkEntryString "[LINK] "
//#define fileEntryString "[FILE] "
//#define fileNameString "File Name : "
//#define dirNameString "Directory Path :"
//#define buttonResetSearchString "Reset search"
//#define buttonDriveString "Drives"
//#define buttonEditPathString "Edit path\nYou can also right click on path buttons"
//#define buttonResetPathString "Reset to current directory"
//#define buttonCreateDirString "Create Directory"
//#define OverWriteDialogTitleString "The file Already Exist !"
//#define OverWriteDialogMessageString "Would you like to OverWrite it ?"
//#define OverWriteDialogConfirmButtonString "Confirm"
//#define OverWriteDialogCancelButtonString "Cancel"
//Validation buttons
//#define okButtonString " OK"
//#define okButtonWidth 0.0f
//#define cancelButtonString " Cancel"
//#define cancelButtonWidth 0.0f
//alignement [0:1], 0.0 is left, 0.5 middle, 1.0 right, and other ratios
//#define okCancelButtonAlignement 0.0f
//#define invertOkAndCancelButtons 0
// DateTimeFormat
// see strftime functionin <ctime> for customize
// "%Y/%m/%d %H:%M" give 2021:01:22 11:47
// "%Y/%m/%d %i:%M%p" give 2021:01:22 11:45PM
//#define DateTimeFormat "%Y/%m/%d %i:%M%p"
// theses icons will appear in table headers
//#define USE_CUSTOM_SORTING_ICON
//#define tableHeaderAscendingIcon "A|"
//#define tableHeaderDescendingIcon "D|"
//#define tableHeaderFileNameString " File name"
//#define tableHeaderFileTypeString " Type"
//#define tableHeaderFileSizeString " Size"
//#define tableHeaderFileDateTimeString " Date"
//#define fileSizeBytes "o"
//#define fileSizeKiloBytes "Ko"
//#define fileSizeMegaBytes "Mo"
//#define fileSizeGigaBytes "Go"
// default table sort field (must be FIELD_FILENAME, FIELD_TYPE, FIELD_SIZE, FIELD_DATE or FIELD_THUMBNAILS)
//#define defaultSortField FIELD_FILENAME
// default table sort order for each field (true => Descending, false => Ascending)
//#define defaultSortOrderFilename true
//#define defaultSortOrderType true
//#define defaultSortOrderSize true
//#define defaultSortOrderDate true
//#define defaultSortOrderThumbnails true
//#define USE_BOOKMARK
//#define bookmarkPaneWith 150.0f
//#define IMGUI_TOGGLE_BUTTON ToggleButton
//#define bookmarksButtonString "Bookmark"
//#define bookmarksButtonHelpString "Bookmark"
//#define addBookmarkButtonString "+"
//#define removeBookmarkButtonString "-"

View file

@ -1,19 +1,17 @@
#include "base_node.h"
#include "uuid.h"
#include "IconsMaterialDesignIcons.h"
int BaseNode::s_nextId = 1;
BaseNode::BaseNode(const std::string &title)
BaseNode::BaseNode(const std::string &title, StoryProject &proj)
: m_project(proj)
{
m_id = UUID().String();
// m_id = UUID().String();
m_id = -1;
m_node = std::make_unique<Node>(GetNextId(), title.c_str());
// m_node->Inputs.emplace_back(GetNextId(), "", PinType::Flow);
// m_node->Inputs.emplace_back(GetNextId(), "Condition", PinType::Bool);
// m_node->Outputs.emplace_back(GetNextId(), "True", PinType::Flow);
// m_node->Outputs.emplace_back(GetNextId(), "False", PinType::Flow);
}
void BaseNode::AddInput()
@ -21,9 +19,27 @@ void BaseNode::AddInput()
m_node->Inputs.emplace_back(GetNextId(), "", PinType::Flow);
}
void BaseNode::AddOutput()
void BaseNode::AddOutputs(int num)
{
m_node->Outputs.emplace_back(GetNextId(), "", PinType::Flow);
for (int i = 0; i < num; i++)
{
m_node->Outputs.emplace_back(GetNextId(), "", PinType::Flow);
}
}
void BaseNode::SetOutputs(uint32_t num)
{
if (num > Outputs())
{
AddOutputs(num - Outputs());
}
else if (num < Outputs())
{
for (unsigned int i = 0; i < (Outputs() - num); i++)
{
DeleteOutput();
}
}
}
void BaseNode::DeleteOutput()
@ -33,28 +49,20 @@ void BaseNode::DeleteOutput()
void BaseNode::SetPosition(int x, int y)
{
ed::SetNodePosition(m_node->ID, ImVec2(0, 0));
m_pos.x = x;
m_pos.y = y;
m_firstFrame = true;
}
void BaseNode::FrameStart()
{
ed::BeginNode(m_node->ID);
// ImGui::Text("Node A");
// for (auto& input : m_node->Inputs)
// {
// ed::BeginPin(input.ID, ed::PinKind::Input);
// ImGui::Text("-> In");
// ed::EndPin();
// }
// for (auto& output : m_node->Outputs)
// {
// ed::BeginPin(output.ID, ed::PinKind::Output);
// ImGui::Text("Out ->");
// ed::EndPin();
// }
if (m_firstFrame)
{
ed::SetNodePosition(m_node->ID, ImVec2(m_pos.x, m_pos.y));
}
m_firstFrame = false;
}
void BaseNode::FrameEnd()
@ -71,7 +79,7 @@ void BaseNode::DrawPins()
{
ed::BeginPin(input.ID, ed::PinKind::Input);
ImGui::Text( ICON_MDI_OCTAGON_OUTLINE " In" );
ImGui::Text( ICON_MDI_OCTAGON_OUTLINE " In" );
ed::EndPin();
}

View file

@ -6,6 +6,7 @@
#include <random>
#include <string>
#include "json.hpp"
#include "story_project.h"
#include <imgui_node_editor.h>
@ -100,7 +101,7 @@ public:
int y;
};
BaseNode(const std::string &title);
BaseNode(const std::string &title, StoryProject &proj);
virtual void Draw() = 0;
@ -114,12 +115,16 @@ public:
uint32_t Outputs() const { return m_node->Outputs.size(); }
void SetId(const std::string &id) { m_id = id; }
std::string GetId() const { return m_id; }
void SetId(const int id) { m_id = id; }
int GetId() const { return m_id; }
void seTitle(const std::string &title) { m_title = title; }
std::string getTitle() const { return m_title; }
virtual void FromJson(nlohmann::json &) {
// default implementation does nothing
}
virtual nlohmann::json ToJson() const {
nlohmann::json j;
@ -132,17 +137,51 @@ public:
return s_nextId++;
}
static void InitId() {
s_nextId = 1;
}
ed::PinId GetInputPinAt(int index)
{
ed::PinId id = -1;
if (index < static_cast<int>(m_node->Inputs.size()))
{
id = m_node->Inputs[index].ID;
}
return id;
}
ed::PinId GetOutputPinAt(int index)
{
ed::PinId id = -1;
if (index < static_cast<int>(m_node->Outputs.size()))
{
id = m_node->Outputs[index].ID;
}
return id;
}
void AddInput();
void AddOutput();
void AddOutputs(int num = 1);
void SetOutputs(uint32_t num);
void DeleteOutput();
private:
StoryProject &m_project;
std::unique_ptr<Node> m_node;
std::string m_title{"Base node"};
std::string m_type;
std::string m_id;
int m_id;
NodePosition m_pos;
bool m_firstFrame{true};
static int s_nextId;

View file

@ -3,6 +3,7 @@
#include <fstream>
CodeEditor::CodeEditor()
: WindowBase("Code editor")
{
}
@ -33,15 +34,15 @@ void CodeEditor::Initialize()
}
}
void CodeEditor::Draw(const char* title, bool* p_open)
void CodeEditor::Draw()
{
if (!IsVisible())
{
return;
}
WindowBase::BeginDraw();
auto cpos = mEditor.GetCursorPosition();
ImGui::Begin(title, p_open, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_MenuBar);
ImGui::SetWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);
if (ImGui::BeginMenuBar())
{
@ -104,5 +105,5 @@ void CodeEditor::Draw(const char* title, bool* p_open)
mEditor.GetLanguageDefinition().mName.c_str(), mFileToEdit.c_str());
mEditor.Render("TextEditor");
ImGui::End();
WindowBase::EndDraw();
}

View file

@ -8,7 +8,7 @@ class CodeEditor : public WindowBase
public:
CodeEditor();
void Draw(const char *title, bool *p_open);
virtual void Draw() override;
void Initialize();
private:

View file

@ -2,6 +2,7 @@
#include "gui.h"
EmulatorWindow::EmulatorWindow()
: WindowBase("Emulator")
{
}
@ -13,19 +14,17 @@ void EmulatorWindow::Initialize() {
}
void EmulatorWindow::Draw(const char *title, bool *p_open)
void EmulatorWindow::Draw()
{
if (!IsVisible())
{
return;
}
// if (!IsVisible())
// {
// return;
// }
ImGui::SetNextWindowSize(ImVec2(626, 744), ImGuiCond_FirstUseEver);
if (!ImGui::Begin(title, p_open))
{
ImGui::End();
return;
}
WindowBase::BeginDraw();
ImGui::SetWindowSize(ImVec2(626, 744), ImGuiCond_FirstUseEver);
// ImGui::Image((void*)(intptr_t)my_image_texture, ImVec2(313, 367));
@ -33,5 +32,5 @@ void EmulatorWindow::Draw(const char *title, bool *p_open)
ImVec2 p = ImGui::GetCursorScreenPos();
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + sz, p.y + sz), ImGui::GetColorU32(ImVec4(1.0, 1.0, 1.0, 1.0)));
ImGui::End();
WindowBase::EndDraw();
}

View file

@ -8,7 +8,7 @@ public:
EmulatorWindow();
void Initialize();
void Draw(const char* title, bool* p_open);
virtual void Draw() override;
private:

View file

@ -10,14 +10,14 @@ your use of the corresponding standard functions.
#include <stdio.h>
#include "imgui_impl_sdl3.h"
#include "imgui_impl_sdlrenderer3.h"
#include "imgui_impl_sdl2.h"
#include "imgui_impl_sdlrenderer2.h"
#include <stdio.h>
#include <SDL3/SDL.h>
#include <SDL2/SDL.h>
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <SDL3/SDL_opengles2.h>
#include <SDL2/SDL_opengles2.h>
#else
#include <SDL3/SDL_opengl.h>
#include <SDL2/SDL_opengl.h>
#endif
#include "IconsMaterialDesignIcons.h"
@ -46,7 +46,13 @@ bool LoadTextureFromFile(const char* filename, Gui::Image &img)
return false;
}
SDL_Surface* surface = SDL_CreateSurfaceFrom((void*)data, img.w, img.h, 4 * img.w, SDL_PIXELFORMAT_RGBA8888);
// SDL3
// SDL_Surface* surface = SDL_CreateSurfaceFrom((void*)data, img.w, img.h, 4 * img.w, SDL_PIXELFORMAT_RGBA8888);
// SDL2
SDL_Surface* surface = SDL_CreateRGBSurfaceFrom((void*)data, img.w, img.h, channels * 8, channels * img.w,
0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
if (surface == nullptr) {
fprintf(stderr, "Failed to create SDL surface: %s\n", SDL_GetError());
@ -59,7 +65,8 @@ bool LoadTextureFromFile(const char* filename, Gui::Image &img)
fprintf(stderr, "Failed to create SDL texture: %s\n", SDL_GetError());
}
SDL_DestroySurface(surface);
// SDL_DestroySurface(surface); // SDL3
SDL_FreeSurface(surface); // SDL2
stbi_image_free(data);
return true;
@ -76,7 +83,7 @@ Gui::Gui()
bool Gui::Initialize()
{
// Setup SDL
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD) != 0)
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
printf("Error: SDL_Init(): %s\n", SDL_GetError());
return -1;
@ -87,13 +94,19 @@ bool Gui::Initialize()
// Create window with SDL_Renderer graphics context
SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN);
window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", 1280, 720, window_flags);
// SDL3
//window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", 1280, 720, window_flags);
// SDL2
window = SDL_CreateWindow("Story Editor", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 720, window_flags);
if (window == nullptr)
{
printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
return -1;
}
renderer = SDL_CreateRenderer(window, NULL, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
if (renderer == nullptr)
{
SDL_Log("Error: SDL_CreateRenderer(): %s\n", SDL_GetError());
@ -139,8 +152,15 @@ bool Gui::Initialize()
//ImGui::StyleColorsLight();
// Setup Platform/Renderer backends
ImGui_ImplSDL3_InitForSDLRenderer(window, renderer);
ImGui_ImplSDLRenderer3_Init(renderer);
// SDL3
// ImGui_ImplSDL3_InitForSDLRenderer(window, renderer);
// ImGui_ImplSDLRenderer3_Init(renderer);
// SDL2
ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
ImGui_ImplSDLRenderer2_Init(renderer);
// Load Fonts
// - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
@ -169,11 +189,22 @@ bool Gui::PollEvent()
SDL_Event event;
while (SDL_PollEvent(&event))
{
// SDL3
/*
ImGui_ImplSDL3_ProcessEvent(&event);
if (event.type == SDL_EVENT_QUIT)
done = true;
if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window))
done = true;
*/
// SLD2
ImGui_ImplSDL2_ProcessEvent(&event);
if (event.type == SDL_QUIT)
done = true;
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
done = true;
}
return done;
@ -182,8 +213,15 @@ bool Gui::PollEvent()
void Gui::StartFrame()
{
// Start the Dear ImGui frame
ImGui_ImplSDLRenderer3_NewFrame();
ImGui_ImplSDL3_NewFrame();
// SDL3
// ImGui_ImplSDLRenderer3_NewFrame();
// ImGui_ImplSDL3_NewFrame();
// SDL2
ImGui_ImplSDLRenderer2_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
}
@ -192,19 +230,32 @@ void Gui::EndFrame()
static ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// Rendering
// Rendering
ImGui::Render();
//SDL_RenderSetScale(renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
SDL_SetRenderDrawColor(renderer, (Uint8)(clear_color.x * 255), (Uint8)(clear_color.y * 255), (Uint8)(clear_color.z * 255), (Uint8)(clear_color.w * 255));
SDL_RenderClear(renderer);
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData());
ImGui::Render();
//ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData()); // SDL3
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData()); // SDL2
SDL_RenderPresent(renderer);
}
void Gui::Destroy()
{
// Cleanup
ImGui_ImplSDLRenderer3_Shutdown();
ImGui_ImplSDL3_Shutdown();
// SDL3
// ImGui_ImplSDLRenderer3_Shutdown();
// ImGui_ImplSDL3_Shutdown();
// SDL2
ImGui_ImplSDLRenderer2_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
SDL_DestroyRenderer(renderer);

View file

@ -18,11 +18,14 @@ public:
int w;
int h;
std::string name;
bool valid() const {
return (w && h);
}
Image();
};
struct Size {

View file

@ -2,6 +2,9 @@
#include <filesystem>
#include <random>
#include "platform_folders.h"
#include "uuid.h"
#ifdef USE_WINDOWS_OS
#include <winsock2.h>
#include <iphlpapi.h>
@ -17,6 +20,7 @@
MainWindow::MainWindow()
: m_resourcesWindow(m_project)
, m_nodeEditorWindow(m_project)
{
m_project.Clear();
}
@ -26,7 +30,34 @@ MainWindow::~MainWindow()
}
void MainWindow::SetupMainMenuBar()
void MainWindow::DrawStatusBar()
{
float statusWindowHeight = ImGui::GetFrameHeight() * 1.4f;
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(ImVec2(viewport->Pos.x, viewport->Pos.y + viewport->Size.y - statusWindowHeight));
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, statusWindowHeight));
ImGui::SetNextWindowViewport(viewport->ID);
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoDocking;
ImGui::Begin("StatusBar", nullptr, windowFlags);
if (true)
{
float dy = ImGui::GetFontSize() * 0.15f;
ImGui::SameLine(ImGui::GetIO().DisplaySize.x - 14.f * ImGui::GetFontSize());
ImGui::SameLine();
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - dy);
ImGui::Text("FPS: %.1f", 1000.0f / ImGui::GetIO().Framerate);
}
ImGui::End();
}
void MainWindow::DrawMainMenuBar()
{
bool showAboutPopup = false;
bool showParameters = false;
@ -89,7 +120,13 @@ void MainWindow::SetupMainMenuBar()
if (showOpenProject)
{
ImGuiFileDialog::Instance()->OpenDialog("OpenProjectDlgKey", "Choose File", "project.json", ".", 1, nullptr, ImGuiFileDialogFlags_Modal);
std::string home = pf::getUserHome() + "/";
#ifdef DEBUG
home = "/home/anthony/ostproj/ba869e4b-03d6-4249-9202-85b4cec767a7/";
#endif
ImGuiFileDialog::Instance()->OpenDialog("OpenProjectDlgKey", "Choose File", ".json", home, 1, nullptr, ImGuiFileDialogFlags_Modal);
}
// Always center this window when appearing
@ -268,7 +305,6 @@ void MainWindow::OpenProjectDialog()
std::string filePathName = ImGuiFileDialog::Instance()->GetFilePathName();
std::string filePath = ImGuiFileDialog::Instance()->GetCurrentPath();
bool success = false;
m_project.Initialize(filePathName);
@ -276,38 +312,16 @@ void MainWindow::OpenProjectDialog()
if (m_project.Load(filePathName, model))
{
m_model.Load(model);
m_nodeEditorWindow.Load(model);
EnableProject();
}
else
{
qWarning() << errorMsg;
QMessageBox::critical(this, tr("Open project error"), errorMsg);
m_consoleWindow.AddMessage("Open project error");
}
m_resourceModel.EndChange();
RefreshProjectInformation();
/*
// action
std::filesystem::path p(filePathName);
std::filesystem::path p2 = m_project.AssetsPath() / p.filename().generic_string();
std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing);
Resource res;
std::string ext = p.extension().string();
ext.erase(ext.begin()); // remove '.' dot sign
std::transform(ext.begin(), ext.end(), ext.begin(), ::toupper);
res.format = ext;
res.type = m_soundFile ? "sound" : "image";
res.file = p.filename().generic_string();
m_project.AppendResource(res);
*/
// RefreshProjectInformation();
}
// close
@ -317,17 +331,17 @@ void MainWindow::OpenProjectDialog()
void MainWindow::EnableProject()
{
auto proj = m_project.GetProjectFilePath();
// Add to recent if not exists
if (!m_recentProjects.contains(m_project.GetProjectFilePath().c_str()))
if (std::find(m_recentProjects.begin(), m_recentProjects.end(), proj) != m_recentProjects.end())
{
m_recentProjects.push_front(m_project.GetProjectFilePath().c_str());
m_recentProjects.push_back(proj);
// Limit to 10 recent projects
if (m_recentProjects.size() > 10) {
m_recentProjects.pop_back();
}
m_toolbar->GenerateRecentProjectsMenu(m_recentProjects);
}
/*
m_ostHmiDock->Open();
m_resourcesDock->Open();
m_scriptEditorDock->Open();
@ -338,6 +352,7 @@ void MainWindow::EnableProject()
m_toolbar->SetActionsActive(true);
m_view->setEnabled(true);
*/
}
@ -570,14 +585,19 @@ void MainWindow::Loop()
gui.StartFrame();
ImGui::DockSpaceOverViewport(ImGui::GetMainViewport());
SetupMainMenuBar();
DrawMainMenuBar();
// DrawStatusBar();
// ------------ Draw all windows
m_consoleWindow.Draw("Console", nullptr);
m_emulatorWindow.Draw();
editor.Draw();
m_resourcesWindow.Draw();
m_nodeEditorWindow.Draw();
console.Draw("Console", nullptr);
m_emulatorWindow.Draw("Emulator", nullptr);
editor.Draw("Code Editor", nullptr);
m_resourcesWindow.Draw("Resources", nullptr);
m_nodeEditorWindow.Draw("Blueprint", nullptr);
ShowOptionsWindow();
NewProjectPopup();

View file

@ -96,7 +96,7 @@ private:
Gui gui;
EmulatorWindow m_emulatorWindow;
ConsoleWindow console;
ConsoleWindow m_consoleWindow;
CodeEditor editor;
ResourcesWindow m_resourcesWindow;
@ -118,7 +118,7 @@ private:
void SaveParams();
void LoadParams();
void SetupMainMenuBar();
void DrawMainMenuBar();
void ShowOptionsWindow();
bool ShowQuitConfirm();
@ -127,6 +127,7 @@ private:
void EnableProject();
void CloseProject();
void OpenProjectDialog();
void DrawStatusBar();
};
#endif // MAINWINDOW_H

View file

@ -2,16 +2,17 @@
namespace ed = ax::NodeEditor;
#include "IconsMaterialDesignIcons.h"
#include "IconsFontAwesome5_c.h"
MediaNode::MediaNode(const std::string &title)
: BaseNode(title)
MediaNode::MediaNode(const std::string &title, StoryProject &proj)
: BaseNode(title, proj)
, m_project(proj)
{
Gui::LoadRawImage("fairy.png", m_image);
// Create defaut one input and one output
AddInput();
AddOutput();
AddOutputs(1);
}
@ -24,7 +25,8 @@ void MediaNode::Draw()
ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_SizingFixedFit;
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(10.0f, 10.0f));
if (ImGui::BeginTable("table1", 1, flags)) {
if (ImGui::BeginTable("table1", 1, flags))
{
ImGui::TableNextRow();
ImU32 bg_color = ImGui::GetColorU32(ImVec4(0.3f, 0.3f, 0.7f, 1.0f));
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, bg_color);
@ -52,12 +54,12 @@ void MediaNode::Draw()
ImGui::Text("Image");
ImGui::SameLine();
ImGui::Text("image.png");
ImGui::Text("%s", m_image.name.c_str());
ImGui::SameLine();
bool do_select = false;
if (ImGui::Button("Select")) {
if (ImGui::Button("Select...")) {
do_select = true; // Instead of saying OpenPopup() here, we set this bool, which is used later in the Deferred Pop-up Section
}
@ -68,15 +70,19 @@ void MediaNode::Draw()
ImGui::Text("Sound");
ImGui::SameLine();
ImGui::Text("sound.mp3");
ImGui::Text("%s", m_soundName.c_str());
ImGui::SameLine();
bool do_select_sound = false;
if (ImGui::Button("Select")) {
do_select_sound = true; // Instead of saying OpenPopup() here, we set this bool, which is used later in the Deferred Pop-up Section
if (ImGui::Button("Play " ICON_MDI_PLAY))
{
m_project.PlaySoundFile(m_soundPath);
}
bool do_select_sound = false;
if (ImGui::Button("Select...")) {
do_select_sound = true; // Instead of saying OpenPopup() here, we set this bool, which is used later in the Deferred Pop-up Section
}
ImGui::AlignTextToFramePadding();
ImGui::Text("Hold to repeat:");
@ -87,11 +93,11 @@ void MediaNode::Draw()
uint32_t counter = Outputs();
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
ImGui::PushButtonRepeat(true);
std::string leftSingle = "##left" + GetId();
std::string leftSingle = "##left" + std::to_string(GetId());
if (ImGui::ArrowButton(leftSingle.c_str(), ImGuiDir_Left)) { if (counter > 1) counter--; }
ImGui::SameLine(0.0f, spacing);
std::string rightSingle = "##right" + GetId();
std::string rightSingle = "##right" + std::to_string(GetId());
if (ImGui::ArrowButton(rightSingle.c_str(), ImGuiDir_Right))
{
counter++;
@ -100,23 +106,27 @@ void MediaNode::Draw()
ImGui::SameLine();
ImGui::Text("%d", counter);
if (counter > Outputs())
{
for (int i = 0; i < (counter - Outputs()); i++)
{
AddOutput();
}
}
else if (counter < Outputs())
{
for (int i = 0; i < (Outputs() - counter); i++)
{
DeleteOutput();
}
}
SetOutputs(counter);
DrawPins();
BaseNode::FrameEnd();
}
/*
"internal-data": {
"image": "fairy.png",
"sound": "la_fee_luminelle.mp3"
},
*/
void MediaNode::FromJson(nlohmann::json &j)
{
m_image.name = j["image"].get<std::string>();
Gui::LoadRawImage(m_project.BuildFullAssetsPath(m_image.name), m_image);
m_soundName = j["sound"].get<std::string>();
m_soundPath = m_project.BuildFullAssetsPath(m_soundName);
}

View file

@ -13,11 +13,16 @@
class MediaNode : public BaseNode
{
public:
MediaNode(const std::string &title);
MediaNode(const std::string &title, StoryProject &proj);
void Draw() override;
virtual void FromJson(nlohmann::json &j) override;
private:
StoryProject &m_project;
Gui::Image m_image;
std::string m_soundName;
std::string m_soundPath;
};

View file

@ -1,15 +1,21 @@
#include "node_editor_window.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <iostream>
#include <cstdint>
#include <algorithm>
#include "IconsFontAwesome5_c.h"
#include "media_node.h"
#include "gui.h"
NodeEditorWindow::NodeEditorWindow()
NodeEditorWindow::NodeEditorWindow(StoryProject &proj)
: WindowBase("Node editor")
, m_project(proj)
{
registerNode<MediaNode>("media-node");
}
NodeEditorWindow::~NodeEditorWindow()
@ -24,15 +30,6 @@ void NodeEditorWindow::Initialize()
m_context = ed::CreateEditor(&config);
ed::SetCurrentEditor(m_context);
auto n1 = std::make_shared<MediaNode>("Branch");
n1->SetPosition(0, 0);
m_nodes.push_back(n1);
auto n2 = std::make_shared<MediaNode>("Branch 2");
n2->SetPosition(100, 100);
m_nodes.push_back(n2);
}
void NodeEditorWindow::Clear()
@ -40,45 +37,123 @@ void NodeEditorWindow::Clear()
m_nodes.clear();
}
void NodeEditorWindow::Draw(const char *title, bool *p_open)
void NodeEditorWindow::LoadNode(const nlohmann::json &nodeJson)
{
static bool resetDockspace = true;
float menuHeight = 0;
if(ImGui::BeginMainMenuBar())
try
{
menuHeight = ImGui::GetWindowSize().y;
int restoredNodeId = nodeJson["id"].get<int>();
nlohmann::json internalDataJson = nodeJson["internal-data"];
std::string type = nodeJson["type"].get<std::string>();
if (ImGui::BeginMenu("Actions"))
auto n = createNode(type, "", m_project);
if (n)
{
if(ImGui::MenuItem("Quit"))
{
// mEvent.ExitGame();
}
ImGui::EndMenu();
}
n->SetId(restoredNodeId);
nlohmann::json posJson = nodeJson["position"];
n->SetOutputs(nodeJson["outPortCount"].get<int>());
n->SetPosition(posJson["x"].get<int>(), posJson["y"].get<int>());
n->FromJson(internalDataJson);
ImGui::EndMainMenuBar();
m_nodes[restoredNodeId] = n;
}
else
{
throw std::logic_error(std::string("No registered model with name ") + type);
}
}
catch (std::exception& e)
{
std::cout << "ERROR: " << e.what() << std::endl;
}
static ImGuiWindowFlags window_flags = ImGuiWindowFlags_None;
}
if (ImGui::Begin("EditorView", NULL, window_flags))
ed::PinId NodeEditorWindow::GetInputPin(int modelNodeId, int pinIndex)
{
ed::PinId id = -1;
for (auto & n : m_nodes)
{
if (n.first == modelNodeId)
{
id = n.second->GetInputPinAt(pinIndex);
}
}
return id;
}
ed::PinId NodeEditorWindow::GetOutputPin(int modelNodeId, int pinIndex)
{
ed::PinId id = -1;
for (auto & n : m_nodes)
{
if (n.first == modelNodeId)
{
id = n.second->GetOutputPinAt(pinIndex);
}
}
return id;
}
void NodeEditorWindow::Load(const nlohmann::json &model)
{
nlohmann::json nodesJsonArray = model["nodes"];
BaseNode::InitId();
m_nodes.clear();
m_links.clear();
for (auto& element : nodesJsonArray) {
LoadNode(element);
}
std::cout << model.dump(4) << std::endl;
nlohmann::json connectionJsonArray = model["connections"];
for (auto& connection : connectionJsonArray)
{
auto conn = std::make_shared<LinkInfo>();
// our model
conn->model = connection.get<Connection>();
// ImGui stuff for links
conn->Id = 100000 + BaseNode::GetNextId();
conn->InputId = GetInputPin(conn->model.inNodeId, conn->model.inPortIndex);
conn->OutputId = GetOutputPin(conn->model.outNodeId, conn->model.outPortIndex);
// Since we accepted new link, lets add one to our list of links.
m_links.push_back(conn);
}
}
void NodeEditorWindow::Draw()
{
if (WindowBase::BeginDraw())
{
ed::SetCurrentEditor(m_context);
ed::Begin("My Editor", ImVec2(0.0, 0.0f));
for (auto & n : m_nodes)
for (const auto & n : m_nodes)
{
n->Draw();
n.second->Draw();
}
for (auto& linkInfo : m_Links)
for (const auto& linkInfo : m_links)
{
ed::Link(linkInfo.Id, linkInfo.InputId, linkInfo.OutputId);
ed::Link(linkInfo->Id, linkInfo->OutputId, linkInfo->InputId);
}
// Handle creation action, returns true if editor want to create new object (node or link)
@ -105,10 +180,10 @@ void NodeEditorWindow::Draw(const char *title, bool *p_open)
if (ed::AcceptNewItem())
{
// Since we accepted new link, lets add one to our list of links.
m_Links.push_back({ ed::LinkId(m_NextLinkId++), inputPinId, outputPinId });
// m_Links.push_back({ ed::LinkId(BaseNode::GetNextId()), inputPinId, outputPinId });
// Draw new link.
ed::Link(m_Links.back().Id, m_Links.back().InputId, m_Links.back().OutputId);
// ed::Link(m_Links.back().Id, m_Links.back().InputId, m_Links.back().OutputId);
}
// You may choose to reject connection between these nodes
@ -130,15 +205,10 @@ void NodeEditorWindow::Draw(const char *title, bool *p_open)
// If you agree that link can be deleted, accept deletion.
if (ed::AcceptDeletedItem())
{
// Then remove link from your data.
for (auto& link : m_Links)
{
if (link.Id == deletedLinkId)
{
m_Links.erase(&link);
break;
}
}
m_links.erase(std::remove_if(m_links.begin(),
m_links.end(),
[deletedLinkId](std::shared_ptr<LinkInfo> inf) { return inf->Id == deletedLinkId; }));
}
// You may reject link deletion by calling:
@ -153,7 +223,7 @@ void NodeEditorWindow::Draw(const char *title, bool *p_open)
}
ImGui::End();
WindowBase::EndDraw();
}
void NodeEditorWindow::ToolbarUI()

View file

@ -9,6 +9,8 @@
#include <imgui_node_editor.h>
#include "base_node.h"
#include "window_base.h"
#include "story_project.h"
#include "json.hpp"
namespace ed = ax::NodeEditor;
@ -27,26 +29,31 @@ class NodeEditorWindow : public WindowBase
public:
struct LinkInfo
{
// Stuff from ImGuiNodeEditor
ed::LinkId Id;
ed::PinId InputId;
ed::PinId OutputId;
// Stuff from the project.json file, our model
Connection model;
};
NodeEditorWindow();
NodeEditorWindow(StoryProject &proj);
~NodeEditorWindow();
void Draw(const char *title, bool *p_open);
virtual void Draw() override;
void Initialize();
void Clear();
void Load(const nlohmann::json &model);
private:
StoryProject &m_project;
ed::EditorContext* m_context = nullptr;
std::vector<std::shared_ptr<BaseNode>> m_nodes;
ImVector<LinkInfo> m_Links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
int m_NextLinkId = 100; // Counter to help generate link ids. In real application this will probably based on pointer to user data structure.
// key: Id
std::map<int, std::shared_ptr<BaseNode>> m_nodes;
std::vector<std::shared_ptr<LinkInfo>> m_links; // List of live links. It is dynamic unless you want to create read-only view over nodes.
void ToolbarUI();
@ -64,26 +71,34 @@ private:
output.Kind = PinKind::Output;
}
}
/*
void BuildNodes()
{
for (auto& node : m_Nodes)
BuildNode(&node);
template<class NodeType>
struct Factory {
static std::shared_ptr<BaseNode> create_func(const std::string &title, StoryProject &proj) {
return std::make_shared<NodeType>(title, proj);
}
};
typedef std::shared_ptr<BaseNode> (*GenericCreator)(const std::string &title, StoryProject &proj);
typedef std::map<std::string, GenericCreator> Registry;
Registry m_registry;
template<class Derived>
void registerNode(const std::string& key) {
m_registry.insert(typename Registry::value_type(key, Factory<Derived>::create_func));
}
Node* SpawnBranchNode()
{
m_Nodes.emplace_back(GetNextId(), "Branch");
m_Nodes.back().Inputs.emplace_back(GetNextId(), "", PinType::Flow);
m_Nodes.back().Inputs.emplace_back(GetNextId(), "Condition", PinType::Bool);
m_Nodes.back().Outputs.emplace_back(GetNextId(), "True", PinType::Flow);
m_Nodes.back().Outputs.emplace_back(GetNextId(), "False", PinType::Flow);
BuildNode(&m_Nodes.back());
return &m_Nodes.back();
std::shared_ptr<BaseNode> createNode(const std::string& key, const std::string &title, StoryProject &proj) {
typename Registry::const_iterator i = m_registry.find(key);
if (i == m_registry.end()) {
throw std::invalid_argument(std::string(__PRETTY_FUNCTION__) +
": key not registered");
}
else return i->second(title, proj);
}
*/
void LoadNode(const nlohmann::json &nodeJson);
ed::PinId GetInputPin(int modelNodeId, int pinIndex);
ed::PinId GetOutputPin(int modelNodeId, int pinIndex);
};

View file

@ -0,0 +1,468 @@
/*
Its is under the MIT license, to encourage reuse by cut-and-paste.
The original files are hosted here: https://github.com/sago007/PlatformFolders
Copyright (c) 2015-2016 Poul Sander
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "platform_folders.h"
#include <iostream>
#include <stdexcept>
#include <cstdio>
#include <cstdlib>
#ifndef _WIN32
#include <pwd.h>
#include <unistd.h>
/**
* Retrives the effective user's home dir.
* If the user is running as root we ignore the HOME environment. It works badly with sudo.
* Writing to $HOME as root implies security concerns that a multiplatform program cannot be assumed to handle.
* @return The home directory. HOME environment is respected for non-root users if it exists.
*/
static std::string getHome() {
std::string res;
int uid = getuid();
const char* homeEnv = std::getenv("HOME");
if ( uid != 0 && homeEnv) {
//We only acknowlegde HOME if not root.
res = homeEnv;
return res;
}
struct passwd* pw = nullptr;
struct passwd pwd;
long bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (bufsize < 0) {
bufsize = 16384;
}
std::vector<char> buffer;
buffer.resize(bufsize);
int error_code = getpwuid_r(uid, &pwd, buffer.data(), buffer.size(), &pw);
if (error_code) {
throw std::runtime_error("Unable to get passwd struct.");
}
const char* tempRes = pw->pw_dir;
if (!tempRes) {
throw std::runtime_error("User has no home directory");
}
res = tempRes;
return res;
}
#endif
#ifdef _WIN32
// Make sure we don't bring in all the extra junk with windows.h
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
// stringapiset.h depends on this
#include <windows.h>
// For SUCCEEDED macro
#include <winerror.h>
// For WideCharToMultiByte
#include <stringapiset.h>
// For SHGetFolderPathW and various CSIDL "magic numbers"
#include <shlobj.h>
namespace pf {
namespace internal {
std::string win32_utf16_to_utf8(const wchar_t* wstr) {
std::string res;
// If the 6th parameter is 0 then WideCharToMultiByte returns the number of bytes needed to store the result.
int actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, nullptr, 0, nullptr, nullptr);
if (actualSize > 0) {
//If the converted UTF-8 string could not be in the initial buffer. Allocate one that can hold it.
std::vector<char> buffer(actualSize);
actualSize = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, &buffer[0], static_cast<int>(buffer.size()), nullptr, nullptr);
res = buffer.data();
}
if (actualSize == 0) {
// WideCharToMultiByte return 0 for errors.
throw std::runtime_error("UTF16 to UTF8 failed with error code: " + std::to_string(GetLastError()));
}
return res;
}
} // namesapce internal
} // namespace pf
class FreeCoTaskMemory {
LPWSTR pointer = NULL;
public:
explicit FreeCoTaskMemory(LPWSTR pointer) : pointer(pointer) {};
~FreeCoTaskMemory() {
CoTaskMemFree(pointer);
}
};
static std::string GetKnownWindowsFolder(REFKNOWNFOLDERID folderId, const char* errorMsg) {
LPWSTR wszPath = NULL;
HRESULT hr;
hr = SHGetKnownFolderPath(folderId, KF_FLAG_CREATE, NULL, &wszPath);
FreeCoTaskMemory scopeBoundMemory(wszPath);
if (!SUCCEEDED(hr)) {
throw std::runtime_error(errorMsg);
}
return pf::internal::win32_utf16_to_utf8(wszPath);
}
static std::string GetAppData() {
return GetKnownWindowsFolder(FOLDERID_RoamingAppData, "RoamingAppData could not be found");
}
static std::string GetAppDataCommon() {
return GetKnownWindowsFolder(FOLDERID_ProgramData, "ProgramData could not be found");
}
static std::string GetAppDataLocal() {
return GetKnownWindowsFolder(FOLDERID_LocalAppData, "LocalAppData could not be found");
}
#elif defined(__APPLE__)
#else
#include <map>
#include <fstream>
#include <sys/types.h>
// For strlen and strtok
#include <cstring>
#include <sstream>
//Typically Linux. For easy reading the comments will just say Linux but should work with most *nixes
static void throwOnRelative(const char* envName, const char* envValue) {
if (envValue[0] != '/') {
char buffer[200];
std::snprintf(buffer, sizeof(buffer), "Environment \"%s\" does not start with an '/'. XDG specifies that the value must be absolute. The current value is: \"%s\"", envName, envValue);
throw std::runtime_error(buffer);
}
}
static std::string getLinuxFolderDefault(const char* envName, const char* defaultRelativePath) {
std::string res;
const char* tempRes = std::getenv(envName);
if (tempRes) {
throwOnRelative(envName, tempRes);
res = tempRes;
return res;
}
res = getHome() + "/" + defaultRelativePath;
return res;
}
static void appendExtraFolders(const char* envName, const char* defaultValue, std::vector<std::string>& folders) {
const char* envValue = std::getenv(envName);
if (!envValue) {
envValue = defaultValue;
}
pf::internal::appendExtraFoldersTokenizer(envName, envValue, folders);
}
#endif
namespace pf {
#if !defined(_WIN32) && !defined(__APPLE__)
namespace internal {
void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders) {
std::stringstream ss(envValue);
std::string value;
while (std::getline(ss, value, ':')) {
if (value[0] == '/') {
folders.push_back(value);
}
else {
//Unless the system is wrongly configured this should never happen... But of course some systems will be incorectly configured.
//The XDG documentation indicates that the folder should be ignored but that the program should continue.
std::cerr << "Skipping path \"" << value << "\" in \"" << envName << "\" because it does not start with a \"/\"\n";
}
}
}
}
#endif
std::string getDataHome() {
#ifdef _WIN32
return GetAppData();
#elif defined(__APPLE__)
return getHome()+"/Library/Application Support";
#else
return getLinuxFolderDefault("XDG_DATA_HOME", ".local/share");
#endif
}
std::string getConfigHome() {
#ifdef _WIN32
return GetAppData();
#elif defined(__APPLE__)
return getHome()+"/Library/Application Support";
#else
return getLinuxFolderDefault("XDG_CONFIG_HOME", ".config");
#endif
}
std::string getCacheDir() {
#ifdef _WIN32
return GetAppDataLocal();
#elif defined(__APPLE__)
return getHome()+"/Library/Caches";
#else
return getLinuxFolderDefault("XDG_CACHE_HOME", ".cache");
#endif
}
std::string getUserHome()
{
#ifdef _WIN32
return std::getenv("USERPROFILE");
#else
return getHome();
#endif
}
std::string getStateDir() {
#ifdef _WIN32
return GetAppDataLocal();
#elif defined(__APPLE__)
return getHome()+"/Library/Application Support";
#else
return getLinuxFolderDefault("XDG_STATE_HOME", ".local/state");
#endif
}
void appendAdditionalDataDirectories(std::vector<std::string>& homes) {
#ifdef _WIN32
homes.push_back(GetAppDataCommon());
#elif !defined(__APPLE__)
appendExtraFolders("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/", homes);
#endif
}
void appendAdditionalConfigDirectories(std::vector<std::string>& homes) {
#ifdef _WIN32
homes.push_back(GetAppDataCommon());
#elif !defined(__APPLE__)
appendExtraFolders("XDG_CONFIG_DIRS", "/etc/xdg", homes);
#endif
}
#if !defined(_WIN32) && !defined(__APPLE__)
struct PlatformFolders::PlatformFoldersData {
std::map<std::string, std::string> folders;
};
static void PlatformFoldersAddFromFile(const std::string& filename, std::map<std::string, std::string>& folders) {
std::ifstream infile(filename.c_str());
std::string line;
while (std::getline(infile, line)) {
if (line.length() == 0 || line.at(0) == '#' || line.substr(0, 4) != "XDG_" || line.find("_DIR") == std::string::npos) {
continue;
}
try {
std::size_t splitPos = line.find('=');
std::string key = line.substr(0, splitPos);
std::size_t valueStart = line.find('"', splitPos);
std::size_t valueEnd = line.find('"', valueStart+1);
std::string value = line.substr(valueStart+1, valueEnd - valueStart - 1);
folders[key] = value;
}
catch (std::exception& e) {
std::cerr << "WARNING: Failed to process \"" << line << "\" from \"" << filename << "\". Error: "<< e.what() << "\n";
continue;
}
}
}
static void PlatformFoldersFillData(std::map<std::string, std::string>& folders) {
folders["XDG_DOCUMENTS_DIR"] = "$HOME/Documents";
folders["XDG_DESKTOP_DIR"] = "$HOME/Desktop";
folders["XDG_DOWNLOAD_DIR"] = "$HOME/Downloads";
folders["XDG_MUSIC_DIR"] = "$HOME/Music";
folders["XDG_PICTURES_DIR"] = "$HOME/Pictures";
folders["XDG_PUBLICSHARE_DIR"] = "$HOME/Public";
folders["XDG_TEMPLATES_DIR"] = "$HOME/.Templates";
folders["XDG_VIDEOS_DIR"] = "$HOME/Videos";
PlatformFoldersAddFromFile( getConfigHome()+"/user-dirs.dirs", folders);
for (std::map<std::string, std::string>::iterator itr = folders.begin() ; itr != folders.end() ; ++itr ) {
std::string& value = itr->second;
if (value.compare(0, 5, "$HOME") == 0) {
value = getHome() + value.substr(5, std::string::npos);
}
}
}
#endif
PlatformFolders::PlatformFolders() {
#if !defined(_WIN32) && !defined(__APPLE__)
this->data = new PlatformFolders::PlatformFoldersData();
try {
PlatformFoldersFillData(data->folders);
}
catch (...) {
delete this->data;
throw;
}
#endif
}
PlatformFolders::~PlatformFolders() {
#if !defined(_WIN32) && !defined(__APPLE__)
delete this->data;
#endif
}
std::string PlatformFolders::getDocumentsFolder() const {
#ifdef _WIN32
return GetKnownWindowsFolder(FOLDERID_Documents, "Failed to find My Documents folder");
#elif defined(__APPLE__)
return getHome()+"/Documents";
#else
return data->folders["XDG_DOCUMENTS_DIR"];
#endif
}
std::string PlatformFolders::getDesktopFolder() const {
#ifdef _WIN32
return GetKnownWindowsFolder(FOLDERID_Desktop, "Failed to find Desktop folder");
#elif defined(__APPLE__)
return getHome()+"/Desktop";
#else
return data->folders["XDG_DESKTOP_DIR"];
#endif
}
std::string PlatformFolders::getPicturesFolder() const {
#ifdef _WIN32
return GetKnownWindowsFolder(FOLDERID_Pictures, "Failed to find My Pictures folder");
#elif defined(__APPLE__)
return getHome()+"/Pictures";
#else
return data->folders["XDG_PICTURES_DIR"];
#endif
}
std::string PlatformFolders::getPublicFolder() const {
#ifdef _WIN32
return GetKnownWindowsFolder(FOLDERID_Public, "Failed to find the Public folder");
#elif defined(__APPLE__)
return getHome()+"/Public";
#else
return data->folders["XDG_PUBLICSHARE_DIR"];
#endif
}
std::string PlatformFolders::getDownloadFolder1() const {
#ifdef _WIN32
return GetKnownWindowsFolder(FOLDERID_Downloads, "Failed to find My Downloads folder");
#elif defined(__APPLE__)
return getHome()+"/Downloads";
#else
return data->folders["XDG_DOWNLOAD_DIR"];
#endif
}
std::string PlatformFolders::getMusicFolder() const {
#ifdef _WIN32
return GetKnownWindowsFolder(FOLDERID_Music, "Failed to find My Music folder");
#elif defined(__APPLE__)
return getHome()+"/Music";
#else
return data->folders["XDG_MUSIC_DIR"];
#endif
}
std::string PlatformFolders::getVideoFolder() const {
#ifdef _WIN32
return GetKnownWindowsFolder(FOLDERID_Videos, "Failed to find My Video folder");
#elif defined(__APPLE__)
return getHome()+"/Movies";
#else
return data->folders["XDG_VIDEOS_DIR"];
#endif
}
std::string PlatformFolders::getSaveGamesFolder1() const {
#ifdef _WIN32
//A dedicated Save Games folder was not introduced until Vista. For XP and older save games are most often saved in a normal folder named "My Games".
//Data that should not be user accessible should be placed under GetDataHome() instead
return GetKnownWindowsFolder(FOLDERID_Documents, "Failed to find My Documents folder")+"\\My Games";
#elif defined(__APPLE__)
return getHome()+"/Library/Application Support";
#else
return getDataHome();
#endif
}
std::string getDesktopFolder() {
return PlatformFolders().getDesktopFolder();
}
std::string getDocumentsFolder() {
return PlatformFolders().getDocumentsFolder();
}
std::string getDownloadFolder() {
return PlatformFolders().getDownloadFolder1();
}
std::string getDownloadFolder1() {
return getDownloadFolder();
}
std::string getPicturesFolder() {
return PlatformFolders().getPicturesFolder();
}
std::string getPublicFolder() {
return PlatformFolders().getPublicFolder();
}
std::string getMusicFolder() {
return PlatformFolders().getMusicFolder();
}
std::string getVideoFolder() {
return PlatformFolders().getVideoFolder();
}
std::string getSaveGamesFolder1() {
return PlatformFolders().getSaveGamesFolder1();
}
std::string getSaveGamesFolder2() {
#ifdef _WIN32
return GetKnownWindowsFolder(FOLDERID_SavedGames, "Failed to find Saved Games folder");
#else
return PlatformFolders().getSaveGamesFolder1();
#endif
}
} //namespace pf

View file

@ -0,0 +1,290 @@
/*
Its is under the MIT license, to encourage reuse by cut-and-paste.
The original files are hosted here: https://github.com/sago007/PlatformFolders
Copyright (c) 2015 Poul Sander
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#ifndef PLATFORM_FOLDERS_H
#define PLATFORM_FOLDERS_H
#include <vector>
#include <string>
/**
* The namespace I use for common function. Nothing special about it.
*/
namespace pf {
#ifndef DOXYGEN_SHOULD_SKIP_THIS
namespace internal {
#if !defined(_WIN32) && !defined(__APPLE__)
void appendExtraFoldersTokenizer(const char* envName, const char* envValue, std::vector<std::string>& folders);
#endif
#ifdef _WIN32
std::string win32_utf16_to_utf8(const wchar_t* wstr);
#endif
}
#endif //DOXYGEN_SHOULD_SKIP_THIS
/**
* Retrives the base folder for storing data files.
* You must add the program name yourself like this:
* @code{.cpp}
* string data_home = getDataHome()+"/My Program Name/";
* @endcode
* On Windows this defaults to %APPDATA% (Roaming profile)
* On Linux this defaults to ~/.local/share but can be configured by the user
* @return The base folder for storing program data.
*/
std::string getDataHome();
std::string getUserHome();
/**
* Retrives the base folder for storing config files.
* You must add the program name yourself like this:
* @code{.cpp}
* string data_home = getConfigHome()+"/My Program Name/";
* @endcode
* On Windows this defaults to %APPDATA% (Roaming profile)
* On Linux this defaults to ~/.config but can be configured by the user
* @return The base folder for storing config data.
*/
std::string getConfigHome();
/**
* Retrives the base folder for storing cache files.
* You must add the program name yourself like this:
* @code{.cpp}
* string data_home = getCacheDir()+"/My Program Name/cache/";
* @endcode
* On Windows this defaults to %APPDATALOCAL%
* On Linux this defaults to ~/.cache but can be configured by the user
* Note that it is recommended to append "cache" after the program name to prevent conflicting with "StateDir" under Windows
* @return The base folder for storing data that do not need to be backed up and might be deleted.
*/
std::string getCacheDir();
/**
* Retrives the base folder used for state files.
* You must add the program name yourself like this:
* @code{.cpp}
* string data_home = getStateDir()+"/My Program Name/";
* @endcode
* On Windows this defaults to %APPDATALOCAL%
* On Linux this defaults to ~/.local/state but can be configured by the user
* On OS X this is the same as getDataHome()
* @return The base folder for storing data that do not need to be backed up but should not be reguarly deleted either.
*/
std::string getStateDir();
/**
* This will append extra folders that your program should be looking for data files in.
* This does not normally include the path returned by GetDataHome().
* If you want all the folders you should do something like:
* @code{.cpp}
* vector<string> folders;
* folders.push_back(getDataHome());
* appendAdditionalDataDirectories(folders);
* for (string s& : folders) {
* s+="/My Program Name/";
* }
* @endcode
* You must apply "/My Program Name/" to all the strings.
* The string at the lowest index has the highest priority.
* @param homes A vector that extra folders will be appended to.
*/
void appendAdditionalDataDirectories(std::vector<std::string>& homes);
/**
* This will append extra folders that your program should be looking for config files in.
* This does not normally include the path returned by GetConfigHome().
* If you want all the folders you should do something like:
* @code{.cpp}
* std::vector<std::string> folders;
* folders.push_back(pf::getConfigHome());
* pf::appendAdditionalConfigDirectories(folders);
* for (std::string s& : folders) {
* s+="/My Program Name/";
* }
* @endcode
* You must apply "/My Program Name/" to all the strings.
* The string at the lowest index has the highest priority.
* @param homes A vector that extra folders will be appended to.
*/
void appendAdditionalConfigDirectories(std::vector<std::string>& homes);
/**
* The folder that represents the desktop.
* Normally you should try not to use this folder.
* @return Absolute path to the user's desktop
*/
std::string getDesktopFolder();
/**
* The folder to store user documents to
* @return Absolute path to the "Documents" folder
*/
std::string getDocumentsFolder();
/**
* The folder where files are downloaded.
* @return Absolute path to the folder where files are downloaded to.
*/
std::string getDownloadFolder();
/**
* The folder where files are downloaded.
* @note This is provided for backward compatibility. Use getDownloadFolder instead.
* @return Absolute path to the folder where files are downloaded to.
*/
std::string getDownloadFolder1();
/**
* The folder for storing the user's pictures.
* @return Absolute path to the "Picture" folder
*/
std::string getPicturesFolder();
/**
* This returns the folder that can be used for sharing files with other users on the same system.
* @return Absolute path to the "Public" folder
*/
std::string getPublicFolder();
/**
* The folder where music is stored
* @return Absolute path to the music folder
*/
std::string getMusicFolder();
/**
* The folder where video is stored
* @return Absolute path to the video folder
*/
std::string getVideoFolder();
/**
* A base folder for storing saved games.
* You must add the program name to it like this:
* @code{.cpp}
* string saved_games_folder = pf::getSaveGamesFolder1()+"/My Program Name/";
* @endcode
* @note Windows: This is an XP compatible version and returns the path to "My Games" in Documents. Vista and later has an official folder.
* @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome()
* @return The folder base folder for storing save games.
*/
std::string getSaveGamesFolder1();
/**
* A base folder for storing saved games.
* You must add the program name to it like this:
* @code{.cpp}
* string saved_games_folder = pf::getSaveGamesFolder2()+"/My Program Name/";
* @endcode
* @note PlatformFolders provide different folders to for saved games as not all operating systems has support for Saved Games yet.
* It is recommended to pick the highest number (currently getSaveGamesFolder2) at the time your product enters production and stick with it
* @note Windows: This returns the "Saved Games" folder. This folder exist in Vista and later
* @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome()
* @return The folder base folder for storing save games.
*/
std::string getSaveGamesFolder2();
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/**
* This class contains methods for finding the system depended special folders.
* For Windows these folders are either by convention or given by CSIDL.
* For Linux XDG convention is used.
* The Linux version has very little error checking and assumes that the config is correct
*/
class PlatformFolders {
public:
PlatformFolders();
~PlatformFolders();
/**
* The folder that represents the desktop.
* Normally you should try not to use this folder.
* @return Absolute path to the user's desktop
*/
std::string getDesktopFolder() const;
/**
* The folder to store user documents to
* @return Absolute path to the "Documents" folder
*/
std::string getDocumentsFolder() const;
/**
* The folder for storing the user's pictures.
* @return Absolute path to the "Picture" folder
*/
std::string getPicturesFolder() const;
/**
* Use pf::getPublicFolder() instead!
*/
std::string getPublicFolder() const;
/**
* The folder where files are downloaded.
* @note Windows: This version is XP compatible and returns the Desktop. Vista and later has a dedicated folder.
* @return Absolute path to the folder where files are downloaded to.
*/
std::string getDownloadFolder1() const;
/**
* The folder where music is stored
* @return Absolute path to the music folder
*/
std::string getMusicFolder() const;
/**
* The folder where video is stored
* @return Absolute path to the video folder
*/
std::string getVideoFolder() const;
/**
* The base folder for storing saved games.
* You must add the program name to it like this:
* @code{.cpp}
* PlatformFolders pf;
* string saved_games_folder = pf.getSaveGamesFolder1()+"/My Program Name/";
* @endcode
* @note Windows: This is an XP compatible version and returns the path to "My Games" in Documents. Vista and later has an official folder.
* @note Linux: XDF does not define a folder for saved games. This will just return the same as GetDataHome()
* @return The folder base folder for storing save games.
*/
std::string getSaveGamesFolder1() const;
private:
PlatformFolders(const PlatformFolders&);
PlatformFolders& operator=(const PlatformFolders&);
#if !defined(_WIN32) && !defined(__APPLE__)
struct PlatformFoldersData;
PlatformFoldersData* data;
#endif
};
#endif // skip doxygen
} //namespace pf
#endif /* PLATFORM_FOLDERS_H */

View file

@ -7,7 +7,8 @@
//static thread_pool pool;
ResourcesWindow::ResourcesWindow(StoryProject &project)
: m_project(project)
: WindowBase("Resources")
, m_project(project)
{
}
@ -62,11 +63,9 @@ void ResourcesWindow::ChooseFile()
}
void ResourcesWindow::Draw(const char *title, bool *p_open)
void ResourcesWindow::Draw()
{
(void) p_open;
ImGui::Begin(title, nullptr);
WindowBase::BeginDraw();
if (ImGui::Button("Add sound"))
@ -99,9 +98,11 @@ void ResourcesWindow::Draw(const char *title, bool *p_open)
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupColumn("Delete", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableHeadersRow();
for (auto & r : m_project)
{
ImGui::TableHeadersRow();
ImGui::TableNextColumn();
ImGui::Text("%s", r.file.c_str());
@ -121,6 +122,6 @@ void ResourcesWindow::Draw(const char *title, bool *p_open)
ImGui::EndTable();
}
ImGui::End();
WindowBase::EndDraw();
}

View file

@ -4,13 +4,14 @@
#include <map>
#include <mutex>
#include "story_project.h"
#include "window_base.h"
class ResourcesWindow
class ResourcesWindow : public WindowBase
{
public:
ResourcesWindow(StoryProject &project);
~ResourcesWindow();
void Draw(const char *title, bool *p_open);
virtual void Draw() override;
private:
StoryProject &m_project;

View file

@ -444,3 +444,24 @@ std::string StoryProject::GetWorkingDir() const
return m_working_dir.string();
}
std::string StoryProject::BuildFullAssetsPath(const std::string &fileName) const
{
return (AssetsPath() / fileName).generic_string();
}
void to_json(nlohmann::json &j, const Connection &p) {
j = nlohmann::json{
{"outNodeId", static_cast<int64_t>(p.outNodeId)},
{"outPortIndex", static_cast<int64_t>(p.outPortIndex)},
{"inNodeId", static_cast<int64_t>(p.inNodeId)},
{"inPortIndex", static_cast<int64_t>(p.inPortIndex)},
};
}
void from_json(const nlohmann::json &j, Connection &p) {
j.at("outNodeId").get_to(p.outNodeId);
j.at("outPortIndex").get_to(p.outPortIndex);
j.at("inNodeId").get_to(p.inNodeId);
j.at("inPortIndex").get_to(p.inPortIndex);
}

View file

@ -48,53 +48,34 @@ struct AudioCommand {
};
// Encaasulate the genaeration of a Version 4 UUID object
// A Version 4 UUID is a universally unique identifier that is generated using random numbers.
class UUID
struct Connection
{
public:
UUID() { New(); }
// Factory method for creating UUID object.
void New()
{
std::random_device rd;
std::mt19937 engine{rd()};
std::uniform_int_distribution<int> dist{0, 256}; //Limits of the interval
for (int index = 0; index < 16; ++index)
{
_data[index] = (unsigned char)dist(engine);
}
_data[6] = ((_data[6] & 0x0f) | 0x40); // Version 4
_data[8] = ((_data[8] & 0x3f) | 0x80); // Variant is 10
}
// Returns UUID as formatted string
std::string String()
{
// Formats to "0065e7d7-418c-4da4-b4d6-b54b6cf7466a"
char buffer[256] = {0};
std::snprintf(buffer, 255,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
_data[0], _data[1], _data[2], _data[3],
_data[4], _data[5],
_data[6], _data[7],
_data[8], _data[9],
_data[10], _data[11], _data[12], _data[13], _data[14], _data[15]);
std::string uuid = buffer;
return uuid;
}
unsigned char _data[16] = {0};
int outNodeId;
int outPortIndex;
int inNodeId;
int inPortIndex;
};
inline bool operator==(Connection const &a, Connection const &b)
{
return a.outNodeId == b.outNodeId && a.outPortIndex == b.outPortIndex
&& a.inNodeId == b.inNodeId && a.inPortIndex == b.inPortIndex;
}
inline bool operator!=(Connection const &a, Connection const &b)
{
return !(a == b);
}
inline void invertConnection(Connection &id)
{
std::swap(id.outNodeId, id.inNodeId);
std::swap(id.outPortIndex, id.inPortIndex);
}
void to_json(nlohmann::json& j, const Connection& p);
void from_json(const nlohmann::json& j, Connection& p);
// FIXME : Structure très Lunii style, à utiliser pour la conversion peut-être ...
@ -173,6 +154,8 @@ struct StoryProject
std::string GetName() const { return m_name; }
std::string GetUuid() const { return m_uuid; }
std::string BuildFullAssetsPath(const std::string &fileName) const;
std::filesystem::path AssetsPath() const { return m_assetsPath; }
static std::string GetFileExtension(const std::string &FileName);

View file

@ -0,0 +1,54 @@
#ifndef UUID_H
#define UUID_H
#include <string>
#include <random>
// Encaasulate the genaeration of a Version 4 UUID object
// A Version 4 UUID is a universally unique identifier that is generated using random numbers.
class UUID
{
public:
UUID() { New(); }
// Factory method for creating UUID object.
void New()
{
std::random_device rd;
std::mt19937 engine{rd()};
std::uniform_int_distribution<int> dist{0, 256}; //Limits of the interval
for (int index = 0; index < 16; ++index)
{
_data[index] = (unsigned char)dist(engine);
}
_data[6] = ((_data[6] & 0x0f) | 0x40); // Version 4
_data[8] = ((_data[8] & 0x3f) | 0x80); // Variant is 10
}
// Returns UUID as formatted string
std::string String()
{
// Formats to "0065e7d7-418c-4da4-b4d6-b54b6cf7466a"
char buffer[256] = {0};
std::snprintf(buffer, 255,
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
_data[0], _data[1], _data[2], _data[3],
_data[4], _data[5],
_data[6], _data[7],
_data[8], _data[9],
_data[10], _data[11], _data[12], _data[13], _data[14], _data[15]);
std::string uuid = buffer;
return uuid;
}
unsigned char _data[16] = {0};
};
#endif // UUID_H

View file

@ -0,0 +1,31 @@
#include "window_base.h"
#include "imgui.h"
WindowBase::WindowBase(const std::string &title)
: m_title(title)
{
}
bool WindowBase::BeginDraw()
{
bool ok = ImGui::Begin(m_title.c_str(), nullptr);
if (m_disabled)
{
ImGui::BeginDisabled();
}
return ok;
}
void WindowBase::EndDraw()
{
ImGui::End();
if (m_disabled)
{
ImGui::EndDisabled();
}
}

View file

@ -1,25 +1,26 @@
#ifndef WINDOW_BASE_H
#define WINDOW_BASE_H
#ifndef WINDOWBASE_H
#define WINDOWBASE_H
#include <string>
class WindowBase
{
public:
WindowBase(bool display = false)
{
mDisplay = display;
WindowBase(const std::string &title);
bool IsDisabled() const {
return m_disabled;
}
void SetVisible(bool enable)
{
mDisplay = enable;
}
virtual void Draw() = 0;
bool BeginDraw();
void EndDraw();
bool IsVisible() const {
return mDisplay;
}
private:
bool mDisplay;
bool m_disabled{false};
std::string m_title;
};
#endif // WINDOW_BASE_H
#endif // WINDOWBASE_H