Compare commits

...

21 Commits

Author SHA1 Message Date
kaetemi e72f40fd17 Unicode path support for mesh_export
--HG--
branch : feature-material-editor
9 years ago
kaetemi ad549070e1 Merge with develop
--HG--
branch : feature-material-editor
9 years ago
kaetemi 197ffd7c6a Compile fix
--HG--
branch : feature-material-editor
9 years ago
kaetemi 8c6952b268 Merge with develop
--HG--
branch : feature-material-editor
9 years ago
kaetemi ef9228df16 Merge with develop
--HG--
branch : feature-material-editor
9 years ago
kaetemi 531398bf0a Merge with develop
--HG--
branch : feature-material-editor
9 years ago
kaetemi 67a5497883 Texture selection dialog
--HG--
branch : feature-material-editor
9 years ago
kaetemi e6385a1b34 Thumbnail cache
--HG--
branch : feature-material-editor
9 years ago
kaetemi 5aab1d651a Better layout
--HG--
branch : feature-material-editor
9 years ago
kaetemi 8205a8ee51 Nicer
--HG--
branch : feature-material-editor
9 years ago
kaetemi 93e8e11cf7 Texture browser
--HG--
branch : feature-material-editor
9 years ago
kaetemi 47bc7e439a Merge with develop
--HG--
branch : feature-material-editor
9 years ago
kaetemi 019ca734c7 Use asset root
--HG--
branch : feature-material-editor
9 years ago
kaetemi 95ea710466 Add widget for import errors
--HG--
branch : feature-material-editor
9 years ago
kaetemi 2053e075fc Properly update default config
--HG--
branch : feature-material-editor
9 years ago
kaetemi 596a4ba7a3 Fix cfg access
--HG--
branch : feature-material-editor
9 years ago
kaetemi ab790a5f08 Show asset database tree for last opened file
--HG--
branch : feature-material-editor
9 years ago
kaetemi 697299d61b Fix exit
--HG--
branch : feature-material-editor
9 years ago
kaetemi 26c8bbff46 Add base for material editor
--HG--
branch : feature-material-editor
9 years ago
kaetemi 571ab41ffc Merge with develop
--HG--
branch : feature-material-editor
9 years ago
kaetemi 7012965c78 Separate scene import functions
--HG--
branch : feature-material-editor
9 years ago

@ -53,9 +53,13 @@ public:
/// Undo init
static void release();
static std::string getAssetRoot();
static void getDatabaseTextureSearchPaths(std::vector<std::string> &paths);
private:
static void cleanup();
static void searchDirectories(const char *var);
static void getSearchPaths(std::vector<std::string> &paths, const char *var);
static CProjectConfig s_Instance;

@ -103,7 +103,7 @@ public:
{
releaseError();
m_ErrorLog = nlfopen(errorLog, "wt");
m_ErrorLog = NLMISC::nlfopen(errorLog, "wt");
fwrite(s_ErrorHeader.c_str(), 1, s_ErrorHeader.length(), m_ErrorLog);
fwrite("\n", 1, 1, m_ErrorLog);
fflush(m_ErrorLog);
@ -114,7 +114,7 @@ public:
{
releaseDepend();
m_DependLog = nlfopen(dependLog, "wt");
m_DependLog = NLMISC::nlfopen(dependLog, "wt");
fwrite(s_DependHeader.c_str(), 1, s_DependHeader.length(), m_DependLog);
fwrite("\n", 1, 1, m_DependLog);
// fflush(m_DependLog);

@ -208,12 +208,12 @@ void CProjectConfig::searchDirectories(const char *var)
{
CConfigFile *cfg = s_ConfigFiles[i];
const TPathString &dir = s_ConfigPaths[i];
CConfigFile::CVar *paths = cfg->getVarPtr(var);
if (paths)
CConfigFile::CVar *pathvar = cfg->getVarPtr(var);
if (pathvar)
{
for (uint i = 0; i < paths->size(); i++)
for (uint j = 0; j < pathvar->size(); j++)
{
TPathString path = paths->asString(i);
TPathString path = pathvar->asString(j);
if (!CPath::isAbsolutePath(path)) path = dir + path;
path = CPath::standardizePath(path);
if (s_SearchPaths.find(path) == s_SearchPaths.end())
@ -233,6 +233,57 @@ void CProjectConfig::release()
cleanup();
}
std::string CProjectConfig::getAssetRoot()
{
return CFile::getPath(s_AssetConfigPath);
}
void CProjectConfig::getSearchPaths(std::vector<std::string> &paths, const char *var)
{
std::set<std::string> deduplicate;
for (uint i = 0; i < s_ConfigFiles.size(); ++i)
{
CConfigFile *cfg = s_ConfigFiles[i];
const TPathString &dir = s_ConfigPaths[i];
CConfigFile::CVar *pathvar = cfg->getVarPtr(var);
if (pathvar)
{
for (uint j = 0; j < pathvar->size(); j++)
{
TPathString path = pathvar->asString(j);
if (!CPath::isAbsolutePath(path)) path = dir + path;
path = CPath::standardizePath(path);
if (deduplicate.find(path) == deduplicate.end())
{
paths.push_back(path);
deduplicate.insert(path);
}
}
}
}
}
void CProjectConfig::getDatabaseTextureSearchPaths(std::vector<std::string> &paths)
{
getSearchPaths(paths, "DatabaseTextureSearchPaths");
}
/*
std::string CProjectConfig::databaseRoot()
{
for (uint i = 0; i < s_ConfigFiles.size(); ++i)
{
CConfigFile *cfg = s_ConfigFiles[i];
const TPathString &dir = s_ConfigPaths[i];
CConfigFile::CVar *path = cfg->getVarPtr("DatabaseRoot");
if (path && CFile::isExists(dir + path->asString()))
return CPath::standardizePath(dir + path->asString());
}
return "";
}
*/
} /* namespace NLPIPELINE */
/* end of file */

@ -1,10 +1,20 @@
IF(WITH_NEL_TOOLS)
IF(WITH_3D)
IF(WITH_QT5)
SUBDIRS(
shared_widgets
panoply_preview)
ENDIF()
IF(WITH_ASSIMP)
SUBDIRS(
mesh_utils
mesh_export)
IF(WITH_QT5)
# NOTE: Also requires C++11, because.
SUBDIRS(
mesh_editor)
ENDIF()
ENDIF()
SUBDIRS(
anim_builder
@ -67,11 +77,6 @@ IF(WITH_NEL_TOOLS AND WITH_3D)
ADD_SUBDIRECTORY(object_viewer_widget)
ENDIF()
IF(WITH_QT5)
ADD_SUBDIRECTORY(shared_widgets)
ADD_SUBDIRECTORY(panoply_preview)
ENDIF()
IF(WITH_NEL_TOOLS)
FIND_PACKAGE(Squish)
ENDIF()

@ -0,0 +1,39 @@
FILE(GLOB SRCS *.cpp)
FILE(GLOB HDRS *.h)
IF (WIN32)
FILE(GLOB RSRC *.rc)
ENDIF (WIN32)
FILE(GLOB RESOURCES *.qrc)
SOURCE_GROUP("" FILES ${SRCS} ${HDRS} ${RSRC} ${RESOURCES})
SET(CMAKE_AUTOMOC ON)
QT5_ADD_RESOURCES(RESOURCE_ADDED ${RESOURCES})
ADD_EXECUTABLE(nl_mesh_editor WIN32 ${SRC}
${SRCS}
${HDRS}
${RSRC}
${RESOURCE_ADDED}
)
IF(QT_STATIC)
SET(PANOPLY_PREVIEW_QT_LIBRARIES ${QT_LIBRARIES})
ELSE()
SET(PANOPLY_PREVIEW_QT_LIBRARIES Qt5::Widgets)
ENDIF()
TARGET_LINK_LIBRARIES(nl_mesh_editor
nelmisc
nel3d
nelsound
nelpipeline
shared_widgets
mesh_utils)
NL_DEFAULT_PROPS(nl_mesh_editor "NeL, Tools, 3D: Mesh Editor")
NL_ADD_RUNTIME_FLAGS(nl_mesh_editor)
INSTALL(TARGETS nl_mesh_editor RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samples3d)

@ -0,0 +1,242 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <nel/misc/types_nl.h>
#include "configuration.h"
// STL includes
// NeL includes
#include <nel/misc/debug.h>
#include <nel/misc/hierarchical_timer.h>
#include <nel/misc/config_file.h>
#include <nel/misc/path.h>
#include <nel/misc/i18n.h>
using namespace std;
using namespace NLMISC;
CConfiguration::CConfiguration()
{
}
CConfiguration::~CConfiguration()
{
}
void CConfiguration::init()
{
// verify data
nlassert(m_ConfigCallbacks.empty());
// load config
std::string appData = CPath::getApplicationDirectory("NeL");
m_ConfigFile.load(appData + "mesh_editor.cfg");
// log config
CConfiguration::setAndCallback("NegFiltersDebug", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
CConfiguration::setAndCallback("NegFiltersInfo", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
CConfiguration::setAndCallback("NegFiltersWarning", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
CConfiguration::setAndCallback("NegFiltersAssert", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
CConfiguration::setAndCallback("NegFiltersError", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
// set the search paths (kinda important)
/*
CConfigFile::CVar *var;
var = m_ConfigFile.getVarPtr("SearchPaths");
uint varsize = var->size();
for (uint i = 0; i < varsize; ++i)
CPath::addSearchPath(var->asString(i), true, false);
var = m_ConfigFile.getVarPtr("RemapExtensions");
varsize = var->size();
for (uint i = 0; i < varsize; i += 2)
CPath::remapExtension(var->asString(i), var->asString(i + 1), true);
*/
}
void CConfiguration::release()
{
// bye bye log config
CConfigFile::CVar emptyVar;
emptyVar.Name = "NegFiltersDebug";
CConfiguration::dropCallback(emptyVar.Name);
cfcbLogFilter(emptyVar);
emptyVar.Name = "NegFiltersInfo";
CConfiguration::dropCallback(emptyVar.Name);
cfcbLogFilter(emptyVar);
emptyVar.Name = "NegFiltersWarning";
CConfiguration::dropCallback(emptyVar.Name);
cfcbLogFilter(emptyVar);
emptyVar.Name = "NegFiltersAssert";
CConfiguration::dropCallback(emptyVar.Name);
cfcbLogFilter(emptyVar);
emptyVar.Name = "NegFiltersError";
CConfiguration::dropCallback(emptyVar.Name);
cfcbLogFilter(emptyVar);
// save and release the config file
if (m_ConfigFile.exists("SaveConfig") && m_ConfigFile.getVarPtr("SaveConfig")->asBool())
{
m_ConfigFile.save();
}
m_ConfigFile.clear();
// release the search paths etc
CPath::releaseInstance();
// verify data
nlassert(!m_ConfigCallbacks.size());
}
void CConfiguration::updateUtilities()
{
//H_AUTO2
CConfigFile::checkConfigFiles();
}
void CConfiguration::setAndCallback(const std::string &varName, CConfigCallback configCallback)
{
m_ConfigCallbacks[varName] = configCallback;
m_ConfigFile.setCallback(varName, cbConfigCallback);
configCallback(*m_ConfigFile.getVarPtr(varName));
}
void CConfiguration::setCallback(const std::string &varName, CConfigCallback configCallback)
{
m_ConfigCallbacks[varName] = configCallback;
m_ConfigFile.setCallback(varName, cbConfigCallback);
}
void CConfiguration::dropCallback(const std::string &varName)
{
m_ConfigFile.setCallback(varName, NULL);
m_ConfigCallbacks.erase(varName);
}
float CConfiguration::getValue(const string &varName, float defaultValue)
{
if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asFloat();
CConfigFile::CVar varToCopy;
varToCopy.forceAsDouble((double)defaultValue);
m_ConfigFile.insertVar(varName, varToCopy);
return defaultValue;
}
double CConfiguration::getValue(const string &varName, double defaultValue)
{
if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asDouble();
CConfigFile::CVar varToCopy;
varToCopy.forceAsDouble(defaultValue);
m_ConfigFile.insertVar(varName, varToCopy);
return defaultValue;
}
int CConfiguration::getValue(const string &varName, int defaultValue)
{
if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asInt();
CConfigFile::CVar varToCopy;
varToCopy.forceAsInt(defaultValue);
m_ConfigFile.insertVar(varName, varToCopy);
return defaultValue;
}
string CConfiguration::getValue(const string &varName, const string &defaultValue)
{
if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asString();
CConfigFile::CVar varToCopy;
varToCopy.forceAsString(defaultValue);
m_ConfigFile.insertVar(varName, varToCopy);
return defaultValue;
}
ucstring CConfiguration::getValue(const string &varName, const ucstring &defaultValue)
{
if (m_ConfigFile.exists(varName)) return ucstring::makeFromUtf8(m_ConfigFile.getVar(varName).asString());
CConfigFile::CVar varToCopy;
varToCopy.forceAsString(defaultValue.toUtf8());
m_ConfigFile.insertVar(varName, varToCopy);
return defaultValue;
}
bool CConfiguration::getValue(const string &varName, bool defaultValue)
{
if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asBool();
CConfigFile::CVar varToCopy;
varToCopy.forceAsInt(defaultValue ? 1 : 0);
m_ConfigFile.insertVar(varName, varToCopy);
return defaultValue;
}
CRGBA CConfiguration::getValue(const string &varName, const CRGBA &defaultValue)
{
if (m_ConfigFile.exists(varName))
{
return getValue(m_ConfigFile.getVar(varName), defaultValue);
}
else
{
// create a new value only if one doesn't exist
CConfigFile::CVar varToCopy;
varToCopy.forceAsInt(defaultValue.R);
varToCopy.setAsInt(defaultValue.G, 1);
varToCopy.setAsInt(defaultValue.B, 2);
varToCopy.setAsInt(defaultValue.A, 3);
m_ConfigFile.insertVar(varName, varToCopy);
}
return defaultValue;
}
CRGBA CConfiguration::getValue(const CConfigFile::CVar &var, const CRGBA &defaultValue)
{
if (var.size() >= 3)
{
if (var.size() > 4) nlwarning("RGBA value in config value '%s' is too long, ignoring unused values");
return CRGBA((uint8)var.asInt(0), (uint8)var.asInt(1), (uint8)var.asInt(2), var.size() >= 4 ? (uint8)var.asInt(3) : 255);
}
nlwarning("Invalid RGBA value in config value '%s', reverting to default { %i, %i, %i, %i }", var.Name.c_str(), (sint)defaultValue.R, (sint)defaultValue.G, (sint)defaultValue.B, (sint)defaultValue.A);
return defaultValue;
}
void CConfiguration::cbConfigCallback(NLMISC::CConfigFile::CVar &var)
{
CConfiguration::getInstance()->m_ConfigCallbacks[var.Name](var);
}
void CConfiguration::cfcbLogFilter(CConfigFile::CVar &var)
{
// from nel/net/service.cpp
CLog *log = NULL;
if (var.Name == "NegFiltersDebug") log = DebugLog;
else if (var.Name == "NegFiltersInfo") log = InfoLog;
else if (var.Name == "NegFiltersWarning") log = WarningLog;
else if (var.Name == "NegFiltersAssert") log = AssertLog;
else if (var.Name == "NegFiltersError") log = ErrorLog;
else nlstop;
// remove all old filters from config file
CConfigFile::CVar &oldvar = m_ConfigFile.getVar(var.Name);
for (uint j = 0; j < oldvar.size(); j++)
log->removeFilter(oldvar.asString(j).c_str());
// add all new filters from config file
for (uint i = 0; i < var.size(); i++)
log->addNegativeFilter(var.asString(i).c_str());
}
/* end of file */

@ -0,0 +1,81 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NLQT_CONFIGURATION_H
#define NLQT_CONFIGURATION_H
#include <nel/misc/types_nl.h>
// STL includes
#include <map>
// NeL includes
#include <nel/misc/callback.h>
#include <nel/misc/config_file.h>
#include <nel/misc/rgba.h>
#include <nel/misc/ucstring.h>
#include <nel/misc/singleton.h>
typedef NLMISC::CCallback<void, NLMISC::CConfigFile::CVar &> CConfigCallback;
/**
* CConfiguration
* \brief CConfiguration
* \date 2010-02-05 15:44GMT
* \author Jan Boon (Kaetemi)
*/
class CConfiguration : public NLMISC::CManualSingleton<CConfiguration> // singleton due to cconfigfile issues
{
public:
CConfiguration();
virtual ~CConfiguration();
void init();
void release();
void updateUtilities();
void setAndCallback(const std::string &varName, CConfigCallback configCallback);
void setCallback(const std::string &varName, CConfigCallback configCallback);
void dropCallback(const std::string &varName);
float getValue(const std::string &varName, float defaultValue);
double getValue(const std::string &varName, double defaultValue);
int getValue(const std::string &varName, int defaultValue);
std::string getValue(const std::string &varName, const std::string &defaultValue);
ucstring getValue(const std::string &varName, const ucstring &defaultValue);
bool getValue(const std::string &varName, bool defaultValue);
NLMISC::CRGBA getValue(const std::string &varName, const NLMISC::CRGBA &defaultValue);
NLMISC::CRGBA getValue(const NLMISC::CConfigFile::CVar &var, const NLMISC::CRGBA &defaultValue);
inline NLMISC::CConfigFile &getConfigFile() { return m_ConfigFile; }
private:
static void cbConfigCallback(NLMISC::CConfigFile::CVar &var);
void cfcbLogFilter(NLMISC::CConfigFile::CVar &var);
private:
CConfiguration(const CConfiguration &);
CConfiguration &operator=(const CConfiguration &);
private:
NLMISC::CConfigFile m_ConfigFile;
std::map<std::string, CConfigCallback> m_ConfigCallbacks;
}; /* class CConfiguration */
#endif /* #ifndef NLQT_CONFIGURATION_H */
/* end of file */

@ -0,0 +1,7 @@
<RCC>
<qresource prefix="/">
<file>data/andbasr.ttf</file>
<file>data/mesh_editor.cfg</file>
<file>data/mesh_editor_default.cfg</file>
</qresource>
</RCC>

@ -0,0 +1 @@
RootConfigFilename = "mesh_editor_default.cfg";

@ -0,0 +1,84 @@
//////////////////////////////////////////////////////////////////////////////
// Config file for NeL Mesh Editor ///////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// This file is used to setup the NeL Mesh Editor tool.
//
//////////////////////////////////////////////////////////////////////////////
// NeL Mesh Editor ///////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Log filters
NegFiltersDebug += { ".zonel", "FRONT: " };
NegFiltersInfo += { };
NegFiltersWarning += { ".zonel", "FRONT: " };
NegFiltersAssert += { };
NegFiltersError += { };
// The language code of the client
LanguageCode = "en";
// If changes to the config should be saved on exit
SaveConfig = 1;
//////////////////////////////////////////////////////////////////////////////
// Graphics //////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// Use OpenGL or Direct3D (Windows)
GraphicsEnabled = 1;
GraphicsDrivers = { "OpenGL", "Direct3D" };
GraphicsDriver = "OpenGL";
// Font name used for all text in the client (it can be a .ttf, .fon, .pfb)
FontName = "andbasr.ttf";
FontShadow = 1;
// Background color
BackgroundColor = { 41, 57, 85 };
// Screenshot formats
ScreenshotJPG = 1;
ScreenshotPNG = 1;
ScreenshotTGA = 0;
//////////////////////////////////////////////////////////////////////////////
// Environment ///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
SunDirection = { -2.935, +0.107, -1.22 };
SunAmbient = { 190, 170, 150 };
SunDiffuse = { 255, 248, 255 };
SunSpecular = { 255, 255, 255};
// 1 if you want to see the fog
// FogEnable = 1;
// FogStart = 100.0; // in meter
// FogEnd = 250.0; // in meter
// FogColor = { 129, 136, 205 }; // { 147, 125, 114 };
//////////////////////////////////////////////////////////////////////////////
// Sound /////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
// The sound driver, choose between "Auto", "FMod", "DSound" and "OpenAl"
SoundEnabled = 0;
SoundDrivers = { "Auto", "OpenAL", "XAudio2", "FMod", "DSound" };
SoundDriver = "OpenAL";
SoundDevice = "";
SoundMaxTrack = 48;
SoundEnableOccludeObstruct = 1;
SoundEnableReverb = 1;
SoundManualRolloff = 1;
SoundUseADPCM = 0;
SoundForceSoftware = 0;
SoundAutoLoadSample = 1;
// end of file

@ -0,0 +1,258 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <nel/misc/types_nl.h>
#include "graphics_config.h"
// STL includes
// Qt includes
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QUndoStack>
// NeL includes
// #include <nel/misc/debug.h>
// Project includes
#include "main_window.h"
#include "configuration.h"
#include "undo_redo_binders.h"
using namespace std;
using namespace NLMISC;
CGraphicsConfig::CGraphicsConfig(QWidget *parent, CConfiguration *configuration, QUndoStack *undoStack)
: QWidget(parent), m_Configuration(configuration), m_UndoStack(undoStack),
m_DriverGroup(NULL), m_Enabled(NULL), m_DriverLabel(NULL), m_Driver(NULL),
m_FontNameLabel(NULL), m_FontName(NULL), m_Apply(NULL),
m_RenderGroup(NULL), m_BackgroundColor(NULL), m_FontShadow(NULL),
m_ScreenshotGroup(NULL)
{
nlassert(m_Configuration);
nlassert(m_UndoStack);
QVBoxLayout *vboxLayout = new QVBoxLayout();
// Driver
{
nlassert(!m_DriverGroup);
m_DriverGroup = new QGroupBox();
QVBoxLayout *groupVboxLayout = new QVBoxLayout();
// Enabled
{
nlassert(!m_Enabled);
m_Enabled = new QCheckBox();
groupVboxLayout->addWidget(m_Enabled);
}
// Driver
{
QHBoxLayout *hboxLayout = new QHBoxLayout();
nlassert(!m_DriverLabel);
m_DriverLabel = new QLabel();
nlassert(!m_Driver);
m_Driver = new QComboBox();
m_DriverLabel->setBuddy(m_Driver);
hboxLayout->addWidget(m_DriverLabel);
hboxLayout->addWidget(m_Driver);
hboxLayout->setStretch(1, 1);
groupVboxLayout->addLayout(hboxLayout);
}
// Font Name
{
QHBoxLayout *hboxLayout = new QHBoxLayout();
nlassert(!m_FontNameLabel);
m_FontNameLabel = new QLabel();
nlassert(!m_FontName);
m_FontName = new QLineEdit();
m_FontNameLabel->setBuddy(m_FontName);
hboxLayout->addWidget(m_FontNameLabel);
hboxLayout->addWidget(m_FontName);
hboxLayout->setStretch(1, 1);
groupVboxLayout->addLayout(hboxLayout);
}
// Apply
{
nlassert(!m_Apply);
m_Apply = new QPushButton();
m_Apply->setDefault(true);
groupVboxLayout->addWidget(m_Apply);
connect(m_Apply, SIGNAL(pressed()), this, SLOT(applyPressed()));
}
m_DriverGroup->setLayout(groupVboxLayout);
vboxLayout->addWidget(m_DriverGroup);
}
// Render
{
nlassert(!m_RenderGroup);
m_RenderGroup = new QGroupBox();
QVBoxLayout *groupVboxLayout = new QVBoxLayout();
// Background Color
{
m_BackgroundColor = new QtColorPicker();
m_BackgroundColor->setStandardColors();
groupVboxLayout->addWidget(m_BackgroundColor);
connect(m_BackgroundColor, SIGNAL(colorChanged(const QColor &)), this, SLOT(uicbBackgroundColor(const QColor &)));
}
// Font Shadow
{
nlassert(!m_FontShadow);
m_FontShadow = new QCheckBox();
groupVboxLayout->addWidget(m_FontShadow);
connect(m_FontShadow, SIGNAL(toggled(bool)), this, SLOT(uicbFontShadow(bool)));
}
m_RenderGroup->setLayout(groupVboxLayout);
vboxLayout->addWidget(m_RenderGroup);
}
// Screenshots
{
nlassert(!m_ScreenshotGroup);
m_ScreenshotGroup = new QGroupBox();
QVBoxLayout *groupVboxLayout = new QVBoxLayout();
m_ScreenshotGroup->setLayout(groupVboxLayout);
vboxLayout->addWidget(m_ScreenshotGroup);
m_ScreenshotGroup->setVisible(false);
}
vboxLayout->addStretch();
setLayout(vboxLayout);
// setup config file callbacks and initialize values
m_Configuration->setAndCallback("GraphicsEnabled", CConfigCallback(this, &CGraphicsConfig::cfcbGraphicsEnabled));
m_Configuration->setCallback("GraphicsDriver", CConfigCallback(this, &CGraphicsConfig::cfcbGraphicsDriver));
m_Configuration->setAndCallback("GraphicsDrivers", CConfigCallback(this, &CGraphicsConfig::cfcbGraphicsDrivers));
m_Configuration->setAndCallback("FontName", CConfigCallback(this, &CGraphicsConfig::cfcbFontName));
m_Configuration->setAndCallback("BackgroundColor", CConfigCallback(this, &CGraphicsConfig::cfcbBackgroundColor));
m_Configuration->setAndCallback("FontShadow", CConfigCallback(this, &CGraphicsConfig::cfcbFontShadow));
// setup translation callback and initialize translation
incbTranslate();
// setup undo/redo automation
CUndoRedoBinderButton *undoRedoEnabled = new CUndoRedoBinderButton(m_Enabled, undoStack);
CUndoRedoBinderComboBox *undoRedoDriver = new CUndoRedoBinderComboBox(m_Driver, undoStack);
CUndoRedoBinderLineEdit *undoRedoFontName = new CUndoRedoBinderLineEdit(m_FontName, undoStack);
CUndoRedoBinderColorPicker *undoRedoBackgroundColor = new CUndoRedoBinderColorPicker(m_BackgroundColor, undoStack);
CUndoRedoBinderButton *undoRedoFontShadow = new CUndoRedoBinderButton(m_FontShadow, undoStack);
}
CGraphicsConfig::~CGraphicsConfig()
{
m_Configuration->dropCallback("FontShadow");
m_Configuration->dropCallback("BackgroundColor");
m_Configuration->dropCallback("FontName");
m_Configuration->dropCallback("GraphicsDrivers");
m_Configuration->dropCallback("GraphicsDriver");
m_Configuration->dropCallback("GraphicsEnabled");
}
void CGraphicsConfig::incbTranslate()
{
m_DriverGroup->setTitle(tr("Driver Settings"));
m_Enabled->setText(tr("Enabled"));
m_DriverLabel->setText(tr("Driver: "));
m_FontNameLabel->setText(tr("Font: "));
m_Apply->setText(tr("Apply"));
m_RenderGroup->setTitle(tr("Render Settings"));
m_BackgroundColor->setText(tr("Background Color"));
m_FontShadow->setText(tr("Font Shadow"));
m_ScreenshotGroup->setTitle(tr("Screenshot Settings"));
}
void CGraphicsConfig::cfcbGraphicsEnabled(NLMISC::CConfigFile::CVar &var)
{
m_Enabled->setChecked(var.asBool());
}
void CGraphicsConfig::cfcbGraphicsDrivers(NLMISC::CConfigFile::CVar &var)
{
while (m_Driver->count())
m_Driver->removeItem(0);
for (uint i = 0; i < var.size(); ++i)
m_Driver->addItem(var.asString(i).c_str());
cfcbGraphicsDriver(m_Configuration->getConfigFile().getVar("GraphicsDriver"));
m_UndoStack->clear();
}
void CGraphicsConfig::cfcbGraphicsDriver(NLMISC::CConfigFile::CVar &var)
{
QString value = var.asString().c_str();
QString dn = value.toLower();
for (sint i = 0; i < m_Driver->count(); ++i)
{
if (dn == m_Driver->itemText(i).toLower())
{
m_Driver->setCurrentIndex(i);
return;
}
}
nlwarning("Unknown GraphicsDriver specified in config, skipping value.");
}
void CGraphicsConfig::cfcbFontName(NLMISC::CConfigFile::CVar &var)
{
m_FontName->setText(var.asString().c_str());
}
void CGraphicsConfig::cfcbBackgroundColor(NLMISC::CConfigFile::CVar &var)
{
m_BackgroundColor->setCurrentColor(QColor(var.asInt(0), var.asInt(1), var.asInt(2)));
emit onBackgroundColor(getBackgroundColor());
}
void CGraphicsConfig::cfcbFontShadow(NLMISC::CConfigFile::CVar &var)
{
m_FontShadow->setChecked(var.asBool());
emit onFontShadow(getFontShadow());
}
void CGraphicsConfig::applyPressed()
{
m_Configuration->getConfigFile().getVar("GraphicsEnabled").setAsInt(getGraphicsEnabled() ? 1 : 0);
m_Configuration->getConfigFile().getVar("GraphicsDriver").setAsString(getGraphicsDriver());
m_Configuration->getConfigFile().getVar("FontName").setAsString(getFontName());
emit applyGraphicsConfig();
}
void CGraphicsConfig::uicbBackgroundColor(const QColor &backgroundColor)
{
m_Configuration->getConfigFile().getVar("BackgroundColor").setAsInt(backgroundColor.red(), 0);
m_Configuration->getConfigFile().getVar("BackgroundColor").setAsInt(backgroundColor.green(), 1);
m_Configuration->getConfigFile().getVar("BackgroundColor").setAsInt(backgroundColor.blue(), 2);
emit onBackgroundColor(getBackgroundColor());
}
void CGraphicsConfig::uicbFontShadow(bool checked)
{
m_Configuration->getConfigFile().getVar("FontShadow").setAsInt(checked ? 1 : 0);
emit onFontShadow(checked);
}
/* end of file */

@ -0,0 +1,116 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NLQT_GRAPHICS_CONFIG_H
#define NLQT_GRAPHICS_CONFIG_H
#include <nel/misc/types_nl.h>
// STL includes
// Qt includes
#include <QWidget>
#include <QCheckBox>
#include <QPushButton>
#include <QGroupBox>
#include <QComboBox>
#include <QLabel>
#include <QLineEdit>
// NeL includes
#include <nel/misc/config_file.h>
#include <nel/misc/rgba.h>
// Project includes
#include "qtcolorpicker.h"
class QUndoStack;
class CMainWindow;
class CConfiguration;
/**
* CGraphicsConfig
* \brief CGraphicsConfig
* \date 2010-02-07 10:15GMT
* \author Jan Boon (Kaetemi)
*/
class CGraphicsConfig : public QWidget
{
Q_OBJECT
public:
CGraphicsConfig(QWidget *parent, CConfiguration *configuration, QUndoStack *undoStack);
virtual ~CGraphicsConfig();
void incbTranslate();
inline bool getGraphicsEnabled() const { return m_Enabled->isChecked(); }
inline std::string getGraphicsDriver() const { std::string v = std::string(m_Driver->currentText().toLatin1()); return v; }
inline std::string getFontName() const { std::string v = std::string(m_FontName->text().toLatin1()); return v; }
inline NLMISC::CRGBA getBackgroundColor() const { QColor c = m_BackgroundColor->currentColor(); NLMISC::CRGBA v(c.red(), c.green(), c.blue()); return v; }
inline bool getFontShadow() const { return m_FontShadow->isChecked(); }
inline bool getScreenshotJPG() const { return true; }
inline bool getScreenshotPNG() const { return true; }
inline bool getScreenshotTGA() const { return false; }
private slots:
void applyPressed();
void uicbBackgroundColor(const QColor &backgroundColor);
void uicbFontShadow(bool checked);
signals:
/// GraphicsEnabled, GraphicsDriver, FontName
void applyGraphicsConfig();
void onBackgroundColor(NLMISC::CRGBA backgroundColor);
void onFontShadow(bool fontShadow);
private:
void cfcbGraphicsEnabled(NLMISC::CConfigFile::CVar &var);
void cfcbGraphicsDrivers(NLMISC::CConfigFile::CVar &var);
void cfcbGraphicsDriver(NLMISC::CConfigFile::CVar &var);
void cfcbFontName(NLMISC::CConfigFile::CVar &var);
void cfcbBackgroundColor(NLMISC::CConfigFile::CVar &var);
void cfcbFontShadow(NLMISC::CConfigFile::CVar &var);
private:
CConfiguration *m_Configuration;
QUndoStack *m_UndoStack;
QGroupBox *m_DriverGroup;
QCheckBox *m_Enabled;
QLabel *m_DriverLabel;
QComboBox *m_Driver;
QLabel *m_FontNameLabel;
QLineEdit *m_FontName;
QPushButton *m_Apply;
QGroupBox *m_RenderGroup;
QtColorPicker *m_BackgroundColor;
QCheckBox *m_FontShadow;
QGroupBox *m_ScreenshotGroup;
private:
CGraphicsConfig(const CGraphicsConfig &);
CGraphicsConfig &operator=(const CGraphicsConfig &);
}; /* class CGraphicsConfig */
#endif /* #ifndef NLQT_GRAPHICS_CONFIG_H */
/* end of file */

@ -0,0 +1,229 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <nel/misc/types_nl.h>
#include "graphics_viewport.h"
// STL includes
// Qt includes
#include <QAction>
// NeL includes
#include <nel/misc/debug.h>
#include <nel/misc/hierarchical_timer.h>
#include <nel/misc/file.h>
#include <nel/misc/bitmap.h>
#include <nel/misc/path.h>
#include <nel/misc/i18n.h>
#include <nel/3d/u_driver.h>
#include <nel/3d/u_text_context.h>
// Project includes
#include "graphics_config.h"
using namespace std;
using namespace NLMISC;
using namespace NL3D;
namespace {
QString nli18n(const char *label)
{
return QString::fromUtf16(CI18N::get(label).c_str());
}
} /* anonymous namespace */
CGraphicsViewport::CGraphicsViewport(QWidget *parent)
: QWidget(parent),
m_GraphicsConfig(NULL),
m_Driver(NULL),
m_TextContext(NULL)
{
}
CGraphicsViewport::~CGraphicsViewport()
{
}
void CGraphicsViewport::init(CGraphicsConfig *graphicsConfig)
{
//H_AUTO2
nldebug("CGraphicsViewport::init");
// copy parameters
m_GraphicsConfig = graphicsConfig;
// check stuff we need
nlassert(m_GraphicsConfig);
// create the driver
nlassert(!m_Driver);
m_Direct3D = false;
std::string driver = m_GraphicsConfig->getGraphicsDriver();
if (driver == "Direct3D") m_Direct3D = true; //m_Driver = Direct3D;
else if (driver == "OpenGL") m_Direct3D = false; //m_Driver = OpenGL;
else
{
nlwarning("Invalid driver specified, defaulting to OpenGL");
//m_Configuration->getConfigFile().getVar("GraphicsDriver").forceAsString("OpenGL");
//m_Driver = OpenGL;
}
m_Driver = UDriver::createDriver(NULL, m_Direct3D, NULL);
nlassert(m_Driver);
// initialize the window with config file values
m_Driver->setDisplay((nlWindow)winId(), NL3D::UDriver::CMode(width(), height(), 32));
// register config callbacks
connect(m_GraphicsConfig, SIGNAL(onBackgroundColor(NLMISC::CRGBA)),
this, SLOT(cfcbBackgroundColor(NLMISC::CRGBA)));
m_BackgroundColor = m_GraphicsConfig->getBackgroundColor();
// set the cache size for the font manager(in bytes)
m_Driver->setFontManagerMaxMemory(2097152);
// create the text context
nlassert(!m_TextContext);
std::string localAppData = CPath::getApplicationDirectory("NeL", true);
std::string fontAppData = localAppData + m_GraphicsConfig->getFontName();
m_TextContext = m_Driver->createTextContext(CFile::isExists(fontAppData) ? fontAppData : m_GraphicsConfig->getFontName());
nlassert(m_TextContext);
connect(m_GraphicsConfig, SIGNAL(onFontShadow(bool)),
this, SLOT(cfcbFontShadow(bool)));
m_TextContext->setShaded(m_GraphicsConfig->getFontShadow());
}
void CGraphicsViewport::release()
{
//H_AUTO2
nldebug("CGraphicsViewport::release");
// release text context
nlassert(m_TextContext);
disconnect(m_GraphicsConfig, SIGNAL(onFontShadow(bool)),
this, SLOT(cfcbFontShadow(bool)));
m_Driver->deleteTextContext(m_TextContext);
m_TextContext = NULL;
// release driver
nlassert(m_Driver);
disconnect(m_GraphicsConfig, SIGNAL(onBackgroundColor(NLMISC::CRGBA)),
this, SLOT(cfcbBackgroundColor(NLMISC::CRGBA)));
m_Driver->release();
delete m_Driver;
m_Driver = NULL;
// reset parameters
m_GraphicsConfig = NULL;
}
void CGraphicsViewport::updateInput()
{
// m_Driver->EventServer.pump(); // Can't do this, conflicts with Qt processing
}
void CGraphicsViewport::renderDriver()
{
m_Driver->clearBuffers(m_BackgroundColor);
}
void CGraphicsViewport::renderDebug2D()
{
m_TextContext->setColor(NL3D::CRGBA (255, 255, 255));
m_TextContext->setFontSize(40);
m_TextContext->setHotSpot(NL3D::UTextContext::BottomLeft);
m_TextContext->printAt(0.3f, 0.5f, std::string("NeL Qt"));
}
void CGraphicsViewport::cfcbBackgroundColor(NLMISC::CRGBA backgroundColor)
{
m_BackgroundColor = backgroundColor;
}
void CGraphicsViewport::cfcbFontShadow(bool fontShadow)
{
m_TextContext->setShaded(fontShadow);
}
QAction *CGraphicsViewport::createSaveScreenshotAction(QObject *parent)
{
QAction *action = new QAction(parent);
connect(action, SIGNAL(triggered()), this, SLOT(saveScreenshot()));
return action;
}
void CGraphicsViewport::saveScreenshot()
{
saveScreenshot(
m_GraphicsConfig->getScreenshotJPG(),
m_GraphicsConfig->getScreenshotPNG(),
m_GraphicsConfig->getScreenshotTGA());
}
void CGraphicsViewport::saveScreenshot(bool jpg, bool png, bool tga)
{
//H_AUTO2
// empty bitmap
CBitmap bitmap;
// copy the driver buffer to the bitmap
m_Driver->getBuffer(bitmap);
// create the file name
string filename = NLMISC::CPath::getApplicationDirectory("NeL") + "screenshots/mesh_editor_";
// write the bitmap as a jpg, png or tga to the file
if (jpg)
{
string newfilename = CFile::findNewFile(filename + ".jpg");
COFile outputFile(newfilename);
bitmap.writeJPG(outputFile, 100);
nlinfo("Screenshot '%s' saved", newfilename.c_str());
}
if (png)
{
string newfilename = CFile::findNewFile(filename + ".png");
COFile outputFile(newfilename);
bitmap.writePNG(outputFile, 24);
nlinfo("Screenshot '%s' saved", newfilename.c_str());
}
if (tga)
{
string newfilename = CFile::findNewFile(filename + ".tga");
COFile outputFile(newfilename);
bitmap.writeTGA(outputFile, 24, false);
nlinfo("Screenshot '%s' saved", newfilename.c_str());
}
}
void CGraphicsViewport::resizeEvent(QResizeEvent *resizeEvent)
{
QWidget::resizeEvent(resizeEvent);
if (m_Driver && !m_Direct3D)
{
m_Driver->setMode(UDriver::CMode(resizeEvent->size().width(), resizeEvent->size().height(), 32));
}
// The OpenGL driver does not resize automatically.
// The Direct3D driver breaks the window mode to include window borders when calling setMode windowed.
// Resizing the window after switching drivers a few times becomes slow.
// There is probably something inside the drivers not being released properly.
}
/* end of file */

@ -0,0 +1,102 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NLQT_GRAPHICS_VIEWPORT_H
#define NLQT_GRAPHICS_VIEWPORT_H
#include <nel/misc/types_nl.h>
// STL includes
// Qt includes
#include <QWidget>
// NeL includes
#include <nel/misc/config_file.h>
#include <nel/misc/rgba.h>
// Project includes
class QAction;
namespace NL3D {
class UDriver;
class UTextContext;
class UScene;
}
class CGraphicsConfig;
/**
* CGraphicsViewport
* \brief CGraphicsViewport
* \date 2010-02-06 10:11GMT
* \author Jan Boon (Kaetemi)
*/
class CGraphicsViewport : public QWidget
{
Q_OBJECT
public:
CGraphicsViewport(QWidget *parent);
virtual ~CGraphicsViewport();
virtual QPaintEngine* paintEngine() const { return NULL; }
void init(CGraphicsConfig *graphicsConfig);
void release();
void updateInput();
void renderDriver();
void renderDebug2D();
QAction *createSaveScreenshotAction(QObject *parent);
void saveScreenshot(bool jpg, bool png, bool tga);
inline NL3D::UDriver *getDriver() { return m_Driver; }
inline NL3D::UTextContext *getTextContext() { return m_TextContext; }
// inline NL3D::UScene *getScene() { return m_Scene; }
public slots:
void saveScreenshot();
private slots:
void cfcbBackgroundColor(NLMISC::CRGBA backgroundColor);
void cfcbFontShadow(bool fontShadow);
private:
virtual void resizeEvent(QResizeEvent *resizeEvent);
private:
NLMISC::CRGBA m_BackgroundColor;
CGraphicsConfig *m_GraphicsConfig;
NL3D::UDriver *m_Driver;
NL3D::UTextContext *m_TextContext;
// NL3D::UScene *m_Scene;
bool m_Direct3D;
private:
CGraphicsViewport(const CGraphicsViewport &);
CGraphicsViewport &operator=(const CGraphicsViewport &);
}; /* class CGraphicsViewport */
#endif /* #ifndef NLQT_GRAPHICS_VIEWPORT_H */
/* end of file */

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "greenpill.ico"

@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/">
<file>icons/cross-circle.png</file>
<file>icons/exclamation.png</file>
<file>icons/information-white.png</file>
<file>icons/folder-open-image.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 651 B

@ -0,0 +1,165 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2014 Jan BOON (jan.boon@kaetemi.be)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <nel/misc/types_nl.h>
// STL includes
#include <stdio.h>
#ifdef NL_OS_WINDOWS
# include <windows.h>
# include <direct.h>
# include <tchar.h>
#endif
// Qt includes
#include <qglobal.h>
#ifdef Q_COMPILER_RVALUE_REFS
#undef Q_COMPILER_RVALUE_REFS
#endif
#include <QApplication>
#include <QMap>
#include <QStyleFactory>
#include <QFileInfo>
#ifdef QT_STATICPLUGIN
#include <QtPlugin>
#if defined(Q_OS_WIN32)
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
#elif defined(Q_OS_MAC)
Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)
#elif defined(Q_OS_UNIX)
Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
#endif
#endif
// NeL includes
#include <nel/misc/debug.h>
#include <nel/misc/common.h>
#include <nel/misc/file.h>
#include <nel/misc/path.h>
#include <nel/misc/command.h>
#include <nel/misc/sheet_id.h>
// Project includes
#include "../shared_widgets/common.h"
#include "main_window.h"
using namespace std;
using namespace NLMISC;
#define NLTOOLS_LOG_FILE "mesh_editor.log"
namespace {
CFileDisplayer *s_FileDisplayer = NULL;
} /* anonymous namespace */
#ifdef NL_OS_WINDOWS
# ifdef _UNICODE
# define tstring wstring
# else
# define tstring string
# endif
#endif
sint main(int argc, char **argv)
{
// low fragmentation heap (windows)
#ifdef NL_OS_WINDOWS
ULONG heapFragValue = 2; // enable low fragmentation heap
if (HeapSetInformation(GetProcessHeap(),
HeapCompatibilityInformation,
&heapFragValue, sizeof(heapFragValue)))
{
nlinfo("HeapSetInformation OK!\n");
}
else
{
nlwarning("HeapSetInformation FAIL! (%d)\n", GetLastError());
}
#endif
#ifdef NL_OS_WINDOWS
HRESULT hr;
hr = hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
bool coInitOk = (hr == S_OK) || (hr == S_FALSE);
#endif
std::string localAppData = CPath::getApplicationDirectory("NeL", true);
std::string appData = CPath::getApplicationDirectory("NeL");
CFile::createDirectoryTree(localAppData);
CFile::createDirectoryTree(appData);
CFile::createDirectoryTree(appData + "screenshots/");
CFile::setRWAccess(localAppData + "andbasr.ttf");
QFile::remove(QString::fromUtf8((localAppData + "andbasr.ttf").c_str()));
QFile(":/data/andbasr.ttf").copy(QString::fromUtf8((localAppData + "andbasr.ttf").c_str()));
CFile::setRWAccess(appData + "mesh_editor_default.cfg");
QFile::remove(QString::fromUtf8((appData + "mesh_editor_default.cfg").c_str()));
QFile(":/data/mesh_editor_default.cfg").copy(QString::fromUtf8((appData + "mesh_editor_default.cfg").c_str()));
if (!QFileInfo(QString::fromUtf8((appData + "mesh_editor.cfg").c_str())).exists())
{
QFile(":/data/mesh_editor.cfg").copy(QString::fromUtf8((appData + "mesh_editor.cfg").c_str()));
CFile::setRWAccess(appData + "mesh_editor.cfg");
}
NLQT::preApplication();
QApplication app(argc, const_cast<char **>(argv));
NLQT::postApplication();
// go nel!
{
// use log.log if NEL_LOG_IN_FILE and NLTOOLS_USE_LOG_LOG defined as 1
createDebug(NULL, false, false);
// create log
// filedisplayer only deletes the 001 etc
if (CFile::isExists(localAppData + NLTOOLS_LOG_FILE))
CFile::deleteFile(localAppData + NLTOOLS_LOG_FILE);
// initialize the log file
s_FileDisplayer = new CFileDisplayer();
s_FileDisplayer->setParam(localAppData + NLTOOLS_LOG_FILE, true);
DebugLog->addDisplayer(s_FileDisplayer);
InfoLog->addDisplayer(s_FileDisplayer);
WarningLog->addDisplayer(s_FileDisplayer);
AssertLog->addDisplayer(s_FileDisplayer);
ErrorLog->addDisplayer(s_FileDisplayer);
nlinfo("Welcome to NeL!");
}
CSheetId::initWithoutSheet();
CMainWindow mainWin;
mainWin.resize(1280, 720);
mainWin.show();
int result = app.exec();
#ifdef NL_OS_WINDOWS
if (coInitOk) CoUninitialize();
#endif
return result;
}
/* end of file */

@ -0,0 +1,548 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <nel/misc/types_nl.h>
#include "main_window.h"
// STL includes
// Qt includes
#include <QtGui>
#include <QTreeView>
#include <QDirModel>
#include <QUndoStack>
#include <QScrollArea>
#include <QAction>
#include <QMenuBar>
#include <QToolBar>
#include <QStatusBar>
#include <QDockWidget>
#include <QMessageBox>
// NeL includes
// #include <nel/misc/debug.h>
#include <nel/3d/u_driver.h>
#include <nel/misc/path.h>
#include <nel/pipeline/project_config.h>
// Project includes
#include "../shared_widgets/command_log.h"
#include "../shared_widgets/error_list.h"
#include "graphics_viewport.h"
#include "graphics_config.h"
#include "texture_select_dialog.h"
using namespace std;
using namespace NLMISC;
using namespace NLQT;
CMainWindow::CMainWindow(QWidget *parent, Qt::WindowFlags flags)
: QMainWindow(parent, flags),
m_UndoStack(NULL),
m_IsGraphicsInitialized(false), m_IsGraphicsEnabled(false),
m_IsSoundInitialized(false), m_IsSoundEnabled(false),
m_Timer(NULL), m_GraphicsViewport(NULL),
m_CommandLog(NULL), m_CommandLogDock(NULL),
m_ErrorList(NULL), m_ErrorListDock(NULL),
m_GraphicsConfig(NULL), m_GraphicsConfigScroll(NULL), m_GraphicsConfigDock(NULL),
m_FileMenu(NULL), m_EditMenu(NULL), m_ViewportMenu(NULL), m_WidgetsMenu(NULL), m_HelpMenu(NULL),
m_FileToolBar(NULL), m_EditToolBar(NULL),
m_AboutAct(NULL), m_QuitAct(NULL), m_PrintDebugAct(NULL),
m_UndoAct(NULL), m_RedoAct(NULL), m_SaveScreenshotAct(NULL),
m_IsExiting(false)
{
setObjectName("CMainWindow");
setWindowTitle(tr("NeL Mesh Editor"));
m_UndoStack = new QUndoStack(this);
m_Configuration.init();
m_GraphicsViewport = new CGraphicsViewport(this);
setCentralWidget(m_GraphicsViewport);
createActions();
createMenus();
createToolBars();
createStatusBar();
createDockWindows();
m_Configuration.setAndCallback("LanguageCode", CConfigCallback(this, &CMainWindow::cfcbLanguageCode));
recalculateMinimumWidth();
m_Timer = new QTimer(this);
connect(m_Timer, SIGNAL(timeout()), this, SLOT(updateRender()));
m_Timer->start(40); // 25fps
m_IsGraphicsEnabled = m_GraphicsConfig->getGraphicsEnabled();
connect(m_GraphicsConfig, SIGNAL(applyGraphicsConfig()), this, SLOT(applyGraphicsConfig()));
m_Configuration.setAndCallback("SoundEnabled", CConfigCallback(this, &CMainWindow::cfcbSoundEnabled));
NLMISC::CConfigFile::CVar *recentFiles = m_Configuration.getConfigFile().getVarPtr("RecentFiles");
if (recentFiles)
{
for (uint i = 0; i < recentFiles->size(); ++i)
{
if (NLMISC::CFile::isExists(recentFiles->asString()))
{
initProjectConfig(recentFiles->asString());
break;
}
}
}
/*
QDockWidget *dock = new QDockWidget(this);
dock->setFloating(true);
CTextureBrowser *browser = new CTextureBrowser(dock);
dock->setWidget(browser);
dock->resize(800, 800);
*/
CTextureSelectDialog *textureSelect = new CTextureSelectDialog(this);
textureSelect->exec();
}
CMainWindow::~CMainWindow()
{
m_Timer->stop();
updateInitialization(false);
delete m_GraphicsConfig; m_GraphicsConfig = NULL;
m_Configuration.dropCallback("SoundEnabled");
m_Configuration.dropCallback("LanguageCode");
m_Configuration.release();
}
void CMainWindow::initProjectConfig(const std::string &asset)
{
NLPIPELINE::CProjectConfig::init(asset,
NLPIPELINE::CProjectConfig::DatabaseTextureSearchPaths,
true);
std::string databaseRoot = NLPIPELINE::CProjectConfig::getAssetRoot();
m_AssetTreeView->setRootIndex(m_AssetTreeModel->index(QString::fromUtf8(databaseRoot.c_str())));
}
void CMainWindow::closeEvent(QCloseEvent *e)
{
m_Timer->stop();
updateInitialization(false);
QMainWindow::closeEvent(e);
}
void CMainWindow::setVisible(bool visible)
{
// called by show()
// code assuming visible window needed to init the 3d driver
if (visible != isVisible())
{
if (visible)
{
QMainWindow::setVisible(true);
updateInitialization(true);
}
else
{
updateInitialization(false);
QMainWindow::setVisible(false);
}
}
}
void CMainWindow::updateInitialization(bool visible)
{
bool done;
do
{
done = true; // set false whenever change
bool wantSound = m_IsSoundEnabled && visible;
bool wantGraphics = m_IsGraphicsEnabled && visible;
// bool wantLandscape = wantGraphics && m_IsGraphicsInitialized && isLandscapeEnabled;
// .. stuff that depends on other stuff goes on top to prioritize deinitialization
// Landscape
// ...
// Graphics (Driver)
if (m_IsGraphicsInitialized)
{
if (!wantGraphics)
{
m_IsGraphicsInitialized = false;
if (m_IsSoundInitialized)
m_SoundUtilities.releaseGraphics();
m_GraphicsViewport->release();
done = false;
}
}
else
{
if (wantGraphics)
{
m_GraphicsViewport->init(m_GraphicsConfig);
if (m_IsSoundInitialized)
m_SoundUtilities.initGraphics(m_GraphicsViewport);
m_IsGraphicsInitialized = true;
done = false;
}
}
// Sound (AudioMixer)
if (m_IsSoundInitialized)
{
if (!wantSound)
{
m_IsSoundInitialized = false;
if (m_IsGraphicsInitialized)
m_SoundUtilities.releaseGraphics();
m_SoundUtilities.release();
done = false;
}
}
else
{
if (wantSound)
{
m_SoundUtilities.init(&m_Configuration);
if (m_IsGraphicsInitialized)
m_SoundUtilities.initGraphics(m_GraphicsViewport);
m_IsSoundInitialized = true;
done = false;
}
}
} while (!done);
}
void CMainWindow::createActions()
{
m_QuitAct = new QAction(this);
m_QuitAct->setShortcuts(QKeySequence::Quit);
connect(m_QuitAct, SIGNAL(triggered()), this, SLOT(close()));
m_AboutAct = new QAction(this);
connect(m_AboutAct, SIGNAL(triggered()), this, SLOT(about()));
m_PrintDebugAct = new QAction(this);
connect(m_PrintDebugAct, SIGNAL(triggered()), this, SLOT(printDebug()));
m_UndoAct = m_UndoStack->createUndoAction(this);
m_UndoAct->setShortcuts(QKeySequence::Undo);
m_RedoAct = m_UndoStack->createRedoAction(this);
m_RedoAct->setShortcuts(QKeySequence::Redo);
m_SaveScreenshotAct = m_GraphicsViewport->createSaveScreenshotAction(this);
}
void CMainWindow::translateActions()
{
m_QuitAct->setText(tr("&Exit"));
m_QuitAct->setStatusTip(tr("Close the NeL Qt application."));
m_AboutAct->setText(tr("&About"));
m_AboutAct->setStatusTip(tr("Show the about box."));
m_PrintDebugAct->setText(tr("Print Debug"));
m_PrintDebugAct->setStatusTip(tr("Print something to debug."));
m_UndoAct->setText(tr("&Undo"));
m_UndoAct->setStatusTip(tr("Undo the last action."));
m_RedoAct->setText(tr("&Redo"));
m_RedoAct->setStatusTip(tr("Redo the last undone action."));
m_SaveScreenshotAct->setText(tr("Save &Screenshot"));
m_SaveScreenshotAct->setStatusTip(tr("Make a screenshot of the current viewport and save it to the default screenshot directory."));
}
void CMainWindow::createMenus()
{
m_FileMenu = menuBar()->addMenu(QString::null);
//m_FileMenu->addAction(saveAct);
//m_FileMenu->addSeparator();
m_FileMenu->addAction(m_QuitAct);
m_EditMenu = menuBar()->addMenu(QString::null);
m_EditMenu->addAction(m_UndoAct);
m_EditMenu->addAction(m_RedoAct);
m_ViewportMenu = menuBar()->addMenu(QString::null);
m_ViewportMenu->addAction(m_SaveScreenshotAct);
m_WidgetsMenu = menuBar()->addMenu(QString::null);
menuBar()->addSeparator();
m_HelpMenu = menuBar()->addMenu(QString::null);
m_HelpMenu->addAction(m_AboutAct);
}
void CMainWindow::translateMenus()
{
m_FileMenu->setTitle(tr("&File"));
m_EditMenu->setTitle(tr("&Edit"));
m_ViewportMenu->setTitle(tr("&Viewport"));
m_WidgetsMenu->setTitle(tr("&Widgets"));
m_HelpMenu->setTitle(tr("&Help"));
}
void CMainWindow::createToolBars()
{
m_FileToolBar = addToolBar(QString::null);
m_FileToolBar->addAction(m_QuitAct);
m_FileToolBar->addAction(m_PrintDebugAct);
m_EditToolBar = addToolBar(QString::null);
m_EditToolBar->addAction(m_AboutAct);
}
void CMainWindow::translateToolBars()
{
m_FileToolBar->setWindowTitle(tr("File"));
m_EditToolBar->setWindowTitle(tr("Edit"));
}
void CMainWindow::createStatusBar()
{
statusBar()->showMessage(tr("Ready"));
}
void CMainWindow::createDockWindows()
{
//QDockWidget *dock = new QDockWidget(tr("Test1"), this);
//dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
//customerList = new QListWidget(dock);
//dock->setWidget(customerList);
//addDockWidget(Qt::RightDockWidgetArea, dock);
//m_WidgetsMenu->addAction(dock->toggleViewAction());
//dock = new QDockWidget(tr("Test2"), this);
//paragraphsList = new QListWidget(dock);
//dock->setWidget(paragraphsList);
//addDockWidget(Qt::RightDockWidgetArea, dock);
//m_WidgetsMenu->addAction(dock->toggleViewAction());
//connect(customerList, SIGNAL(currentTextChanged(QString)),
// this, SLOT(insertCustomer(QString)));
//connect(paragraphsList, SIGNAL(currentTextChanged(QString)),
// this, SLOT(addParagraph(QString)));
//dock = new QDockWidget(
// CommandLog (Console)
{
m_CommandLogDock = new QDockWidget(this);
m_CommandLogDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
m_CommandLog = new CCommandLogDisplayer(m_CommandLogDock);
m_CommandLogDock->setWidget(m_CommandLog);
addDockWidget(Qt::BottomDockWidgetArea, m_CommandLogDock);
m_WidgetsMenu->addAction(m_CommandLogDock->toggleViewAction());
}
// ErrorList (Error List)
{
m_ErrorListDock = new QDockWidget(this);
m_ErrorListDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
m_ErrorList = new CErrorList(m_ErrorListDock);
m_ErrorListDock->setWidget(m_ErrorList);
addDockWidget(Qt::BottomDockWidgetArea, m_ErrorListDock);
m_WidgetsMenu->addAction(m_ErrorListDock->toggleViewAction());
tabifyDockWidget(m_CommandLogDock, m_ErrorListDock);
}
// GraphicsConfig (Graphics Configuration)
{
m_GraphicsConfigDock = new QDockWidget(this);
m_GraphicsConfigDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_GraphicsConfigScroll = new QScrollArea();
m_GraphicsConfigScroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_GraphicsConfigScroll->setWidgetResizable(true);
m_GraphicsConfig = new CGraphicsConfig(m_GraphicsConfigDock, &m_Configuration, m_UndoStack);
m_GraphicsConfigScroll->setWidget(m_GraphicsConfig);
m_GraphicsConfigDock->setWidget(m_GraphicsConfigScroll);
addDockWidget(Qt::RightDockWidgetArea, m_GraphicsConfigDock);
m_WidgetsMenu->addAction(m_GraphicsConfigDock->toggleViewAction());
}
// AssetTree (Assets)
{
m_AssetTreeDock = new QDockWidget(this);
m_AssetTreeDock->setAllowedAreas(Qt::AllDockWidgetAreas);
m_AssetTreeView = new QTreeView(m_AssetTreeDock);
m_AssetTreeModel = new QDirModel();
/*
QStringList filters;
filters.push_back("*.nelmat");
filters.push_back("*.dae");
filters.push_back("*.3ds");
filters.push_back("*.fbx");
filters.push_back("*.blend");
m_AssetTreeModel->setNameFilters(filters);
*/
m_AssetTreeView->setModel(m_AssetTreeModel);
m_AssetTreeView->setSortingEnabled(true);
m_AssetTreeDock->setWidget(m_AssetTreeView);
addDockWidget(Qt::LeftDockWidgetArea, m_AssetTreeDock);
m_WidgetsMenu->addAction(m_AssetTreeDock->toggleViewAction());
}
}
void CMainWindow::translateDockWindows()
{
m_CommandLogDock->setWindowTitle(tr("Console"));
m_ErrorListDock->setWindowTitle(tr("Error List"));
m_GraphicsConfigDock->setWindowTitle(tr("Graphics Configuration"));
m_AssetTreeDock->setWindowTitle(tr("Asset Database"));
}
void CMainWindow::recalculateMinimumWidth()
{
if (m_GraphicsConfigScroll)
m_GraphicsConfigScroll->setMinimumWidth(m_GraphicsConfig->minimumSizeHint().width() + m_GraphicsConfigScroll->minimumSizeHint().width());
}
void CMainWindow::applyGraphicsConfig()
{
// reinitializes the graphics system completely
// heavy lifting is done in updateInitialization
m_IsGraphicsEnabled = false;
updateInitialization(isVisible());
m_IsGraphicsEnabled = m_GraphicsConfig->getGraphicsEnabled();
updateInitialization(isVisible());
}
void CMainWindow::cfcbSoundEnabled(NLMISC::CConfigFile::CVar &var)
{
// temp, todo as above
m_IsSoundEnabled = var.asBool(); // update loop inits
}
void CMainWindow::cfcbLanguageCode(NLMISC::CConfigFile::CVar &var)
{
setWindowTitle(tr("NeL Mesh Editor"));
translateActions();
translateMenus();
translateToolBars();
translateDockWindows();
recalculateMinimumWidth();
}
void CMainWindow::about()
{
QMessageBox::about(this, tr("NeL Mesh Editor"), tr("NeL Mesh Editor"));
}
void CMainWindow::updateRender()
{
bool visible = isVisible();
updateInitialization(visible);
if (visible)
{
// call all update functions
// 01. Update Utilities (configuration etc)
m_Configuration.updateUtilities();
// 02. Update Time (deltas)
// ...
// 03. Update Receive (network, servertime, receive messages)
// ...
// 04. Update Input (keyboard controls, etc)
if (m_IsGraphicsInitialized)
m_GraphicsViewport->updateInput();
// 05. Update Weather (sky, snow, wind, fog, sun)
// ...
// 06. Update Entities (movement, do after possible tp from incoming messages etc)
// - Move other entities
// - Update self entity
// - Move bullets
// ...
// 07. Update Landscape (async zone loading near entity)
// ...
// 08. Update Collisions (entities)
// - Update entities
// - Update move container (swap with Update entities? todo: check code!)
// - Update bullets
// ...
// 09. Update Animations (playlists)
// - Needs to be either before or after entities, not sure,
// there was a problem with wrong order a while ago!!!
// ...
// 10. Update Camera (depends on entities)
// ...
// 11. Update Interface (login, ui, etc)
// ...
// 12. Update Sound (sound driver)
if (m_IsSoundInitialized)
m_SoundUtilities.updateSound();
// 13. Update Send (network, send new position etc)
// ...
// 14. Update Debug (stuff for dev)
// ...
if (m_IsGraphicsInitialized && !m_GraphicsViewport->getDriver()->isLost())
{
// 01. Render Driver (background color)
m_GraphicsViewport->renderDriver(); // clear all buffers
// 02. Render Sky (sky scene)
// ...
// 04. Render Scene (entity scene)
// ...
// 05. Render Effects (flare)
// ...
// 06. Render Interface 3D (player names)
// ...
// 07. Render Debug 3D
// ...
// 08. Render Interface 2D (chatboxes etc, optionally does have 3d)
// ...
// 09. Render Debug 2D (stuff for dev)
m_GraphicsViewport->renderDebug2D();
// swap 3d buffers
m_GraphicsViewport->getDriver()->swapBuffers();
}
}
}
void CMainWindow::printDebug()
{
nldebug("This is a debug message.");
}
/* end of file */

@ -0,0 +1,193 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NLQT_MAIN_WINDOW_H
#define NLQT_MAIN_WINDOW_H
#include <nel/misc/types_nl.h>
// STL includes
// Qt includes
#include <QMainWindow>
// NeL includes
#include <nel/misc/rgba.h>
#include <nel/misc/ucstring.h>
#include <nel/misc/time_nl.h>
#include <nel/3d/animation_time.h>
#include <nel/net/login_cookie.h>
// Project includes
#include "configuration.h"
#include "sound_utilities.h"
class QTreeView;
class QDirModel;
class QUndoStack;
class QScrollArea;
class QTimer;
namespace NLMISC {
class CConfigFile;
}
namespace NL3D {
class UDriver;
class UScene;
class UTextContext;
class UVisualCollisionManager;
}
namespace NLPACS {
class UMoveContainer;
class UGlobalRetriever;
}
namespace NLSOUND {
class UAudioMixer;
class CSoundAnimManager;
}
namespace NLQT {
class CCommandLogDisplayer;
class CErrorList;
}
class CGraphicsViewport;
class CGraphicsConfig;
/**
* CMainWindow
* \brief CMainWindow
* \date 2010-02-05 13:01GMT
* \author Jan Boon (Kaetemi)
*/
class CMainWindow : public QMainWindow
{
Q_OBJECT
public:
CMainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
virtual ~CMainWindow();
virtual void setVisible(bool visible);
private slots:
void applyGraphicsConfig();
// void applySoundConfig();
void about();
void updateRender();
void printDebug();
protected:
virtual void closeEvent(QCloseEvent *e);
private:
void updateInitialization(bool visible);
void initProjectConfig(const std::string &asset);
void createActions();
void translateActions();
void createMenus();
void translateMenus();
void createToolBars();
void translateToolBars();
void createStatusBar();
void createDockWindows();
void translateDockWindows();
void recalculateMinimumWidth();
void cfcbSoundEnabled(NLMISC::CConfigFile::CVar &var);
void cfcbLanguageCode(NLMISC::CConfigFile::CVar &var);
private:
CMainWindow(const CMainWindow &);
CMainWindow &operator=(const CMainWindow &);
private:
CConfiguration m_Configuration;
CSoundUtilities m_SoundUtilities;
QUndoStack *m_UndoStack;
bool m_IsExiting;
bool m_IsGraphicsInitialized, m_IsGraphicsEnabled;
bool m_IsSoundInitialized, m_IsSoundEnabled;
QTimer *m_Timer;
CGraphicsViewport *m_GraphicsViewport;
NLQT::CCommandLogDisplayer *m_CommandLog;
QDockWidget *m_CommandLogDock;
NLQT::CErrorList *m_ErrorList;
QDockWidget *m_ErrorListDock;
CGraphicsConfig *m_GraphicsConfig;
QScrollArea *m_GraphicsConfigScroll;
QDockWidget *m_GraphicsConfigDock;
QTreeView *m_AssetTreeView;
QDirModel *m_AssetTreeModel;
QDockWidget *m_AssetTreeDock;
QMenu *m_FileMenu;
QMenu *m_EditMenu;
QMenu *m_ViewportMenu;
QMenu *m_WidgetsMenu;
QMenu *m_HelpMenu;
QToolBar *m_FileToolBar;
QToolBar *m_EditToolBar;
QAction *m_AboutAct;
QAction *m_QuitAct;
QAction *m_PrintDebugAct;
QAction *m_UndoAct;
QAction *m_RedoAct;
QAction *m_SaveScreenshotAct;
//NLMISC::CConfigFile *ConfigFile; // owned by CConfiguration
//CLoadingScreen LoadingScreen; // owned by CLoading (special case, always available)
//NL3D::UDriver *Driver; // owned by CGraphics
//NL3D::UTextContext *TextContext; // owned by CGraphics
//NLSOUND::UAudioMixer *AudioMixer; // owned by CSound
//NLSOUND::CSoundAnimManager *SoundAnimManager; // owned by CSound
//THCOMMON::CSheetLoader *SheetLoader; // owned by initSheets and releaseSheets
//NL3D::UScene *Scene; // owned by CEnvironment
//NLPACS::UMoveContainer *MoveContainer; // owned by CEnvironment
//NLPACS::UGlobalRetriever *GlobalRetriever; /// The global retriever used for pacs // owned by CEnvironment
//NL3D::UVisualCollisionManager *VisualCollisionManager; /// The collision manager for ground snapping // owned by CEnvironment
//THCLIENT::CKeyBinder *KeyBinder; // owned by CInterface
//NLMISC::TLocalTime LocalTime; // use for delta only // owned by CGameTime
//NLMISC::TLocalTime LocalTimeDelta; // owned by CGameTime
//NL3D::TGlobalAnimationTime AnimationTime; // owned by CGameTime
//NL3D::TAnimationTime AnimationTimeDelta; // owned by CGameTime
//float FramesPerSecond; // owned by CGameTime
//float FramesPerSecondSmooth; // owned by CGameTime
//NLMISC::CVector DetailTargetPosition; // player or camera position for lod improvements // owned by camera
}; /* class CMainWindow */
#endif /* #ifndef NLQT_MAIN_WINDOW_H */
/* end of file */

@ -0,0 +1,952 @@
/****************************************************************************
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of a Qt Solutions component.
**
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Solutions Commercial License Agreement provided
** with the Software or, alternatively, in accordance with the terms
** contained in a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** Please note Third Party Software included with Qt Solutions may impose
** additional restrictions and it is the user's responsibility to ensure
** that they have met the licensing requirements of the GPL, LGPL, or Qt
** Solutions Commercial license and the relevant license of the Third
** Party Software they are using.
**
** If you are unsure which license is appropriate for your use, please
** contact Nokia at qt-info@nokia.com.
**
****************************************************************************/
#include "qtcolorpicker_p.h"
/*!
Constructs a QtColorPicker widget. The popup will display a grid
with \a cols columns, or if \a cols is -1, the number of columns
will be calculated automatically.
If \a enableColorDialog is true, the popup will also have a "More"
button (signified by an ellipsis "...") that presents a
QColorDialog when clicked.
After constructing a QtColorPicker, call insertColor() to add
individual colors to the popup grid, or call setStandardColors()
to add all the standard colors in one go.
The \a parent argument is passed to QFrame's constructor.
\sa QFrame
*/
QtColorPicker::QtColorPicker(QWidget *parent,
int cols, bool enableColorDialog)
: QPushButton(parent), popup(0), withColorDialog(enableColorDialog)
{
setFocusPolicy(Qt::StrongFocus);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
setAutoDefault(false);
setAutoFillBackground(true);
setCheckable(true);
// Set text
setText(tr("Black"));
firstInserted = false;
// Create and set icon
col = Qt::black;
dirty = true;
// Create color grid popup and connect to it.
popup = new ColorPickerPopup(cols, withColorDialog, this);
connect(popup, SIGNAL(selected(const QColor &)),
SLOT(setCurrentColor(const QColor &)));
connect(popup, SIGNAL(hid()), SLOT(popupClosed()));
// Connect this push button's pressed() signal.
connect(this, SIGNAL(toggled(bool)), SLOT(buttonPressed(bool)));
}
/*!
Destructs the QtColorPicker.
*/
QtColorPicker::~QtColorPicker()
{
}
/*! \internal
Pops up the color grid, and makes sure the status of
QtColorPicker's button is right.
*/
void QtColorPicker::buttonPressed(bool toggled)
{
if (!toggled)
return;
const QRect desktop = QApplication::desktop()->geometry();
// Make sure the popup is inside the desktop.
QPoint pos = mapToGlobal(rect().bottomLeft());
if (pos.x() < desktop.left())
pos.setX(desktop.left());
if (pos.y() < desktop.top())
pos.setY(desktop.top());
if ((pos.x() + popup->sizeHint().width()) > desktop.width())
pos.setX(desktop.width() - popup->sizeHint().width());
if ((pos.y() + popup->sizeHint().height()) > desktop.bottom())
pos.setY(desktop.bottom() - popup->sizeHint().height());
popup->move(pos);
if (ColorPickerItem *item = popup->find(col))
item->setSelected(true);
// Remove focus from this widget, preventing the focus rect
// from showing when the popup is shown. Order an update to
// make sure the focus rect is cleared.
clearFocus();
update();
// Allow keyboard navigation as soon as the popup shows.
popup->setFocus();
// Execute the popup. The popup will enter the event loop.
popup->show();
}
/*!
\internal
*/
void QtColorPicker::paintEvent(QPaintEvent *e)
{
if (dirty) {
int iconSize = style()->pixelMetric(QStyle::PM_SmallIconSize);
QPixmap pix(iconSize, iconSize);
pix.fill(palette().button().color());
QPainter p(&pix);
int w = pix.width(); // width of cell in pixels
int h = pix.height(); // height of cell in pixels
p.setPen(QPen(Qt::gray));
p.setBrush(col);
p.drawRect(2, 2, w - 5, h - 5);
setIcon(QIcon(pix));
dirty = false;
}
QPushButton::paintEvent(e);
}
/*! \internal
Makes sure the button isn't pressed when the popup hides.
*/
void QtColorPicker::popupClosed()
{
setChecked(false);
setFocus();
}
/*!
Returns the currently selected color.
\sa text()
*/
QColor QtColorPicker::currentColor() const
{
return col;
}
/*!
Returns the color at position \a index.
*/
QColor QtColorPicker::color(int index) const
{
return popup->color(index);
}
/*!
Adds the 17 predefined colors from the Qt namespace.
(The names given to the colors, "Black", "White", "Red", etc., are
all translatable.)
\sa insertColor()
*/
void QtColorPicker::setStandardColors()
{
insertColor(Qt::black, tr("Black"));
insertColor(Qt::white, tr("White"));
insertColor(Qt::red, tr("Red"));
insertColor(Qt::darkRed, tr("Dark red"));
insertColor(Qt::green, tr("Green"));
insertColor(Qt::darkGreen, tr("Dark green"));
insertColor(Qt::blue, tr("Blue"));
insertColor(Qt::darkBlue, tr("Dark blue"));
insertColor(Qt::cyan, tr("Cyan"));
insertColor(Qt::darkCyan, tr("Dark cyan"));
insertColor(Qt::magenta, tr("Magenta"));
insertColor(Qt::darkMagenta, tr("Dark magenta"));
insertColor(Qt::yellow, tr("Yellow"));
insertColor(Qt::darkYellow, tr("Dark yellow"));
insertColor(Qt::gray, tr("Gray"));
insertColor(Qt::darkGray, tr("Dark gray"));
insertColor(Qt::lightGray, tr("Light gray"));
}
/*!
Makes \a color current. If \a color is not already in the color grid, it
is inserted with the text "Custom".
This function emits the colorChanged() signal if the new color is
valid, and different from the old one.
*/
void QtColorPicker::setCurrentColor(const QColor &color)
{
if (col == color || !color.isValid())
return;
ColorPickerItem *item = popup->find(color);
if (!item) {
insertColor(color, tr("Custom"));
item = popup->find(color);
}
col = color;
setText(item->text());
dirty = true;
popup->hide();
repaint();
item->setSelected(true);
emit colorChanged(color);
}
/*!
Adds the color \a color with the name \a text to the color grid,
at position \a index. If index is -1, the color is assigned
automatically assigned a position, starting from left to right,
top to bottom.
*/
void QtColorPicker::insertColor(const QColor &color, const QString &text, int index)
{
popup->insertColor(color, text, index);
if (!firstInserted) {
col = color;
setText(text);
firstInserted = true;
}
}
/*! \property QtColorPicker::colorDialog
\brief Whether the ellipsis "..." (more) button is available.
If this property is set to TRUE, the color grid popup will include
a "More" button (signified by an ellipsis, "...") which pops up a
QColorDialog when clicked. The user will then be able to select
any custom color they like.
*/
void QtColorPicker::setColorDialogEnabled(bool enabled)
{
withColorDialog = enabled;
}
bool QtColorPicker::colorDialogEnabled() const
{
return withColorDialog;
}
/*!
Pops up a color grid with Qt default colors at \a point, using
global coordinates. If \a allowCustomColors is true, there will
also be a button on the popup that invokes QColorDialog.
For example:
\code
void Drawer::mouseReleaseEvent(QMouseEvent *e)
{
if (e->button() & RightButton) {
QColor color = QtColorPicker::getColor(mapToGlobal(e->pos()));
}
}
\endcode
*/
QColor QtColorPicker::getColor(const QPoint &point, bool allowCustomColors)
{
ColorPickerPopup popup(-1, allowCustomColors);
popup.insertColor(Qt::black, tr("Black"), 0);
popup.insertColor(Qt::white, tr("White"), 1);
popup.insertColor(Qt::red, tr("Red"), 2);
popup.insertColor(Qt::darkRed, tr("Dark red"), 3);
popup.insertColor(Qt::green, tr("Green"), 4);
popup.insertColor(Qt::darkGreen, tr("Dark green"), 5);
popup.insertColor(Qt::blue, tr("Blue"), 6);
popup.insertColor(Qt::darkBlue, tr("Dark blue"), 7);
popup.insertColor(Qt::cyan, tr("Cyan"), 8);
popup.insertColor(Qt::darkCyan, tr("Dark cyan"), 9);
popup.insertColor(Qt::magenta, tr("Magenta"), 10);
popup.insertColor(Qt::darkMagenta, tr("Dark magenta"), 11);
popup.insertColor(Qt::yellow, tr("Yellow"), 12);
popup.insertColor(Qt::darkYellow, tr("Dark yellow"), 13);
popup.insertColor(Qt::gray, tr("Gray"), 14);
popup.insertColor(Qt::darkGray, tr("Dark gray"), 15);
popup.insertColor(Qt::lightGray, tr("Light gray"), 16);
popup.move(point);
popup.exec();
return popup.lastSelected();
}
/*! \internal
Constructs the popup widget.
*/
ColorPickerPopup::ColorPickerPopup(int width, bool withColorDialog,
QWidget *parent)
: QFrame(parent, Qt::Popup)
{
setFrameStyle(QFrame::StyledPanel);
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
setFocusPolicy(Qt::StrongFocus);
setMouseTracking(true);
cols = width;
if (withColorDialog)
{
moreButton = new ColorPickerButton(this);
moreButton->setFixedWidth(24);
moreButton->setFixedHeight(21);
moreButton->setFrameRect(QRect(2, 2, 20, 17));
connect(moreButton, SIGNAL(clicked()), SLOT(getColorFromDialog()));
}
else
{
moreButton = 0;
}
eventLoop = 0;
grid = 0;
regenerateGrid();
}
/*! \internal
Destructs the popup widget.
*/
ColorPickerPopup::~ColorPickerPopup()
{
if (eventLoop)
eventLoop->exit();
}
/*! \internal
If there is an item whole color is equal to \a col, returns a
pointer to this item; otherwise returns 0.
*/
ColorPickerItem *ColorPickerPopup::find(const QColor &col) const
{
for (int i = 0; i < items.size(); ++i) {
if (items.at(i) && items.at(i)->color() == col)
return items.at(i);
}
return 0;
}
/*! \internal
Adds \a item to the grid. The items are added from top-left to
bottom-right.
*/
void ColorPickerPopup::insertColor(const QColor &col, const QString &text, int index)
{
// Don't add colors that we have already.
ColorPickerItem *existingItem = find(col);
ColorPickerItem *lastSelectedItem = find(lastSelected());
if (existingItem) {
if (lastSelectedItem && existingItem != lastSelectedItem)
lastSelectedItem->setSelected(false);
existingItem->setFocus();
existingItem->setSelected(true);
return;
}
ColorPickerItem *item = new ColorPickerItem(col, text, this);
if (lastSelectedItem) {
lastSelectedItem->setSelected(false);
}
else {
item->setSelected(true);
lastSel = col;
}
item->setFocus();
connect(item, SIGNAL(selected()), SLOT(updateSelected()));
if (index == -1)
index = items.count();
items.insert((unsigned int)index, item);
regenerateGrid();
update();
}
/*! \internal
*/
QColor ColorPickerPopup::color(int index) const
{
if (index < 0 || index > (int) items.count() - 1)
return QColor();
ColorPickerPopup *that = (ColorPickerPopup *)this;
return that->items.at(index)->color();
}
/*! \internal
*/
void ColorPickerPopup::exec()
{
show();
QEventLoop e;
eventLoop = &e;
(void) e.exec();
eventLoop = 0;
}
/*! \internal
*/
void ColorPickerPopup::updateSelected()
{
QLayoutItem *layoutItem;
int i = 0;
while ((layoutItem = grid->itemAt(i)) != 0) {
QWidget *w = layoutItem->widget();
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *litem = reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
if (litem != sender())
litem->setSelected(false);
}
++i;
}
if (sender() && sender()->inherits("ColorPickerItem")) {
ColorPickerItem *item = (ColorPickerItem *)sender();
lastSel = item->color();
emit selected(item->color());
}
hide();
}
/*! \internal
*/
void ColorPickerPopup::mouseReleaseEvent(QMouseEvent *e)
{
if (!rect().contains(e->pos()))
hide();
}
/*! \internal
Controls keyboard navigation and selection on the color grid.
*/
void ColorPickerPopup::keyPressEvent(QKeyEvent *e)
{
int curRow = 0;
int curCol = 0;
bool foundFocus = false;
for (int j = 0; !foundFocus && j < grid->rowCount(); ++j) {
for (int i = 0; !foundFocus && i < grid->columnCount(); ++i) {
if (widgetAt[j][i] && widgetAt[j][i]->hasFocus()) {
curRow = j;
curCol = i;
foundFocus = true;
break;
}
}
}
switch (e->key()) {
case Qt::Key_Left:
if (curCol > 0) --curCol;
else if (curRow > 0) { --curRow; curCol = grid->columnCount() - 1; }
break;
case Qt::Key_Right:
if (curCol < grid->columnCount() - 1 && widgetAt[curRow][curCol + 1]) ++curCol;
else if (curRow < grid->rowCount() - 1) { ++curRow; curCol = 0; }
break;
case Qt::Key_Up:
if (curRow > 0) --curRow;
else curCol = 0;
break;
case Qt::Key_Down:
if (curRow < grid->rowCount() - 1) {
QWidget *w = widgetAt[curRow + 1][curCol];
if (w) {
++curRow;
} else for (int i = 1; i < grid->columnCount(); ++i) {
if (!widgetAt[curRow + 1][i]) {
curCol = i - 1;
++curRow;
break;
}
}
}
break;
case Qt::Key_Space:
case Qt::Key_Return:
case Qt::Key_Enter: {
QWidget *w = widgetAt[curRow][curCol];
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
wi->setSelected(true);
QLayoutItem *layoutItem;
int i = 0;
while ((layoutItem = grid->itemAt(i)) != 0) {
QWidget *w = layoutItem->widget();
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *litem
= reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
if (litem != wi)
litem->setSelected(false);
}
++i;
}
lastSel = wi->color();
emit selected(wi->color());
hide();
} else if (w && w->inherits("QPushButton")) {
ColorPickerItem *wi = reinterpret_cast<ColorPickerItem *>(w);
wi->setSelected(true);
QLayoutItem *layoutItem;
int i = 0;
while ((layoutItem = grid->itemAt(i)) != 0) {
QWidget *w = layoutItem->widget();
if (w && w->inherits("ColorPickerItem")) {
ColorPickerItem *litem
= reinterpret_cast<ColorPickerItem *>(layoutItem->widget());
if (litem != wi)
litem->setSelected(false);
}
++i;
}
lastSel = wi->color();
emit selected(wi->color());
hide();
}
}
break;
case Qt::Key_Escape:
hide();
break;
default:
e->ignore();
break;
}
widgetAt[curRow][curCol]->setFocus();
}
/*! \internal
*/
void ColorPickerPopup::hideEvent(QHideEvent *e)
{
if (eventLoop) {
eventLoop->exit();
}
setFocus();
emit hid();
QFrame::hideEvent(e);
}
/*! \internal
*/
QColor ColorPickerPopup::lastSelected() const
{
return lastSel;
}
/*! \internal
Sets focus on the popup to enable keyboard navigation. Draws
focusRect and selection rect.
*/
void ColorPickerPopup::showEvent(QShowEvent *)
{
bool foundSelected = false;
for (int i = 0; i < grid->columnCount(); ++i) {
for (int j = 0; j < grid->rowCount(); ++j) {
QWidget *w = widgetAt[j][i];
if (w && w->inherits("ColorPickerItem")) {
if (((ColorPickerItem *)w)->isSelected()) {
w->setFocus();
foundSelected = true;
break;
}
}
}
}
if (!foundSelected) {
if (items.count() == 0)
setFocus();
else
widgetAt[0][0]->setFocus();
}
}
/*!
*/
void ColorPickerPopup::regenerateGrid()
{
widgetAt.clear();
int columns = cols;
if (columns == -1)
columns = (int) ceil(sqrt((float) items.count()));
// When the number of columns grows, the number of rows will
// fall. There's no way to shrink a grid, so we create a new
// one.
if (grid) delete grid;
grid = new QGridLayout(this);
grid->setMargin(1);
grid->setSpacing(0);
int ccol = 0, crow = 0;
for (int i = 0; i < items.size(); ++i) {
if (items.at(i)) {
widgetAt[crow][ccol] = items.at(i);
grid->addWidget(items.at(i), crow, ccol++);
if (ccol == columns) {
++crow;
ccol = 0;
}
}
}
if (moreButton) {
grid->addWidget(moreButton, crow, ccol);
widgetAt[crow][ccol] = moreButton;
}
updateGeometry();
}
/*! \internal
Copies the color dialog's currently selected item and emits
itemSelected().
*/
void ColorPickerPopup::getColorFromDialog()
{
bool ok;
QRgb rgb = QColorDialog::getRgba(lastSel.rgba(), &ok, parentWidget());
if (!ok)
return;
QColor col = QColor::fromRgba(rgb);
insertColor(col, tr("Custom"), -1);
lastSel = col;
emit selected(col);
}
/*!
Constructs a ColorPickerItem whose color is set to \a color, and
whose name is set to \a text.
*/
ColorPickerItem::ColorPickerItem(const QColor &color, const QString &text,
QWidget *parent)
: QFrame(parent), c(color), t(text), sel(false)
{
setToolTip(t);
setFixedWidth(24);
setFixedHeight(21);
}
/*!
Destructs a ColorPickerItem.
*/
ColorPickerItem::~ColorPickerItem()
{
}
/*!
Returns the item's color.
\sa text()
*/
QColor ColorPickerItem::color() const
{
return c;
}
/*!
Returns the item's text.
\sa color()
*/
QString ColorPickerItem::text() const
{
return t;
}
/*!
*/
bool ColorPickerItem::isSelected() const
{
return sel;
}
/*!
*/
void ColorPickerItem::setSelected(bool selected)
{
sel = selected;
update();
}
/*!
Sets the item's color to \a color, and its name to \a text.
*/
void ColorPickerItem::setColor(const QColor &color, const QString &text)
{
c = color;
t = text;
setToolTip(t);
update();
}
/*!
*/
void ColorPickerItem::mouseMoveEvent(QMouseEvent *)
{
setFocus();
update();
}
/*!
*/
void ColorPickerItem::mouseReleaseEvent(QMouseEvent *)
{
sel = true;
emit selected();
}
/*!
*/
void ColorPickerItem::mousePressEvent(QMouseEvent *)
{
setFocus();
update();
}
/*!
*/
void ColorPickerItem::paintEvent(QPaintEvent *)
{
QPainter p(this);
int w = width(); // width of cell in pixels
int h = height(); // height of cell in pixels
p.setPen( QPen( Qt::gray, 0, Qt::SolidLine ) );
if (sel)
p.drawRect(1, 1, w - 3, h - 3);
p.setPen( QPen( Qt::black, 0, Qt::SolidLine ) );
p.drawRect(3, 3, w - 7, h - 7);
p.fillRect(QRect(4, 4, w - 8, h - 8), QBrush(c));
if (hasFocus())
p.drawRect(0, 0, w - 1, h - 1);
}
/*!
*/
ColorPickerButton::ColorPickerButton(QWidget *parent)
: QFrame(parent)
{
setFrameStyle(StyledPanel);
}
/*!
*/
void ColorPickerButton::mousePressEvent(QMouseEvent *)
{
setFrameShadow(Sunken);
update();
}
/*!
*/
void ColorPickerButton::mouseMoveEvent(QMouseEvent *)
{
setFocus();
update();
}
/*!
*/
void ColorPickerButton::mouseReleaseEvent(QMouseEvent *)
{
setFrameShadow(Raised);
repaint();
emit clicked();
}
/*!
*/
void ColorPickerButton::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Up
|| e->key() == Qt::Key_Down
|| e->key() == Qt::Key_Left
|| e->key() == Qt::Key_Right)
{
qApp->sendEvent(parent(), e);
}
else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return)
{
setFrameShadow(Sunken);
update();
}
else
{
QFrame::keyPressEvent(e);
}
}
/*!
*/
void ColorPickerButton::keyReleaseEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Up
|| e->key() == Qt::Key_Down
|| e->key() == Qt::Key_Left
|| e->key() == Qt::Key_Right)
{
qApp->sendEvent(parent(), e);
}
else if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Space || e->key() == Qt::Key_Return)
{
setFrameShadow(Raised);
repaint();
emit clicked();
}
else
{
QFrame::keyReleaseEvent(e);
}
}
/*!
*/
void ColorPickerButton::focusInEvent(QFocusEvent *e)
{
setFrameShadow(Raised);
update();
QFrame::focusOutEvent(e);
}
/*!
*/
void ColorPickerButton::focusOutEvent(QFocusEvent *e)
{
setFrameShadow(Raised);
update();
QFrame::focusOutEvent(e);
}
/*!
*/
void ColorPickerButton::paintEvent(QPaintEvent *e)
{
QFrame::paintEvent(e);
QPainter p(this);
p.fillRect(contentsRect(), palette().button());
QRect r = rect();
int offset = frameShadow() == Sunken ? 1 : 0;
QPen pen(palette().buttonText(), 1);
p.setPen(pen);
p.drawRect(r.center().x() + offset - 4, r.center().y() + offset, 1, 1);
p.drawRect(r.center().x() + offset , r.center().y() + offset, 1, 1);
p.drawRect(r.center().x() + offset + 4, r.center().y() + offset, 1, 1);
if (hasFocus()) {
p.setPen( QPen( Qt::black, 0, Qt::SolidLine ) );
p.drawRect(0, 0, width() - 1, height() - 1);
}
p.end();
}

@ -0,0 +1,107 @@
/****************************************************************************
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of a Qt Solutions component.
**
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Solutions Commercial License Agreement provided
** with the Software or, alternatively, in accordance with the terms
** contained in a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** Please note Third Party Software included with Qt Solutions may impose
** additional restrictions and it is the user's responsibility to ensure
** that they have met the licensing requirements of the GPL, LGPL, or Qt
** Solutions Commercial license and the relevant license of the Third
** Party Software they are using.
**
** If you are unsure which license is appropriate for your use, please
** contact Nokia at qt-info@nokia.com.
**
****************************************************************************/
#ifndef QTCOLORPICKER_H
#define QTCOLORPICKER_H
#include <QPushButton>
#include <QString>
#include <QColor>
#include <QLabel>
#include <QEvent>
#include <QFocusEvent>
#define QT_QTCOLORPICKER_EXPORT
class ColorPickerPopup;
class QT_QTCOLORPICKER_EXPORT QtColorPicker : public QPushButton
{
Q_OBJECT
Q_PROPERTY(bool colorDialog READ colorDialogEnabled WRITE setColorDialogEnabled)
public:
QtColorPicker(QWidget *parent = 0,
int columns = -1, bool enableColorDialog = true);
~QtColorPicker();
void insertColor(const QColor &color, const QString &text = QString::null, int index = -1);
QColor currentColor() const;
QColor color(int index) const;
void setColorDialogEnabled(bool enabled);
bool colorDialogEnabled() const;
void setStandardColors();
static QColor getColor(const QPoint &pos, bool allowCustomColors = true);
public Q_SLOTS:
void setCurrentColor(const QColor &col);
Q_SIGNALS:
void colorChanged(const QColor &);
protected:
void paintEvent(QPaintEvent *e);
private Q_SLOTS:
void buttonPressed(bool toggled);
void popupClosed();
private:
ColorPickerPopup *popup;
QColor col;
bool withColorDialog;
bool dirty;
bool firstInserted;
};
#endif

@ -0,0 +1,251 @@
/****************************************************************************
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of a Qt Solutions component.
**
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Solutions Commercial License Agreement provided
** with the Software or, alternatively, in accordance with the terms
** contained in a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.1, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** Please note Third Party Software included with Qt Solutions may impose
** additional restrictions and it is the user's responsibility to ensure
** that they have met the licensing requirements of the GPL, LGPL, or Qt
** Solutions Commercial license and the relevant license of the Third
** Party Software they are using.
**
** If you are unsure which license is appropriate for your use, please
** contact Nokia at qt-info@nokia.com.
**
****************************************************************************/
#include <QApplication>
#include <QDesktopWidget>
#include <QPainter>
#include <QPushButton>
#include <QColorDialog>
#include <QMap>
#include <QLayout>
#include <QStyle>
#include <QLabel>
#include <QToolTip>
#include <QPixmap>
#include <QFocusEvent>
#include <QPaintEvent>
#include <QGridLayout>
#include <QHideEvent>
#include <QKeyEvent>
#include <QShowEvent>
#include <QMouseEvent>
#include <math.h>
#include "qtcolorpicker.h"
/*! \class QtColorPicker
\brief The QtColorPicker class provides a widget for selecting
colors from a popup color grid.
Users can invoke the color picker by clicking on it, or by
navigating to it and pressing Space. They can use the mouse or
arrow keys to navigate between colors on the grid, and select a
color by clicking or by pressing Enter or Space. The
colorChanged() signal is emitted whenever the color picker's color
changes.
The widget also supports negative selection: Users can click and
hold the mouse button on the QtColorPicker widget, then move the
mouse over the color grid and release the mouse button over the
color they wish to select.
The color grid shows a customized selection of colors. An optional
ellipsis "..." button (signifying "more") can be added at the
bottom of the grid; if the user presses this, a QColorDialog pops
up and lets them choose any color they like. This button is made
available by using setColorDialogEnabled().
When a color is selected, the QtColorPicker widget shows the color
and its name. If the name cannot be determined, the translatable
name "Custom" is used.
The QtColorPicker object is optionally initialized with the number
of columns in the color grid. Colors are then added left to right,
top to bottom using insertColor(). If the number of columns is not
set, QtColorPicker calculates the number of columns and rows that
will make the grid as square as possible.
\code
DrawWidget::DrawWidget(QWidget *parent, const char *name)
{
QtColorPicker *picker = new QtColorPicker(this);
picker->insertColor(red, "Red"));
picker->insertColor(QColor("green"), "Green"));
picker->insertColor(QColor(0, 0, 255), "Blue"));
picker->insertColor(white);
connect(colors, SIGNAL(colorChanged(const QColor &)), SLOT(setCurrentColor(const QColor &)));
}
\endcode
An alternative to adding colors manually is to initialize the grid
with QColorDialog's standard colors using setStandardColors().
QtColorPicker also provides a the static function getColor(),
which pops up the grid of standard colors at any given point.
\img colorpicker1.png
\img colorpicker2.png
\sa QColorDialog
*/
/*! \fn QtColorPicker::colorChanged(const QColor &color)
This signal is emitted when the QtColorPicker's color is changed.
\a color is the new color.
To obtain the color's name, use text().
*/
/*
A class that acts very much like a QPushButton. It's not styled,
so we can expect the exact same look, feel and geometry
everywhere. Also, this button always emits clicked on
mouseRelease, even if the mouse button was not pressed inside the
widget.
*/
class ColorPickerButton : public QFrame
{
Q_OBJECT
public:
ColorPickerButton(QWidget *parent);
signals:
void clicked();
protected:
void mousePressEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void keyPressEvent(QKeyEvent *e);
void keyReleaseEvent(QKeyEvent *e);
void paintEvent(QPaintEvent *e);
void focusInEvent(QFocusEvent *e);
void focusOutEvent(QFocusEvent *e);
};
/*
This class represents each "color" or item in the color grid.
*/
class ColorPickerItem : public QFrame
{
Q_OBJECT
public:
ColorPickerItem(const QColor &color = Qt::white, const QString &text = QString::null,
QWidget *parent = 0);
~ColorPickerItem();
QColor color() const;
QString text() const;
void setSelected(bool);
bool isSelected() const;
signals:
void clicked();
void selected();
public slots:
void setColor(const QColor &color, const QString &text = QString());
protected:
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void paintEvent(QPaintEvent *e);
private:
QColor c;
QString t;
bool sel;
};
/*
*/
class ColorPickerPopup : public QFrame
{
Q_OBJECT
public:
ColorPickerPopup(int width, bool withColorDialog,
QWidget *parent = 0);
~ColorPickerPopup();
void insertColor(const QColor &col, const QString &text, int index);
void exec();
void setExecFlag();
QColor lastSelected() const;
ColorPickerItem *find(const QColor &col) const;
QColor color(int index) const;
signals:
void selected(const QColor &);
void hid();
public slots:
void getColorFromDialog();
protected slots:
void updateSelected();
protected:
void keyPressEvent(QKeyEvent *e);
void showEvent(QShowEvent *e);
void hideEvent(QHideEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void regenerateGrid();
private:
QMap<int, QMap<int, QWidget *> > widgetAt;
QList<ColorPickerItem *> items;
QGridLayout *grid;
ColorPickerButton *moreButton;
QEventLoop *eventLoop;
int lastPos;
int cols;
QColor lastSel;
};

@ -0,0 +1,170 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <nel/misc/types_nl.h>
#include "sound_utilities.h"
// STL includes
// NeL includes
#include <nel/misc/debug.h>
#include <nel/misc/hierarchical_timer.h>
#include <nel/misc/config_file.h>
#include <nel/sound/u_audio_mixer.h>
#include <nel/sound/sound_anim_manager.h>
#include <nel/misc/progress_callback.h>
#include <nel/3d/u_particle_system_sound.h>
// Project includes
#include "configuration.h"
#include "graphics_viewport.h"
using namespace std;
using namespace NLMISC;
using namespace NLSOUND;
CSoundUtilities::CSoundUtilities()
: m_Configuration(NULL),
m_GraphicsViewport(NULL),
//m_LandscapeUtilities(NULL),
//m_PacsUtilities(NULL),
m_AudioMixer(NULL),
m_SoundAnimManager(NULL)
{
}
CSoundUtilities::~CSoundUtilities()
{
// release();
}
void CSoundUtilities::init(CConfiguration *configuration)
{
//H_AUTO2
nldebug("CSoundUtilities::init");
// copy parameters
m_Configuration = configuration;
// check stuff we need
nlassert(m_Configuration);
// create audiomixer
NL3D::UParticleSystemSound::setPSSound(NULL);
nlassert(!m_AudioMixer);
m_AudioMixer = UAudioMixer::createAudioMixer();
nlassert(m_AudioMixer);
// init audiomixer
std::vector<std::string> devices;
m_AudioMixer->initDriver(m_Configuration->getValue("SoundDriver", string("Auto")));
m_AudioMixer->getDevices(devices);
UAudioMixer::CInitInfo audioInfo;
audioInfo.AutoLoadSample = m_Configuration->getValue("SoundAutoLoadSample", true);
audioInfo.EnableOccludeObstruct = m_Configuration->getValue("SoundEnableOccludeObstruct", true);
audioInfo.EnableReverb = m_Configuration->getValue("SoundEnableReverb", true);
audioInfo.ManualRolloff = m_Configuration->getValue("SoundManualRolloff", true);
audioInfo.ForceSoftware = m_Configuration->getValue("SoundForceSoftware", false);
audioInfo.MaxTrack = m_Configuration->getValue("SoundMaxTrack", 48);
audioInfo.UseADPCM = m_Configuration->getValue("SoundUseADPCM", false);
m_AudioMixer->initDevice(m_Configuration->getValue("SoundDevice", string("")), audioInfo, NULL);
m_AudioMixer->setLowWaterMark(1);
// config callbacks
// ...
// sound anim manager
nlassert(!m_SoundAnimManager);
m_SoundAnimManager = new CSoundAnimManager(m_AudioMixer);
nlassert(m_SoundAnimManager);
// temp listener pos
m_AudioMixer->setListenerPos(CVector(0.0f, 0.0f, 0.0f));
// init sources
// ...
}
void CSoundUtilities::release()
{
//H_AUTO2
nldebug("CSoundUtilities::release");
// release sources
// ...
// release sound anim manager
if (m_SoundAnimManager)
{
delete m_SoundAnimManager;
m_SoundAnimManager = NULL;
}
else nlwarning("!m_SoundAnimManager");
// drop config callbacks
// ...
// release audiomixer (todo: +sources!!!)
if (m_AudioMixer)
{
delete m_AudioMixer;
m_AudioMixer = NULL;
}
else nlwarning("!m_AudioMixer");
// reset parameters
m_Configuration = NULL;
}
void CSoundUtilities::updateSound()
{
m_AudioMixer->update();
}
void CSoundUtilities::initGraphics(CGraphicsViewport *graphicsViewport)
{
//H_AUTO2
nldebug("CSoundUtilities::initGraphics");
// copy parameters
m_GraphicsViewport = graphicsViewport;
// check stuff we need
nlassert(m_GraphicsViewport);
// set particle system sound
NL3D::UParticleSystemSound::setPSSound(m_AudioMixer);
// ...
// todo: displayers for all the test sound sources :)
}
void CSoundUtilities::releaseGraphics()
{
//H_AUTO2
nldebug("CSoundUtilities::releaseGraphics");
// ..
// clear particle system sound
NL3D::UParticleSystemSound::setPSSound(NULL);
// reset parameters
m_GraphicsViewport = NULL;
}
/* end of file */

@ -0,0 +1,83 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NLQT_SOUND_UTILITIES_H
#define NLQT_SOUND_UTILITIES_H
#include <nel/misc/types_nl.h>
// STL includes
// NeL includes
// Project includes
namespace NLSOUND {
class UAudioMixer;
class CSoundAnimManager;
}
class CConfiguration;
class CGraphicsViewport;
//class CLandscapeUtilities;
//class CPacsUtilities;
/**
* CSoundUtilities
* \brief CSoundUtilities
* \date 2010-02-06 12:26GMT
* \author Jan Boon (Kaetemi)
*/
class CSoundUtilities
{
public:
CSoundUtilities();
virtual ~CSoundUtilities();
void init(CConfiguration *configuration);
void release();
void initGraphics(CGraphicsViewport *graphicsViewport);
void releaseGraphics();
//void initLandscape(CLandscapeUtilities *landscapeUtilities);
//void releaseLandscape();
//void initPacs(CPacsUtilities *pacsUtilities);
//void releasePacs();
void updateSound();
inline NLSOUND::UAudioMixer *getAudioMixer() { return m_AudioMixer; }
inline NLSOUND::CSoundAnimManager *getSoundAnimManager() { return m_SoundAnimManager; }
private:
CConfiguration *m_Configuration;
CGraphicsViewport *m_GraphicsViewport;
//CLandscapeUtilities *m_LandscapeUtilities;
//CPacsUtilities *m_PacsUtilities;
NLSOUND::UAudioMixer *m_AudioMixer;
NLSOUND::CSoundAnimManager *m_SoundAnimManager;
private:
CSoundUtilities(const CSoundUtilities &);
CSoundUtilities &operator=(const CSoundUtilities &);
}; /* class CSoundUtilities */
#endif /* #ifndef NLQT_SOUND_UTILITIES_H */
/* end of file */

@ -0,0 +1,200 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2016 Winch Gate Property Limited
// Author: Jan Boon <jan.boon@kaetemi.be>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <nel/misc/types_nl.h>
#include "texture_browser.h"
// STL includes
#include <functional>
// Qt includes
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QPixmap>
#include <QListWidget>
#include <QFileInfo>
// NeL includes
// #include <nel/misc/debug.h>
#include <nel/misc/common.h>
#include <nel/misc/bitmap.h>
#include <nel/misc/file.h>
#include <nel/misc/sha1.h>
#include <nel/pipeline/project_config.h>
// Project includes
#include "../shared_widgets/event_loop.h"
// See also: studio/.../gui_editor/texture_chooser.cpp
// UTILITY ->
QImage qImageFromCBitmap(NLMISC::CBitmap &bitmap, bool alpha)
{
QImage img(bitmap.getWidth(), bitmap.getHeight(), alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
NLMISC::CObjectVector<uint8> &pixels = bitmap.getPixels();
uint height = bitmap.getHeight();
uint stride = bitmap.getWidth() * sizeof(NLMISC::CRGBA);
for (uint y = 0; y < height; ++y)
{
// memcpy(img.scanLine(y), &pixels[y * stride], stride);
// Convert from ABGR to ARGB
uint8 *dst = img.scanLine(y);
uint8 *src = &pixels[y * stride];
for (uint x = 0; x < stride; x += 4)
{
dst[x] = src[x + 2];
dst[x + 1] = src[x + 1];
dst[x + 2] = src[x];
dst[x + 3] = src[x + 3];
}
}
return img;
}
// <- UTILITY
CTextureBrowser::CTextureBrowser(QWidget *parent) : QListWidget(parent)
{
qRegisterMetaType<CStdFunctionVoid>("CStdFunctionVoid");
m_Thread = new CEventLoop();
m_Thread->run();
setViewMode(QListWidget::IconMode);
setIconSize(QSize(128, 128));
setResizeMode(QListWidget::Adjust);
setGridSize(QSize(144, 160));
// setDirectory("W:/database/stuff/fyros/agents/_textures/actors/");
}
CTextureBrowser::~CTextureBrowser()
{
m_Thread->clear();
delete m_Thread;
}
std::string CTextureBrowser::getSelectedTextureFile() const
{
std::string res;
QList<QListWidgetItem *> items = selectedItems();
if (items.size() > 0)
res = items[0]->text().toUtf8().data();
return res;
}
void CTextureBrowser::setDirectory(const QString &dir)
{
if (dir == m_CurrentDirectory)
return;
// Remove any pending stuff
m_Thread->clear();
// Sync up, clear, and start processing
m_Thread->immediate([this, dir]() -> void {
invokeStdFunction([this, dir]() -> void {
clear();
std::string cacheDir = NLMISC::CPath::getApplicationDirectory("NeL", true) + "cache/thumbnails/";
NLMISC::CFile::createDirectoryTree(cacheDir);
std::vector<std::string> files;
NLMISC::CPath::getPathContent(dir.toUtf8().data(), false, false, true, files);
QImage dummyimg = QImage(128, 128, QImage::Format_ARGB32);
dummyimg.fill(0);
QIcon dummy = QIcon(QPixmap::fromImage(dummyimg));
for (size_t i = 0; i < files.size(); ++i)
{
std::string &file = files[i];
QString fileName = QFileInfo(QString::fromUtf8(file.c_str())).fileName();
std::string ext = NLMISC::toLower(NLMISC::CFile::getExtension(file));
if (ext == "dds" || ext == "tga" || ext == "png" || ext == "jpg" || ext == "jpeg")
{
QListWidgetItem *item = new QListWidgetItem(dummy, fileName);
item->setSizeHint(gridSize());
addItem(item);
m_Thread->immediate([this, file, cacheDir, item]() -> void {
CHashKey filePathHash = getSHA1((uint8 *)file.c_str(), file.size()); // Get SHA1 of filepath
std::string hash = NLMISC::toLower(filePathHash.toString()); // Hash in text format
std::string cacheFile = cacheDir + hash + ".png";
QString cacheFilePath = QString::fromUtf8(cacheFile.c_str());
uint32 assetModification = NLMISC::CFile::getFileModificationDate(file);
uint32 assetSize = NLMISC::CFile::getFileSize(file);
QImage image;
if (NLMISC::CFile::isExists(cacheFile))
{
if (image.load(QString::fromUtf8(cacheFile.c_str()), "PNG"))
{
// Use thumnbail if it matches only
uint32 thumbnailModification = image.text("NL_ASSET_MODIFICATION").toUInt();
uint32 thumbnailSize = image.text("NL_ASSET_SIZE").toUInt();
if (thumbnailSize != assetSize || thumbnailModification != assetModification)
{
image = QImage();
}
}
else
{
image = QImage();
}
}
if (image.isNull())
{
if (NLMISC::CFile::isExists(cacheFile))
NLMISC::CFile::deleteFile(cacheFile);
NLMISC::CIFile f;
if (f.open(file))
{
NLMISC::CBitmap bitmap;
bitmap.load(f);
uint w = bitmap.getWidth();
uint h = bitmap.getHeight();
if (w == h) bitmap.resample(128, 128);
else if (w > h) bitmap.resample(128, h * 128 / w);
else bitmap.resample(w * 128 / h, 128);
image = qImageFromCBitmap(bitmap, false);
image.setText("NL_ASSET_MODIFICATION", QString::number(assetModification));
image.setText("NL_ASSET_SIZE", QString::number(assetSize));
image.save(cacheFilePath, "PNG");
}
}
if (!image.isNull())
{
QIcon icon = QIcon(QPixmap::fromImage(image));
invokeStdFunction([this, icon, item]() -> void {
item->setIcon(icon); // IMPORANT: Must set icon with exact size of existing so the Qt UI doesn't flicker...
});
}
});
}
}
});
});
}
void CTextureBrowser::invokeStdFunction(CStdFunctionVoid f)
{
QMetaObject::invokeMethod(this, "callStdFunction", Qt::QueuedConnection, Q_ARG(CStdFunctionVoid, f));
}
void CTextureBrowser::callStdFunction(CStdFunctionVoid f)
{
f();
}
/* end of file */

@ -0,0 +1,71 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2016 Winch Gate Property Limited
// Author: Jan Boon <jan.boon@kaetemi.be>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NL_TEXTURE_BROWSER_H
#define NL_TEXTURE_BROWSER_H
#include <nel/misc/types_nl.h>
// STL includes
#include <functional>
// Qt includes
#include <QListWidget>
// NeL includes
// ...
class CEventLoop;
typedef std::function<void()> CStdFunctionVoid;
/**
* CTextureBrowser
* \brief CTextureBrowser
* \date 2016-02-18 14:06GMT
* \author Jan Boon <jan.boon@kaetemi.be>
*/
class CTextureBrowser : public QListWidget
{
Q_OBJECT
public:
CTextureBrowser(QWidget *parent = NULL);
virtual ~CTextureBrowser();
std::string getSelectedTextureFile() const;
void setDirectory(const QString &dir);
// STD INVOKE ->
public:
void invokeStdFunction(CStdFunctionVoid f);
private slots:
void callStdFunction(CStdFunctionVoid f);
// <- STD INVOKE
private:
CEventLoop *m_Thread;
QString m_CurrentDirectory;
private:
CTextureBrowser(const CTextureBrowser &);
CTextureBrowser &operator=(const CTextureBrowser &);
}; /* class CTextureBrowser */
#endif /* #ifndef NL_TEXTURE_BROWSER_H */
/* end of file */

@ -0,0 +1,113 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2016 Winch Gate Property Limited
// Author: Jan Boon <jan.boon@kaetemi.be>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <nel/misc/types_nl.h>
#include "texture_select_dialog.h"
// STL includes
#include <functional>
// Qt includes
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QMessageBox>
#include <QPixmap>
#include <QListWidget>
#include <QFileInfo>
#include <QSplitter>
#include <QPushButton>
#include <QDir>
// NeL includes
// #include <nel/misc/debug.h>
#include <nel/misc/common.h>
#include <nel/misc/bitmap.h>
#include <nel/misc/file.h>
#include <nel/misc/sha1.h>
#include <nel/pipeline/project_config.h>
// Project includes
#include "texture_browser.h"
CTextureSelectDialog::CTextureSelectDialog(QWidget *parent) : QDialog(parent)
{
resize(640, 400);
setWindowTitle(tr("Select Texture"));
m_TextureBrowser = new CTextureBrowser(this);
QVBoxLayout *outer = new QVBoxLayout(this);
setLayout(outer);
QSplitter *splitter = new QSplitter(Qt::Horizontal, this);
outer->addWidget(splitter);
QListWidget *folderList = new QListWidget(this);
splitter->addWidget(folderList);
splitter->addWidget(m_TextureBrowser);
QList<int> sizes;
sizes << 160 << 480;
splitter->setSizes(sizes);
QHBoxLayout *buttons = new QHBoxLayout(this);
outer->addLayout(buttons);
buttons->addStretch();
QPushButton *select = new QPushButton("Select", this);
buttons->addWidget(select);
QPushButton *cancel = new QPushButton("Cancel", this);
buttons->addWidget(cancel);
connect(select, &QPushButton::clicked, this, &QDialog::accept);
connect(cancel, &QPushButton::clicked, this, &QDialog::reject);
std::vector<std::string> paths;
NLPIPELINE::CProjectConfig::getDatabaseTextureSearchPaths(paths);
QString assetRoot = QString::fromUtf8(NLPIPELINE::CProjectConfig::getAssetRoot().c_str());
QIcon folder(":/icons/folder-open-image.png");
for (uint i = 0; i < paths.size(); ++i)
{
QString path = QString::fromUtf8(paths[i].c_str());
if (path.startsWith(assetRoot))
path = path.mid(assetRoot.size());
folderList->addItem(new QListWidgetItem(folder, path));
}
auto textChanged = [this, assetRoot](const QString &text) -> void {
if (text.isEmpty()) return;
else if (QDir::isRelativePath(text)) m_TextureBrowser->setDirectory(assetRoot + text);
else m_TextureBrowser->setDirectory(text);
};
if (folderList->count())
{
folderList->item(0)->setSelected(true);
textChanged(folderList->item(0)->text());
}
connect(folderList, &QListWidget::currentTextChanged, this, textChanged);
}
CTextureSelectDialog::~CTextureSelectDialog()
{
}
/* end of file */

@ -0,0 +1,60 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2016 Winch Gate Property Limited
// Author: Jan Boon <jan.boon@kaetemi.be>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NL_TEXTURE_SELECT_DIALOG_H
#define NL_TEXTURE_SELECT_DIALOG_H
#include <nel/misc/types_nl.h>
// STL includes
// Qt includes
#include <QDialog>
// NeL includes
// ...
// Project includes
#include "texture_browser.h"
/**
* CTextureSelectDialog
* \brief CTextureSelectDialog
* \date 2016-02-18 14:06GMT
* \author Jan Boon <jan.boon@kaetemi.be>
*/
class CTextureSelectDialog : public QDialog
{
Q_OBJECT
public:
CTextureSelectDialog(QWidget *parent = NULL);
virtual ~CTextureSelectDialog();
inline std::string getSelectedTextureFile() const { return m_TextureBrowser->getSelectedTextureFile(); }
private:
CTextureBrowser *m_TextureBrowser;
private:
CTextureSelectDialog(const CTextureSelectDialog &);
CTextureSelectDialog &operator=(const CTextureSelectDialog &);
}; /* class CTextureSelectDialog */
#endif /* #ifndef NL_TEXTURE_SELECT_DIALOG_H */
/* end of file */

@ -0,0 +1,363 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <nel/misc/types_nl.h>
#include "undo_redo_binders.h"
// STL includes
// Qt includes
#include <QUndoStack>
#include <QAbstractButton>
#include <QLineEdit>
#include <QComboBox>
// NeL includes
#include <nel/misc/debug.h>
// Project includes
#include "qtcolorpicker.h"
// using namespace std;
// using namespace NLMISC;
namespace {
int a_UndoCommandId = 9000;
} /* anonymous namespace */
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
CUndoRedoBinderButton::CUndoRedoBinderButton(QAbstractButton *abstractButton, QUndoStack *undoStack)
: QObject(abstractButton), m_AbstractButton(abstractButton), m_UndoStack(undoStack)
{
nlassert(m_AbstractButton);
bool c;
m_Checked = m_AbstractButton->isChecked();
c = connect(m_AbstractButton, SIGNAL(toggled(bool)), this, SLOT(abstractButtonToggled(bool)));
nlassertex(c, ("connect toggled(bool)"));
m_Enabled = true;
}
CUndoRedoBinderButton::~CUndoRedoBinderButton()
{
m_UndoStack->clear(); // may contain commands on a deleted button
}
void CUndoRedoBinderButton::abstractButtonToggled(bool checked)
{
if (m_Enabled)
{
if (checked != m_Checked)
{
bool undo = m_Checked;
/* bool redo = checked; */
m_Checked = checked; /* redo; */
m_UndoStack->push(new CUndoRedoCommandButton(this, m_AbstractButton, undo));
}
}
else
{
m_Checked = checked;
}
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
CUndoRedoCommandButton::CUndoRedoCommandButton(CUndoRedoBinderButton *binder, QAbstractButton *abstractButton, bool undo/*, bool redo*/)
: QUndoCommand(), m_Binder(binder), m_AbstractButton(abstractButton), m_Undo(undo)/*, m_Redo(redo)*/
{
// nldebug("CUndoRedoCommandButton::CUndoRedoCommandButton()");
nlassert(m_AbstractButton);
}
CUndoRedoCommandButton::~CUndoRedoCommandButton()
{
}
void CUndoRedoCommandButton::undo()
{
// nldebug("CUndoRedoCommandButton::undo()");
// nlassert(m_AbstractButton);
m_Binder->enable(false);
if (m_AbstractButton->isChecked() != m_Undo)
m_AbstractButton->setChecked(m_Undo);
m_Binder->enable(true);
}
void CUndoRedoCommandButton::redo()
{
// nldebug("CUndoRedoCommandButton::redo()");
// nlassert(m_AbstractButton);
m_Binder->enable(false);
if (m_AbstractButton->isChecked() == m_Undo) /* != m_Redo) */
m_AbstractButton->setChecked(!m_Undo); /* (m_Redo); */
m_Binder->enable(true);
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
CUndoRedoBinderLineEdit::CUndoRedoBinderLineEdit(QLineEdit *lineEdit, QUndoStack *undoStack)
: QObject(lineEdit), m_LineEdit(lineEdit), m_UndoStack(undoStack)
{
nlassert(m_LineEdit);
m_Id = ++a_UndoCommandId;
bool c;
m_LastValue = m_LineEdit->text();
c = connect(m_LineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(lineEditTextChanged(const QString &)));
nlassertex(c, ("connect textChanged(const QString &)"));
m_Enabled = true;
}
CUndoRedoBinderLineEdit::~CUndoRedoBinderLineEdit()
{
m_UndoStack->clear(); // may contain commands on a deleted LineEdit
}
void CUndoRedoBinderLineEdit::lineEditTextChanged(const QString &text)
{
if (m_LineEdit->isRedoAvailable())
{
// workaround internal undo redo of lineedit
m_LineEdit->redo();
m_UndoStack->undo();
return;
}
if (m_Enabled)
{
if (text != m_LastValue)
{
QString undo = m_LastValue;
const QString &redo = text;
m_LastValue = redo;
m_UndoStack->push(new CUndoRedoCommandLineEdit(this, m_LineEdit, undo, redo, m_Id));
}
}
else
{
m_LastValue = text;
}
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
CUndoRedoCommandLineEdit::CUndoRedoCommandLineEdit(CUndoRedoBinderLineEdit *binder, QLineEdit *lineEdit, const QString &undo, const QString &redo, int id)
: QUndoCommand(), m_Binder(binder), m_LineEdit(lineEdit), m_Undo(undo), m_Redo(redo), m_Id(id)
{
// nldebug("CUndoRedoCommandLineEdit::CUndoRedoCommandLineEdit()");
nlassert(m_LineEdit);
}
CUndoRedoCommandLineEdit::~CUndoRedoCommandLineEdit()
{
}
bool CUndoRedoCommandLineEdit::mergeWith(const QUndoCommand *other)
{
if (m_Id != other->id()) return false;
m_Redo = static_cast<const CUndoRedoCommandLineEdit *>(other)->m_Redo;
return true;
}
void CUndoRedoCommandLineEdit::undo()
{
// nldebug("CUndoRedoCommandLineEdit::undo()");
// nlassert(m_LineEdit);
m_Binder->enable(false);
if (m_LineEdit->text() != m_Undo)
m_LineEdit->setText(m_Undo);
m_Binder->enable(true);
}
void CUndoRedoCommandLineEdit::redo()
{
// nldebug("CUndoRedoCommandLineEdit::redo()");
// nlassert(m_LineEdit);
m_Binder->enable(false);
if (m_LineEdit->text() != m_Redo)
m_LineEdit->setText(m_Redo);
m_Binder->enable(true);
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
CUndoRedoBinderComboBox::CUndoRedoBinderComboBox(QComboBox *comboBox, QUndoStack *undoStack)
: QObject(comboBox), m_ComboBox(comboBox), m_UndoStack(undoStack)
{
nlassert(m_ComboBox);
bool c;
m_LastValue = m_ComboBox->currentIndex();
c = connect(m_ComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(comboBoxCurrentIndexChanged(int)));
nlassertex(c, ("connect currentIndexChanged(int)"));
m_Enabled = true;
}
CUndoRedoBinderComboBox::~CUndoRedoBinderComboBox()
{
m_UndoStack->clear(); // may contain commands on a deleted ComboBox
}
void CUndoRedoBinderComboBox::comboBoxCurrentIndexChanged(int index)
{
if (m_Enabled)
{
if (index != m_LastValue)
{
int undo = m_LastValue;
int redo = index;
m_LastValue = redo;
m_UndoStack->push(new CUndoRedoCommandComboBox(this, m_ComboBox, undo, redo));
}
}
else
{
m_LastValue = index;
}
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
CUndoRedoCommandComboBox::CUndoRedoCommandComboBox(CUndoRedoBinderComboBox *binder, QComboBox *comboBox, int undo, int redo)
: QUndoCommand(), m_Binder(binder), m_ComboBox(comboBox), m_Undo(undo), m_Redo(redo)
{
// nldebug("CUndoRedoCommandComboBox::CUndoRedoCommandComboBox()");
nlassert(m_ComboBox);
}
CUndoRedoCommandComboBox::~CUndoRedoCommandComboBox()
{
}
void CUndoRedoCommandComboBox::undo()
{
// nldebug("CUndoRedoCommandComboBox::undo()");
// nlassert(m_ComboBox);
m_Binder->enable(false);
if (m_ComboBox->currentIndex() != m_Undo)
m_ComboBox->setCurrentIndex(m_Undo);
m_Binder->enable(true);
}
void CUndoRedoCommandComboBox::redo()
{
// nldebug("CUndoRedoCommandComboBox::redo()");
// nlassert(m_ComboBox);
m_Binder->enable(false);
if (m_ComboBox->currentIndex() != m_Redo)
m_ComboBox->setCurrentIndex(m_Redo);
m_Binder->enable(true);
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
CUndoRedoBinderColorPicker::CUndoRedoBinderColorPicker(QtColorPicker *colorPicker, QUndoStack *undoStack)
: QObject(colorPicker), m_ColorPicker(colorPicker), m_UndoStack(undoStack)
{
nlassert(m_ColorPicker);
bool c;
m_LastValue = m_ColorPicker->currentColor();
c = connect(m_ColorPicker, SIGNAL(colorChanged(const QColor &)), this, SLOT(colorPickerColorChanged(const QColor &)));
nlassertex(c, ("connect colorChanged(const QColor &)"));
m_Enabled = true;
}
CUndoRedoBinderColorPicker::~CUndoRedoBinderColorPicker()
{
m_UndoStack->clear(); // may contain commands on a deleted ColorPicker
}
void CUndoRedoBinderColorPicker::colorPickerColorChanged(const QColor &col)
{
if (m_Enabled)
{
if (col != m_LastValue)
{
QColor undo = m_LastValue;
const QColor &redo = col;
m_LastValue = redo;
m_UndoStack->push(new CUndoRedoCommandColorPicker(this, m_ColorPicker, undo, redo));
}
}
else
{
m_LastValue = col;
}
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
CUndoRedoCommandColorPicker::CUndoRedoCommandColorPicker(CUndoRedoBinderColorPicker *binder, QtColorPicker *colorPicker, const QColor &undo, const QColor &redo)
: QUndoCommand(), m_Binder(binder), m_ColorPicker(colorPicker), m_Undo(undo), m_Redo(redo)
{
// nldebug("CUndoRedoCommandColorPicker::CUndoRedoCommandColorPicker()");
nlassert(m_ColorPicker);
}
CUndoRedoCommandColorPicker::~CUndoRedoCommandColorPicker()
{
}
void CUndoRedoCommandColorPicker::undo()
{
// nldebug("CUndoRedoCommandColorPicker::undo()");
// nlassert(m_ColorPicker);
m_Binder->enable(false);
if (m_ColorPicker->currentColor() != m_Undo)
m_ColorPicker->setCurrentColor(m_Undo);
m_Binder->enable(true);
}
void CUndoRedoCommandColorPicker::redo()
{
// nldebug("CUndoRedoCommandColorPicker::redo()");
// nlassert(m_ColorPicker);
m_Binder->enable(false);
if (m_ColorPicker->currentColor() != m_Redo)
m_ColorPicker->setCurrentColor(m_Redo);
m_Binder->enable(true);
}
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/* end of file */

@ -0,0 +1,314 @@
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef NLQT_UNDO_REDO_BINDERS_H
#define NLQT_UNDO_REDO_BINDERS_H
#include <nel/misc/types_nl.h>
// STL includes
// Qt includes
#include <QObject>
#include <QString>
#include <QColor>
#include <QUndoCommand>
// NeL includes
// Project includes
class QUndoStack;
class QAbstractButton;
class QLineEdit;
class QComboBox;
class QtColorPicker;
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/**
* CUndoRedoBinderButton
* \brief CUndoRedoBinderButton
* \date 2010-02-13 14:02GMT
* \author Jan Boon (Kaetemi)
*/
class CUndoRedoBinderButton : public QObject
{
Q_OBJECT
public:
CUndoRedoBinderButton(QAbstractButton *abstractButton, QUndoStack *undoStack);
virtual ~CUndoRedoBinderButton();
inline void enable(bool enabled) { m_Enabled = enabled; }
private slots:
void abstractButtonToggled(bool checked);
private:
bool m_Enabled; // binder enabled
bool m_Checked;
QAbstractButton *m_AbstractButton;
QUndoStack *m_UndoStack;
private:
CUndoRedoBinderButton(const CUndoRedoBinderButton &);
CUndoRedoBinderButton &operator=(const CUndoRedoBinderButton &);
}; /* class CUndoRedoBinderButton */
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/**
* CUndoRedoCommandButton
* \brief CUndoRedoCommandButton
* \date 2010-02-13 14:02GMT
* \author Jan Boon (Kaetemi)
*/
class CUndoRedoCommandButton : public QUndoCommand
{
public:
CUndoRedoCommandButton(CUndoRedoBinderButton *binder, QAbstractButton *abstractButton, bool undo/*, bool redo*/);
virtual ~CUndoRedoCommandButton();
virtual void undo();
virtual void redo();
private:
bool m_Undo;
/*bool m_Redo;*/
CUndoRedoBinderButton *m_Binder;
QAbstractButton *m_AbstractButton;
QUndoStack *m_UndoStack;
private:
CUndoRedoCommandButton(const CUndoRedoCommandButton &);
CUndoRedoCommandButton &operator=(const CUndoRedoCommandButton &);
}; /* class CUndoRedoCommandButton */
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/**
* CUndoRedoBinderLineEdit
* \brief CUndoRedoBinderLineEdit
* \date 2010-02-13 14:02GMT
* \author Jan Boon (Kaetemi)
*/
class CUndoRedoBinderLineEdit : public QObject
{
Q_OBJECT
public:
CUndoRedoBinderLineEdit(QLineEdit *lineEdit, QUndoStack *undoStack);
virtual ~CUndoRedoBinderLineEdit();
inline void enable(bool enabled) { m_Enabled = enabled; }
private slots:
void lineEditTextChanged(const QString &text);
private:
bool m_Enabled; // binder enabled
QString m_LastValue;
QLineEdit *m_LineEdit;
QUndoStack *m_UndoStack;
int m_Id;
private:
CUndoRedoBinderLineEdit(const CUndoRedoBinderLineEdit &);
CUndoRedoBinderLineEdit &operator=(const CUndoRedoBinderLineEdit &);
}; /* class CUndoRedoBinderLineEdit */
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/**
* CUndoRedoCommandLineEdit
* \brief CUndoRedoCommandLineEdit
* \date 2010-02-13 14:02GMT
* \author Jan Boon (Kaetemi)
*/
class CUndoRedoCommandLineEdit : public QUndoCommand
{
public:
CUndoRedoCommandLineEdit(CUndoRedoBinderLineEdit *binder, QLineEdit *abtractLineEdit, const QString &undo, const QString &redo, int id);
virtual ~CUndoRedoCommandLineEdit();
virtual void undo();
virtual void redo();
virtual int id() const { return m_Id; };
virtual bool mergeWith(const QUndoCommand *other);
private:
QString m_Undo;
QString m_Redo;
CUndoRedoBinderLineEdit *m_Binder;
QLineEdit *m_LineEdit;
QUndoStack *m_UndoStack;
int m_Id;
private:
CUndoRedoCommandLineEdit(const CUndoRedoCommandLineEdit &);
CUndoRedoCommandLineEdit &operator=(const CUndoRedoCommandLineEdit &);
}; /* class CUndoRedoCommandLineEdit */
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/**
* CUndoRedoBinderComboBox
* \brief CUndoRedoBinderComboBox
* \date 2010-02-13 14:02GMT
* \author Jan Boon (Kaetemi)
*/
class CUndoRedoBinderComboBox : public QObject
{
Q_OBJECT
public:
CUndoRedoBinderComboBox(QComboBox *comboBox, QUndoStack *undoStack);
virtual ~CUndoRedoBinderComboBox();
inline void enable(bool enabled) { m_Enabled = enabled; }
private slots:
void comboBoxCurrentIndexChanged(int index);
private:
bool m_Enabled; // binder enabled
int m_LastValue;
QComboBox *m_ComboBox;
QUndoStack *m_UndoStack;
private:
CUndoRedoBinderComboBox(const CUndoRedoBinderComboBox &);
CUndoRedoBinderComboBox &operator=(const CUndoRedoBinderComboBox &);
}; /* class CUndoRedoBinderComboBox */
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/**
* CUndoRedoCommandComboBox
* \brief CUndoRedoCommandComboBox
* \date 2010-02-13 14:02GMT
* \author Jan Boon (Kaetemi)
*/
class CUndoRedoCommandComboBox : public QUndoCommand
{
public:
CUndoRedoCommandComboBox(CUndoRedoBinderComboBox *binder, QComboBox *abtractComboBox, int undo, int redo);
virtual ~CUndoRedoCommandComboBox();
virtual void undo();
virtual void redo();
private:
int m_Undo;
int m_Redo;
CUndoRedoBinderComboBox *m_Binder;
QComboBox *m_ComboBox;
QUndoStack *m_UndoStack;
private:
CUndoRedoCommandComboBox(const CUndoRedoCommandComboBox &);
CUndoRedoCommandComboBox &operator=(const CUndoRedoCommandComboBox &);
}; /* class CUndoRedoCommandComboBox */
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/**
* CUndoRedoBinderColorPicker
* \brief CUndoRedoBinderColorPicker
* \date 2010-02-13 14:02GMT
* \author Jan Boon (Kaetemi)
*/
class CUndoRedoBinderColorPicker : public QObject
{
Q_OBJECT
public:
CUndoRedoBinderColorPicker(QtColorPicker *colorPicker, QUndoStack *undoStack);
virtual ~CUndoRedoBinderColorPicker();
inline void enable(bool enabled) { m_Enabled = enabled; }
private slots:
void colorPickerColorChanged(const QColor &col);
private:
bool m_Enabled; // binder enabled
QColor m_LastValue;
QtColorPicker *m_ColorPicker;
QUndoStack *m_UndoStack;
private:
CUndoRedoBinderColorPicker(const CUndoRedoBinderColorPicker &);
CUndoRedoBinderColorPicker &operator=(const CUndoRedoBinderColorPicker &);
}; /* class CUndoRedoBinderColorPicker */
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
/**
* CUndoRedoCommandColorPicker
* \brief CUndoRedoCommandColorPicker
* \date 2010-02-13 14:02GMT
* \author Jan Boon (Kaetemi)
*/
class CUndoRedoCommandColorPicker : public QUndoCommand
{
public:
CUndoRedoCommandColorPicker(CUndoRedoBinderColorPicker *binder, QtColorPicker *abtractColorPicker, const QColor &undo, const QColor &redo);
virtual ~CUndoRedoCommandColorPicker();
virtual void undo();
virtual void redo();
private:
QColor m_Undo;
QColor m_Redo;
CUndoRedoBinderColorPicker *m_Binder;
QtColorPicker *m_ColorPicker;
QUndoStack *m_UndoStack;
private:
CUndoRedoCommandColorPicker(const CUndoRedoCommandColorPicker &);
CUndoRedoCommandColorPicker &operator=(const CUndoRedoCommandColorPicker &);
}; /* class CUndoRedoCommandColorPicker */
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
#endif /* #ifndef NLQT_UNDO_REDO_BINDERS_H */
/* end of file */

@ -24,6 +24,24 @@
#include <nel/3d/register_3d.h>
#include <nel/3d/scene.h>
#ifdef NL_OS_WINDOWS
#define main nlMain
int nlMain(int argc, char *argv[]);
static std::vector<std::string> nlArgs;
static std::vector<const char *> nlCArgs;
int wmain(int argc, wchar_t *argv[])
{
nlArgs.resize(argc);
nlCArgs.resize(argc);
for (int i = 0; i < argc; ++i)
{
nlArgs[i] = wideToUtf8(argv[i]);
nlCArgs[i] = nlArgs[i].c_str();
}
nlMain(argc, const_cast<char **>(&nlCArgs[0]));
}
#endif
int main(int argc, char *argv[])
{
NLMISC::CApplicationContext app;

@ -279,10 +279,10 @@ void exportShapes(CMeshUtilsContext &context)
}
}
// TODO: Separate load scene and save scene functions
int exportScene(const CMeshUtilsSettings &settings)
int initSceneContext(CMeshUtilsContext &context)
{
CMeshUtilsContext context(settings);
const CMeshUtilsSettings &settings = context.Settings;
NLMISC::CFile::createDirectoryTree(settings.DestinationDirectoryPath);
if (!settings.ToolDependLog.empty())
@ -290,22 +290,41 @@ int exportScene(const CMeshUtilsSettings &settings)
if (!settings.ToolErrorLog.empty())
context.ToolLogger.initError(settings.ToolErrorLog);
context.ToolLogger.writeDepend(NLPIPELINE::BUILD, "*", NLMISC::CPath::standardizePath(context.Settings.SourceFilePath, false).c_str()); // Base input file
// Apply database configuration
if (!NLPIPELINE::CProjectConfig::init(settings.SourceFilePath,
// Apply database configuration
if (!NLPIPELINE::CProjectConfig::init(settings.SourceFilePath,
NLPIPELINE::CProjectConfig::DatabaseTextureSearchPaths,
true))
{
tlerror(context.ToolLogger, context.Settings.SourceFilePath.c_str(), "Unable to find database.cfg in input path or any of its parents.");
tlwarning(context.ToolLogger, context.Settings.SourceFilePath.c_str(), "Unable to find nel.cfg in input path or any of its parents.");
// return EXIT_FAILURE; We can continue but the output will not be guaranteed...
}
return EXIT_SUCCESS;
}
int loadSceneMeta(CMeshUtilsContext &context)
{
if (context.SceneMeta.load(context.Settings.SourceFilePath))
context.ToolLogger.writeDepend(NLPIPELINE::BUILD, "*", context.SceneMeta.metaFilePath().c_str()); // Meta input file
return EXIT_SUCCESS;
}
int importSceneAssimp(CMeshUtilsContext &context)
{
std::vector<char> memFile;
{
NLMISC::CIFile ifile(context.Settings.SourceFilePath);
memFile.resize(ifile.getFileSize());
ifile.serialBuffer((uint8 *)&memFile[0], memFile.size());
}
std::string fileExt = NLMISC::CFile::getExtension(context.Settings.SourceFilePath);
Assimp::Importer importer;
const aiScene *scene = importer.ReadFile(settings.SourceFilePath, 0
| aiProcess_Triangulate
const aiScene *scene = importer.ReadFileFromMemory(&memFile[0], memFile.size(), 0
| aiProcess_Triangulate
| aiProcess_ValidateDataStructure
| aiProcess_GenNormals // Or GenSmoothNormals? TODO: Validate smoothness between material boundaries!
); // aiProcess_SplitLargeMeshes | aiProcess_LimitBoneWeights
, fileExt.c_str()); // aiProcess_SplitLargeMeshes | aiProcess_LimitBoneWeights
if (!scene)
{
const char *errs = importer.GetErrorString();
@ -313,6 +332,7 @@ int exportScene(const CMeshUtilsSettings &settings)
else tlerror(context.ToolLogger, context.Settings.SourceFilePath.c_str(), "Unable to load scene");
return EXIT_FAILURE;
}
// aiProcess_Triangulate
// aiProcess_ValidateDataStructure: TODO: Catch Assimp error output stream
// aiProcess_RemoveRedundantMaterials: Not used because we may override materials with NeL Material from meta
@ -320,8 +340,6 @@ int exportScene(const CMeshUtilsSettings &settings)
//scene->mRootNode->mMetaData
context.InternalScene = scene;
if (context.SceneMeta.load(context.Settings.SourceFilePath))
context.ToolLogger.writeDepend(NLPIPELINE::BUILD, "*", context.SceneMeta.metaFilePath().c_str()); // Meta input file
validateInternalNodeNames(context, context.InternalScene->mRootNode);
@ -344,10 +362,43 @@ int exportScene(const CMeshUtilsSettings &settings)
// Import shapes
importShapes(context, context.InternalScene->mRootNode);
return EXIT_SUCCESS;
}
int saveSceneMeta(CMeshUtilsContext &context)
{
// Save scene meta
context.SceneMeta.save();
return EXIT_SUCCESS;
}
int exportScene(CMeshUtilsContext &context)
{
// Export shapes
exportShapes(context);
return EXIT_SUCCESS;
}
int exportScene(const CMeshUtilsSettings &settings)
{
CMeshUtilsContext context(settings);
int res;
res = initSceneContext(context);
if (res != EXIT_SUCCESS) return res;
res = loadSceneMeta(context);
if (res != EXIT_SUCCESS) return res;
res = importSceneAssimp(context);
if (res != EXIT_SUCCESS) return res;
res = exportScene(context);
return res;
}
/* end of file */

@ -21,6 +21,7 @@
#include <string>
struct CMeshUtilsContext;
struct CMeshUtilsSettings
{
CMeshUtilsSettings();
@ -37,6 +38,14 @@ struct CMeshUtilsSettings
std::string SkelDirectory;*/
};
int initSceneContext(CMeshUtilsContext &context);
int loadSceneMeta(CMeshUtilsContext &context);
int saveSceneMeta(CMeshUtilsContext &context);
int importSceneAssimp(CMeshUtilsContext &context);
int exportScene(CMeshUtilsContext &context);
int exportScene(const CMeshUtilsSettings &settings);
#endif /* NL_MESH_UTILS_H */

@ -60,8 +60,8 @@ CCommandLog::CCommandLog(QWidget *parent) : QWidget(parent)
layout->addWidget(m_CommandInput);
setLayout(layout);
connect(m_CommandInput, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
connect(this, SIGNAL(tSigDisplay(const QColor &, const QString &)), this, SLOT(tSlotDisplay(const QColor &, const QString &)));
connect(m_CommandInput, SIGNAL(returnPressed()), this, SLOT(returnPressed()), Qt::QueuedConnection);
connect(this, SIGNAL(tSigDisplay(const QColor &, const QString &)), this, SLOT(tSlotDisplay(const QColor &, const QString &)), Qt::QueuedConnection);
}
@ -123,7 +123,7 @@ void CCommandLog::returnPressed()
CCommandLogDisplayer::CCommandLogDisplayer(QWidget *parent) : CCommandLog(parent)
{
connect(this, SIGNAL(execCommand(const std::string &)), this, SLOT(execCommandLog(const std::string &)));
connect(this, SIGNAL(execCommand(const QString &)), this, SLOT(execCommandLog(const QString &)), Qt::QueuedConnection);
DebugLog->addDisplayer(this);
InfoLog->addDisplayer(this);
WarningLog->addDisplayer(this);

@ -48,16 +48,21 @@ namespace {
void preApplication()
{
QCoreApplication::libraryPaths();
QString app_location = QCoreApplication::applicationFilePath();
app_location.truncate(app_location.lastIndexOf(QLatin1Char('/')));
app_location = QDir(app_location).canonicalPath();
QCoreApplication::removeLibraryPath(app_location);
QCoreApplication::addLibraryPath("./platforms");
QCoreApplication::addLibraryPath("./qtwebengine");
QCoreApplication::addLibraryPath("./imageformats");
QCoreApplication::addLibraryPath("./iconengines");
QCoreApplication::addLibraryPath("./designer");
char *qpa = getenv("QT_QPA_PLATFORM_PLUGIN_PATH");
if (qpa && qpa[0])
{
// Trick to avoid Qt attempting to load up every file in the application path as Qt plugin, speeds up debug startup
QCoreApplication::libraryPaths();
QString app_location = QCoreApplication::applicationFilePath();
app_location.truncate(app_location.lastIndexOf(QLatin1Char('/')));
app_location = QDir(app_location).canonicalPath();
QCoreApplication::removeLibraryPath(app_location);
QCoreApplication::addLibraryPath("./platforms");
QCoreApplication::addLibraryPath("./qtwebengine");
QCoreApplication::addLibraryPath("./imageformats");
QCoreApplication::addLibraryPath("./iconengines");
QCoreApplication::addLibraryPath("./designer");
}
}
void postApplication()

@ -0,0 +1,477 @@
/*
Copyright (C) 2015 by authors
Author: Jan Boon <jan.boon@kaetemi.be>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Source: https://github.com/kaetemi/errorlist
#include "error_list.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QListWidget>
#include <QListWidgetItem>
#include <QTextEdit>
#include <QSplitter>
#include <QDateTime>
namespace NLQT {
#define DATAROLE_TYPE (Qt::UserRole + 0)
#define DATAROLE_TIMESTAMP (Qt::UserRole + 1)
#define DATAROLE_GROUP (Qt::UserRole + 2)
#define DATAROLE_MESSAGE (Qt::UserRole + 3)
#define DATAROLE_LINE (Qt::UserRole + 4)
#define DATAROLE_USERDATA (Qt::UserRole + 5)
#define DATAROLE_COLLAPSED (Qt::UserRole + 6)
class CErrorListItem : public QListWidgetItem
{
public:
CErrorListItem(const QIcon &icon, const QString &message) : QListWidgetItem(icon, message)
{
}
virtual bool operator<(const QListWidgetItem &other) const Q_DECL_OVERRIDE
{
time_t this_timestamp = data(DATAROLE_TIMESTAMP).toInt();
time_t other_timestamp = other.data(DATAROLE_TIMESTAMP).toInt();
return this_timestamp < other_timestamp;
}
};
const char *iconNames[] = {
":/icons/cross-circle.png",
":/icons/exclamation.png",
":/icons/information-white.png"
};
const char *filterText[] = {
"Errors",
"Warnings",
"Messages"
};
CErrorList::CErrorList(QWidget *parent) : QWidget(parent), m_Collapse(true), m_CollapseBtn(NULL), m_Message(NULL)
{
m_Filter[0] = true;
m_Filter[1] = true;
m_Filter[2] = true;
m_FilterBtn[0] = NULL;
m_FilterBtn[1] = NULL;
m_FilterBtn[2] = NULL;
m_FilterCounts[0] = 0;
m_FilterCounts[1] = 0;
m_FilterCounts[2] = 0;
QVBoxLayout *layout = new QVBoxLayout(this);
QHBoxLayout *buttons = new QHBoxLayout(this);
QPushButton *clearBtn = new QPushButton(this);
clearBtn->setText(tr("Clear"));
connect(clearBtn, SIGNAL(clicked()), this, SLOT(clear()));
buttons->addWidget(clearBtn);
QPushButton *collapseBtn = new QPushButton(this);
m_CollapseBtn = collapseBtn;
collapseBtn->setText(tr("Collapse"));
collapseBtn->setCheckable(true);
collapseBtn->setChecked(m_Collapse);
connect(collapseBtn, SIGNAL(toggled(bool)), this, SLOT(collapse(bool)));
buttons->addWidget(collapseBtn);
buttons->addStretch();
QPushButton *errorBtn = new QPushButton(this);
m_FilterBtn[0] = errorBtn;
errorBtn->setIcon(QIcon(iconNames[0]));
updateFilterCount(0);
errorBtn->setCheckable(true);
errorBtn->setChecked(m_Filter[0]);
connect(errorBtn, SIGNAL(toggled(bool)), this, SLOT(filterError(bool)));
buttons->addWidget(errorBtn);
QPushButton *warningBtn = new QPushButton(this);
m_FilterBtn[1] = warningBtn;
warningBtn->setIcon(QIcon(iconNames[1]));
updateFilterCount(1);
warningBtn->setCheckable(true);
warningBtn->setChecked(m_Filter[1]);
connect(warningBtn, SIGNAL(toggled(bool)), this, SLOT(filterWarning(bool)));
buttons->addWidget(warningBtn);
QPushButton *messageBtn = new QPushButton(this);
m_FilterBtn[2] = messageBtn;
messageBtn->setIcon(QIcon(iconNames[2]));
updateFilterCount(2);
messageBtn->setCheckable(true);
messageBtn->setChecked(m_Filter[2]);
connect(messageBtn, SIGNAL(toggled(bool)), this, SLOT(filterMessage(bool)));
buttons->addWidget(messageBtn);
layout->addLayout(buttons);
QSplitter *splitter = new QSplitter(Qt::Vertical, this);
m_List = new QListWidget(this);
m_List->setTextElideMode(Qt::ElideRight);
m_List->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
// m_List->setSortingEnabled(true);
connect(m_List, &QListWidget::itemClicked, this, &CErrorList::listItemClicked);
connect(m_List, &QListWidget::itemDoubleClicked, this, &CErrorList::listItemDoubleClicked);
splitter->addWidget(m_List);
QTextEdit *messageText = new QTextEdit(this);
m_Message = messageText;
messageText->setReadOnly(true);
messageText->setVisible(false);
messageText->setAcceptRichText(true);
splitter->addWidget(messageText);
layout->addWidget(splitter);
setLayout(layout);
}
CErrorList::~CErrorList()
{
}
void CErrorList::clear()
{
m_CurrentMessage = NULL;
m_Message->setVisible(false);
m_CollapseItems.clear();
m_List->clear();
m_FilterCounts[0] = 0;
m_FilterCounts[1] = 0;
m_FilterCounts[2] = 0;
updateFilterCount(0);
updateFilterCount(1);
updateFilterCount(2);
}
void CErrorList::clear(const QString &group)
{
for (int i = 0; i < m_List->count(); ++i)
{
QListWidgetItem *item = m_List->item(i);
if (item->data(DATAROLE_GROUP).toString() == group)
{
if (m_CurrentMessage == item)
{
m_CurrentMessage = NULL;
m_Message->setVisible(false);
}
if (m_Collapse)
{
QString cs = getCollapseString(item);
std::map<QString, QListWidgetItem *>::iterator it
= m_CollapseItems.find(cs);
if (it != m_CollapseItems.end())
m_CollapseItems.erase(it);
}
--m_FilterCounts[(int)item->data(DATAROLE_TYPE).toInt()];
delete item;
--i;
}
}
updateFilterCount(0);
updateFilterCount(1);
updateFilterCount(2);
}
void CErrorList::collapse(bool c)
{
if (c != m_Collapse)
{
m_Collapse = c;
m_CollapseBtn->setChecked(c);
if (c)
{
for (int i = 0; i < m_List->count(); ++i)
{
QListWidgetItem *item = m_List->item(i);
QString cs = getCollapseString(item);
QListWidgetItem *ref = m_CollapseItems[cs];
if (ref != NULL)
{
ref->setData(DATAROLE_COLLAPSED, ref->data(DATAROLE_COLLAPSED).toInt() + 1);
updateCollapseText(ref);
item->setData(DATAROLE_COLLAPSED, 0);
item->setHidden(true);
if (m_CurrentMessage == item)
{
m_CurrentMessage = NULL;
m_Message->setHidden(true);
}
}
else
{
m_CollapseItems[cs] = item;
}
}
}
else
{
m_CollapseItems.clear();
for (int i = 0; i < m_List->count(); ++i)
{
int cc = m_List->item(i)->data(DATAROLE_COLLAPSED).toInt();
if (cc > 1)
{
m_List->item(i)->setText(m_List->item(i)->data(DATAROLE_LINE).toString());
}
if (cc == 0)
{
bool hide = !m_Filter[m_List->item(i)->data(DATAROLE_TYPE).toInt()];
m_List->item(i)->setHidden(hide);
}
if (cc != 1)
{
m_List->item(i)->setData(DATAROLE_COLLAPSED, 1);
}
}
}
}
}
void CErrorList::filter(ErrorType type, bool f)
{
if (f != m_Filter[(int)type])
{
m_Filter[(int)type] = f;
m_FilterBtn[(int)type]->setChecked(f);
for (int i = 0; i < m_List->count(); ++i)
{
if (m_List->item(i)->data(DATAROLE_TYPE).toInt() == (int)type)
{
bool hide =
m_List->item(i)->data(DATAROLE_COLLAPSED).toInt() == 0
|| !f;
m_List->item(i)->setHidden(hide);
if (hide && m_CurrentMessage == m_List->item(i))
{
m_CurrentMessage = NULL;
m_Message->setHidden(true);
}
}
}
}
}
void CErrorList::updateFilterCount(int filter)
{
m_FilterBtn[filter]->setText(QString(" ") + QString::number(m_FilterCounts[filter]) + " " + filterText[filter]);
}
void CErrorList::filterError(bool f)
{
filter(Error, f);
}
void CErrorList::filterWarning(bool f)
{
filter(Warning, f);
}
void CErrorList::filterMessage(bool f)
{
filter(Message, f);
}
void CErrorList::markClear(const QString &group)
{
for (int i = 0; i < m_List->count(); ++i)
{
QListWidgetItem *item = m_List->item(i);
if (item->data(DATAROLE_GROUP).toString() == group)
{
QString cs = getCollapseString(item);
m_MarkedClear.insert(cs);
}
}
}
void CErrorList::clearMarked()
{
for (int i = 0; i < m_List->count(); ++i)
{
QListWidgetItem *item = m_List->item(i);
QString cs = getCollapseString(item);
if (m_MarkedClear.find(cs) != m_MarkedClear.end())
{
if (m_CurrentMessage == item)
{
m_CurrentMessage = NULL;
m_Message->setVisible(false);
}
if (m_Collapse)
{
QString cs = getCollapseString(item);
std::map<QString, QListWidgetItem *>::iterator it
= m_CollapseItems.find(cs);
if (it != m_CollapseItems.end())
m_CollapseItems.erase(it);
}
--m_FilterCounts[(int)item->data(DATAROLE_TYPE).toInt()];
delete item;
--i;
}
}
}
void CErrorList::listItemClicked(QListWidgetItem *item)
{
if (item != m_CurrentMessage)
{
if (item->isSelected())
{
QString text = item->data(DATAROLE_MESSAGE).toString();
m_Message->setHtml(text);
m_Message->setVisible(true);
}
else
{
m_CurrentMessage = NULL;
m_Message->setVisible(false);
}
}
}
void CErrorList::listItemDoubleClicked(QListWidgetItem *item)
{
emit request(item->data(DATAROLE_GROUP).toString(), item->data(DATAROLE_USERDATA).toMap());
}
QString CErrorList::getCollapseString(QListWidgetItem *item)
{
return item->data(DATAROLE_GROUP).toString() + " / " + item->data(DATAROLE_LINE).toString();
}
void CErrorList::updateCollapseText(QListWidgetItem *item)
{
item->setText(QString("(" + QString::number(item->data(DATAROLE_COLLAPSED).toInt()) + "x) " + item->data(DATAROLE_LINE).toString()));// .replace('\n', ' ').replace('\r', ' ')));
}
void CErrorList::add(ErrorType type, const QString &group, time_t timestamp, const QString &message, const QMap<QString, QVariant> &userData)
{
QTextDocument doc;
doc.setHtml(message);
QString line = doc.toPlainText().replace('\n', ' ').replace('\r', ' ');
CErrorListItem *item = new CErrorListItem(QIcon(iconNames[(int)type]), line);
item->setData(DATAROLE_TYPE, (int)type);
item->setData(DATAROLE_TIMESTAMP, timestamp);
item->setData(DATAROLE_GROUP, group);
item->setData(DATAROLE_MESSAGE, message);
item->setData(DATAROLE_LINE, line);
item->setData(DATAROLE_USERDATA, userData);
QString cs = getCollapseString(item);
if (m_MarkedClear.find(cs) != m_MarkedClear.end())
{
m_MarkedClear.erase(cs);
return;
}
bool hide = m_Collapse;
if (hide)
{
QListWidgetItem *ref = m_CollapseItems[cs];
hide = ref != NULL;
if (hide)
{
ref->setData(DATAROLE_COLLAPSED, ref->data(DATAROLE_COLLAPSED).toInt() + 1);
updateCollapseText(ref);
item->setData(DATAROLE_COLLAPSED, 0);
}
else
{
m_CollapseItems[cs] = item;
}
}
if (!hide)
{
item->setData(DATAROLE_COLLAPSED, 1);
hide = !m_Filter[(int)type];
}
m_List->addItem(item);
item->setHidden(hide);
++m_FilterCounts[(int)type];
updateFilterCount((int)type);
}
void CErrorList::update(const QString &group, const QString &message)
{
// NOTE: This does not play well with collapse, so you should only have one message present in the category
// Automatically adds a message if no message exists in the category
for (int i = 0; i < m_List->count(); ++i)
{
QListWidgetItem *item = m_List->item(i);
if (item->data(DATAROLE_GROUP).toString() == group)
{
QTextDocument doc;
doc.setHtml(message);
QString line = doc.toPlainText().replace('\n', ' ').replace('\r', ' ');
item->setData(DATAROLE_MESSAGE, message);
item->setData(DATAROLE_LINE, line);
item->setText(line);
return;
}
}
add(Message, group, message);
}
void CErrorList::add(ErrorType type, const QString &group, time_t timestamp, const QString &message)
{
QMap<QString, QVariant> nullMap;
add(type, group, timestamp, message, nullMap);
}
void CErrorList::add(ErrorType type, const QString &group, const QString &message, const QMap<QString, QVariant> &userData)
{
add(type, group, QDateTime::currentDateTime().toTime_t(), message, userData);
}
void CErrorList::add(ErrorType type, const QString &group, const QString &message)
{
QMap<QString, QVariant> nullMap;
add(type, group, message, nullMap);
}
}
/* end of file */

@ -0,0 +1,118 @@
/*
Copyright (C) 2015 by authors
Author: Jan Boon <jan.boon@kaetemi.be>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Source: https://github.com/kaetemi/errorlist
#ifndef ERRORLIST_H
#define ERRORLIST_H
#define ERRORLIST_EXPORT
#include <set>
#include <map>
#include <QWidget>
#include <QString>
#include <QMap>
#include <QVariant>
class QListWidgetItem;
class QListWidget;
class QPushButton;
class QTextEdit;
namespace NLQT {
class ERRORLIST_EXPORT CErrorList : public QWidget
{
Q_OBJECT
public:
enum ErrorType
{
Error,
Warning,
Message
};
public:
CErrorList(QWidget *parent);
virtual ~CErrorList();
void add(ErrorType type, const QString &group, time_t timestamp, const QString &message, const QMap<QString, QVariant> &userData);
void add(ErrorType type, const QString &group, time_t timestamp, const QString &message);
void add(ErrorType type, const QString &group, const QString &message, const QMap<QString, QVariant> &userData);
void add(ErrorType type, const QString &group, const QString &message);
void update(const QString &group, const QString &message);
void markClear(const QString &group);
void clearMarked();
void clear(const QString &group);
void filter(ErrorType type, bool f);
signals:
void request(const QString &group, const QMap<QString, QVariant> &userData);
public slots:
void clear();
void collapse(bool c);
void filterError(bool f);
void filterWarning(bool f);
void filterMessage(bool f);
private slots:
void listItemClicked(QListWidgetItem *item);
void listItemDoubleClicked(QListWidgetItem *item);
private:
void updateFilterCount(int filter);
static QString getCollapseString(QListWidgetItem *item);
static void updateCollapseText(QListWidgetItem *item);
private:
QListWidget *m_List;
std::map<QString, QListWidgetItem *> m_CollapseItems;
bool m_Collapse;
QPushButton *m_CollapseBtn;
bool m_Filter[3];
QPushButton *m_FilterBtn[3];
int m_FilterCounts[3];
QTextEdit *m_Message;
QListWidgetItem *m_CurrentMessage;
std::set<QString> m_MarkedClear;
}; /* class CErrorList */
}
#endif /* ERRORLIST_H */
/* end of file */

@ -0,0 +1,281 @@
/*
Copyright (C) 2016 by authors
Author: Jan Boon <jan.boon@kaetemi.be>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Source: https://github.com/kaetemi/threadutil/blob/master/threadutil/eventloop.h
#ifndef NL_EVENT_LOOP_H
#define NL_EVENT_LOOP_H
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <queue>
#include <set>
class CEventLoop
{
public:
CEventLoop() : m_Running(false), m_Handle(0)
{
}
~CEventLoop()
{
stop();
clear();
}
void run()
{
stop();
m_Running = true;
m_Thread = std::move(std::thread(&CEventLoop::loop, this));
}
void runSync()
{
stop();
m_Running = true;
loop();
}
void stop() // thread-safe
{
m_Running = false;
poke();
if (m_Thread.joinable())
m_Thread.join();
}
void clear() // thread-safe
{
std::unique_lock<std::mutex> lock(m_QueueLock);
std::unique_lock<std::mutex> tlock(m_QueueTimeoutLock);
m_Immediate = std::move(std::queue<std::function<void()>>());
m_Timeout = std::move(std::priority_queue<timeout_func>());
}
void clear(int handle) // thread-safe, relatively slow, not recommended nor reliable to do this for timeouts, only reliable for intervals
{
std::unique_lock<std::mutex> lock(m_QueueTimeoutLock);
std::priority_queue<timeout_func> timeout;
while (m_Timeout.size())
{
if (m_Timeout.top().handle != handle)
timeout.push(m_Timeout.top());
m_Timeout.pop();
}
m_Timeout = std::move(timeout);
}
void join() // thread-safe
{
std::mutex syncLock;
std::condition_variable syncCond;
std::unique_lock<std::mutex> lock(syncLock);
immediate([this, &syncCond]() -> void {
syncCond.notify_one();
});
m_PokeCond.wait(lock);
}
public:
void immediate(std::function<void()> f) // thread-safe
{
std::unique_lock<std::mutex> lock(m_QueueLock);
m_Immediate.push(f);
poke();
}
template<class rep, class period>
int timeout(std::function<void()> f, const std::chrono::duration<rep, period>& delta) // thread-safe
{
timeout_func tf;
tf.f = f;
tf.time = std::chrono::steady_clock::now() + delta;
tf.interval = std::chrono::nanoseconds::zero();
tf.handle = ++m_Handle;
; {
std::unique_lock<std::mutex> lock(m_QueueTimeoutLock);
m_Timeout.push(tf);
poke();
}
return tf.handle;
}
template<class rep, class period>
int interval(std::function<void()> f, const std::chrono::duration<rep, period>& interval) // thread-safe
{
timeout_func tf;
tf.f = f;
tf.time = std::chrono::steady_clock::now() + interval;
tf.interval = interval;
tf.handle = ++m_Handle;
; {
std::unique_lock<std::mutex> lock(m_QueueTimeoutLock);
m_Timeout.push(tf);
poke();
}
return tf.handle;
}
int timed(std::function<void()> f, const std::chrono::steady_clock::time_point &point) // thread-safe
{
timeout_func tf;
tf.f = f;
tf.time = point;
tf.interval = std::chrono::steady_clock::duration::zero();
tf.handle = ++m_Handle;
; {
std::unique_lock<std::mutex> lock(m_QueueTimeoutLock);
m_Timeout.push(tf);
poke();
}
return tf.handle;
}
public:
void thread(std::function<void()> f, std::function<void()> callback)
{
std::thread t([this, f, callback]() -> void {
f();
immediate(callback);
});
t.detach();
}
private:
void loop()
{
while (m_Running)
{
m_Poked = false;
for (;;)
{
m_QueueLock.lock();
if (!m_Immediate.size())
{
m_QueueLock.unlock();
break;
}
std::function<void()> f = m_Immediate.front();
m_Immediate.pop();
m_QueueLock.unlock();
f();
}
bool poked = false;
for (;;)
{
m_QueueTimeoutLock.lock();
if (!m_Timeout.size())
{
m_QueueTimeoutLock.unlock();
break;
}
const timeout_func &tfr = m_Timeout.top();
if (tfr.time > std::chrono::steady_clock::now()) // wait
{
m_QueueTimeoutLock.unlock();
; {
std::unique_lock<std::mutex> lock(m_PokeLock);
if (!m_Poked)
m_PokeCond.wait_until(lock, tfr.time);
}
poked = true;
break;
}
timeout_func tf = tfr;
m_Timeout.pop();
m_QueueTimeoutLock.unlock();
tf.f(); // call
if (tf.interval > std::chrono::nanoseconds::zero()) // repeat
{
tf.time += tf.interval;
; {
std::unique_lock<std::mutex> lock(m_QueueTimeoutLock);
m_Timeout.push(tf);
poke();
}
}
}
if (!poked)
{
std::unique_lock<std::mutex> lock(m_PokeLock);
if (!m_Poked)
m_PokeCond.wait(lock);
}
}
}
void poke() // private
{
std::unique_lock<std::mutex> lock(m_PokeLock);
m_PokeCond.notify_one();
m_Poked = true;
}
private:
struct timeout_func
{
std::function<void()> f;
std::chrono::steady_clock::time_point time;
std::chrono::steady_clock::duration interval;
int handle;
bool operator <(const timeout_func &o) const
{
return time > o.time;
}
};
private:
volatile bool m_Running;
volatile bool m_Poked;
std::thread m_Thread;
std::mutex m_PokeLock;
std::condition_variable m_PokeCond;
std::mutex m_QueueLock;
std::queue<std::function<void()>> m_Immediate;
std::mutex m_QueueTimeoutLock;
std::priority_queue<timeout_func> m_Timeout;
int m_Handle;
};
#endif /* NL_EVENT_LOOP_H */
/* end of file */
Loading…
Cancel
Save