Begin working on a recent files list. Add test data.

master
poikilos 2021-03-21 01:42:48 -04:00
parent 128f629335
commit 320d13c46f
12 changed files with 213 additions and 55 deletions

View File

@ -72,14 +72,16 @@ void Engine::setEnableTextureInterpolation(bool EnableTextureInterpolation)
void Engine::addRecent(std::string path)
{
int count = this->countRecent();
std::string name = "recent" + std::to_string(count);
this->settings.set(name, path);
if (!this->hasRecent(path)) {
int count = this->countRecent();
std::string name = "recent" + std::to_string(count);
this->settings.set(name, path);
}
}
void Engine::addRecentPaths(std::vector<std::string> paths)
{
for (std::vector<std::string>::iterator it = paths.begin() ; it != paths.end(); ++it) {
for (std::vector<std::string>::iterator it = paths.begin(); it != paths.end(); ++it) {
this->addRecent(*it);
}
}
@ -93,6 +95,24 @@ int Engine::countRecent()
return count;
}
bool Engine::hasRecent(std::string path) {
int count = 0;
while (true) {
bool found = false;
std::string value = this->settings.get("recent" + std::to_string(count), found);
if (found) {
if (value == path) {
break;
}
count++;
}
else {
break;
}
}
return false;
}
std::vector<std::string> Engine::recentPaths()
{
std::vector<std::string> results;
@ -336,6 +356,9 @@ Engine::Engine()
}
if (appdatas.length() > 0) {
myAppData = appdatas + path_separator_s + std::string("b3view");
if (!Utility::is_directory(myAppData)) {
Utility::create_directory(myAppData);
}
}
std::string settingsName = "settings.conf";
std::string settingsPath = settingsName;

View File

@ -104,6 +104,7 @@ public:
void addRecentPaths(std::vector<std::string> paths);
int countRecent();
std::vector<std::string> recentPaths();
bool hasRecent(std::string path);
};
#endif // ENGINE_H

View File

@ -1,4 +1,8 @@
#include "Debug.h"
#include "Engine.h"
#include "Utility.h"
#include "UserInterface.h"
#include <algorithm>
#include <iostream>
#include <string>
@ -8,9 +12,6 @@
// #include <filesystem> // requires C++17
#include <experimental/filesystem> // requires C++14 such as gcc 8.2.1
#include "Debug.h"
#include "Engine.h"
#include "Utility.h"
using namespace irr;
using namespace irr::core;
@ -24,6 +25,9 @@ using namespace std;
// namespace fs = std::filesystem; // doesn't work (not a namespace in gcc's C++17)
// using namespace std::filesystem; // doesn't work (not a namespace in gcc's C++17)
namespace fs = std::experimental::filesystem;
// namespace fs = std::filesystem; // doesn't work (not a namespace in gcc's C++17)
const u32 UserInterface::UIC_FILE_RECENT_FIRST = UIE_RECENTMENU + 1;
// PRIVATE
void UserInterface::setupUserInterface()
@ -39,7 +43,6 @@ void UserInterface::setupUserInterface()
fileMenu->addItem(L"Open", UIC_FILE_OPEN);
this->fileRecentIdx = fileMenu->addItem(L"Open Recent", UIC_FILE_RECENT, true, true);
std::vector<std::string> recentPaths = this->m_Engine->recentPaths();
this->addRecentPaths(recentPaths);
fileMenu->addItem(L"Change Texture", UIC_FILE_OPEN_TEXTURE);
fileMenu->addItem(L"Previous Texture Shift F3", UIC_FILE_PREVIOUS_TEXTURE);
fileMenu->addItem(L"Next Texture F3", UIC_FILE_NEXT_TEXTURE);
@ -54,11 +57,12 @@ void UserInterface::setupUserInterface()
this->recentMenu = fileMenu->getSubMenu(this->fileRecentIdx);
this->recentMenu->addItem(L"Clear Recent", UIC_FILE_RECENT_CLEAR);
this->uic_file_recent_first = UIC_FILE_RECENT_CLEAR + 1;
this->uic_file_recent_next = this->uic_file_recent_first;
this->uic_file_recent_next = UserInterface::UIC_FILE_RECENT_FIRST;
this->m_file_recent_first_idx = -1;
this->m_file_recent_last_idx = -1;
this->recent_initialized = true;
this->addRecentMenuItems(recentPaths, false);
// Playback Menu
playbackMenu = menu->getSubMenu(1);
@ -503,6 +507,7 @@ void UserInterface::snapWidgets()
// PUBLIC
UserInterface::UserInterface(Engine* engine)
{
this->recent_initialized = false;
viewTextureInterpolationIdx = 0;
viewWireframeIdx = 0;
viewLightingIdx = 0;
@ -776,21 +781,31 @@ void UserInterface::exportMeshToHome(std::string extension)
void UserInterface::clearRecent()
{
// for (int idx=this->uic_file_recent_next-1; idx>=this->uic_file_recent_first; idx--) {
// for (int idx=this->uic_file_recent_next-1; idx>=UserInterface::uic_file_recent_first; idx--) {
for (std::vector<u32>::iterator idxIt = this->recentIndices.begin(); idxIt != this->recentIndices.end(); ++idxIt) {
this->recentMenu->removeItem(*idxIt);
}
this->recentIndices.clear();
this->uic_file_recent_next = this->uic_file_recent_first;
this->uic_file_recent_next = UserInterface::UIC_FILE_RECENT_FIRST;
this->m_file_recent_first_idx = -1;
this->m_file_recent_last_idx = -1;
}
void UserInterface::addRecent(std::string path)
void UserInterface::addRecentMenuItem(std::string path, bool addToEngine)
{
if (!this->recent_initialized) {
throw std::string("The UI is not ready in addRecent.");
}
if (!this->hasRecent(path)) {
u32 newI = this->recentMenu->addItem(Utility::toWstring(path).c_str(), this->uic_file_recent_next);
IGUIContextMenu* menu = this->recentMenu->getSubMenu(newI);
wstring path_ws = Utility::toWstring(path);
if (this->uic_file_recent_next < UserInterface::UIC_FILE_RECENT_FIRST) {
throw std::string("this->uic_file_recent_next is "
+ std::to_string(this->uic_file_recent_next)
+ " but should be equal to or greater than first: "
+ std::to_string(this->uic_file_recent_next));
}
u32 newI = this->recentMenu->addItem(path_ws.c_str(), this->uic_file_recent_next);
// IGUIContextMenu* menu = this->recentMenu->getSubMenu(newI);
this->recentIndices.push_back(newI);
this->uic_file_recent_next += 1;
/*
@ -803,19 +818,32 @@ void UserInterface::addRecent(std::string path)
}
}
void UserInterface::addRecentPaths(std::vector<std::string> paths)
void UserInterface::addRecentMenuItems(std::vector<std::string> paths, bool addToEngine)
{
if (!this->recent_initialized) {
throw std::string("The UI is not ready in addRecent.");
}
for (std::vector<std::string>::iterator it = paths.begin() ; it != paths.end(); ++it) {
this->addRecent(*it);
this->addRecentMenuItem(*it, addToEngine);
}
}
bool UserInterface::hasRecent(std::string path)
{
if (!this->recent_initialized) {
throw std::string("The UI is not ready in addRecent.");
}
for (std::vector<u32>::iterator uiIt = this->recentIndices.begin() ; uiIt != this->recentIndices.end(); ++uiIt) {
IGUIContextMenu* menu = this->recentMenu->getSubMenu(*uiIt);
if (Utility::toString(menu->getText()) == path) {
return true;
if (menu != nullptr) {
if (Utility::toString(menu->getText()) == path) {
return true;
}
}
else {
const std::string msg = "There was no menu for " + std::to_string(*uiIt) + " in hasRecent";
cerr << msg << endl;
throw std::string(msg);
}
}
return false;
@ -823,6 +851,9 @@ bool UserInterface::hasRecent(std::string path)
void UserInterface::openRecent(s32 menuID, std::wstring menuText)
{
if (!this->recent_initialized) {
throw std::string("The UI is not ready in addRecent.");
}
IGUIElement* menu = this->recentMenu->getElementFromId(menuID);
std::string path = Utility::toString(menu->getText());
cerr << "path: " << path << endl;
@ -868,7 +899,7 @@ bool UserInterface::OnEvent(const SEvent& event)
else {
result = m_Engine->loadMesh(fileOpenDialog->getFileName());
}
this->addRecent(Utility::toString(path));
this->addRecentMenuItem(Utility::toString(path), true);
if (!result) {
this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox(
@ -968,6 +999,7 @@ bool UserInterface::OnEvent(const SEvent& event)
}
break;
case UIE_RECENTMENU:
cerr << "called UIE_RECENTMENU unexpectedly for \"" << ge->Caller->getText() << "\"" << endl;
break;
default:
// if ((ge->Caller->getID() >= this->m_file_recent_first_idx)
@ -977,7 +1009,8 @@ bool UserInterface::OnEvent(const SEvent& event)
this->openRecent(callerID, ge->Caller->getText());
}
else {
cerr << "Unknown caller id: " << callerID << endl;
cerr << "Unknown caller id: " << callerID << " Text:" << ge->Caller->getText() << endl;
handled = false;
}
}

View File

@ -69,7 +69,7 @@ enum UserInterfaceCommands {
class UserInterface : public irr::IEventReceiver {
private:
irr::s32 spacing_y;
irr::u32 uic_file_recent_first;
static const irr::u32 UIC_FILE_RECENT_FIRST;
irr::u32 uic_file_recent_next;
irr::s32 m_file_recent_first_idx;
irr::s32 m_file_recent_last_idx;
@ -77,6 +77,7 @@ private:
irr::gui::IGUIEnvironment* m_Gui;
irr::gui::CGUITTFont* m_GuiFont;
irr::gui::CGUITTFace* m_GuiFontFace;
bool recent_initialized;
void setupUserInterface();
void displayLoadFileDialog();
@ -128,8 +129,8 @@ public:
bool loadNextTexture(int direction);
void exportMeshToHome(std::string extension);
void clearRecent();
void addRecent(std::string path);
void addRecentPaths(std::vector<std::string> paths);
void addRecentMenuItem(std::string path, bool addToEngine);
void addRecentMenuItems(std::vector<std::string> paths, bool addToEngine);
bool hasRecent(std::string path);
void openRecent(irr::s32 menuID, std::wstring menuText);
bool OnSelectMesh();

View File

@ -1,16 +1,29 @@
#include "Debug.h"
#include "Utility.h"
#include <algorithm>
#include <clocale>
#include <cmath>
#include <cwctype> // #include <cwtype>
#include <iostream>
#include <filesystem>
#include <locale>
#include <sstream>
#include <string>
#include <vector>
#include <assert.h>
#include <sys/stat.h>
// NOTE: to use filesystem, you must also include the fs library such
// as via the `-lstdc++fs` linker option -- see b3view.pro
// #include <filesystem> // requires C++17
#include <experimental/filesystem> // requires C++14 such as gcc 8.2.1
#include "Debug.h"
// C++14: namespace filesystem = std::experimental::filesystem;
// namespace fs = std::filesystem; // doesn't work (not a namespace in gcc's C++17)
// using namespace std::filesystem; // doesn't work (not a namespace in gcc's C++17)
namespace fs = std::experimental::filesystem;
// namespace fs = std::filesystem; // doesn't work (not a namespace in gcc's C++17)
using namespace irr::core;
using namespace irr::scene;
@ -459,6 +472,37 @@ bool Utility::isFile(const std::wstring& name)
}
}
bool Utility::is_directory(const std::string &path)
{
return fs::is_directory(fs::status(path));
/*
//pre C++17:
struct stat info;
if (stat(path, &info) != 0) {
// TODO: ^ fails on OSX 10.11 according to a comment on the
// accepted answer on
// https://stackoverflow.com/questions/18100097/portable-way-to-check-if-directory-exists-windows-linux-c
}
*/
}
bool Utility::is_directory(const std::wstring &path)
{
return fs::is_directory(fs::status(path));
/*
//pre C++17:
struct stat info;
if (stat(path, &info) != 0) {
// TODO: ^ fails on OSX 10.11 according to a comment on the
// accepted answer on
// https://stackoverflow.com/questions/18100097/portable-way-to-check-if-directory-exists-windows-linux-c
}
*/
}
void Utility::create_directory(const std::string &path) {
fs::create_directory(path);
}
std::string Utility::toString(int val)
{
return std::to_string(val);
@ -554,5 +598,8 @@ void TestUtility::assertEqual(const std::string subject, const std::string expec
assert(subject == expectedResult);
}
#ifdef DEBUG
static TestUtility testutility; // Run tests (Creating the first instance runs the static constructor).
#elif QT_DEBUG
static TestUtility testutility; // Run tests (Creating the first instance runs the static constructor).
#endif

View File

@ -48,6 +48,9 @@ public:
static std::wstring delimiter(const std::wstring& path);
static bool isFile(const std::string& name);
static bool isFile(const std::wstring& name);
static bool is_directory(const std::string& name);
static bool is_directory(const std::wstring &path);
static void create_directory(const std::string &path);
static std::string toString(int val);
static std::string toString(irr::f32 val);
static std::string toString(const std::wstring& name);

View File

@ -1,8 +1,8 @@
#include "View.h"
#include "Engine.h"
#include <iostream>
#include "Utility.h"
#include "View.h"
#include <iostream>
using namespace irr;
using namespace irr::core;

View File

@ -37,9 +37,12 @@ LIBS += -lIrrlicht \
-lXxf86vm \
-lXcursor
#QMAKE_CXXFLAGS += -std=c++17
#QMAKE_LFLAGS += -lstdc++fs
# <experimental/filesystem>:
LIBS += -lstdc++fs
# Freetype
INCLUDEPATH += /usr/include/freetype2
LIBS += -lfreetype

View File

@ -1,15 +1,24 @@
#!/bin/sh
#!/bin/bash
# ^ bash is required for the "if" syntax used here.
if [ -z "$PREFIX" ]; then
PREFIX="/usr"
fi
if [ -z "$DEBUG" ]; then
DEBUG=false
fi
if [ "@$1" == "@--debug" ]; then
DEBUG=true
fi
OPTION1="-O2"
OPTION2=""
OPTION2=
OPTION3=
if [ "@$DEBUG" = "@true" ]; then
OPTION1="-g"
#OPTION2="-DQT_QML_DEBUG"
OPTION3="-DDEBUG=true"
echo "* build:Debug"
else
echo "* build:Release"
fi
#IRR_INCDIR=
#IRR_LIBDIR=
@ -35,28 +44,38 @@ fi
# gcc -o build/b3view main.cpp Debug.cpp Engine.cpp EventHandler.cpp settings.cpp UserInterface.cpp Utility.cpp View.cpp -I$FT2_INCDIR
# based on qtcreator's build after clean (see contributing.md; some options are unclear):
eche
g++ -c -pipe $OPTION1 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/main.o ../b3view/main.cpp
g++ -c -pipe $OPTION1 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/Engine.o ../b3view/Engine.cpp
g++ -c -pipe $OPTION1 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/EventHandler.o ../b3view/EventHandler.cpp
g++ -c -pipe $OPTION1 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/UserInterface.o ../b3view/UserInterface.cpp
g++ -c -pipe $OPTION1 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/View.o ../b3view/View.cpp
g++ -c -pipe $OPTION1 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/Debug.o ../b3view/Debug.cpp
g++ -c -pipe $OPTION1 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/CGUITTFont.o ../b3view/extlib/CGUITTFont.cpp
g++ -c -pipe $OPTION1 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/Utility.o ../b3view/Utility.cpp
g++ -c -pipe $OPTION1 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/settings.o ../b3view/settings.cpp
g++ -c -pipe $OPTION1 $OPTION2 $OPTION3 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/main.o ../b3view/main.cpp
if [ $? -ne 0 ]; then
echo "Error: building main failed. Ensure that libirrlicht-dev is installed."
exit 1
fi
g++ -c -pipe $OPTION1 $OPTION2 $OPTION3 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/Engine.o ../b3view/Engine.cpp
g++ -c -pipe $OPTION1 $OPTION2 $OPTION3 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/EventHandler.o ../b3view/EventHandler.cpp
g++ -c -pipe $OPTION1 $OPTION2 $OPTION3 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/UserInterface.o ../b3view/UserInterface.cpp
g++ -c -pipe $OPTION1 $OPTION2 $OPTION3 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/View.o ../b3view/View.cpp
g++ -c -pipe $OPTION1 $OPTION2 $OPTION3 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/Debug.o ../b3view/Debug.cpp
g++ -c -pipe $OPTION1 $OPTION2 $OPTION3 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/CGUITTFont.o ../b3view/extlib/CGUITTFont.cpp
g++ -c -pipe $OPTION1 $OPTION2 $OPTION3 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/Utility.o ../b3view/Utility.cpp
g++ -c -pipe $OPTION1 $OPTION2 $OPTION3 -fPIC -I../b3view -I$FT2_INCDIR -o $OBJDIR/settings.o ../b3view/settings.cpp
#-w: suppress warning
# -I.: include the current directory (suppresses errors when using include < instead of include "
#-pipe: "Use pipes rather than intermediate files."
#Options starting with -g, -f, -m, -O, -W, or --param are automatically
# passed on to the various sub-processes invoked by g++. In order to pass
# other options on to these processes the -W<letter> options must be used.
rm "$OUT_BIN"
if [ -f "$OUT_BIN" ]; then
echo "Error: $OUT_BIN couldn't be deleted."
exit 1
if [ -f "$$OUT_BIN" ]; then
mv "$OUT_BIN" "$OUT_BIN.BAK"
if [ $? -ne 0 ]; then
echo "Error: 'mv \"$OUT_BIN\" \"$OUT_BIN.BAK\"' failed.."
exit 1
fi
fi
g++ -o build/b3view $OBJDIR/main.o $OBJDIR/Engine.o $OBJDIR/EventHandler.o $OBJDIR/UserInterface.o $OBJDIR/Debug.o $OBJDIR/View.o $OBJDIR/CGUITTFont.o $OBJDIR/Utility.o $OBJDIR/settings.o -lIrrlicht -lX11 -lGL -lXxf86vm -lXcursor -lstdc++fs -lfreetype
if [ $? -ne 0 ]; then
echo "* linking failed."
else
echo "* linking suceeded."
fi
if [ ! -f "$OUT_BIN" ]; then
echo "Error: $OUT_BIN couldn't be built."
exit 1
@ -77,5 +96,11 @@ if [ -f "$INSTALLED_BIN" ]; then
else
echo "* FAILED to install $INSTALLED_BIN."
fi
else
echo "* skipping install since './$OUT_BIN' failed."
echo "* try:"
echo " $0 --debug"
echo " # then:"
echo " gdb \"$OUT_BIN\""
fi
fi

View File

@ -9,6 +9,8 @@ bat: [github.com/poikilos/mobs_sky](https://github.com/poikilos/mobs_sky)
Website: [poikilos.org](https://poikilos.org)
## Requirements
* libirrlicht
## Main Features in poikilos fork
* stabilized (makes sure font, model or texture loads before using;

View File

@ -1,14 +1,13 @@
#include "Utility.h"
// #include "Debug.h"
#include "settings.h"
#include <fstream>
#include <iostream>
#include <vector>
#include <algorithm> // std::find
#include <assert.h>
#include "settings.h"
#include "Utility.h"
// #include "Debug.h"
using namespace std;
void Settings::init_default_symbols() {
@ -76,8 +75,22 @@ bool Settings::load(std::string path)
std::string value = Utility::trim(line.substr(signPos+1));
std::string::size_type iSz;
std::string::size_type fSz;
int valueI = std::stoi(value, &iSz);
float valueF = std::stof(value, &fSz);
int valueI;
int valueF;
try {
valueI = std::stoi(value, &iSz);
}
catch (const std::invalid_argument& ex) {
valueI = 0;
iSz = 0;
}
try {
valueF = std::stof(value, &iSz);
}
catch (const std::invalid_argument& ex) {
valueF = 0.0f;
fSz = 0;
}
// ^ radix (3rd param) default is 10 (base-10 number system)
cerr << name << std::endl;
cerr << " valueI length: " << iSz << std::endl;
@ -89,9 +102,8 @@ bool Settings::load(std::string path)
typeStr = "int";
}
else if (iSz > 0) {
cerr << this->pre << "WARNING: The file has a "
<< typeStr << " for " << name << ", but "
<< this->types[name] << " was expected."
cerr << this->pre << "WARNING: The value \"" << value
<< "\" starts with a number but is not a number."
<< std::endl;
}
@ -137,6 +149,7 @@ bool Settings::load(std::string path)
}
newfile.close();
readable = true;
cerr << "* load finished reading " << path << " (elements:" << this->table.size() << ")" << endl;
}
this->section = "";
this->pre = "";
@ -455,4 +468,8 @@ void TestSettings::assert_section_set_on_create()
}
}
#ifdef DEBUG
static TestSettings testsettings; // Run tests (Creating the first instance runs the static constructor).
#elif QT_DEBUG
static TestSettings testsettings; // Run tests (Creating the first instance runs the static constructor).
#endif

3
test.conf Normal file
View File

@ -0,0 +1,3 @@
a = 3
[more]
b = 2