forked from mirror/openmw-tes3mp
Merge branch 'master' into QtOGre
Conflicts: apps/opencs/model/doc/document.cpp apps/opencs/view/render/pagedworldspacewidget.cpp apps/opencs/view/render/pagedworldspacewidget.hpp components/nif/niffile.hpp libs/openengine/bullet/physic.hpploadfix
commit
312b7cd571
@ -0,0 +1,139 @@
|
||||
Adam Hogan <comrade@comrade-desktop.(none)>
|
||||
Aleksandar Jovanov <ajovanov93@yahoo.com>
|
||||
Alexander Olofsson <ace@haxalot.com>
|
||||
Alex McKibben <mckibbenta@gmail.com>
|
||||
Alex "rainChu" Haddad <alx1213@gmail.com>
|
||||
Ardekantur <greystone@ardekantur.com>
|
||||
Armin Preiml <b.nutzer@gmail.com>
|
||||
Artem Kotsynyak <greye@carceri>
|
||||
Arthur Moore <arthur@Behemoth>
|
||||
Arthur Moore <Arthur.Moore.git@cd-net.net>
|
||||
athile <athile@athile.net>
|
||||
athile <athile.g@gmail.com>
|
||||
Stefan Galowicz <bogglez@the.mind>
|
||||
Bret Curtis <psi29a@gmail.com>
|
||||
Britt Mathis <britt.mathis@gmail.com>
|
||||
Sandy Carter <bwrsandman@gmail.com>
|
||||
Sandy Carter <mr.sandy.carter@gmail.com>
|
||||
Carl Maxwell <carl.maxwell@gmail.com>
|
||||
cc9cii <cc9c@iinet.net.au>
|
||||
Cory F. Cohen <cfcohen@verizon.net>
|
||||
Chris Robinson <chris.kcat@gmail.com>
|
||||
Cris Mihalache <mirceam94@hotmail.com>
|
||||
darkf <lw9k123@gmail.com>
|
||||
Diggory Hardy <diggory.hardy@gmail.com>
|
||||
Thomas Luppi <ThomasLuppi@gmail.com>
|
||||
Thomas Luppi <tluppi@thomas-GE60.(none)>
|
||||
Dmitriy 'Endorph' Shkurskiy <end0rph@hotmail.com>
|
||||
Dmitry Marakasov <amdmi3@amdmi3.ru>
|
||||
Douglas Diniz <dgdiniz@gmail.com>
|
||||
Douglas Mencken <dougmencken@gmail.com>
|
||||
Edmondo Tommasina <edmondo.tommasina@gmail.com>
|
||||
Eduard Cot <eduard@eduard-iMac.(none)>
|
||||
Eli2 <fabian@fabian-desktop.(none)>
|
||||
Emanuel Guével <guevel.emanuel@gmail.com>
|
||||
Leon Saunders <LeonDavidSaunders@gmail.com>
|
||||
Fil Krynicki <filipkrynicki@gmail.com>
|
||||
John Blomberg <johnblo@kth.se>
|
||||
Gašper Sedej <gsedej@gmail.com>
|
||||
Michał Bień <michal1.bien@gmail.com>
|
||||
Joel Graff <monograff76@gmail.com>
|
||||
Paul McElroy <pcm1123@gmail.com>
|
||||
Artem Kotsynyak <greye@carceri>
|
||||
Artem Kotsynyak <greye@null.net>
|
||||
gugus <gus_512@hotmail.com>
|
||||
guidoj <guido@thuisbasis.net>
|
||||
gus <gus_512@hotmail.com>
|
||||
Hallfaer Tuilinn <gijsbertth@gmail.com>
|
||||
Julian Ospald <julian.ospald@googlemail.com>
|
||||
Jacob Essex <jacob@jacobessex.com>
|
||||
Jan Borsodi <jborsodi@gmail.com>
|
||||
Jan-Peter Nilsson <peppe@pappkartong.se>
|
||||
Jason Hooks <Hooks@.(none)>
|
||||
Jason Hooks <jason@Jason-ThinkPad-R61.(none)>
|
||||
Jason Hooks <jhooks1@mix.wvu.edu>
|
||||
Jeffrey Haines <jeffhaines@me.com>
|
||||
Jeffrey Haines <jib-y@users.noreply.github.com>
|
||||
Jordan Ayers <jordan.ayers@gmail.com>
|
||||
Jordan Milne <jordan.milne@saynotolinux.com>
|
||||
Josua Grawitter <josh@greyage.org>
|
||||
Julien Voisin <pouicpouicpouic@gmail.com>
|
||||
Karl-Felix Glatzer <karl.glatzer@gmx.de>
|
||||
Chris Robinson <chris.kcat@gmail.com>
|
||||
Kevin Poitra <pupkev@yahoo.com>
|
||||
Roman Proskuryakov <humbug@deeptown.org>
|
||||
Lars Söderberg <lazze_1983@hotmail.com>
|
||||
lazydev <lazydev@homecomp>
|
||||
lazydev <lazydev@nomail>
|
||||
Lukasz Gromanowski <lgromanowski@gmail.com>
|
||||
Marc Bouvier <marcrbouvier@gmail.com>
|
||||
Marcin Hulist <Gohan1989@gmail.com>
|
||||
Marc Zinnschlag <marc@zpages.de>
|
||||
Marek Kochanowicz <herr@mikrus.pl>
|
||||
Marek Kochanowicz <marek@localhost.localdomain>
|
||||
Marek Kochanowicz <sirherrbatka@gmail.com>
|
||||
Mark Siewert <mark.siewert@t-online.de>
|
||||
Mark Siewert <ms@cerebra.localdomain>
|
||||
megaton <9megaton6@gmail.com>
|
||||
Michael Mc Donnell <michael@mcdonnell.dk>
|
||||
Michael Papageorgiou <werdanith@yahoo.gr>
|
||||
Michal Sciubidlo <michal.sciubidlo@gmail.com>
|
||||
Michał Ściubidło <michal.sciubidlo@gmail.com>
|
||||
Nathan Jeffords <blunted2night@gmail.com>
|
||||
Nicolay Korslund <korslund@gmail.com>
|
||||
Nicolay Korslund <nicolayk@met.no>
|
||||
Nikolay Kasyanov <corrmage@gmail.com>
|
||||
pchan3 <chantlerpeter@gmail.com>
|
||||
Pieter van der Kloet <pvdkloet@gmail.com>
|
||||
Mateusz Kołaczek <mateusz.kolaczek@gmail.com>
|
||||
Bret Curtis <psi29a@gmail.com>
|
||||
Pieter van der Kloet <pvdkloet@gmail.com>
|
||||
Rohit Nirmal <rohitnirmal9@gmail.com>
|
||||
Roman Melnik <kromgart@gmail.com>
|
||||
Radu-Marius Popovici <rpopovici@github.com>
|
||||
Sandy Carter <bwrsandman@gmail.com>
|
||||
Scott Howard <showard314@gmail.com>
|
||||
Jannik Heller <scrawl@baseoftrash.de>
|
||||
Jannik Heller <scrawl@scrawl-laptop.(none)>
|
||||
Sebastian Wick <sebastian@sebastianwick.net>
|
||||
Sebastian Wick <wick.sebastian@gmail.com>
|
||||
Sergey Shambir <sergey.shambir.auto@gmail.com>
|
||||
sergoz <parapvr@yandex.ru>
|
||||
Chris Boyce <slothlife@users.noreply.github.com>
|
||||
Star-Demon <starsickle@yahoo.com>
|
||||
Sylvain Thesnieres <garvek@gmail.com>
|
||||
Thomas Luppi <digrules@gmail.com>
|
||||
Thomas Luppi <tluppi@thomas-GE60.(none)>
|
||||
Thoronador <thoronador@users.sourceforge.net>
|
||||
TomKoenderink <tom_koenderink-github@omniadicta.net>
|
||||
Tom Mason <wheybags@wheybags.com>
|
||||
Torben Carrington <torbenlcarrington@Gmail.com>
|
||||
Vincent Heuken <vincent@vincentheuken.com>
|
||||
Manuel Edelmann <edelmann.manuel@gmail.com>
|
||||
Manuel Edelmann <vorenon@hotmail.com>
|
||||
Alexander Nadeau <wareya@gmail.com>
|
||||
Michael Hogan <mr.michaelhogan@gmail.com>
|
||||
Jacob Essex <github@JacobEssex.com>
|
||||
Yuri Krupenin <yuri.krupenin@gmail.com>
|
||||
Bret Curtis <noone@your.box>
|
||||
|
||||
sirherrbatka <herr@localhost.localdomain>
|
||||
sirherrbatka <sirherrbatka@myopera.com>
|
||||
sergei <sergei@ubuntu.(none)>
|
||||
riothamus <digimars@gmail.com>
|
||||
nobrakal <nobrakal@gmail.com>
|
||||
nkorslund <nkorslund@ea6a568a-9f4f-0410-981a-c910a81bb256>
|
||||
mrcheko <cheko@sevas.ua>
|
||||
Miroslav Puda <pakanek@gmail.com>
|
||||
MiroslavR <miroslavr256@gmail.com>
|
||||
mckibbenta <mckibbenta@gmail.com>
|
||||
jeaye <jeaye@arrownext.com>
|
||||
eroen <eroen@falcon.eroen.eu>
|
||||
eroen <eroen@occam.eroen.eu>
|
||||
dreamer-dead <dreamer.dead@gmail.com>
|
||||
crysthala <crystalsoulslayer@gmail.com>
|
||||
Berulacks <beru@eml.cc>
|
||||
Axujen <axujen@gmail.com>
|
||||
root <root@debian>
|
||||
unknown <Hooks@.(none)>
|
||||
|
@ -0,0 +1,31 @@
|
||||
|
||||
#include "blacklist.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
bool CSMDoc::Blacklist::isBlacklisted (const CSMWorld::UniversalId& id) const
|
||||
{
|
||||
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> >::const_iterator iter =
|
||||
mIds.find (id.getType());
|
||||
|
||||
if (iter==mIds.end())
|
||||
return false;
|
||||
|
||||
return std::binary_search (iter->second.begin(), iter->second.end(),
|
||||
Misc::StringUtils::lowerCase (id.getId()));
|
||||
}
|
||||
|
||||
void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type,
|
||||
const std::vector<std::string>& ids)
|
||||
{
|
||||
std::vector<std::string>& list = mIds[type];
|
||||
|
||||
int size = list.size();
|
||||
|
||||
list.resize (size+ids.size());
|
||||
|
||||
std::transform (ids.begin(), ids.end(), list.begin()+size, Misc::StringUtils::lowerCase);
|
||||
std::sort (list.begin(), list.end());
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
#ifndef CSM_DOC_BLACKLIST_H
|
||||
#define CSM_DOC_BLACKLIST_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "../world/universalid.hpp"
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
/// \brief ID blacklist sorted by UniversalId type
|
||||
class Blacklist
|
||||
{
|
||||
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> > mIds;
|
||||
|
||||
public:
|
||||
|
||||
bool isBlacklisted (const CSMWorld::UniversalId& id) const;
|
||||
|
||||
void add (CSMWorld::UniversalId::Type type, const std::vector<std::string>& ids);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,162 @@
|
||||
|
||||
#include "runner.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QTemporaryFile>
|
||||
#include <QTextStream>
|
||||
|
||||
#include "operation.hpp"
|
||||
|
||||
CSMDoc::Runner::Runner (const boost::filesystem::path& projectPath)
|
||||
: mRunning (false), mStartup (0), mProjectPath (projectPath)
|
||||
{
|
||||
connect (&mProcess, SIGNAL (finished (int, QProcess::ExitStatus)),
|
||||
this, SLOT (finished (int, QProcess::ExitStatus)));
|
||||
|
||||
connect (&mProcess, SIGNAL (readyReadStandardOutput()),
|
||||
this, SLOT (readyReadStandardOutput()));
|
||||
|
||||
mProcess.setProcessChannelMode (QProcess::MergedChannels);
|
||||
|
||||
mProfile.blank();
|
||||
}
|
||||
|
||||
CSMDoc::Runner::~Runner()
|
||||
{
|
||||
if (mRunning)
|
||||
{
|
||||
disconnect (&mProcess, 0, this, 0);
|
||||
mProcess.kill();
|
||||
mProcess.waitForFinished();
|
||||
}
|
||||
}
|
||||
|
||||
void CSMDoc::Runner::start (bool delayed)
|
||||
{
|
||||
if (mStartup)
|
||||
{
|
||||
delete mStartup;
|
||||
mStartup = 0;
|
||||
}
|
||||
|
||||
if (!delayed)
|
||||
{
|
||||
mLog.clear();
|
||||
|
||||
QString path = "openmw";
|
||||
#ifdef Q_OS_WIN
|
||||
path.append(QString(".exe"));
|
||||
#elif defined(Q_OS_MAC)
|
||||
QDir dir(QCoreApplication::applicationDirPath());
|
||||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
dir.cdUp();
|
||||
path = dir.absoluteFilePath(path.prepend("OpenMW.app/Contents/MacOS/"));
|
||||
#else
|
||||
path.prepend(QString("./"));
|
||||
#endif
|
||||
|
||||
mStartup = new QTemporaryFile (this);
|
||||
mStartup->open();
|
||||
|
||||
{
|
||||
QTextStream stream (mStartup);
|
||||
|
||||
if (!mStartupInstruction.empty())
|
||||
stream << QString::fromUtf8 (mStartupInstruction.c_str()) << '\n';
|
||||
|
||||
stream << QString::fromUtf8 (mProfile.mScriptText.c_str());
|
||||
}
|
||||
|
||||
mStartup->close();
|
||||
|
||||
QStringList arguments;
|
||||
arguments << "--skip-menu";
|
||||
|
||||
if (mProfile.mFlags & ESM::DebugProfile::Flag_BypassNewGame)
|
||||
arguments << "--new-game=0";
|
||||
else
|
||||
arguments << "--new-game=1";
|
||||
|
||||
arguments << ("--script-run="+mStartup->fileName());;
|
||||
|
||||
arguments <<
|
||||
QString::fromUtf8 (("--data="+mProjectPath.parent_path().string()).c_str());
|
||||
|
||||
for (std::vector<std::string>::const_iterator iter (mContentFiles.begin());
|
||||
iter!=mContentFiles.end(); ++iter)
|
||||
{
|
||||
arguments << QString::fromUtf8 (("--content="+*iter).c_str());
|
||||
}
|
||||
|
||||
arguments
|
||||
<< QString::fromUtf8 (("--content="+mProjectPath.filename().string()).c_str());
|
||||
|
||||
mProcess.start (path, arguments);
|
||||
}
|
||||
|
||||
mRunning = true;
|
||||
emit runStateChanged();
|
||||
}
|
||||
|
||||
void CSMDoc::Runner::stop()
|
||||
{
|
||||
delete mStartup;
|
||||
mStartup = 0;
|
||||
|
||||
if (mProcess.state()==QProcess::NotRunning)
|
||||
{
|
||||
mRunning = false;
|
||||
emit runStateChanged();
|
||||
}
|
||||
else
|
||||
mProcess.kill();
|
||||
}
|
||||
|
||||
bool CSMDoc::Runner::isRunning() const
|
||||
{
|
||||
return mRunning;
|
||||
}
|
||||
|
||||
void CSMDoc::Runner::configure (const ESM::DebugProfile& profile,
|
||||
const std::vector<std::string>& contentFiles, const std::string& startupInstruction)
|
||||
{
|
||||
mProfile = profile;
|
||||
mContentFiles = contentFiles;
|
||||
mStartupInstruction = startupInstruction;
|
||||
}
|
||||
|
||||
void CSMDoc::Runner::finished (int exitCode, QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
mRunning = false;
|
||||
emit runStateChanged();
|
||||
}
|
||||
|
||||
QTextDocument *CSMDoc::Runner::getLog()
|
||||
{
|
||||
return &mLog;
|
||||
}
|
||||
|
||||
void CSMDoc::Runner::readyReadStandardOutput()
|
||||
{
|
||||
mLog.setPlainText (
|
||||
mLog.toPlainText() + QString::fromUtf8 (mProcess.readAllStandardOutput()));
|
||||
}
|
||||
|
||||
|
||||
CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, Operation *operation)
|
||||
: QObject (runner), mRunner (runner)
|
||||
{
|
||||
connect (operation, SIGNAL (done (int, bool)), this, SLOT (saveDone (int, bool)));
|
||||
}
|
||||
|
||||
void CSMDoc::SaveWatcher::saveDone (int type, bool failed)
|
||||
{
|
||||
if (failed)
|
||||
mRunner->stop();
|
||||
else
|
||||
mRunner->start();
|
||||
|
||||
deleteLater();
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
#ifndef CSM_DOC_RUNNER_H
|
||||
#define CSM_DOC_RUNNER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#include <QObject>
|
||||
#include <QProcess>
|
||||
#include <QTextDocument>
|
||||
|
||||
#include <components/esm/debugprofile.hpp>
|
||||
|
||||
class QTemporaryFile;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Runner : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QProcess mProcess;
|
||||
bool mRunning;
|
||||
ESM::DebugProfile mProfile;
|
||||
std::vector<std::string> mContentFiles;
|
||||
std::string mStartupInstruction;
|
||||
QTemporaryFile *mStartup;
|
||||
QTextDocument mLog;
|
||||
boost::filesystem::path mProjectPath;
|
||||
|
||||
public:
|
||||
|
||||
Runner (const boost::filesystem::path& projectPath);
|
||||
|
||||
~Runner();
|
||||
|
||||
/// \param delayed Flag as running but do not start the OpenMW process yet (the
|
||||
/// process must be started by another call of start with delayed==false)
|
||||
void start (bool delayed = false);
|
||||
|
||||
void stop();
|
||||
|
||||
/// \note Running state is entered when the start function is called. This
|
||||
/// is not necessarily identical to the moment the child process is started.
|
||||
bool isRunning() const;
|
||||
|
||||
void configure (const ESM::DebugProfile& profile,
|
||||
const std::vector<std::string>& contentFiles,
|
||||
const std::string& startupInstruction);
|
||||
|
||||
QTextDocument *getLog();
|
||||
|
||||
signals:
|
||||
|
||||
void runStateChanged();
|
||||
|
||||
private slots:
|
||||
|
||||
void finished (int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
void readyReadStandardOutput();
|
||||
};
|
||||
|
||||
class Operation;
|
||||
|
||||
/// \brief Watch for end of save operation and restart or stop runner
|
||||
class SaveWatcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Runner *mRunner;
|
||||
|
||||
public:
|
||||
|
||||
/// *this attaches itself to runner
|
||||
SaveWatcher (Runner *runner, Operation *operation);
|
||||
|
||||
private slots:
|
||||
|
||||
void saveDone (int type, bool failed);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,25 +0,0 @@
|
||||
#ifndef CSM_FILTER_FILTER_H
|
||||
#define CSM_FILTER_FILTER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <components/esm/filter.hpp>
|
||||
|
||||
namespace CSMFilter
|
||||
{
|
||||
/// \brief Wrapper for Filter record
|
||||
struct Filter : public ESM::Filter
|
||||
{
|
||||
enum Scope
|
||||
{
|
||||
Scope_Project = 0, // per project
|
||||
Scope_Session = 1, // exists only for one editing session; not saved
|
||||
Scope_Content = 2 // embedded in the edited content file
|
||||
};
|
||||
|
||||
Scope mScope;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,51 @@
|
||||
#include "bodypartcheck.hpp"
|
||||
|
||||
CSMTools::BodyPartCheckStage::BodyPartCheckStage(
|
||||
const CSMWorld::IdCollection<ESM::BodyPart> &bodyParts,
|
||||
const CSMWorld::Resources &meshes,
|
||||
const CSMWorld::IdCollection<ESM::Race> &races ) :
|
||||
mBodyParts(bodyParts),
|
||||
mMeshes(meshes),
|
||||
mRaces(races)
|
||||
{ }
|
||||
|
||||
int CSMTools::BodyPartCheckStage::setup()
|
||||
{
|
||||
return mBodyParts.getSize();
|
||||
}
|
||||
|
||||
void CSMTools::BodyPartCheckStage::perform ( int stage, Messages &messages )
|
||||
{
|
||||
const CSMWorld::Record<ESM::BodyPart> &record = mBodyParts.getRecord(stage);
|
||||
|
||||
if ( record.isDeleted() )
|
||||
return;
|
||||
|
||||
const ESM::BodyPart &bodyPart = record.get();
|
||||
|
||||
CSMWorld::UniversalId id( CSMWorld::UniversalId::Type_BodyPart, bodyPart.mId );
|
||||
|
||||
// Check BYDT
|
||||
if (bodyPart.mData.mPart > 14 )
|
||||
messages.push_back(std::make_pair( id, bodyPart.mId + " has out of range part value." ));
|
||||
|
||||
if (bodyPart.mData.mFlags > 3 )
|
||||
messages.push_back(std::make_pair( id, bodyPart.mId + " has out of range flags value." ));
|
||||
|
||||
if (bodyPart.mData.mType > 2 )
|
||||
messages.push_back(std::make_pair( id, bodyPart.mId + " has out of range type value." ));
|
||||
|
||||
// Check MODL
|
||||
|
||||
if ( bodyPart.mModel.empty() )
|
||||
messages.push_back(std::make_pair( id, bodyPart.mId + " has no model." ));
|
||||
else if ( mMeshes.searchId( bodyPart.mModel ) == -1 )
|
||||
messages.push_back(std::make_pair( id, bodyPart.mId + " has invalid model." ));
|
||||
|
||||
// Check FNAM
|
||||
|
||||
if ( bodyPart.mRace.empty() )
|
||||
messages.push_back(std::make_pair( id, bodyPart.mId + " has no race." ));
|
||||
else if ( mRaces.searchId( bodyPart.mRace ) == -1 )
|
||||
messages.push_back(std::make_pair( id, bodyPart.mId + " has invalid race." ));
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
#ifndef CSM_TOOLS_BODYPARTCHECK_H
|
||||
#define CSM_TOOLS_BODYPARTCHECK_H
|
||||
|
||||
#include <components/esm/loadbody.hpp>
|
||||
#include <components/esm/loadrace.hpp>
|
||||
|
||||
#include "../world/resources.hpp"
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "../doc/stage.hpp"
|
||||
|
||||
namespace CSMTools
|
||||
{
|
||||
/// \brief VerifyStage: make sure that body part records are internally consistent
|
||||
class BodyPartCheckStage : public CSMDoc::Stage
|
||||
{
|
||||
const CSMWorld::IdCollection<ESM::BodyPart> &mBodyParts;
|
||||
const CSMWorld::Resources &mMeshes;
|
||||
const CSMWorld::IdCollection<ESM::Race> &mRaces;
|
||||
|
||||
public:
|
||||
BodyPartCheckStage(
|
||||
const CSMWorld::IdCollection<ESM::BodyPart> &bodyParts,
|
||||
const CSMWorld::Resources &meshes,
|
||||
const CSMWorld::IdCollection<ESM::Race> &races );
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform( int stage, Messages &messages );
|
||||
///< Messages resulting from this tage will be appended to \a messages.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,25 @@
|
||||
|
||||
#include "scope.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
CSMWorld::Scope CSMWorld::getScopeFromId (const std::string& id)
|
||||
{
|
||||
// get root namespace
|
||||
std::string namespace_;
|
||||
|
||||
std::string::size_type i = id.find ("::");
|
||||
|
||||
if (i!=std::string::npos)
|
||||
namespace_ = Misc::StringUtils::lowerCase (id.substr (0, i));
|
||||
|
||||
if (namespace_=="project")
|
||||
return Scope_Project;
|
||||
|
||||
if (namespace_=="session")
|
||||
return Scope_Session;
|
||||
|
||||
return Scope_Content;
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
#ifndef CSM_WOLRD_SCOPE_H
|
||||
#define CSM_WOLRD_SCOPE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
enum Scope
|
||||
{
|
||||
// record stored in content file
|
||||
Scope_Content = 1,
|
||||
|
||||
// record stored in project file
|
||||
Scope_Project = 2,
|
||||
|
||||
// record that exists only for the duration of one editing session
|
||||
Scope_Session = 4
|
||||
};
|
||||
|
||||
Scope getScopeFromId (const std::string& id);
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,93 @@
|
||||
|
||||
#include "globaldebugprofilemenu.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include <QActionGroup>
|
||||
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/record.hpp"
|
||||
|
||||
void CSVDoc::GlobalDebugProfileMenu::rebuild()
|
||||
{
|
||||
clear();
|
||||
|
||||
delete mActions;
|
||||
mActions = 0;
|
||||
|
||||
int idColumn = mDebugProfiles->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
||||
int stateColumn = mDebugProfiles->findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
|
||||
int globalColumn = mDebugProfiles->findColumnIndex (
|
||||
CSMWorld::Columns::ColumnId_GlobalProfile);
|
||||
|
||||
int size = mDebugProfiles->rowCount();
|
||||
|
||||
std::vector<QString> ids;
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
{
|
||||
int state = mDebugProfiles->data (mDebugProfiles->index (i, stateColumn)).toInt();
|
||||
|
||||
bool global = mDebugProfiles->data (mDebugProfiles->index (i, globalColumn)).toInt();
|
||||
|
||||
if (state!=CSMWorld::RecordBase::State_Deleted && global)
|
||||
ids.push_back (
|
||||
mDebugProfiles->data (mDebugProfiles->index (i, idColumn)).toString());
|
||||
}
|
||||
|
||||
mActions = new QActionGroup (this);
|
||||
connect (mActions, SIGNAL (triggered (QAction *)), this, SLOT (actionTriggered (QAction *)));
|
||||
|
||||
std::sort (ids.begin(), ids.end());
|
||||
|
||||
for (std::vector<QString>::const_iterator iter (ids.begin()); iter!=ids.end(); ++iter)
|
||||
{
|
||||
mActions->addAction (addAction (*iter));
|
||||
}
|
||||
}
|
||||
|
||||
CSVDoc::GlobalDebugProfileMenu::GlobalDebugProfileMenu (CSMWorld::IdTable *debugProfiles,
|
||||
QWidget *parent)
|
||||
: QMenu (parent), mDebugProfiles (debugProfiles), mActions (0)
|
||||
{
|
||||
rebuild();
|
||||
|
||||
connect (mDebugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
|
||||
this, SLOT (profileAboutToBeRemoved (const QModelIndex&, int, int)));
|
||||
|
||||
connect (mDebugProfiles, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||
this, SLOT (profileInserted (const QModelIndex&, int, int)));
|
||||
|
||||
connect (mDebugProfiles, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT (profileChanged (const QModelIndex&, const QModelIndex&)));
|
||||
}
|
||||
|
||||
void CSVDoc::GlobalDebugProfileMenu::updateActions (bool running)
|
||||
{
|
||||
if (mActions)
|
||||
mActions->setEnabled (!running);
|
||||
}
|
||||
|
||||
void CSVDoc::GlobalDebugProfileMenu::profileAboutToBeRemoved (const QModelIndex& parent,
|
||||
int start, int end)
|
||||
{
|
||||
rebuild();
|
||||
}
|
||||
|
||||
void CSVDoc::GlobalDebugProfileMenu::profileInserted (const QModelIndex& parent, int start,
|
||||
int end)
|
||||
{
|
||||
rebuild();
|
||||
}
|
||||
|
||||
void CSVDoc::GlobalDebugProfileMenu::profileChanged (const QModelIndex& topLeft,
|
||||
const QModelIndex& bottomRight)
|
||||
{
|
||||
rebuild();
|
||||
}
|
||||
|
||||
void CSVDoc::GlobalDebugProfileMenu::actionTriggered (QAction *action)
|
||||
{
|
||||
emit triggered (std::string (action->text().toUtf8().constData()));
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
#ifndef CSV_DOC_GLOBALDEBUGPROFILEMENU_H
|
||||
#define CSV_DOC_GLOBALDEBUGPROFILEMENU_H
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
class QModelIndex;
|
||||
class QActionGroup;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class IdTable;
|
||||
}
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class GlobalDebugProfileMenu : public QMenu
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
CSMWorld::IdTable *mDebugProfiles;
|
||||
QActionGroup *mActions;
|
||||
|
||||
private:
|
||||
|
||||
void rebuild();
|
||||
|
||||
public:
|
||||
|
||||
GlobalDebugProfileMenu (CSMWorld::IdTable *debugProfiles, QWidget *parent = 0);
|
||||
|
||||
void updateActions (bool running);
|
||||
|
||||
private slots:
|
||||
|
||||
void profileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
|
||||
|
||||
void profileInserted (const QModelIndex& parent, int start, int end);
|
||||
|
||||
void profileChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||
|
||||
void actionTriggered (QAction *action);
|
||||
|
||||
signals:
|
||||
|
||||
void triggered (const std::string& profile);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,20 @@
|
||||
|
||||
#include "runlogsubview.hpp"
|
||||
|
||||
#include <QTextEdit>
|
||||
|
||||
CSVDoc::RunLogSubView::RunLogSubView (const CSMWorld::UniversalId& id,
|
||||
CSMDoc::Document& document)
|
||||
: SubView (id)
|
||||
{
|
||||
QTextEdit *edit = new QTextEdit (this);
|
||||
edit->setDocument (document.getRunLog());
|
||||
edit->setReadOnly (true);
|
||||
|
||||
setWidget (edit);
|
||||
}
|
||||
|
||||
void CSVDoc::RunLogSubView::setEditLock (bool locked)
|
||||
{
|
||||
// ignored since this SubView does not have editing
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
#ifndef CSV_DOC_RUNLOGSUBVIEW_H
|
||||
#define CSV_DOC_RUNLOGSUBVIEW_H
|
||||
|
||||
#include "subview.hpp"
|
||||
|
||||
namespace CSVDoc
|
||||
{
|
||||
class RunLogSubView : public SubView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
RunLogSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
|
||||
|
||||
virtual void setEditLock (bool locked);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,77 +0,0 @@
|
||||
|
||||
#include "filtercreator.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QLabel>
|
||||
|
||||
#include "../../model/filter/filter.hpp"
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/columns.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
|
||||
std::string CSVFilter::FilterCreator::getNamespace() const
|
||||
{
|
||||
switch (mScope->currentIndex())
|
||||
{
|
||||
case CSMFilter::Filter::Scope_Project: return "project::";
|
||||
case CSMFilter::Filter::Scope_Session: return "session::";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void CSVFilter::FilterCreator::update()
|
||||
{
|
||||
mNamespace->setText (QString::fromUtf8 (getNamespace().c_str()));
|
||||
GenericCreator::update();
|
||||
}
|
||||
|
||||
std::string CSVFilter::FilterCreator::getId() const
|
||||
{
|
||||
return getNamespace() + GenericCreator::getId();
|
||||
}
|
||||
|
||||
void CSVFilter::FilterCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
|
||||
{
|
||||
int index =
|
||||
dynamic_cast<CSMWorld::IdTable&> (*getData().getTableModel (getCollectionId())).
|
||||
findColumnIndex (CSMWorld::Columns::ColumnId_Scope);
|
||||
|
||||
command.addValue (index, mScope->currentIndex());
|
||||
}
|
||||
|
||||
CSVFilter::FilterCreator::FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
const CSMWorld::UniversalId& id)
|
||||
: GenericCreator (data, undoStack, id)
|
||||
{
|
||||
mNamespace = new QLabel ("::", this);
|
||||
insertAtBeginning (mNamespace, false);
|
||||
|
||||
mScope = new QComboBox (this);
|
||||
|
||||
mScope->addItem ("Project");
|
||||
mScope->addItem ("Session");
|
||||
/// \todo re-enable for OpenMW 1.1
|
||||
// mScope->addItem ("Content");
|
||||
|
||||
connect (mScope, SIGNAL (currentIndexChanged (int)), this, SLOT (setScope (int)));
|
||||
|
||||
insertAtBeginning (mScope, false);
|
||||
|
||||
QLabel *label = new QLabel ("Scope", this);
|
||||
insertAtBeginning (label, false);
|
||||
|
||||
mScope->setCurrentIndex (1);
|
||||
}
|
||||
|
||||
void CSVFilter::FilterCreator::reset()
|
||||
{
|
||||
GenericCreator::reset();
|
||||
}
|
||||
|
||||
void CSVFilter::FilterCreator::setScope (int index)
|
||||
{
|
||||
update();
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
#ifndef CSV_FILTER_FILTERCREATOR_H
|
||||
#define CSV_FILTER_FILTERCREATOR_H
|
||||
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
|
||||
#include "../world/genericcreator.hpp"
|
||||
|
||||
namespace CSVFilter
|
||||
{
|
||||
class FilterCreator : public CSVWorld::GenericCreator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QComboBox *mScope;
|
||||
QLabel *mNamespace;
|
||||
|
||||
private:
|
||||
|
||||
std::string getNamespace() const;
|
||||
|
||||
protected:
|
||||
|
||||
void update();
|
||||
|
||||
virtual std::string getId() const;
|
||||
|
||||
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
|
||||
|
||||
public:
|
||||
|
||||
FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
const CSMWorld::UniversalId& id);
|
||||
|
||||
virtual void reset();
|
||||
|
||||
private slots:
|
||||
|
||||
void setScope (int index);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,23 @@
|
||||
#ifndef CSV_RENDER_ELEMENTS_H
|
||||
#define CSV_RENDER_ELEMENTS_H
|
||||
|
||||
namespace CSVRender
|
||||
{
|
||||
/// Visual elements in a scene
|
||||
enum Elements
|
||||
{
|
||||
// elements that are part of the actual scene
|
||||
Element_Reference = 0x1,
|
||||
Element_Terrain = 0x2,
|
||||
Element_Water = 0x4,
|
||||
Element_Pathgrid = 0x8,
|
||||
Element_Fog = 0x10,
|
||||
|
||||
// control elements
|
||||
Element_CellMarker = 0x10000,
|
||||
Element_CellArrow = 0x20000,
|
||||
Element_CellBorder = 0x40000
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,151 @@
|
||||
|
||||
#include "scenetoolrun.hpp"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <QFrame>
|
||||
#include <QTableWidget>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QApplication>
|
||||
|
||||
void CSVWidget::SceneToolRun::adjustToolTips()
|
||||
{
|
||||
QString toolTip = mToolTip;
|
||||
|
||||
if (mSelected==mProfiles.end())
|
||||
toolTip += "<p>No debug profile selected (function disabled)";
|
||||
else
|
||||
{
|
||||
toolTip += "<p>Debug profile: " + QString::fromUtf8 (mSelected->c_str());
|
||||
toolTip += "<p>(right click to switch to a different profile)";
|
||||
}
|
||||
|
||||
setToolTip (toolTip);
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolRun::updateIcon()
|
||||
{
|
||||
setIcon (QIcon (mSelected==mProfiles.end() ? mIconDisabled : mIcon));
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolRun::updatePanel()
|
||||
{
|
||||
mTable->setRowCount (mProfiles.size());
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (std::set<std::string>::const_iterator iter (mProfiles.begin()); iter!=mProfiles.end();
|
||||
++iter, ++i)
|
||||
{
|
||||
mTable->setItem (i, 0, new QTableWidgetItem (QString::fromUtf8 (iter->c_str())));
|
||||
|
||||
mTable->setItem (i, 1, new QTableWidgetItem (
|
||||
QApplication::style()->standardIcon (QStyle::SP_TitleBarCloseButton), ""));
|
||||
}
|
||||
}
|
||||
|
||||
CSVWidget::SceneToolRun::SceneToolRun (SceneToolbar *parent, const QString& toolTip,
|
||||
const QString& icon, const QString& iconDisabled, const std::vector<std::string>& profiles)
|
||||
: SceneTool (parent, Type_TopAction), mProfiles (profiles.begin(), profiles.end()),
|
||||
mSelected (mProfiles.begin()), mToolTip (toolTip), mIcon (icon),
|
||||
mIconDisabled (iconDisabled)
|
||||
{
|
||||
updateIcon();
|
||||
adjustToolTips();
|
||||
|
||||
mPanel = new QFrame (this, Qt::Popup);
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout (mPanel);
|
||||
|
||||
layout->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||
|
||||
mTable = new QTableWidget (0, 2, this);
|
||||
|
||||
mTable->setShowGrid (false);
|
||||
mTable->verticalHeader()->hide();
|
||||
mTable->horizontalHeader()->hide();
|
||||
mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch);
|
||||
mTable->horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents);
|
||||
mTable->setSelectionMode (QAbstractItemView::NoSelection);
|
||||
|
||||
layout->addWidget (mTable);
|
||||
|
||||
connect (mTable, SIGNAL (clicked (const QModelIndex&)),
|
||||
this, SLOT (clicked (const QModelIndex&)));
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolRun::showPanel (const QPoint& position)
|
||||
{
|
||||
updatePanel();
|
||||
|
||||
mPanel->move (position);
|
||||
mPanel->show();
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolRun::activate()
|
||||
{
|
||||
if (mSelected!=mProfiles.end())
|
||||
emit runRequest (*mSelected);
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolRun::removeProfile (const std::string& profile)
|
||||
{
|
||||
std::set<std::string>::iterator iter = mProfiles.find (profile);
|
||||
|
||||
if (iter!=mProfiles.end())
|
||||
{
|
||||
if (iter==mSelected)
|
||||
{
|
||||
if (iter!=mProfiles.begin())
|
||||
--mSelected;
|
||||
else
|
||||
++mSelected;
|
||||
}
|
||||
|
||||
mProfiles.erase (iter);
|
||||
|
||||
if (mSelected==mProfiles.end())
|
||||
updateIcon();
|
||||
|
||||
adjustToolTips();
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolRun::addProfile (const std::string& profile)
|
||||
{
|
||||
std::set<std::string>::iterator iter = mProfiles.find (profile);
|
||||
|
||||
if (iter==mProfiles.end())
|
||||
{
|
||||
mProfiles.insert (profile);
|
||||
|
||||
if (mSelected==mProfiles.end())
|
||||
{
|
||||
mSelected = mProfiles.begin();
|
||||
updateIcon();
|
||||
}
|
||||
|
||||
adjustToolTips();
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolRun::clicked (const QModelIndex& index)
|
||||
{
|
||||
if (index.column()==0)
|
||||
{
|
||||
// select profile
|
||||
mSelected = mProfiles.begin();
|
||||
std::advance (mSelected, index.row());
|
||||
mPanel->hide();
|
||||
adjustToolTips();
|
||||
}
|
||||
else if (index.column()==1)
|
||||
{
|
||||
// remove profile from list
|
||||
std::set<std::string>::iterator iter = mProfiles.begin();
|
||||
std::advance (iter, index.row());
|
||||
removeProfile (*iter);
|
||||
updatePanel();
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
#ifndef CSV_WIDGET_SCENETOOLRUN_H
|
||||
#define CSV_WIDGET_SCENETOOLRUN_H
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "scenetool.hpp"
|
||||
|
||||
class QFrame;
|
||||
class QTableWidget;
|
||||
class QModelIndex;
|
||||
|
||||
namespace CSVWidget
|
||||
{
|
||||
class SceneToolRun : public SceneTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::set<std::string> mProfiles;
|
||||
std::set<std::string>::iterator mSelected;
|
||||
QString mToolTip;
|
||||
QString mIcon;
|
||||
QString mIconDisabled;
|
||||
QFrame *mPanel;
|
||||
QTableWidget *mTable;
|
||||
|
||||
private:
|
||||
|
||||
void adjustToolTips();
|
||||
|
||||
void updateIcon();
|
||||
|
||||
void updatePanel();
|
||||
|
||||
public:
|
||||
|
||||
SceneToolRun (SceneToolbar *parent, const QString& toolTip, const QString& icon,
|
||||
const QString& iconDisabled, const std::vector<std::string>& profiles);
|
||||
|
||||
virtual void showPanel (const QPoint& position);
|
||||
|
||||
virtual void activate();
|
||||
|
||||
/// \attention This function does not remove the profile from the profile selection
|
||||
/// panel.
|
||||
void removeProfile (const std::string& profile);
|
||||
|
||||
/// \attention This function doe not add the profile to the profile selection
|
||||
/// panel. This only happens when the panel is re-opened.
|
||||
///
|
||||
/// \note Adding profiles that are already listed is a no-op.
|
||||
void addProfile (const std::string& profile);
|
||||
|
||||
private slots:
|
||||
|
||||
void clicked (const QModelIndex& index);
|
||||
|
||||
signals:
|
||||
|
||||
void runRequest (const std::string& profile);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,205 @@
|
||||
|
||||
#include "scenetooltoggle.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QFrame>
|
||||
#include <QIcon>
|
||||
#include <QPainter>
|
||||
|
||||
#include "scenetoolbar.hpp"
|
||||
#include "pushbutton.hpp"
|
||||
|
||||
void CSVWidget::SceneToolToggle::adjustToolTip()
|
||||
{
|
||||
QString toolTip = mToolTip;
|
||||
|
||||
toolTip += "<p>Currently enabled: ";
|
||||
|
||||
bool first = true;
|
||||
|
||||
for (std::map<PushButton *, ButtonDesc>::const_iterator iter (mButtons.begin());
|
||||
iter!=mButtons.end(); ++iter)
|
||||
if (iter->first->isChecked())
|
||||
{
|
||||
if (!first)
|
||||
toolTip += ", ";
|
||||
else
|
||||
first = false;
|
||||
|
||||
toolTip += iter->second.mName;
|
||||
}
|
||||
|
||||
if (first)
|
||||
toolTip += "none";
|
||||
|
||||
toolTip += "<p>(left click to alter selection)";
|
||||
|
||||
setToolTip (toolTip);
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolToggle::adjustIcon()
|
||||
{
|
||||
unsigned int selection = getSelection();
|
||||
if (!selection)
|
||||
setIcon (QIcon (QString::fromUtf8 (mEmptyIcon.c_str())));
|
||||
else
|
||||
{
|
||||
QPixmap pixmap (48, 48);
|
||||
pixmap.fill (QColor (0, 0, 0, 0));
|
||||
|
||||
{
|
||||
QPainter painter (&pixmap);
|
||||
|
||||
for (std::map<PushButton *, ButtonDesc>::const_iterator iter (mButtons.begin());
|
||||
iter!=mButtons.end(); ++iter)
|
||||
if (iter->first->isChecked())
|
||||
{
|
||||
painter.drawImage (getIconBox (iter->second.mIndex),
|
||||
QImage (QString::fromUtf8 (iter->second.mSmallIcon.c_str())));
|
||||
}
|
||||
}
|
||||
|
||||
setIcon (pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
QRect CSVWidget::SceneToolToggle::getIconBox (int index) const
|
||||
{
|
||||
// layout for a 3x3 grid
|
||||
int xMax = 3;
|
||||
int yMax = 3;
|
||||
|
||||
// icon size
|
||||
int xBorder = 1;
|
||||
int yBorder = 1;
|
||||
|
||||
int iconXSize = (mIconSize-xBorder*(xMax+1))/xMax;
|
||||
int iconYSize = (mIconSize-yBorder*(yMax+1))/yMax;
|
||||
|
||||
int y = index / xMax;
|
||||
int x = index % xMax;
|
||||
|
||||
int total = mButtons.size();
|
||||
|
||||
int actualYIcons = total/xMax;
|
||||
|
||||
if (total % xMax)
|
||||
++actualYIcons;
|
||||
|
||||
if (actualYIcons!=yMax)
|
||||
{
|
||||
// space out icons vertically, if there aren't enough to populate all rows
|
||||
int diff = yMax - actualYIcons;
|
||||
yBorder += (diff*(yBorder+iconXSize)) / (actualYIcons+1);
|
||||
}
|
||||
|
||||
if (y==actualYIcons-1)
|
||||
{
|
||||
// generating the last row of icons
|
||||
int actualXIcons = total % xMax;
|
||||
|
||||
if (actualXIcons)
|
||||
{
|
||||
// space out icons horizontally, if there aren't enough to fill the last row
|
||||
int diff = xMax - actualXIcons;
|
||||
|
||||
xBorder += (diff*(xBorder+iconXSize)) / (actualXIcons+1);
|
||||
}
|
||||
}
|
||||
|
||||
return QRect ((iconXSize+xBorder)*x+xBorder, (iconYSize+yBorder)*y+yBorder,
|
||||
iconXSize, iconYSize);
|
||||
}
|
||||
|
||||
CSVWidget::SceneToolToggle::SceneToolToggle (SceneToolbar *parent, const QString& toolTip,
|
||||
const std::string& emptyIcon)
|
||||
: SceneTool (parent), mEmptyIcon (emptyIcon), mButtonSize (parent->getButtonSize()),
|
||||
mIconSize (parent->getIconSize()), mToolTip (toolTip), mFirst (0)
|
||||
{
|
||||
mPanel = new QFrame (this, Qt::Popup);
|
||||
|
||||
mLayout = new QHBoxLayout (mPanel);
|
||||
|
||||
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
|
||||
|
||||
mPanel->setLayout (mLayout);
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolToggle::showPanel (const QPoint& position)
|
||||
{
|
||||
mPanel->move (position);
|
||||
mPanel->show();
|
||||
|
||||
if (mFirst)
|
||||
mFirst->setFocus (Qt::OtherFocusReason);
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolToggle::addButton (const std::string& icon, unsigned int id,
|
||||
const std::string& smallIcon, const QString& name, const QString& tooltip)
|
||||
{
|
||||
if (mButtons.size()>=9)
|
||||
throw std::runtime_error ("Exceeded number of buttons in toggle type tool");
|
||||
|
||||
PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())),
|
||||
PushButton::Type_Toggle, tooltip.isEmpty() ? name: tooltip, mPanel);
|
||||
|
||||
button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
|
||||
button->setIconSize (QSize (mIconSize, mIconSize));
|
||||
button->setFixedSize (mButtonSize, mButtonSize);
|
||||
|
||||
mLayout->addWidget (button);
|
||||
|
||||
ButtonDesc desc;
|
||||
desc.mId = id;
|
||||
desc.mSmallIcon = smallIcon;
|
||||
desc.mName = name;
|
||||
desc.mIndex = mButtons.size();
|
||||
|
||||
mButtons.insert (std::make_pair (button, desc));
|
||||
|
||||
connect (button, SIGNAL (clicked()), this, SLOT (selected()));
|
||||
|
||||
if (mButtons.size()==1)
|
||||
mFirst = button;
|
||||
}
|
||||
|
||||
unsigned int CSVWidget::SceneToolToggle::getSelection() const
|
||||
{
|
||||
unsigned int selection = 0;
|
||||
|
||||
for (std::map<PushButton *, ButtonDesc>::const_iterator iter (mButtons.begin());
|
||||
iter!=mButtons.end(); ++iter)
|
||||
if (iter->first->isChecked())
|
||||
selection |= iter->second.mId;
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolToggle::setSelection (unsigned int selection)
|
||||
{
|
||||
for (std::map<PushButton *, ButtonDesc>::iterator iter (mButtons.begin());
|
||||
iter!=mButtons.end(); ++iter)
|
||||
iter->first->setChecked (selection & iter->second.mId);
|
||||
|
||||
adjustToolTip();
|
||||
adjustIcon();
|
||||
}
|
||||
|
||||
void CSVWidget::SceneToolToggle::selected()
|
||||
{
|
||||
std::map<PushButton *, ButtonDesc>::const_iterator iter =
|
||||
mButtons.find (dynamic_cast<PushButton *> (sender()));
|
||||
|
||||
if (iter!=mButtons.end())
|
||||
{
|
||||
if (!iter->first->hasKeepOpen())
|
||||
mPanel->hide();
|
||||
|
||||
adjustToolTip();
|
||||
adjustIcon();
|
||||
|
||||
emit selectionChanged();
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
#ifndef CSV_WIDGET_SCENETOOL_TOGGLE_H
|
||||
#define CSV_WIDGET_SCENETOOL_TOGGLE_H
|
||||
|
||||
#include "scenetool.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
class QHBoxLayout;
|
||||
class QRect;
|
||||
|
||||
namespace CSVWidget
|
||||
{
|
||||
class SceneToolbar;
|
||||
class PushButton;
|
||||
|
||||
///< \brief Multi-Toggle tool
|
||||
class SceneToolToggle : public SceneTool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
struct ButtonDesc
|
||||
{
|
||||
unsigned int mId;
|
||||
std::string mSmallIcon;
|
||||
QString mName;
|
||||
int mIndex;
|
||||
};
|
||||
|
||||
std::string mEmptyIcon;
|
||||
QWidget *mPanel;
|
||||
QHBoxLayout *mLayout;
|
||||
std::map<PushButton *, ButtonDesc> mButtons; // widget, id
|
||||
int mButtonSize;
|
||||
int mIconSize;
|
||||
QString mToolTip;
|
||||
PushButton *mFirst;
|
||||
|
||||
void adjustToolTip();
|
||||
|
||||
void adjustIcon();
|
||||
|
||||
QRect getIconBox (int index) const;
|
||||
|
||||
public:
|
||||
|
||||
SceneToolToggle (SceneToolbar *parent, const QString& toolTip,
|
||||
const std::string& emptyIcon);
|
||||
|
||||
virtual void showPanel (const QPoint& position);
|
||||
|
||||
/// \attention After the last button has been added, setSelection must be called at
|
||||
/// least once to finalise the layout.
|
||||
///
|
||||
/// \note The layout algorithm can not handle more than 9 buttons. To prevent this An
|
||||
/// attempt to add more will result in an exception being thrown.
|
||||
/// The small icons will be sized at (x-4)/3 (where x is the main icon size).
|
||||
void addButton (const std::string& icon, unsigned int id,
|
||||
const std::string& smallIcon, const QString& name, const QString& tooltip = "");
|
||||
|
||||
unsigned int getSelection() const;
|
||||
|
||||
/// \param or'ed button IDs. IDs that do not exist will be ignored.
|
||||
void setSelection (unsigned int selection);
|
||||
|
||||
signals:
|
||||
|
||||
void selectionChanged();
|
||||
|
||||
private slots:
|
||||
|
||||
void selected();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue